grid_tools 1.14.0
Loading...
Searching...
No Matches
psym2.f90
Go to the documentation of this file.
1
4
11module psym2
12use pkind, only: spi,dp
13use pietc, only: u0,u1,o2
14implicit none
15private
17
18real(dp),dimension(2,2,2,2):: id
19data id/u1,u0,u0,u0, u0,o2,o2,u0, u0,o2,o2,u0, u0,u0,u0,u1/! Effective identity
20
21interface eigensym2; module procedure eigensym2,eigensym2d; end interface
22interface invsym2; module procedure invsym2,invsym2d; end interface
23interface sqrtsym2; module procedure sqrtsym2,sqrtsym2d; end interface
24interface sqrtsym2d_e; module procedure sqrtsym2d_e; end interface
25interface sqrtsym2d_t; module procedure sqrtsym2d_t; end interface
26interface expsym2; module procedure expsym2,expsym2d; end interface
27interface expsym2d_e; module procedure expsym2d_e; end interface
28interface expsym2d_t; module procedure expsym2d_t; end interface
29interface logsym2; module procedure logsym2,logsym2d; end interface
30interface id2222; module procedure id2222; end interface
31interface chol2; module procedure chol2; end interface
32
33contains
34
42subroutine eigensym2(em,vv,oo)! [eigensym2]
43implicit none
44real(dp),dimension(2,2),intent(in ):: em
45real(dp),dimension(2,2),intent(out):: vv,oo
46real(dp):: a,b,c,d,e,f,g,h
47a=em(1,1); b=em(1,2); c=em(2,2)
48d=a*c-b*b! <- det(em)
49e=(a+c)*o2; f=(a-c)*o2
50h=sqrt(f**2+b**2)
51g=sqrt(b**2+(h+abs(f))**2)
52if (g==u0)then; vv(:,1)=(/u1,u0/)
53elseif(f> u0)then; vv(:,1)=(/h+f,b/)/g
54else ; vv(:,1)=(/b,h-f/)/g
55endif
56vv(:,2)=(/-vv(2,1),vv(1,1)/)
57oo=matmul(transpose(vv),matmul(em,vv))
58oo(1,2)=u0; oo(2,1)=u0
59end subroutine eigensym2
60
75subroutine eigensym2d(em,vv,oo,vvd,ood,ff)! [eigensym2]
76implicit none
77real(dp),dimension(2,2), intent(in ):: em
78real(dp),dimension(2,2), intent(out):: vv,oo
79real(dp),dimension(2,2,2,2),intent(out):: vvd,ood
80logical, intent(out):: ff
81real(dp),dimension(2,2):: emd,tt,vvr
82real(dp) :: oodif,dtheta
83integer(spi) :: i,j
84call eigensym2(em,vv,oo); vvr(1,:)=-vv(2,:); vvr(2,:)=vv(1,:)
85oodif=oo(1,1)-oo(2,2); ff=oodif==u0; if(ff)return
86ood=0
87vvd=0
88do j=1,2
89 do i=1,2
90 emd=0
91 if(i==j)then
92 emd(i,j)=u1
93 else
94 emd(i,j)=o2; emd(j,i)=o2
95 endif
96 tt=matmul(transpose(vv),matmul(emd,vv))
97 ood(1,1,i,j)=tt(1,1)
98 ood(2,2,i,j)=tt(2,2)
99 dtheta=tt(1,2)/oodif
100 vvd(:,:,i,j)=vvr*dtheta
101 enddo
102enddo
103end subroutine eigensym2d
104
111subroutine invsym2(em,z)! [invsym2]
112implicit none
113real(dp),dimension(2,2),intent(in ):: em
114real(dp),dimension(2,2),intent(out):: z
115real(dp):: detem
116z(1,1)=em(2,2); z(2,1)=-em(2,1); z(1,2)=-em(1,2); z(2,2)=em(1,1)
117detem=em(1,1)*em(2,2)-em(2,1)*em(1,2)
118z=z/detem
119end subroutine invsym2
120
131subroutine invsym2d(em,z,zd)! [invsym2]
132implicit none
133real(dp),dimension(2,2) ,intent(in ):: em
134real(dp),dimension(2,2) ,intent(out):: z
135real(dp),dimension(2,2,2,2),intent(out):: zd
136integer(spi):: k,l
137call invsym2(em,z)
138call id2222(zd)
139do l=1,2; do k=1,2
140 zd(:,:,k,l)=-matmul(matmul(z,zd(:,:,k,l)),z)
141enddo; enddo
142end subroutine invsym2d
143
149subroutine sqrtsym2(em,z)! [sqrtsym2]
150implicit none
151real(dp),dimension(2,2),intent(in ):: em
152real(dp),dimension(2,2),intent(out):: z
153real(dp),dimension(2,2):: vv,oo
154integer(spi) :: i
155call eigensym2(em,vv,oo)
156do i=1,2
157if(oo(i,i)<0)stop 'In sqrtsym2; matrix em is not non-negative'
158oo(i,i)=sqrt(oo(i,i)); enddo
159z=matmul(vv,matmul(oo,transpose(vv)))
160end subroutine sqrtsym2
161
176subroutine sqrtsym2d(x,z,zd)! [sqrtsym2]
177implicit none
178real(dp),dimension(2,2), intent(in ):: x
179real(dp),dimension(2,2), intent(out):: z
180real(dp),dimension(2,2,2,2),intent(out):: zd
181real(dp),dimension(2,2):: px
182real(dp) :: rdetx,lrdetx,htrpxs,q
183rdetx=sqrt(x(1,1)*x(2,2)-x(1,2)*x(2,1)) ! <- sqrt(determinant of x)
184lrdetx=sqrt(rdetx)
185px=x/rdetx ! - preconditioned x (has unit determinant)
186htrpxs= ((px(1,1)+px(2,2))/2)**2 ! - {half-trace-px}-squared
187q=htrpxs-u1
188if(q<.05_dp)then ! - Taylor expansion method
189 call sqrtsym2d_t(px,z,zd)
190 z=z*lrdetx; zd=zd/lrdetx
191else
192 call sqrtsym2d_e(x,z,zd) ! - Eigen-method
193endif
194end subroutine sqrtsym2d
195
202subroutine sqrtsym2d_e(x,z,zd)! [sqrtsym2d_e]
203implicit none
204real(dp),dimension(2,2), intent(in ):: x
205real(dp),dimension(2,2), intent(out):: z
206real(dp),dimension(2,2,2,2),intent(out):: zd
207real(dp),dimension(2,2,2,2):: vvd,ood
208real(dp),dimension(2,2) :: vv,oo,oori,tt
209integer(spi) :: i,j
210logical :: ff
211call eigensym2(x,vv,oo,vvd,ood,ff)
212z=u0; z(1,1)=sqrt(oo(1,1)); z(2,2)=sqrt(oo(2,2))
213z=matmul(matmul(vv,z),transpose(vv))
214oori=u0; oori(1,1)=u1/sqrt(oo(1,1)); oori(2,2)=u1/sqrt(oo(2,2))
215do j=1,2
216do i=1,2
217 tt=matmul(vvd(:,:,i,j),transpose(vv))
218 zd(:,:,i,j)=o2*matmul(matmul(matmul(vv,ood(:,:,i,j)),oori),transpose(vv))&
219 +matmul(tt,z)-matmul(z,tt)
220enddo
221enddo
222end subroutine sqrtsym2d_e
223
235subroutine sqrtsym2d_t(x,z,zd)! [sqrtsym2d_t]
236implicit none
237real(dp),dimension(2,2), intent(in ):: x
238real(dp),dimension(2,2), intent(out):: z
239real(dp),dimension(2,2,2,2),intent(out):: zd
240integer(spi),parameter :: nit=300 ! number of iterative increments allowed
241real(dp),parameter :: crit=1.e-17
242real(dp),dimension(2,2) :: r,rp,rd,rpd
243real(dp) :: c
244integer(spi) :: i,j,n
245r=x; r(1,1)=x(1,1)-1; r(2,2)=x(2,2)-1
246z=u0; z(1,1)=u1; z(2,2)=u1
247rp=r
248c=o2
249do n=0,nit
250 z=z+c*rp
251 rp=matmul(rp,r)
252 if(sum(abs(rp))<crit)exit
253 c=-c*(n*2+1)/(2*(n+2))
254enddo
255do j=1,2; do i=1,2
256 rd=id(:,:,i,j)
257 rpd=rd
258 zd(:,:,i,j)=0
259 rp=r
260 c=o2
261 do n=0,nit
262 zd(:,:,i,j)=zd(:,:,i,j)+c*rpd
263 rpd=matmul(rd,rp)+matmul(r,rpd)
264 rp=matmul(r,rp)
265 if(sum(abs(rp))<crit)exit
266 c=-c*(n*2+1)/(2*(n+2))
267 enddo
268enddo; enddo
269end subroutine sqrtsym2d_t
270
276subroutine expsym2(em,expem)! [expsym2]
277implicit none
278real(dp),dimension(2,2),intent(in ):: em
279real(dp),dimension(2,2),intent(out):: expem
280real(dp),dimension(2,2):: vv,oo
281integer(spi) :: i
282call eigensym2(em,vv,oo)
283do i=1,2; oo(i,i)=exp(oo(i,i)); enddo
284expem=matmul(vv,matmul(oo,transpose(vv)))
285end subroutine expsym2
286
293subroutine expsym2d(x,z,zd)! [expsym2]
294implicit none
295real(dp),dimension(2,2), intent(in ):: x
296real(dp),dimension(2,2), intent(out):: z
297real(dp),dimension(2,2,2,2),intent(out):: zd
298real(dp),dimension(2,2):: px
299real(dp) :: trxh,detpx
300trxh=(x(1,1)+x(2,2))*o2
301px=x;px(1,1)=x(1,1)-trxh;px(2,2)=x(2,2)-trxh
302detpx=abs(px(1,1)*px(2,2)-px(1,2)*px(2,1))
303if(detpx<.1_dp)then; call expsym2d_t(px,z,zd)
304else ; call expsym2d_e(px,z,zd)
305endif
306z=z*exp(trxh)
307end subroutine expsym2d
308
316subroutine expsym2d_e(x,z,zd)! [expsym2d_e]
317implicit none
318real(dp),dimension(2,2), intent(in ):: x
319real(dp),dimension(2,2), intent(out):: z
320real(dp),dimension(2,2,2,2),intent(out):: zd
321real(dp),dimension(2,2,2,2):: vvd,ood
322real(dp),dimension(2,2) :: vv,oo,ooe,tt
323integer(spi) :: i,j
324logical :: ff
325call eigensym2(x,vv,oo,vvd,ood,ff)
326z=u0; z(1,1)=exp(oo(1,1)); z(2,2)=exp(oo(2,2))
327z=matmul(matmul(vv,z),transpose(vv))
328ooe=u0; ooe(1,1)=exp(oo(1,1)); ooe(2,2)=exp(oo(2,2))
329do j=1,2
330do i=1,2
331 tt=matmul(vvd(:,:,i,j),transpose(vv))
332 zd(:,:,i,j)=matmul(matmul(matmul(vv,ood(:,:,i,j)),ooe),transpose(vv))&
333 +matmul(tt,z)-matmul(z,tt)
334enddo
335enddo
336end subroutine expsym2d_e
337
346subroutine expsym2d_t(x,z,zd)! [expsym2d_t]
347implicit none
348real(dp),dimension(2,2), intent(in ):: x
349real(dp),dimension(2,2), intent(out):: z
350real(dp),dimension(2,2,2,2),intent(out):: zd
351integer(spi),parameter :: nit=100 ! number of iterative increments allowed
352real(dp),parameter :: crit=1.e-17_dp
353real(dp),dimension(2,2) :: xp,xd,xpd
354real(dp) :: c
355integer(spi) :: i,j,n
356z=0; z(1,1)=u1; z(2,2)=u1
357xp=x
358c=u1
359do n=1,nit
360 z=z+c*xp
361 xp=matmul(xp,x)
362 if(sum(abs(xp))<crit)exit
363 c=c/(n+1)
364enddo
365do j=1,2; do i=1,2
366 xd=id(:,:,i,j)
367 xpd=xd
368 zd(:,:,i,j)=0
369 xp=x
370 c=u1
371 do n=1,nit
372 zd(:,:,i,j)=zd(:,:,i,j)+c*xpd
373 xpd=matmul(xd,xp)+matmul(x,xpd)
374 xp=matmul(x,xp)
375 if(sum(abs(xpd))<crit)exit
376 c=c/(n+1)
377 enddo
378enddo; enddo
379end subroutine expsym2d_t
380
386subroutine logsym2(em,logem)! [logsym2]
387implicit none
388real(dp),dimension(2,2),intent(in ):: em
389real(dp),dimension(2,2),intent(out):: logem
390real(dp),dimension(2,2):: vv,oo
391integer(spi) :: i
392call eigensym2(em,vv,oo)
393do i=1,2
394 if(oo(i,i)<=u0)stop 'In logsym2; matrix em is not positive definite'
395 oo(i,i)=log(oo(i,i))
396enddo
397logem=matmul(vv,matmul(oo,transpose(vv)))
398end subroutine logsym2
399
408subroutine logsym2d(x,z,zd)! [logsym2]
409use pfun, only: sinhox
410implicit none
411real(dp),dimension(2,2), intent(in ):: x
412real(dp),dimension(2,2), intent(out):: z
413real(dp),dimension(2,2,2,2),intent(out):: zd
414real(dp),dimension(2,2):: vv,oo,d11,d12,d22,pqr,d11pqr,d12pqr,d22pqr
415real(dp) :: c,s,cc,cs,ss,c2h,p,q,r,lp,lq,L
416integer(spi) :: i
417call eigensym2(x,vv,oo)
418if(oo(1,1)<=u0 .or. oo(2,2)<=u0)stop 'In logsym2; matrix x is not positive definite'
419c=vv(1,1); s=vv(1,2); cc=c*c; cs=c*s; ss=s*s; c2h=(cc-ss)*o2
420p=u1/oo(1,1); q=u1/oo(2,2); lp=log(p); lq=log(q); oo(1,1)=-lp; oo(2,2)=-lq
421z=matmul(vv,matmul(oo,transpose(vv)))
422l=(lp-lq)*o2; r=sqrt(p*q)/sinhox(l)
423d11(1,:)=(/ cc,cs /); d11(2,:)=(/ cs,ss/)
424d12(1,:)=(/-cs,c2h/); d12(2,:)=(/c2h,cs/)
425d22(1,:)=(/ ss,-cs/); d22(2,:)=(/-cs,cc/)
426pqr(1,:)=(/p,r/) ; pqr(2,:)=(/r,q/)
427d11pqr=d11*pqr
428d12pqr=d12*pqr
429d22pqr=d22*pqr
430zd(:,:,1,1)=matmul(vv,matmul(d11pqr,transpose(vv)))
431zd(:,:,1,2)=matmul(vv,matmul(d12pqr,transpose(vv)))
432zd(:,:,2,2)=matmul(vv,matmul(d22pqr,transpose(vv)))
433zd(:,:,2,1)=zd(:,:,1,2)
434end subroutine logsym2d
435
441subroutine id2222(em)! [id2222]
442implicit none
443real(dp),dimension(2,2,2,2),intent(out):: em
444real(dp),dimension(2,2,2,2) :: id
445!data id/u1,u0,u0,u0, u0,o2,o2,u0, u0,o2,o2,u0, u0,u0,u0,u1/! Effective identity
446em=id
447end subroutine id2222
448
457subroutine chol2(s,c,ff)! [chol2]
458use pietc, only: u0
459implicit none
460real(dp),dimension(2,2),intent(in ):: s
461real(dp),dimension(2,2),intent(out):: c
462logical ,intent(out):: ff
463real(dp):: r
464ff=s(1,1)<=u0; if(ff)return
465c(1,1)=sqrt(s(1,1))
466c(1,2)=u0
467c(2,1)=s(2,1)/c(1,1)
468r=s(2,2)-c(2,1)**2
469ff=r<=u0; if(ff)return
470c(2,2)=sqrt(r)
471end subroutine chol2
472
473end module psym2
474
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 u1
one
Definition pietc.f90:20
real(dp), parameter o2
half
Definition pietc.f90:32
real(dp), parameter u0
zero
Definition pietc.f90:19
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
A suite of routines to perform the eigen-decomposition of symmetric 2*2 matrices and to deliver basic...
Definition psym2.f90:11
subroutine logsym2d(x, z, zd)
General routine to evaluate the logarithm, z=log(x), and the symmetric derivative,...
Definition psym2.f90:409
subroutine expsym2d(x, z, zd)
Get the exp of a symmetric 2*2 matrix, and its symmetric derivative.
Definition psym2.f90:294
subroutine eigensym2d(em, vv, oo, vvd, ood, ff)
For a symmetric 2*2 matrix, em, return the normalized eigenvectors, vv, and the diagonal matrix of ei...
Definition psym2.f90:76
subroutine invsym2d(em, z, zd)
Get the inverse, z,of a 2*2 symmetric matrix, em, and its derivative, zd, with respect to symmetric v...
Definition psym2.f90:132
real(dp), dimension(2, 2, 2, 2) id
ID.
Definition psym2.f90:18
subroutine sqrtsym2d(x, z, zd)
General routine to evaluate z=sqrt(x), and the symmetric derivative, zd = dz/dx, where x is a symmetr...
Definition psym2.f90:177