grid_tools 1.14.0
Loading...
Searching...
No Matches
pesg.f90
Go to the documentation of this file.
1
4
15module pesg
16!=============================================================================
17use pkind, only: spi,dp
18use pietc, only: f,t,u0,u1,u2,o2,rtod,dtor,pih,pi2
19implicit none
20private
24
25interface xctoxs; module procedure xctoxs; end interface
26interface xstoxc; module procedure xstoxc,xstoxc1; end interface
27interface xstoxt; module procedure xstoxt; end interface
28interface xttoxs; module procedure xttoxs,xttoxs1; end interface
29interface xttoxm; module procedure xttoxm; end interface
30interface zttozm; module procedure zttozm; end interface
31interface xmtoxt; module procedure xmtoxt,xmtoxt1; end interface
32interface zmtozt; module procedure zmtozt,zmtozt1; end interface
33interface xctoxm_ak; module procedure xctoxm_ak; end interface
34interface xmtoxc_ak
35 module procedure xmtoxc_ak,xmtoxc_vak,xmtoxc_vak1; end interface
36interface get_edges; module procedure get_edges; end interface
37interface get_qx; module procedure get_qx,get_qxd; end interface
38interface get_qofv;module procedure get_qofv,get_qofvd,get_qsofvs;end interface
39interface get_meanq; module procedure get_meanqd,get_meanqs; end interface
40interface guessak_map; module procedure guessak_map; end interface
41interface guessak_geo; module procedure guessak_geo; end interface
42interface bestesg_geo; module procedure bestesg_geo; end interface
43interface bestesg_map; module procedure bestesg_map; end interface
44interface hgrid_ak_rr;module procedure hgrid_ak_rr,hgrid_ak_rr_c; end interface
45interface hgrid_ak_rc; module procedure hgrid_ak_rc; end interface
46interface hgrid_ak_dd;module procedure hgrid_ak_dd,hgrid_ak_dd_c; end interface
47interface hgrid_ak_dc; module procedure hgrid_ak_dc; end interface
48interface hgrid_ak; module procedure hgrid_ak,hgrid_ak_c; end interface
49interface gtoxm_ak_rr
50 module procedure gtoxm_ak_rr_m,gtoxm_ak_rr_g; end interface
51interface gtoxm_ak_dd
52 module procedure gtoxm_ak_dd_m,gtoxm_ak_dd_g; end interface
53interface xmtog_ak_rr
54 module procedure xmtog_ak_rr_m,xmtog_ak_rr_g; end interface
55interface xmtog_ak_dd
56 module procedure xmtog_ak_dd_m,xmtog_ak_dd_g; end interface
57
58interface gaulegh; module procedure gaulegh; end interface
59
60contains
61
67subroutine xctoxs(xc,xs)! [xctoxs]
68implicit none
69real(dp),dimension(3),intent(in ):: xc
70real(dp),dimension(2),intent(out):: xs
71real(dp):: zp
72zp=u1+xc(3); xs=xc(1:2)/zp
73end subroutine xctoxs
74
84subroutine xstoxc(xs,xc,xcd)! [xstoxc]
85use pmat4, only: outer_product
86implicit none
87real(dp),dimension(2), intent(in ):: xs
88real(dp),dimension(3), intent(out):: xc
89real(dp),dimension(3,2),intent(out):: xcd
90real(dp):: zp
91zp=u2/(u1+dot_product(xs,xs)); xc(1:2)=xs*zp; xc(3)=zp
92xcd=-outer_product(xc,xs)*zp; xcd(1,1)=xcd(1,1)+zp; xcd(2,2)=xcd(2,2)+zp
93xc(3)=xc(3)-u1
94end subroutine xstoxc
95
106subroutine xstoxc1(xs,xc,xcd,xcdd)! [xstoxc]
107use pmat4, only: outer_product
108implicit none
109real(dp),dimension(2), intent(in ):: xs
110real(dp),dimension(3), intent(out):: xc
111real(dp),dimension(3,2), intent(out):: xcd
112real(dp),dimension(3,2,2),intent(out):: xcdd
113real(dp),dimension(3,2):: zpxcdxs
114real(dp),dimension(3) :: zpxc
115real(dp) :: zp
116integer(spi) :: i
117zp=u2/(u1+dot_product(xs,xs)); xc(1:2)=xs*zp; xc(3)=zp
118xcd=-outer_product(xc,xs)*zp
119zpxc=zp*xc; xc(3)=xc(3)-u1; xcdd=u0
120do i=1,2
121 zpxcdxs=xcd*xc(i)
122 xcdd(:,i,i)=xcdd(:,i,i)-zpxc
123 xcdd(:,i,:)=xcdd(:,i,:)-zpxcdxs
124 xcdd(:,:,i)=xcdd(:,:,i)-zpxcdxs
125 xcdd(i,:,i)=xcdd(i,:,i)-zpxc(1:2)
126 xcdd(i,i,:)=xcdd(i,i,:)-zpxc(1:2)
127enddo
128do i=1,2; xcd(i,i)=xcd(i,i)+zp; enddo
129end subroutine xstoxc1
130
138subroutine xstoxt(k,xs,xt,ff)! [xstoxt]
139implicit none
140real(dp), intent(in ):: k
141real(dp),dimension(2),intent(in ):: xs
142real(dp),dimension(2),intent(out):: xt
143logical, intent(out):: ff
144real(dp):: s,sc
145s=k*(xs(1)*xs(1)+xs(2)*xs(2)); sc=u1-s
146ff=abs(s)>=u1; if(ff)return
147xt=u2*xs/sc
148end subroutine xstoxt
149
158subroutine xttoxs(k,xt,xs,xsd,ff)! [xttoxs
159use pmat4, only: outer_product
160implicit none
161real(dp), intent(in ):: k
162real(dp),dimension(2), intent(in ):: xt
163real(dp),dimension(2), intent(out):: xs
164real(dp),dimension(2,2),intent(out):: xsd
165logical, intent(out):: ff
166real(dp),dimension(2):: rspd
167real(dp) :: s,sp,rsp,rsppi,rsppis
168integer(spi) :: i
169s=k*dot_product(xt,xt); sp=u1+s
170ff=(sp<=u0); if(ff)return
171rsp=sqrt(sp)
172rsppi=u1/(u1+rsp)
173rsppis=rsppi**2
174xs=xt*rsppi
175rspd=k*xt/rsp
176xsd=-outer_product(xt,rspd)*rsppis
177do i=1,2; xsd(i,i)=xsd(i,i)+rsppi; enddo
178end subroutine xttoxs
179
192subroutine xttoxs1(k,xt,xs,xsd,xsdd,xs1,xsd1,ff)! [xttoxs]
193use pmat4, only: outer_product
194implicit none
195real(dp), intent(in ):: k
196real(dp),dimension(2), intent(in ):: xt
197real(dp),dimension(2), intent(out):: xs ,xs1
198real(dp),dimension(2,2), intent(out):: xsd,xsd1
199real(dp),dimension(2,2,2),intent(out):: xsdd
200logical, intent(out):: ff
201real(dp),dimension(2,2):: rspdd
202real(dp),dimension(2) :: rspd,rspd1,rsppid
203real(dp) :: s,sp,rsp,rsppi,rsppis,s1,rsp1
204integer(spi) :: i
205s1=dot_product(xt,xt); s=k*s1; sp=u1+s
206ff=(sp<=u0); if(ff)return
207rsp=sqrt(sp); rsp1=o2*s1/rsp
208rsppi=u1/(u1+rsp); rsppis=rsppi**2
209xs=xt*rsppi; xs1=-xt*rsp1*rsppis
210rspd=k*xt/rsp; rspd1=(xt*rsp-k*xt*rsp1)/sp
211rsppid=-rspd*rsppis
212xsd1=-outer_product(xt,rspd1-u2*rspd*rsp1*rsppi)
213do i=1,2; xsd1(i,i)=xsd1(i,i)-rsp1; enddo; xsd1=xsd1*rsppis
214
215xsd=-outer_product(xt,rspd)*rsppis
216do i=1,2; xsd(i,i)=xsd(i,i)+rsppi; enddo
217
218rspdd=-outer_product(xt,rspd)*rsppi
219xsdd=u0
220do i=1,2; xsdd(i,:,i)= rsppid; enddo
221do i=1,2; xsdd(i,i,:)=xsdd(i,i,:)+rsppid; enddo
222do i=1,2; xsdd(:,:,i)=xsdd(:,:,i)+u2*rspdd*rsppid(i); enddo
223do i=1,2; rspdd(i,i)=rspdd(i,i)+rsp*rsppi; enddo
224do i=1,2; xsdd(i,:,:)=xsdd(i,:,:)-xt(i)*rspdd*rsppi*k/sp; enddo
225end subroutine xttoxs1
226
234subroutine xttoxm(a,xt,xm,ff)! [xttoxm]
235implicit none
236real(dp), intent(in ):: a
237real(dp),dimension(2),intent(in ):: xt
238real(dp),dimension(2),intent(out):: xm
239logical ,intent(out):: ff
240integer(spi):: i
241do i=1,2; call zttozm(a,xt(i),xm(i),ff); if(ff)return; enddo
242end subroutine xttoxm
243
253subroutine xmtoxt(a,xm,xt,xtd,ff)! [xmtoxt]
254implicit none
255real(dp), intent(in ):: a
256real(dp),dimension(2), intent(in ):: xm
257real(dp),dimension(2), intent(out):: xt
258real(dp),dimension(2,2),intent(out):: xtd
259logical, intent(out):: ff
260integer(spi):: i
261xtd=u0; do i=1,2; call zmtozt(a,xm(i),xt(i),xtd(i,i),ff); if(ff)return; enddo
262end subroutine xmtoxt
263
275subroutine xmtoxt1(a,xm,xt,xtd,xt1,xtd1,ff)! [xmtoxt]
276implicit none
277real(dp), intent(in ):: a
278real(dp),dimension(2), intent(in ):: xm
279real(dp),dimension(2), intent(out):: xt,xt1
280real(dp),dimension(2,2), intent(out):: xtd,xtd1
281logical, intent(out):: ff
282integer(spi):: i
283xtd=u0
284xtd1=u0
285do i=1,2
286 call zmtozt1(a,xm(i),xt(i),xtd(i,i),xt1(i),xtd1(i,i),ff)
287 if(ff)return
288enddo
289end subroutine xmtoxt1
290
298subroutine zttozm(a,zt,zm,ff)! [zttozm]
299implicit none
300real(dp),intent(in ):: a,zt
301real(dp),intent(out):: zm
302logical, intent(out):: ff
303real(dp):: ra,razt
304ff=f
305if (a>u0)then; ra=sqrt( a); razt=ra*zt; zm=atan(razt)/ra
306elseif(a<u0)then; ra=sqrt(-a); razt=ra*zt; ff=abs(razt)>=u1; if(ff)return
307 zm=atanh(razt)/ra
308else ; zm=zt
309endif
310end subroutine zttozm
311
322subroutine zmtozt(a,zm,zt,ztd,ff)! [zmtozt]
323implicit none
324real(dp),intent(in ):: a,zm
325real(dp),intent(out):: zt,ztd
326logical, intent(out):: ff
327real(dp):: ra
328ff=f
329if (a>u0)then; ra=sqrt( a); zt=tan(ra*zm)/ra; ff=abs(ra*zm)>=pih
330elseif(a<u0)then; ra=sqrt(-a); zt=tanh(ra*zm)/ra
331else ; zt=zm
332endif
333ztd=u1+a*zt*zt
334end subroutine zmtozt
335
347subroutine zmtozt1(a,zm,zt,ztd,zt1,ztd1,ff)! [zmtozt]
348use pietc, only: o3
349use pfun, only: sinoxm,sinox,sinhoxm,sinhox
350implicit none
351real(dp),intent(in ):: a,zm
352real(dp),intent(out):: zt,ztd,zt1,ztd1
353logical, intent(out):: ff
354real(dp):: ra,rad,razm
355ff=f
356if (a>u0)then;ra=sqrt( a);razm=ra*zm; zt=tan(razm)/ra; ff=abs(razm)>=pih
357rad=o2/ra
358zt1=(rad*zm/ra)*((-u2*sin(razm*o2)**2-sinoxm(razm))/cos(razm)+(tan(razm))**2)
359elseif(a<u0)then;ra=sqrt(-a);razm=ra*zm; zt=tanh(razm)/ra
360rad=-o2/ra
361zt1=(rad*zm/ra)*((u2*sinh(razm*o2)**2-sinhoxm(razm))/cosh(razm)-(tanh(razm))**2)
362else ;zt=zm; zt1=zm**3*o3
363endif
364ztd=u1+a*zt*zt
365ztd1=zt*zt +u2*a*zt*zt1
366end subroutine zmtozt1
367
380subroutine xmtoxc_vak(ak,xm,xc,xcd,ff)! [xmtoxc_ak]
381implicit none
382real(dp),dimension(2), intent(in ):: ak,xm
383real(dp),dimension(3), intent(out):: xc
384real(dp),dimension(3,2),intent(out):: xcd
385logical, intent(out):: ff
386call xmtoxc_ak(ak(1),ak(2),xm,xc,xcd,ff)
387end subroutine xmtoxc_vak
388
399subroutine xmtoxc_vak1(ak,xm,xc,xcd,xc1,xcd1,ff)! [xmtoxc_ak]
400implicit none
401real(dp),dimension(2), intent(in ):: ak,xm
402real(dp),dimension(3), intent(out):: xc
403real(dp),dimension(3,2), intent(out):: xcd
404real(dp),dimension(3,2), intent(out):: xc1
405real(dp),dimension(3,2,2),intent(out):: xcd1
406logical, intent(out):: ff
407real(dp),dimension(3,2,2):: xcdd
408real(dp),dimension(2,2,2):: xsd1,xsdd
409real(dp),dimension(2,2) :: xtd,xsd,xs1,xtd1,xsdk,mat22
410real(dp),dimension(2) :: xt,xt1,xs,xsk
411integer(spi) :: i
412call xmtoxt1(ak(1),xm,xt,xtd,xt1,xtd1,ff); if(ff)return
413call xttoxs1(ak(2),xt,xs,xsd,xsdd,xsk,xsdk,ff); if(ff)return
414xs1(:,2)=xsk; xs1(:,1)=matmul(xsd,xt1)
415mat22=xsdd(:,:,1)*xt1(1)+xsdd(:,:,2)*xt1(2)
416xsd1(:,:,1)=matmul(xsd,xtd1)+matmul(mat22,xtd)
417xsd1(:,:,2)=matmul(xsdk,xtd)
418xsd=matmul(xsd,xtd)
419call xstoxc(xs,xc,xcd,xcdd)
420xc1=matmul(xcd,xs1)
421do i=1,3; xcd1(i,:,:)=matmul(transpose(xsd),matmul(xcdd(i,:,:),xs1)); enddo
422do i=1,2; xcd1(:,:,i)=xcd1(:,:,i)+matmul(xcd,xsd1(:,:,i)); enddo
423xcd=matmul(xcd,xsd)
424end subroutine xmtoxc_vak1
425
439subroutine xmtoxc_ak(a,k,xm,xc,xcd,ff)! [xmtoxc_ak]
440implicit none
441real(dp), intent(in ):: a,k
442real(dp),dimension(2), intent(in ):: xm
443real(dp),dimension(3), intent(out):: xc
444real(dp),dimension(3,2),intent(out):: xcd
445logical, intent(out):: ff
446real(dp),dimension(2,2):: xtd,xsd
447real(dp),dimension(2) :: xt,xs
448call xmtoxt(a,xm,xt,xtd,ff); if(ff)return
449call xttoxs(k,xt,xs,xsd,ff); if(ff)return
450xsd=matmul(xsd,xtd)
451call xstoxc(xs,xc,xcd)
452xcd=matmul(xcd,xsd)
453end subroutine xmtoxc_ak
454
465subroutine xctoxm_ak(a,k,xc,xm,ff)! [xctoxm_ak]
466implicit none
467real(dp), intent(in ):: a,k
468real(dp),dimension(3),intent(in ):: xc
469real(dp),dimension(2),intent(out):: xm
470logical, intent(out):: ff
471real(dp),dimension(2):: xs,xt
472ff=f
473call xctoxs(xc,xs)
474call xstoxt(k,xs,xt,ff); if(ff)return
475call xttoxm(a,xt,xm,ff)
476end subroutine xctoxm_ak
477
488subroutine get_edges(arcx,arcy,edgex,edgey)! [get_edges]
489implicit none
490real(dp), intent(in ):: arcx,arcy
491real(dp),dimension(3),intent(out):: edgex,edgey
492real(dp):: cx,sx,cy,sy,rarcx,rarcy
493rarcx=arcx*dtor; rarcy=arcy*dtor
494cx=cos(rarcx); sx=sin(rarcx)
495cy=cos(rarcy); sy=sin(rarcy)
496edgex=(/sx,u0,cx/); edgey=(/u0,sy,cy/)
497end subroutine get_edges
498
511subroutine get_qx(j0, v1,v2,v3,v4)! [get_qx]
512use psym2, only: logsym2
513implicit none
514real(dp),dimension(3,2),intent(in ):: j0
515real(dp), intent(out):: v1,v2,v3,v4
516real(dp),dimension(2,2):: el,g
517g=matmul(transpose(j0),j0)
518call logsym2(g,el); el=el*o2
519v1=el(1,1)**2+u2*el(1,2)**2+el(2,2)**2
520v2=el(1,1)
521v3=el(2,2)
522v4=(el(1,1)+el(2,2))**2
523end subroutine get_qx
524
541subroutine get_qxd(j0,j0d, v1,v2,v3,v4,v1d,v2d,v3d,v4d)! [get_qx]
542use psym2, only: logsym2
543implicit none
544real(dp),dimension(3,2), intent(in ):: j0
545real(dp),dimension(3,2,2),intent(in ):: j0d
546real(dp), intent(out):: v1,v2,v3,v4
547real(dp),dimension(2), intent(out):: v1d,v2d,v3d,v4d
548real(dp),dimension(2,2,2,2):: deldg
549real(dp),dimension(2,2,2) :: eld,gd
550real(dp),dimension(2,2) :: el,g
551integer(spi) :: i,j,k
552g=matmul(transpose(j0),j0)
553do i=1,2
554 gd(:,:,i)=matmul(transpose(j0d(:,:,i)),j0)+matmul(transpose(j0),j0d(:,:,i))
555enddo
556call logsym2(g,el,deldg); el=el*o2; deldg=deldg*o2
557eld=u0
558do i=1,2; do j=1,2; do k=1,2
559 eld(:,:,k)=eld(:,:,k)+deldg(:,:,i,j)*gd(i,j,k)
560enddo ; enddo ; enddo
561v1=el(1,1)**2+u2*el(1,2)**2+el(2,2)**2
562v2=el(1,1)
563v3=el(2,2)
564v4=(el(1,1)+el(2,2))**2
565v1d=u2*(el(1,1)*eld(1,1,:)+u2*el(1,2)*eld(1,2,:)+el(2,2)*eld(2,2,:))
566v2d=eld(1,1,:)
567v3d=eld(2,2,:)
568v4d=u2*(el(1,1)+el(2,2))*(eld(1,1,:)+eld(2,2,:))
569end subroutine get_qxd
570
602subroutine get_meanqd(ngh,lam,xg,wg,ak,ma, q,qdak,qdma, & ! [get_meanq]
603 ga,gadak,gadma, ff)
604implicit none
605integer(spi), intent(in ):: ngh
606real(dp), intent(in ):: lam
607real(dp),dimension(ngh),intent(in ):: xg,wg
608real(dp),dimension(2) ,intent(in ):: ak,ma
609real(dp), intent(out):: q
610real(dp),dimension(2), intent(out):: qdak,qdma
611real(dp),dimension(2), intent(out):: ga
612real(dp),dimension(2,2),intent(out):: gadak,gadma
613logical, intent(out):: ff
614real(dp),dimension(3,2,2):: xcd1
615real(dp),dimension(3,2) :: xcd,xc1
616real(dp),dimension(3) :: xc
617real(dp),dimension(2) :: xm, v1dxy,v2dxy,v3dxy,v4dxy, &
618 v1dL,v2dL,v3dL,v4dL, v1d,v2d,v3d,v4d
619real(dp) :: wx,wy, &
620 v1xy,v2xy,v3xy,v4xy, v1L,v2L,v3L,v4L, v1,v2,v3,v4
621integer(spi) :: i,ic,ix,iy
622v1 =u0; v2 =u0; v3 =u0; v4 =u0
623v1d=u0; v2d=u0; v3d=u0; v4d=u0
624do iy=1,ngh
625 wy=wg(iy)
626 xm(2)=ma(2)*xg(iy)
627 v1l =u0; v2l =u0; v3l =u0; v4l =u0
628 v1dl=u0; v2dl=u0; v3dl=u0; v4dl=u0
629 do ix=1,ngh
630 wx=wg(ix)
631 xm(1)=ma(1)*xg(ix)
632 call xmtoxc_ak(ak,xm,xc,xcd,xc1,xcd1,ff); if(ff)return
633 call get_qx(xcd,xcd1, v1xy,v2xy,v3xy,v4xy, v1dxy,v2dxy,v3dxy,v4dxy)
634 v1l =v1l +wx*v1xy; v2l =v2l +wx*v2xy
635 v3l =v3l +wx*v3xy; v4l =v4l +wx*v4xy
636 v1dl=v1dl+wx*v1dxy;v2dl=v2dl+wx*v2dxy
637 v3dl=v3dl+wx*v3dxy;v4dl=v4dl+wx*v4dxy
638 enddo
639 v1 =v1 +wy*v1l; v2 =v2 +wy*v2l; v3 =v3 +wy*v3l; v4 =v4 +wy*v4l
640 v1d=v1d+wy*v1dl; v2d=v2d+wy*v2dl; v3d=v3d+wy*v3dl; v4d=v4d+wy*v4dl
641enddo
642call get_qofv(lam,v1,v2,v3,v4, q)! <- Q(lam) based on the v1,v2,v3,v4
643call get_qofv(lam,v2,v3, v1d,v2d,v3d,v4d, qdak)! <- Derivative of Q wrt ak
644! Derivatives of ga wrt ak, and of q and ga wrt ma:
645gadma=u0! <- needed because only diagonal elements are filled
646do i=1,2
647 ic=3-i
648 xm=0; xm(i)=ma(i)
649 call xmtoxc_ak(ak,xm,xc,xcd,xc1,xcd1,ff); if(ff)return
650 ga(i)=atan2(xc(i),xc(3))*rtod
651 gadak(i,:)=(xc(3)*xc1(i,:)-xc(i)*xc1(3,:))*rtod
652 gadma(i,i)=(xc(3)*xcd(i,i)-xc(i)*xcd(3,i))*rtod
653
654 v1l=u0; v2l=u0; v3l=u0; v4l=u0
655 do iy=1,ngh
656 wy=wg(iy)
657 xm(ic)=ma(ic)*xg(iy)
658 call xmtoxc_ak(ak,xm,xc,xcd,ff); if(ff)return
659 call get_qx(xcd, v1xy,v2xy,v3xy,v4xy)
660 v1l=v1l+wy*v1xy; v2l=v2l+wy*v2xy; v3l=v3l+wy*v3xy; v4l=v4l+wy*v4xy
661 enddo
662 v1d(i)=(v1l-v1)/ma(i); v2d(i)=(v2l-v2)/ma(i)
663 v3d(i)=(v3l-v3)/ma(i); v4d(i)=(v4l-v4)/ma(i)
664enddo
665call get_qofv(lam,v2,v3, v1d,v2d,v3d,v4d, qdma)
666end subroutine get_meanqd
667
681subroutine get_meanqs(n,ngh,lam,xg,wg,aks,mas, qs,ff)! [get_meanq]
682implicit none
683integer(spi), intent(in ):: n,ngh
684real(dp),dimension(ngh),intent(in ):: xg,wg
685real(dp), intent(in ):: lam
686real(dp),dimension(2,n),intent(in ):: aks,mas
687real(dp),dimension(n), intent(out):: qs
688logical, intent(out):: ff
689real(dp),dimension(n) :: v1s,v2s,v3s,v4s
690real(dp),dimension(n) :: v1sL,v2sL,v3sL,v4sL
691real(dp),dimension(3,2):: xcd
692real(dp),dimension(3) :: xc
693real(dp),dimension(2) :: xm,xgs
694real(dp) :: wx,wy, v1xy,v2xy,v3xy,v4xy
695integer(spi) :: i,ix,iy
696v1s=u0; v2s=u0; v3s=u0; v4s=u0
697do iy=1,ngh
698 wy=wg(iy)
699 v1sl=u0; v2sl=u0; v3sl=u0; v4sl=u0
700 do ix=1,ngh
701 wx=wg(ix)
702 xgs=(/xg(ix),xg(iy)/)
703 do i=1,n
704 xm=mas(:,i)*xgs
705 call xmtoxc_ak(aks(:,i),xm,xc,xcd,ff); if(ff)return
706 call get_qx(xcd,v1xy,v2xy,v3xy,v4xy)
707 v1sl(i)=v1sl(i)+wx*v1xy; v2sl(i)=v2sl(i)+wx*v2xy
708 v3sl(i)=v3sl(i)+wx*v3xy; v4sl(i)=v4sl(i)+wx*v4xy
709 enddo
710 enddo
711 v1s=v1s+wy*v1sl; v2s=v2s+wy*v2sl; v3s=v3s+wy*v3sl; v4s=v4s+wy*v4sl
712enddo
713call get_qofv(n,lam,v1s,v2s,v3s,v4s, qs)
714end subroutine get_meanqs
715
728subroutine get_qofv(lam,v1,v2,v3,v4, q)! [get_qofv]
729implicit none
730real(dp),intent(in ):: lam,v1,v2,v3,v4
731real(dp),intent(out):: q
732real(dp):: lamc
733lamc=u1-lam
734q=lamc*(v1-(v2**2+v3**2)) +lam*(v4 -(v2+v3)**2)
735end subroutine get_qofv
736
750subroutine get_qofvd(lam, v2,v3, v1d,v2d,v3d,v4d, qd)! [get_qofv]
751implicit none
752real(dp), intent(in ):: lam,v2,v3
753real(dp),dimension(2),intent(in ):: v1d,v2d,v3d,v4d
754real(dp),dimension(2),intent(out):: qd
755real(dp):: lamc
756lamc=u1-lam
757qd=lamc*(v1d-u2*(v2d*v2+v3d*v3))+lam*(v4d-u2*(v2d+v3d)*(v2+v3))
758end subroutine get_qofvd
759
770subroutine get_qsofvs(n,lam,v1s,v2s,v3s,v4s, qs)! [get_qofv]
771implicit none
772integer(spi), intent(in ):: n
773real(dp), intent(in ):: lam
774real(dp),dimension(n),intent(in ):: v1s,v2s,v3s,v4s
775real(dp),dimension(n),intent(out):: qs
776real(dp):: lamc
777lamc=u1-lam
778qs=lamc*(v1s-(v2s**2+v3s**2)) +lam*(v4s -(v2s+v3s)**2)
779end subroutine get_qsofvs
780
790subroutine guessak_map(asp,tmarcx,ak)! [guessak_map]
791implicit none
792real(dp), intent(in ):: asp,tmarcx
793real(dp),dimension(2),intent(out):: ak
794real(dp):: gmarcx
795gmarcx=tmarcx*rtod
796call guessak_geo(asp,gmarcx,ak)
797end subroutine guessak_map
798
808subroutine guessak_geo(asp,arc,ak)! [guessak_geo]
809implicit none
810real(dp), intent(in ):: asp,arc
811real(dp),dimension(2),intent(out):: ak
812integer(spi),parameter :: narc=11,nasp=10! <- Table index bounds
813real(dp), parameter :: eps=1.e-7_dp,darc=10._dp+eps,dasp=.1_dp+eps
814real(dp),dimension(nasp,0:narc):: adarc,kdarc
815real(dp) :: sasp,sarc,wx0,wx1,wa0,wa1
816integer(spi) :: iasp0,iasp1,iarc0,iarc1
817!------------------------
818! Tables of approximate A (adarc) and K (kdarc), valid for lam=0.8, for aspect ratio,
819! asp, at .1, .2, .3, .4, .5, .6, .7, .8, 1. and major semi-arc, arcx, at values,
820! 0 (nominally), 10., ..., 100. degrees (where the nominal "0" angle is actually
821! from a computation at 3 degrees, since zero would not make sense).
822! The 100 degree rows are repeated as the 110 degree entries deliberately to pad the
823! table into the partly forbidden parameter space to allow skinny domains of up to
824! 110 degree semi-length to be validly endowed with optimal A and K:
825data adarc/ &
826-.450_dp,-.328_dp,-.185_dp,-.059_dp,0.038_dp,0.107_dp,0.153_dp,0.180_dp,0.195_dp,0.199_dp,&
827-.452_dp,-.327_dp,-.184_dp,-.058_dp,0.039_dp,0.108_dp,0.154_dp,0.182_dp,0.196_dp,0.200_dp,&
828-.457_dp,-.327_dp,-.180_dp,-.054_dp,0.043_dp,0.112_dp,0.158_dp,0.186_dp,0.200_dp,0.205_dp,&
829-.464_dp,-.323_dp,-.173_dp,-.047_dp,0.050_dp,0.118_dp,0.164_dp,0.192_dp,0.208_dp,0.213_dp,&
830-.465_dp,-.313_dp,-.160_dp,-.035_dp,0.060_dp,0.127_dp,0.173_dp,0.202_dp,0.217_dp,0.224_dp,&
831-.448_dp,-.288_dp,-.138_dp,-.017_dp,0.074_dp,0.140_dp,0.184_dp,0.213_dp,0.230_dp,0.237_dp,&
832-.395_dp,-.244_dp,-.104_dp,0.008_dp,0.093_dp,0.156_dp,0.199_dp,0.227_dp,0.244_dp,0.252_dp,&
833-.301_dp,-.177_dp,-.057_dp,0.042_dp,0.119_dp,0.175_dp,0.215_dp,0.242_dp,0.259_dp,0.269_dp,&
834-.185_dp,-.094_dp,0.001_dp,0.084_dp,0.150_dp,0.199_dp,0.235_dp,0.260_dp,0.277_dp,0.287_dp,&
835-.069_dp,-.006_dp,0.066_dp,0.132_dp,0.186_dp,0.227_dp,0.257_dp,0.280_dp,0.296_dp,0.308_dp,&
8360.038_dp,0.081_dp,0.134_dp,0.185_dp,0.226_dp,0.258_dp,0.283_dp,0.303_dp,0.319_dp,0.333_dp,&
8370.038_dp,0.081_dp,0.134_dp,0.185_dp,0.226_dp,0.258_dp,0.283_dp,0.303_dp,0.319_dp,0.333_dp/
838
839data kdarc/ &
840-.947_dp,-.818_dp,-.668_dp,-.535_dp,-.433_dp,-.361_dp,-.313_dp,-.284_dp,-.269_dp,-.264_dp,&
841-.946_dp,-.816_dp,-.665_dp,-.533_dp,-.431_dp,-.359_dp,-.311_dp,-.282_dp,-.267_dp,-.262_dp,&
842-.942_dp,-.806_dp,-.655_dp,-.524_dp,-.424_dp,-.353_dp,-.305_dp,-.276_dp,-.261_dp,-.255_dp,&
843-.932_dp,-.789_dp,-.637_dp,-.509_dp,-.412_dp,-.343_dp,-.296_dp,-.266_dp,-.250_dp,-.244_dp,&
844-.909_dp,-.759_dp,-.609_dp,-.486_dp,-.394_dp,-.328_dp,-.283_dp,-.254_dp,-.237_dp,-.230_dp,&
845-.863_dp,-.711_dp,-.569_dp,-.456_dp,-.372_dp,-.310_dp,-.266_dp,-.238_dp,-.220_dp,-.212_dp,&
846-.779_dp,-.642_dp,-.518_dp,-.419_dp,-.343_dp,-.287_dp,-.247_dp,-.220_dp,-.202_dp,-.192_dp,&
847-.661_dp,-.556_dp,-.456_dp,-.374_dp,-.310_dp,-.262_dp,-.226_dp,-.200_dp,-.182_dp,-.171_dp,&
848-.533_dp,-.462_dp,-.388_dp,-.325_dp,-.274_dp,-.234_dp,-.203_dp,-.179_dp,-.161_dp,-.150_dp,&
849-.418_dp,-.373_dp,-.322_dp,-.275_dp,-.236_dp,-.204_dp,-.178_dp,-.156_dp,-.139_dp,-.127_dp,&
850-.324_dp,-.296_dp,-.261_dp,-.229_dp,-.200_dp,-.174_dp,-.152_dp,-.133_dp,-.117_dp,-.104_dp,&
851-.324_dp,-.296_dp,-.261_dp,-.229_dp,-.200_dp,-.174_dp,-.152_dp,-.133_dp,-.117_dp,-.104_dp/
852!=============================================================================
853sasp=asp/dasp
854iasp0=floor(sasp); wa1=sasp-iasp0
855iasp1=iasp0+1; wa0=iasp1-sasp
856sarc=arc/darc
857iarc0=floor(sarc); wx1=sarc-iarc0
858iarc1=iarc0+1; wx0=iarc1-sarc
859if(iasp0<1 .or. iasp1>nasp)stop 'Guessak_geo; Aspect ratio out of range'
860if(iarc0<0 .or. iarc1>narc)stop 'Guessak_geo; Major semi-arc is out of range'
861
862! Bilinearly interpolate A and K from crude table into a 2-vector:
863ak=(/wx0*(wa0*adarc(iasp0,iarc0)+wa1*adarc(iasp1,iarc0))+ &
864 wx1*(wa0*adarc(iasp0,iarc1)+wa1*adarc(iasp1,iarc1)), &
865 wx0*(wa0*kdarc(iasp0,iarc0)+wa1*kdarc(iasp1,iarc0))+ &
866 wx1*(wa0*kdarc(iasp0,iarc1)+wa1*kdarc(iasp1,iarc1))/)
867end subroutine guessak_geo
868
902subroutine bestesg_geo(lam,garcx,garcy, a,k,marcx,marcy,q,ff)! [bestesg_geo]
903use pietc, only: u5,o5,s18,s36,s54,s72,ms18,ms36,ms54,ms72
904use pmat, only: inv
905use psym2, only: chol2
906implicit none
907real(dp),intent(in ):: lam,garcx,garcy
908real(dp),intent(out):: a,k,marcx,marcy,q
909logical ,intent(out):: FF
910integer(spi),parameter :: nit=200,mit=20,ngh=25
911real(dp) ,parameter :: u2o5=u2*o5,&
912 f18=u2o5*s18,f36=u2o5*s36,f54=u2o5*s54,&
913 f72=u2o5*s72,mf18=-f18,mf36=-f36,mf54=-f54,&
914 mf72=-f72,&
915 r=0.001_dp,rr=r*r,dang=pi2*o5,crit=1.e-14_dp
916real(dp),dimension(ngh) :: wg,xg
917real(dp),dimension(0:4,0:4):: em5 ! <- Fourier matrix for 5 points
918real(dp),dimension(0:4) :: qs
919real(dp),dimension(2,0:4) :: aks,mas
920real(dp),dimension(2,2) :: basis0,basis,hess,el,gadak,gadma,madga,madak
921real(dp),dimension(2) :: ak,dak,dma,vec2,grad,qdak,qdma,ga,ma,gat
922real(dp) :: s,tgarcx,tgarcy,asp,ang
923integer(spi) :: i,it
924logical :: flip
925data em5/o5,u2o5, u0,u2o5, u0,& ! <-The Fourier matrix for 5 points. Applied
926 o5, f18, f72,mf54, f36,& ! to the five 72-degree spaced values in a
927 o5,mf54, f36, f18,mf72,& ! column-vector, the product vector has the
928 o5,mf54,mf36, f18, f72,& ! components, wave-0, cos and sin wave-1,
929 o5, f18,mf72,mf54,mf36/ ! cos and sin wave-2.
930! First guess upper-triangular basis regularizing the samples used to
931! estimate the Hessian of q by finite differencing:
932data basis0/0.1_dp,u0, 0.3_dp,0.3_dp/
933ff=lam<u0 .or. lam>=u1
934if(ff)then; print'("In bestesg_geo; lam out of range")';return; endif
935ff= garcx<=u0 .or. garcy<=u0
936if(ff)then
937 print'("In bestesg_geo; a nonpositive domain parameter, garcx or garcy")'
938 return
939endif
940call gaulegh(ngh,xg,wg)! <- Prepare Gauss-Legendre nodes xg and weights wg
941flip=garcy>garcx
942if(flip)then; tgarcx=garcy; tgarcy=garcx! <- Switch
943else ; tgarcx=garcx; tgarcy=garcy! <- Don't switch
944endif
945ga=(/tgarcx,tgarcy/)
946asp=tgarcy/tgarcx
947basis=basis0
948
949call guessak_geo(asp,tgarcx,ak)
950ma=ga*dtor*0.9_dp ! Shrink first estimate, to start always within bounds
951
952! Perform a Newton iteration (except with imperfect Hessian) to find the
953! parameter vector, ak, at which the derivative of Q at constant geographical
954! semi-axes, ga, as given, goes to zero. The direct evaluation of the
955! Q-derivative at constant ma (which is what is actually computed in
956! get_meanq) therefore needs modification to obtain Q-derivarive at constant
957! ga:
958! dQ/d(ak)|_ga = dQ/d(ak)|_ma - dQ/d(ma)|_ak*d(ma)/d(ga)|_ak*d(ga)/d(ak)|_ma
959!
960! Since the Hessian evaluation is only carried out at constant map-space
961! semi-axes, ma, it is not ideal for this problem; consequently, the allowance
962! of newton iterations, nit, is much more liberal than we allow for the
963! companion routine, bestesg_map, where the constant ma condition WAS
964! appropriate.
965do it=1,nit
966 call get_meanq(ngh,lam,xg,wg,ak,ma,q,qdak,qdma,gat,gadak,gadma,ff)
967 if(ff)return
968 madga=gadma; call inv(madga)! <- d(ma)/d(ga)|_ak ("at constant ak")
969 madak=-matmul(madga,gadak)
970 qdak=qdak+matmul(qdma,madak)! dQ/d(ak)|_ga
971 if(it<=mit)then ! <- Only recompute aks if the basis is new
972! Place five additional sample points around the stencil-ellipse:
973 do i=0,4
974 ang=i*dang ! steps of 72 degrees
975 vec2=(/cos(ang),sin(ang)/)*r ! points on a circle of radius r ...
976 dak=matmul(basis,vec2)
977 dma=matmul(madak,dak)
978 aks(:,i)=ak+dak ! ... become points on an ellipse.
979 mas(:,i)=ma+dma
980 enddo
981 call get_meanq(5,ngh,lam,xg,wg,aks,mas, qs,ff)
982 endif
983 grad=matmul(qdak,basis)/q ! <- New grad estimate, accurate to near roundoff
984 if(it<mit)then ! Assume the hessian will have significantly changed
985! Recover an approximate Hessian estimate, normalized by q, from all
986! 6 samples, q, qs. These are wrt the basis, not (a,k) directly. Note that
987! this finite-difference Hessian is wrt q at constant ak, which is roughly
988! approximating the desired Hessian wrt q at constant ga; the disparity
989! is the reason that we allow more iterations in this routine than in
990! companion routine bestesg_map, since we cannot achieve superlinear
991! convergence in the present case.
992! Make qs the 5-pt discrete Fourier coefficients of the ellipse pts:
993 qs=matmul(em5,qs)/q
994! grad=qs(1:2)/r ! Old finite difference estimate is inferior to new grad
995 qs(0)=qs(0)-u1! <- cos(2*ang) coefficient relative to the central value.
996 hess(1,1)=qs(0)+qs(3)! <- combine cos(0*ang) and cos(2*ang) coefficients
997 hess(1,2)=qs(4) ! <- sin(2*ang) coefficient
998 hess(2,1)=qs(4) !
999 hess(2,2)=qs(0)-qs(3)! <- combine cos(0*ang) and cos(2*ang) coefficients
1000 hess=hess*u2/rr ! <- rr is r**2
1001
1002! Perform a Cholesky decomposition of the hessian:
1003 call chol2(hess,el,ff)
1004 if(ff)then
1005 print'(" In bestESG_geo, Hessian is not positive; cholesky fails")'
1006 return
1007 endif
1008! Invert the cholesky factor in place:
1009 el(1,1)=u1/el(1,1); el(2,2)=u1/el(2,2); el(2,1)=-el(2,1)*el(1,1)*el(2,2)
1010 endif
1011! Estimate a Newton step towards the minimum of function Q(a,k):
1012 vec2=-matmul(transpose(el),matmul(el,grad))
1013 dak=matmul(basis,vec2)
1014 gat=gat+matmul(gadak,dak)! <- increment ga
1015 ak=ak+dak! <- increment the parameter vector estimate
1016 dma=-matmul(madga,gat-ga)
1017 ma=ma+dma
1018
1019! Use the inverse cholesky factor to re-condition the basis. This is to make
1020! the next stencil-ellipse more closely share the shape of the elliptical
1021! contours of Q near its minumum -- essentially a preconditioning of the
1022! numerical optimization:
1023 if(it<mit)basis=matmul(basis,transpose(el))
1024
1025 s=sqrt(dot_product(dak,dak))
1026 if(s<crit)exit ! <-Sufficient convergence of the Newton iteration
1027enddo
1028if(it>nit)print'("WARNING; Relatively inferior convergence in bestesg_geo")'
1029a=ak(1)
1030k=ak(2)
1031if(flip)then; marcx=ma(2); marcy=ma(1)! Remember to switch back
1032else ; marcx=ma(1); marcy=ma(2)! don't switch
1033endif
1034end subroutine bestesg_geo
1035
1072subroutine bestesg_map(lam,marcx,marcy, a,k,garcx,garcy,q,ff) ![bestesg_map]
1073use pietc, only: u5,o5,s18,s36,s54,s72,ms18,ms36,ms54,ms72
1074use psym2, only: chol2
1075implicit none
1076real(dp),intent(in ):: lam,marcx,marcy
1077real(dp),intent(out):: a,k,garcx,garcy,q
1078logical ,intent(out):: FF
1079integer(spi),parameter :: nit=25,mit=7,ngh=25
1080real(dp),parameter :: u2o5=u2*o5, &
1081 f18=u2o5*s18,f36=u2o5*s36,f54=u2o5*s54, &
1082 f72=u2o5*s72,mf18=-f18,mf36=-f36,mf54=-f54,&
1083 mf72=-f72,&
1084 r=0.001_dp,rr=r*r,dang=pi2*o5,crit=1.e-12_dp
1085real(dp),dimension(ngh) :: wg,xg
1086real(dp),dimension(0:4,0:4):: em5 ! <- Fourier matrix for 5 points
1087real(dp),dimension(0:4) :: qs ! <-Sampled q, its Fourier coefficients
1088real(dp),dimension(2,0:4) :: aks,mas! <- tiny elliptical array of ak
1089real(dp),dimension(2,2) :: basis0,basis,hess,el,gadak,gadma
1090real(dp),dimension(2) :: ak,dak,vec2,grad,qdak,qdma,ga,ma
1091real(dp) :: s,tmarcx,tmarcy,asp,ang
1092integer(spi) :: i,it
1093logical :: flip
1094data em5/o5,u2o5, u0,u2o5, u0,& ! <-The Fourier matrix for 5 points. Applied
1095 o5, f18, f72,mf54, f36,& ! to the five 72-degree spaced values in a
1096 o5,mf54, f36, f18,mf72,& ! column-vector, the product vector has the
1097 o5,mf54,mf36, f18, f72,& ! components, wave-0, cos and sin wave-1,
1098 o5, f18,mf72,mf54,mf36/ ! cos and sin wave-2.
1099! First guess upper-triangular basis regularizing the samples used to
1100! estimate the Hessian of q by finite differencing:
1101data basis0/0.1_dp,u0, 0.3_dp,0.3_dp/
1102ff=lam<u0 .or. lam>=u1
1103if(ff)then; print'("In bestesg_map; lam out of range")';return; endif
1104ff= marcx<=u0 .or. marcy<=u0
1105if(ff)then
1106 print'("In bestesg_map; a nonpositive domain parameter, marcx or marcy")'
1107 return
1108endif
1109call gaulegh(ngh,xg,wg)
1110flip=marcy>marcx
1111if(flip)then; tmarcx=marcy; tmarcy=marcx! <- Switch
1112else ; tmarcx=marcx; tmarcy=marcy! <- Don't switch
1113endif
1114ma=(/tmarcx,tmarcy/); do i=0,4; mas(:,i)=ma; enddo
1115asp=tmarcy/tmarcx
1116basis=basis0
1117
1118call guessak_map(asp,tmarcx,ak)
1119
1120do it=1,nit
1121 call get_meanq(ngh,lam,xg,wg,ak,ma,q,qdak,qdma,ga,gadak,gadma,ff)
1122 if(ff)return
1123 if(it<=mit)then
1124! Place five additional sample points around the stencil-ellipse:
1125 do i=0,4
1126 ang=i*dang ! steps of 72 degrees
1127 vec2=(/cos(ang),sin(ang)/)*r ! points on a circle of radius r ...
1128 aks(:,i)=ak+matmul(basis,vec2) ! ... become points on an ellipse.
1129 enddo
1130 call get_meanq(5,ngh,lam,xg,wg,aks,mas, qs,ff)
1131 endif
1132 grad=matmul(qdak,basis)/q ! <- New grad estimate, accurate to near roundoff
1133 if(it<mit)then
1134! Recover Hessian estimate, normalized by q, from all
1135! 6 samples, q, qs. These are wrt the basis, not (a,k) directly.
1136! The Hessian estimate uses a careful finite method, which is accurate
1137! enough. The gradient is NOT estimated by finite differences because we
1138! need the gradient to be accurate to near roundoff levels in order that
1139! the converged Newton iteration is a precise solution.
1140! Make qs the 5-pt discrete Fourier coefficients of the ellipse pts:
1141 qs=matmul(em5,qs)/q
1142! grad=qs(1:2)/r ! Old finite difference estimate is inferior to new grad
1143 qs(0)=qs(0)-u1
1144 hess(1,1)=qs(0)+qs(3)! <- combine cos(0*ang) and cos(2*ang) coefficients
1145 hess(1,2)=qs(4) ! <- sin(2*ang) coefficient
1146 hess(2,1)=qs(4) !
1147 hess(2,2)=qs(0)-qs(3)! <- combine cos(0*ang) and cos(2*ang) coefficients
1148 hess=hess*u2/rr ! <- rr is r**2
1149
1150! Perform a Cholesky decomposition of the hessian:
1151 call chol2(hess,el,ff)
1152 if(ff)then
1153 print'(" In bestESG_map, hessian is not positive; cholesky fails")'
1154 return
1155 endif
1156! Invert the cholesky factor in place:
1157 el(1,1)=u1/el(1,1); el(2,2)=u1/el(2,2); el(2,1)=-el(2,1)*el(1,1)*el(2,2)
1158 endif
1159! Estimate a Newton step towards the minimum of function Q(a,k):
1160 vec2=-matmul(transpose(el),matmul(el,grad))
1161 dak=matmul(basis,vec2)
1162 ga=ga+matmul(gadak,dak)! <- increment ga
1163 ak=ak+dak! <- increment the parameter vector estimate
1164
1165! Use the inverse cholesky factor to re-condition the basis. This is to make
1166! the next stencil-ellipse more closely share the shape of the elliptical
1167! contours of Q near its minumum -- essentially a preconditioning of the
1168! numerical optimization:
1169 if(it<mit)basis=matmul(basis,transpose(el))
1170
1171 s=sqrt(dot_product(dak,dak))
1172 if(s<crit)exit ! <-Sufficient convergence of the Newton iteration
1173enddo
1174if(it>nit)print'("WARNING; Relatively inferior convergence in bestesg_map")'
1175a=ak(1)
1176k=ak(2)
1177if(flip)then; garcx=ga(2); garcy=ga(1)! Remember to switch back
1178else ; garcx=ga(1); garcy=ga(2)! don't switch
1179endif
1180end subroutine bestesg_map
1181
1219subroutine hgrid_ak_rr(lx,ly,nx,ny,A,K,plat,plon,pazi, & ! [hgrid_ak_rr]
1220 delx,dely, glat,glon,garea, ff)
1221use pmat4, only: sarea
1222use pmat5, only: ctogr
1223implicit none
1224integer(spi), intent(in ):: lx,ly,nx,ny
1225real(dp), intent(in ):: a,k,plat,plon,pazi, &
1226 delx,dely
1227real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: glat,glon
1228real(dp),dimension(lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1229logical, intent(out):: ff
1230real(dp),dimension(3,3):: prot,azirot
1231real(dp),dimension(3,2):: xcd
1232real(dp),dimension(3) :: xc
1233real(dp),dimension(2) :: xm
1234real(dp) :: clat,slat,clon,slon,cazi,sazi,&
1235 rlat,drlata,drlatb,drlatc, &
1236 rlon,drlona,drlonb,drlonc
1237integer(spi) :: ix,iy,mx,my
1238clat=cos(plat); slat=sin(plat)
1239clon=cos(plon); slon=sin(plon)
1240cazi=cos(pazi); sazi=sin(pazi)
1241
1242azirot(:,1)=(/ cazi, sazi, u0/)
1243azirot(:,2)=(/-sazi, cazi, u0/)
1244azirot(:,3)=(/ u0, u0, u1/)
1245
1246prot(:,1)=(/ -slon, clon, u0/)
1247prot(:,2)=(/-slat*clon, -slat*slon, clat/)
1248prot(:,3)=(/ clat*clon, clat*slon, slat/)
1249prot=matmul(prot,azirot)
1250mx=lx+nx ! Index of the 'right' edge of the rectangular grid
1251my=ly+ny ! Index of the 'top' edge of the rectangular grid
1252do iy=ly,my
1253 xm(2)=iy*dely
1254 do ix=lx,mx
1255 xm(1)=ix*delx
1256 call xmtoxc_ak(a,k,xm,xc,xcd,ff)
1257 if(ff)return
1258 xcd=matmul(prot,xcd)
1259 xc =matmul(prot,xc )
1260 call ctogr(xc,glat(ix,iy),glon(ix,iy))
1261 enddo
1262enddo
1263
1264! Compute the areas of the quadrilateral grid cells:
1265do iy=ly,my-1
1266 do ix=lx,mx-1
1267 rlat =glat(ix ,iy )
1268 drlata=glat(ix+1,iy )-rlat
1269 drlatb=glat(ix+1,iy+1)-rlat
1270 drlatc=glat(ix ,iy+1)-rlat
1271 rlon =glon(ix ,iy )
1272 drlona=glon(ix+1,iy )-rlon
1273 drlonb=glon(ix+1,iy+1)-rlon
1274 drlonc=glon(ix ,iy+1)-rlon
1275! If 'I' is the grid point (ix,iy), 'A' is (ix+1,iy); 'B' is (ix+1,iy+1)
1276! and 'C' is (ix,iy+1), then the area of the grid cell IABC is the sum of
1277! the areas of the traingles, IAB and IBC (the latter being the negative
1278! of the signed area of triangle, ICB):
1279 garea(ix,iy)=sarea(rlat, drlata,drlona, drlatb,drlonb) &
1280 -sarea(rlat, drlatc,drlonc, drlatb,drlonb)
1281 enddo
1282enddo
1283end subroutine hgrid_ak_rr
1284
1336subroutine hgrid_ak_rr_c(lx,ly,nx,ny,a,k,plat,plon,pazi, & ! [hgrid_ak_rr]
1337 delx,dely, glat,glon,garea,dx,dy,angle_dx,angle_dy, ff)
1339use pmat5, only: ctogr
1340implicit none
1341integer(spi), intent(in ):: lx,ly,nx,ny
1342real(dp), intent(in ):: a,k,plat,plon,pazi, &
1343 delx,dely
1344real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: glat,glon
1345real(dp),dimension(lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1346real(dp),dimension(lx:lx+nx-1,ly:ly+ny ),intent(out):: dx
1347real(dp),dimension(lx:lx+nx ,ly:ly+ny-1),intent(out):: dy
1348real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: angle_dx,angle_dy
1349logical, intent(out):: ff
1350real(dp),dimension(lx-1:lx+nx+1,ly-1:ly+ny+1):: gat ! Temporary area array
1351real(dp),dimension(lx-1:lx+nx+1,ly :ly+ny ):: dxt ! Temporary dx array
1352real(dp),dimension(lx :lx+nx ,ly-1:ly+ny+1):: dyt ! Temporary dy array
1353real(dp),dimension(3,3):: prot,azirot
1354real(dp),dimension(3,2):: xcd,eano
1355real(dp),dimension(2,2):: xcd2
1356real(dp),dimension(3) :: xc,east,north
1357real(dp),dimension(2) :: xm
1358real(dp) :: clat,slat,clon,slon,cazi,sazi,delxy
1359integer(spi) :: ix,iy,mx,my,lxm,lym,mxp,myp
1360delxy=delx*dely
1361clat=cos(plat); slat=sin(plat)
1362clon=cos(plon); slon=sin(plon)
1363cazi=cos(pazi); sazi=sin(pazi)
1364
1365azirot(:,1)=(/ cazi, sazi, u0/)
1366azirot(:,2)=(/-sazi, cazi, u0/)
1367azirot(:,3)=(/ u0, u0, u1/)
1368
1369prot(:,1)=(/ -slon, clon, u0/)
1370prot(:,2)=(/-slat*clon, -slat*slon, clat/)
1371prot(:,3)=(/ clat*clon, clat*slon, slat/)
1372prot=matmul(prot,azirot)
1373
1374mx=lx+nx ! Index of the 'right' edge of the rectangular grid
1375my=ly+ny ! Index of the 'top' edge of the rectangular grid
1376lxm=lx-1; mxp=mx+1 ! Indices of extra left and right edges
1377lym=ly-1; myp=my+1 ! Indices of extra bottom and top edges
1378
1379!-- main body of horizontal grid:
1380do iy=ly,my
1381 xm(2)=iy*dely
1382 do ix=lx,mx
1383 xm(1)=ix*delx
1384 call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1385 xcd=matmul(prot,xcd)
1386 xc =matmul(prot,xc )
1387 call ctogr(xc,glat(ix,iy),glon(ix,iy))
1388 east=(/-xc(2),xc(1),u0/); east=east/sqrt(dot_product(east,east))
1389 north=cross_product(xc,east)
1390 eano(:,1)=east; eano(:,2)=north
1391 xcd2=matmul(transpose(eano),xcd)
1392 angle_dx(ix,iy)=atan2( xcd2(2,1),xcd2(1,1))
1393 angle_dy(ix,iy)=atan2(-xcd2(1,2),xcd2(2,2))
1394 dxt(ix,iy)=sqrt(dot_product(xcd2(:,1),xcd2(:,1)))*delx
1395 dyt(ix,iy)=sqrt(dot_product(xcd2(:,2),xcd2(:,2)))*dely
1396 gat(ix,iy)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1397 enddo
1398enddo
1399
1400!-- extra left edge, gat, dxt only:
1401xm(1)=lxm*delx
1402do iy=ly,my
1403 xm(2)=iy*dely
1404 call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1405 xcd=matmul(prot,xcd)
1406 xc =matmul(prot,xc )
1407 east=(/-xc(2),xc(1),u0/); east=east/sqrt(dot_product(east,east))
1408 north=cross_product(xc,east)
1409 eano(:,1)=east; eano(:,2)=north
1410 xcd2=matmul(transpose(eano),xcd)
1411 dxt(lxm,iy)=sqrt(dot_product(xcd2(:,1),xcd2(:,1)))*delx
1412 gat(lxm,iy)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1413enddo
1414
1415!-- extra right edge, gat, dxt only:
1416xm(1)=mxp*delx
1417do iy=ly,my
1418 xm(2)=iy*dely
1419 call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1420 xcd=matmul(prot,xcd)
1421 xc =matmul(prot,xc )
1422 east=(/-xc(2),xc(1),u0/); east=east/sqrt(dot_product(east,east))
1423 north=cross_product(xc,east)
1424 eano(:,1)=east; eano(:,2)=north
1425 xcd2=matmul(transpose(eano),xcd)
1426 dxt(mxp,iy)=sqrt(dot_product(xcd2(:,1),xcd2(:,1)))*delx
1427 gat(mxp,iy)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1428enddo
1429
1430!-- extra bottom edge, gat, dyt only:
1431xm(2)=lym*dely
1432do ix=lx,mx
1433 xm(1)=ix*delx
1434 call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1435 xcd=matmul(prot,xcd)
1436 xc =matmul(prot,xc )
1437 east=(/-xc(2),xc(1),u0/); east=east/sqrt(dot_product(east,east))
1438 north=cross_product(xc,east)
1439 eano(:,1)=east; eano(:,2)=north
1440 xcd2=matmul(transpose(eano),xcd)
1441 dyt(ix,lym)=sqrt(dot_product(xcd2(:,2),xcd2(:,2)))*dely
1442 gat(ix,lym)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1443enddo
1444
1445!-- extra top edge, gat, dyt only:
1446xm(2)=myp*dely
1447do ix=lx,mx
1448 xm(1)=ix*delx
1449 call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1450 xcd=matmul(prot,xcd)
1451 xc =matmul(prot,xc )
1452 east=(/-xc(2),xc(1),u0/); east=east/sqrt(dot_product(east,east))
1453 north=cross_product(xc,east)
1454 eano(:,1)=east; eano(:,2)=north
1455 xcd2=matmul(transpose(eano),xcd)
1456 dyt(ix,myp)=sqrt(dot_product(xcd2(:,2),xcd2(:,2)))*dely
1457 gat(ix,myp)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1458enddo
1459
1460! Extra four corners, gat only:
1461xm(2)=lym*dely
1462!-- extra bottom left corner:
1463xm(1)=lxm*delx
1464call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1465xcd=matmul(prot,xcd)
1466xc =matmul(prot,xc )
1467gat(lxm,lym)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1468
1469!-- extra bottom right corner:
1470xm(1)=mxp*delx
1471call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1472xcd=matmul(prot,xcd)
1473xc =matmul(prot,xc )
1474gat(mxp,lym)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1475
1476xm(2)=myp*dely
1477!-- extra top left corner:
1478xm(1)=lxm*delx
1479call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1480xcd=matmul(prot,xcd)
1481xc =matmul(prot,xc )
1482gat(lxm,myp)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1483
1484!-- extra top right corner:
1485xm(1)=mxp*delx
1486call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
1487xcd=matmul(prot,xcd)
1488xc =matmul(prot,xc )
1489gat(mxp,myp)=triple_product(xc,xcd(:,1),xcd(:,2))*delxy
1490
1491!-- 4th-order averaging over each central interval using 4-pt. stencils:
1492dx =(13_dp*(dxt(lx :mx-1,:)+dxt(lx+1:mx ,:)) &
1493 -(dxt(lxm:mx-2,:)+dxt(lx+2:mxp,:)))/24_dp
1494dy =(13_dp*(dyt(:,ly :my-1)+dyt(:,ly+1:my )) &
1495 -(dyt(:,lym:my-2)+dyt(:,ly+2:myp)))/24_dp
1496gat(lx:mx-1,:)=(13_dp*(gat(lx :mx-1,:)+gat(lx+1:mx ,:)) &
1497 -(gat(lxm:mx-2,:)+gat(lx+2:mxp,:)))/24_dp
1498garea =(13_dp*(gat(lx:mx-1,ly :my-1)+gat(lx:mx-1,ly+1:my )) &
1499 -(gat(lx:mx-1,lym:my-2)+gat(lx:mx-1,ly+2:myp)))/24_dp
1500end subroutine hgrid_ak_rr_c
1501
1539subroutine hgrid_ak_rc(lx,ly,nx,ny,A,K,plat,plon,pazi, & ! [hgrid_ak_rc]
1540 delx,dely, xc,xcd,garea, ff)
1541use pmat4, only: sarea
1542use pmat5, only: ctogr
1543implicit none
1544integer(spi),intent(in ):: lx,ly,nx,ny
1545real(dp), intent(in ):: a,k,plat,plon,pazi,delx,dely
1546real(dp),dimension(3, lx:lx+nx ,ly:ly+ny ),intent(out):: xc
1547real(dp),dimension(3,2,lx:lx+nx ,ly:ly+ny ),intent(out):: xcd
1548real(dp),dimension( lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1549logical, intent(out):: ff
1550real(dp),dimension(3,3):: prot,azirot
1551real(dp),dimension(2) :: xm
1552real(dp) :: clat,slat,clon,slon,cazi,sazi, &
1553 rlat,rlata,rlatb,rlatc,drlata,drlatb,drlatc, &
1554 rlon,rlona,rlonb,rlonc,drlona,drlonb,drlonc
1555integer(spi) :: ix,iy,mx,my
1556clat=cos(plat); slat=sin(plat)
1557clon=cos(plon); slon=sin(plon)
1558cazi=cos(pazi); sazi=sin(pazi)
1559
1560azirot(:,1)=(/ cazi, sazi, u0/)
1561azirot(:,2)=(/-sazi, cazi, u0/)
1562azirot(:,3)=(/ u0, u0, u1/)
1563
1564prot(:,1)=(/ -slon, clon, u0/)
1565prot(:,2)=(/-slat*clon, -slat*slon, clat/)
1566prot(:,3)=(/ clat*clon, clat*slon, slat/)
1567prot=matmul(prot,azirot)
1568mx=lx+nx ! Index of the 'right' edge of the rectangular grid
1569my=ly+ny ! Index of the 'top' edge of the rectangular grid
1570do iy=ly,my
1571 xm(2)=iy*dely
1572 do ix=lx,mx
1573 xm(1)=ix*delx
1574 call xmtoxc_ak(a,k,xm,xc(:,ix,iy),xcd(:,:,ix,iy),ff)
1575 if(ff)return
1576 xcd(:,:,ix,iy)=matmul(prot,xcd(:,:,ix,iy))
1577 xc(:, ix,iy)=matmul(prot,xc(:, ix,iy))
1578 enddo
1579enddo
1580
1581! Compute the areas of the quadrilateral grid cells:
1582do iy=ly,my-1
1583 do ix=lx,mx-1
1584 call ctogr(xc(:,ix ,iy ),rlat ,rlon )
1585 call ctogr(xc(:,ix+1,iy ),rlata,rlona)
1586 call ctogr(xc(:,ix+1,iy+1),rlatb,rlonb)
1587 call ctogr(xc(:,ix ,iy+1),rlatc,rlonc)
1588 drlata=rlata-rlat; drlona=rlona-rlon
1589 drlatb=rlatb-rlat; drlonb=rlonb-rlon
1590 drlatc=rlatc-rlat; drlonc=rlonc-rlon
1591
1592! If 'I' is the grid point (ix,iy), 'A' is (ix+1,iy); 'B' is (ix+1,iy+1)
1593! and 'C' is (ix,iy+1), then the area of the grid cell IABC is the sum of
1594! the areas of the triangles, IAB and IBC (the latter being the negative
1595! of the signed area of triangle, ICB):
1596 garea(ix,iy)=sarea(rlat, drlata,drlona, drlatb,drlonb) &
1597 -sarea(rlat, drlatc,drlonc, drlatb,drlonb)
1598 enddo
1599enddo
1600end subroutine hgrid_ak_rc
1601
1628subroutine hgrid_ak_dd(lx,ly,nx,ny,a,k,pdlat,pdlon,pdazi, & ! [hgrid_ak_dd]
1629 delx,dely, gdlat,gdlon,garea, ff)
1630implicit none
1631integer(spi), intent(in ):: lx,ly,nx,ny
1632real(dp), intent(in ):: A,K,pdlat,pdlon,&
1633 pdazi,delx,dely
1634real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: gdlat,gdlon
1635real(dp),dimension(lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1636logical, intent(out):: ff
1637real(dp):: plat,plon,pazi
1638plat=pdlat*dtor ! Convert these angles from degrees to radians
1639plon=pdlon*dtor !
1640pazi=pdazi*dtor !
1641call hgrid_ak_rr(lx,ly,nx,ny,a,k,plat,plon,pazi, &
1642 delx,dely, gdlat,gdlon,garea, ff)
1643if(ff)return
1644gdlat=gdlat*rtod ! Convert these angles from radians to degrees
1645gdlon=gdlon*rtod !
1646end subroutine hgrid_ak_dd
1647
1671subroutine hgrid_ak_dd_c(lx,ly,nx,ny,a,k,pdlat,pdlon,pdazi, &! [hgrid_ak_dd]
1672 delx,dely, gdlat,gdlon,garea,dx,dy,dangle_dx,dangle_dy, ff)
1673implicit none
1674integer(spi), intent(in ):: lx,ly,nx,ny
1675real(dp), intent(in ):: a,k,pdlat,pdlon,&
1676 pdazi,delx,dely
1677real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: gdlat,gdlon
1678real(dp),dimension(lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1679real(dp),dimension(lx:lx+nx-1,ly:ly+ny ),intent(out):: dx
1680real(dp),dimension(lx:lx+nx ,ly:ly+ny-1),intent(out):: dy
1681real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: dangle_dx,dangle_dy
1682logical, intent(out):: ff
1683real(dp):: plat,plon,pazi
1684plat=pdlat*dtor ! Convert these angles from degrees to radians
1685plon=pdlon*dtor !
1686pazi=pdazi*dtor !
1687call hgrid_ak_rr_c(lx,ly,nx,ny,a,k,plat,plon,pazi, &
1688 delx,dely, gdlat,gdlon,garea,dx,dy,dangle_dx,dangle_dy, ff)
1689if(ff)return
1690gdlat =gdlat *rtod ! Convert these angles from radians to degrees
1691gdlon =gdlon *rtod !
1692dangle_dx=dangle_dx*rtod !
1693dangle_dy=dangle_dy*rtod !
1694end subroutine hgrid_ak_dd_c
1695
1722subroutine hgrid_ak_dc(lx,ly,nx,ny,a,k,pdlat,pdlon,pdazi, & ! [hgrid_ak_dc]
1723 delx,dely, xc,xcd,garea, ff)
1724implicit none
1725integer(spi),intent(in ):: lx,ly,nx,ny
1726real(dp), intent(in ):: A,K,pdlat,pdlon,pdazi,delx,dely
1727real(dp),dimension(3, lx:lx+nx ,ly:ly+ny ),intent(out):: xc
1728real(dp),dimension(3,2,lx:lx+nx ,ly:ly+ny ),intent(out):: xcd
1729real(dp),dimension( lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1730logical, intent(out):: ff
1731real(dp):: plat,plon,pazi
1732plat=pdlat*dtor
1733plon=pdlon*dtor
1734pazi=pdazi*dtor
1735call hgrid_ak_rc(lx,ly,nx,ny,a,k,plat,plon,pazi, &
1736 delx,dely, xc,xcd,garea, ff)
1737end subroutine hgrid_ak_dc
1738
1764subroutine hgrid_ak(lx,ly,nx,ny,a,k,plat,plon,pazi, & ! [hgrid_ak]
1765 re,delxre,delyre, glat,glon,garea, ff)
1766implicit none
1767integer(spi), intent(in ):: lx,ly,nx,ny
1768real(dp), intent(in ):: a,k,plat,plon,pazi, &
1769 re,delxre,delyre
1770real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: glat,glon
1771real(dp),dimension(lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1772logical, intent(out):: ff
1773real(dp):: delx,dely,rere
1774delx=delxre/re ! <- set nondimensional grid step delx
1775dely=delyre/re ! <- set nondimensional grid step dely
1776call hgrid_ak_rr(lx,ly,nx,ny,a,k,plat,plon,pazi, &
1777 delx,dely, glat,glon,garea, ff)
1778if(ff)return
1779rere=re*re
1780garea=garea*rere ! <- Convert from steradians to physical area units.
1781end subroutine hgrid_ak
1782
1816subroutine hgrid_ak_c(lx,ly,nx,ny,a,k,plat,plon,pazi, & ! [hgrid_ak]
1817 re,delxre,delyre, glat,glon,garea,dx,dy,dangle_dx,dangle_dy, ff)
1818implicit none
1819integer(spi), intent(in ):: lx,ly,nx,ny
1820real(dp), intent(in ):: a,k,plat,plon,pazi, &
1821 re,delxre,delyre
1822real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: glat,glon
1823real(dp),dimension(lx:lx+nx-1,ly:ly+ny-1),intent(out):: garea
1824real(dp),dimension(lx:lx+nx-1,ly:ly+ny ),intent(out):: dx
1825real(dp),dimension(lx:lx+nx ,ly:ly+ny-1),intent(out):: dy
1826real(dp),dimension(lx:lx+nx ,ly:ly+ny ),intent(out):: dangle_dx,dangle_dy
1827logical, intent(out):: ff
1828real(dp):: delx,dely,rere
1829delx=delxre/re ! <- set nondimensional grid step delx
1830dely=delyre/re ! <- set nondimensional grid step dely
1831call hgrid_ak_rr_c(lx,ly,nx,ny,a,k,plat,plon,pazi, &
1832 delx,dely, glat,glon,garea,dx,dy,dangle_dx,dangle_dy, ff)
1833if(ff)return
1834rere=re*re
1835garea=garea*rere ! <- Convert from steradians to physical area units.
1836dx=dx*re ! <- Convert from nondimensional to physical length units.
1837dy=dy*re ! <-
1838dangle_dx=dangle_dx*rtod ! <-Convert from radians to degrees
1839dangle_dy=dangle_dy*rtod ! <-Convert from radians to degrees
1840end subroutine hgrid_ak_c
1841
1851subroutine gaulegh(m,x,w)! [gaulegh]
1852implicit none
1853integer(spi), intent(IN ):: m ! <- number of nodes in half-interval
1854real(dp),dimension(m),intent(OUT):: x,w ! <- nodes and weights
1855integer(spi),parameter:: nit=8
1856real(dp), parameter:: eps=3.e-14_dp
1857integer(spi) :: i,ic,j,jm,it,m2,m4p,m4p3
1858real(dp) :: z,zzm,p1,p2,p3,pp,z1
1859m2=m*2; m4p=m*4+1; m4p3=m4p+2
1860do i=1,m; ic=m4p3-4*i
1861 z=cos(pih*ic/m4p); zzm=z*z-u1
1862 do it=1,nit
1863 p1=u1; p2=u0
1864 do j=1,m2; jm=j-1; p3=p2; p2=p1; p1=((j+jm)*z*p2-jm*p3)/j; enddo
1865 pp=m2*(z*p1-p2)/zzm; z1=z; z=z1-p1/pp; zzm=z*z-u1
1866 if(abs(z-z1) <= eps)exit
1867 enddo
1868 x(i)=z; w(i)=-u2/(zzm*pp*pp)
1869enddo
1870end subroutine gaulegh
1871
1887subroutine gtoxm_ak_rr_m(A,K,plat,plon,pazi,lat,lon,xm,ff)! [gtoxm_ak_rr]
1888use pmat5, only: grtoc
1889implicit none
1890real(dp), intent(in ):: a,k,plat,plon,pazi,lat,lon
1891real(dp),dimension(2),intent(out):: xm
1892logical, intent(out):: ff
1893real(dp),dimension(3,3):: prot,azirot
1894real(dp) :: clat,slat,clon,slon,cazi,sazi
1895real(dp),dimension(3) :: xc
1896clat=cos(plat); slat=sin(plat)
1897clon=cos(plon); slon=sin(plon)
1898cazi=cos(pazi); sazi=sin(pazi)
1899
1900azirot(:,1)=(/ cazi, sazi, u0/)
1901azirot(:,2)=(/-sazi, cazi, u0/)
1902azirot(:,3)=(/ u0, u0, u1/)
1903
1904prot(:,1)=(/ -slon, clon, u0/)
1905prot(:,2)=(/-slat*clon, -slat*slon, clat/)
1906prot(:,3)=(/ clat*clon, clat*slon, slat/)
1907prot=matmul(prot,azirot)
1908
1909call grtoc(lat,lon,xc)
1910xc=matmul(transpose(prot),xc)
1911call xctoxm_ak(a,k,xc,xm,ff)
1912end subroutine gtoxm_ak_rr_m
1913
1931subroutine gtoxm_ak_rr_g(A,K,plat,plon,pazi,delx,dely,lat,lon,&! [gtoxm_ak_rr]
1932 xm,ff)
1933implicit none
1934real(dp), intent(in ):: a,k,plat,plon,pazi,delx,dely,lat,lon
1935real(dp),dimension(2),intent(out):: xm
1936logical, intent(out):: ff
1937call gtoxm_ak_rr_m(a,k,plat,plon,pazi,lat,lon,xm,ff); if(ff)return
1938xm(1)=xm(1)/delx; xm(2)=xm(2)/dely
1939end subroutine gtoxm_ak_rr_g
1940
1953subroutine gtoxm_ak_dd_m(A,K,pdlat,pdlon,pdazi,dlat,dlon,&! [gtoxm_ak_dd]
1954 xm,ff)
1955implicit none
1956real(dp), intent(in ):: a,k,pdlat,pdlon,pdazi,dlat,dlon
1957real(dp),dimension(2),intent(out):: xm
1958logical, intent(out):: ff
1959real(dp):: plat,plon,pazi,lat,lon
1960plat=pdlat*dtor ! Convert these angles from degrees to radians
1961plon=pdlon*dtor !
1962pazi=pdazi*dtor !
1963lat=dlat*dtor
1964lon=dlon*dtor
1965call gtoxm_ak_rr_m(a,k,plat,plon,pazi,lat,lon,xm,ff)
1966end subroutine gtoxm_ak_dd_m
1967
1982subroutine gtoxm_ak_dd_g(A,K,pdlat,pdlon,pdazi,delx,dely,&! [gtoxm_ak_dd]
1983dlat,dlon, xm,ff)
1984implicit none
1985real(dp), intent(in ):: a,k,pdlat,pdlon,pdazi,delx,dely,dlat,dlon
1986real(dp),dimension(2),intent(out):: xm
1987logical, intent(out):: ff
1988real(dp):: plat,plon,pazi,lat,lon
1989plat=pdlat*dtor ! Convert these angles from degrees to radians
1990plon=pdlon*dtor !
1991pazi=pdazi*dtor !
1992lat=dlat*dtor
1993lon=dlon*dtor
1994call gtoxm_ak_rr_g(a,k,plat,plon,pazi,delx,dely,lat,lon,xm,ff)
1995end subroutine gtoxm_ak_dd_g
1996
2014subroutine xmtog_ak_rr_m(A,K,plat,plon,pazi,xm,lat,lon,ff)! [xmtog_ak_rr]
2015use pmat5, only: ctogr
2016implicit none
2017real(dp), intent(in ):: a,k,plat,plon,pazi
2018real(dp),dimension(2),intent(in ):: xm
2019real(dp), intent(out):: lat,lon
2020logical, intent(out):: ff
2021real(dp),dimension(3,2):: xcd
2022real(dp),dimension(3,3):: prot,azirot
2023real(dp) :: clat,slat,clon,slon,cazi,sazi
2024real(dp),dimension(3) :: xc
2025clat=cos(plat); slat=sin(plat)
2026clon=cos(plon); slon=sin(plon)
2027cazi=cos(pazi); sazi=sin(pazi)
2028
2029azirot(:,1)=(/ cazi, sazi, u0/)
2030azirot(:,2)=(/-sazi, cazi, u0/)
2031azirot(:,3)=(/ u0, u0, u1/)
2032
2033prot(:,1)=(/ -slon, clon, u0/)
2034prot(:,2)=(/-slat*clon, -slat*slon, clat/)
2035prot(:,3)=(/ clat*clon, clat*slon, slat/)
2036prot=matmul(prot,azirot)
2037call xmtoxc_ak(a,k,xm,xc,xcd,ff); if(ff)return
2038xc=matmul(prot,xc)
2039call ctogr(xc,lat,lon)
2040end subroutine xmtog_ak_rr_m
2041
2061subroutine xmtog_ak_rr_g(A,K,plat,plon,pazi,delx,dely,xm,&! [xmtog_ak_rr]
2062 lat,lon,ff)
2063implicit none
2064real(dp), intent(in ):: a,k,plat,plon,pazi,delx,dely
2065real(dp),dimension(2),intent(in ):: xm
2066real(dp), intent(out):: lat,lon
2067logical, intent(out):: ff
2068real(dp),dimension(2):: xmt
2069xmt(1)=xm(1)*delx ! Convert from grid units to intrinsic map-space units
2070xmt(2)=xm(2)*dely !
2071call xmtog_ak_rr_m(a,k,plat,plon,pazi,xmt,lat,lon,ff)
2072end subroutine xmtog_ak_rr_g
2073
2086subroutine xmtog_ak_dd_m(A,K,pdlat,pdlon,pdazi,xm,dlat,dlon,ff)! [xmtog_ak_dd]
2087use pmat5, only: ctogr
2088implicit none
2089real(dp), intent(in ):: a,k,pdlat,pdlon,pdazi
2090real(dp),dimension(2),intent(in ):: xm
2091real(dp), intent(out):: dlat,dlon
2092logical, intent(out):: ff
2093real(dp):: plat,plon,pazi,lat,lon
2094plat=pdlat*dtor ! Convert these angles from degrees to radians
2095plon=pdlon*dtor !
2096pazi=pdazi*dtor !
2097call xmtog_ak_rr_m(a,k,plat,plon,pazi,xm,lat,lon,ff)
2098dlat=lat*rtod
2099dlon=lon*rtod
2100end subroutine xmtog_ak_dd_m
2101
2116subroutine xmtog_ak_dd_g(A,K,pdlat,pdlon,pdazi,delx,dely,xm,&! [xmtog_ak_dd]
2117 dlat,dlon,ff)
2118implicit none
2119real(dp), intent(in ):: a,k,pdlat,pdlon,pdazi,delx,dely
2120real(dp),dimension(2),intent(in ):: xm
2121real(dp), intent(out):: dlat,dlon
2122logical, intent(out):: ff
2123real(dp),dimension(2):: xmt
2124real(dp) :: plat,plon,pazi,lat,lon
2125xmt(1)=xm(1)*delx ! Convert from grid units to intrinsic map-space units
2126xmt(2)=xm(2)*dely !
2127plat=pdlat*dtor ! Convert these angles from degrees to radians
2128plon=pdlon*dtor !
2129pazi=pdazi*dtor !
2130call xmtog_ak_rr_m(a,k,plat,plon,pazi,xmt,lat,lon,ff)
2131dlat=lat*rtod
2132dlon=lon*rtod
2133end subroutine xmtog_ak_dd_g
2134
2135end module pesg
2136
Suite of routines to perform the 2-parameter family of Extended Schmidt Gnomonic (ESG) regional grid ...
Definition pesg.f90:15
subroutine get_meanqd(ngh, lam, xg, wg, ak, ma, q, qdak, qdma, ga, gadak, gadma, ff)
For a parameter vector, ak and a map-space domain-parameter vector, ma, return the lambda-parameteriz...
Definition pesg.f90:604
subroutine xmtog_ak_rr_g(a, k, plat, plon, pazi, delx, dely, xm, lat, lon, ff)
For an ESG map with parameters, (A,K), and geographical orientation, given by plon,...
Definition pesg.f90:2063
subroutine get_qsofvs(n, lam, v1s, v2s, v3s, v4s, qs)
General util to convert value.
Definition pesg.f90:771
subroutine gtoxm_ak_dd_g(a, k, pdlat, pdlon, pdazi, delx, dely, dlat, dlon, xm, ff)
Like gtoxm_ak_rr_g, except lat, lon, azimuth, are expressed in degrees.
Definition pesg.f90:1984
subroutine hgrid_ak_rr_c(lx, ly, nx, ny, a, k, plat, plon, pazi, delx, dely, glat, glon, garea, dx, dy, angle_dx, angle_dy, ff)
Use a and k as the parameters of an extended Schmidt-transformed gnomonic (ESG) mapping centered at (...
Definition pesg.f90:1338
subroutine xmtog_ak_dd_g(a, k, pdlat, pdlon, pdazi, delx, dely, xm, dlat, dlon, ff)
Like xmtog_ak_rr_g, except lat, lon, azimuth, are expressed in degrees.
Definition pesg.f90:2118
subroutine xstoxc1(xs, xc, xcd, xcdd)
Standard transformation from polar stereographic map coordinates, xs, to cartesian,...
Definition pesg.f90:107
subroutine get_qxd(j0, j0d, v1, v2, v3, v4, v1d, v2d, v3d, v4d)
From a jacobian matrix, j0, and its derivative, j0d, get a sufficient set of v.
Definition pesg.f90:542
subroutine hgrid_ak_dd_c(lx, ly, nx, ny, a, k, pdlat, pdlon, pdazi, delx, dely, gdlat, gdlon, garea, dx, dy, dangle_dx, dangle_dy, ff)
Like hgrid_ak_rr_c, except all the angle arguments (but not delx,dely) are in degrees instead of radi...
Definition pesg.f90:1673
subroutine gtoxm_ak_dd_m(a, k, pdlat, pdlon, pdazi, dlat, dlon, xm, ff)
Like gtoxm_ak_rr_m, except lat, lon, azimuth, are expressed in degrees.
Definition pesg.f90:1955
subroutine xmtoxc_vak(ak, xm, xc, xcd, ff)
Assuming the vector AK parameterization of the Extended Schmidt-transformed Gnomonic (ESG) mapping wi...
Definition pesg.f90:381
subroutine xttoxs1(k, xt, xs, xsd, xsdd, xs1, xsd1, ff)
Like xttoxs, but also, return the derivatives, wrt K, of xs and xsd.
Definition pesg.f90:193
subroutine xmtoxc_vak1(ak, xm, xc, xcd, xc1, xcd1, ff)
Like xmtoxc_vak, _ak, but also return derivatives wrt ak.
Definition pesg.f90:400
subroutine get_qofvd(lam, v2, v3, v1d, v2d, v3d, v4d, qd)
Like get_qofv, but for (only) the 2-vector derivatives of Q.
Definition pesg.f90:751
subroutine gtoxm_ak_rr_g(a, k, plat, plon, pazi, delx, dely, lat, lon, xm, ff)
Given the map specification (angles in radians), the grid spacing (in map-space units) and the sample...
Definition pesg.f90:1933
subroutine gtoxm_ak_rr_m(a, k, plat, plon, pazi, lat, lon, xm, ff)
Given the map specification (angles in radians), the grid spacing (in map-space units) and the sample...
Definition pesg.f90:1888
subroutine hgrid_ak_c(lx, ly, nx, ny, a, k, plat, plon, pazi, re, delxre, delyre, glat, glon, garea, dx, dy, dangle_dx, dangle_dy, ff)
Like hgrid_ak_rr_c except the argument list includes the earth radius, re, and this is used to expres...
Definition pesg.f90:1818
subroutine zmtozt1(a, zm, zt, ztd, zt1, ztd1, ff)
Like zmtozt, but also, get the derivative with respect to a, zt1 of zt, and ztd1 of ztd.
Definition pesg.f90:348
subroutine xmtog_ak_dd_m(a, k, pdlat, pdlon, pdazi, xm, dlat, dlon, ff)
Like xmtog_ak_rr_m, except lat, lon, azimuth, are expressed in degrees.
Definition pesg.f90:2087
subroutine xmtog_ak_rr_m(a, k, plat, plon, pazi, xm, lat, lon, ff)
Given the ESG map specified by parameters (A,K) and geographical center and orientation,...
Definition pesg.f90:2015
subroutine get_meanqs(n, ngh, lam, xg, wg, aks, mas, qs, ff)
Like getmeanqd, except for n different values, aks, of ak and n different values, mas of ma,...
Definition pesg.f90:682
subroutine xmtoxt1(a, xm, xt, xtd, xt1, xtd1, ff)
Like zmtozt1, but for 2-vector xm and xt, and 2*2 diagonal Jacobian xtd Also, the derivatives,...
Definition pesg.f90:276
This module is for evaluating several useful real-valued functions that are not always available in F...
Definition pfun.f90:11
Some of the commonly used constants (pi etc) mainly for double-precision subroutines.
Definition pietc.f90:14
real(dp), parameter dtor
Degrees to radians.
Definition pietc.f90:54
logical, parameter f
for pain-relief in logical ops
Definition pietc.f90:18
real(dp), parameter o5
fifth
Definition pietc.f90:35
real(dp), parameter u1
one
Definition pietc.f90:20
real(dp), parameter o2
half
Definition pietc.f90:32
real(dp), parameter s54
sine(54 deg)
Definition pietc.f90:73
real(dp), parameter rtod
radians to degrees
Definition pietc.f90:55
real(dp), parameter s18
sine(18 deg)
Definition pietc.f90:61
real(dp), parameter o3
third
Definition pietc.f90:33
real(dp), parameter ms54
minus-sine(54 deg)
Definition pietc.f90:101
real(dp), parameter s36
sine(36 deg)
Definition pietc.f90:67
real(dp), parameter pih
pi*half
Definition pietc.f90:44
real(dp), parameter u5
five
Definition pietc.f90:28
real(dp), parameter s72
sine(72 deg)
Definition pietc.f90:79
real(dp), parameter ms18
minus-sine(18 deg)
Definition pietc.f90:89
real(dp), parameter ms72
minus-sine(72 deg)
Definition pietc.f90:107
real(dp), parameter ms36
minus-sine(36 deg)
Definition pietc.f90:95
logical, parameter t
for pain-relief in logical ops
Definition pietc.f90:17
real(dp), parameter u0
zero
Definition pietc.f90:19
real(dp), parameter u2
two
Definition pietc.f90:22
real(dp), parameter pi2
Pi*2.
Definition pietc.f90:43
Standard integer, real, and complex single and double precision kinds.
Definition pkind.f90:7
integer, parameter dp
Double precision real kind.
Definition pkind.f90:11
integer, parameter spi
Single precision integer kind.
Definition pkind.f90:8
Module for handy vector and matrix operations in Euclidean geometry.
Definition pmat4.f90:45
Utility routines for orienting the globe and basic geographical mappings.
Definition pmat5.f90:27
A suite of routines to perform the eigen-decomposition of symmetric 2*2 matrices and to deliver basic...
Definition psym2.f90:11