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