FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
hecmw_local_matrix.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2019 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
5 
7  use hecmw_util
9 
10  private
11  public :: hecmwst_local_matrix
12  public :: hecmw_localmat_write
13  public :: hecmw_localmat_blocking
14  public :: hecmw_localmat_free
15  public :: hecmw_localmat_mulvec
16  public :: hecmw_trimatmul_ttkt
18  public :: hecmw_trimatmul_ttkt_mpc
19  public :: hecmw_localmat_transpose
20  public :: hecmw_localmat_assemble
21  public :: hecmw_localmat_add
24  public :: hecmw_localmat_multmat
26 
27  type hecmwst_local_matrix
28  integer :: nr, nc, nnz, ndof
29  integer(kind=kint), pointer :: index(:)
30  integer(kind=kint), pointer :: item(:)
31  real(kind=kreal), pointer :: a(:)
32  end type hecmwst_local_matrix
33 
34  integer(kind=kint), parameter :: cNCOL_ITEM = 3
35  integer(kind=kint), parameter :: cLID = 1
36  integer(kind=kint), parameter :: cRANK = 2
37  integer(kind=kint), parameter :: cGID = 3
38 
39  integer(kind=kint), parameter :: DEBUG = 0
40  integer(kind=kint), parameter :: DEBUG_MATRIX = 0
41  integer(kind=kint), parameter :: TIMER = 0
42 
43 contains
44 
45  subroutine hecmw_localmat_write(Tmat,iunit)
46  implicit none
47  type (hecmwst_local_matrix), intent(in) :: tmat
48  integer(kind=kint), intent(in) :: iunit
49  integer(kind=kint) :: nr, nc, nnz, ndof, ndof2, i, js, je, j, jj
50  character(len=64) :: fmt
51  nr=tmat%nr
52  nc=tmat%nc
53  nnz=tmat%nnz
54  ndof=tmat%ndof
55  ndof2=ndof*ndof
56  write(iunit,'(a,4i10)') 'nr, nc, nnz, ndof', nr, nc, nnz, ndof
57  write(iunit,'(a)') 'i, j, A'
58  write(fmt,'(a,i0,a)') '(',ndof,'f12.3)'
59  do i=1,nr
60  js=tmat%index(i-1)+1
61  je=tmat%index(i)
62  do j=js,je
63  jj=tmat%item(j)
64  if (ndof==1) then
65  write(iunit,'(2i10,f12.3)') i, jj, tmat%A(j)
66  else
67  write(iunit,'(2i10)') i, jj
68  write(iunit,fmt) tmat%A((j-1)*ndof2+1:j*ndof2)
69  endif
70  enddo
71  enddo
72  end subroutine hecmw_localmat_write
73 
74  subroutine hecmw_localmat_write_size(Tmat,iunit)
75  implicit none
76  type (hecmwst_local_matrix), intent(in) :: tmat
77  integer(kind=kint), intent(in) :: iunit
78  integer(kind=kint) :: nr, nc, nnz, ndof
79  nr=tmat%nr
80  nc=tmat%nc
81  nnz=tmat%nnz
82  ndof=tmat%ndof
83  write(iunit,'(a,4i10)') 'nr, nc, nnz, ndof', nr, nc, nnz, ndof
84  end subroutine hecmw_localmat_write_size
85 
86  subroutine hecmw_localmat_write_ij(Tmat,iunit)
87  implicit none
88  type (hecmwst_local_matrix), intent(in) :: tmat
89  integer(kind=kint), intent(in) :: iunit
90  integer(kind=kint) :: nr, nc, nnz, ndof, i, js, je, j, jj
91  nr=tmat%nr
92  nc=tmat%nc
93  nnz=tmat%nnz
94  ndof=tmat%ndof
95  write(iunit,'(a,4i10)') 'nr, nc, nnz, ndof', nr, nc, nnz, ndof
96  write(iunit,'(a)') 'i, j'
97  do i=1,nr
98  js=tmat%index(i-1)+1
99  je=tmat%index(i)
100  do j=js,je
101  jj=tmat%item(j)
102  write(iunit,'(2i10)') i, jj
103  enddo
104  enddo
105  end subroutine hecmw_localmat_write_ij
106 
107  subroutine hecmw_localmat_blocking(Tmat, ndof, BTmat)
108  implicit none
109  type (hecmwst_local_matrix), intent(in) :: tmat
110  integer, intent(in) :: ndof
111  type (hecmwst_local_matrix), intent(out) :: btmat
112  integer, allocatable :: iw(:)
113  integer :: ndof2, i, icnt, idof, idx, ls, le, l, j, jb, k, lb0, jdof, ks, ke
114  ndof2=ndof*ndof
115 
116  if (mod(tmat%nr, ndof) /= 0 .or. mod(tmat%nc, ndof) /= 0) then
117  write(0,*) tmat%nr, tmat%nc, ndof
118  stop 'ERROR: blocking_Tmat failed'
119  endif
120  btmat%nr=tmat%nr/ndof
121  btmat%nc=tmat%nc/ndof
122  btmat%ndof=ndof
123 
124  allocate(iw(btmat%nc))
125  allocate(btmat%index(0:btmat%nr))
126 
127  btmat%index(0)=0
128  do i=1,btmat%nr
129  icnt=0
130  do idof=1,ndof
131  idx=(i-1)*ndof+idof
132  ls=tmat%index(idx-1)+1
133  le=tmat%index(idx)
134  lcol: do l=ls,le
135  j=tmat%item(l)
136  jb=(j-1)/ndof+1
137  do k=1,icnt
138  if (iw(k)==jb) cycle lcol
139  enddo
140  icnt=icnt+1
141  iw(icnt)=jb
142  enddo lcol
143  enddo
144  btmat%index(i)=btmat%index(i-1)+icnt
145  enddo
146 
147  btmat%nnz=btmat%index(btmat%nr)
148  allocate(btmat%item(btmat%nnz))
149  allocate(btmat%A(btmat%nnz*ndof2))
150  btmat%A=0.d0
151 
152  do i=1,btmat%nr
153  icnt=0
154  do idof=1,ndof
155  idx=(i-1)*ndof+idof
156  ls=tmat%index(idx-1)+1
157  le=tmat%index(idx)
158  lcol2: do l=ls,le
159  j=tmat%item(l)
160  jb=(j-1)/ndof+1
161  do k=1,icnt
162  if (iw(k)==jb) cycle lcol2
163  enddo
164  icnt=icnt+1
165  iw(icnt)=jb
166  enddo lcol2
167  enddo
168  ! if (icnt /= BTmat%index(i)-BTmat%index(i-1)) stop 'ERROR: blocking Tmat'
169  ! ! call qsort(iw, 1, icnt)
170  lb0=btmat%index(i-1)
171  do k=1,icnt
172  btmat%item(lb0+k)=iw(k)
173  enddo
174  do idof=1,ndof
175  idx=(i-1)*ndof+idof
176  ls=tmat%index(idx-1)+1
177  le=tmat%index(idx)
178  lcol3: do l=ls,le
179  j=tmat%item(l)
180  jb=(j-1)/ndof+1
181  jdof=mod((j-1), ndof)+1
182  ks=btmat%index(i-1)+1
183  ke=btmat%index(i)
184  do k=ks,ke
185  if (btmat%item(k)==jb) then
186  btmat%A((k-1)*ndof2+(idof-1)*ndof+jdof)=tmat%A(l)
187  cycle lcol3
188  endif
189  enddo
190  stop 'ERROR: something wrong in blocking Tmat'
191  enddo lcol3
192  enddo
193  enddo
194  end subroutine hecmw_localmat_blocking
195 
196  subroutine hecmw_localmat_free(Tmat)
197  implicit none
198  type (hecmwst_local_matrix), intent(inout) :: tmat
199  deallocate(tmat%index)
200  if (associated(tmat%item)) deallocate(tmat%item)
201  if (associated(tmat%A)) deallocate(tmat%A)
202  tmat%nr=0
203  tmat%nc=0
204  tmat%nnz=0
205  tmat%ndof=0
206  end subroutine hecmw_localmat_free
207 
208  subroutine hecmw_trimatmul_ttkt(hecMESH, BTtmat, hecMAT, BTmat, &
209  iwS, num_lagrange, hecTKT)
211  implicit none
212  type (hecmwst_local_mesh), intent(inout) :: hecmesh
213  type (hecmwst_local_matrix), intent(inout) :: bttmat, btmat
214  type (hecmwst_matrix), intent(in) :: hecmat
215  integer(kind=kint), intent(in) :: iws(:)
216  integer(kind=kint), intent(in) :: num_lagrange
217  type (hecmwst_matrix), intent(inout) :: hectkt
218  if (hecmesh%n_neighbor_pe == 0) then
219  call hecmw_trimatmul_ttkt_serial(hecmesh, bttmat, hecmat, btmat, &
220  iws, num_lagrange, hectkt)
221  else
222  call hecmw_trimatmul_ttkt_parallel(hecmesh, bttmat, hecmat, btmat, &
223  iws, num_lagrange, hectkt)
224  endif
225  end subroutine hecmw_trimatmul_ttkt
226 
227  subroutine hecmw_trimatmul_ttkt_serial(hecMESH, BTtmat, hecMAT, BTmat, &
228  iwS, num_lagrange, hecTKT)
230  implicit none
231  type (hecmwst_local_mesh), intent(in) :: hecmesh
232  type (hecmwst_local_matrix), intent(in) :: bttmat, btmat
233  type (hecmwst_matrix), intent(in) :: hecmat
234  integer(kind=kint), intent(in) :: iws(:)
235  integer(kind=kint), intent(in) :: num_lagrange
236  type (hecmwst_matrix), intent(inout) :: hectkt
237  type (hecmwst_local_matrix) :: bttkt
238  real(kind=kreal) :: num
239 
240  ! perform three matrices multiplication for elimination
241  call trimatmul_ttkt(bttmat, hecmat, btmat, bttkt)
242  call debug_write_matrix(bttkt, 'BTtKT(MPC)', debug_matrix)
243 
244  ! place small numbers where the DOF is eliminated
245  !num = hecmw_mat_diag_max(hecMAT, hecMESH) * 1.0d-10
246  num = 1.d0
247  call place_num_on_diag(bttkt, iws, num_lagrange, num)
248  call debug_write_matrix(bttkt, 'BTtKT(MPC) (place 1.0 on slave diag)', debug_matrix)
249 
250  ! make_new HECMW matrix
251  call make_new_hecmat(hecmat, bttkt, hectkt)
252  call hecmw_localmat_free(bttkt)
253  end subroutine hecmw_trimatmul_ttkt_serial
254 
255  subroutine hecmw_trimatmul_ttkt_parallel(hecMESH, BTtmat, hecMAT, BTmat, &
256  iwS, num_lagrange, hecTKT)
258  implicit none
259  type (hecmwST_local_mesh), intent(inout) :: hecMESH
260  type (hecmwST_local_matrix), intent(inout) :: BTtmat, BTmat
261  type (hecmwST_matrix), intent(in) :: hecMAT
262  integer(kind=kint), intent(in) :: iwS(:)
263  integer(kind=kint), intent(in) :: num_lagrange
264  type (hecmwST_matrix), intent(inout) :: hecTKT
265  type (hecmwST_local_matrix) :: BKmat, BTtKmat, BTtKTmat
266  real(kind=kreal) :: num
267  real(kind=kreal) :: t0, t1
268 
269  ! perform three matrices multiplication for elimination
270  t0 = hecmw_wtime()
271  call hecmw_localmat_init_with_hecmat(bkmat, hecmat)
272  call debug_write_matrix(bkmat, 'BKmat (hecMAT)', debug_matrix)
273  t1 = hecmw_wtime()
274  if (timer >= 1) write(0, '(A,f10.4)') "#### hecmw_trimatmul_TtKT_parallel (1) : ",t1-t0
275 
276  t0 = hecmw_wtime()
277  call hecmw_localmat_multmat(bttmat, bkmat, hecmesh, bttkmat)
278  if (debug >= 2) write(0,*) ' DEBUG2: multiply Tt and K done'
279  call debug_write_matrix(bttkmat, 'BTtKmat', debug_matrix)
280  call hecmw_localmat_free(bkmat)
281  t1 = hecmw_wtime()
282  if (timer >= 1) write(0, '(A,f10.4)') "#### hecmw_trimatmul_TtKT_parallel (2) : ",t1-t0
283 
284  t0 = hecmw_wtime()
285  call hecmw_localmat_multmat(bttkmat, btmat, hecmesh, bttktmat)
286  if (debug >= 2) write(0,*) ' DEBUG2: multiply TtK and T done'
287  call debug_write_matrix(bttktmat, 'BTtKTmat', debug_matrix)
288  call hecmw_localmat_free(bttkmat)
289  t1 = hecmw_wtime()
290  if (timer >= 1) write(0, '(A,f10.4)') "#### hecmw_trimatmul_TtKT_parallel (3) : ",t1-t0
291 
292  t0 = hecmw_wtime()
293  ! place small numbers where the DOF is eliminated
294  !num = hecmw_mat_diag_max(hecMAT, hecMESH) * 1.0d-10
295  num = 1.d0
296  call place_num_on_diag(bttktmat, iws, num_lagrange, num)
297  if (debug >= 2) then
298  write(700+hecmw_comm_get_rank(),*) 'num_lagrange =', num_lagrange
299  if (debug >= 3) then
300  write(700+hecmw_comm_get_rank(),*) 'iwS(1:num_lagrange)'
301  write(700+hecmw_comm_get_rank(),*) iws(1:num_lagrange)
302  endif
303  endif
304  call debug_write_matrix(bttktmat, 'BTtKTmat (place 1.0 on slave diag)', debug_matrix)
305  t1 = hecmw_wtime()
306  if (timer >= 1) write(0, '(A,f10.4)') "#### hecmw_trimatmul_TtKT_parallel (4) : ",t1-t0
307 
308  t0 = hecmw_wtime()
309  ! make_new HECMW matrix
310  call make_new_hecmat(hecmat, bttktmat, hectkt)
311  call hecmw_localmat_free(bttktmat)
312  t1 = hecmw_wtime()
313  if (timer >= 1) write(0, '(A,f10.4)') "#### hecmw_trimatmul_TtKT_parallel (5) : ",t1-t0
314  end subroutine hecmw_trimatmul_ttkt_parallel
315 
316  subroutine trimatmul_ttkt(BTtmat, hecMAT, BTmat, BTtKT)
317  implicit none
318  type (hecmwST_local_matrix), intent(in) :: BTtmat, BTmat
319  type (hecmwST_matrix), intent(in) :: hecMAT
320  type (hecmwST_local_matrix), intent(out) :: BTtKT
321  integer :: nr, nc, ndof, ndof2, i, icnt, js, je, j, jj, ks, ke, k, kk
322  integer :: ls, le, l, ll, m, ms, me, mm
323  integer, allocatable :: iw(:)
324  real(kind=kreal), pointer :: ttp(:), kp(:), tp(:), ttktp(:)
325  ! real(kind=kreal) :: tsym_s, tsym_e, tnum_s, tnum_e
326 
327  nr=bttmat%nr
328  nc=btmat%nc
329  ndof=bttmat%ndof
330  ndof2=ndof*ndof
331 
332  bttkt%nr=nr
333  bttkt%nc=nc
334  bttkt%ndof=ndof
335  allocate(bttkt%index(0:nr))
336 
337  ! tsym_s = hecmw_wtime()
338 
339  !$omp parallel default(none), &
340  !$omp& private(iw,i,icnt,js,je,j,jj,ks,ke,k,kk,ls,le,l,ll,m), &
341  !$omp& shared(nr,nc,BTtmat,hecMAT,BTmat,BTtKT)
342  allocate(iw(nc))
343  !$omp do
344  do i=1,nr
345  icnt=0
346  js=bttmat%index(i-1)+1
347  je=bttmat%index(i)
348  do j=js,je
349  jj=bttmat%item(j)
350  ! lower
351  ks=hecmat%indexL(jj-1)+1
352  ke=hecmat%indexL(jj)
353  do k=ks,ke
354  kk=hecmat%itemL(k)
355  ls=btmat%index(kk-1)+1
356  le=btmat%index(kk)
357  ll1: do l=ls,le
358  ll=btmat%item(l)
359  do m=1,icnt
360  if (iw(m)==ll) cycle ll1
361  enddo
362  icnt=icnt+1
363  iw(icnt)=ll
364  !if (i==1) write(0,*) 'l', icnt, jj, kk, ll
365  enddo ll1
366  enddo
367  ! diagonal
368  ls=btmat%index(jj-1)+1
369  le=btmat%index(jj)
370  ll2: do l=ls,le
371  ll=btmat%item(l)
372  do m=1,icnt
373  if (iw(m)==ll) cycle ll2
374  enddo
375  icnt=icnt+1
376  iw(icnt)=ll
377  !if (i==1) write(0,*) 'd', icnt, jj, kk, ll
378  enddo ll2
379  ! upper
380  ks=hecmat%indexU(jj-1)+1
381  ke=hecmat%indexU(jj)
382  do k=ks,ke
383  kk=hecmat%itemU(k)
384  ls=btmat%index(kk-1)+1
385  le=btmat%index(kk)
386  ll3: do l=ls,le
387  ll=btmat%item(l)
388  do m=1,icnt
389  if (iw(m)==ll) cycle ll3
390  enddo
391  icnt=icnt+1
392  iw(icnt)=ll
393  !if (i==1) write(0,*) 'u', icnt, jj, kk, ll
394  enddo ll3
395  enddo
396  enddo
397  if (icnt == 0) icnt=1
398  !if (i==1) write(0,*) iw(1:icnt)
399  bttkt%index(i)=icnt
400  enddo
401  !$omp end do
402  deallocate(iw)
403  !$omp end parallel
404 
405  ! tsym_e = hecmw_wtime()
406  ! write(0,*) 'tsym:',tsym_e-tsym_s
407 
408  bttkt%index(0)=0
409  do i=1,nr
410  bttkt%index(i)=bttkt%index(i-1)+bttkt%index(i)
411  enddo
412  !write(0,*) BTtKT%index(1:n)-BTtKT%index(0:n-1)
413 
414  bttkt%nnz=bttkt%index(nr)
415  allocate(bttkt%item(bttkt%nnz))
416  allocate(bttkt%A(bttkt%nnz*ndof2))
417  bttkt%item=0
418  bttkt%A=0.d0
419 
420  ! tnum_s = hecmw_wtime()
421 
422  !$omp parallel default(none), &
423  !$omp& private(i,icnt,js,je,j,jj,ks,ke,k,kk,ls,le,l,ll,m, &
424  !$omp& ms,me,mm,Ttp,Kp,Tp,TtKTp), &
425  !$omp& shared(nr,nc,BTtmat,hecMAT,BTmat,BTtKT,ndof,ndof2)
426  !$omp do
427  do i=1,nr
428  icnt=0
429  ms=bttkt%index(i-1)+1
430  !me=BTtKT%index(i)
431  js=bttmat%index(i-1)+1
432  je=bttmat%index(i)
433  do j=js,je
434  jj=bttmat%item(j)
435  ttp=>bttmat%A((j-1)*ndof2+1:j*ndof2)
436  ! lower
437  ks=hecmat%indexL(jj-1)+1
438  ke=hecmat%indexL(jj)
439  do k=ks,ke
440  kk=hecmat%itemL(k)
441  kp=>hecmat%AL((k-1)*ndof2+1:k*ndof2)
442  ls=btmat%index(kk-1)+1
443  le=btmat%index(kk)
444  do l=ls,le
445  ll=btmat%item(l)
446  tp=>btmat%A((l-1)*ndof2+1:l*ndof2)
447  me=ms-1+icnt
448  mm=-1
449  do m=ms,me
450  if (bttkt%item(m)==ll) mm=m
451  enddo
452  if (mm<0) then
453  icnt=icnt+1
454  mm=me+1
455  bttkt%item(mm)=ll
456  !if (i==1) write(0,*) 'l', mm, jj, kk, ll
457  endif
458  ttktp=>bttkt%A((mm-1)*ndof2+1:mm*ndof2)
459  call blk_trimatmul_add(ndof, ttp, kp, tp, ttktp)
460  enddo
461  enddo
462  ! diagonal
463  kp=>hecmat%D((jj-1)*ndof2+1:jj*ndof2)
464  ls=btmat%index(jj-1)+1
465  le=btmat%index(jj)
466  do l=ls,le
467  ll=btmat%item(l)
468  tp=>btmat%A((l-1)*ndof2+1:l*ndof2)
469  me=ms-1+icnt
470  mm=-1
471  do m=ms,me
472  if (bttkt%item(m)==ll) mm=m
473  enddo
474  if (mm<0) then
475  icnt=icnt+1
476  mm=me+1
477  bttkt%item(mm)=ll
478  !if (i==1) write(0,*) 'd', mm, jj, kk, ll
479  endif
480  ttktp=>bttkt%A((mm-1)*ndof2+1:mm*ndof2)
481  call blk_trimatmul_add(ndof, ttp, kp, tp, ttktp)
482  enddo
483  ! upper
484  ks=hecmat%indexU(jj-1)+1
485  ke=hecmat%indexU(jj)
486  do k=ks,ke
487  kk=hecmat%itemU(k)
488  kp=>hecmat%AU((k-1)*ndof2+1:k*ndof2)
489  ls=btmat%index(kk-1)+1
490  le=btmat%index(kk)
491  do l=ls,le
492  ll=btmat%item(l)
493  tp=>btmat%A((l-1)*ndof2+1:l*ndof2)
494  me=ms-1+icnt
495  mm=-1
496  do m=ms,me
497  if (bttkt%item(m)==ll) mm=m
498  enddo
499  if (mm<0) then
500  icnt=icnt+1
501  mm=me+1
502  bttkt%item(mm)=ll
503  !if (i==1) write(0,*) 'u', mm, jj, kk, ll
504  endif
505  ttktp=>bttkt%A((mm-1)*ndof2+1:mm*ndof2)
506  call blk_trimatmul_add(ndof, ttp, kp, tp, ttktp)
507  enddo
508  enddo
509  enddo
510  if (icnt == 0) then
511  icnt=1
512  bttkt%item(ms)=i
513  endif
514  ! error check!
515  !write(0,*) BTtKT%item(ms:ms-1+icnt)
516  !write(0,*) BTtKT%index(i)-BTtKT%index(i-1), icnt
517  if (ms-1+icnt /= bttkt%index(i)) stop 'ERROR: trimatmul'
518  enddo
519  !$omp end do
520  !$omp end parallel
521 
522  ! tnum_e = hecmw_wtime()
523  ! write(0,*) 'tnum:',tnum_e-tnum_s
524  end subroutine trimatmul_ttkt
525 
526  subroutine blk_trimatmul_add(ndof, A, B, C, ABC)
527  implicit none
528  integer, intent(in) :: ndof
529  real(kind=kreal), intent(in) :: a(:), b(:), c(:)
530  real(kind=kreal), intent(inout) :: abc(:)
531  real(kind=kreal), allocatable :: ab(:)
532  integer :: ndof2, i, j, k, i0, j0, ij, ik, jk
533 
534  ndof2=ndof*ndof
535  allocate(ab(ndof2))
536  ab=0.d0
537 
538  do i=1,ndof
539  i0=(i-1)*ndof
540  do j=1,ndof
541  ij=i0+j
542  j0=(j-1)*ndof
543  do k=1,ndof
544  ik=i0+k
545  jk=j0+k
546  ab(ik)=ab(ik)+a(ij)*b(jk)
547  enddo
548  enddo
549  enddo
550 
551  do i=1,ndof
552  i0=(i-1)*ndof
553  do j=1,ndof
554  ij=i0+j
555  j0=(j-1)*ndof
556  do k=1,ndof
557  ik=i0+k
558  jk=j0+k
559  abc(ik)=abc(ik)+ab(ij)*c(jk)
560  enddo
561  enddo
562  enddo
563 
564  deallocate(ab)
565  end subroutine blk_trimatmul_add
566 
567  subroutine place_num_on_diag(BTtKT, iwS, num_lagrange, num)
568  implicit none
569  type (hecmwST_local_matrix), intent(inout) :: BTtKT
570  integer(kind=kint), intent(in) :: iwS(:)
571  integer(kind=kint), intent(in) :: num_lagrange
572  real(kind=kreal), intent(in) :: num
573  integer(kind=kint) :: ndof, ndof2, ilag, i, idof, js, je, j, jj
574  integer(kind=kint) :: nmissing, k, ks, ke
575  integer(kind=kint), allocatable :: missing(:), cnt(:)
576  integer(kind=kint), pointer :: index(:), item(:)
577  real(kind=kreal), pointer :: a(:)
578 
579  ndof=bttkt%ndof
580  ndof2=ndof*ndof
581 
582  ! check if there are places
583  allocate(missing(num_lagrange))
584  nmissing = 0
585  outer1: do ilag=1,num_lagrange
586  i=(iws(ilag)-1)/ndof+1
587  idof=mod(iws(ilag)-1, ndof)+1
588  js=bttkt%index(i-1)+1
589  je=bttkt%index(i)
590  do j=js,je
591  jj=bttkt%item(j)
592  if (jj==i) cycle outer1 ! found place
593  enddo
594  ! not found
595  do k=1,nmissing
596  if (missing(k) == i) cycle outer1 ! already marked as missing
597  enddo
598  nmissing = nmissing + 1
599  missing(nmissing) = i
600  enddo outer1
601 
602  ! if not, reallocate
603  if (nmissing > 0) then
604  allocate(cnt(bttkt%nr))
605  allocate(index(0:bttkt%nr))
606  do i=1,bttkt%nr
607  cnt(i) = bttkt%index(i) - bttkt%index(i-1)
608  enddo
609  do i=1,nmissing
610  cnt(missing(i)) = cnt(missing(i)) + 1
611  enddo
612  call make_index(bttkt%nr, cnt, index)
613  allocate(item(bttkt%nnz + nmissing))
614  allocate(a(ndof2 * (bttkt%nnz + nmissing)))
615  do i=1,bttkt%nr
616  ks=index(i-1)+1
617  js=bttkt%index(i-1)+1
618  je=bttkt%index(i)
619  item(ks:ks+(je-js))=bttkt%item(js:je)
620  a(ndof2*(ks-1)+1:ndof2*(ks+(je-js)))=bttkt%A(ndof2*(js-1)+1:ndof2*je)
621  enddo
622  do i=1,nmissing
623  ke=index(missing(i))
624  item(ke)=missing(i)
625  a(ndof2*(ke-1)+1:ndof2*ke)=0.d0
626  enddo
627  deallocate(bttkt%index)
628  deallocate(bttkt%item)
629  deallocate(bttkt%A)
630  bttkt%index => index
631  bttkt%item => item
632  bttkt%A => a
633  bttkt%nnz = index(bttkt%nr)
634  deallocate(cnt)
635  endif
636  deallocate(missing)
637 
638  ! place num
639  outer: do ilag=1,num_lagrange
640  i=(iws(ilag)-1)/ndof+1
641  idof=mod(iws(ilag)-1, ndof)+1
642  js=bttkt%index(i-1)+1
643  je=bttkt%index(i)
644  do j=js,je
645  jj=bttkt%item(j)
646  if (jj==i) then
647  !write(0,*) ilag, i, idof
648  bttkt%A((j-1)*ndof2+(idof-1)*ndof+idof)=num
649  cycle outer
650  endif
651  enddo
652  enddo outer
653  end subroutine place_num_on_diag
654 
655  subroutine replace_hecmat(hecMAT, BTtKT)
656  implicit none
657  type (hecmwST_matrix), intent(inout) :: hecMAT
658  type (hecmwST_local_matrix), intent(in) :: BTtKT
659  integer :: nr, nc, ndof, ndof2, i, nl, nu, js, je, j, jj
660  integer :: ksl, ksu, k
661 
662  nr=bttkt%nr
663  nc=bttkt%nc
664  ndof=hecmat%NDOF
665  ndof2=ndof*ndof
666 
667  ! free old hecMAT
668  if (associated(hecmat%AL)) deallocate(hecmat%AL)
669  if (associated(hecmat%AU)) deallocate(hecmat%AU)
670  if (associated(hecmat%itemL)) deallocate(hecmat%itemL)
671  if (associated(hecmat%itemU)) deallocate(hecmat%itemU)
672  hecmat%indexL=0
673  hecmat%indexU=0
674 
675  ! count NPL, NPU
676  !$omp parallel default(none),private(i,nl,nu,js,je,j,jj), &
677  !$omp& shared(nr,BTtKT,hecMAT)
678  !$omp do
679  do i=1,nr
680  nl=0
681  nu=0
682  js=bttkt%index(i-1)+1
683  je=bttkt%index(i)
684  do j=js,je
685  jj=bttkt%item(j)
686  if (jj < i) then
687  nl=nl+1
688  elseif (i < jj) then
689  nu=nu+1
690  else
691  ! diagonal
692  endif
693  enddo
694  hecmat%indexL(i)=nl
695  hecmat%indexU(i)=nu
696  enddo
697  !$omp end do
698  !$omp end parallel
699 
700  hecmat%indexL(0)=0
701  hecmat%indexU(0)=0
702  do i=1,nc
703  hecmat%indexL(i)=hecmat%indexL(i-1)+hecmat%indexL(i)
704  hecmat%indexU(i)=hecmat%indexU(i-1)+hecmat%indexU(i)
705  enddo
706  hecmat%NPL=hecmat%indexL(nc)
707  hecmat%NPU=hecmat%indexU(nc)
708 
709  ! allocate new hecMAT
710  allocate(hecmat%itemL(hecmat%NPL), hecmat%itemU(hecmat%NPU))
711  allocate(hecmat%AL(hecmat%NPL*ndof2), hecmat%AU(hecmat%NPU*ndof2))
712  hecmat%itemL=0
713  hecmat%itemU=0
714  hecmat%D=0.d0
715  hecmat%AL=0.d0
716  hecmat%AU=0.d0
717 
718  ! copy from BTtKT to hecMAT
719  !$omp parallel default(none),private(i,nl,nu,js,je,ksl,ksu,j,jj,k), &
720  !$omp& shared(nr,BTtKT,hecMAT,ndof2)
721  !$omp do
722  do i=1,nr
723  nl=0
724  nu=0
725  js=bttkt%index(i-1)+1
726  je=bttkt%index(i)
727  ksl=hecmat%indexL(i-1)+1
728  ksu=hecmat%indexU(i-1)+1
729  do j=js,je
730  jj=bttkt%item(j)
731  if (jj < i) then
732  k=ksl+nl
733  hecmat%itemL(k)=jj
734  hecmat%AL((k-1)*ndof2+1:k*ndof2)=bttkt%A((j-1)*ndof2+1:j*ndof2)
735  nl=nl+1
736  elseif (i < jj) then
737  k=ksu+nu
738  hecmat%itemU(k)=jj
739  hecmat%AU((k-1)*ndof2+1:k*ndof2)=bttkt%A((j-1)*ndof2+1:j*ndof2)
740  nu=nu+1
741  else
742  hecmat%D((i-1)*ndof2+1:i*ndof2)=bttkt%A((j-1)*ndof2+1:j*ndof2)
743  endif
744  enddo
745  ! if (ksl+nl /= hecMAT%indexL(i)+1) stop 'ERROR: indexL'
746  ! if (ksu+nu /= hecMAT%indexU(i)+1) stop 'ERROR: indexU'
747  enddo
748  !$omp end do
749  !$omp end parallel
750 
751  ! do i=1,hecMAT%NPL
752  ! if (hecMAT%itemL(i) <= 0) stop 'ERROR: negative itemL'
753  ! if (hecMAT%itemL(i) > nc) stop 'ERROR: too big itemL'
754  ! enddo
755  ! do i=1,hecMAT%NPU
756  ! if (hecMAT%itemU(i) <= 0) stop 'ERROR: negative itemU'
757  ! if (hecMAT%itemU(i) > nc) stop 'ERROR: too big itemU'
758  ! enddo
759  end subroutine replace_hecmat
760 
761  subroutine make_new_hecmat(hecMAT, BTtKT, hecTKT)
762  implicit none
763  type(hecmwst_matrix), intent(in) :: hecMAT
764  type(hecmwst_local_matrix), intent(in) :: BTtKT
765  type(hecmwst_matrix), intent(inout) :: hecTKT
766  integer(kind=kint) :: nr, nc, ndof, ndof2
767 
768  nr=bttkt%nr
769  nc=bttkt%nc
770  ndof=bttkt%ndof
771  ndof2=ndof*ndof
772 
773  !write(0,*) 'DEBUG: nr, nc =',nr,nc
774 
775  ! if (nr /= nc) then
776  ! stop 'ERROR: nr /= nc'
777  ! endif
778  hectkt%N =hecmat%N
779  hectkt%NP=nc
780  hectkt%NDOF=ndof
781 
782  if (associated(hectkt%D)) deallocate(hectkt%D)
783  allocate(hectkt%D(nc*ndof2))
784 
785  if (associated(hectkt%indexL)) deallocate(hectkt%indexL)
786  if (associated(hectkt%indexU)) deallocate(hectkt%indexU)
787  allocate(hectkt%indexL(0:nc))
788  allocate(hectkt%indexU(0:nc))
789 
790  hectkt%Iarray=hecmat%Iarray
791  hectkt%Rarray=hecmat%Rarray
792 
793  call replace_hecmat(hectkt, bttkt)
794  end subroutine make_new_hecmat
795 
796  subroutine hecmw_localmat_mulvec(BTmat, V, TV)
797  implicit none
798  type (hecmwst_local_matrix), intent(in) :: btmat
799  real(kind=kreal), intent(in), target :: v(:)
800  real(kind=kreal), intent(out), target :: tv(:)
801  real(kind=kreal), pointer :: tvp(:), tp(:), vp(:)
802  integer :: nr, ndof, ndof2, i, js, je, j, jj, k, kl0, l
803  !!$ real(kind=kreal) :: vnorm
804 
805  nr=btmat%nr
806  ndof=btmat%ndof
807  ndof2=ndof*ndof
808 
809  tv=0.d0
810 
811  !!$ vnorm=0.d0
812  !!$ do i=1,nr*ndof
813  !!$ vnorm=vnorm+V(i)**2
814  !!$ enddo
815  !!$ write(0,*) 'vnorm:', sqrt(vnorm)
816 
817  !$omp parallel default(none),private(i,TVp,js,je,j,jj,Tp,Vp,k,kl0,l), &
818  !$omp& shared(nr,TV,ndof,BTmat,ndof2,V)
819  !$omp do
820  do i=1,nr
821  tvp=>tv((i-1)*ndof+1:i*ndof)
822  js=btmat%index(i-1)+1
823  je=btmat%index(i)
824  do j=js,je
825  jj=btmat%item(j)
826  tp=>btmat%A((j-1)*ndof2+1:j*ndof2)
827  vp=>v((jj-1)*ndof+1:jj*ndof)
828  do k=1,ndof
829  kl0=(k-1)*ndof
830  do l=1,ndof
831  tvp(k)=tvp(k)+tp(kl0+l)*vp(l)
832  enddo
833  enddo
834  enddo
835  enddo
836  !$omp end do
837  !$omp end parallel
838  end subroutine hecmw_localmat_mulvec
839 
840  subroutine hecmw_trimatmul_ttkt_mpc(hecMESH, hecMAT, hecTKT)
841  implicit none
842  type (hecmwst_local_mesh), intent(inout) :: hecmesh
843  type (hecmwst_matrix), intent(in) :: hecmat
844  type (hecmwst_matrix), intent(inout) :: hectkt
845  type (hecmwst_local_matrix) :: btmat, bttmat
846  integer(kind=kint), allocatable :: iws(:)
847  integer(kind=kint) :: ndof, n_mpc, i_mpc
848  integer(kind=kint) :: i, j, k, kk, ilag
849  integer(kind=kint) :: num_lagrange
850  real(kind=kreal) :: t0, t1
851  t0 = hecmw_wtime()
852  ndof=hecmat%NDOF
853  n_mpc=0
854  outer: do i=1,hecmesh%mpc%n_mpc
855  do j= hecmesh%mpc%mpc_index(i-1) + 1, hecmesh%mpc%mpc_index(i)
856  if (hecmesh%mpc%mpc_dof(j) > ndof) cycle outer
857  enddo
858  n_mpc=n_mpc+1
859  enddo outer
860  allocate(iws(n_mpc))
861  i_mpc=0
862  outer2: do i=1,hecmesh%mpc%n_mpc
863  do j= hecmesh%mpc%mpc_index(i-1) + 1, hecmesh%mpc%mpc_index(i)
864  if (hecmesh%mpc%mpc_dof(j) > ndof) cycle outer2
865  enddo
866  i_mpc=i_mpc+1
867  k=hecmesh%mpc%mpc_index(i-1)+1
868  kk=ndof*(hecmesh%mpc%mpc_item(k)-1)+hecmesh%mpc%mpc_dof(k)
869  iws(i_mpc)=kk
870  enddo outer2
871  if (debug >= 2) then
872  write(700+hecmw_comm_get_rank(),*) 'DEBUG: n_mpc, slaves',n_mpc,iws(1:n_mpc)
873  endif
874  t1 = hecmw_wtime()
875  if (timer >= 1) write(0, '(A,f10.4)') "### hecmw_trimatmul_TtKT_mpc (1) : ",t1-t0
876  t0 = hecmw_wtime()
877  call make_btmat_mpc(hecmesh, ndof, btmat)
878  call debug_write_matrix(btmat, 'BTmat(MPC)', debug_matrix)
879  t1 = hecmw_wtime()
880  if (timer >= 1) write(0, '(A,f10.4)') "### hecmw_trimatmul_TtKT_mpc (2) : ",t1-t0
881  t0 = hecmw_wtime()
882  call hecmw_localmat_transpose(btmat, bttmat)
883  ! if (hecmw_localmat_equal(BTtmat, BTtmat2) == 0) then
884  ! write(0,*) 'ERROR: BTtmat2 is incorrect!!!'
885  ! else
886  ! write(0,*) 'DEBUG: BTtmat2 is correct'
887  ! endif
888  call debug_write_matrix(bttmat, 'BTtmat(MPC)', debug_matrix)
889 
890  if (debug >= 3) then
891  write(700+hecmw_comm_get_rank(),*) 'hecMESH%node_ID before trimatmul_TtKT'
892  do i=hecmesh%nn_internal+1, hecmesh%n_node
893  write(700+hecmw_comm_get_rank(),*) i,hecmesh%node_ID(2*i-1),hecmesh%node_ID(2*i),hecmesh%global_node_ID(i)
894  enddo
895  endif
896  t1 = hecmw_wtime()
897  if (timer >= 1) write(0, '(A,f10.4)') "### hecmw_trimatmul_TtKT_mpc (3) : ",t1-t0
898  t0 = hecmw_wtime()
899  call hecmw_trimatmul_ttkt(hecmesh, bttmat, hecmat, btmat, iws, n_mpc, hectkt)
900  t1 = hecmw_wtime()
901  if (timer >= 1) write(0, '(A,f10.4)') "### hecmw_trimatmul_TtKT_mpc (4) : ",t1-t0
902  t0 = hecmw_wtime()
903  if (debug >= 3) then
904  write(700+hecmw_comm_get_rank(),*) 'hecMESH%node_ID after trimatmul_TtKT'
905  do i=hecmesh%nn_internal+1, hecmesh%n_node
906  write(700+hecmw_comm_get_rank(),*) i,hecmesh%node_ID(2*i-1),hecmesh%node_ID(2*i),hecmesh%global_node_ID(i)
907  enddo
908  endif
909 
910  if (associated(hectkt%B)) deallocate(hectkt%B)
911  if (associated(hectkt%X)) deallocate(hectkt%X)
912  num_lagrange = size(hecmat%B) - hecmat%NP*ndof
913  allocate(hectkt%B(ndof*hectkt%NP + num_lagrange))
914  allocate(hectkt%X(ndof*hectkt%NP + num_lagrange))
915  hectkt%B(:) = 0.d0
916  hectkt%X(:) = 0.d0
917  do i=1, ndof*hecmat%NP
918  hectkt%B(i) = hecmat%B(i)
919  hectkt%X(i) = hecmat%X(i)
920  enddo
921  do i=1, num_lagrange
922  hectkt%B(ndof*hectkt%NP+i) = hecmat%B(ndof*hecmat%NP+i)
923  hectkt%X(ndof*hectkt%NP+i) = hecmat%X(ndof*hecmat%NP+i)
924  enddo
925  do ilag=1,n_mpc
926  hectkt%X(iws(ilag)) = 0.d0
927  enddo
928 
929  call hecmw_localmat_free(btmat)
930  call hecmw_localmat_free(bttmat)
931  ! call hecmw_localmat_free(BTtmat2)
932  deallocate(iws)
933  t1 = hecmw_wtime()
934  if (timer >= 1) write(0, '(A,f10.4)') "### hecmw_trimatmul_TtKT_mpc (5) : ",t1-t0
935  end subroutine hecmw_trimatmul_ttkt_mpc
936 
937  subroutine make_btmat_mpc(hecMESH, ndof, BTmat)
938  implicit none
939  type (hecmwst_local_mesh), intent(in) :: hecmesh
940  integer(kind=kint), intent(in) :: ndof
941  type (hecmwst_local_matrix), intent(out) :: btmat
942  type (hecmwst_local_matrix) :: tmat
943  integer(kind=kint) :: n_mpc
944  integer(kind=kint) :: i,j,k,js,jj,kk
945  n_mpc=0
946  outer: do i=1,hecmesh%mpc%n_mpc
947  do j= hecmesh%mpc%mpc_index(i-1) + 1, hecmesh%mpc%mpc_index(i)
948  if (hecmesh%mpc%mpc_dof(j) > ndof) cycle outer
949  enddo
950  n_mpc=n_mpc+1
951  enddo outer
952  tmat%nr=hecmesh%n_node*ndof
953  tmat%nc=tmat%nr
954  tmat%ndof=1
955  allocate(tmat%index(0:tmat%nr))
956  ! count nonzero in each row
957  tmat%index(1:tmat%nr)=1
958  outer2: do i=1,hecmesh%mpc%n_mpc
959  do j= hecmesh%mpc%mpc_index(i-1) + 1, hecmesh%mpc%mpc_index(i)
960  if (hecmesh%mpc%mpc_dof(j) > ndof) cycle outer2
961  enddo
962  k=hecmesh%mpc%mpc_index(i-1)+1
963  kk=ndof*(hecmesh%mpc%mpc_item(k)-1)+hecmesh%mpc%mpc_dof(k)
964  tmat%index(kk)=hecmesh%mpc%mpc_index(i)-hecmesh%mpc%mpc_index(i-1)-1
965  enddo outer2
966  ! index
967  tmat%index(0)=0
968  do i=1,tmat%nr
969  tmat%index(i)=tmat%index(i-1)+tmat%index(i)
970  enddo
971  tmat%nnz=tmat%index(tmat%nr)
972  allocate(tmat%item(tmat%nnz), tmat%A(tmat%nnz))
973  ! diag
974  do i=1,tmat%nr
975  js=tmat%index(i-1)+1
976  tmat%item(js)=i
977  tmat%A(js)=1.d0
978  enddo
979  ! others
980  outer3: do i=1,hecmesh%mpc%n_mpc
981  do j= hecmesh%mpc%mpc_index(i-1) + 1, hecmesh%mpc%mpc_index(i)
982  if (hecmesh%mpc%mpc_dof(j) > ndof) cycle outer3
983  enddo
984  k=hecmesh%mpc%mpc_index(i-1)+1
985  kk=ndof*(hecmesh%mpc%mpc_item(k)-1)+hecmesh%mpc%mpc_dof(k)
986  js=tmat%index(kk-1)+1
987  do j= hecmesh%mpc%mpc_index(i-1) + 2, hecmesh%mpc%mpc_index(i)
988  jj = ndof * (hecmesh%mpc%mpc_item(j) - 1) + hecmesh%mpc%mpc_dof(j)
989  tmat%item(js)=jj
990  tmat%A(js)=-hecmesh%mpc%mpc_val(j)
991  js=js+1
992  enddo
993  enddo outer3
994  !call debug_write_matrix(Tmat, 'Tmat(MPC)', DEBUG_MATRIX)
995  call hecmw_localmat_blocking(tmat, ndof, btmat)
996  call hecmw_localmat_free(tmat)
997  end subroutine make_btmat_mpc
998 
999 
1000  subroutine hecmw_localmat_transpose(Tmat, Ttmat)
1001  implicit none
1002  type (hecmwst_local_matrix), intent(in) :: tmat
1003  type (hecmwst_local_matrix), intent(out) :: ttmat
1004  integer(kind=kint), allocatable :: iw(:)
1005  integer(kind=kint) :: i, j, jj, ndof, ndof2, k, idof, jdof
1006  allocate(iw(tmat%nc))
1007  iw = 0
1008  do i = 1, tmat%nr
1009  do j = tmat%index(i-1)+1, tmat%index(i)
1010  jj = tmat%item(j)
1011  iw(jj) = iw(jj) + 1
1012  enddo
1013  enddo
1014  ttmat%nr = tmat%nc
1015  ttmat%nc = tmat%nr
1016  ttmat%nnz = tmat%nnz
1017  ttmat%ndof = tmat%ndof
1018  ndof = tmat%ndof
1019  ndof2 = ndof * ndof
1020  allocate(ttmat%index(0:ttmat%nr))
1021  allocate(ttmat%item(ttmat%nnz))
1022  allocate(ttmat%A(ttmat%nnz*ndof2))
1023  ttmat%index(0) = 0
1024  do i = 1, ttmat%nr
1025  ttmat%index(i) = ttmat%index(i-1) + iw(i)
1026  iw(i) = ttmat%index(i-1) + 1
1027  enddo
1028  do i = 1, tmat%nr
1029  do j = tmat%index(i-1)+1, tmat%index(i)
1030  jj = tmat%item(j)
1031  k = iw(jj)
1032  ttmat%item( k ) = i
1033  do idof = 1, ndof
1034  do jdof = 1, ndof
1035  ttmat%A((k-1)*ndof2+(idof-1)*ndof+jdof) = &
1036  tmat%A((j-1)*ndof2+(jdof-1)*ndof+idof)
1037  enddo
1038  enddo
1039  iw(jj) = k + 1
1040  enddo
1041  enddo
1042  end subroutine hecmw_localmat_transpose
1043 
1044  function hecmw_localmat_equal(Tmat1, Tmat2)
1045  implicit none
1046  type (hecmwst_local_matrix), intent(in) :: tmat1, tmat2
1047  integer(kind=kint) :: hecmw_localmat_equal
1048  integer(kind=kint) :: i, j, k0, k, ndof, ndof2
1049  hecmw_localmat_equal = 0
1050  if (tmat1%nr /= tmat2%nr) return
1051  if (tmat1%nc /= tmat2%nc) return
1052  if (tmat1%nnz /= tmat2%nnz) return
1053  if (tmat1%ndof /= tmat2%ndof) return
1054  ndof = tmat1%ndof
1055  ndof2 = ndof * ndof
1056  do i = 1, tmat1%nr
1057  if (tmat1%index(i) /= tmat2%index(i)) return
1058  do j = tmat1%index(i-1)+1, tmat1%index(i)
1059  if (tmat1%item(j) /= tmat2%item(j)) return
1060  k0 = (j-1)*ndof2
1061  do k = 1, ndof2
1062  if (tmat1%A(k0+k) /= tmat2%A(k0+k)) return
1063  enddo
1064  enddo
1065  enddo
1066  hecmw_localmat_equal = 1
1067  end function hecmw_localmat_equal
1068 
1069 !!!
1070 !!! Subroutines for parallel contact analysis with iterative linear solver
1071 !!!
1072 
1073  subroutine hecmw_localmat_assemble(BTmat, hecMESH, hecMESHnew)
1074  implicit none
1075  type (hecmwst_local_matrix), intent(inout) :: btmat
1076  type (hecmwst_local_mesh), intent(in) :: hecmesh
1077  type (hecmwst_local_mesh), intent(inout) :: hecmeshnew
1078  integer(kind=kint) :: nn_int, np, ndof, ndof2, nr_ext, nnz_ext
1079  integer(kind=kint), allocatable :: exp_rows_index(:), exp_cols_index(:)
1080  integer(kind=kint), allocatable :: exp_rows_item(:,:), exp_cols_item(:,:)
1081  type (hecmwst_local_matrix), allocatable :: bt_ext(:)
1082  type (hecmwst_local_matrix) :: bt_int
1083  type (hecmwst_local_matrix) :: btnew
1084  ! some checks
1085  if (debug >= 1) write(0,*) 'DEBUG: nr,nc,nnz,ndof',btmat%nr,btmat%nc,btmat%nnz,btmat%ndof
1086  if (btmat%nr /= hecmesh%n_node) stop 'ERROR: invalid size in hecmw_localmat_assemble'
1087  !
1088  nn_int = hecmesh%nn_internal
1089  np = hecmesh%n_node
1090  ndof = btmat%ndof
1091  ndof2 = ndof*ndof
1092  !
1093  nr_ext = np - nn_int
1094  nnz_ext = btmat%index(np) - btmat%index(nn_int)
1095  !
1096  call prepare_bt_ext(btmat, hecmesh, exp_rows_index, exp_rows_item, bt_ext)
1097  if (debug >= 1) write(0,*) 'DEBUG: prepare_BT_ext done'
1098  !
1099  call prepare_column_info(hecmesh, bt_ext, exp_cols_index, exp_cols_item)
1100  if (debug >= 1) write(0,*) 'DEBUG: prepare_column info done'
1101  !
1102  call send_bt_ext_and_recv_bt_int(hecmesh, exp_rows_index, exp_rows_item, bt_ext, &
1103  exp_cols_index, exp_cols_item, bt_int, hecmeshnew)
1104  if (debug >= 1) write(0,*) 'DEBUG: send BT_ext and recv BT_int done'
1105  !
1106  !write(0,*) 'BTmat%ndof,BT_int%ndof',BTmat%ndof,BT_int%ndof
1107  call hecmw_localmat_add(btmat, bt_int, btnew)
1108  if (debug >= 1) write(0,*) 'DEBUG: localmat_add done'
1109  !
1110  call hecmw_localmat_free(btmat)
1111  call hecmw_localmat_free(bt_int)
1112  !
1113  btmat%nr = btnew%nr
1114  btmat%nc = btnew%nc
1115  btmat%nnz = btnew%nnz
1116  btmat%ndof = btnew%ndof
1117  btmat%index => btnew%index
1118  btmat%item => btnew%item
1119  btmat%A => btnew%A
1120  !
1121  ! hecMESH%n_node = hecMESHnew%n_node
1122  ! hecMESH%n_neighbor_pe = hecMESHnew%n_neighbor_pe
1123  ! deallocate(hecMESH%neighbor_pe)
1124  ! deallocate(hecMESH%import_index)
1125  ! deallocate(hecMESH%export_index)
1126  ! deallocate(hecMESH%import_item)
1127  ! deallocate(hecMESH%export_item)
1128  ! deallocate(hecMESH%node_ID)
1129  ! deallocate(hecMESH%global_node_ID)
1130  ! hecMESH%neighbor_pe => hecMESHnew%neighbor_pe
1131  ! hecMESH%import_index => hecMESHnew%import_index
1132  ! hecMESH%export_index => hecMESHnew%export_index
1133  ! hecMESH%import_item => hecMESHnew%import_item
1134  ! hecMESH%export_item => hecMESHnew%export_item
1135  ! hecMESH%node_ID => hecMESHnew%node_ID
1136  ! hecMESH%global_node_ID => hecMESHnew%global_node_ID
1137  !
1138  if (debug >= 1) write(0,*) 'DEBUG: update BTmat and hecMESH done'
1139  end subroutine hecmw_localmat_assemble
1140 
1141  subroutine prepare_bt_ext(BTmat, hecMESH, exp_rows_index, exp_rows_item, BT_ext)
1142  implicit none
1143  type (hecmwst_local_matrix), intent(in) :: btmat
1144  type (hecmwst_local_mesh), intent(in) :: hecmesh
1145  integer(kind=kint), allocatable, intent(out) :: exp_rows_index(:)
1146  integer(kind=kint), allocatable, intent(out) :: exp_rows_item(:,:)
1147  type (hecmwst_local_matrix), allocatable, intent(out) :: bt_ext(:)
1148  integer(kind=kint), allocatable :: incl_nz(:), exp_cols_per_row(:), exp_rows_per_rank(:)
1149  integer(kind=kint) :: nn_int
1150  logical, parameter :: flg_check_nonzero_numerically = .true.
1151  nn_int = hecmesh%nn_internal
1152  !
1153  if (flg_check_nonzero_numerically) then
1154  ! efficient for assembling conMAT which has same non-zero profile as hecMAT
1155  ! but only dofs related to cntact are actually non-zero
1156  call check_external_nz_blocks(btmat, nn_int, incl_nz)
1157  else
1158  ! probably good enough to assemble T or T^t
1159  call incl_all_external_nz_blocks(btmat, nn_int, incl_nz)
1160  endif
1161  !
1162  call count_ext_rows_with_nz(btmat, nn_int, incl_nz, exp_cols_per_row)
1163  !
1164  call count_exp_rows_per_rank(hecmesh, exp_cols_per_row, exp_rows_per_rank)
1165  !
1166  allocate(exp_rows_index(0:hecmesh%n_neighbor_pe))
1167  call make_index(hecmesh%n_neighbor_pe, exp_rows_per_rank, exp_rows_index)
1168  !write(0,*) 'exp_rows_index',exp_rows_index(:)
1169  !
1170  deallocate(exp_rows_per_rank)
1171  !
1172  call make_exp_rows_item(hecmesh, exp_cols_per_row, exp_rows_index, exp_rows_item)
1173  !
1174  deallocate(exp_cols_per_row)
1175  !
1176  allocate(bt_ext(hecmesh%n_neighbor_pe))
1177  call extract_bt_ext(hecmesh, btmat, incl_nz, exp_rows_index, exp_rows_item, bt_ext)
1178  !
1179  deallocate(incl_nz)
1180  end subroutine prepare_bt_ext
1181 
1182  subroutine check_external_nz_blocks(BTmat, nn_internal, incl_nz)
1183  implicit none
1184  type (hecmwst_local_matrix), intent(in) :: btmat
1185  integer(kind=kint), intent(in) :: nn_internal
1186  integer(kind=kint), allocatable, intent(out) :: incl_nz(:)
1187  integer(kind=kint) :: ndof2, i0, nnz_ext, i, k, nnz_blk
1188  if (nn_internal > btmat%nr) stop 'ERROR: invalid nn_internal'
1189  ndof2 = btmat%ndof ** 2
1190  i0 = btmat%index(nn_internal)
1191  nnz_ext = btmat%index(btmat%nr) - i0
1192  allocate(incl_nz(nnz_ext))
1193  nnz_blk = 0
1194  do i = 1, nnz_ext
1195  incl_nz(i) = 0
1196  do k = 1, ndof2
1197  if (btmat%A(ndof2*(i0+i-1)+k) /= 0.0d0) then
1198  incl_nz(i) = 1
1199  nnz_blk = nnz_blk + 1
1200  exit
1201  endif
1202  enddo
1203  enddo
1204  if (debug >= 1) write(0,*) 'DEBUG: nnz_blk',nnz_blk
1205  end subroutine check_external_nz_blocks
1206 
1207  subroutine incl_all_external_nz_blocks(BTmat, nn_internal, incl_nz)
1208  implicit none
1209  type (hecmwst_local_matrix), intent(in) :: btmat
1210  integer(kind=kint), intent(in) :: nn_internal
1211  integer(kind=kint), allocatable, intent(out) :: incl_nz(:)
1212  integer(kind=kint) :: i0, nnz_ext
1213  if (nn_internal > btmat%nr) stop 'ERROR: invalid nn_internal'
1214  i0 = btmat%index(nn_internal)
1215  nnz_ext = btmat%index(btmat%nr) - i0
1216  allocate(incl_nz(nnz_ext))
1217  incl_nz(1:nnz_ext) = 1
1218  end subroutine incl_all_external_nz_blocks
1219 
1220  subroutine count_ext_rows_with_nz(BTmat, nn_internal, incl_nz, exp_cols_per_row)
1221  implicit none
1222  type (hecmwst_local_matrix), intent(in) :: btmat
1223  integer(kind=kint), intent(in) :: nn_internal
1224  integer(kind=kint), intent(in) :: incl_nz(:)
1225  integer(kind=kint), allocatable, intent(out) :: exp_cols_per_row(:)
1226  integer(kind=kint) :: nr_ext, nnz_int, i, irow, js, je, j, jcol
1227  nr_ext = btmat%nr - nn_internal
1228  nnz_int = btmat%index(nn_internal)
1229  allocate(exp_cols_per_row(nr_ext))
1230  exp_cols_per_row(:) = 0
1231  do i = 1, nr_ext
1232  irow = nn_internal+i
1233  js = btmat%index(irow-1)+1
1234  je = btmat%index(irow)
1235  do j = js, je
1236  jcol = btmat%item(j)
1237  if (incl_nz(j-nnz_int) == 1) exp_cols_per_row(i) = exp_cols_per_row(i) + 1
1238  enddo
1239  enddo
1240  !write(0,*) 'exp_cols_per_row',exp_cols_per_row(:)
1241  end subroutine count_ext_rows_with_nz
1242 
1243  subroutine count_exp_rows_per_rank(hecMESH, exp_cols_per_row, exp_rows_per_rank)
1244  implicit none
1245  type (hecmwst_local_mesh), intent(in) :: hecmesh
1246  integer(kind=kint), intent(in) :: exp_cols_per_row(:)
1247  integer(kind=kint), allocatable, intent(out) :: exp_rows_per_rank(:)
1248  integer(kind=kint) :: nn_int, np, nr_ext, i, irow, exp_rank, idom
1249  allocate(exp_rows_per_rank(hecmesh%n_neighbor_pe))
1250  exp_rows_per_rank(1:hecmesh%n_neighbor_pe) = 0
1251  nn_int = hecmesh%nn_internal
1252  np = hecmesh%n_node
1253  nr_ext = np - nn_int
1254  do i = 1, nr_ext
1255  if (exp_cols_per_row(i) > 0) then
1256  irow = nn_int + i
1257  exp_rank = hecmesh%node_ID(2*irow)
1258  call rank_to_idom(hecmesh, exp_rank, idom)
1259  exp_rows_per_rank(idom) = exp_rows_per_rank(idom) + 1
1260  endif
1261  enddo
1262  !write(0,*) 'exp_rows_per_rank',exp_rows_per_rank(:)
1263  end subroutine count_exp_rows_per_rank
1264 
1265  subroutine rank_to_idom(hecMESH, rank, idom)
1266  implicit none
1267  type (hecmwst_local_mesh), intent(in) :: hecmesh
1268  integer(kind=kint), intent(in) :: rank
1269  integer(kind=kint), intent(out) :: idom
1270  integer(kind=kint) :: i
1271  do i = 1, hecmesh%n_neighbor_pe
1272  if (hecmesh%neighbor_pe(i) == rank) then
1273  idom = i
1274  return
1275  endif
1276  enddo
1277  stop 'ERROR: exp_rank not found in neighbor_pe'
1278  end subroutine rank_to_idom
1279 
1280  subroutine make_index(len, cnt, index)
1281  implicit none
1282  integer(kind=kint), intent(in) :: len
1283  integer(kind=kint), intent(in) :: cnt(len)
1284  integer(kind=kint), intent(out) :: index(0:)
1285  integer(kind=kint) :: i
1286  ! write(0,*) 'make_index: len',len
1287  index(0) = 0
1288  do i = 1,len
1289  index(i) = index(i-1) + cnt(i)
1290  enddo
1291  end subroutine make_index
1292 
1293  subroutine make_exp_rows_item(hecMESH, exp_cols_per_row, exp_rows_index, exp_rows_item)
1294  implicit none
1295  type (hecmwst_local_mesh), intent(in) :: hecmesh
1296  integer(kind=kint), intent(in) :: exp_cols_per_row(:)
1297  integer(kind=kint), allocatable, intent(in) :: exp_rows_index(:)
1298  integer(kind=kint), allocatable, intent(out) :: exp_rows_item(:,:)
1299  integer(kind=kint), allocatable :: cnt(:)
1300  integer(kind=kint) :: nn_int, np, nr_ext, i, irow, exp_rank, idom, idx
1301  allocate(exp_rows_item(2,exp_rows_index(hecmesh%n_neighbor_pe)))
1302  allocate(cnt(hecmesh%n_neighbor_pe))
1303  cnt(:) = 0
1304  nn_int = hecmesh%nn_internal
1305  np = hecmesh%n_node
1306  nr_ext = np - nn_int
1307  do i = 1, nr_ext
1308  if (exp_cols_per_row(i) > 0) then
1309  irow = nn_int + i
1310  exp_rank = hecmesh%node_ID(2*irow)
1311  call rank_to_idom(hecmesh, exp_rank, idom)
1312  cnt(idom) = cnt(idom) + 1
1313  idx = exp_rows_index(idom-1) + cnt(idom)
1314  exp_rows_item(1,idx) = irow
1315  exp_rows_item(2,idx) = exp_cols_per_row(i)
1316  endif
1317  enddo
1318  !write(0,*) 'cnt',cnt(:)
1319  do idom = 1, hecmesh%n_neighbor_pe
1320  if (cnt(idom) /= exp_rows_index(idom)-exp_rows_index(idom-1)) stop 'ERROR: make exp_rows_item'
1321  enddo
1322  !write(0,*) 'exp_rows_item(1,:)',exp_rows_item(1,:)
1323  !write(0,*) 'exp_rows_item(2,:)',exp_rows_item(2,:)
1324  end subroutine make_exp_rows_item
1325 
1326  subroutine extract_bt_ext(hecMESH, BTmat, incl_nz, exp_rows_index, exp_rows_item, BT_ext)
1327  implicit none
1328  type (hecmwst_local_mesh), intent(in) :: hecmesh
1329  type (hecmwst_local_matrix), intent(in) :: btmat
1330  integer(kind=kint), intent(in) :: incl_nz(:)
1331  integer(kind=kint), allocatable, intent(in) :: exp_rows_index(:)
1332  integer(kind=kint), intent(in) :: exp_rows_item(:,:)
1333  type (hecmwst_local_matrix), allocatable, intent(out) :: bt_ext(:)
1334  integer(kind=kint) :: ndof, ndof2, nn_int, nnz_int, idom, j, idx, ncol, cnt, jrow, ks, ke, k, kcol
1335  allocate(bt_ext(hecmesh%n_neighbor_pe))
1336  ndof = btmat%ndof
1337  ndof2 = ndof * ndof
1338  nn_int = hecmesh%nn_internal
1339  nnz_int = btmat%index(nn_int)
1340  do idom = 1, hecmesh%n_neighbor_pe
1341  bt_ext(idom)%nr = exp_rows_index(idom) - exp_rows_index(idom-1)
1342  bt_ext(idom)%nc = btmat%nc
1343  bt_ext(idom)%nnz = 0
1344  bt_ext(idom)%ndof = ndof
1345  allocate(bt_ext(idom)%index(0:bt_ext(idom)%nr))
1346  bt_ext(idom)%index(0) = 0
1347  do j = 1, bt_ext(idom)%nr
1348  idx = exp_rows_index(idom-1) + j
1349  ncol = exp_rows_item(2,idx)
1350  bt_ext(idom)%index(j) = bt_ext(idom)%index(j-1) + ncol
1351  enddo
1352  bt_ext(idom)%nnz = bt_ext(idom)%index(bt_ext(idom)%nr)
1353  if (debug >= 1) write(0,*) 'DEBUG: idom,nr,nc,nnz,ndof', &
1354  idom,bt_ext(idom)%nr,bt_ext(idom)%nc,bt_ext(idom)%nnz,bt_ext(idom)%ndof
1355  allocate(bt_ext(idom)%item(bt_ext(idom)%nnz))
1356  allocate(bt_ext(idom)%A(bt_ext(idom)%nnz * ndof2))
1357  cnt = 0
1358  do j = 1, bt_ext(idom)%nr
1359  idx = exp_rows_index(idom-1) + j
1360  jrow = exp_rows_item(1,idx)
1361  if (jrow < 1 .or. btmat%nr < jrow) stop 'ERROR: extract BT_ext: jrow'
1362  ks = btmat%index(jrow-1)+1
1363  ke = btmat%index(jrow)
1364  do k = ks, ke
1365  kcol = btmat%item(k)
1366  if (incl_nz(k-nnz_int) == 0) cycle
1367  cnt = cnt + 1
1368  bt_ext(idom)%item(cnt) = kcol
1369  bt_ext(idom)%A(ndof2*(cnt-1)+1:ndof2*cnt) = btmat%A(ndof2*(k-1)+1:ndof2*k)
1370  enddo
1371  if (cnt /= bt_ext(idom)%index(j)) stop 'ERROR: extract BT_ext'
1372  enddo
1373  ! write(label,'(a,i0,a)') 'BT_ext(',idom,')'
1374  ! call debug_write_matrix(Bt_ext(idom), label, DEBUG_MATRIX)
1375  enddo
1376  end subroutine extract_bt_ext
1377 
1378  subroutine prepare_column_info(hecMESH, BT_ext, exp_cols_index, exp_cols_item)
1379  implicit none
1380  type (hecmwst_local_mesh), intent(in) :: hecmesh
1381  type (hecmwst_local_matrix), intent(in) :: bt_ext(:)
1382  integer(kind=kint), allocatable, intent(out) :: exp_cols_index(:)
1383  integer(kind=kint), allocatable, intent(out) :: exp_cols_item(:,:)
1384  !
1385  call make_exp_cols_index(hecmesh%n_neighbor_pe, bt_ext, exp_cols_index)
1386  if (debug >= 2) write(0,*) ' DEBUG2: make exp_cols_index done'
1387  if (debug >= 3) write(0,*) ' DEBUG3: exp_cols_index', exp_cols_index(0:hecmesh%n_neighbor_pe)
1388  !
1389  ! (col ID, rank, global ID)
1390  !
1391  call make_exp_cols_item(hecmesh, bt_ext, exp_cols_index, exp_cols_item)
1392  if (debug >= 2) write(0,*) ' DEBUG2: make exp_cols_item done'
1393  ! if (DEBUG >= 3) write(0,*) ' DEBUG3: exp_cols_item', exp_cols_item(1:cNCOL_ITEM,1:exp_cols_index(hecMESH%n_neighbor_pe))
1394  end subroutine prepare_column_info
1395 
1396  subroutine make_exp_cols_index(nnb, BT_ext, exp_cols_index)
1397  implicit none
1398  integer(kind=kint), intent(in) :: nnb
1399  type (hecmwst_local_matrix), intent(in) :: bt_ext(:)
1400  integer(kind=kint), allocatable, intent(out) :: exp_cols_index(:)
1401  integer(kind=kint) :: idom
1402  allocate(exp_cols_index(0:nnb))
1403  exp_cols_index(0) = 0
1404  do idom = 1, nnb
1405  exp_cols_index(idom) = exp_cols_index(idom-1) + bt_ext(idom)%nnz
1406  enddo
1407  end subroutine make_exp_cols_index
1408 
1409  subroutine make_exp_cols_item(hecMESH, BT_ext, exp_cols_index, exp_cols_item)
1410  implicit none
1411  type (hecmwst_local_mesh), intent(in) :: hecmesh
1412  type (hecmwst_local_matrix), intent(in) :: bt_ext(:)
1413  integer(kind=kint), allocatable, intent(in) :: exp_cols_index(:)
1414  integer(kind=kint), allocatable, intent(out) :: exp_cols_item(:,:)
1415  integer(kind=kint) :: cnt, idom, j, jcol
1416  allocate(exp_cols_item(cncol_item,exp_cols_index(hecmesh%n_neighbor_pe)))
1417  cnt = 0
1418  do idom = 1, hecmesh%n_neighbor_pe
1419  do j = 1, bt_ext(idom)%nnz
1420  cnt = cnt + 1
1421  jcol = bt_ext(idom)%item(j)
1422  ! if (DEBUG >= 3) write(0,*) ' DEBUG3: idom,j,cnt,jcol,nn_internal,n_node',&
1423  ! idom,j,cnt,jcol,hecMESH%nn_internal,hecMESH%n_node
1424  ! if (DEBUG >= 3) write(0,*) ' DEBUG3: size of exp_cols_item',size(exp_cols_item)
1425  ! if (DEBUG >= 3) write(0,*) ' DEBUG3: size of node_ID',size(hecMESH%node_ID)
1426  ! if (DEBUG >= 3) write(0,*) ' DEBUG3: size of global_node_ID',size(hecMESH%global_node_ID)
1427  exp_cols_item(clid,cnt) = hecmesh%node_ID(2*jcol-1)
1428  exp_cols_item(crank,cnt) = hecmesh%node_ID(2*jcol)
1429  if (cncol_item >= 3) exp_cols_item(cgid,cnt) = hecmesh%global_node_ID(jcol)
1430  ! if (DEBUG >= 3) write(0,*) ' DEBUG3: lid,rank(,gid)',exp_cols_item(1:cNCOL_ITEM,cnt)
1431  enddo
1432  if (cnt /= exp_cols_index(idom)) stop 'ERROR: make exp_cols_item'
1433  enddo
1434  end subroutine make_exp_cols_item
1435 
1436  subroutine send_bt_ext_and_recv_bt_int(hecMESH, exp_rows_index, exp_rows_item, BT_ext, &
1437  exp_cols_index, exp_cols_item, BT_int, hecMESHnew)
1438  implicit none
1439  type (hecmwst_local_mesh), intent(in) :: hecmesh
1440  integer(kind=kint), allocatable, intent(inout) :: exp_rows_index(:), exp_cols_index(:)
1441  integer(kind=kint), allocatable, intent(inout) :: exp_rows_item(:,:), exp_cols_item(:,:)
1442  type (hecmwst_local_matrix), allocatable, intent(inout) :: bt_ext(:)
1443  type (hecmwst_local_matrix), intent(out) :: bt_int
1444  type (hecmwst_local_mesh), intent(inout) :: hecmeshnew
1445  integer(kind=kint), allocatable :: imp_rows_index(:), imp_cols_index(:)
1446  integer(kind=kint), allocatable :: imp_rows_item(:,:), imp_cols_item(:,:)
1447  real(kind=kreal), allocatable :: imp_vals_item(:)
1448  integer(kind=kint), allocatable :: map(:), add_nodes(:,:)
1449  integer(kind=kint) :: ndof, ndof2, idom, n_add_node, i0
1450  if (hecmesh%n_neighbor_pe == 0) return
1451  ndof = bt_ext(1)%ndof
1452  ndof2 = ndof*ndof
1453  !
1454  call convert_rowid_to_remote_localid(hecmesh, exp_rows_index(hecmesh%n_neighbor_pe), exp_rows_item)
1455  if (debug >= 2) write(0,*) ' DEBUG2: convert rowID to remote localID done'
1456  !
1457  call send_recv_bt_ext_nr_nnz(hecmesh, bt_ext, imp_rows_index, imp_cols_index)
1458  if (debug >= 2) write(0,*) ' DEBUG2: send recv BT_ext nr and nnz done'
1459  !
1460  call send_recv_bt_ext_contents(hecmesh, bt_ext, &
1461  exp_rows_index, exp_cols_index, exp_rows_item, exp_cols_item, &
1462  imp_rows_index, imp_cols_index, &
1463  imp_rows_item, imp_cols_item, imp_vals_item)
1464  if (debug >= 2) write(0,*) ' DEBUG2: send recv BT_ext contents done'
1465  !
1466  do idom = 1, hecmesh%n_neighbor_pe
1467  call hecmw_localmat_free(bt_ext(idom))
1468  enddo
1469  deallocate(bt_ext)
1470  !
1471  call allocate_bt_int(hecmesh, ndof, imp_rows_index, imp_rows_item, bt_int)
1472  if (debug >= 2) write(0,*) ' DEBUG2: allocate BT_int done'
1473  !
1474  ! call copy_mesh(hecMESH, hecMESHnew)
1475  ! if (DEBUG >= 2) write(0,*) ' DEBUG2: copy mesh done'
1476  !
1477  call map_imported_cols(hecmeshnew, imp_cols_index(hecmesh%n_neighbor_pe), &
1478  imp_cols_item, n_add_node, add_nodes, map, i0)
1479  if (debug >= 2) write(0,*) ' DEBUG2: map imported cols done'
1480  !
1481  call update_comm_table(hecmeshnew, n_add_node, add_nodes, i0)
1482  if (debug >= 2) write(0,*) ' DEBUG2: update comm_table done'
1483  !
1484  bt_int%nc = hecmeshnew%n_node
1485  !
1486  call copy_vals_to_bt_int(hecmesh%n_neighbor_pe, imp_rows_index, imp_cols_index, &
1487  imp_rows_item, map, ndof2, imp_vals_item, bt_int)
1488  if (debug >= 2) write(0,*) ' DEBUG2: copy vals to BT_int done'
1489  !
1490  deallocate(imp_rows_index)
1491  deallocate(imp_cols_index)
1492  deallocate(imp_rows_item)
1493  deallocate(imp_cols_item)
1494  deallocate(imp_vals_item)
1495  deallocate(map)
1496  !
1497  call sort_and_uniq_rows(bt_int)
1498  if (debug >= 2) write(0,*) ' DEBUG2: sort and uniq rows of BT_int done'
1499  end subroutine send_bt_ext_and_recv_bt_int
1500 
1501  subroutine convert_rowid_to_remote_localid(hecMESH, len, exp_rows_item)
1502  implicit none
1503  type (hecmwst_local_mesh), intent(in) :: hecmesh
1504  integer(kind=kint), intent(in) :: len
1505  integer(kind=kint), intent(out) :: exp_rows_item(:,:)
1506  integer(kind=kint) :: i
1507  do i = 1, len
1508  exp_rows_item(1,i) = hecmesh%node_ID(2 * exp_rows_item(1,i) - 1)
1509  enddo
1510  end subroutine convert_rowid_to_remote_localid
1511 
1512  subroutine send_recv_bt_ext_nr_nnz(hecMESH, BT_ext, imp_rows_index, imp_cols_index)
1513  use m_hecmw_comm_f
1514  implicit none
1515  type (hecmwst_local_mesh), intent(in) :: hecmesh
1516  type (hecmwst_local_matrix), intent(in) :: bt_ext(:)
1517  integer(kind=kint), allocatable, intent(out) :: imp_rows_index(:), imp_cols_index(:)
1518  integer(kind=kint) :: nnb, idom, irank, tag, recvbuf(2)
1519  integer(kind=kint), allocatable :: sendbuf(:,:)
1520  integer(kind=kint), allocatable :: requests(:)
1521  integer(kind=kint), allocatable :: statuses(:,:)
1522  nnb = hecmesh%n_neighbor_pe
1523  allocate(imp_rows_index(0:nnb))
1524  allocate(imp_cols_index(0:nnb))
1525  allocate(requests(nnb))
1526  allocate(statuses(hecmw_status_size, nnb))
1527  allocate(sendbuf(2,nnb))
1528  do idom = 1, nnb
1529  irank = hecmesh%neighbor_pe(idom)
1530  ! nr = exp_rows_per_rank(idom)
1531  sendbuf(1,idom) = bt_ext(idom)%nr
1532  sendbuf(2,idom) = bt_ext(idom)%nnz
1533  tag=2001
1534  call hecmw_isend_int(sendbuf(1,idom), 2, irank, tag, hecmesh%MPI_COMM, &
1535  requests(idom))
1536  enddo
1537  imp_rows_index(0) = 0
1538  imp_cols_index(0) = 0
1539  do idom = 1, nnb
1540  irank = hecmesh%neighbor_pe(idom)
1541  tag = 2001
1542  call hecmw_recv_int(recvbuf, 2, irank, tag, &
1543  hecmesh%MPI_COMM, statuses(:,1))
1544  imp_rows_index(idom) = imp_rows_index(idom-1) + recvbuf(1)
1545  imp_cols_index(idom) = imp_cols_index(idom-1) + recvbuf(2)
1546  enddo
1547  call hecmw_waitall(nnb, requests, statuses)
1548  deallocate(requests)
1549  deallocate(statuses)
1550  deallocate(sendbuf)
1551  end subroutine send_recv_bt_ext_nr_nnz
1552 
1553  subroutine send_recv_bt_ext_contents(hecMESH, BT_ext, &
1554  exp_rows_index, exp_cols_index, exp_rows_item, exp_cols_item, &
1555  imp_rows_index, imp_cols_index, &
1556  imp_rows_item, imp_cols_item, imp_vals_item)
1557  use m_hecmw_comm_f
1558  implicit none
1559  type (hecmwST_local_mesh), intent(in) :: hecMESH
1560  type (hecmwST_local_matrix), intent(in) :: BT_ext(:)
1561  integer(kind=kint), allocatable, intent(inout) :: exp_rows_index(:), exp_cols_index(:)
1562  integer(kind=kint), allocatable, intent(inout) :: exp_rows_item(:,:), exp_cols_item(:,:)
1563  integer(kind=kint), allocatable, intent(in) :: imp_rows_index(:), imp_cols_index(:)
1564  integer(kind=kint), allocatable, intent(out) :: imp_rows_item(:,:), imp_cols_item(:,:)
1565  real(kind=kreal), allocatable, intent(out) :: imp_vals_item(:)
1566  integer(kind=kint) :: nnb, ndof2, n_send, idom, irank, tag, nr, nnz
1567  integer(kind=kint), allocatable :: requests(:)
1568  integer(kind=kint), allocatable :: statuses(:,:)
1569  nnb = hecmesh%n_neighbor_pe
1570  if (nnb < 1) return
1571  ndof2 = bt_ext(1)%ndof ** 2
1572  allocate(imp_rows_item(2,imp_rows_index(nnb)))
1573  allocate(imp_cols_item(cncol_item,imp_cols_index(nnb)))
1574  allocate(imp_vals_item(ndof2*imp_cols_index(nnb)))
1575  allocate(requests(3*nnb))
1576  allocate(statuses(hecmw_status_size, 3*nnb))
1577  n_send = 0
1578  do idom = 1, nnb
1579  irank = hecmesh%neighbor_pe(idom)
1580  if (bt_ext(idom)%nr > 0) then
1581  n_send = n_send + 1
1582  tag = 2002
1583  call hecmw_isend_int(exp_rows_item(1,exp_rows_index(idom-1)+1), &
1584  2*bt_ext(idom)%nr, irank, tag, hecmesh%MPI_COMM, &
1585  requests(n_send))
1586  n_send = n_send + 1
1587  tag = 2003
1588  call hecmw_isend_int(exp_cols_item(1,exp_cols_index(idom-1)+1), &
1589  cncol_item*bt_ext(idom)%nnz, irank, tag, hecmesh%MPI_COMM, &
1590  requests(n_send))
1591  n_send = n_send + 1
1592  tag = 2004
1593  call hecmw_isend_r(bt_ext(idom)%A, ndof2*bt_ext(idom)%nnz, irank, &
1594  tag, hecmesh%MPI_COMM, requests(n_send))
1595  endif
1596  enddo
1597  do idom = 1, nnb
1598  irank = hecmesh%neighbor_pe(idom)
1599  nr = imp_rows_index(idom) - imp_rows_index(idom-1)
1600  nnz = imp_cols_index(idom) - imp_cols_index(idom-1)
1601  if (nr > 0) then
1602  tag = 2002
1603  call hecmw_recv_int(imp_rows_item(1,imp_rows_index(idom-1)+1), &
1604  2*nr, irank, tag, hecmesh%MPI_COMM, statuses(:,1))
1605  tag = 2003
1606  call hecmw_recv_int(imp_cols_item(1,imp_cols_index(idom-1)+1), &
1607  cncol_item*nnz, irank, tag, hecmesh%MPI_COMM, statuses(:,1))
1608  tag = 2004
1609  call hecmw_recv_r(imp_vals_item(ndof2*imp_cols_index(idom-1)+1), &
1610  ndof2*nnz, irank, tag, hecmesh%MPI_COMM, statuses(:,1))
1611  endif
1612  enddo
1613  call hecmw_waitall(n_send, requests, statuses)
1614  deallocate(exp_rows_index)
1615  deallocate(exp_rows_item)
1616  deallocate(exp_cols_index)
1617  deallocate(exp_cols_item)
1618  end subroutine send_recv_bt_ext_contents
1619 
1620  subroutine allocate_bt_int(hecMESH, ndof, imp_rows_index, imp_rows_item, BT_int)
1621  implicit none
1622  type (hecmwST_local_mesh), intent(in) :: hecMESH
1623  integer(kind=kint), intent(in) :: ndof
1624  integer(kind=kint), allocatable, intent(in) :: imp_rows_index(:), imp_rows_item(:,:)
1625  type (hecmwST_local_matrix), intent(out) :: BT_int
1626  integer(kind=kint), allocatable :: cnt(:)
1627  integer(kind=kint) :: idom, is, ie, i, irow, ncol, ndof2
1628  ndof2 = ndof*ndof
1629  bt_int%nr = hecmesh%nn_internal
1630  bt_int%nc = hecmesh%n_node
1631  bt_int%nnz = 0
1632  bt_int%ndof = ndof
1633  allocate(cnt(bt_int%nr))
1634  cnt(:) = 0
1635  do idom = 1, hecmesh%n_neighbor_pe
1636  is = imp_rows_index(idom-1)+1
1637  ie = imp_rows_index(idom)
1638  do i = is, ie
1639  irow = imp_rows_item(1,i)
1640  ncol = imp_rows_item(2,i)
1641  if (irow < 1 .or. bt_int%nr < irow) stop 'ERROR: allocate BT_int'
1642  cnt(irow) = cnt(irow) + ncol !!! might include duplicate cols
1643  enddo
1644  enddo
1645  !
1646  allocate(bt_int%index(0:bt_int%nr))
1647  call make_index(bt_int%nr, cnt, bt_int%index)
1648  !
1649  bt_int%nnz = bt_int%index(bt_int%nr)
1650  allocate(bt_int%item(bt_int%nnz))
1651  allocate(bt_int%A(bt_int%nnz * ndof2))
1652  bt_int%A(:) = 0.d0
1653  end subroutine allocate_bt_int
1654 
1655  subroutine copy_mesh(src, dst)
1656  implicit none
1657  type (hecmwST_local_mesh), intent(in) :: src
1658  type (hecmwST_local_mesh), intent(out) :: dst
1659  dst%zero = src%zero
1660  dst%MPI_COMM = src%MPI_COMM
1661  dst%PETOT = src%PETOT
1662  dst%PEsmpTOT = src%PEsmpTOT
1663  dst%my_rank = src%my_rank
1664  dst%n_subdomain = src%n_subdomain
1665  dst%n_node = src%n_node
1666  dst%nn_internal = src%nn_internal
1667  dst%n_dof = src%n_dof
1668  dst%n_neighbor_pe = src%n_neighbor_pe
1669  allocate(dst%neighbor_pe(dst%n_neighbor_pe))
1670  dst%neighbor_pe(:) = src%neighbor_pe(:)
1671  allocate(dst%import_index(0:dst%n_neighbor_pe))
1672  allocate(dst%export_index(0:dst%n_neighbor_pe))
1673  dst%import_index(:)= src%import_index(:)
1674  dst%export_index(:)= src%export_index(:)
1675  allocate(dst%import_item(dst%import_index(dst%n_neighbor_pe)))
1676  dst%import_item(:) = src%import_item(:)
1677  allocate(dst%export_item(dst%export_index(dst%n_neighbor_pe)))
1678  dst%export_item(:) = src%export_item(:)
1679  allocate(dst%node_ID(2*dst%n_node))
1680  dst%node_ID(1:2*dst%n_node) = src%node_ID(1:2*src%n_node)
1681  allocate(dst%global_node_ID(dst%n_node))
1682  dst%global_node_ID(1:dst%n_node) = src%global_node_ID(1:src%n_node)
1683  dst%mpc%n_mpc = 0
1684  dst%node => src%node
1685  end subroutine copy_mesh
1686 
1687  subroutine map_imported_cols(hecMESHnew, ncols, cols, n_add_node, add_nodes, map, i0)
1688  implicit none
1689  type (hecmwST_local_mesh), intent(inout) :: hecMESHnew
1690  integer(kind=kint), intent(in) :: ncols
1691  integer(kind=kint), intent(in) :: cols(cNCOL_ITEM,ncols)
1692  integer(kind=kint), allocatable, intent(out) :: map(:)
1693  integer(kind=kint), intent(out) :: n_add_node
1694  integer(kind=kint), allocatable, intent(out) :: add_nodes(:,:)
1695  integer(kind=kint), intent(out) :: i0
1696  allocate(map(ncols))
1697  !
1698  call map_present_nodes(hecmeshnew, ncols, cols, map, n_add_node)
1699  !
1700  ! add nodes == unmapped nodes
1701  !
1702  call extract_add_nodes(ncols, cols, map, n_add_node, add_nodes)
1703  !
1704  call append_nodes(hecmeshnew, n_add_node, add_nodes, i0)
1705  !
1706  call map_additional_nodes(ncols, cols, n_add_node, add_nodes, i0, map)
1707  end subroutine map_imported_cols
1708 
1709  subroutine map_present_nodes(hecMESH, ncols, cols, map, n_add_node)
1710  implicit none
1711  type (hecmwST_local_mesh), intent(in) :: hecMESH
1712  integer(kind=kint), intent(in) :: ncols
1713  integer(kind=kint), intent(in) :: cols(cNCOL_ITEM,ncols)
1714  integer(kind=kint), intent(out) :: map(ncols)
1715  integer(kind=kint), intent(out) :: n_add_node
1716  integer(kind=kint) :: i, j, lid, rank, llid, n_ext_node, idx
1717  integer(kind=kint), allocatable :: ext_node(:)
1718  type (hecmwST_pair_array) :: parray
1719  !
1720  call hecmw_pair_array_init(parray, hecmesh%n_node - hecmesh%nn_internal)
1721  do i = hecmesh%nn_internal + 1, hecmesh%n_node
1722  call hecmw_pair_array_append(parray, i, hecmesh%node_ID(2*i-1), hecmesh%node_ID(2*i))
1723  enddo
1724  call hecmw_pair_array_sort(parray)
1725  !
1726  n_add_node = 0
1727  n_ext_node = 0
1728  allocate(ext_node(ncols))
1729  !$omp parallel default(none), &
1730  !$omp& private(i,lid,rank,llid,idx,j), &
1731  !$omp& shared(ncols,hecMESH,cols,map,n_ext_node,ext_node,parray), &
1732  !$omp& reduction(+:n_add_node)
1733  !$omp do
1734  do i = 1, ncols
1735  lid = cols(clid,i)
1736  rank = cols(crank,i)
1737  ! check rank
1738  if (rank == hecmesh%my_rank) then ! internal: set mapping
1739  map(i) = lid
1740  else ! external
1741  !$omp atomic capture
1742  n_ext_node = n_ext_node + 1
1743  idx = n_ext_node
1744  !$omp end atomic
1745  ext_node(idx) = i
1746  endif
1747  enddo
1748  !$omp end do
1749  !$omp do
1750  do j = 1, n_ext_node
1751  i = ext_node(j)
1752  lid = cols(clid,i)
1753  rank = cols(crank,i)
1754  ! search node_ID in external nodes
1755  llid = hecmw_pair_array_find_id(parray, lid, rank)
1756  if (llid > 0) then ! found: set mapping
1757  map(i) = llid
1758  else ! not found
1759  map(i) = -1
1760  n_add_node = n_add_node + 1
1761  endif
1762  enddo
1763  !$omp end do
1764  !$omp end parallel
1765  deallocate(ext_node)
1766  !
1767  call hecmw_pair_array_finalize(parray)
1768  end subroutine map_present_nodes
1769 
1770  subroutine extract_add_nodes(ncols, cols, map, n_add_node, add_nodes)
1771  implicit none
1772  integer(kind=kint), intent(in) :: ncols
1773  integer(kind=kint), intent(in) :: cols(cNCOL_ITEM,ncols), map(ncols)
1774  integer(kind=kint), intent(inout) :: n_add_node
1775  integer(kind=kint), allocatable, intent(out) :: add_nodes(:,:)
1776  integer(kind=kint) :: cnt, i
1777  allocate(add_nodes(cncol_item,n_add_node))
1778  cnt = 0
1779  do i = 1, ncols
1780  if (map(i) == -1) then
1781  cnt = cnt + 1
1782  add_nodes(1:cncol_item,cnt) = cols(1:cncol_item,i)
1783  endif
1784  enddo
1785  if (cnt /= n_add_node) stop 'ERROR: extract add_nodes'
1786  call sort_and_uniq_add_nodes(n_add_node, add_nodes)
1787  end subroutine extract_add_nodes
1788 
1789  subroutine sort_and_uniq_add_nodes(n_add_node, add_nodes)
1790  implicit none
1791  integer(kind=kint), intent(inout) :: n_add_node
1792  integer(kind=kint), intent(inout) :: add_nodes(cNCOL_ITEM,n_add_node)
1793  integer(kind=kint) :: ndup
1794  call sort_add_nodes(add_nodes, 1, n_add_node)
1795  call uniq_add_nodes(add_nodes, n_add_node, ndup)
1796  n_add_node = n_add_node - ndup
1797  end subroutine sort_and_uniq_add_nodes
1798 
1799  recursive subroutine sort_add_nodes(add_nodes, id1, id2)
1800  implicit none
1801  integer(kind=kint), intent(inout) :: add_nodes(:,:)
1802  integer(kind=kint), intent(in) :: id1, id2
1803  integer(kind=kint) :: center, left, right
1804  integer(kind=kint) :: pivot(cNCOL_ITEM), tmp(cNCOL_ITEM)
1805  if (id1 >= id2) return
1806  center = (id1 + id2) / 2
1807  pivot(1:cncol_item) = add_nodes(1:cncol_item,center)
1808  left = id1
1809  right = id2
1810  do
1811  do while ((add_nodes(crank,left) < pivot(crank)) .or. &
1812  (add_nodes(crank,left) == pivot(crank) .and. add_nodes(clid,left) < pivot(clid)))
1813  left = left + 1
1814  enddo
1815  do while ((pivot(crank) < add_nodes(crank,right)) .or. &
1816  (pivot(crank) == add_nodes(crank,right) .and. pivot(clid) < add_nodes(clid,right)))
1817  right = right - 1
1818  enddo
1819  if (left >= right) exit
1820  tmp(1:cncol_item) = add_nodes(1:cncol_item,left)
1821  add_nodes(1:cncol_item,left) = add_nodes(1:cncol_item,right)
1822  add_nodes(1:cncol_item,right) = tmp(1:cncol_item)
1823  left = left + 1
1824  right = right - 1
1825  enddo
1826  if (id1 < left-1) call sort_add_nodes(add_nodes, id1, left-1)
1827  if (right+1 < id2) call sort_add_nodes(add_nodes, right+1, id2)
1828  return
1829  end subroutine sort_add_nodes
1830 
1831  subroutine uniq_add_nodes(add_nodes, len, ndup)
1832  implicit none
1833  integer(kind=kint), intent(inout) :: add_nodes(:,:)
1834  integer(kind=kint), intent(in) :: len
1835  integer(kind=kint), intent(out) :: ndup
1836  integer(kind=kint) :: i
1837  ndup = 0
1838  do i = 2,len
1839  if (add_nodes(clid,i) == add_nodes(clid,i-1-ndup) .and. &
1840  add_nodes(crank,i) == add_nodes(crank,i-1-ndup)) then
1841  ndup = ndup + 1
1842  else if (ndup > 0) then
1843  add_nodes(1:cncol_item,i-ndup) = add_nodes(1:cncol_item,i)
1844  endif
1845  enddo
1846  end subroutine uniq_add_nodes
1847 
1848  subroutine search_add_nodes(n_add_node, add_nodes, rank, lid, idx)
1849  implicit none
1850  integer(kind=kint), intent(in) :: n_add_node
1851  integer(kind=kint), intent(in) :: add_nodes(cNCOL_ITEM,n_add_node)
1852  integer(kind=kint), intent(in) :: rank
1853  integer(kind=kint), intent(in) :: lid
1854  integer(kind=kint), intent(out) :: idx
1855  integer(kind=kint) :: left, right, center
1856  left = 1
1857  right = n_add_node
1858  do while (left <= right)
1859  center = (left + right) / 2
1860  if ((rank == add_nodes(crank,center)) .and. (lid == add_nodes(clid,center))) then
1861  idx = center
1862  return
1863  else if ((rank < add_nodes(crank,center)) .or. &
1864  (rank == add_nodes(crank,center) .and. lid < add_nodes(clid,center))) then
1865  right = center - 1
1866  else if ((add_nodes(crank,center) < rank) .or. &
1867  (add_nodes(crank,center) == rank .and. add_nodes(clid,center) < lid)) then
1868  left = center + 1
1869  endif
1870  end do
1871  idx = -1
1872  end subroutine search_add_nodes
1873 
1874  subroutine append_nodes(hecMESHnew, n_add_node, add_nodes, i0)
1875  implicit none
1876  type (hecmwST_local_mesh), intent(inout) :: hecMESHnew
1877  integer(kind=kint), intent(in) :: n_add_node
1878  integer(kind=kint), intent(in) :: add_nodes(:,:)
1879  integer(kind=kint), intent(out) :: i0
1880  integer(kind=kint) :: n_node, i, ii
1881  integer(kind=kint), pointer :: node_ID(:), global_node_ID(:)
1882  i0 = hecmeshnew%n_node
1883  n_node = hecmeshnew%n_node + n_add_node
1884  allocate(node_id(2*n_node))
1885  allocate(global_node_id(n_node))
1886  do i = 1, hecmeshnew%n_node
1887  node_id(2*i-1) = hecmeshnew%node_ID(2*i-1)
1888  node_id(2*i ) = hecmeshnew%node_ID(2*i )
1889  global_node_id(i) = hecmeshnew%global_node_ID(i)
1890  enddo
1891  do i = 1, n_add_node
1892  ii = hecmeshnew%n_node + i
1893  node_id(2*ii-1) = add_nodes(clid,i)
1894  node_id(2*ii ) = add_nodes(crank,i)
1895  if (cncol_item >= 3) then
1896  global_node_id(ii) = add_nodes(cgid,i)
1897  else
1898  global_node_id(ii) = -1
1899  endif
1900  enddo
1901  deallocate(hecmeshnew%node_ID)
1902  deallocate(hecmeshnew%global_node_ID)
1903  hecmeshnew%n_node = n_node
1904  hecmeshnew%node_ID => node_id
1905  hecmeshnew%global_node_ID => global_node_id
1906  end subroutine append_nodes
1907 
1908  subroutine map_additional_nodes(ncols, cols, n_add_node, add_nodes, i0, map)
1909  implicit none
1910  integer(kind=kint), intent(in) :: ncols
1911  integer(kind=kint), intent(in) :: cols(cNCOL_ITEM,ncols)
1912  integer(kind=kint), intent(in) :: n_add_node
1913  integer(kind=kint), intent(in) :: add_nodes(cNCOL_ITEM,n_add_node)
1914  integer(kind=kint), intent(in) :: i0
1915  integer(kind=kint), intent(inout) :: map(ncols)
1916  integer(kind=kint) :: i, j
1917  do i = 1, ncols
1918  if (map(i) > 0) cycle
1919  call search_add_nodes(n_add_node, add_nodes, cols(crank,i), cols(clid,i), j)
1920  if (j == -1) stop 'ERROR: map_additional_nodes'
1921  map(i) = i0 + j
1922  enddo
1923  end subroutine map_additional_nodes
1924 
1925  subroutine update_comm_table(hecMESHnew, n_add_node, add_nodes, i0)
1926  use m_hecmw_comm_f
1927  implicit none
1928  type (hecmwST_local_mesh), intent(inout) :: hecMESHnew
1929  integer(kind=kint), intent(in) :: n_add_node
1930  integer(kind=kint), allocatable, intent(inout) :: add_nodes(:,:)
1931  integer(kind=kint), intent(in) :: i0
1932  integer(kind=kint), allocatable :: n_add_imp(:), add_imp_index(:)
1933  integer(kind=kint), allocatable :: add_imp_item_remote(:), add_imp_item_local(:)
1934  integer(kind=kint), allocatable :: n_add_exp(:), add_exp_index(:), add_exp_item(:)
1935  integer(kind=kint), allocatable :: n_new_imp(:), n_new_exp(:)
1936  integer(kind=kint) :: npe, nnb, comm, new_nnb
1937  integer(kind=kint), pointer :: nbpe(:), new_nbpe(:)
1938  integer(kind=kint), pointer :: import_index(:), export_index(:), import_item(:), export_item(:)
1939  integer(kind=kint), pointer :: new_import_index(:), new_export_index(:)
1940  integer(kind=kint), pointer :: new_import_item(:), new_export_item(:)
1941  npe = hecmeshnew%PETOT
1942  nnb = hecmeshnew%n_neighbor_pe
1943  comm = hecmeshnew%MPI_COMM
1944  nbpe => hecmeshnew%neighbor_pe
1945  import_index => hecmeshnew%import_index
1946  export_index => hecmeshnew%export_index
1947  import_item => hecmeshnew%import_item
1948  export_item => hecmeshnew%export_item
1949  !
1950  call count_add_imp_per_rank(n_add_node, add_nodes, npe, n_add_imp)
1951  if (debug >= 3) write(0,*) ' DEBUG3: count add_imp per rank done'
1952  !
1953  allocate(add_imp_index(0:npe))
1954  call make_index(npe, n_add_imp, add_imp_index)
1955  if (debug >= 3) write(0,*) ' DEBUG3: make add_imp_index done'
1956  !
1957  call make_add_imp_item(n_add_node, add_nodes, npe, i0, add_imp_index, &
1958  add_imp_item_remote, add_imp_item_local)
1959  if (debug >= 3) write(0,*) ' DEBUG3: make add_imp_item done'
1960  !
1961  deallocate(add_nodes)
1962  !
1963  ! all_to_all n_add_imp -> n_add_exp
1964  !
1965  allocate(n_add_exp(npe))
1966  call hecmw_alltoall_int(n_add_imp, 1, n_add_exp, 1, comm)
1967  if (debug >= 3) write(0,*) ' DEBUG3: alltoall n_add_imp to n_add_exp done'
1968  !
1969  allocate(add_exp_index(0:npe))
1970  call make_index(npe, n_add_exp, add_exp_index)
1971  if (debug >= 3) write(0,*) ' DEBUG3: make add_exp_index done'
1972  !
1973  call send_recv_add_imp_exp_item(npe, add_imp_index, add_imp_item_remote, &
1974  add_exp_index, add_exp_item, comm)
1975  if (debug >= 3) write(0,*) ' DEBUG3: send recv add_imp/exp_item done'
1976  !
1977  ! count new import
1978  !
1979  call count_new_comm_nodes(npe, nnb, nbpe, import_index, n_add_imp, n_new_imp)
1980  if (debug >= 3) write(0,*) ' DEBUG3: count new comm_nodes (import) done'
1981  !
1982  ! count new export
1983  !
1984  call count_new_comm_nodes(npe, nnb, nbpe, export_index, n_add_exp, n_new_exp)
1985  if (debug >= 3) write(0,*) ' DEBUG3: count new comm_nodes (export) done'
1986  !
1987  call update_neighbor_pe(npe, n_new_imp, n_new_exp, new_nnb, new_nbpe)
1988  if (debug >= 3) write(0,*) ' DEBUG3: update neighbor_pe done'
1989  !
1990  ! merge import table: import
1991  !
1992  call merge_comm_table(npe, nnb, nbpe, import_index, import_item, &
1993  new_nnb, new_nbpe, add_imp_index, add_imp_item_local, n_add_imp, n_new_imp, &
1994  new_import_index, new_import_item)
1995  if (debug >= 3) write(0,*) ' DEBUG3: merge comm_table (import) done'
1996  !
1997  deallocate(n_add_imp)
1998  deallocate(add_imp_index)
1999  deallocate(add_imp_item_remote, add_imp_item_local)
2000  deallocate(n_new_imp)
2001  !
2002  ! merge export table: export
2003  !
2004  call merge_comm_table(npe, nnb, nbpe, export_index, export_item, &
2005  new_nnb, new_nbpe, add_exp_index, add_exp_item, n_add_exp, n_new_exp, &
2006  new_export_index, new_export_item)
2007  if (debug >= 3) write(0,*) ' DEBUG3: merge comm_table (export) done'
2008  !
2009  deallocate(n_add_exp)
2010  deallocate(add_exp_index)
2011  deallocate(add_exp_item)
2012  deallocate(n_new_exp)
2013  !
2014  deallocate(nbpe)
2015  deallocate(import_index,import_item)
2016  deallocate(export_index,export_item)
2017  hecmeshnew%n_neighbor_pe = new_nnb
2018  hecmeshnew%neighbor_pe => new_nbpe
2019  hecmeshnew%import_index => new_import_index
2020  hecmeshnew%export_index => new_export_index
2021  hecmeshnew%import_item => new_import_item
2022  hecmeshnew%export_item => new_export_item
2023  end subroutine update_comm_table
2024 
2025  subroutine count_add_imp_per_rank(n_add_node, add_nodes, npe, n_add_imp)
2026  implicit none
2027  integer(kind=kint), intent(in) :: n_add_node
2028  integer(kind=kint), intent(in) :: add_nodes(cNCOL_ITEM,n_add_node)
2029  integer(kind=kint), intent(in) :: npe
2030  integer(kind=kint), allocatable, intent(out) :: n_add_imp(:)
2031  integer(kind=kint) :: i, rank
2032  allocate(n_add_imp(npe))
2033  n_add_imp(:) = 0
2034  do i = 1, n_add_node
2035  rank = add_nodes(crank,i)
2036  n_add_imp(rank+1) = n_add_imp(rank+1) + 1
2037  enddo
2038  end subroutine count_add_imp_per_rank
2039 
2040  subroutine make_add_imp_item(n_add_node, add_nodes, npe, i0, add_imp_index, &
2041  add_imp_item_remote, add_imp_item_local)
2042  implicit none
2043  integer(kind=kint), intent(in) :: n_add_node
2044  integer(kind=kint), intent(in) :: add_nodes(cNCOL_ITEM,n_add_node)
2045  integer(kind=kint), intent(in) :: npe, i0
2046  integer(kind=kint), allocatable, intent(in) :: add_imp_index(:)
2047  integer(kind=kint), allocatable, intent(out) :: add_imp_item_remote(:), add_imp_item_local(:)
2048  integer(kind=kint), allocatable :: cnt(:)
2049  integer(kind=kint) :: i, lid, rank, ipe
2050  allocate(add_imp_item_remote(add_imp_index(npe)))
2051  allocate(add_imp_item_local(add_imp_index(npe)))
2052  allocate(cnt(npe))
2053  cnt(:) = 0
2054  do i = 1, n_add_node
2055  lid = add_nodes(clid,i)
2056  rank = add_nodes(crank,i)
2057  ipe = rank + 1
2058  cnt(ipe) = cnt(ipe) + 1
2059  add_imp_item_remote(add_imp_index(ipe-1) + cnt(ipe)) = lid
2060  add_imp_item_local(add_imp_index(ipe-1) + cnt(ipe)) = i0 + i
2061  enddo
2062  deallocate(cnt)
2063  end subroutine make_add_imp_item
2064 
2065  subroutine send_recv_add_imp_exp_item(npe, add_imp_index, add_imp_item_remote, &
2066  add_exp_index, add_exp_item, mpi_comm)
2067  use m_hecmw_comm_f
2068  implicit none
2069  integer(kind=kint), intent(in) :: npe
2070  integer(kind=kint), allocatable, intent(in) :: add_imp_index(:), add_imp_item_remote(:)
2071  integer(kind=kint), allocatable, intent(in) :: add_exp_index(:)
2072  integer(kind=kint), allocatable, intent(out) :: add_exp_item(:)
2073  integer(kind=kint), intent(in) :: mpi_comm
2074  integer(kind=kint) :: n_send, i, irank, is, ie, len, tag
2075  integer(kind=kint), allocatable :: requests(:)
2076  integer(kind=kint), allocatable :: statuses(:,:)
2077  allocate(add_exp_item(add_exp_index(npe)))
2078  allocate(requests(npe))
2079  allocate(statuses(hecmw_status_size, npe))
2080  n_send = 0
2081  do i = 1, npe
2082  irank = i-1
2083  is = add_imp_index(i-1)+1
2084  ie = add_imp_index(i)
2085  len = ie - is + 1
2086  if (len == 0) cycle
2087  tag = 4001
2088  n_send = n_send + 1
2089  call hecmw_isend_int(add_imp_item_remote(is:ie), len, irank, tag, &
2090  mpi_comm, requests(n_send))
2091  enddo
2092  !
2093  do i = 1, npe
2094  irank = i-1
2095  is = add_exp_index(i-1)+1
2096  ie = add_exp_index(i)
2097  len = ie - is + 1
2098  if (len == 0) cycle
2099  tag = 4001
2100  call hecmw_recv_int(add_exp_item(is:ie), len, irank, tag, &
2101  mpi_comm, statuses(:,1))
2102  enddo
2103  call hecmw_waitall(n_send, requests, statuses)
2104  end subroutine send_recv_add_imp_exp_item
2105 
2106  subroutine count_new_comm_nodes(npe, org_nnb, org_nbpe, org_index, n_add, n_new)
2107  implicit none
2108  integer(kind=kint), intent(in) :: npe, org_nnb
2109  !integer(kind=kint), intent(in) :: org_nbpe(org_nnb), org_index(0:org_nnb), n_add(npe)
2110  integer(kind=kint), pointer, intent(in) :: org_nbpe(:), org_index(:)
2111  integer(kind=kint), intent(in) :: n_add(:)
2112  integer(kind=kint), allocatable, intent(out) :: n_new(:)
2113  integer(kind=kint) :: i, irank, n_org
2114  allocate(n_new(npe))
2115  n_new(:) = n_add(:)
2116  do i = 1, org_nnb
2117  irank = org_nbpe(i)
2118  n_org = org_index(i) - org_index(i-1)
2119  n_new(irank+1) = n_new(irank+1) + n_org
2120  enddo
2121  end subroutine count_new_comm_nodes
2122 
2123  subroutine update_neighbor_pe(npe, n_new_imp, n_new_exp, &
2124  new_nnb, new_nbpe)
2125  implicit none
2126  integer(kind=kint), intent(in) :: npe
2127  integer(kind=kint), intent(in) :: n_new_imp(npe), n_new_exp(npe)
2128  integer(kind=kint), intent(out) :: new_nnb
2129  integer(kind=kint), pointer, intent(out) :: new_nbpe(:)
2130  integer(kind=kint) :: i
2131  new_nnb = 0
2132  do i = 1, npe
2133  if (n_new_imp(i) > 0 .or. n_new_exp(i) > 0) new_nnb = new_nnb+1
2134  enddo
2135  allocate(new_nbpe(new_nnb))
2136  new_nnb = 0
2137  do i = 1, npe
2138  if (n_new_imp(i) > 0 .or. n_new_exp(i) > 0) then
2139  new_nnb = new_nnb+1
2140  new_nbpe(new_nnb) = i-1
2141  endif
2142  enddo
2143  end subroutine update_neighbor_pe
2144 
2145  subroutine merge_comm_table(npe, org_nnb, org_nbpe, org_index, org_item, &
2146  new_nnb, new_nbpe, add_index, add_item, n_add, n_new, new_index, new_item)
2147  implicit none
2148  integer(kind=kint), intent(in) :: npe, org_nnb
2149  !integer(kind=kint), intent(in) :: org_nbpe(org_nnb), org_index(0:org_nnb), org_item(:)
2150  integer(kind=kint), pointer, intent(in) :: org_nbpe(:), org_index(:), org_item(:)
2151  integer(kind=kint), intent(in) :: new_nnb
2152  !integer(kind=kint), intent(in) :: new_nbpe(new_nnb), add_index(0:npe), add_item(:)
2153  integer(kind=kint), pointer, intent(in) :: new_nbpe(:)
2154  integer(kind=kint), allocatable, intent(in) :: add_index(:), add_item(:)
2155  integer(kind=kint), intent(in) :: n_add(npe), n_new(npe)
2156  integer(kind=kint), pointer, intent(out) :: new_index(:), new_item(:)
2157  integer(kind=kint), allocatable :: cnt(:)
2158  integer(kind=kint) :: i, irank, j, jrank, i0, j0, len
2159  ! if (associated(new_index)) deallocate(new_index)
2160  ! if (associated(new_item)) deallocate(new_item)
2161  allocate(new_index(0:new_nnb))
2162  new_index(0) = 0
2163  do i = 1, new_nnb
2164  irank = new_nbpe(i)
2165  new_index(i) = new_index(i-1) + n_new(irank+1)
2166  enddo
2167  allocate(new_item(new_index(new_nnb)))
2168  allocate(cnt(npe))
2169  cnt(:) = 0
2170  j = 1
2171  jrank = new_nbpe(j)
2172  do i = 1, org_nnb
2173  if (org_index(i) - org_index(i-1) == 0) cycle
2174  irank = org_nbpe(i)
2175  do while (jrank < irank)
2176  j = j + 1
2177  if (j > new_nnb) exit
2178  jrank = new_nbpe(j)
2179  enddo
2180  if (jrank /= irank) stop 'ERROR: merging comm table: org into new'
2181  i0 = org_index(i-1)
2182  len = org_index(i) - i0
2183  j0 = new_index(j-1)
2184  new_item(j0+1:j0+len) = org_item(i0+1:i0+len)
2185  cnt(jrank+1) = len
2186  enddo
2187  j = 1
2188  jrank = new_nbpe(j)
2189  do i = 1, npe
2190  if (n_add(i) == 0) cycle
2191  irank = i-1
2192  do while (jrank < irank)
2193  j = j + 1
2194  jrank = new_nbpe(j)
2195  enddo
2196  if (jrank /= irank) stop 'ERROR: merging comm table: add into new'
2197  i0 = add_index(i-1)
2198  len = add_index(i) - i0
2199  j0 = new_index(j-1) + cnt(jrank+1)
2200  new_item(j0+1:j0+len) = add_item(i0+1:i0+len)
2201  cnt(jrank+1) = cnt(jrank+1) + len
2202  if (cnt(jrank+1) /= new_index(j)-new_index(j-1)) stop 'ERROR: merging comm table'
2203  enddo
2204  deallocate(cnt)
2205  end subroutine merge_comm_table
2206 
2207  subroutine copy_vals_to_bt_int(nnb, imp_rows_index, imp_cols_index, &
2208  imp_rows_item, map, ndof2, imp_vals_item, BT_int)
2209  implicit none
2210  integer(kind=kint), intent(in) :: nnb
2211  integer(kind=kint), allocatable, intent(in) :: imp_rows_index(:), imp_cols_index(:)
2212  integer(kind=kint), intent(in) :: imp_rows_item(:,:), map(:)
2213  integer(kind=kint), intent(in) :: ndof2
2214  real(kind=kreal), intent(in) :: imp_vals_item(:)
2215  type (hecmwST_local_matrix), intent(inout) :: BT_int
2216  integer(kind=kint), allocatable :: cnt(:)
2217  integer(kind=kint) :: idom, is, ie, ic0, i, irow, ncol, j0, j
2218  allocate(cnt(bt_int%nr))
2219  cnt(:) = 0
2220  do idom = 1, nnb
2221  is = imp_rows_index(idom-1)+1
2222  ie = imp_rows_index(idom)
2223  ic0 = imp_cols_index(idom-1)
2224  do i = is, ie
2225  irow = imp_rows_item(1,i)
2226  ncol = imp_rows_item(2,i)
2227  if (irow < 1 .or. bt_int%nr < irow) stop 'ERROR: copy vals to BT_int: irow'
2228  j0 = bt_int%index(irow-1) + cnt(irow)
2229  do j = 1, ncol
2230  bt_int%item(j0+j) = map(ic0+j)
2231  bt_int%A(ndof2*(j0+j-1)+1:ndof2*(j0+j)) = imp_vals_item(ndof2*(ic0+j-1)+1:ndof2*(ic0+j))
2232  enddo
2233  cnt(irow) = cnt(irow) + ncol
2234  ic0 = ic0 + ncol
2235  enddo
2236  if (ic0 /= imp_cols_index(idom)) stop 'ERROR: copy vals to BT_int: ic0'
2237  enddo
2238  deallocate(cnt)
2239  end subroutine copy_vals_to_bt_int
2240 
2241  subroutine sort_and_uniq_rows(BTmat)
2242  use hecmw_array_util
2243  implicit none
2244  type (hecmwST_local_matrix), intent(inout) :: BTmat
2245  integer(kind=kint) :: nr, ndof, ndof2
2246  integer(kind=kint) :: irow, is, ie, is_new, ie_new, i, i_new
2247  integer(kind=kint) :: ndup, ndup_tot
2248  integer(kind=kint) :: js, je, js_new, je_new
2249  integer(kind=kint) :: new_nnz
2250  integer(kind=kint), allocatable :: cnt(:)
2251  integer(kind=kint), pointer :: sort_item(:), new_index(:), new_item(:)
2252  real(kind=kreal), pointer :: new_a(:)
2253  logical :: sorted
2254  real(kind=kreal) :: t0, t1
2255  t0 = hecmw_wtime()
2256  nr = btmat%nr
2257  ! check if already sorted
2258  sorted = .true.
2259  outer: do irow = 1, nr
2260  is = btmat%index(irow-1)+1
2261  ie = btmat%index(irow)
2262  do i = is, ie-1
2263  if (btmat%item(i) >= btmat%item(i+1)) then
2264  sorted = .false.
2265  exit outer
2266  endif
2267  enddo
2268  end do outer
2269  t1 = hecmw_wtime()
2270  if (timer >= 4) write(0, '(A,f10.4,L2)') "####### sort_and_uniq_rows (1) : ",t1-t0,sorted
2271  t0 = hecmw_wtime()
2272  if (sorted) return
2273  ! perform sort
2274  ndof = btmat%ndof
2275  ndof2 = ndof*ndof
2276  ! duplicate item array (sort_item)
2277  allocate(sort_item(btmat%nnz))
2278  do i = 1, btmat%nnz
2279  sort_item(i) = btmat%item(i)
2280  enddo
2281  ! sort and uniq item for each row
2282  allocate(cnt(nr))
2283  ndup_tot = 0
2284  !$omp parallel do default(none), &
2285  !$omp& schedule(dynamic,1), &
2286  !$omp& private(irow,is,ie,ndup), &
2287  !$omp& shared(nr,BTmat,sort_item,cnt), &
2288  !$omp& reduction(+:ndup_tot)
2289  do irow = 1, nr
2290  is = btmat%index(irow-1)+1
2291  ie = btmat%index(irow)
2292  call hecmw_qsort_int_array(sort_item, is, ie)
2293  call hecmw_uniq_int_array(sort_item, is, ie, ndup)
2294  cnt(irow) = (ie-is+1) - ndup
2295  ndup_tot = ndup_tot + ndup
2296  enddo
2297  !$omp end parallel do
2298  t1 = hecmw_wtime()
2299  if (timer >= 4) write(0, '(A,f10.4,I5)') "####### sort_and_uniq_rows (2) : ",t1-t0,ndup_tot
2300  t0 = hecmw_wtime()
2301  ! make new index and item array (new_index, new_item)
2302  if (ndup_tot == 0) then
2303  new_index => btmat%index
2304  new_nnz = btmat%nnz
2305  new_item => sort_item
2306  else
2307  allocate(new_index(0:nr))
2308  call make_index(nr, cnt, new_index)
2309  new_nnz = new_index(nr)
2310  allocate(new_item(new_nnz))
2311  do irow = 1, nr
2312  is = btmat%index(irow-1)+1
2313  ie = is+cnt(irow)-1
2314  is_new = new_index(irow-1)+1
2315  ie_new = is_new+cnt(irow)-1
2316  new_item(is_new:ie_new) = sort_item(is:ie)
2317  enddo
2318  deallocate(sort_item)
2319  endif
2320  deallocate(cnt)
2321  t1 = hecmw_wtime()
2322  if (timer >= 4) write(0, '(A,f10.4)') "####### sort_and_uniq_rows (3) : ",t1-t0
2323  t0 = hecmw_wtime()
2324  ! allocate and clear value array (new_A)
2325  allocate(new_a(ndof2*new_nnz))
2326  new_a(:) = 0.d0
2327  ! copy/add value from old A to new A
2328  !$omp parallel do default(none), &
2329  !$omp& schedule(dynamic,1), &
2330  !$omp& private(irow,is,ie,is_new,ie_new,i,i_new,js,je,js_new,je_new), &
2331  !$omp& shared(nr,BTmat,new_index,new_item,ndof2,new_A)
2332  do irow = 1, nr
2333  is = btmat%index(irow-1)+1
2334  ie = btmat%index(irow)
2335  is_new = new_index(irow-1)+1
2336  ie_new = new_index(irow)
2337  ! for each item in row
2338  do i = is, ie
2339  ! find place in new item
2340  call hecmw_bsearch_int_array(new_item, is_new, ie_new, btmat%item(i), i_new)
2341  if (i_new == -1) stop 'ERROR: sort_and_uniq_rows'
2342  js = ndof2*(i-1)+1
2343  je = ndof2*i
2344  js_new = ndof2*(i_new-1)+1
2345  je_new = ndof2*i_new
2346  new_a(js_new:je_new) = new_a(js_new:je_new) + btmat%A(js:je)
2347  enddo
2348  enddo
2349  !$omp end parallel do
2350  t1 = hecmw_wtime()
2351  if (timer >= 4) write(0, '(A,f10.4)') "####### sort_and_uniq_rows (4) : ",t1-t0
2352  t0 = hecmw_wtime()
2353  ! deallocate/update nnz, index, item, A
2354  if (ndup_tot == 0) then
2355  deallocate(btmat%item)
2356  btmat%item => new_item
2357  deallocate(btmat%A)
2358  btmat%A => new_a
2359  else
2360  btmat%nnz = new_nnz
2361  deallocate(btmat%index)
2362  btmat%index => new_index
2363  deallocate(btmat%item)
2364  btmat%item => new_item
2365  deallocate(btmat%A)
2366  btmat%A => new_a
2367  endif
2368  end subroutine sort_and_uniq_rows
2369 
2370  subroutine hecmw_localmat_add(Amat, Bmat, Cmat)
2371  implicit none
2372  type (hecmwst_local_matrix), intent(in) :: amat
2373  type (hecmwst_local_matrix), intent(in) :: bmat
2374  type (hecmwst_local_matrix), intent(out) :: cmat
2375  integer(kind=kint) :: ndof, ndof2, nr, nc, i, icnt, js, je, j, jcol, idx, i0, k
2376  integer(kind=kint), allocatable :: iw(:)
2377  if (amat%ndof /= bmat%ndof) stop 'ERROR: hecmw_localmat_add: non-matching ndof'
2378  ndof = amat%ndof
2379  ndof2 = ndof*ndof
2380  nr = min(amat%nr, bmat%nr)
2381  nc = max(amat%nc, bmat%nc)
2382  cmat%ndof = ndof
2383  cmat%nr = nr
2384  cmat%nc = nc
2385  cmat%nnz = 0
2386  allocate(cmat%index(0:nr))
2387  cmat%index(0) = 0
2388  allocate(iw(nc))
2389  do i = 1, nr
2390  icnt = 0
2391  ! Amat
2392  js = amat%index(i-1)+1
2393  je = amat%index(i)
2394  do j = js, je
2395  jcol = amat%item(j)
2396  icnt = icnt + 1
2397  iw(icnt) = jcol
2398  enddo
2399  ! Bmat
2400  js = bmat%index(i-1)+1
2401  je = bmat%index(i)
2402  lj1: do j = js, je
2403  jcol = bmat%item(j)
2404  do k = 1, icnt
2405  if (iw(k) == jcol) cycle lj1
2406  enddo
2407  icnt = icnt + 1
2408  iw(icnt) = jcol
2409  enddo lj1
2410  cmat%index(i) = cmat%index(i-1) + icnt
2411  enddo
2412  cmat%nnz = cmat%index(nr)
2413  allocate(cmat%item(cmat%nnz))
2414  allocate(cmat%A(ndof2*cmat%nnz))
2415  do i = 1, nr
2416  i0 = cmat%index(i-1)
2417  icnt = 0
2418  ! Amat
2419  js = amat%index(i-1)+1
2420  je = amat%index(i)
2421  do j = js, je
2422  jcol = amat%item(j)
2423  icnt = icnt + 1
2424  idx = i0 + icnt
2425  cmat%item(idx) = jcol
2426  cmat%A(ndof2*(idx-1)+1:ndof2*idx) = amat%A(ndof2*(j-1)+1:ndof2*j)
2427  enddo
2428  ! Bmat
2429  js = bmat%index(i-1)+1
2430  je = bmat%index(i)
2431  lj2: do j = js, je
2432  jcol = bmat%item(j)
2433  do k = 1, icnt
2434  idx = i0 + k
2435  if (cmat%item(idx) == jcol) then
2436  cmat%A(ndof2*(idx-1)+1:ndof2*idx) = &
2437  cmat%A(ndof2*(idx-1)+1:ndof2*idx) + bmat%A(ndof2*(j-1)+1:ndof2*j)
2438  cycle lj2
2439  endif
2440  enddo
2441  icnt = icnt + 1
2442  idx = i0 + icnt
2443  cmat%item(idx) = jcol
2444  cmat%A(ndof2*(idx-1)+1:ndof2*idx) = bmat%A(ndof2*(j-1)+1:ndof2*j)
2445  enddo lj2
2446  if (i0 + icnt /= cmat%index(i)) stop 'ERROR: merge localmat'
2447  enddo
2448  call sort_and_uniq_rows(cmat)
2449  end subroutine hecmw_localmat_add
2450 
2451  ! subroutine hecmw_localmat_add(Amat, Bmat, Cmat)
2452  ! implicit none
2453  ! type (hecmwST_local_matrix), intent(in) :: Amat
2454  ! type (hecmwST_local_matrix), intent(in) :: Bmat
2455  ! type (hecmwST_local_matrix), intent(out) :: Cmat
2456  ! integer(kind=kint) :: ndof, ndof2, nr, nc, i, js, je, j, jcol, nnz_row, idx, ks, ke, k, kcol
2457  ! if (Amat%ndof /= Bmat%ndof) stop 'ERROR: hecmw_localmat_add: non-matching ndof'
2458  ! ndof = Amat%ndof
2459  ! ndof2 = ndof*ndof
2460  ! nr = min(Amat%nr, Bmat%nr)
2461  ! nc = max(Amat%nc, Bmat%nc)
2462  ! Cmat%ndof = ndof
2463  ! Cmat%nr = nr
2464  ! Cmat%nc = nc
2465  ! Cmat%nnz = Amat%index(nr) + Bmat%index(nr)
2466  ! allocate(Cmat%index(0:nr))
2467  ! allocate(Cmat%item(Cmat%nnz))
2468  ! allocate(Cmat%A(ndof2 * Cmat%nnz))
2469  ! Cmat%index(0) = 0
2470  ! idx = 0
2471  ! do i = 1, nr
2472  ! ! Amat
2473  ! js = Amat%index(i-1)+1
2474  ! je = Amat%index(i)
2475  ! do j = js, je
2476  ! idx = idx + 1
2477  ! Cmat%item(idx) = Amat%item(j)
2478  ! Cmat%A(ndof2*(idx-1)+1:ndof2*idx) = Amat%A(ndof2*(j-1)+1:ndof2*j)
2479  ! enddo
2480  ! ! Bmat
2481  ! js = Bmat%index(i-1)+1
2482  ! je = Bmat%index(i)
2483  ! do j = js, je
2484  ! idx = idx + 1
2485  ! Cmat%item(idx) = Bmat%item(j)
2486  ! Cmat%A(ndof2*(idx-1)+1:ndof2*idx) = Bmat%A(ndof2*(j-1)+1:ndof2*j)
2487  ! enddo
2488  ! Cmat%index(i) = idx
2489  ! enddo
2490  ! if (Cmat%index(nr) /= Cmat%nnz) stop 'ERROR: merge localmat'
2491  ! call sort_and_uniq_rows(Cmat)
2492  ! end subroutine hecmw_localmat_add
2493 
2494  subroutine hecmw_localmat_init_with_hecmat(BKmat, hecMAT, num_lagrange)
2495  implicit none
2496  type (hecmwst_local_matrix), intent(inout) :: bkmat
2497  type (hecmwst_matrix), intent(in) :: hecmat
2498  integer(kind=kint), optional, intent(in) :: num_lagrange
2499  integer(kind=kint) :: ndof, ndof2, i, idx, idx2, js, je, j, k
2500  integer(kind=kint), allocatable :: incl_nz(:), cnt(:)
2501  logical :: check_nonzero
2502  check_nonzero = .false.
2503  !check_nonzero = .true. !!! always checking nonzero seems to be faster
2504  !
2505  ndof = hecmat%NDOF
2506  ndof2 = ndof*ndof
2507  ! nr, nc, nnz
2508  bkmat%nr = hecmat%NP
2509  bkmat%nc = hecmat%NP
2510  bkmat%ndof = ndof
2511  !
2512  if (present(num_lagrange)) then !!! TEMPORARY (DUE TO WRONG conMAT WHEN num_lagrange==0) !!!
2513  check_nonzero = .true.
2514  endif
2515  !
2516  if (check_nonzero) then
2517  allocate(incl_nz(hecmat%NPL + hecmat%NPU + hecmat%NP))
2518  allocate(cnt(bkmat%nr))
2519  incl_nz(:) = 0
2520  !$omp parallel default(none), &
2521  !$omp& private(i,idx,js,je,j,k), &
2522  !$omp& shared(BKmat,hecMAT,cnt,ndof2,incl_nz)
2523  !$omp do
2524  do i = 1, bkmat%nr
2525  idx = hecmat%indexL(i-1) + (i-1) + hecmat%indexU(i-1)
2526  cnt(i) = 0
2527  ! lower
2528  js = hecmat%indexL(i-1)+1
2529  je = hecmat%indexL(i)
2530  do j = js, je
2531  idx = idx + 1
2532  do k = 1, ndof2
2533  if (hecmat%AL(ndof2*(j-1)+k) /= 0.0d0) then
2534  incl_nz(idx) = 1
2535  cnt(i) = cnt(i) + 1
2536  exit
2537  endif
2538  enddo
2539  enddo
2540  ! diag
2541  idx = idx + 1
2542  do k = 1, ndof2
2543  if (hecmat%D(ndof2*(i-1)+k) /= 0.0d0) then
2544  incl_nz(idx) = 1
2545  cnt(i) = cnt(i) + 1
2546  exit
2547  endif
2548  enddo
2549  ! upper
2550  js = hecmat%indexU(i-1)+1
2551  je = hecmat%indexU(i)
2552  do j = js, je
2553  idx = idx + 1
2554  do k = 1, ndof2
2555  if (hecmat%AU(ndof2*(j-1)+k) /= 0.0d0) then
2556  incl_nz(idx) = 1
2557  cnt(i) = cnt(i) + 1
2558  exit
2559  endif
2560  enddo
2561  enddo
2562  if (idx /= hecmat%indexL(i) + i + hecmat%indexU(i)) stop 'ERROR: hecmw_localmat_init_with_hecmat: count'
2563  enddo
2564  !$omp end do
2565  !$omp end parallel
2566  ! index
2567  allocate(bkmat%index(0:bkmat%nr))
2568  call make_index(bkmat%nr, cnt, bkmat%index)
2569  deallocate(cnt)
2570  bkmat%nnz = bkmat%index(bkmat%nr)
2571  ! item, A
2572  allocate(bkmat%item(bkmat%nnz))
2573  allocate(bkmat%A(ndof2 * bkmat%nnz))
2574  !$omp parallel default(none), &
2575  !$omp& private(i,idx,idx2,js,je,j), &
2576  !$omp& shared(BKmat,hecMAT,ndof2,incl_nz)
2577  !$omp do
2578  do i = 1, bkmat%nr
2579  idx = hecmat%indexL(i-1) + (i-1) + hecmat%indexU(i-1)
2580  idx2 = bkmat%index(i-1)
2581  ! lower
2582  js = hecmat%indexL(i-1)+1
2583  je = hecmat%indexL(i)
2584  do j = js, je
2585  idx = idx + 1
2586  if (incl_nz(idx) == 1) then
2587  idx2 = idx2 + 1
2588  bkmat%item(idx2) = hecmat%itemL(j)
2589  bkmat%A(ndof2*(idx2-1)+1:ndof2*idx2) = hecmat%AL(ndof2*(j-1)+1:ndof2*j)
2590  endif
2591  enddo
2592  ! diag
2593  idx = idx + 1
2594  if (incl_nz(idx) == 1) then
2595  idx2 = idx2 + 1
2596  bkmat%item(idx2) = i
2597  bkmat%A(ndof2*(idx2-1)+1:ndof2*idx2) = hecmat%D(ndof2*(i-1)+1:ndof2*i)
2598  endif
2599  ! upper
2600  js = hecmat%indexU(i-1)+1
2601  je = hecmat%indexU(i)
2602  do j = js, je
2603  idx = idx + 1
2604  if (incl_nz(idx) == 1) then
2605  idx2 = idx2 + 1
2606  bkmat%item(idx2) = hecmat%itemU(j)
2607  bkmat%A(ndof2*(idx2-1)+1:ndof2*idx2) = hecmat%AU(ndof2*(j-1)+1:ndof2*j)
2608  endif
2609  enddo
2610  if (idx /= hecmat%indexL(i) + i + hecmat%indexU(i)) stop 'ERROR: hecmw_localmat_init_with_hecmat: copy'
2611  if (idx2 /= bkmat%index(i)) stop 'ERROR: hecmw_localmat_init_with_hecmat: index'
2612  enddo
2613  !$omp end do
2614  !$omp end parallel
2615  deallocate(incl_nz)
2616  else
2617  bkmat%nnz = hecmat%NPL + hecmat%NP + hecmat%NPU
2618  allocate(bkmat%index(0:bkmat%nr))
2619  allocate(bkmat%item(bkmat%nnz))
2620  allocate(bkmat%A(ndof2 * bkmat%nnz))
2621  bkmat%index(0) = 0
2622  !$omp parallel do default(none), &
2623  !$omp& private(i,idx,js,je,j), &
2624  !$omp& shared(BKmat,hecMAT,ndof2)
2625  do i = 1, bkmat%nr
2626  idx = hecmat%indexL(i-1) + (i-1) + hecmat%indexU(i-1)
2627  ! lower
2628  js = hecmat%indexL(i-1)+1
2629  je = hecmat%indexL(i)
2630  do j = js, je
2631  idx = idx + 1
2632  bkmat%item(idx) = hecmat%itemL(j)
2633  bkmat%A(ndof2*(idx-1)+1:ndof2*idx) = hecmat%AL(ndof2*(j-1)+1:ndof2*j)
2634  enddo
2635  ! diag
2636  idx = idx + 1
2637  bkmat%item(idx) = i
2638  bkmat%A(ndof2*(idx-1)+1:ndof2*idx) = hecmat%D(ndof2*(i-1)+1:ndof2*i)
2639  ! upper
2640  js = hecmat%indexU(i-1)+1
2641  je = hecmat%indexU(i)
2642  do j = js, je
2643  idx = idx + 1
2644  bkmat%item(idx) = hecmat%itemU(j)
2645  bkmat%A(ndof2*(idx-1)+1:ndof2*idx) = hecmat%AU(ndof2*(j-1)+1:ndof2*j)
2646  enddo
2647  bkmat%index(i) = idx
2648  if (idx /= hecmat%indexL(i) + i + hecmat%indexU(i)) stop 'ERROR: hecmw_localmat_init_with_hecmat: copy'
2649  enddo
2650  !$omp end parallel do
2651  endif
2652  end subroutine hecmw_localmat_init_with_hecmat
2653 
2654  subroutine hecmw_localmat_add_hecmat(BKmat, hecMAT)
2655  implicit none
2656  type (hecmwst_local_matrix), intent(inout) :: bkmat
2657  type (hecmwst_matrix), intent(in) :: hecmat
2658  type (hecmwst_local_matrix) :: w1mat, w2mat
2659  !! Should Be Simple If Non-Zero Profile Is Kept !!
2660  call hecmw_localmat_init_with_hecmat(w1mat, hecmat)
2661  call debug_write_matrix(w1mat, 'BKmat (hecMAT)', debug_matrix)
2662  call hecmw_localmat_add(bkmat, w1mat, w2mat)
2663  call hecmw_localmat_free(bkmat)
2664  call hecmw_localmat_free(w1mat)
2665  bkmat%nr = w2mat%nr
2666  bkmat%nc = w2mat%nc
2667  bkmat%nnz = w2mat%nnz
2668  bkmat%ndof = w2mat%ndof
2669  bkmat%index => w2mat%index
2670  bkmat%item => w2mat%item
2671  bkmat%A => w2mat%A
2672  end subroutine hecmw_localmat_add_hecmat
2673 
2674  subroutine hecmw_localmat_multmat(BKmat, BTmat, hecMESH, BKTmat)
2675  implicit none
2676  type (hecmwst_local_matrix), intent(in) :: bkmat
2677  type (hecmwst_local_matrix), intent(inout) :: btmat
2678  type (hecmwst_local_mesh), intent(inout) :: hecmesh
2679  type (hecmwst_local_matrix), intent(out) :: bktmat
2680  type (hecmwst_matrix_comm) :: heccomm
2681  type (hecmwst_local_mesh) :: hecmeshnew
2682  type (hecmwst_local_matrix), allocatable :: bt_exp(:)
2683  type (hecmwst_local_matrix) :: bt_imp, bt_all
2684  integer(kind=kint), allocatable :: exp_cols_index(:)
2685  integer(kind=kint), allocatable :: exp_cols_item(:,:)
2686  real(kind=kreal) :: t0, t1
2687  t0 = hecmw_wtime()
2688  !
2689  if (hecmesh%PETOT > 1) then
2690  call make_comm_table(bkmat, hecmesh, heccomm)
2691  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: make_comm_table done'
2692  t1 = hecmw_wtime()
2693  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (1) : ',t1-t0
2694  t0 = hecmw_wtime()
2695  !
2696  if (btmat%nr > hecmesh%nn_internal) then
2697  ! consider only internal part of BTmat
2698  if (debug >= 1) write(0,'(A)') 'DEBUG: hecmw_localmat_multmat: ignore external part of BTmat'
2699  btmat%nr = hecmesh%nn_internal
2700  btmat%nnz = btmat%index(btmat%nr)
2701  endif
2702  !
2703  call extract_bt_exp(btmat, heccomm, bt_exp)
2704  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: extract_BT_exp done'
2705  t1 = hecmw_wtime()
2706  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (2) : ',t1-t0
2707  t0 = hecmw_wtime()
2708  !
2709  call prepare_column_info(hecmesh, bt_exp, exp_cols_index, exp_cols_item)
2710  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: prepare column info done'
2711  t1 = hecmw_wtime()
2712  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (3) : ',t1-t0
2713  t0 = hecmw_wtime()
2714  !
2715  call send_bt_exp_and_recv_bt_imp(hecmesh, heccomm, bt_exp, exp_cols_index, exp_cols_item, bt_imp, hecmeshnew)
2716  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: send BT_exp and recv BT_imp done'
2717  t1 = hecmw_wtime()
2718  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (4) : ',t1-t0
2719  t0 = hecmw_wtime()
2720  call free_comm_table(heccomm)
2721  !
2722  call concat_btmat_and_bt_imp(btmat, bt_imp, bt_all)
2723  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: concat BTmat and BT_imp into BT_all done'
2724  t1 = hecmw_wtime()
2725  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (5) : ',t1-t0
2726  t0 = hecmw_wtime()
2727  call hecmw_localmat_free(bt_imp)
2728  !
2729  call multiply_mat_mat(bkmat, bt_all, bktmat)
2730  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: multiply BKmat and BT_all into BKTmat done'
2731  t1 = hecmw_wtime()
2732  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (6) : ',t1-t0
2733  t0 = hecmw_wtime()
2734  call hecmw_localmat_free(bt_all)
2735  !
2736  if (hecmesh%n_neighbor_pe > 0) then
2737  hecmesh%n_node = hecmeshnew%n_node
2738  hecmesh%n_neighbor_pe = hecmeshnew%n_neighbor_pe
2739  deallocate(hecmesh%neighbor_pe)
2740  deallocate(hecmesh%import_index)
2741  deallocate(hecmesh%export_index)
2742  deallocate(hecmesh%import_item)
2743  deallocate(hecmesh%export_item)
2744  deallocate(hecmesh%node_ID)
2745  deallocate(hecmesh%global_node_ID)
2746  hecmesh%neighbor_pe => hecmeshnew%neighbor_pe
2747  hecmesh%import_index => hecmeshnew%import_index
2748  hecmesh%export_index => hecmeshnew%export_index
2749  hecmesh%import_item => hecmeshnew%import_item
2750  hecmesh%export_item => hecmeshnew%export_item
2751  hecmesh%node_ID => hecmeshnew%node_ID
2752  hecmesh%global_node_ID => hecmeshnew%global_node_ID
2753  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: update hecMESH done'
2754  t1 = hecmw_wtime()
2755  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat (7) : ',t1-t0
2756  endif
2757  else
2758  call multiply_mat_mat(bkmat, btmat, bktmat)
2759  if (debug >= 1) write(0,*) 'DEBUG: hecmw_localmat_multmat: multiply BKmat and BTmat into BKTmat done'
2760  t1 = hecmw_wtime()
2761  if (timer >= 2) write(0,'(A,f10.4)') '##### hecmw_localmat_multmat : ',t1-t0
2762  endif
2763  end subroutine hecmw_localmat_multmat
2764 
2765  subroutine make_comm_table(BKmat, hecMESH, hecCOMM)
2766  use m_hecmw_comm_f
2767  implicit none
2768  type (hecmwst_local_matrix), intent(in) :: bkmat
2769  type (hecmwst_local_mesh), intent(in) :: hecmesh
2770  type (hecmwst_matrix_comm), intent(out) :: heccomm
2771  integer(kind=kint) :: nn_int, nn_ext, nnb, i, icol, irank, idom, idx, n_send, tag, js, je, len
2772  integer(kind=kint), allocatable :: is_nz_col(:), imp_cnt(:), exp_cnt(:), import_item_remote(:)
2773  integer(kind=kint), allocatable :: requests(:), statuses(:,:)
2774  heccomm%zero = hecmesh%zero
2775  heccomm%HECMW_COMM = hecmesh%MPI_COMM
2776  heccomm%PETOT = hecmesh%PETOT
2777  heccomm%PEsmpTOT = hecmesh%PEsmpTOT
2778  heccomm%my_rank = hecmesh%my_rank
2779  heccomm%errnof = hecmesh%errnof
2780  heccomm%n_subdomain = hecmesh%n_subdomain
2781  heccomm%n_neighbor_pe = hecmesh%n_neighbor_pe
2782  allocate(heccomm%neighbor_pe(heccomm%n_neighbor_pe))
2783  heccomm%neighbor_pe(:) = hecmesh%neighbor_pe(:)
2784  !
2785  nn_int = hecmesh%nn_internal
2786  nn_ext = hecmesh%n_node - hecmesh%nn_internal
2787  nnb = heccomm%n_neighbor_pe
2788  !
2789  ! check_external_nz_cols (by profile (not number))
2790  allocate(is_nz_col(nn_ext))
2791  is_nz_col(:) = 0
2792  do i = 1, bkmat%index(nn_int)
2793  icol = bkmat%item(i)
2794  if (icol > nn_int) is_nz_col(icol - nn_int) = 1
2795  enddo
2796  !
2797  ! count_nz_cols_per_rank
2798  allocate(imp_cnt(nnb))
2799  imp_cnt(:) = 0
2800  do i = 1, nn_ext
2801  if (is_nz_col(i) == 1) then
2802  irank = hecmesh%node_ID(2*(nn_int+i))
2803  call rank_to_idom(hecmesh, irank, idom)
2804  imp_cnt(idom) = imp_cnt(idom) + 1
2805  endif
2806  enddo
2807  if (debug >= 3) write(0,*) ' DEBUG3: imp_cnt',imp_cnt(:)
2808  !
2809  ! make_index
2810  allocate(heccomm%import_index(0:nnb))
2811  call make_index(nnb, imp_cnt, heccomm%import_index)
2812  if (debug >= 3) write(0,*) ' DEBUG3: import_index',heccomm%import_index(:)
2813  !
2814  ! fill item
2815  allocate(heccomm%import_item(heccomm%import_index(nnb)))
2816  imp_cnt(:) = 0
2817  do i = 1, nn_ext
2818  if (is_nz_col(i) == 1) then
2819  irank = hecmesh%node_ID(2*(nn_int+i))
2820  call rank_to_idom(hecmesh, irank, idom)
2821  imp_cnt(idom) = imp_cnt(idom) + 1
2822  idx = heccomm%import_index(idom-1)+imp_cnt(idom)
2823  heccomm%import_item(idx) = nn_int+i
2824  endif
2825  enddo
2826  if (debug >= 3) write(0,*) ' DEBUG3: import_item',heccomm%import_item(:)
2827  !
2828  allocate(import_item_remote(heccomm%import_index(nnb)))
2829  do i = 1, heccomm%import_index(nnb)
2830  import_item_remote(i) = hecmesh%node_ID(2*heccomm%import_item(i)-1)
2831  enddo
2832  if (debug >= 3) write(0,*) ' DEBUG3: import_item_remote',import_item_remote(:)
2833  !
2834  allocate(requests(2*nnb))
2835  allocate(statuses(hecmw_status_size, 2*nnb))
2836  !
2837  ! send/recv
2838  n_send = 0
2839  do idom = 1, nnb
2840  irank = heccomm%neighbor_pe(idom)
2841  n_send = n_send + 1
2842  tag = 6001
2843  call hecmw_isend_int(imp_cnt(idom), 1, irank, tag, heccomm%HECMW_COMM, requests(n_send))
2844  if (imp_cnt(idom) > 0) then
2845  js = heccomm%import_index(idom-1)+1
2846  je = heccomm%import_index(idom)
2847  len = je-js+1
2848  n_send = n_send + 1
2849  tag = 6002
2850  call hecmw_isend_int(import_item_remote(js:je), len, irank, tag, &
2851  heccomm%HECMW_COMM, requests(n_send))
2852  endif
2853  enddo
2854  !
2855  ! index
2856  allocate(exp_cnt(nnb))
2857  do idom = 1, nnb
2858  irank = heccomm%neighbor_pe(idom)
2859  tag = 6001
2860  call hecmw_recv_int(exp_cnt(idom), 1, irank, tag, heccomm%HECMW_COMM, statuses(:,1))
2861  enddo
2862  allocate(heccomm%export_index(0:nnb))
2863  call make_index(nnb, exp_cnt, heccomm%export_index)
2864  if (debug >= 3) write(0,*) ' DEBUG3: export_index',heccomm%export_index(:)
2865  !
2866  ! item
2867  allocate(heccomm%export_item(heccomm%export_index(nnb)))
2868  do idom = 1, nnb
2869  if (exp_cnt(idom) <= 0) cycle
2870  irank = heccomm%neighbor_pe(idom)
2871  js = heccomm%export_index(idom-1)+1
2872  je = heccomm%export_index(idom)
2873  len = je-js+1
2874  tag = 6002
2875  call hecmw_recv_int(heccomm%export_item(js:je), len, irank, tag, &
2876  heccomm%HECMW_COMM, statuses(:,1))
2877  enddo
2878  if (debug >= 3) write(0,*) ' DEBUG3: export_item',heccomm%export_item(:)
2879  call hecmw_waitall(n_send, requests, statuses)
2880  !
2881  deallocate(imp_cnt)
2882  deallocate(exp_cnt)
2883  deallocate(import_item_remote)
2884  end subroutine make_comm_table
2885 
2886  subroutine free_comm_table(hecCOMM)
2887  implicit none
2888  type (hecmwST_matrix_comm), intent(inout) :: hecCOMM
2889  deallocate(heccomm%neighbor_pe)
2890  deallocate(heccomm%import_index)
2891  deallocate(heccomm%import_item)
2892  deallocate(heccomm%export_index)
2893  deallocate(heccomm%export_item)
2894  end subroutine free_comm_table
2895 
2896  subroutine extract_bt_exp(BTmat, hecCOMM, BT_exp)
2897  implicit none
2898  type (hecmwST_local_matrix), intent(in) :: BTmat
2899  type (hecmwST_matrix_comm), intent(in) :: hecCOMM
2900  type (hecmwST_local_matrix), allocatable, intent(out) :: BT_exp(:)
2901  integer(kind=kint) :: ndof, ndof2, idom, idx_0, idx_n, j, jrow, nnz_row, idx, ks, ke, k
2902  if (heccomm%n_neighbor_pe == 0) return
2903  allocate(bt_exp(heccomm%n_neighbor_pe))
2904  ndof = btmat%ndof
2905  ndof2 = ndof * ndof
2906  do idom = 1, heccomm%n_neighbor_pe
2907  idx_0 = heccomm%export_index(idom-1)
2908  idx_n = heccomm%export_index(idom)
2909  bt_exp(idom)%nr = idx_n - idx_0
2910  bt_exp(idom)%nc = btmat%nc
2911  bt_exp(idom)%nnz = 0
2912  bt_exp(idom)%ndof = ndof
2913  allocate(bt_exp(idom)%index(0:bt_exp(idom)%nr))
2914  bt_exp(idom)%index(0) = 0
2915  do j = 1, bt_exp(idom)%nr
2916  jrow = heccomm%export_item(idx_0 + j)
2917  nnz_row = btmat%index(jrow) - btmat%index(jrow-1)
2918  bt_exp(idom)%index(j) = bt_exp(idom)%index(j-1) + nnz_row
2919  enddo
2920  bt_exp(idom)%nnz = bt_exp(idom)%index(bt_exp(idom)%nr)
2921  allocate(bt_exp(idom)%item(bt_exp(idom)%nnz))
2922  allocate(bt_exp(idom)%A(ndof2 * bt_exp(idom)%nnz))
2923  idx = 0
2924  do j = 1, bt_exp(idom)%nr
2925  jrow = heccomm%export_item(idx_0 + j)
2926  ks = btmat%index(jrow-1) + 1
2927  ke = btmat%index(jrow)
2928  do k = ks, ke
2929  idx = idx + 1
2930  bt_exp(idom)%item(idx) = btmat%item(k)
2931  bt_exp(idom)%A(ndof2*(idx-1)+1:ndof2*idx) = btmat%A(ndof2*(k-1)+1:ndof2*k)
2932  enddo
2933  if (idx /= bt_exp(idom)%index(j)) stop 'ERROR: extract BT_exp'
2934  enddo
2935  enddo
2936  end subroutine extract_bt_exp
2937 
2938  subroutine send_bt_exp_and_recv_bt_imp(hecMESH, hecCOMM, BT_exp, exp_cols_index, exp_cols_item, BT_imp, hecMESHnew)
2939  use m_hecmw_comm_f
2940  implicit none
2941  type (hecmwST_local_mesh), intent(in) :: hecMESH
2942  type (hecmwST_matrix_comm), intent(in) :: hecCOMM
2943  type (hecmwST_local_matrix), allocatable, intent(inout) :: BT_exp(:)
2944  integer(kind=kint), allocatable, intent(inout) :: exp_cols_index(:)
2945  integer(kind=kint), allocatable, intent(inout) :: exp_cols_item(:,:)
2946  type (hecmwST_local_matrix), intent(out) :: BT_imp
2947  type (hecmwST_local_mesh), intent(inout) :: hecMESHnew
2948  integer(kind=kint), allocatable :: nnz_imp(:), cnt(:), index_imp(:)
2949  integer(kind=kint), allocatable :: imp_cols_index(:)
2950  integer(kind=kint), allocatable :: imp_cols_item(:,:)
2951  real(kind=kreal), allocatable :: imp_vals_item(:)
2952  integer(kind=kint) :: nnb, ndof, ndof2, idom, irank, nr, n_send, tag, idx_0, idx_n, j, jj, nnz
2953  integer(kind=kint), allocatable :: requests(:)
2954  integer(kind=kint), allocatable :: statuses(:,:)
2955  integer(kind=kint), allocatable :: map(:), add_nodes(:,:)
2956  integer(kind=kint) :: n_add_node, i0
2957  nnb = heccomm%n_neighbor_pe
2958  if (nnb == 0) then
2959  bt_imp%nr = 0
2960  bt_imp%nc = 0
2961  bt_imp%nnz = 0
2962  bt_imp%ndof = 0
2963  allocate(bt_imp%index(0:0))
2964  bt_imp%index(0) = 0
2965  return
2966  endif
2967  ndof = bt_exp(1)%ndof
2968  ndof2 = ndof*ndof
2969  allocate(requests(nnb*3))
2970  allocate(statuses(hecmw_status_size, nnb*3))
2971  n_send = 0
2972  do idom = 1, nnb
2973  irank = heccomm%neighbor_pe(idom)
2974  nr = bt_exp(idom)%nr
2975  if (nr == 0) cycle
2976  n_send = n_send + 1
2977  tag = 3001
2978  call hecmw_isend_int(bt_exp(idom)%index(0:bt_exp(idom)%nr), bt_exp(idom)%nr + 1, &
2979  irank, tag, heccomm%HECMW_COMM, requests(n_send))
2980  if (bt_exp(idom)%nnz == 0) cycle
2981  n_send = n_send + 1
2982  tag = 3002
2983  call hecmw_isend_int(exp_cols_item(1,exp_cols_index(idom-1)+1), &
2984  cncol_item * bt_exp(idom)%nnz, irank, tag, heccomm%HECMW_COMM, requests(n_send))
2985  n_send = n_send + 1
2986  tag = 3003
2987  call hecmw_isend_r(bt_exp(idom)%A, ndof2 * bt_exp(idom)%nnz, &
2988  irank, tag, heccomm%HECMW_COMM, requests(n_send))
2989  enddo
2990  !
2991  ! BT_imp%nr = hecCOMM%import_index(nnb)
2992  bt_imp%nr = hecmesh%n_node - hecmesh%nn_internal
2993  bt_imp%nc = 0 !!! TEMPORARY
2994  bt_imp%nnz = 0
2995  bt_imp%ndof = ndof
2996  !
2997  allocate(nnz_imp(nnb))
2998  allocate(cnt(bt_imp%nr))
2999  !
3000  cnt(:) = 0
3001  do idom = 1, nnb
3002  irank = heccomm%neighbor_pe(idom)
3003  idx_0 = heccomm%import_index(idom-1)
3004  idx_n = heccomm%import_index(idom)
3005  nr = idx_n - idx_0
3006  if (nr == 0) then
3007  nnz_imp(idom) = 0
3008  cycle
3009  endif
3010  allocate(index_imp(0:nr))
3011  tag = 3001
3012  call hecmw_recv_int(index_imp(0:nr), nr+1, irank, tag, &
3013  heccomm%HECMW_COMM, statuses(:,1))
3014  nnz_imp(idom) = index_imp(nr)
3015  do j = 1, nr
3016  jj = heccomm%import_item(idx_0 + j) - hecmesh%nn_internal
3017  if (jj < 1 .or. bt_imp%nr < jj) stop 'ERROR: jj out of range'
3018  if (cnt(jj) /= 0) stop import rows?'
3019  cnt(jj) = index_imp(j) - index_imp(j-1)
3020  enddo
3021  deallocate(index_imp)
3022  enddo
3023  !
3024  allocate(imp_cols_index(0:nnb))
3025  call make_index(nnb, nnz_imp, imp_cols_index)
3026  deallocate(nnz_imp)
3027  !
3028  allocate(BT_imp%index(0:BT_imp%nr))
3029  call make_index(BT_imp%nr, cnt, BT_imp%index)
3030  deallocate(cnt)
3031  !
3032  BT_imp%nnz = BT_imp%index(BT_imp%nr)
3033  if (BT_imp%nnz /= imp_cols_index(nnb)) &
3034  stop 'error: total num of nonzero of bt_imp'
3035  !
3036  allocate(imp_cols_item(cNCOL_ITEM, BT_imp%nnz))
3037  allocate(imp_vals_item(ndof2 * BT_imp%nnz))
3038  !
3039  do idom = 1, nnb
3040  irank = hecCOMM%neighbor_pe(idom)
3041  idx_0 = imp_cols_index(idom-1)
3042  idx_n = imp_cols_index(idom)
3043  nnz = idx_n - idx_0
3044  if (nnz == 0) cycle
3045  tag = 3002
3046  call HECMW_RECV_INT(imp_cols_item(1, idx_0 + 1), cNCOL_ITEM * nnz, &
3047  irank, tag, hecCOMM%HECMW_COMM, statuses(:,1))
3048  tag = 3003
3049  call HECMW_RECV_R(imp_vals_item(ndof2*idx_0 + 1), ndof2 * nnz, &
3050  irank, tag, hecCOMM%HECMW_COMM, statuses(:,1))
3051  enddo
3052  call HECMW_Waitall(n_send, requests, statuses)
3053  if (DEBUG >= 2) write(0,*) ' debug2: send bt_imp and recv into temporary data done'
3054  !
3055  deallocate(requests)
3056  deallocate(statuses)
3057  !
3058  do idom = 1, nnb
3059  call hecmw_localmat_free(BT_exp(idom))
3060  enddo
3061  deallocate(BT_exp)
3062  deallocate(exp_cols_index)
3063  deallocate(exp_cols_item)
3064  !
3065  call copy_mesh(hecMESH, hecMESHnew)
3066  !
3067  call map_imported_cols(hecMESHnew, imp_cols_index(nnb), imp_cols_item, n_add_node, add_nodes, map, i0)
3068  if (DEBUG >= 2) write(0,*) ' debug2: map imported cols done'
3069  !
3070  call update_comm_table(hecMESHnew, n_add_node, add_nodes, i0)
3071  if (DEBUG >= 2) write(0,*) ' debug2: update comm_table done'
3072  !
3073  BT_imp%nc = hecMESHnew%n_node
3074  !
3075  allocate(BT_imp%item(BT_imp%nnz))
3076  allocate(BT_imp%A(ndof2 * BT_imp%nnz))
3077  call copy_vals_to_BT_imp(hecCOMM, hecMESH%nn_internal, imp_cols_index, map, imp_vals_item, BT_imp)
3078  if (DEBUG >= 2) write(0,*) ' debug2: copy vals to bt_imp done'
3079  !
3080  deallocate(imp_cols_index)
3081  deallocate(imp_cols_item)
3082  deallocate(imp_vals_item)
3083  deallocate(map)
3084  end subroutine send_BT_exp_and_recv_BT_imp
3085 
3086  subroutine copy_vals_to_BT_imp(hecCOMM, nn_internal, imp_cols_index, map, imp_vals_item, BT_imp)
3087  implicit none
3088  type (hecmwST_matrix_comm), intent(in) :: hecCOMM
3089  integer(kind=kint), intent(in) :: nn_internal
3090  integer(kind=kint), allocatable, intent(in) :: imp_cols_index(:)
3091  integer(kind=kint), intent(in) :: map(:)
3092  real(kind=kreal), intent(in) :: imp_vals_item(:)
3093  type (hecmwST_local_matrix), intent(inout) :: BT_imp
3094  integer(kind=kint) :: nnb, ndof2, idx, idom, idx_0, idx_n, nr, j, jrow, ks, ke, k
3095  nnb = hecCOMM%n_neighbor_pe
3096  ndof2 = BT_imp%ndof ** 2
3097  idx = 0
3098  do idom = 1, nnb
3099  idx_0 = hecCOMM%import_index(idom-1)
3100  idx_n = hecCOMM%import_index(idom)
3101  nr = idx_n - idx_0
3102  if (nr == 0) cycle
3103  do j = 1, nr
3104  jrow = hecCOMM%import_item(idx_0 + j) - nn_internal
3105  ks = BT_imp%index(jrow-1)+1
3106  ke = BT_imp%index(jrow)
3107  do k = ks, ke
3108  idx = idx + 1
3109  BT_imp%item(k) = map(idx)
3110  BT_imp%A(ndof2*(k-1)+1:ndof2*k) = imp_vals_item(ndof2*(idx-1)+1:ndof2*idx)
3111  enddo
3112  enddo
3113  if (idx /= imp_cols_index(idom)) stop 'error: copy vals to bt_imp'
3114  enddo
3115  end subroutine copy_vals_to_BT_imp
3116 
3117  subroutine concat_BTmat_and_BT_imp(BTmat, BT_imp, BT_all)
3118  implicit none
3119  type (hecmwST_local_matrix), intent(in) :: BTmat
3120  type (hecmwST_local_matrix), intent(in) :: BT_imp
3121  type (hecmwST_local_matrix), intent(out) :: BT_all
3122  integer(kind=kint) :: ndof, ndof2, i, ii
3123  ndof = BTmat%ndof
3124 .and. if (BT_imp%nr > 0 BT_imp%ndof /= ndof) stop 'error: concat btmat and bt_imp: ndof'
3125  ndof2 = ndof*ndof
3126  BT_all%nr = BTmat%nr + BT_imp%nr
3127  BT_all%nc = max(BTmat%nc, BT_imp%nc)
3128  BT_all%nnz = BTmat%nnz + BT_imp%nnz
3129  BT_all%ndof = ndof
3130  allocate(BT_all%index(0:BT_all%nr))
3131  allocate(BT_all%item(BT_all%nnz))
3132  allocate(BT_all%A(ndof2 * BT_all%nnz))
3133  BT_all%index(0) = 0
3134  do i = 1, BTmat%nr
3135  BT_all%index(i) = BTmat%index(i)
3136  enddo
3137  do i = 1, BT_imp%nr
3138  BT_all%index(BTmat%nr+i) = BT_all%index(BTmat%nr+i-1) + &
3139  BT_imp%index(i) - BT_imp%index(i-1)
3140  enddo
3141  do i = 1, BTmat%nnz
3142  BT_all%item(i) = BTmat%item(i)
3143  BT_all%A(ndof2*(i-1)+1:ndof2*i) = BTmat%A(ndof2*(i-1)+1:ndof2*i)
3144  enddo
3145  do i = 1, BT_imp%nnz
3146  ii = BTmat%nnz + i
3147  BT_all%item(ii) = BT_imp%item(i)
3148  BT_all%A(ndof2*(ii-1)+1:ndof2*ii) = BT_imp%A(ndof2*(i-1)+1:ndof2*i)
3149  enddo
3150  end subroutine concat_BTmat_and_BT_imp
3151 
3152  subroutine multiply_mat_mat(Amat, Bmat, Cmat)
3153  implicit none
3154  type (hecmwST_local_matrix), intent(in) :: Amat
3155  type (hecmwST_local_matrix), intent(in) :: Bmat
3156  type (hecmwST_local_matrix), intent(out) :: Cmat
3157  integer(kind=kint) :: ndof, ndof2, nr, nc, nnz, i, icnt
3158  integer(kind=kint) :: js, je, j, jj, ks, ke, k, kk, l, ll, l0
3159  integer(kind=kint), allocatable :: iw(:)
3160  real(kind=kreal), pointer :: Ap(:), Bp(:), Cp(:)
3161  real(kind=kreal) :: t0, t1
3162  t0 = hecmw_wtime()
3163  if (Amat%ndof /= Bmat%ndof) stop 'error: multiply_mat_mat: unmatching ndof'
3164  ndof = Amat%ndof
3165  ndof2 = ndof*ndof
3166  nr = Amat%nr
3167  nc = Bmat%nc
3168  if (Amat%nc /= Bmat%nr) then
3169  write(0,*) 'amat: nr, nc = ', Amat%nr, Amat%nc
3170  write(0,*) 'bmat: nr, nc = ', Bmat%nr, Bmat%nc
3171  stop 'error: multiply_mat_mat: unmatching size'
3172  endif
3173  Cmat%ndof = ndof
3174  Cmat%nr = nr
3175  Cmat%nc = nc
3176  allocate(Cmat%index(0:nr))
3177  Cmat%index(0) = 0
3178  !$omp parallel default(none), &
3179  !$omp& private(iw,i,icnt,js,je,j,jj,ks,ke,k,kk,l), &
3180  !$omp& shared(nr,nc,Amat,Bmat,Cmat)
3181  allocate(iw(nc))
3182  !$omp do
3183  do i = 1, nr
3184  icnt = 0
3185  js = Amat%index(i-1)+1
3186  je = Amat%index(i)
3187  do j = js, je
3188  jj = Amat%item(j)
3189  ks = Bmat%index(jj-1)+1
3190  ke = Bmat%index(jj)
3191  kl1: do k = ks, ke
3192  kk = Bmat%item(k)
3193  do l = 1, icnt
3194  if (iw(l) == kk) cycle kl1
3195  enddo
3196  icnt = icnt + 1
3197  iw(icnt) = kk
3198  enddo kl1
3199  enddo
3200  Cmat%index(i) = icnt
3201  enddo
3202  !$omp end do
3203  deallocate(iw)
3204  !$omp end parallel
3205  do i = 1, nr
3206  Cmat%index(i) = Cmat%index(i-1) + Cmat%index(i)
3207  enddo
3208  nnz = Cmat%index(nr)
3209  Cmat%nnz = nnz
3210  !write(0,*) 'nnz',nnz
3211  t1 = hecmw_wtime()
3212  if (TIMER >= 3) write(0, '(a,f10.4)') "###### multiply_mat_mat (1) : ",t1-t0
3213  t0 = hecmw_wtime()
3214  allocate(Cmat%item(nnz))
3215  allocate(Cmat%A(ndof2 * nnz))
3216  Cmat%A(:) = 0.0d0
3217  !$omp parallel default(none), &
3218  !$omp& private(i,icnt,l0,js,je,j,jj,Ap,ks,ke,k,kk,Bp,ll,l,Cp), &
3219  !$omp& shared(nr,Cmat,Amat,Bmat,ndof2,ndof)
3220  !$omp do
3221  do i = 1, nr
3222  icnt = 0
3223  l0 = Cmat%index(i-1)
3224  ! item
3225  js = Amat%index(i-1)+1
3226  je = Amat%index(i)
3227  do j = js, je
3228  jj = Amat%item(j)
3229  Ap => Amat%A(ndof2*(j-1)+1:ndof2*j)
3230  ks = Bmat%index(jj-1)+1
3231  ke = Bmat%index(jj)
3232  do k = ks, ke
3233  kk = Bmat%item(k)
3234  Bp => Bmat%A(ndof2*(k-1)+1:ndof2*k)
3235  ll = -1
3236  do l = 1, icnt
3237  if (Cmat%item(l0+l) == kk) then
3238  ll = l0 + l
3239  exit
3240  endif
3241  enddo
3242  if (ll < 0) then
3243  icnt = icnt + 1
3244  ll = l0 + icnt
3245  Cmat%item(ll) = kk
3246  endif
3247  Cp => Cmat%A(ndof2*(ll-1)+1:ndof2*ll)
3248  call blk_matmul_add(ndof, Ap, Bp, Cp)
3249  enddo
3250  enddo
3251  !write(0,*) 'l0,icnt,index(i)',Cmat%index(i-1),icnt,Cmat%index(i)
3252  if (l0+icnt /= Cmat%index(i)) stop 'error: multiply_mat_mat: unknown error'
3253  enddo
3254  !$omp end do
3255  !$omp end parallel
3256  t1 = hecmw_wtime()
3257  if (TIMER >= 3) write(0, '(a,f10.4)') "###### multiply_mat_mat (2) : ",t1-t0
3258  t0 = hecmw_wtime()
3259  call sort_and_uniq_rows(Cmat)
3260  t1 = hecmw_wtime()
3261  if (TIMER >= 3) write(0, '(a,f10.4)') "###### multiply_mat_mat (3) : ",t1-t0
3262  end subroutine multiply_mat_mat
3263 
3264  subroutine blk_matmul_add(ndof, A, B, AB)
3265  implicit none
3266  integer, intent(in) :: ndof
3267  real(kind=kreal), intent(in) :: A(:), B(:)
3268  real(kind=kreal), intent(inout) :: AB(:)
3269  integer :: ndof2, i, j, k, i0, j0, ij, ik, jk
3270  ndof2=ndof*ndof
3271  do i=1,ndof
3272  i0=(i-1)*ndof
3273  do j=1,ndof
3274  ij=i0+j
3275  j0=(j-1)*ndof
3276  do k=1,ndof
3277  ik=i0+k
3278  jk=j0+k
3279  !$omp atomic
3280  AB(ik)=AB(ik)+A(ij)*B(jk)
3281  enddo
3282  enddo
3283  enddo
3284  end subroutine blk_matmul_add
3285 
3286  subroutine hecmw_localmat_make_hecmat(hecMAT, BTtKTmat, hecTKT)
3287  implicit none
3288  type (hecmwST_matrix), intent(in) :: hecMAT
3289  type (hecmwST_local_matrix), intent(in) :: BTtKTmat
3290  type (hecmwST_matrix), intent(inout) :: hecTKT
3291  call make_new_hecmat(hecMAT, BTtKTmat, hecTKT)
3292  end subroutine hecmw_localmat_make_hecmat
3293 
3294  !> \brief Debug write matrix
3295  !>
3296  subroutine debug_write_matrix(Mat, label, level)
3297  type(hecmwST_local_matrix), intent(in) :: Mat !< matrix
3298  character(len=*), intent(in) :: label !< label for matrix
3299  integer(kind=kint), intent(in) :: level !< debug level
3300  !
3301  integer(kind=kint) :: iunit
3302 
3303  if (level <= 0) return
3304 
3305  iunit = 700 + hecmw_comm_get_rank()
3306  write(iunit,'(a,a)') trim(label),'============================================================'
3307  if (level == 1) then
3308  call hecmw_localmat_write_size(Mat, iunit)
3309  else if (level == 2) then
3310  call hecmw_localmat_write_ij(Mat, iunit)
3311  else
3312  call hecmw_localmat_write(Mat, iunit)
3313  endif
3314  end subroutine debug_write_matrix
3315 
3316 end module hecmw_local_matrix
subroutine, public hecmw_bsearch_int_array(array, istart, iend, val, idx)
recursive subroutine, public hecmw_qsort_int_array(array, istart, iend)
subroutine, public hecmw_uniq_int_array(array, istart, iend, ndup)
subroutine, public hecmw_localmat_init_with_hecmat(BKmat, hecMAT, num_lagrange)
subroutine trimatmul_ttkt(BTtmat, hecMAT, BTmat, BTtKT)
subroutine, public hecmw_trimatmul_ttkt(hecMESH, BTtmat, hecMAT, BTmat, iwS, num_lagrange, hecTKT)
subroutine, public hecmw_localmat_free(Tmat)
subroutine allocate_bt_int(hecMESH, ndof, imp_rows_index, imp_rows_item, BT_int)
subroutine, public hecmw_localmat_add(Amat, Bmat, Cmat)
subroutine count_new_comm_nodes(npe, org_nnb, org_nbpe, org_index, n_add, n_new)
subroutine, public hecmw_localmat_transpose(Tmat, Ttmat)
subroutine free_comm_table(hecCOMM)
subroutine, public hecmw_localmat_multmat(BKmat, BTmat, hecMESH, BKTmat)
subroutine send_recv_bt_ext_contents(hecMESH, BT_ext, exp_rows_index, exp_cols_index, exp_rows_item, exp_cols_item, imp_rows_index, imp_cols_index, imp_rows_item, imp_cols_item, imp_vals_item)
subroutine, public hecmw_localmat_mulvec(BTmat, V, TV)
subroutine count_add_imp_per_rank(n_add_node, add_nodes, npe, n_add_imp)
subroutine hecmw_trimatmul_ttkt_parallel(hecMESH, BTtmat, hecMAT, BTmat, iwS, num_lagrange, hecTKT)
subroutine, public hecmw_localmat_write(Tmat, iunit)
subroutine, public hecmw_localmat_blocking(Tmat, ndof, BTmat)
subroutine, public hecmw_localmat_make_hecmat(hecMAT, BTtKTmat, hecTKT)
subroutine, public hecmw_trimatmul_ttkt_serial(hecMESH, BTtmat, hecMAT, BTmat, iwS, num_lagrange, hecTKT)
subroutine, public hecmw_trimatmul_ttkt_mpc(hecMESH, hecMAT, hecTKT)
subroutine, public hecmw_localmat_assemble(BTmat, hecMESH, hecMESHnew)
subroutine, public hecmw_localmat_add_hecmat(BKmat, hecMAT)
subroutine, public hecmw_pair_array_append(parray, id, i1, i2)
subroutine, public hecmw_pair_array_finalize(parray)
integer(kind=kint) function, public hecmw_pair_array_find_id(parray, i1, i2)
subroutine, public hecmw_pair_array_init(parray, max_num)
subroutine, public hecmw_pair_array_sort(parray)
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=4), parameter kreal
integer(kind=kint), parameter hecmw_status_size
integer(kind=kint) function hecmw_comm_get_rank()
real(kind=kreal) function hecmw_wtime()
subroutine hecmw_isend_int(sbuf, sc, dest, tag, comm, req)
subroutine hecmw_recv_int(rbuf, rc, source, tag, comm, stat)
subroutine hecmw_isend_r(sbuf, sc, dest, tag, comm, req)
subroutine hecmw_waitall(cnt, reqs, stats)
subroutine hecmw_recv_r(rbuf, rc, source, tag, comm, stat)
subroutine hecmw_alltoall_int(sbuf, sc, rbuf, rc, comm)