FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
solve_LINEQ_contact_elim.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 !-------------------------------------------------------------------------------
8  use hecmw_util
11  use hecmw_solver
13  use m_hecmw_comm_f
17  use hecmw_ebc_defer
18 
19  implicit none
20 
21  private
23  public :: solve_lineq_contact_elim
24 
25  logical, save :: INITIALIZED = .false.
26  integer, save :: SymType = 0
27 
28  ! Structure signature of the previously solved system. The converted system
29  ! (hecTKT) is rebuilt from scratch every call, and its sparsity/halo (even NP)
30  ! changes when the contact state changes -- that is a STRUCTURE change, but this
31  ! path historically raised only Iarray(97) ("values changed"). Preconditioners
32  ! that cache structure across solves under the Iarray(98)/(97) recycling contract
33  ! (e.g. SA-AMG) then reuse a stale hierarchy (observed: out-of-bounds fine matvec
34  ! / heap corruption on mobile_case np=8). We therefore compare the structure
35  ! (sizes + pattern hash) against the previous call and raise Iarray(98) when it
36  ! differs. The verdict is allreduced so every rank takes the same setup path
37  ! (refresh and rebuild have different collective patterns -> a per-rank decision
38  ! deadlocks). PREV_BRANCH additionally forces a rebuild when switching between
39  ! the contact (hecTKT) and no-contact (hecMAT) branches, which solve different
40  ! matrix objects.
41  integer(kind=kint), save :: PREV_SIG(4) = -1
42  integer(kind=8), save :: PREV_HASH = 0
43  integer(kind=kint), save :: PREV_BRANCH = 0
44 
45  integer, parameter :: DEBUG = 0 ! 0: no message, 1: some messages, 2: more messages, 3: even more messages
46  logical, parameter :: DEBUG_VECTOR = .false.
47  logical, parameter :: DEBUG_MATRIX = .false.
48 
49 contains
50 
51  subroutine solve_lineq_contact_elim_init(hecMESH, hecMAT, hecLagMAT, is_sym)
52  type(hecmwst_local_mesh), intent(in) :: hecmesh
53  type(hecmwst_matrix), intent(inout) :: hecmat
54  type(hecmwst_matrix_lagrange), intent(in) :: heclagmat
55  logical, intent(in) :: is_sym
56 
57  if (initialized) then
58  initialized = .false.
59  endif
60 
61  hecmat%Iarray(98) = 1
62  hecmat%Iarray(97) = 1
63  prev_sig = -1; prev_hash = 0; prev_branch = 0
64 
65  if (is_sym) then
66  symtype = 1
67  else
68  symtype = 0
69  endif
70 
71  initialized = .true.
72  end subroutine solve_lineq_contact_elim_init
73 
74  subroutine solve_lineq_contact_elim(hecMESH, hecMAT, hecLagMAT, hecEBC, istat, conMAT, is_contact_active)
75  type(hecmwst_local_mesh), intent(inout) :: hecmesh
76  type(hecmwst_matrix), intent(inout) :: hecmat
77  type(hecmwst_matrix_lagrange), intent(inout) :: heclagmat
78  type(hecmwst_ebc), intent(inout) :: hecebc
79  integer(kind=kint), intent(out) :: istat
80  type(hecmwst_matrix), intent(in) :: conmat
81  logical, intent(in) :: is_contact_active
82  !
83  integer(kind=kint) :: solver_type, method_org
84  integer(kind=kint) :: is_contact
85  integer(kind=kint) :: myrank
86 
87  myrank = hecmw_comm_get_rank()
88 
89  hecmat%Iarray(97) = 1
90 
91  is_contact = 0
92  if (is_contact_active) is_contact = 1
93  call hecmw_allreduce_i1(hecmesh, is_contact, hecmw_max)
94 
95  if (is_contact == 0) then
96  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: no contact'
97  ! switching from the contact branch: the previously solved system was hecTKT
98  ! (different structure) -> report a structure change (is_contact is already
99  ! allreduced, so this decision is rank-uniform)
100  if (prev_branch /= 1) hecmat%Iarray(98) = 1
101  prev_branch = 1
102  solver_type = hecmw_mat_get_solver_type(hecmat)
103  if (solver_type == 1 .and. symtype == 1) then
104  ! use CG because the matrix is symmetric
105  method_org = hecmw_mat_get_method(hecmat)
106  call hecmw_mat_set_method(hecmat, 1)
107  endif
108  ! solve
109  call solve_with_mpc(hecmesh, hecmat, hecebc)
110  if (solver_type == 1 .and. symtype == 1) then
111  ! restore solver setting
112  call hecmw_mat_set_method(hecmat, method_org)
113  endif
114  else
115  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: with contact'
116  ! switching from the no-contact branch: invalidate the stored signature so the
117  ! first converted system after the switch reports a structure change
118  if (prev_branch /= 2) then; prev_sig = -1; prev_hash = 0; end if
119  prev_branch = 2
120  call solve_eliminate(hecmesh, hecmat, heclagmat, conmat, hecebc)
121  endif
122 
123  istat = hecmw_mat_get_flag_diverged(hecmat)
124  end subroutine solve_lineq_contact_elim
125 
126  subroutine solve_with_mpc(hecMESH, hecMAT, hecEBC)
127  type(hecmwst_local_mesh), intent(inout) :: hecmesh
128  type(hecmwst_matrix), intent(inout) :: hecmat
129  type(hecmwst_ebc), intent(inout) :: hecebc
130  !
131  type (hecmwst_local_mesh), pointer :: hecmeshmpc
132  type (hecmwst_matrix), pointer :: hecmatmpc
133  integer(kind=kint) :: method
134  logical :: fg_cg, fg_amg
135 
136  fg_cg = (hecmw_mat_get_method(hecmat) == 1)
137  fg_amg = (hecmw_mat_get_precond(hecmat) == 5)
138 
139  call hecmw_mpc_mat_init(hecmesh, hecmat, hecmeshmpc, hecmatmpc)
140  call hecmw_mpc_mat_ass(hecmesh, hecmat, hecmeshmpc, hecmatmpc)
141  call hecmw_mpc_trans_rhs(hecmesh, hecmat, hecmatmpc)
142  call hecmw_ebc_apply(hecmeshmpc, hecmatmpc, hecebc)
143  call hecmw_solve(hecmeshmpc,hecmatmpc)
144  if (fg_cg .and. fg_amg .and. hecmw_mat_get_flag_diverged(hecmatmpc) /= 0) then
145  ! avoid ML and retry when diverged
146  call hecmw_mat_set_precond(hecmatmpc, 3) ! set diag-scaling
147  hecmatmpc%Iarray(97:98) = 1
148  hecmatmpc%X(:) = 0.d0
149  call hecmw_solve(hecmeshmpc,hecmatmpc)
150  call hecmw_mat_set_precond(hecmatmpc, 5) ! restore amg
151  endif
152  call hecmw_mpc_tback_sol(hecmesh, hecmat, hecmatmpc)
153  call hecmw_mpc_mat_finalize(hecmesh, hecmat, hecmeshmpc, hecmatmpc)
154  end subroutine solve_with_mpc
155 
160  subroutine notify_structure_change(hecMESH, hecTKT)
161  type(hecmwst_local_mesh), intent(in) :: hecmesh
162  type(hecmwst_matrix), intent(inout) :: hectkt
163  integer(kind=kint) :: sig(4), changed
164  integer(kind=8) :: h
165  sig = (/ hectkt%N, hectkt%NP, hectkt%NPL, hectkt%NPU /)
166  h = pattern_hash(hectkt)
167  changed = 0
168  if (any(sig /= prev_sig) .or. h /= prev_hash) changed = 1
169  call hecmw_allreduce_i1(hecmesh, changed, hecmw_max)
170  if (changed /= 0) hectkt%Iarray(98) = 1
171  prev_sig = sig; prev_hash = h
172  end subroutine notify_structure_change
173 
176  function pattern_hash(hecMAT) result(h)
177  type(hecmwst_matrix), intent(in) :: hecmat
178  integer(kind=8) :: h
179  integer(kind=kint) :: i
180  h = 0_8
181  do i = 0, hecmat%NP
182  h = ieor(ishftc(h, 5), int(hecmat%indexL(i), 8))
183  h = ieor(ishftc(h, 7), int(hecmat%indexU(i), 8))
184  end do
185  do i = 1, hecmat%NPL
186  h = ieor(ishftc(h, 5), int(hecmat%itemL(i), 8))
187  end do
188  do i = 1, hecmat%NPU
189  h = ieor(ishftc(h, 7), int(hecmat%itemU(i), 8))
190  end do
191  end function pattern_hash
192 
195  subroutine solve_eliminate(hecMESH,hecMAT,hecLagMAT,conMAT,hecEBC)
196  type(hecmwst_local_mesh), intent(inout) :: hecmesh
197  type(hecmwst_matrix), intent(inout) :: hecmat
198  type(hecmwst_matrix_lagrange), intent(inout) :: heclagmat
199  type(hecmwst_matrix), intent(in) :: conmat
200  type(hecmwst_ebc), intent(inout) :: hecebc
201  !
202  type(hecmwst_local_mesh) :: hecmeshtmp
203  type (hecmwst_local_mesh), pointer :: hecmeshmpc
204  type (hecmwst_matrix), pointer :: hecmatmpc
205  integer(kind=kint), allocatable :: slaves4lag(:)
206  real(kind=kreal), allocatable :: bls_inv(:)
207  real(kind=kreal), allocatable :: bus_inv(:)
208  type(hecmwst_local_matrix) :: tmat
209  type(hecmwst_local_matrix) :: ttmat
210  integer(kind=kint), allocatable :: slaves(:)
211  type(hecmwst_contact_comm) :: concomm
212  type(hecmwst_local_matrix) :: kmat
213  real(kind=kreal), allocatable :: btot(:)
214  type(hecmwst_matrix) :: hectkt
215  integer(kind=kint) :: ndof
216  integer(kind=kint) :: myrank
217  real(kind=kreal) :: t0, t1, t2
218 
219  myrank = hecmw_comm_get_rank()
220 
221  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: solve_eliminate start'
222  t0 = hecmw_wtime()
223 
224  ndof=hecmat%NDOF
225  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: num_lagrange',heclagmat%num_lagrange
226 
227  call copy_mesh(hecmesh, hecmeshtmp)
228 
229  allocate(slaves4lag(heclagmat%num_lagrange), bls_inv(heclagmat%num_lagrange), &
230  bus_inv(heclagmat%num_lagrange))
231 
232  t1 = hecmw_wtime()
233  call make_transformation_matrices(hecmesh, hecmeshtmp, hecmat, heclagmat, &
234  slaves4lag, bls_inv, bus_inv, slaves, tmat, ttmat)
235  t2 = hecmw_wtime()
236  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: made trans matrices', t2-t1
237 
238  t1 = t2
239  call make_contact_comm_table(hecmesh, hecmat, heclagmat, concomm)
240  t2 = hecmw_wtime()
241  if (debug >= 2) write(0,*) ' DEBUG2: make contact comm_table done', hecmw_wtime()-t1
242 
243  t1 = t2
244  allocate(btot(hecmat%NP*ndof+heclagmat%num_lagrange))
245  call assemble_equation(hecmesh, hecmeshtmp, hecmat, conmat, heclagmat%num_lagrange, &
246  slaves, kmat, btot)
247  t2 = hecmw_wtime()
248  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: assembled equation ', t2-t1
249 
250  if (hecmw_comm_get_size() > 1) then
251  if (kmat%nc /= ttmat%nc) then
252  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: node migrated with Kmat',kmat%nc-ttmat%nc
253  tmat%nc = kmat%nc
254  ttmat%nc = kmat%nc
255  endif
256  endif
257 
258  t1 = t2
259  call convert_equation(hecmeshtmp, hecmat, kmat, tmat, ttmat, btot, slaves, &
260  slaves4lag, bls_inv, concomm, hectkt)
261  t2 = hecmw_wtime()
262  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: converted equation ', t2-t1
263 
264  ! report a structure change to the solver/preconditioner when the converted
265  ! system's structure differs from the previous call (see PREV_SIG)
266  call notify_structure_change(hecmesh, hectkt)
267 
268  ! the converted system inherits the asymmetry of the contact terms (friction);
269  ! direct solvers choose their factorization mode from this flag, which
270  ! hecmw_mat_init defaulted to .true.
271  hectkt%symmetric = (symtype == 1)
272 
273  t1 = t2
274  call solve_with_mpc(hecmeshtmp, hectkt, hecebc)
275  ! the eliminated system hecTKT is what the solver actually saw; carry its
276  ! verdict back to hecMAT so callers can read it without knowing about hecTKT
279  if (debug_vector) call debug_write_vector(hectkt%X, 'Solution(converted)', 'hecTKT%X', ndof, hectkt%N)
280  t2 = hecmw_wtime()
281  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: linear solver done ', t2-t1
282 
283  t1 = t2
284  call recover_solution(hecmeshtmp, hecmat, hectkt, tmat, kmat, btot, &
285  slaves4lag, bls_inv, bus_inv, concomm, slaves)
286  t2 = hecmw_wtime()
287  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: recovered solution ', t2-t1
288 
289  if (debug >= 1) call check_solution(hecmesh, hecmeshtmp, hecmat, hectkt, heclagmat, kmat, btot, &
290  concomm, slaves)
291  if (debug >= 2) call check_solution2(hecmesh, hecmat, conmat, heclagmat, concomm, slaves)
292 
293  call hecmw_localmat_free(tmat)
294  call hecmw_localmat_free(ttmat)
295  call hecmw_mat_finalize(hectkt)
296  call hecmw_localmat_free(kmat)
297  call hecmw_contact_comm_finalize(concomm)
298  call free_mesh(hecmeshtmp)
299  deallocate(slaves4lag)
300  t2 = hecmw_wtime()
301  if ((debug >= 1 .and. myrank==0) .or. debug >= 2) write(0,*) 'DEBUG: solve_eliminate end', t2-t0
302  end subroutine solve_eliminate
303 
306  subroutine copy_mesh(src, dst)
307  type(hecmwst_local_mesh), intent(in) :: src
308  type(hecmwst_local_mesh), intent(out) :: dst
309 
310  dst%zero = src%zero
311  dst%MPI_COMM = src%MPI_COMM
312  dst%PETOT = src%PETOT
313  dst%PEsmpTOT = src%PEsmpTOT
314  dst%my_rank = src%my_rank
315  dst%n_subdomain = src%n_subdomain
316  dst%n_node = src%n_node
317  dst%nn_internal = src%nn_internal
318  dst%n_elem = src%n_elem
319  dst%ne_internal = src%ne_internal
320  dst%n_elem_type = src%n_elem_type
321  dst%n_dof = src%n_dof
322  dst%n_neighbor_pe = src%n_neighbor_pe
323  if (src%n_neighbor_pe > 0) then
324  allocate(dst%neighbor_pe(dst%n_neighbor_pe))
325  dst%neighbor_pe(:) = src%neighbor_pe(:)
326  allocate(dst%import_index(0:dst%n_neighbor_pe))
327  dst%import_index(:)= src%import_index(:)
328  allocate(dst%export_index(0:dst%n_neighbor_pe))
329  dst%export_index(:)= src%export_index(:)
330  allocate(dst%import_item(dst%import_index(dst%n_neighbor_pe)))
331  dst%import_item(1:dst%import_index(dst%n_neighbor_pe)) = src%import_item(1:dst%import_index(dst%n_neighbor_pe))
332  allocate(dst%export_item(dst%export_index(dst%n_neighbor_pe)))
333  dst%export_item(1:dst%export_index(dst%n_neighbor_pe)) = src%export_item(1:dst%export_index(dst%n_neighbor_pe))
334  else
335  dst%neighbor_pe => null()
336  dst%import_index => null()
337  dst%export_index => null()
338  dst%import_item => null()
339  dst%export_item => null()
340  endif
341  allocate(dst%global_node_ID(dst%n_node))
342  dst%global_node_ID(1:dst%n_node) = src%global_node_ID(1:dst%n_node)
343  allocate(dst%node_ID(2*dst%n_node))
344  dst%node_ID(1:2*dst%n_node) = src%node_ID(1:2*dst%n_node)
345  allocate(dst%elem_type_item(dst%n_elem_type))
346  dst%elem_type_item(:) = src%elem_type_item(:)
347  !
348  dst%mpc%n_mpc = src%mpc%n_mpc
349  dst%mpc%mpc_index => src%mpc%mpc_index
350  dst%mpc%mpc_item => src%mpc%mpc_item
351  dst%mpc%mpc_dof => src%mpc%mpc_dof
352  dst%mpc%mpc_val => src%mpc%mpc_val
353  dst%mpc%mpc_const => src%mpc%mpc_const
354  !
355  dst%node_group%n_grp = src%node_group%n_grp
356  dst%node_group%n_bc = src%node_group%n_bc
357  dst%node_group%grp_name => src%node_group%grp_name
358  dst%node_group%grp_index => src%node_group%grp_index
359  dst%node_group%grp_item => src%node_group%grp_item
360  dst%node_group%bc_grp_ID => src%node_group%bc_grp_ID
361  dst%node_group%bc_grp_type => src%node_group%bc_grp_type
362  dst%node_group%bc_grp_index => src%node_group%bc_grp_index
363  dst%node_group%bc_grp_dof => src%node_group%bc_grp_dof
364  dst%node_group%bc_grp_val => src%node_group%bc_grp_val
365  !
366  dst%node => src%node
367  end subroutine copy_mesh
368 
371  subroutine free_mesh(hecMESH)
372  type(hecmwst_local_mesh), intent(inout) :: hecmesh
373 
374  if (hecmesh%n_neighbor_pe > 0) then
375  deallocate(hecmesh%neighbor_pe)
376  deallocate(hecmesh%import_index)
377  deallocate(hecmesh%export_index)
378  deallocate(hecmesh%import_item)
379  deallocate(hecmesh%export_item)
380  deallocate(hecmesh%global_node_ID)
381  endif
382  deallocate(hecmesh%node_ID)
383  deallocate(hecmesh%elem_type_item)
384  !hecMESH%node => null()
385  end subroutine free_mesh
386 
389  subroutine make_transformation_matrices(hecMESH, hecMESHtmp, hecMAT, hecLagMAT, &
390  slaves4lag, BLs_inv, BUs_inv, slaves, Tmat, Ttmat)
391  type(hecmwst_local_mesh), intent(in) :: hecmesh
392  type(hecmwst_local_mesh), intent(inout) :: hecmeshtmp
393  type(hecmwst_matrix), intent(inout) :: hecmat
394  type(hecmwst_matrix_lagrange), intent(inout) :: heclagmat
395  integer(kind=kint), intent(out) :: slaves4lag(:)
396  real(kind=kreal), intent(out) :: bls_inv(:)
397  real(kind=kreal), intent(out) :: bus_inv(:)
398  integer(kind=kint), allocatable, intent(out) :: slaves(:)
399  type(hecmwst_local_matrix), intent(out) :: tmat
400  type(hecmwst_local_matrix), intent(out) :: ttmat
401  !
402  integer(kind=kint) :: myrank, n
403 
404  myrank = hecmw_comm_get_rank()
405  n = hecmat%NP
406 
407  ! choose slave DOFs to be eliminated with Lag. DOFs
408  call choose_slaves(hecmat, heclagmat, n, slaves4lag)
409  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: slave DOFs chosen'
410 
411  call make_bls_inv(heclagmat, hecmat%NDOF, slaves4lag, bls_inv)
412  call make_bus_inv(heclagmat, hecmat%NDOF, slaves4lag, bus_inv)
413 
414  call add_c_to_tmat(hecmat, heclagmat, n, slaves4lag, bls_inv, tmat)
415  if (debug_matrix) call debug_write_matrix(tmat, 'Tmat (local, C only)')
416  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: add C to Tmat done'
417 
418  call add_ct_to_ttmat(hecmat, heclagmat, n, slaves4lag, bus_inv, ttmat)
419  if (debug_matrix) call debug_write_matrix(ttmat, 'Ttmat (local, Ct only)')
420  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: add Ct to Tt done'
421 
422  if (hecmw_comm_get_size() > 1) then
423  ! communicate and assemble Tmat (updating hecMESHtmp)
424  call hecmw_localmat_assemble(tmat, hecmesh, hecmeshtmp)
425  if (debug >= 2) then
426  write(0,*) ' DEBUG2[',myrank,']: assemble T done'
427  if (tmat%nc /= hecmesh%n_node) write(0,*) ' DEBUG2[',myrank,']: node migrated with T',tmat%nc-hecmesh%n_node
428  endif
429  if (debug_matrix) call debug_write_matrix(tmat, 'Tmat (assembled, C only)')
430 
431  ! communicate and assemble Ttmat (updating hecMESHtmp)
432  call hecmw_localmat_assemble(ttmat, hecmesh, hecmeshtmp)
433  if (debug >= 2) then
434  write(0,*) ' DEBUG2[',myrank,']: assemble Tt done'
435  if (ttmat%nc /= tmat%nc) write(0,*) ' DEBUG2[',myrank,']: node migrated with Ttmat',ttmat%nc-tmat%nc
436  tmat%nc = ttmat%nc
437  endif
438  if (debug_matrix) call debug_write_matrix(ttmat, 'Ttmat (assembled, Ct only)')
439  endif
440 
441  ! add Ip to Tmat and Ttmat
442  call make_slave_list(hecmeshtmp, tmat%ndof, slaves4lag, slaves)
443  call add_ip_to_tmat(tmat, slaves)
444  if (debug_matrix) call debug_write_matrix(tmat, 'Tmat (final)')
445  call add_ip_to_tmat(ttmat, slaves)
446  if (debug_matrix) call debug_write_matrix(ttmat, 'Ttmat (final)')
447  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: place 1 on diag of T and Tt done'
448  end subroutine make_transformation_matrices
449 
452  subroutine choose_slaves(hecMAT, hecLagMAT, n, slaves4lag)
453  type(hecmwst_matrix), intent(in) :: hecmat
454  type(hecmwst_matrix_lagrange), intent(in) :: heclagmat
455  integer(kind=kint), intent(in) :: n
456  integer(kind=kint), intent(out) :: slaves4lag(:)
457  !
458  integer(kind=kint) :: ndof, i, j, idof, jdof, l, ls, le, idx, imax, iwmin
459  real(kind=kreal) :: val, vmax
460  integer(kind=kint), allocatable :: mark_slave4lag(:)
461  integer(kind=kint), allocatable :: iw1l(:), iw1u(:)
462  integer(kind=kint) :: n_slave_in, n_slave_out, ilag
463  integer(kind=kint) :: myrank
464 
465  myrank = hecmw_comm_get_rank()
466  ndof=hecmat%NDOF
467 
468  allocate(mark_slave4lag(n*ndof), source=0)
469  slaves4lag=0
470 
471  if (heclagmat%num_lagrange == 0) return
472 
473  allocate(iw1l(n*ndof))
474  allocate(iw1u(n*ndof))
475  iw1l=0
476  iw1u=0
477 
478  ! Count how many times each dof appear in Lagrange matrix
479  ! lower
480  do i=1,heclagmat%num_lagrange
481  ls=heclagmat%indexL_lagrange(i-1)+1
482  le=heclagmat%indexL_lagrange(i)
483  do l=ls,le
484  j=heclagmat%itemL_lagrange(l)
485  do jdof=1,ndof
486  idx=(j-1)*ndof+jdof
487  iw1l(idx)=iw1l(idx)+1
488  enddo
489  enddo
490  enddo
491  ! upper
492  do i=1,n
493  ls=heclagmat%indexU_lagrange(i-1)+1
494  le=heclagmat%indexU_lagrange(i)
495  do l=ls,le
496  j=heclagmat%itemU_lagrange(l)
497  do idof=1,ndof
498  idx=(i-1)*ndof+idof
499  iw1u(idx)=iw1u(idx)+1
500  enddo
501  enddo
502  enddo
503  !!$ write(0,*) 'iw1L, iw1U:'
504  !!$ do i=1,n*ndof
505  !!$ if (iw1L(i) > 0 .or. iw1U(i) > 0) write(0,*) i, iw1L(i), iw1U(i)
506  !!$ enddo
507 
508  ! Choose dofs that
509  ! - appear only once in both lower and upper Lag. and
510  ! - has greatest coefficient among them (in lower Lag.)
511  do i=1,heclagmat%num_lagrange
512  ls=heclagmat%indexL_lagrange(i-1)+1
513  le=heclagmat%indexL_lagrange(i)
514  vmax = 0.d0
515  imax = -1
516  iwmin = n
517  do l=ls,le
518  j=heclagmat%itemL_lagrange(l)
519  do jdof=1,ndof
520  idx=(j-1)*ndof+jdof
521  val=heclagmat%AL_lagrange((l-1)*ndof+jdof)
522  if (iw1l(idx) < iwmin .and. iw1u(idx) < iwmin) then
523  iwmin = min(iw1l(idx),iw1u(idx))
524  vmax = 0.d0
525  endif
526  if (iw1l(idx) == iwmin .and. iw1u(idx) == iwmin) then
527  if (abs(val) > abs(vmax)) then
528  imax=idx
529  vmax=val
530  endif
531  endif
532  enddo
533  enddo
534  if (imax == -1) stop "ERROR: iterative solver for contact failed"
535  mark_slave4lag(imax)=i
536  slaves4lag(i)=imax
537  enddo
538  !!$ write(0,*) 'mark_slave4lag:'
539  !!$ do i=1,n*ndof
540  !!$ if (mark_slave4lag(i) > 0) write(0,*) i, mark_slave4lag(i), iw1L(i), iw1U(i)
541  !!$ enddo
542  !!$ write(0,*) 'slaves4lag:'
543  !!$ write(0,*) slaves4lag(:)
544  if (debug >= 2) then
545  n_slave_in = 0
546  n_slave_out = 0
547  do ilag=1,heclagmat%num_lagrange
548  i = slaves4lag(ilag)
549  if (0 < i .and. i <= hecmat%N*ndof) then
550  n_slave_in = n_slave_in + 1
551  elseif (hecmat%N*ndof < i .and. i <= hecmat%NP*ndof) then
552  n_slave_out = n_slave_out + 1
553  endif
554  enddo
555  write(0,*) ' DEBUG2[',myrank,']: n_slave(in,out,tot)',n_slave_in,n_slave_out,heclagmat%num_lagrange
556  endif
557 
558  deallocate(mark_slave4lag)
559  deallocate(iw1l, iw1u)
560  end subroutine choose_slaves
561 
564  subroutine make_bls_inv(hecLagMAT, ndof, slaves4lag, BLs_inv)
565  type(hecmwst_matrix_lagrange), intent(in) :: heclagmat
566  integer(kind=kint), intent(in) :: ndof
567  integer(kind=kint), intent(in) :: slaves4lag(:)
568  real(kind=kreal), intent(out) :: bls_inv(:)
569  !
570  integer(kind=kint) :: ilag, ls, le, l, j, jdof, idx
571 
572  if (heclagmat%num_lagrange == 0) return
573 
574  bls_inv=0.d0
575  do ilag=1,heclagmat%num_lagrange
576  ls=heclagmat%indexL_lagrange(ilag-1)+1
577  le=heclagmat%indexL_lagrange(ilag)
578  lloop: do l=ls,le
579  j=heclagmat%itemL_lagrange(l)
580  do jdof=1,ndof
581  idx=(j-1)*ndof+jdof
582  if (idx==slaves4lag(ilag)) then
583  bls_inv(ilag) = 1.0d0/heclagmat%AL_lagrange((l-1)*ndof+jdof)
584  exit lloop
585  endif
586  enddo
587  enddo lloop
588  enddo
589  !write(0,*) BLs_inv
590  end subroutine make_bls_inv
591 
594  subroutine make_bus_inv(hecLagMAT, ndof, slaves4lag, BUs_inv)
595  type(hecmwst_matrix_lagrange), intent(in) :: heclagmat
596  integer(kind=kint), intent(in) :: ndof
597  integer(kind=kint), intent(in) :: slaves4lag(:)
598  real(kind=kreal), intent(out) :: bus_inv(:)
599  !
600  integer(kind=kint) :: ilag, i, idof, js, je, j, k
601 
602  if (heclagmat%num_lagrange == 0) return
603 
604  bus_inv=0.d0
605  do ilag=1,size(slaves4lag)
606  i=(slaves4lag(ilag)+ndof-1)/ndof
607  idof=slaves4lag(ilag)-(i-1)*ndof
608  js=heclagmat%indexU_lagrange(i-1)+1
609  je=heclagmat%indexU_lagrange(i)
610  do j=js,je
611  k=heclagmat%itemU_lagrange(j)
612  if (k==ilag) then
613  bus_inv(ilag) = 1.0d0/heclagmat%AU_lagrange((j-1)*ndof+idof)
614  exit
615  endif
616  enddo
617  enddo
618  !write(0,*) BUs_inv
619  end subroutine make_bus_inv
620 
623  subroutine add_c_to_tmat(hecMAT, hecLagMAT, n, slaves4lag, BLs_inv, Tmat)
624  type(hecmwst_matrix), intent(inout) :: hecmat
625  type(hecmwst_matrix_lagrange), intent(inout) :: heclagmat
626  integer(kind=kint), intent(in) :: n
627  integer(kind=kint), intent(in) :: slaves4lag(:)
628  real(kind=kreal), intent(in) :: bls_inv(:)
629  type(hecmwst_local_matrix), intent(out) :: tmat
630  !
631  type(hecmwst_local_matrix) :: tmat11
632  integer(kind=kint), allocatable :: nz_cnt(:)
633  integer(kind=kint) :: ndof, i, ilag, l, js, je, j, k, jdof, kk, jj
634  real(kind=kreal) :: factor
635 
636  ndof=hecmat%NDOF
637  tmat11%nr=n*ndof
638  tmat11%nc=tmat11%nr
639  tmat11%nnz=heclagmat%numL_lagrange*ndof-heclagmat%num_lagrange
640  tmat11%ndof=1
641 
642  allocate(tmat11%index(0:tmat11%nr))
643  allocate(tmat11%item(tmat11%nnz), tmat11%A(tmat11%nnz))
644  allocate(nz_cnt(tmat11%nr), source=0)
645  ! index
646  do ilag=1,size(slaves4lag)
647  nz_cnt(slaves4lag(ilag))=ndof*(heclagmat%indexL_lagrange(ilag)-heclagmat%indexL_lagrange(ilag-1))-1
648  enddo
649  tmat11%index(0)=0
650  do i=1,tmat11%nr
651  tmat11%index(i)=tmat11%index(i-1)+nz_cnt(i)
652  enddo
653  deallocate(nz_cnt)
654  if (tmat11%nnz /= tmat11%index(tmat11%nr)) then
655  write(0,*) tmat11%nnz, tmat11%index(tmat11%nr)
656  tmat11%nnz = tmat11%index(tmat11%nr)
657  !stop 'ERROR: Tmat11%nnz wrong'
658  endif
659  ! item and A
660  do ilag=1,size(slaves4lag)
661  i=slaves4lag(ilag)
662  l=tmat11%index(i-1)+1
663  js=heclagmat%indexL_lagrange(ilag-1)+1
664  je=heclagmat%indexL_lagrange(ilag)
665  factor=-bls_inv(ilag)
666  do j=js,je
667  k=heclagmat%itemL_lagrange(j)
668  do jdof=1,ndof
669  kk=(k-1)*ndof+jdof
670  jj=(j-1)*ndof+jdof
671  if (kk==i) cycle
672  tmat11%item(l)=kk
673  tmat11%A(l)=heclagmat%AL_lagrange(jj)*factor
674  l=l+1
675  enddo
676  enddo
677  if (l /= tmat11%index(i)+1) then
678  write(0,*) l, tmat11%index(i)+1
679  stop 'ERROR: Tmat11%index wrong'
680  endif
681  enddo
682  !call hecmw_localmat_write(Tmat11, 0)
683  ! make 3x3-block version of Tmat
684  call hecmw_localmat_blocking(tmat11, ndof, tmat)
685  call hecmw_localmat_free(tmat11)
686  end subroutine add_c_to_tmat
687 
690  subroutine add_ct_to_ttmat(hecMAT, hecLagMAT, n, slaves4lag, BUs_inv, Ttmat)
691  type(hecmwst_matrix), intent(inout) :: hecmat
692  type(hecmwst_matrix_lagrange), intent(inout) :: heclagmat
693  integer(kind=kint), intent(in) :: n
694  integer(kind=kint), intent(in) :: slaves4lag(:)
695  real(kind=kreal), intent(in) :: bus_inv(:)
696  type(hecmwst_local_matrix), intent(out) :: ttmat
697  !
698  type(hecmwst_local_matrix) :: ttmat11
699  integer(kind=kint), allocatable :: nz_cnt(:)
700  integer(kind=kint) :: ndof, i, idof, idx, ilag, l, js, je, j, k
701 
702  ndof=hecmat%NDOF
703  ttmat11%nr=n*ndof
704  ttmat11%nc=ttmat11%nr
705  ttmat11%nnz=heclagmat%numU_lagrange*ndof-heclagmat%num_lagrange
706  ttmat11%ndof=1
707 
708  allocate(ttmat11%index(0:ttmat11%nr))
709  allocate(ttmat11%item(ttmat11%nnz), ttmat11%A(ttmat11%nnz))
710  allocate(nz_cnt(ttmat11%nr), source=0)
711  ! index
712  if (heclagmat%num_lagrange > 0) then
713  do i=1,n
714  do idof=1,ndof
715  idx=(i-1)*ndof+idof
716  nz_cnt(idx)=heclagmat%indexU_lagrange(i)-heclagmat%indexU_lagrange(i-1)
717  enddo
718  enddo
719  do ilag=1,size(slaves4lag)
720  nz_cnt(slaves4lag(ilag))=0
721  enddo
722  endif
723  ttmat11%index(0)=0
724  do i=1,ttmat11%nr
725  ttmat11%index(i)=ttmat11%index(i-1)+nz_cnt(i)
726  enddo
727  if (ttmat11%nnz /= ttmat11%index(ttmat11%nr)) then
728  write(0,*) ttmat11%nnz, ttmat11%index(ttmat11%nr)
729  !stop 'ERROR: Ttmat11%nnz wrong'
730  ttmat11%nnz = ttmat11%index(ttmat11%nr)
731  endif
732  ! item and A
733  do i=1,n
734  do idof=1,ndof
735  idx=(i-1)*ndof+idof
736  l=ttmat11%index(idx-1)+1
737  if (nz_cnt(idx) > 0) then
738  ! offdiagonal
739  js=heclagmat%indexU_lagrange(i-1)+1
740  je=heclagmat%indexU_lagrange(i)
741  do j=js,je
742  k=heclagmat%itemU_lagrange(j)
743  ttmat11%item(l)=slaves4lag(k)
744  ttmat11%A(l)=-heclagmat%AU_lagrange((j-1)*ndof+idof)*bus_inv(k)
745  l=l+1
746  enddo
747  endif
748  if (l /= ttmat11%index(idx)+1) then
749  write(0,*) l, ttmat11%index(idx)+1
750  stop 'ERROR: Ttmat11%index wrong'
751  endif
752  enddo
753  enddo
754  deallocate(nz_cnt)
755  !call hecmw_localmat_write(Ttmat11, 0)
756  ! make 3x3-block version of Ttmat
757  call hecmw_localmat_blocking(ttmat11, ndof, ttmat)
758  call hecmw_localmat_free(ttmat11)
759  end subroutine add_ct_to_ttmat
760 
763  subroutine make_slave_list(hecMESHtmp, ndof, slaves4lag, slaves)
764  type(hecmwst_local_mesh), intent(in) :: hecmeshtmp
765  integer(kind=kint), intent(in) :: ndof
766  integer(kind=kint), intent(in) :: slaves4lag(:)
767  integer(kind=kint), allocatable, intent(out) :: slaves(:)
768  !
769  integer(kind=kint), allocatable :: mark_slave(:)
770  integer(kind=kint) :: n_slave
771  integer(kind=kint) :: ilag, i
772  integer(kind=kint) :: myrank
773 
774  myrank = hecmw_comm_get_rank()
775  allocate(mark_slave(hecmeshtmp%n_node*ndof), source=0)
776  do ilag=1,size(slaves4lag)
777  mark_slave(slaves4lag(ilag))=1
778  enddo
779  call hecmw_assemble_i(hecmeshtmp, mark_slave, hecmeshtmp%n_node, ndof)
780  n_slave = 0
781  do i = 1, hecmeshtmp%nn_internal * ndof
782  if (mark_slave(i) /= 0) n_slave = n_slave + 1
783  enddo
784  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: n_slave',n_slave
785  allocate(slaves(n_slave))
786  n_slave = 0
787  do i = 1, hecmeshtmp%nn_internal * ndof
788  if (mark_slave(i) /= 0) then
789  n_slave = n_slave + 1
790  slaves(n_slave) = i
791  endif
792  enddo
793  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: slaves',slaves(:)
794  deallocate(mark_slave)
795  end subroutine make_slave_list
796 
799  subroutine add_ip_to_tmat(Tmat, slaves)
800  type(hecmwst_local_matrix), intent(inout) :: tmat
801  integer(kind=kint), intent(in) :: slaves(:)
802  !
803  type(hecmwst_local_matrix) :: imat, wmat
804  integer(kind=kint) :: ndof, ndof2, i, irow, idof
805 
806  ndof = tmat%ndof
807  ndof2 = ndof*ndof
808  ! Imat: unit matrix except for slave dofs
809  imat%nr = tmat%nr
810  imat%nc = tmat%nc
811  imat%nnz = imat%nr
812  imat%ndof = ndof
813  allocate(imat%index(0:imat%nr))
814  allocate(imat%item(imat%nnz))
815  imat%index(0) = 0
816  do i = 1, imat%nr
817  imat%index(i) = i
818  imat%item(i) = i
819  enddo
820  allocate(imat%A(ndof2 * imat%nnz))
821  imat%A(:) = 0.0d0
822  do irow = 1, imat%nr
823  do idof = 1, ndof
824  imat%A(ndof2*(irow-1)+ndof*(idof-1)+idof) = 1.0d0
825  enddo
826  enddo
827  do i = 1, size(slaves)
828  irow = (slaves(i)+ndof-1)/ndof
829  idof = slaves(i)-ndof*(irow-1)
830  imat%A(ndof2*(irow-1)+ndof*(idof-1)+idof) = 0.0d0
831  enddo
832  call hecmw_localmat_add(tmat, imat, wmat)
833  call hecmw_localmat_free(tmat)
834  call hecmw_localmat_free(imat)
835  tmat%nr = wmat%nr
836  tmat%nc = wmat%nc
837  tmat%nnz = wmat%nnz
838  tmat%ndof = wmat%ndof
839  tmat%index => wmat%index
840  tmat%item => wmat%item
841  tmat%A => wmat%A
842  end subroutine add_ip_to_tmat
843 
846  subroutine make_contact_comm_table(hecMESH, hecMAT, hecLagMAT, conCOMM)
847  type(hecmwst_local_mesh), intent(in) :: hecmesh
848  type(hecmwst_matrix), intent(in) :: hecmat
849  type(hecmwst_matrix_lagrange), intent(in) :: heclagmat
850  type(hecmwst_contact_comm), intent(out) :: concomm
851  !
852  integer(kind=kint) :: n_contact_dof
853  integer(kind=kint), allocatable :: contact_dofs(:)
854 
855  ! make list of contact dofs including masters and slaves
856  call make_contact_dof_list(hecmat, heclagmat, n_contact_dof, contact_dofs)
857 
858  ! make comm_table for contact dofs
859  call hecmw_contact_comm_init(concomm, hecmesh, hecmat%ndof, n_contact_dof, contact_dofs)
860  end subroutine make_contact_comm_table
861 
864  subroutine make_contact_dof_list(hecMAT, hecLagMAT, n_contact_dof, contact_dofs)
865  type(hecmwst_matrix), intent(in) :: hecmat
866  type(hecmwst_matrix_lagrange), intent(in) :: heclagmat
867  integer(kind=kint), intent(out) :: n_contact_dof
868  integer(kind=kint), allocatable, intent(out) :: contact_dofs(:)
869  !
870  integer(kind=kint) :: ndof, icnt, ilag, ls, le, l, jnode, k, inode, idof, i
871  integer(kind=kint), allocatable :: iw(:)
872  logical :: found
873  integer(kind=kint) :: myrank
874 
875  if (heclagmat%num_lagrange == 0) then
876  n_contact_dof = 0
877  return
878  endif
879  ! lower
880  ndof = hecmat%NDOF
881  allocate(iw(hecmat%NP))
882  icnt = 0
883  do ilag = 1, heclagmat%num_lagrange
884  ls = heclagmat%indexL_lagrange(ilag-1)+1
885  le = heclagmat%indexL_lagrange(ilag)
886  lloop1: do l = ls, le
887  jnode = heclagmat%itemL_lagrange(l)
888  do k = 1, icnt
889  if (iw(k) == jnode) cycle lloop1
890  enddo
891  icnt = icnt + 1
892  iw(icnt) = jnode
893  enddo lloop1
894  enddo
895  ! upper
896  do inode = 1, hecmat%NP
897  ls = heclagmat%indexU_lagrange(inode-1)+1
898  le = heclagmat%indexU_lagrange(inode)
899  if (ls <= le) then
900  found = .false.
901  do k = 1, icnt
902  if (iw(k) == inode) found = .true.
903  enddo
904  if (.not. found) then
905  icnt = icnt + 1
906  iw(icnt) = inode
907  endif
908  endif
909  enddo
910  call quick_sort(iw, 1, icnt)
911  allocate(contact_dofs(icnt*ndof))
912  do i = 1, icnt
913  do idof = 1, ndof
914  contact_dofs((i-1)*ndof+idof) = (iw(i)-1)*ndof+idof
915  enddo
916  enddo
917  n_contact_dof = icnt*ndof
918  deallocate(iw)
919  myrank = hecmw_comm_get_rank()
920  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: n_contact_dof',n_contact_dof
921  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: contact_dofs',contact_dofs(:)
922  end subroutine make_contact_dof_list
923 
926  recursive subroutine quick_sort(array, id1, id2)
927  integer(kind=kint), intent(inout) :: array(:)
928  integer(kind=kint), intent(in) :: id1, id2
929  !
930  integer(kind=kint) :: pivot, center, left, right, tmp
931 
932  if (id1 >= id2) return
933  center = (id1 + id2) / 2
934  pivot = array(center)
935  left = id1
936  right = id2
937  do
938  do while (array(left) < pivot)
939  left = left + 1
940  end do
941  do while (pivot < array(right))
942  right = right - 1
943  end do
944  if (left >= right) exit
945  tmp = array(left)
946  array(left) = array(right)
947  array(right) = tmp
948  left = left + 1
949  right = right - 1
950  end do
951  if (id1 < left-1) call quick_sort(array, id1, left-1)
952  if (right+1 < id2) call quick_sort(array, right+1, id2)
953  return
954  end subroutine quick_sort
955 
958  subroutine assemble_equation(hecMESH, hecMESHtmp, hecMAT, conMAT, num_lagrange, &
959  slaves, Kmat, Btot)
960  type(hecmwst_local_mesh), intent(in) :: hecmesh
961  type(hecmwst_local_mesh), intent(inout) :: hecmeshtmp
962  type(hecmwst_matrix), intent(in) :: hecmat
963  type(hecmwst_matrix), intent(in) :: conmat
964  integer(kind=kint), intent(in) :: num_lagrange
965  integer(kind=kint), intent(in) :: slaves(:)
966  ! type(hecmwST_contact_comm), intent(in) :: conCOMM !< contact comm table for optimized communication
967  type(hecmwst_local_matrix), intent(out) :: kmat
968  real(kind=kreal), intent(out) :: btot(:)
969  !
970  integer(kind=kint) :: myrank
971 
972  myrank = hecmw_comm_get_rank()
973 
974  call assemble_matrix(hecmesh, hecmeshtmp, hecmat, conmat, num_lagrange, kmat)
975  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: assemble matrix done'
976 
977  call assemble_rhs(hecmesh, hecmat, conmat, num_lagrange, slaves, btot)
978  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: assemble rhs done'
979 
980  end subroutine assemble_equation
981 
984  subroutine assemble_matrix(hecMESH, hecMESHtmp, hecMAT, conMAT, num_lagrange, Kmat)
985  type(hecmwst_local_mesh), intent(in) :: hecmesh
986  type(hecmwst_local_mesh), intent(inout) :: hecmeshtmp
987  type(hecmwst_matrix), intent(in) :: hecmat
988  type(hecmwst_matrix), intent(in) :: conmat
989  integer(kind=kint), intent(in) :: num_lagrange
990  type(hecmwst_local_matrix), intent(out) :: kmat
991  !
992  integer(kind=kint) :: myrank
993 
994  myrank = hecmw_comm_get_rank()
995 
996  ! init Kmat and substitute conMAT
997  call hecmw_localmat_init_with_hecmat(kmat, conmat, num_lagrange)
998  if (debug_matrix) call debug_write_matrix(kmat, 'Kmat (conMAT local)')
999 
1000  if (hecmw_comm_get_size() > 1) then
1001  ! communicate and assemble Kmat (updating hecMESHtmp)
1002  call hecmw_localmat_assemble(kmat, hecmesh, hecmeshtmp)
1003  if (debug_matrix) call debug_write_matrix(kmat, 'Kmat (conMAT assembled)')
1004  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: assemble K (conMAT) done'
1005  endif
1006 
1007  ! add hecMAT to Kmat
1008  call hecmw_localmat_add_hecmat(kmat, hecmat)
1009  if (debug_matrix) call debug_write_matrix(kmat, 'Kmat (hecMAT added)')
1010  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: add hecMAT to K done'
1011  end subroutine assemble_matrix
1012 
1015  subroutine assemble_rhs(hecMESH, hecMAT, conMAT, num_lagrange, slaves, Btot)
1016  type(hecmwst_local_mesh), intent(in) :: hecmesh
1017  type(hecmwst_matrix), intent(in) :: hecmat
1018  type(hecmwst_matrix), intent(in) :: conmat
1019  integer(kind=kint), intent(in) :: num_lagrange
1020  integer(kind=kint), intent(in) :: slaves(:)
1021  ! type(hecmwST_contact_comm), intent(in) :: conCOMM !< contact comm table for optimized communication
1022  real(kind=kreal), intent(out) :: btot(:)
1023  !
1024  integer(kind=kint) :: ndof, nndof, npndof, i, myrank
1025 
1026  myrank = hecmw_comm_get_rank()
1027 
1028  ndof = hecmat%NDOF
1029  npndof = hecmat%NP*ndof
1030  nndof = hecmat%N *ndof
1031 
1032  if (debug_vector) call debug_write_vector(hecmat%B, 'RHS(hecMAT)', 'hecMAT%B', ndof, hecmat%N, &
1033  hecmat%NP, .false., num_lagrange, slaves)
1034  if (debug_vector) call debug_write_vector(conmat%B, 'RHS(conMAT)', 'conMAT%B', ndof, conmat%N, &
1035  conmat%NP, .true., num_lagrange, slaves)
1036 
1037  do i=1,npndof+num_lagrange
1038  btot(i) = conmat%B(i)
1039  enddo
1040 
1041  if (hecmw_comm_get_size() > 1) then
1042  ! next line cannot be: call hecmw_contact_comm_reduce_r(conCOMM, Btot, HECMW_SUM) !!! alag_tied fails
1043  call hecmw_assemble_r(hecmesh, btot, hecmat%NP, ndof)
1044  if (debug_vector) call debug_write_vector(btot, 'RHS(conMAT assembled)', 'Btot', ndof, conmat%N, &
1045  conmat%NP, .false., num_lagrange, slaves)
1046  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: assemble RHS (conMAT%B) done'
1047  endif
1048 
1049  ! add hecMAT%B to Btot
1050  do i=1,nndof
1051  btot(i)=btot(i)+hecmat%B(i)
1052  enddo
1053  if (debug_vector) call debug_write_vector(btot, 'RHS(total)', 'Btot', ndof, conmat%N, &
1054  conmat%NP, .false., num_lagrange, slaves)
1055  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: add hecMAT%B to RHS done'
1056  end subroutine assemble_rhs
1057 
1060  subroutine convert_equation(hecMESHtmp, hecMAT, Kmat, Tmat, Ttmat, Btot, slaves, &
1061  slaves4lag, BLs_inv, conCOMM, hecTKT)
1062  type(hecmwst_local_mesh), intent(inout) :: hecmeshtmp
1063  type(hecmwst_matrix), intent(in) :: hecmat
1064  type(hecmwst_local_matrix), intent(inout) :: kmat
1065  type(hecmwst_local_matrix), intent(inout) :: tmat
1066  type(hecmwst_local_matrix), intent(in) :: ttmat
1067  real(kind=kreal), intent(in) :: btot(:)
1068  integer(kind=kint), intent(in) :: slaves(:)
1069  integer(kind=kint), intent(in) :: slaves4lag(:)
1070  real(kind=kreal), intent(in) :: bls_inv(:)
1071  type(hecmwst_contact_comm), intent(in) :: concomm
1072  type(hecmwst_matrix), intent(out) :: hectkt
1073  !
1074  integer(kind=kint) :: myrank
1075 
1076  myrank = hecmw_comm_get_rank()
1077 
1078  call convert_matrix(hecmeshtmp, hecmat, ttmat, kmat, tmat, slaves, hectkt)
1079  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: converted matrix'
1080 
1081  call convert_rhs(hecmeshtmp, hecmat, hectkt, ttmat, kmat, &
1082  slaves4lag, bls_inv, btot, concomm)
1083  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: converted RHS'
1084  end subroutine convert_equation
1085 
1088  subroutine convert_matrix(hecMESHtmp, hecMAT, Ttmat, Kmat, Tmat, slaves, hecTKT)
1089  type(hecmwst_local_mesh), intent(inout) :: hecmeshtmp
1090  type(hecmwst_matrix), intent(in) :: hecmat
1091  type(hecmwst_local_matrix), intent(in) :: ttmat
1092  type(hecmwst_local_matrix), intent(inout) :: kmat
1093  type(hecmwst_local_matrix), intent(inout) :: tmat
1094  integer(kind=kint), intent(in) :: slaves(:)
1095  type(hecmwst_matrix), intent(out) :: hectkt
1096  !
1097  type(hecmwst_local_matrix) :: ttkmat, ttktmat
1098  integer(kind=kint) :: myrank
1099 
1100  myrank = hecmw_comm_get_rank()
1101 
1102  ! compute TtKmat = Ttmat * Kmat (updating hecMESHtmp)
1103  call hecmw_localmat_multmat(ttmat, kmat, hecmeshtmp, ttkmat)
1104  if (debug_matrix) call debug_write_matrix(ttkmat, 'TtKmat')
1105  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: multiply Tt and K done'
1106 
1107  ! compute TtKTmat = TtKmat * Tmat (updating hecMESHtmp)
1108  call hecmw_localmat_multmat(ttkmat, tmat, hecmeshtmp, ttktmat)
1109  if (debug_matrix) call debug_write_matrix(ttktmat, 'TtKTmat')
1110  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: multiply TtK and T done'
1111  call hecmw_localmat_free(ttkmat)
1112 
1113  ! shrink comm_table
1114 
1115  call place_one_on_diag_of_slave_dof(ttktmat, slaves)
1116  if (debug_matrix) call debug_write_matrix(ttktmat, 'TtKTmat (place 1.0 on slave diag)')
1117 
1118  call hecmw_mat_init(hectkt)
1119  call hecmw_localmat_make_hecmat(hecmat, ttktmat, hectkt)
1120  if (debug >= 3) write(0,*) ' DEBUG3[',myrank,']: convert TtKT to hecTKT done'
1121  call hecmw_localmat_free(ttktmat)
1122  end subroutine convert_matrix
1123 
1126  subroutine place_one_on_diag_of_slave_dof(TtKTmat, slaves)
1127  type(hecmwst_local_matrix), intent(inout) :: ttktmat
1128  integer(kind=kint), intent(in) :: slaves(:)
1129  !
1130  integer(kind=kint) :: ndof, ndof2, i, irow, idof, js, je, j, jcol
1131 
1132  ndof = ttktmat%ndof
1133  ndof2 = ndof*ndof
1134  do i = 1, size(slaves)
1135  irow = (slaves(i)+ndof-1)/ndof
1136  idof = slaves(i)-ndof*(irow-1)
1137  js = ttktmat%index(irow-1)+1
1138  je = ttktmat%index(irow)
1139  do j = js, je
1140  jcol = ttktmat%item(j)
1141  if (irow /= jcol) cycle
1142  if (abs(ttktmat%A(ndof2*(j-1)+ndof*(idof-1)+idof)) > tiny(0.0d0)) &
1143  stop 'ERROR: nonzero diag on slave dof of TtKTmat'
1144  ttktmat%A(ndof2*(j-1)+ndof*(idof-1)+idof) = 1.0d0
1145  enddo
1146  enddo
1147  end subroutine place_one_on_diag_of_slave_dof
1148 
1151  subroutine convert_rhs(hecMESHtmp, hecMAT, hecTKT, Ttmat, Kmat, &
1152  slaves4lag, BLs_inv, Btot, conCOMM)
1153  type(hecmwst_local_mesh), intent(in) :: hecmeshtmp
1154  type(hecmwst_matrix), intent(in) :: hecmat
1155  type(hecmwst_matrix), intent(inout) :: hectkt
1156  type(hecmwst_local_matrix), intent(in) :: ttmat
1157  type(hecmwst_local_matrix), intent(in) :: kmat
1158  integer(kind=kint), intent(in) :: slaves4lag(:)
1159  real(kind=kreal), intent(in) :: bls_inv(:)
1160  real(kind=kreal), target, intent(in) :: btot(:)
1161  type(hecmwst_contact_comm), intent(in) :: concomm
1162  !
1163  real(kind=kreal), allocatable :: btmp(:)
1164  real(kind=kreal), pointer :: blag(:)
1165  integer(kind=kint) :: ndof, npndof, nndof, npndof_new, num_lagrange, i
1166 
1167  ! SIZE:
1168  ! Btot <=> hecMAT, hecMESH
1169  ! Btmp <=> Kmat, hecMESHtmp
1170  ! hecTKT%B <=> hecTKT, hecMESHtmp
1171  ndof = hecmat%NDOF
1172  npndof = hecmat%NP*ndof
1173  nndof = hecmat%N *ndof
1174  npndof_new = hectkt%NP*ndof
1175  num_lagrange = size(slaves4lag)
1176 
1177  allocate(hectkt%B(npndof_new), source=0.d0)
1178  allocate(hectkt%X(npndof_new), source=0.d0)
1179  allocate(btmp(npndof_new))
1180  !
1181  !! Ttmat*(B+K*(-Bs^-1)*Blag)
1182  !
1183  ! B2=-Bs^-1*Blag
1184  blag => btot(npndof+1:npndof+num_lagrange)
1185  hectkt%B(slaves4lag(:))=-bls_inv(:)*blag(:)
1186  ! send external contact dof => recv internal contact dof
1187  ! next line can be: call hecmw_assemble_R(hecMESHtmp, hecTKT%B, hecTKT%NP, ndof)
1188  call hecmw_contact_comm_reduce_r(concomm, hectkt%B, hecmw_sum)
1189  ! Btmp=B+K*B2 (including update of hecTKT%B)
1190  call hecmw_update_r(hecmeshtmp, hectkt%B, hectkt%NP, ndof)
1191  call hecmw_localmat_mulvec(kmat, hectkt%B, btmp)
1192  do i=1,nndof
1193  btmp(i)=btot(i)+btmp(i)
1194  enddo
1195  ! B2=Ttmat*Btmp
1196  call hecmw_update_r(hecmeshtmp, btmp, hectkt%NP, ndof)
1197  call hecmw_localmat_mulvec(ttmat, btmp, hectkt%B)
1198  deallocate(btmp)
1199 
1200  if (debug_vector) call debug_write_vector(hectkt%B, 'RHS(converted)', 'hecTKT%B', ndof, hectkt%N)
1201  end subroutine convert_rhs
1202 
1205  subroutine recover_solution(hecMESHtmp, hecMAT, hecTKT, Tmat, Kmat, Btot, &
1206  slaves4lag, BLs_inv, BUs_inv, conCOMM, slaves)
1207  ! type(hecmwST_local_mesh), intent(in) :: hecMESH !< original mesh
1208  type(hecmwst_local_mesh), intent(in) :: hecmeshtmp
1209  type(hecmwst_matrix), intent(inout) :: hecmat
1210  type(hecmwst_matrix), intent(inout) :: hectkt
1211  type(hecmwst_local_matrix), intent(in) :: tmat
1212  type(hecmwst_local_matrix), intent(in) :: kmat
1213  real(kind=kreal), intent(in) :: btot(:)
1214  integer(kind=kint), intent(in) :: slaves4lag(:)
1215  real(kind=kreal), intent(in) :: bls_inv(:)
1216  real(kind=kreal), intent(in) :: bus_inv(:)
1217  type(hecmwst_contact_comm), intent(in) :: concomm
1218  integer(kind=kint), intent(in) :: slaves(:)
1219  !
1220  integer(kind=kint) :: myrank
1221 
1222  myrank = hecmw_comm_get_rank()
1223 
1224  hecmat%Iarray=hectkt%Iarray
1225  hecmat%Rarray=hectkt%Rarray
1226 
1227  call comp_x_slave(hecmeshtmp, hecmat, hectkt, tmat, btot, &
1228  slaves4lag, bls_inv, concomm, slaves)
1229  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: recovered slave disp'
1230 
1231  call comp_lag(hecmeshtmp, hecmat, hectkt, kmat, btot, &
1232  slaves4lag, bus_inv, concomm, slaves)
1233  if (debug >= 2) write(0,*) ' DEBUG2[',myrank,']: recovered lag'
1234 
1235  if (debug_vector) call debug_write_vector(hecmat%X, 'Solution(original)', 'hecMAT%X', hecmat%NDOF, hecmat%N, &
1236  hecmat%NP, .false., size(slaves4lag), slaves)
1237  end subroutine recover_solution
1238 
1241  subroutine comp_x_slave(hecMESHtmp, hecMAT, hecTKT, Tmat, Btot, &
1242  slaves4lag, BLs_inv, conCOMM, slaves)
1243  ! type(hecmwST_local_mesh), intent(in) :: hecMESH !< original mesh
1244  type(hecmwst_local_mesh), intent(in) :: hecmeshtmp
1245  type(hecmwst_matrix), intent(inout) :: hecmat
1246  type(hecmwst_matrix), intent(in) :: hectkt
1247  type(hecmwst_local_matrix), intent(in) :: tmat
1248  real(kind=kreal), target, intent(in) :: btot(:)
1249  integer(kind=kint), intent(in) :: slaves4lag(:)
1250  real(kind=kreal), intent(in) :: bls_inv(:)
1251  type(hecmwst_contact_comm), intent(in) :: concomm
1252  integer(kind=kint), intent(in) :: slaves(:)
1253  !
1254  integer(kind=kint) :: ndof, ndof2, npndof, nndof, num_lagrange
1255  real(kind=kreal), allocatable :: xtmp(:)
1256  real(kind=kreal), pointer :: blag(:)
1257 
1258  ndof = hecmat%NDOF
1259  ndof2 = ndof*ndof
1260  npndof = hecmat%NP * ndof
1261  nndof = hecmat%N * ndof
1262  num_lagrange = size(slaves4lag)
1263  !!
1264  !! {X} = [T] {Xp} - [-Bs^-1] {c}
1265  !!
1266  ! compute {X} = [T] {Xp}
1267  call hecmw_update_r(hecmeshtmp, hectkt%X, hectkt%NP, ndof)
1268  call hecmw_localmat_mulvec(tmat, hectkt%X, hecmat%X)
1269  !
1270  ! compute {Xtmp} = [-Bs^-1] {c}
1271  allocate(xtmp(npndof), source=0.0d0)
1272  blag => btot(npndof+1:npndof+num_lagrange)
1273  xtmp(slaves4lag(:)) = -bls_inv(:) * blag(:)
1274  !
1275  ! send external contact dof => recv internal contact dof
1276  ! next line can be: call hecmw_assemble_R(hecMESH, Xtmp, hecMAT%NP, ndof)
1277  call hecmw_contact_comm_reduce_r(concomm, xtmp, hecmw_sum)
1278  !
1279  ! {X} = {X} - {Xtmp}
1280  hecmat%X(slaves(:)) = hecmat%X(slaves(:)) - xtmp(slaves(:))
1281  deallocate(xtmp)
1282  end subroutine comp_x_slave
1283 
1286  subroutine comp_lag(hecMESHtmp, hecMAT, hecTKT, Kmat, Btot, &
1287  slaves4lag, BUs_inv, conCOMM, slaves)
1288  ! type(hecmwST_local_mesh), intent(in) :: hecMESH !< original mesh
1289  type(hecmwst_local_mesh), intent(in) :: hecmeshtmp
1290  type(hecmwst_matrix), intent(inout) :: hecmat
1291  type(hecmwst_matrix), intent(inout) :: hectkt
1292  type(hecmwst_local_matrix), intent(in) :: kmat
1293  real(kind=kreal), intent(in) :: btot(:)
1294  integer(kind=kint), intent(in) :: slaves4lag(:)
1295  real(kind=kreal), intent(in) :: bus_inv(:)
1296  type(hecmwst_contact_comm), intent(in) :: concomm
1297  integer(kind=kint), intent(in) :: slaves(:)
1298  !
1299  integer(kind=kint) :: ndof, npndof, nndof, npndof_new, num_lagrange
1300  real(kind=kreal), allocatable :: btmp(:)
1301  real(kind=kreal), pointer :: xlag(:)
1302 
1303  ndof=hecmat%ndof
1304  npndof = hecmat%NP * ndof
1305  nndof = hecmat%N * ndof
1306  npndof_new = hectkt%NP * ndof
1307  num_lagrange = size(slaves4lag)
1308 
1309  !! <SUMMARY>
1310  !! {lag} = [Bs^-T] ( {fs} - [Ksp Kss] {u} )
1311  !!
1312  ! 1. {Btmp} = [Kmat] {X}
1313  hectkt%X(1:nndof) = hecmat%X(1:nndof)
1314  call hecmw_update_r(hecmeshtmp, hectkt%X, hectkt%NP, ndof)
1315  allocate(btmp(npndof))
1316  call hecmw_localmat_mulvec(kmat, hectkt%X, btmp)
1317  !
1318  ! 2. {Btmp_s} = {fs} - {Btmp_s}
1319  btmp(slaves(:)) = btot(slaves(:)) - btmp(slaves(:))
1320  !
1321  ! 3. send internal contact dof => recv external contact dof
1322  ! next line can be: call hecmw_update_R(hecMESH, Btmp, hecMAT%NP, ndof)
1323  call hecmw_contact_comm_bcast_r(concomm, btmp)
1324  !
1325  ! 4. {lag} = [Bs^-T] {Btmp_s}
1326  xlag => hecmat%X(npndof+1:npndof+num_lagrange)
1327  xlag(:)=bus_inv(:)*btmp(slaves4lag(:))
1328  deallocate(btmp)
1329  end subroutine comp_lag
1330 
1333  subroutine check_solution(hecMESH, hecMESHtmp, hecMAT, hecTKT, hecLagMAT, Kmat, Btot, &
1334  conCOMM, slaves)
1335  type(hecmwst_local_mesh), intent(in) :: hecmesh
1336  type(hecmwst_local_mesh), intent(in) :: hecmeshtmp
1337  type(hecmwst_matrix), intent(inout) :: hecmat
1338  type(hecmwst_matrix), intent(inout) :: hectkt
1339  type(hecmwst_matrix_lagrange) , intent(in) :: heclagmat
1340  type(hecmwst_local_matrix), intent(in) :: kmat
1341  real(kind=kreal), target, intent(in) :: btot(:)
1342  type(hecmwst_contact_comm), intent(in) :: concomm
1343  integer(kind=kint), intent(in) :: slaves(:)
1344  !
1345  integer(kind=kint) :: ndof, nndof, npndof, num_lagrange, i, ls, le, l, j, idof, jdof
1346  real(kind=kreal), allocatable, target :: r(:)
1347  real(kind=kreal), allocatable :: btmp(:)
1348  real(kind=kreal), pointer :: rlag(:), blag(:), xlag(:)
1349  real(kind=kreal) :: rnrm2, rlagnrm2
1350  real(kind=kreal) :: bnrm2, blagnrm2
1351  integer(kind=kint) :: myrank
1352 
1353  myrank = hecmw_comm_get_rank()
1354  ndof = hecmat%NDOF
1355  nndof = hecmat%N * ndof
1356  npndof = hecmat%NP * ndof
1357  num_lagrange = heclagmat%num_lagrange
1358  !
1359  allocate(r(npndof + num_lagrange), source=0.0d0)
1360  allocate(btmp(npndof))
1361  !
1362  rlag => r(npndof+1:npndof+num_lagrange)
1363  blag => btot(npndof+1:npndof+num_lagrange)
1364  xlag => hecmat%X(npndof+1:npndof+num_lagrange)
1365  !
1366  !! {r} = {b} - [K] {x} - [Bt] {lag}
1367  !! {rlag} = {c} - [B] {x}
1368  !
1369  ! {r} = {b} - [K] {x}
1370  do i = 1, nndof
1371  hectkt%X(i) = hecmat%X(i)
1372  enddo
1373  call hecmw_update_r(hecmeshtmp, hectkt%X, hectkt%NP, ndof)
1374  call hecmw_localmat_mulvec(kmat, hectkt%X, btmp)
1375  do i = 1, nndof
1376  r(i) = btot(i) - btmp(i)
1377  enddo
1378  !
1379  ! {r} = {r} - [Bt] {lag}
1380  btmp(:) = 0.0d0
1381  if (heclagmat%num_lagrange > 0) then
1382  do i = 1, hecmat%NP
1383  ls = heclagmat%indexU_lagrange(i-1)+1
1384  le = heclagmat%indexU_lagrange(i)
1385  do l = ls, le
1386  j = heclagmat%itemU_lagrange(l)
1387  do idof = 1, ndof
1388  btmp(ndof*(i-1)+idof) = btmp(ndof*(i-1)+idof) + heclagmat%AU_lagrange(ndof*(l-1)+idof) * xlag(j)
1389  enddo
1390  enddo
1391  enddo
1392  endif
1393  ! next line can be: call hecmw_assemble_R(hecMESH, Btmp, hecMAT%NP, ndof)
1394  call hecmw_contact_comm_reduce_r(concomm, btmp, hecmw_sum)
1395  do i = 1, nndof
1396  r(i) = r(i) - btmp(i)
1397  enddo
1398  !
1399  ! {rlag} = {c} - [B] {x}
1400  call hecmw_update_r(hecmesh, hecmat%X, hecmat%NP, ndof)
1401  do i = 1, num_lagrange
1402  rlag(i) = blag(i)
1403  ls = heclagmat%indexL_lagrange(i-1)+1
1404  le = heclagmat%indexL_lagrange(i)
1405  do l = ls, le
1406  j = heclagmat%itemL_lagrange(l)
1407  do jdof = 1, ndof
1408  rlag(i) = rlag(i) - heclagmat%AL_lagrange(ndof*(l-1)+jdof) * hecmat%X(ndof*(j-1)+jdof)
1409  enddo
1410  enddo
1411  enddo
1412  !
1413  ! residual in original system
1414  if (debug_vector) call debug_write_vector(r, 'Residual', 'R', ndof, hecmat%N, &
1415  hecmat%NP, .false., heclagmat%num_lagrange, slaves)
1416  !
1417  call hecmw_innerproduct_r(hecmesh, ndof, r, r, rnrm2)
1418  call hecmw_innerproduct_r(hecmesh, ndof, btot, btot, bnrm2)
1419  rlagnrm2 = dot_product(rlag, rlag)
1420  call hecmw_allreduce_r1(hecmesh, rlagnrm2, hecmw_sum)
1421  blagnrm2 = dot_product(blag, blag)
1422  call hecmw_allreduce_r1(hecmesh, blagnrm2, hecmw_sum)
1423  !
1424  if (myrank == 0) then
1425  write(0,*) 'INFO: resid(x,lag,tot)',sqrt(rnrm2),sqrt(rlagnrm2),sqrt(rnrm2+rlagnrm2)
1426  write(0,*) 'INFO: rhs (x,lag,tot)',sqrt(bnrm2),sqrt(blagnrm2),sqrt(bnrm2+blagnrm2)
1427  endif
1428  end subroutine check_solution
1429 
1432  subroutine check_solution2(hecMESH, hecMAT, conMAT, hecLagMAT, conCOMM, slaves)
1433  implicit none
1434  type(hecmwst_local_mesh), intent(in) :: hecmesh
1435  type(hecmwst_matrix), intent(inout) :: hecmat
1436  type(hecmwst_matrix), intent(in) :: conmat
1437  type(hecmwst_matrix_lagrange) , intent(in) :: heclagmat
1438  type(hecmwst_contact_comm), intent(in) :: concomm
1439  integer(kind=kint), intent(in) :: slaves(:)
1440  !
1441  integer(kind=kint) :: ndof, ndof2, nndof, npndof, num_lagrange
1442  integer(kind=kint) :: i, idof, j, jdof, ls, le, l
1443  integer(kind=kint) :: irow, js, je, jcol
1444  real(kind=kreal), allocatable, target :: r(:)
1445  real(kind=kreal), allocatable :: r_con(:)
1446  real(kind=kreal), pointer :: rlag(:), blag(:), xlag(:)
1447  real(kind=kreal) :: rnrm2, rlagnrm2
1448  integer(kind=kint) :: myrank
1449 
1450  myrank = hecmw_comm_get_rank()
1451  ndof = hecmat%NDOF
1452  ndof2 = ndof*ndof
1453  nndof = hecmat%N * ndof
1454  npndof = hecmat%NP * ndof
1455  num_lagrange = heclagmat%num_lagrange
1456  !
1457  allocate(r(npndof + num_lagrange))
1458  r(:) = 0.0d0
1459  allocate(r_con(npndof))
1460  r_con(:) = 0.0d0
1461  !
1462  rlag => r(npndof+1:npndof+num_lagrange)
1463  blag => conmat%B(npndof+1:npndof+num_lagrange)
1464  xlag => hecmat%X(npndof+1:npndof+num_lagrange)
1465  !
1466  !! <SUMMARY>
1467  !! {r} = {b} - [K] {x} - [Bt] {lag}
1468  !! {rlag} = {c} - [B] {x}
1469  !
1470  ! 1. {r} = {r_org} + {r_con}
1471  ! {r_org} = {b_org} - [hecMAT] {x}
1472  ! {r_con} = {b_con} - [conMAT] {x} - [Bt] {lag}
1473  !
1474  ! 1.1 {r_org}
1475  ! {r} = {b} - [K] {x}
1476  call hecmw_matresid(hecmesh, hecmat, hecmat%X, hecmat%B, r)
1477  !
1478  if (debug_vector) call debug_write_vector(r, 'Residual(original)', 'R', ndof, hecmat%N, &
1479  hecmat%NP, .false., num_lagrange, slaves)
1480  !
1481  ! 1.2 {r_con}
1482  ! 1.2.1 {r_con} = {b_con} - [conMAT]{x}
1483  ! Note: compute not only internal DOFs but also external DOFs, locally
1484  ! !call hecmw_update_3_R(hecMESH, hecMAT%X, hecMAT%NP) ! X is already updated
1485  do i = 1, npndof
1486  r_con(i) = conmat%B(i)
1487  enddo
1488  do irow = 1,hecmat%NP
1489  ! lower
1490  js = conmat%indexL(irow-1)+1
1491  je = conmat%indexL(irow)
1492  do j = js, je
1493  jcol = conmat%itemL(j)
1494  do idof = 1, ndof
1495  i = ndof*(irow-1)+idof
1496  do jdof = 1, ndof
1497  r_con(i) = r_con(i) - conmat%AL(ndof2*(j-1)+ndof*(idof-1)+jdof) * hecmat%X(ndof*(jcol-1)+jdof)
1498  enddo
1499  enddo
1500  enddo
1501  ! diag
1502  do idof = 1, ndof
1503  i = ndof*(irow-1)+idof
1504  do jdof = 1, ndof
1505  r_con(i) = r_con(i) - conmat%D(ndof2*(irow-1)+ndof*(idof-1)+jdof) * hecmat%X(ndof*(irow-1)+jdof)
1506  enddo
1507  enddo
1508  ! upper
1509  js = conmat%indexU(irow-1)+1
1510  je = conmat%indexU(irow)
1511  do j = js, je
1512  jcol = conmat%itemU(j)
1513  do idof = 1, ndof
1514  i = ndof*(irow-1)+idof
1515  do jdof = 1, ndof
1516  r_con(i) = r_con(i) - conmat%AU(ndof2*(j-1)+ndof*(idof-1)+jdof) * hecmat%X(ndof*(jcol-1)+jdof)
1517  enddo
1518  enddo
1519  enddo
1520  end do
1521  !
1522  ! 1.2.2 {r_con} = {r_con} - [Bt] {lag}
1523  if (num_lagrange > 0) then
1524  do i = 1, hecmat%NP
1525  ls = heclagmat%indexU_lagrange(i-1)+1
1526  le = heclagmat%indexU_lagrange(i)
1527  do l = ls, le
1528  j = heclagmat%itemU_lagrange(l)
1529  do idof = 1, ndof
1530  r_con(ndof*(i-1)+idof) = r_con(ndof*(i-1)+idof) - heclagmat%AU_lagrange(ndof*(l-1)+idof) * xlag(j)
1531  enddo
1532  enddo
1533  enddo
1534  endif
1535  !
1536  if (debug_vector) call debug_write_vector(r, 'Residual(contact,local)', 'R_con', ndof, hecmat%N, &
1537  hecmat%NP, .true., num_lagrange, slaves)
1538  !
1539  ! 1.2.3 send external part of {r_con}
1540  call hecmw_contact_comm_reduce_r(concomm, r_con, hecmw_sum)
1541  !
1542  if (debug_vector) call debug_write_vector(r, 'Residual(contact,assembled)', 'R_con', ndof, hecmat%N, &
1543  hecmat%NP, .false., num_lagrange, slaves)
1544  !
1545  ! 1.3 {r} = {r_org} + {r_con}
1546  do i = 1,nndof
1547  r(i) = r(i) + r_con(i)
1548  enddo
1549  !
1550  if (debug_vector) call debug_write_vector(r, 'Residual(total)', 'R', ndof, hecmat%N, &
1551  hecmat%NP, .false., num_lagrange, slaves)
1552  !
1553  ! 2. {rlag} = {c} - [B] {x}
1554  !call hecmw_update_3_R(hecMESH, hecMAT%X, hecMAT%NP) ! X is already updated
1555  do i = 1, num_lagrange
1556  rlag(i) = blag(i)
1557  ls = heclagmat%indexL_lagrange(i-1)+1
1558  le = heclagmat%indexL_lagrange(i)
1559  do l = ls, le
1560  j = heclagmat%itemL_lagrange(l)
1561  do jdof = 1, ndof
1562  rlag(i) = rlag(i) - heclagmat%AL_lagrange(ndof*(l-1)+jdof) * hecmat%X(ndof*(j-1)+jdof)
1563  enddo
1564  enddo
1565  enddo
1566  !
1567  if (debug_vector) then
1568  write(1000+myrank,*) 'Residual(lagrange)-----------------------------------------------------'
1569  if (num_lagrange > 0) then
1570  write(1000+myrank,*) 'R(lag):',npndof+1,'-',npndof+num_lagrange
1571  write(1000+myrank,*) r(npndof+1:npndof+num_lagrange)
1572  endif
1573  endif
1574  !
1575  call hecmw_innerproduct_r(hecmesh, ndof, r, r, rnrm2)
1576  rlagnrm2 = dot_product(rlag, rlag)
1577  call hecmw_allreduce_r1(hecmesh, rlagnrm2, hecmw_sum)
1578  !
1579  if (myrank == 0) write(0,*) 'INFO: resid(x,lag,tot)',sqrt(rnrm2),sqrt(rlagnrm2),sqrt(rnrm2+rlagnrm2)
1580  end subroutine check_solution2
1581 
1584  subroutine debug_write_matrix(Mat, label)
1585  type(hecmwst_local_matrix), intent(in) :: mat
1586  character(len=*), intent(in) :: label
1587  !
1588  integer(kind=kint) :: myrank
1589 
1590  myrank = hecmw_comm_get_rank()
1591  write(1000+myrank,*) trim(label),'============================================================'
1592  call hecmw_localmat_write(mat, 1000+myrank)
1593  end subroutine debug_write_matrix
1594 
1597  subroutine debug_write_vector(Vec, label, name, ndof, N, &
1598  NP, write_ext, num_lagrange, slaves)
1599  real(kind=kreal), intent(in) :: vec(:)
1600  character(len=*), intent(in) :: label
1601  character(len=*), intent(in) :: name
1602  integer(kind=kint), intent(in) :: ndof
1603  integer(kind=kint), intent(in) :: n
1604  integer(kind=kint), intent(in), optional :: np
1605  logical, intent(in), optional :: write_ext
1606  integer(kind=kint), intent(in), optional :: num_lagrange
1607  integer(kind=kint), intent(in), optional :: slaves(:)
1608  !
1609  integer(kind=kint) :: myrank
1610 
1611  myrank = hecmw_comm_get_rank()
1612  write(1000+myrank,*) trim(label),'------------------------------------------------------------'
1613  write(1000+myrank,*) 'size of ',trim(name),size(vec)
1614  write(1000+myrank,*) trim(name),': 1-',n*ndof
1615  write(1000+myrank,*) vec(1:n*ndof)
1616  if (present(write_ext) .and. present(np)) then
1617  if (write_ext) then
1618  write(1000+myrank,*) trim(name),'(external): ',n*ndof+1,'-',np*ndof
1619  write(1000+myrank,*) vec(n*ndof+1:np*ndof)
1620  endif
1621  endif
1622  if (present(num_lagrange) .and. present(np)) then
1623  if (num_lagrange > 0) then
1624  write(1000+myrank,*) trim(name),'(lag):',np*ndof+1,'-',np*ndof+num_lagrange
1625  write(1000+myrank,*) vec(np*ndof+1:np*ndof+num_lagrange)
1626  endif
1627  endif
1628  if (present(slaves)) then
1629  if (size(slaves) > 0) then
1630  write(1000+myrank,*) trim(name),'(slave):',slaves(:)
1631  write(1000+myrank,*) vec(slaves(:))
1632  endif
1633  endif
1634  end subroutine debug_write_vector
1635 
1636 end module m_solve_lineq_contact_elim
Essential boundary conditions kept as per-DOF marks and values so that they can be imposed on the mat...
subroutine, public hecmw_ebc_apply(hecMESH, hecMAT, hecEBC, conMAT)
subroutine, public hecmw_localmat_init_with_hecmat(BKmat, hecMAT, num_lagrange)
subroutine, public hecmw_localmat_free(Tmat)
subroutine, public hecmw_localmat_add(Amat, Bmat, Cmat)
subroutine, public hecmw_localmat_multmat(BKmat, BTmat, hecMESH, BKTmat)
subroutine, public hecmw_localmat_mulvec(BTmat, V, TV)
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_localmat_assemble(BTmat, hecMESH, hecMESHnew)
subroutine, public hecmw_localmat_add_hecmat(BKmat, hecMAT)
integer(kind=kint) function, public hecmw_mat_get_solver_type(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_flag_diverged(hecMAT)
subroutine, public hecmw_mat_init(hecMAT)
subroutine, public hecmw_mat_finalize(hecMAT)
subroutine, public hecmw_mat_set_flag_diverged(hecMAT, flag_diverged)
subroutine, public hecmw_mat_set_flag_converged(hecMAT, flag_converged)
integer(kind=kint) function, public hecmw_mat_get_flag_converged(hecMAT)
subroutine, public hecmw_mat_set_method(hecMAT, method)
integer(kind=kint) function, public hecmw_mat_get_method(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_precond(hecMAT)
subroutine, public hecmw_mat_set_precond(hecMAT, precond)
subroutine, public hecmw_mpc_tback_sol(hecMESH, hecMAT, hecMATmpc)
subroutine, public hecmw_mpc_mat_init(hecMESH, hecMAT, hecMESHmpc, hecMATmpc, conMAT, conMATmpc)
subroutine, public hecmw_mpc_mat_ass(hecMESH, hecMAT, hecMESHmpc, hecMATmpc, conMAT, conMATmpc, hecLagMAT)
subroutine, public hecmw_mpc_mat_finalize(hecMESH, hecMAT, hecMESHmpc, hecMATmpc, conMATmpc)
subroutine, public hecmw_mpc_trans_rhs(hecMESH, hecMAT, hecMATmpc)
subroutine, public hecmw_matresid(hecMESH, hecMAT, X, B, R, COMMtime)
subroutine hecmw_innerproduct_r(hecMESH, ndof, X, Y, sum, COMMtime)
subroutine hecmw_solve(hecMESH, hecMAT)
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=kint), parameter hecmw_sum
integer(kind=kint) function hecmw_comm_get_size()
integer(kind=kint), parameter hecmw_max
integer(kind=4), parameter kreal
integer(kind=kint) function hecmw_comm_get_rank()
real(kind=kreal) function hecmw_wtime()
subroutine hecmw_assemble_r(hecMESH, val, n, m)
subroutine hecmw_update_r(hecMESH, val, n, m)
subroutine hecmw_allreduce_i1(hecMESH, s, ntag)
subroutine hecmw_assemble_i(hecMESH, val, n, m)
subroutine hecmw_allreduce_r1(hecMESH, s, ntag)
subroutine, public hecmw_contact_comm_reduce_r(conComm, vec, op)
subroutine, public hecmw_contact_comm_bcast_r(conComm, vec)
subroutine, public hecmw_contact_comm_init(conComm, hecMESH, ndof, n_contact_dof, contact_dofs)
subroutine, public hecmw_contact_comm_finalize(conComm)
This module provides interface of iteratie linear equation solver for contact problems using Lagrange...
subroutine, public solve_lineq_contact_elim_init(hecMESH, hecMAT, hecLagMAT, is_sym)
subroutine, public solve_lineq_contact_elim(hecMESH, hecMAT, hecLagMAT, hecEBC, istat, conMAT, is_contact_active)
Structure for Lagrange multiplier-related part of stiffness matrix (Lagrange multiplier-related matri...