KronLinInv  0.3
Kronecker-product-based linear inversion
kronlininv.f08
Go to the documentation of this file.
1 
2 !------------------------------------------------------------------------
3 !
4 ! Copyright 2018, Andrea Zunino
5 !
6 ! This file is part of KronLinInv.
7 !
8 ! KronLinInv is free software: you can redistribute it and/or modify
9 ! it under the terms of the GNU General Public License as published by
10 ! the Free Software Foundation, either version 3 of the License, or
11 ! (at your option) any later version.
12 !
13 ! KronLinInv is distributed in the hope that it will be useful,
14 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ! GNU General Public License for more details.
17 !
18 ! You should have received a copy of the GNU General Public License
19 ! along with KronLinInv. If not, see <http://www.gnu.org/licenses/>.
20 !
21 !------------------------------------------------------------------------
22 
23 
29 
30 
31 
32 !-------------------------------------------------------------
38 !
39 !-------------------------------------------------------------
40 module realprec
41 
42  ! http://fortranwiki.org/fortran/show/Real+precision
43  integer,parameter :: pdigits=15 !15 !! used also by MPI
44  integer,parameter :: rexprange=307 !307 !! used also by MPI
45 
46  ! RESULT = SELECTED_REAL_KIND([P, R, RADIX])
47  integer,parameter :: dp = selected_real_kind(pdigits, rexprange)
48 
49  ! integer, parameter :: sp = selected_real_kind(6, 37)
50  ! integer, parameter :: dp = selected_real_kind(15, 307)
51  ! integer, parameter :: qp = selected_real_kind(33, 4931)
52 
53  private :: pdigits,rexprange
54  public :: dp
55 
56 end module realprec
57 
58 
59 !################################################################
60 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
61 !################################################################
62 
63 !-------------------------------------------------------------------------
67 !
68 !
71 !
72 !-------------------------------------------------------------------------
73 module kronlininv
74 
75  use realprec
76  use, intrinsic :: iso_fortran_env, only: output_unit
77 
78  implicit none
79 !#ifdef omppara
80  include 'omp_lib.h'
81 !#endif
82 
83 
84  private :: solvels,symgeneigvv,symsolvels
86 
87 contains
88 
89  !!!=====================================================
90  !--------------------------------------------------
91  ! DESCRIPTION:
180  ! REVISION HISTORY:
182  !
183  !--------------------------------------------------
184  subroutine calcfactors(G1,G2,G3,Cm1,Cm2,Cm3,Cd1,Cd2,Cd3,&
185  U1,U2,U3,diaginvlambda,iUCm1,iUCm2,iUCm3,&
186  iUCmGtiCd1,iUCmGtiCd2,iUCmGtiCd3 )
187 
188  real(dp),intent(in) :: G1(:,:),G2(:,:),G3(:,:),&
189  Cm1(:,:),Cm2(:,:),Cm3(:,:),&
190  Cd1(:,:),Cd2(:,:),Cd3(:,:)
191 
192  real(dp),intent(out) :: U1(:,:),U2(:,:),U3(:,:),&
193  iUCm1(:,:),iUCm2(:,:),iUCm3(:,:),&
194  iUCmGtiCd1(:,:),iUCmGtiCd2(:,:),iUCmGtiCd3(:,:),&
195  diaginvlambda(:)
196 
197  real(dp),allocatable :: lambda1(:),lambda2(:),lambda3(:)
198  real(dp),allocatable :: iCdG1(:,:),iCdG2(:,:),iCdG3(:,:),&
199  GtiCdG1(:,:),GtiCdG2(:,:),GtiCdG3(:,:),&
200  ide1(:,:),ide2(:,:),ide3(:,:),&
201  iCd1(:,:),iCd2(:,:),iCd3(:,:)
202  integer :: i,j,k,p,nm,nm1,nm2,nm3,nd1,nd2,nd3
203  character :: uplo
204 
205  !! Lapack routines
206  external dsygv
207 
208  nm1 = size(cm1,1)
209  nm2 = size(cm2,1)
210  nm3 = size(cm3,1)
211  nd1 = size(cd1,1)
212  nd2 = size(cd2,1)
213  nd3 = size(cd3,1)
214  nm = nm1*nm2*nm3
215 
216  !! compute preliminary stuff
217  print*,'calcfactors(): compute preliminary stuff'
218  allocate(icdg1(nd1,nm1),icdg2(nd2,nm2),icdg3(nd3,nm3))
219  call symsolvels( cd1, g1, icdg1 )
220  call symsolvels( cd2, g2, icdg2 )
221  call symsolvels( cd3, g3, icdg3 )
222 
223  !allocate(GtiCdG1(nm1,nm1),GtiCdG2(nm2,nm2),GtiCdG3(nm3,nm3))
224  gticdg1 = matmul( transpose(g1), icdg1 )
225  gticdg2 = matmul( transpose(g2), icdg2 )
226  gticdg3 = matmul( transpose(g3), icdg3 )
227 
228  !!--------------------------
229  !! fa
230  !!--------------------------
231  !! compute eigendecomposition
232  print*,'calcfactors(): compute fa'
233  allocate(lambda1(nm1),lambda2(nm2),lambda3(nm3))
234  uplo = 'L'
235  call symgeneigvv(gticdg1,uplo,cm1,lambda1,u1)
236  call symgeneigvv(gticdg2,uplo,cm2,lambda2,u2)
237  call symgeneigvv(gticdg3,uplo,cm3,lambda3,u3)
238 
239  !!--------------------------
240  !! fb
241  !!--------------------------
242  !! calculates diagonal central factor
243  print*,'calcfactors():compute fb'
244  p=1
245  do i=1,nm1
246  do j=1,nm2
247  do k=1,nm3
248  diaginvlambda(p) = 1.0_dp/(1.0_dp+lambda1(i)*lambda2(j)*lambda3(k))
249  p = p+1
250  end do
251  end do
252  end do
253 
254  !!--------------------------
255  !! fc
256  !!--------------------------
257  !! computes U1^-1 Cmx, U2^-1 Cmy, U3^-1 Cmz
258  print*,'calcfactors(): compute fc'
259  call solvels( u1, cm1, iucm1 )
260  call solvels( u2, cm2, iucm2 )
261  call solvels( u3, cm3, iucm3 )
262 
263  !!--------------------------
264  !! fd
265  !!--------------------------
266  print*,'calcfactors(): compute fd'
267  allocate(ide1(nd1,nd1),ide2(nd2,nd2),ide3(nd3,nd3))
268  ide1 = 0.0_dp ! Initialize the array.
269  ide2 = 0.0_dp
270  ide3 = 0.0_dp
271  forall(i = 1:nd1) ide1(i,i) = 1.0_dp ! Set the diagonal.
272  forall(i = 1:nd2) ide2(i,i) = 1.0_dp
273  forall(i = 1:nd3) ide3(i,i) = 1.0_dp
274  allocate(icd1(nd1,nd1),icd2(nd2,nd2),icd3(nd3,nd3))
275  call symsolvels( cd1, ide1, icd1 )
276  call symsolvels( cd2, ide2, icd2 )
277  call symsolvels( cd3, ide3, icd3 )
278 
279  iucmgticd1 = matmul( iucm1, matmul( transpose(g1), icd1 ))
280  iucmgticd2 = matmul( iucm2, matmul( transpose(g2), icd2 ))
281  iucmgticd3 = matmul( iucm3, matmul( transpose(g3), icd3 ))
282 
283  ! print*,
284  ! print*,shape(U1),shape(U2),shape(U3)
285  ! print*,shape(iUCm1),shape(iUCm2),shape(iUCm3)
286  ! print*,shape(iUCmGtiCd1),shape(iUCmGtiCd2),shape(iUCmGtiCd3)
287  ! print*,
288  print*,'calcfactors(): end '
289  end subroutine calcfactors
290 
291  !!!==================================================
292  !-------------------------------------------------
294  !
304  !
305  !
306  ! REVISION HISTORY:
310  !
311  !-------------------------------------------------
312  subroutine blockpostcov(U1,U2,U3, diaginvlambda, &
313  iUCm1,iUCm2,iUCm3, astart,aend,bstart,bend, postC)
314  !!
315  !! Calculates a block of the posterior covariance
316  !!
317  real(dp),intent(in) :: U1(:,:),U2(:,:),U3(:,:),iUCm1(:,:), &
318  iUCm2(:,:),iUCm3(:,:)
319  !! diaginvlambda = (I + lam1 x lam2 x lam3 )^-1
320  real(dp),intent(in) :: diaginvlambda(:) !! diagonal/vector central factor
321  real(dp),intent(out) :: postC(:,:)
322  integer,intent(in) :: astart,aend,bstart,bend
323 
324  integer :: a,b
325  real(dp),allocatable :: row1(:),row2(:),col1(:)
326  integer :: Nr12,Nc1
327  integer :: Ni,Nj,Nk,Nl,Nm,Nn,Na,Nb
328 
329  integer,allocatable :: av(:)!,bv(:)
330  integer,allocatable :: iv(:),jv(:),kv(:) !,lv(:),mv(:),nv(:)
331  integer :: p,csha1,csha2,everynit,nthr,privcount,totcount
332  real(dp) :: eta,frac,startt,endt
333 
334  ni = size(u1,1)
335  nl = size(u1,2)
336  nj = size(u2,1)
337  nm = size(u2,2)
338  nk = size(u3,1)
339  nn = size(u3,2)
340  na = ni*nj*nk
341  nb = nl*nm*nn
342 
343  !! check shape of output array
344  if (na /= nb) then
345  write(*,*) '(Na /= Nb)', na,nb
346  stop
347  end if
348  csha1 = aend-astart+1
349  csha2 = bend-bstart+1
350  if ( (size(postc,1)/=csha1) .or. (size(postc,2)/=csha2)) then
351  write(*,*) "Wrong size of the posterior covariance block array."
352  stop
353  end if
354  !! check limits of requested block
355  if ( (astart<1) .or. (aend>na) .or. (astart>aend) .or. &
356  (bstart<1) .or. (bend>na) .or. (bstart>bend) ) then
357  write(*,*) "Wrong size of the requested block array."
358  stop
359  end if
360 
361  !! vectorize row and col calculations for Kron prod AxBxC
362  allocate(av(na),iv(na),jv(na),kv(na))
363  !allocate(bv(Nb),lv(Nb),mv(Nb),nv(Nb))
364  forall(p = 1:na) av(p) = p
365  !forall(p = 1:Nb) bv(p) = p
366 
367  !! vectors containing all possible indices for
368  !! row calculations of Kron prod AxBxC
369  iv = (av-1)/(nk*nj)+1
370  jv = (av-1-(iv-1)*nk*nj)/nk + 1
371  kv = av-(jv-1)*nk-(iv-1)*nk*nj
372 
373  !! allocate stuff
374  nr12 = size(u1,2)* size(u2,2)* size(u3,2)
375  nc1 = size(iucm1,1)* size(iucm2,1)* size(iucm3,1)
376  allocate(row1(nr12),row2(nr12),col1(nc1))
377 
378  !!------------------------
379  if (aend-astart+1<20) then
380  everynit = 1
381  else if (aend-astart+1<100000) then
382  everynit = (aend-astart+1)/100
383  else
384  everynit = (aend-astart+1)/1000
385  end if
386 
387 
388  !!------------------------
389  !$OMP PARALLEL PRIVATE(privcount)
390  startt = omp_get_wtime()
391  nthr = omp_get_num_threads()
392 
393  totcount = aend-astart+1
394  privcount = -1
395  if ( omp_get_thread_num()==0 ) write(output_unit,*)
396  !$OMP DO PRIVATE(row2,col1,a,b)
397  do a=astart,aend
398  privcount = privcount + 1
399  if ( (omp_get_thread_num()==0 ) .and. (mod(privcount,everynit/nthr)==0) ) then
400  frac = real(privcount,dp)/(real(totcount,dp)/real(nthr,dp))
401  eta = ( (omp_get_wtime()-startt) / real(privcount,dp) ) * &
402  (real(totcount-nthr*privcount,dp)/real(nthr,dp))
403  write(output_unit,fmt='(a19,f7.3,6x,a4,f12.2,1x,a3,a5)') 'blockpostcov(): %',&
404  frac*100_dp,"ETA:",eta/60.0,"min",char(27)//'[1A'//achar(13)
405  flush(output_unit) !! to make sure it prints immediately
406  end if
407 
408  !! row first two factors
409  !! a row x diag matrix
410  !!row2 = U1(iv(a),lv) * U2(jv(a),mv) * U3(kv(a),nv) * diaginvlambda
411  row2 = u1(iv(a),iv) * u2(jv(a),jv) * u3(kv(a),kv) * diaginvlambda
412 
413  do b=bstart,bend
414 
415  !! calculate one row of first TWO factors
416  !!call columnAxBxC(Ni,Nj,Nk,Nl,Nm,Nn, iUCm1,iUCm2,iUCm3,b,col1)
417  col1 = iucm1(iv,iv(b)) * iucm2(jv,jv(b)) * iucm3(kv,kv(b))
418 
419  !! calculate one element of the posterior covariance
420  postc(a,b) = sum(row2*col1)
421 
422  end do
423  end do
424  !$OMP END DO
425  endt = omp_get_wtime()
426  !$OMP END PARALLEL
427  write(output_unit,*)
428  print*,"blockpostcov():",endt-startt," OMP wall clock time"
429 
430  end subroutine blockpostcov
431 
432  !!!==================================================
433  !-------------------------------------------------
444  !
445  !
446  ! REVISION HISTORY:
449  !
450  !-------------------------------------------------
451  subroutine bandpostcov(U1,U2,U3, diaginvlambda, &
452  iUCm1,iUCm2,iUCm3, lowdiag, updiag, bandpostC)
453  !!
454  !! Calculate a band of the posterior covariance
455  !!
456  real(dp),intent(in) :: U1(:,:),U2(:,:),U3(:,:),iUCm1(:,:), &
457  iUCm2(:,:),iUCm3(:,:)
458  !! diaginvlambda = (I + lam1 x lam2 x lam3 )^-1
459  real(dp),intent(in) :: diaginvlambda(:) !! diagonal/vector central factor
460  real(dp),intent(inout) :: bandpostC(:,:)
461  integer,intent(in) :: lowdiag, updiag
462 
463  integer :: a,b
464  real(dp),allocatable :: row1(:),row2(:),col1(:)
465  integer :: Nr12,Nc1
466  integer :: Ni,Nj,Nk,Nl,Nm,Nn,Na,Nb
467 
468  integer,allocatable :: av(:)!,bv(:)
469  integer,allocatable :: iv(:),jv(:),kv(:) !,lv(:),mv(:),nv(:)
470  integer :: p,aband,aend,bband,astart,d
471  integer :: nthr,privcount,everynit
472  real(dp) :: eta,frac,startt,firststartt,endt
473 
474  ni = size(u1,1)
475  nl = size(u1,2)
476  nj = size(u2,1)
477  nm = size(u2,2)
478  nk = size(u3,1)
479  nn = size(u3,2)
480  na = ni*nj*nk
481  nb = nl*nm*nn
482 
483  if (na /= nb) then
484  write(*,*) '(Na /= Nb)', na,nb
485  stop
486  end if
487  if ( (updiag>=na) .or. (lowdiag>=na) .or. (lowdiag<0) .or. (updiag<0) ) then
488  write(*,*) .or."(updiag<Na) (lowdiag<Na)"
489  write(*,*) "updiag",updiag,"Na",na,"lowdiag",lowdiag,"Na",na
490  stop
491  end if
492 
493  !! vectorize row and col calculations for Kron prod AxBxC
494  allocate(av(na),iv(na),jv(na),kv(na))
495  !allocate(bv(Nb),lv(Nb),mv(Nb),nv(Nb))
496  forall(p = 1:na) av(p) = p
497  !forall(p = 1:Nb) bv(p) = p
498 
499  !! vectors containing all possible indices for
500  !! row calculations of Kron prod AxBxC
501  iv = (av-1)/(nk*nj)+1
502  jv = (av-1-(iv-1)*nk*nj)/nk+1
503  kv = av-(jv-1)*nk-(iv-1)*nk*nj
504  !! vectors containing all possible indices for
505  !! column calculations of Kron prod AxBxC
506  ! lv = (bv-1)/(Nn*Nm) + 1
507  ! mv = (bv-1-(lv-1)*Nn*Nm)/Nn + 1
508  ! nv = bv-(mv-1)*Nn-(lv-1)*Nn*Nm
509 
510  !! allocate stuff
511  nr12 = size(u1,2)* size(u2,2)* size(u3,2)
512  nc1 = size(iucm1,1)* size(iucm2,1)* size(iucm3,1)
513  allocate(row1(nr12),row2(nr12),col1(nc1))
514 
515 
516  everynit = 250
517 
518 
519  ! Lapack: http://www.netlib.org/lapack/lug/node124.html
520  ! aij is stored in AB(ku+1+i-j,j) for max(1,j-ku) <= i <= \min(m,j+kl).
521  !------------
522  ! Diagonals of a matrix
523  ! i + d = j
524  ! main diag d = 0
525  ! upper d > 0
526  ! lower d < 0
527  ! diagonals of a matrix and indices of related band matrix
528  ! ONLY for square matrix
529 
530  ! initialize postC
531  bandpostc = 0.0_dp
532 
533  !!=====================================
534  firststartt = omp_get_wtime()
535 
536  do d=-lowdiag,updiag
537  if (d<0) then
538  astart = abs(d)+1
539  else
540  astart = 1
541  end if
542  if (d>0) then
543  aend = na-abs(d)
544  else
545  aend = na
546  end if
547  !print*,'diagonal',d
548  !! indices of normal matrix
549 
550  print*,"Diagonal ",d," from range [",-lowdiag,",",updiag,"]"
551  !-------------------------
552  !$OMP PARALLEL
553  privcount = -1
554  startt = omp_get_wtime()
555  nthr = omp_get_num_threads()
556 
557  !$OMP DO PRIVATE(row2,col1,a,b,aband,bband,privcount)
558  do a=astart,aend
559  privcount = privcount + 1
560  if ( (omp_get_thread_num()==0 ) .and. (mod(privcount,everynit/nthr)==0) ) then
561  frac = real(privcount,dp)/(real(nb,dp)/real(nthr,dp))
562  eta = ( (omp_get_wtime()-startt) / real(privcount,dp) ) * &
563  (real(aend-astart+1-nthr*privcount,dp)/real(nthr,dp))
564  write(output_unit,fmt='(a27,f7.3,6x,a4,f12.2,1x,a3,a5)') 'bandpostcov(): %',&
565  frac*100_dp,"ETA:",eta/60.0,"min",char(27)//'[1A'//achar(13)
566  flush(output_unit) !! to make sure it prints immediately
567  end if
568 
569  b = a+d
570  !! indices of the band matrix
571  aband = updiag+1+a-b
572  bband = b
573 
574  !! row first two factors
575  row2 = diaginvlambda * u1(iv(a),iv) * u2(jv(a),jv) * u3(kv(a),kv)
576 
577  !! calculate one row of first TWO factors
578  !!call columnAxBxC(Ni,Nj,Nk,Nl,Nm,Nn, iUCm1,iUCm2,iUCm3,b,col1)
579  col1 = iucm1(iv,iv(b)) * iucm2(jv,jv(b)) * iucm3(kv,kv(b))
580 
581  !! calculate one element of the posterior covariance
582  !! store it in the band storage format
583  bandpostc(aband,bband) = sum(row2*col1)
584  !print*, a,b,aband,bband,bandpostC(aband,bband)
585 
586  end do ! a=astart,aend
587  !$OMP END DO
588  endt = omp_get_wtime()
589  !$OMP END PARALLEL
590  write(output_unit,*)
591  print*,"bandpostcov():",endt-firststartt," OMP wall clock time"
592 
593  end do
594 
595 
596  end subroutine bandpostcov
597 
598  !!!===============================================================
599  !-------------------------------------------------
601  !
618  !
619  !
620  ! REVISION HISTORY:
623  !
624  !-------------------------------------------------
625  subroutine posteriormean(U1,U2,U3, diaginvlambda, Z1,Z2,Z3,&
626  G1,G2,G3, mprior, dobs, postm)
627  !!
628  !! Calculate the posterior mean model
629  !!
630  real(dp),intent(in) :: U1(:,:),U2(:,:),U3(:,:), G1(:,:),G2(:,:),G3(:,:)
631  real(dp),intent(in) :: Z1(:,:),Z2(:,:),Z3(:,:)
632  real(dp),intent(in) :: mprior(:),dobs(:),diaginvlambda(:)
633  real(dp),intent(out) :: postm(:)
634 
635  real(dp),allocatable :: row2(:),col1(:),bigmatrow(:),datrow(:)
636  real(dp),allocatable :: ddiff(:)
637  integer :: Nr12,Nc1,a,b,Na,Nb
638  integer :: Ni,Nj,Nk,Nl,Nm,Nn
639 
640  integer,allocatable :: av(:),bv(:)
641  integer,allocatable :: iv(:),jv(:),kv(:),lv(:),mv(:),nv(:)
642  !! ivo(:),jvo(:),kvo(:)
643  integer :: p,j,i,everynit
644 
645  real(dp),allocatable :: Zh(:),elUDZh(:)
646  real(dp) :: datp,elg,elrowud,tZZ
647 
648  integer :: nsteps,hr,min,nthread,privcount,nthr
649  real(dp) :: eta,et1,et2,sec,startt,firststartt,endt,finish,frac
650  character(8) :: curdate
651  character(10) :: curtime
652 
653  write(output_unit,*) "posteriormean(): calculating posterior mean... [using OpenMP]"
654 
655  !! sizes
656  ni = size(z1,1)
657  nl = size(z1,2)
658  nj = size(z2,1)
659  nm = size(z2,2)
660  nk = size(z3,1)
661  nn = size(z3,2)
662 
663  !! sizes
664  ! Nr12 = size(U1,2)*size(U2,2)*size(U3,2)
665  ! Nc1 = size(Z1,1)*size(Z2,1)*size(Z3,1)
666  na = size(mprior,1)
667  nb = size(dobs,1)
668 
669  !! allocate stuff
670  allocate(ddiff(nb))
671  allocate(zh(na),eludzh(na))
672 
673  !! vectorize row and col calculations for Kron prod AxBxC
674  !!allocate(ivo(Nb),jvo(Nb),kvo(Nb))
675  allocate(av(na),iv(na),jv(na),kv(na))
676  allocate(bv(nb),lv(nb),mv(nb),nv(nb))
677  forall(p = 1:na) av(p) = p
678  forall(p = 1:nb) bv(p) = p
679 
680  !! vectors containing all possible indices for
681  !! row calculations of Kron prod AxBxC
682  iv = (av-1)/(nk*nj)+1
683  jv = (av-1-(iv-1)*nk*nj)/nk+1
684  kv = av-(jv-1)*nk-(iv-1)*nk*nj
685  !! vectors containing all possible indices for
686  !! column calculations of Kron prod AxBxC
687  lv = (bv-1)/(nn*nm) + 1
688  mv = (bv-1-(lv-1)*nn*nm)/nn + 1
689  nv = bv-(mv-1)*nn-(lv-1)*nn*nm
690  !! Gs have different shape than Us !!
691 
692  !!#######################
693  if (na<1000)then
694  everynit = na/50
695  else if (na<100000) then
696  everynit = na/100
697  else
698  everynit = na/1000
699  end if
700 
701 
702  !!---------------------------------
703  !$OMP PARALLEL PRIVATE(privcount)
704  firststartt = omp_get_wtime()
705  nthr = omp_get_num_threads()
706 
707  !!#######################
708  !!# dobs - dcalc #
709  !!#######################
710  startt= omp_get_wtime()
711  privcount = -1
712  !$OMP DO PRIVATE(b)
713  !! difference obs-calc data
714  do b=1,nb
715  privcount = privcount + 1
716  if ( (omp_get_thread_num()==0 ) .and. (mod(privcount,everynit/nthr)==0) ) then
717  frac = real(privcount,dp)/(real(nb,dp)/real(nthr,dp))
718  eta = ( (omp_get_wtime()-startt) / real(privcount,dp) ) * &
719  (real(nb-nthr*privcount,dp)/real(nthr,dp))
720  write(output_unit,fmt='(a27,f7.3,6x,a4,f12.2,1x,a3,a5)') 'posteriormean() loop 1/3: %',&
721  frac*100_dp,"ETA:",eta/60.0,"min",char(27)//'[1A'//achar(13)
722  flush(output_unit) !! to make sure it prints immediately
723  end if
724 
725  !!---------------------------------------------------------------------------
726  ddiff(b) = dobs(b) - sum(mprior * g1(lv(b),iv) * g2(mv(b),jv) * g3(nv(b),kv))
727  !!---------------------------------------------------------------------------
728 
729  end do
730  !$OMP END DO
731 
732  !!#######################
733  !!# === U d Z h === #
734  !!#######################
735  privcount = -1
736  startt= omp_get_wtime()
737  !$OMP DO PRIVATE(a)
738  do a=1,na
739  privcount = privcount + 1
740  if ( (omp_get_thread_num()==0 ) .and. (mod(privcount,everynit/nthr)==0) ) then
741  frac = real(privcount,dp)/(real(na,dp)/real(nthr,dp))
742  eta = ( (omp_get_wtime()-startt) / real(privcount,dp) ) * &
743  (real(na-nthr*privcount,dp)/real(nthr,dp))
744  write(output_unit,fmt='(a27,f7.3,6x,a4,f12.2,1x,a3,a5)') 'posteriormean() loop 2/3: %',&
745  frac*100_dp,"ETA:",eta/60.0,"min",char(27)//'[1A'//achar(13)
746  flush(output_unit) !! to make sure it prints immediately
747  end if
748 
749  !!---------------------------------------------------------------------------
750  zh(a) = sum( z1(iv(a),lv) * z2(jv(a),mv) * z3(kv(a),nv) * ddiff )
751  !!---------------------------------------------------------------------------
752 
753  end do
754  !$OMP END DO
755 
756  !!-----------------------------------------------
757  !! Second loop
758  !!### need to re-loop because full Zh is needed
759  !!#######################
760  !!# post(a) #
761  !!#######################
762  privcount = -1
763  startt= omp_get_wtime()
764  !$OMP DO PRIVATE(a)
765  do a=1,na
766  privcount = privcount + 1
767  if ( (omp_get_thread_num()==0 ) .and. (mod(privcount,everynit/nthr)==0) ) then
768  frac = real(privcount,dp)/(real(na,dp)/real(nthr,dp))
769  eta = ( (omp_get_wtime()-startt) / real(privcount,dp) ) * &
770  (real(na-nthr*privcount,dp)/real(nthr,dp))
771  write(output_unit,fmt='(a27,f7.3,6x,a4,f12.2,1x,a3,a5)') 'posteriormean() loop 3/3: %',&
772  frac*100_dp,"ETA:",eta/60.0,"min",char(27)//'[1A'//achar(13)
773  flush(output_unit) !! to make sure it prints immediately
774  end if
775 
776  !!--------------------------------------------------------------------------------
777  eludzh(a) = sum( u1(iv(a),iv) * u2(jv(a),jv) * u3(kv(a),kv) * diaginvlambda * zh )
778  !! element of the posterior mean
779  postm(a) = mprior(a) + eludzh(a)
780  !!--------------------------------------------------------------------------------
781 
782  end do
783  !$OMP END DO
784  endt = omp_get_wtime()
785  !$OMP END PARALLEL
786  write(output_unit,*)
787  print*,"posteriormean():",endt-firststartt," OMP wall clock time"
788 
789  end subroutine posteriormean
790 
791  !!!==================================================
792  !-------------------------------------------------
804  !
805  !
806  ! REVISION HISTORY:
808  !
809  !-------------------------------------------------
810  subroutine symgeneigvv(A,uplo,Bpd,lambda,U)
811  real(dp),intent(in) :: A(:,:),Bpd(:,:)
812  character,intent(in) :: uplo
813  real(dp),intent(out) :: lambda(:),U(:,:)
814  integer :: n,lwork,itype,info
815  character :: jobz
816  real(dp),allocatable :: work(:),tmpB(:,:)
817  ! DSYGV computes all the eigenvalues, and optionally, the eigenvectors
818  ! of a real generalized symmetric-definite eigenproblem, of the form
819  ! A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x.
820  ! Here A and B are assumed to be symmetric and B is also
821  ! positive definite.
822  itype = 3
823  jobz = 'V'
824  n=size(a,1)
825  if ( (size(a,2)/=n) .or. (size(bpd,1)/=n) .or. (size(bpd,2)/=n) ) then
826  write(*,*) "symgeneigvv(): Matrices have wrong sizes"
827  stop
828  end if
829  allocate(tmpb(n,n))
830  u = a
831  tmpb = bpd
832  lwork=3*n-1
833  ! lwork=-1
834  ! allocate(work(1))
835  ! call DSYGV(itype,jobz,uplo,nm1,U1,nm1,choCm1,nm1,lambda1,work,lwork,info)
836  ! deallocate(work)
837  allocate(work(lwork))
838  call dsygv(itype,jobz,uplo,n,u,n,tmpb,n,lambda,work,lwork,info)
839  if (info /= 0) stop 'symgeneigvv(): Matrix eigendecomposition failed!'
840  end subroutine symgeneigvv
841 
842  !!!==================================================
843  !-------------------------------------------------
846  !
850  !
851  !
852  ! REVISION HISTORY:
854  !
855  !-------------------------------------------------
856  subroutine solvels( A, B, sol )
857  real(dp),intent(in) :: A(:,:),B(:,:)
858  real(dp),intent(out) :: sol(:,:)
859  integer,allocatable :: ipiv(:)
860  integer :: n,nrhs,lda,ldb
861  integer :: info
862  real(dp),allocatable :: A2(:,:)
863  ! External procedures defined in LAPACK
864  external dgesv
865  n = size(a,1)
866  nrhs = size(b,2)
867  allocate(a2(n,n))
868  a2 = a
869  lda = size(a,1)
870  allocate(ipiv(n))
871  ldb = size(b,1)
872  sol = b
873  call dgesv(n,nrhs,a2,lda,ipiv,sol,ldb,info)
874  if (info/=0) then
875  write(*,*) "linear system solver failed...'"
876  print*,'info: ',info
877  stop
878  end if
879  end subroutine solvels
880 
881  !!!============================================================
882  !-------------------------------------------------
885  !
889  !
890  ! REVISION HISTORY:
892  !
893  !-------------------------------------------------
894  subroutine symsolvels( A, B, sol )
895  real(dp),intent(in) :: A(:,:),B(:,:)
896  real(dp),intent(out) :: sol(:,:)
897  integer,parameter :: wmax=3000 ! max size allowed for work
898  integer,allocatable :: ipiv(:)
899  integer :: n,nrhs,lda,ldb,lwork
900  character :: uplo
901  real(dp),allocatable :: work(:),A2(:,:)
902  integer :: info
903  ! External procedures defined in LAPACK
904  external dsysv
905  uplo = 'L'
906  n = size(a,1)
907  nrhs = size(b,2)
908  allocate(a2(n,n))
909  a2 = a
910  lda = size(a,1)
911  allocate(ipiv(n))
912  ldb = size(b,1)
913  ! copy B to sol to avoid it to be overwritten
914  sol = b
915  ! apparently work must be allocated for the query to dsysv to work...
916  allocate(work(1))
917  lwork = -1
918  call dsysv(uplo,n,nrhs,a2,lda,ipiv,sol,ldb,work,lwork,info)
919  lwork = min(wmax,int(work(1)))
920  !! now lwork is assigned, so actually calculate eigvec/val
921  deallocate(work)
922  allocate(work(lwork))
923  call dsysv(uplo,n,nrhs,a2,lda,ipiv,sol,ldb,work,lwork,info)
924  if (info/=0) then
925  write(*,*) "linear system solver failed...'"
926  print*,'info: ',info
927  stop
928  end if
929  end subroutine symsolvels
930 
931  !!====================================================
932 
933 end module kronlininv
934 
935 !!====================================================
936 !!====================================================
subroutine, public bandpostcov(U1, U2, U3, diaginvlambda, iUCm1, iUCm2, iUCm3, lowdiag, updiag, bandpostC)
Computes a band of the posterior covariance. See http://www.netlib.org/lapack/lug/node124.html
Definition: kronlininv.f08:453
integer, parameter, public dp
subroutine, public calcfactors(G1, G2, G3, Cm1, Cm2, Cm3, Cd1, Cd2, Cd3, U1, U2, U3, diaginvlambda, iUCm1, iUCm2, iUCm3, iUCmGtiCd1, iUCmGtiCd2, iUCmGtiCd3)
Computes the factors necessary to solve the inverse problem.
Definition: kronlininv.f08:187
subroutine, private symgeneigvv(A, uplo, Bpd, lambda, U)
Computes eigenvalues and eigenvectors of the generalized symmetric definite eigenproblem. See http://www.netlib.org/lapack/lug/node54.html
Definition: kronlininv.f08:811
subroutine, public blockpostcov(U1, U2, U3, diaginvlambda, iUCm1, iUCm2, iUCm3, astart, aend, bstart, bend, postC)
Computes a block of the posterior covariance.
Definition: kronlininv.f08:314
integer, parameter, public rexprange
subroutine, private symsolvels(A, B, sol)
Solves a linear system AX = B for symmetric A, real numbers
Definition: kronlininv.f08:895
integer, parameter, public pdigits
subroutine, public posteriormean(U1, U2, U3, diaginvlambda, Z1, Z2, Z3, G1, G2, G3, mprior, dobs, postm)
Computes the posterior mean
Definition: kronlininv.f08:627
This file contains the parallel OpenMPI (distributed memory) version of KronLinInv. OpenMPI and LAPACK libraries are required to be installed in the system.
Procedures to perform linear inversion under gaussian assumptions using the Kronecker-product approac...
Definition: kronlininv.f08:73
subroutine, private solvels(A, B, sol)
Solves a linear system AX = B, real numbers
Definition: kronlininv.f08:857