!-------------------------------------- LICENCE BEGIN ------------------------------------ !Environment Canada - Atmospheric Science and Technology License/Disclaimer, ! version 3; Last Modified: May 7, 2008. !This is free but copyrighted software; you can use/redistribute/modify it under the terms !of the Environment Canada - Atmospheric Science and Technology License/Disclaimer !version 3 or (at your option) any later version that should be found at: !http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html ! !This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; !without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. !See the above mentioned License/Disclaimer for more details. !You should have received a copy of the License/Disclaimer along with this software; !if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec), !CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca !-------------------------------------- LICENCE END -------------------------------------- ! ***function: VSTRETCH_AXIS2 - will return a stretched axis given the * parameters NX,F_nxla,F_xbeg,F_xend,F_dxla *integer function vstretch_axis2 6,2 $ ( F_x_8, F_dxla, F_xbeg, F_xend, F_margin, NX, F_nxla, F_amp, $ F_stagger_L, F_print_L, F_dxmax, F_nimax, F_gauss_L) * implicit none #include "taglam4d.cdk"
* integer F_margin, NX, F_nxla, F_nimax real F_amp, F_dxla, F_xbeg, F_xend, F_dxmax real*8 F_x_8(NX) logical F_stagger_L, F_print_L, F_gauss_L *author: Luc Fillion for LAM4D from GEM code from Vivian Lee - July 1999 * *revision * v2_00 - Lee V. - initial MPI version * v2_20 - Lee V. - converted input F_x to F_x_8 (real*8) * v2_30 - A. Methot - introduction of a new stretch grid design * v2_30 - with upper limits on grid point spacing * v3_11 - M. Tanguay - Introduce Grd_gauss_L * L. Fillion - ARMA/EC - 28 May 2008 * - Debug according to -qcheck compiling option on IBM. Pointer need to be controlled... * *object * see above id * *arguments * Name I/O Description *---------------------------------------------------------------- * stretch_axis O - value of 0(no error), -1 (error) * F_x_8 O - axis containing values for each grid point * F_dxla I/O - on input,number of degrees between grid points in * the uniform domain. * - on output, calculated number of degrees between grid * points if the axis is uniform * F_xbeg I - starting (latitude/longitude) degree of the axis * F_xend I - ending (latitude/longitude) degree of the axis * F_margin O - number of points between the border of the variable * variable grid to the border of the uniform domain * NX I - total number of points of the grid in the axis * F_nxla I - number of points in the uniform domain of the axis * F_amp O - the amplification factor used to determine the grid * points outside of the uniform domain. * F_stagger_L I - .TRUE.if grid points do not lie on the end points * of the axis (F_xbeg,F_xend) * F_print_L I - .TRUE. to print comments,values of this function * F_dxmax I - upper limit on grid spacing (degrees) * F_nimax O - number of points having upper limit grid spacing * F_gauss_L I - TRUE if GEM grid is set as Gaussian * * *notes * The function qqqroot3 is included in this deck (written by J.Cote) * *modules #include "comlun.cdk"
real*8 qqqroot3 external qqqroot3 * logical sampar integer nit, it, i real*8 a0, am, eps, xdist_8, e, guess, hx, x1, x2 real*8 amp_8, F_dxla_8 real*8 hxmax * real*8 deg2rad_8 real*8, parameter :: CLXXX_8 = 180.0 real*8, parameter :: ONE_8 = 1.0 * real groots(NX) real ay(NX) real*8 G_ygauss_8(NX+1) integer status,j * F_dxla_8 = F_dxla hxmax = F_dxmax * if (F_print_L) then write(nulout,*) '*** vstretch_axis(begin) *******' write(nulout,*) 'VSTRETCH_AXIS2: NX = ',NX write(nulout,*) 'VSTRETCH_AXIS2: F_nxla = ',F_nxla write(nulout,*) 'VSTRETCH_AXIS2: F_dxla = ',F_dxla write(nulout,*) 'VSTRETCH_AXIS2: F_stagger_L = ',F_stagger_L write(nulout,*) 'VSTRETCH_AXIS2: F_xbeg = ',F_xbeg write(nulout,*) 'VSTRETCH_AXIS2: F_xend = ',F_xend endif xdist_8 = F_xend - F_xbeg guess = - 1.0 eps = 1.0e-15 nit = 10 * * Evaluate Gaussian latitudes if requested * ---------------------------------------- if(F_gauss_L.and.F_stagger_L) then * if( NX .ne. F_nxla) then ! call gem_stop('VSTRETCH_AXIS2 NOT VALID',-1) ! call abort3d(nulout,'VSTRETCH_AXIS2: NX .ne. F_nxla') endif * deg2rad_8 = acos( -ONE_8 )/CLXXX_8 * call ez_glat (ay,groots,NX,0) * do j=1,NX G_ygauss_8(j) = ay(j) enddo G_ygauss_8(NX+1) = G_ygauss_8(1) + 180.0 * endif * if ( NX .lt. F_nxla ) then ! call abort3d(nulout,'VSTRETCH_AXIS2: NX .lt. F_nxla') print *,'*' print *, 'VSTRETCH_AXIS ERROR: NX = ',NX,' < ',' F_nxla = ',F_nxla vstretch_axis2=-1 return else if ( NX .eq. F_nxla ) then * the grid is uniform amp_8 = 1.0 e = 0.0 if ( F_stagger_L ) then F_dxla_8 = xdist_8/(NX) else F_dxla_8 = xdist_8/(NX-1) hxmax=F_dxla_8 endif F_margin = 0 F_nimax = 0 if (F_print_L) then write(nulout,*) 'Uniform Grid Detected: F_dxla=',F_dxla_8 endif else * the grid is variable if (F_print_L) then write(nulout,*) 'Variable Grid Detected' endif F_nimax = 0 if ( (NX-1)*F_dxla .ge. xdist_8 ) then ! call abort3d(nulout,'VSTRETCH_AXIS2: (NX-1)*F_dxla .ge. xdist_8') vstretch_axis2=-1 return endif endif *C----------------------------------------------------------------------- *C -BEGIN ITERATION LOOP IF UPPER LIMIT GRID SPACING IS REACHED ------- *C----------------------------------------------------------------------- 8888 continue if ( NX .gt. F_nxla ) then if ( F_nimax .gt. ( NX - F_nxla - 1 ) /2 ) then ! call abort3d(nulout,'VSTRETCH_AXIS2: (NX-1)*F_dxla .ge. xdist_8') ! print *,'STRETCH_AXIS ERROR: no convergence in ', ! % ' in nimax iteration: nimax=', F_nimax vstretch_axis2=-1 return endif a0 = 0.5 *( ( F_nxla-1 ) - % ( xdist_8 - 2. * F_nimax * hxmax )/F_dxla_8 % ) if ( a0 .gt. 0.0 ) then ! call abort3d(nulout,'VSTRETCH_AXIS2: a0 .gt. 0.0') ! print * ! print *,'STRETCH_AXIS ERROR: ', ! % 'illegal values for F_nxla and F_dxla, a0 = ',a0,' < 0' vstretch_axis2 = -1 return endif * if (F_print_L) print *,'a0 = ',a0 sampar = mod( NX - F_nxla, 2 ) .eq. 0 if (F_print_L) print *,'sampar = ',sampar,' NX=',NX,' F_nxla=',F_nxla * if ( .not. sampar ) then print * print *,'STRETCH_AXIS ERROR: sampar must be true' print *,'Cannot have equal points (F_margins) on either', % ' side of uniform grid' vstretch_axis2 = -1 return endif F_margin = ( NX - F_nxla )/2 - F_nimax if (F_print_L) print *,'F_margin = ',F_margin if ( .not. F_stagger_L ) then am = 1.0 amp_8 = qqqroot3
( guess,a0,am,F_margin,nit,eps,it,e ) if ( it .lt. 0 ) then print * print *,'STRETCH_AXIS: ERROR in QQQROOT3 function' vstretch_axis2 = -1 return endif else am = 1.5 amp_8 = qqqroot3
( guess,a0,am,F_margin,nit,eps,it,e) if ( it .lt. 0 ) then print * print *,'STRETCH_AXIS: ERROR in QQQROOT3 function' vstretch_axis2 = -1 return endif endif endif * if (F_print_L) print *,'amp_8 = ',amp_8,' estimate = ',e if (F_print_L) print *,'nimax = ',F_nimax * * phi-grid * x1 = - 0.5 * ( F_nxla - 1 ) * F_dxla_8 + (F_xbeg+F_xend)/2.0 F_x_8(F_nimax+F_margin+1) = x1 if(F_gauss_L.and.F_stagger_L) F_x_8(F_nimax+F_margin+1) = G_ygauss_8(1) * C computed grid points in the stretched sector C to the left or bottom of central area x2 = x1 hx = F_dxla_8 do i=F_nimax+F_margin,F_nimax+1,-1 hx = amp_8 * hx x2 = x2 - hx F_x_8(i) = x2 enddo if ( hx .gt. hxmax ) then F_nimax=F_nimax+1 go to 8888 endif *C----------------------------------------------------------------------- *C ---END ITERATION LOOP IF UPPER LIMIT GRID SPACING IS REACHED ------- *C----------------------------------------------------------------------- C compute grid points in the central area C of uniform resolution if(F_gauss_L.and.F_stagger_L) then do i=F_nimax+F_margin+1,F_nimax+F_margin+F_nxla-1 F_x_8(i+1) = G_ygauss_8(i+1) enddo else write(nulout,*) 'VSTRETCH_AXIS2: F_nimax=',F_nimax write(nulout,*) 'VSTRETCH_AXIS2: F_margin=',F_margin write(nulout,*) 'VSTRETCH_AXIS2: F_nxla=',F_nxla write(nulout,*) 'VSTRETCH_AXIS2: F_nimax+F_margin+1 = ',F_nimax+F_margin+1 write(nulout,*) 'VSTRETCH_AXIS2: F_nimax+F_margin+F_nxla-1=', & F_nimax+F_margin+F_nxla-1 do i=F_nimax+F_margin+1,F_nimax+F_margin+F_nxla-1 x2 = x1 + ( i - F_margin - F_nimax ) * F_dxla_8 F_x_8(i+1) = x2 enddo endif * hx = F_dxla_8 C computed grid points in the stretched sector C to the right or top of central area write(nulout,*) 'VSTRETCH_AXIS2: F_nimax=',F_nimax write(nulout,*) 'VSTRETCH_AXIS2: F_margin=',F_margin write(nulout,*) 'VSTRETCH_AXIS2: F_nxla=',F_nxla write(nulout,*) 'VSTRETCH_AXIS2: F_nimax+F_margin+F_nxla=', & F_nimax+F_margin+F_nxla write(nulout,*) 'VSTRETCH_AXIS2: NX-F_nimax=',NX-F_nimax !cluc do i=F_nimax+F_margin+F_nxla,NX-F_nimax ! upper limit = NX in LU mode! must reduce by 1 do i=F_nimax+F_margin+F_nxla,NX-F_nimax-1 hx = amp_8 * hx x2 = x2 + hx F_x_8(i+1) = x2 enddo if ( hxmax/hx .gt. amp_8 .and. F_nimax .ne. 0 ) then print *,'STRETCH_AXIS ERROR: ', % ' problem with amplification factor ' vstretch_axis2 = -1 return endif C NOTING IS DONE HERE IF F_nimax=0 C compute grid points in the upper limit uniform C resolution area to the left or bottom end of grid do i=F_nimax,1,-1 F_x_8(i)=F_x_8(i+1)-hxmax enddo C NOTING IS DONE HERE IF F_nimax=0 C compute grid points in the upper limit uniform C resolution area to the right or top end of grid do i=NX-F_nimax+1,NX F_x_8(i)=F_x_8(i-1)+hxmax enddo if (F_print_L) then print *,'x = ',(F_x_8(i),i=1,NX) print *,'F_x_8(end)-F_x_8(beg) = ', (F_x_8(NX) - F_x_8(1)) print *,'*' print *,'*** vstretch_axis(end) *******' print *,'*' endif vstretch_axis2 = 0 F_amp = amp_8 F_dxla = F_dxla_8 F_margin = F_margin + F_nimax return end * ***function: QQQROOT3 - finds a root of a0+r+r**2+...+r**(m-1)+am*r**m=0., * using at most nit iterations of bodewigs method, * with initial guess r = x or computed. *
real*8 function qqqroot3( x, a0, am, m, nit, eps, it, e ) 2 implicit none real*8 a0, am, x, eps integer m, nit, it * *author j. cote - august 1995 - modification of root2x -> root2 * *arguments * in - x - first guess, if x > 0 * - a0 - constant coefficient of equation * - am - coefficient of r ** m * - m - degree of polynomial equation * - nit - max no. of iterations * - eps - accuracy of the root * out - it - no of iter. taken, failure flag if < 0 * ** *---------------------------------------------------------------------- real*8 f, fp, fs, e, de, fm *---------------------------------------------------------------------- * it = 0 if ( x .gt. 0.0 ) then * qqqroot3 = x e = qqqroot3 - 1.0 * else * * compute first guess assuming e is near 0.0 * * coefficients of power series * * c0 = a0 + m - 1 + am * c1 = m * ( m - 1 + 2 * am )/2 * c2 = m * ( m - 1 ) * ( m - 2 + 3 * am )/6 * c3 = m * ( m - 1 ) * ( m - 2 ) * ( m - 3 + 4 * am )/24 * fm = m * f = - c0/c1 f = - 2.0 * ( a0 + am + fm - 1.0 )/ % ( fm * ( fm - 1.0 + 2.0 * am ) ) * fp = + c2/c1 fp = ( fm - 1.0 ) * ( fm + 3.0 * am - 2.0 )/ % ( 3.0 * ( fm - 1.0 + 2.0 * am ) ) * fs = + c3/c1 fs = ( fm - 1.0 ) * ( fm - 2.0 ) * ( fm - 3.0 + 4.0 * am )/ % ( 12.0 * ( fm - 1.0 + 2.0 * am ) ) * * first order estimate * * second order estimate * e = f/( 0.5 + sqrt( 0.25 + fp * f ) ) * * third order estimate * e = f/( 1.0 + e * ( fp + e * fs ) ) qqqroot3 = 1.0 + e * endif * do 200 it=1,nit * de = qqqroot3 ** ( m - 2 ) f = a0 + qqqroot3 * ( ( qqqroot3 * de - 1.0 )/e + % am * qqqroot3 * de ) fs = ( ( ( fm - 1.0 ) * e - 1.0 ) * qqqroot3 * de + 1.0 )/ % (e**2) fp = fs + am * fm * qqqroot3 * de fs = ( fm * ( fm - 1.0 ) * ( 1.0 + am * e ) * de - 2.0 * fs )/e * * bodewigs method for correcting the root ( 3rd order convergence ) * de = - f / fp de = - f / ( fp + 0.5 * fs * de ) e = e + de qqqroot3 = 1.0 + e * if ( abs(de) .le. eps ) return * 200 continue it = - nit * *---------------------------------------------------------------------- * return end