FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
solve_LINEQ_mf_contact.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2026 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
8  use hecmw_util
14  use hecmw_ebc_defer
15 
16  private
18  public :: solve_lineq_mf_contact
19 
20  logical, save :: INITIALIZED = .false.
21  logical, save :: NEED_ANALYSIS = .true.
22  logical, save :: IS_SYMMETRIC = .true.
26  type (hecmwST_matrix), save :: mfMAT
27 
30  integer(kind=kint), parameter :: MFC_IR_STEPS = 5
31  real(kind=kreal), parameter :: mfc_ir_tol = 1.0d-8
32 
33 contains
34 
35  subroutine solve_lineq_mf_contact_init(hecMESH,hecMAT,hecLagMAT,is_sym)
36  implicit none
37  type (hecmwst_local_mesh), intent(in) :: hecmesh
38  type (hecmwst_matrix), intent(inout) :: hecmat
39  type (hecmwst_matrix_lagrange), intent(in) :: heclagmat
40  logical, intent(in) :: is_sym
41 
42  if (initialized) then
43  call hecmw_mat_finalize(mfmat)
44  initialized = .false.
45  endif
46  call hecmw_mat_init(mfmat)
47  is_symmetric = is_sym
48  need_analysis = .true.
49  initialized = .true.
50  end subroutine solve_lineq_mf_contact_init
51 
52  subroutine solve_lineq_mf_contact(hecMESH,hecMAT,hecLagMAT,hecEBC,istat)
53  implicit none
54  type (hecmwst_local_mesh), intent(inout) :: hecmesh
55  type (hecmwst_matrix), intent(inout) :: hecmat
56  type (hecmwst_matrix_lagrange), intent(inout) :: heclagmat
57  type (hecmwst_ebc), intent(inout) :: hecebc
58  integer(kind=kint), intent(out) :: istat
59  integer(kind=kint) :: ntdf, mpc_method, iterlog, timelog, irmax, it
60  real(kind=kreal) :: bnrm, rnrm, rprev, irtol, t1, t2
61  real(kind=kreal), allocatable :: bb(:), xx(:), rr(:), xp(:)
62  ! the unit hecmw_solve passes to the direct solvers for error messages
63  integer(kind=kint), parameter :: imsg = 51
64 
65  mpc_method = hecmw_mat_get_mpc_method(hecmat)
66  if (mpc_method < 1 .or. 3 < mpc_method) then
67  mpc_method = 1
68  call hecmw_mat_set_mpc_method(hecmat,mpc_method)
69  endif
70  if (mpc_method /= 1) then
71  write(*,*) 'ERROR: MPCMETHOD other than penalty is not available for DIRECTmf solver', &
72  ' in contact analysis without elimination'
73  stop
74  endif
75  call hecmw_mat_ass_equation(hecmesh, hecmat)
76  call hecmw_mat_ass_equation_rhs(hecmesh, hecmat)
77  call hecmw_ebc_apply(hecmesh, hecmat, hecebc)
78 
79  call hecmw_mat_dump(hecmat, hecmesh)
80 
81  if (need_analysis) then
82  call mf_contact_set_profile(hecmat, heclagmat)
83  need_analysis = .false.
84  endif
85 
86  call mf_contact_set_values(hecmat, heclagmat)
87  ntdf = hecmat%NP*hecmat%NDOF + heclagmat%num_lagrange
88  mfmat%B(1:ntdf) = hecmat%B(1:ntdf)
89  mfmat%X(1:ntdf) = 0.0d0
90  mfmat%Iarray(97) = 1
91  mfmat%symmetric = is_symmetric
92 
93  call hecmw_solve_direct_mf(hecmesh, mfmat, imsg)
94  istat = 0
95 
96  ! refine on the saddle-point system itself: the refinement of the driver measures its
97  ! norms through the mesh, which does not cover the Lagrange rows
98  irmax = hecmat%Iarray(44)
99  if (irmax == 0) irmax = mfc_ir_steps
100  if (irmax > 0) then
101  iterlog = hecmw_mat_get_iterlog(hecmat)
102  timelog = hecmw_mat_get_timelog(hecmat)
103  irtol = hecmat%Rarray(42)
104  if (.not. (irtol > 0.0d0)) irtol = mfc_ir_tol
105  allocate(bb(ntdf), xx(ntdf), rr(ntdf), xp(ntdf))
106  bb(1:ntdf) = mfmat%B(1:ntdf)
107  xx(1:ntdf) = mfmat%X(1:ntdf)
108  bnrm = sqrt(dot_product(bb(1:ntdf), bb(1:ntdf)))
109  t1 = hecmw_wtime()
110  rprev = huge(rprev)
111  do it = 1, irmax
112  call mf_contact_resid(ntdf, xx, bb, rr)
113  rnrm = sqrt(dot_product(rr(1:ntdf), rr(1:ntdf))) / max(bnrm, tiny(bnrm))
114  if (iterlog > 0) write(*,'(a,i0,a,1pe11.4)') '[DIRECTmf]: refinement ', it - 1, ': residual = ', rnrm
115  if (rnrm <= irtol) exit
116  ! a step that grew the residual would hand back a worse solution than it got,
117  ! so the step is undone and the sweep stops with a warning
118  if (rnrm > rprev) then
119  xx(1:ntdf) = xp(1:ntdf)
120  write(*,'(a,1pe11.4)') '[DIRECTmf]: WARNING: refinement diverged, reverted to residual = ', rprev
121  exit
122  endif
123  rprev = rnrm
124  xp(1:ntdf) = xx(1:ntdf)
125  mfmat%B(1:ntdf) = rr(1:ntdf)
126  call hecmw_solve_direct_mf(hecmesh, mfmat, imsg)
127  xx(1:ntdf) = xx(1:ntdf) + mfmat%X(1:ntdf)
128  enddo
129  t2 = hecmw_wtime()
130  if (timelog > 0) write(*,'(a,f10.3,a)') '[DIRECTmf]: refinement done (', t2 - t1, ' sec)'
131  mfmat%X(1:ntdf) = xx(1:ntdf)
132  deallocate(bb, xx, rr, xp)
133  endif
134 
135  hecmat%X(1:ntdf) = mfmat%X(1:ntdf)
136 
137  call hecmw_mat_dump_solution(hecmat)
138  end subroutine solve_lineq_mf_contact
139 
144  subroutine mf_contact_set_profile(hecMAT, hecLagMAT)
145  implicit none
146  type (hecmwst_matrix), intent(in) :: hecmat
147  type (hecmwst_matrix_lagrange), intent(in) :: heclagmat
148  integer(kind=kint) :: np, ndof, nlag, ntdf, npl, npu
149  integer(kind=kint) :: i, j, k, l, cl, cu
150 
151  np = hecmat%NP
152  ndof = hecmat%NDOF
153  nlag = heclagmat%num_lagrange
154  ntdf = np*ndof + nlag
155  npl = hecmat%NPL*ndof*ndof + np*ndof*(ndof-1)/2
156  npu = hecmat%NPU*ndof*ndof + np*ndof*(ndof-1)/2
157  if (nlag > 0) then
158  npl = npl + heclagmat%numL_lagrange*ndof
159  npu = npu + heclagmat%numU_lagrange*ndof
160  endif
161 
162  call hecmw_mat_finalize(mfmat)
163  mfmat%N = ntdf
164  mfmat%NP = ntdf
165  mfmat%NDOF = 1
166  mfmat%NPL = npl
167  mfmat%NPU = npu
168  allocate(mfmat%indexL(0:ntdf), mfmat%indexU(0:ntdf))
169  allocate(mfmat%itemL(npl), mfmat%itemU(npu))
170  allocate(mfmat%D(ntdf), mfmat%AL(npl), mfmat%AU(npu))
171  allocate(mfmat%B(ntdf), mfmat%X(ntdf))
172 
173  cl = 0
174  cu = 0
175  mfmat%indexL(0) = 0
176  mfmat%indexU(0) = 0
177  do i = 1, np
178  do j = 1, ndof
179  do l = hecmat%indexL(i-1)+1, hecmat%indexL(i)
180  do k = 1, ndof
181  cl = cl + 1
182  mfmat%itemL(cl) = (hecmat%itemL(l)-1)*ndof + k
183  enddo
184  enddo
185  do k = 1, j-1
186  cl = cl + 1
187  mfmat%itemL(cl) = (i-1)*ndof + k
188  enddo
189  do k = j+1, ndof
190  cu = cu + 1
191  mfmat%itemU(cu) = (i-1)*ndof + k
192  enddo
193  do l = hecmat%indexU(i-1)+1, hecmat%indexU(i)
194  do k = 1, ndof
195  cu = cu + 1
196  mfmat%itemU(cu) = (hecmat%itemU(l)-1)*ndof + k
197  enddo
198  enddo
199  if (nlag > 0) then
200  do l = heclagmat%indexU_lagrange(i-1)+1, heclagmat%indexU_lagrange(i)
201  cu = cu + 1
202  mfmat%itemU(cu) = np*ndof + heclagmat%itemU_lagrange(l)
203  enddo
204  endif
205  mfmat%indexL((i-1)*ndof+j) = cl
206  mfmat%indexU((i-1)*ndof+j) = cu
207  enddo
208  enddo
209  do i = 1, nlag
210  do l = heclagmat%indexL_lagrange(i-1)+1, heclagmat%indexL_lagrange(i)
211  do k = 1, ndof
212  cl = cl + 1
213  mfmat%itemL(cl) = (heclagmat%itemL_lagrange(l)-1)*ndof + k
214  enddo
215  enddo
216  mfmat%indexL(np*ndof+i) = cl
217  mfmat%indexU(np*ndof+i) = cu
218  enddo
219 
220  mfmat%Iarray = hecmat%Iarray
221  mfmat%Rarray = hecmat%Rarray
222  if (mfmat%Iarray(43) /= 0) then
223  ! the user asked for BLR, so the fallback is reported regardless of LOGLEVEL
224  if (hecmw_comm_get_rank() == 0) write(*,*) &
225  '[DIRECTmf]: BLR is not available in contact analysis without elimination; disabled'
226  endif
227  ! the refinement stays with the caller (mf_contact_resid); the driver would measure it
228  ! through the mesh
229  mfmat%Iarray(43) = 0
230  mfmat%Iarray(44) = -1
231  mfmat%Iarray(48) = 0
232  mfmat%Iarray(98) = 1
233  end subroutine mf_contact_set_profile
234 
237  subroutine mf_contact_set_values(hecMAT, hecLagMAT)
238  implicit none
239  type (hecmwst_matrix), intent(in) :: hecmat
240  type (hecmwst_matrix_lagrange), intent(in) :: heclagmat
241  integer(kind=kint) :: np, ndof, nlag
242  integer(kind=kint) :: i, j, k, l, cl, cu
243 
244  np = hecmat%NP
245  ndof = hecmat%NDOF
246  nlag = heclagmat%num_lagrange
247 
248  cl = 0
249  cu = 0
250  do i = 1, np
251  do j = 1, ndof
252  do l = hecmat%indexL(i-1)+1, hecmat%indexL(i)
253  do k = 1, ndof
254  cl = cl + 1
255  mfmat%AL(cl) = hecmat%AL(((l-1)*ndof+j-1)*ndof+k)
256  enddo
257  enddo
258  do k = 1, j-1
259  cl = cl + 1
260  mfmat%AL(cl) = hecmat%D(((i-1)*ndof+j-1)*ndof+k)
261  enddo
262  mfmat%D((i-1)*ndof+j) = hecmat%D(((i-1)*ndof+j-1)*ndof+j)
263  do k = j+1, ndof
264  cu = cu + 1
265  mfmat%AU(cu) = hecmat%D(((i-1)*ndof+j-1)*ndof+k)
266  enddo
267  do l = hecmat%indexU(i-1)+1, hecmat%indexU(i)
268  do k = 1, ndof
269  cu = cu + 1
270  mfmat%AU(cu) = hecmat%AU(((l-1)*ndof+j-1)*ndof+k)
271  enddo
272  enddo
273  if (nlag > 0) then
274  do l = heclagmat%indexU_lagrange(i-1)+1, heclagmat%indexU_lagrange(i)
275  cu = cu + 1
276  mfmat%AU(cu) = heclagmat%AU_lagrange((l-1)*ndof+j)
277  enddo
278  endif
279  enddo
280  enddo
281  do i = 1, nlag
282  mfmat%D(np*ndof+i) = 0.0d0
283  do l = heclagmat%indexL_lagrange(i-1)+1, heclagmat%indexL_lagrange(i)
284  do k = 1, ndof
285  cl = cl + 1
286  mfmat%AL(cl) = heclagmat%AL_lagrange((l-1)*ndof+k)
287  enddo
288  enddo
289  enddo
290  end subroutine mf_contact_set_values
291 
293  subroutine mf_contact_resid(ntdf, x, b, r)
294  implicit none
295  integer(kind=kint), intent(in) :: ntdf
296  real(kind=kreal), intent(in) :: x(:), b(:)
297  real(kind=kreal), intent(out) :: r(:)
298  integer(kind=kint) :: i, l
299  real(kind=kreal) :: s
300 
301  do i = 1, ntdf
302  s = mfmat%D(i)*x(i)
303  do l = mfmat%indexL(i-1)+1, mfmat%indexL(i)
304  s = s + mfmat%AL(l)*x(mfmat%itemL(l))
305  enddo
306  do l = mfmat%indexU(i-1)+1, mfmat%indexU(i)
307  s = s + mfmat%AU(l)*x(mfmat%itemU(l))
308  enddo
309  r(i) = b(i) - s
310  enddo
311  end subroutine mf_contact_resid
312 
313 end module m_solve_lineq_mf_contact
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_mat_ass_equation_rhs(hecMESH, hecMAT)
subroutine, public hecmw_mat_ass_equation(hecMESH, hecMAT)
subroutine, public hecmw_mat_dump(hecMAT, hecMESH)
subroutine, public hecmw_mat_dump_solution(hecMAT)
subroutine, public hecmw_mat_init(hecMAT)
subroutine, public hecmw_mat_finalize(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_iterlog(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_timelog(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_mpc_method(hecMAT)
subroutine, public hecmw_mat_set_mpc_method(hecMAT, mpc_method)
Multifrontal direct solver (METHOD=DIRECTmf): LDLt with threshold pivoting for symmetric (possibly in...
subroutine, public hecmw_solve_direct_mf(hecMESH, hecMAT, imsg)
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=4), parameter kreal
integer(kind=kint) function hecmw_comm_get_rank()
real(kind=kreal) function hecmw_wtime()
This module provides linear equation solver interface of DIRECTmf for contact problems using Lagrange...
subroutine, public solve_lineq_mf_contact_init(hecMESH, hecMAT, hecLagMAT, is_sym)
subroutine, public solve_lineq_mf_contact(hecMESH, hecMAT, hecLagMAT, hecEBC, istat)
Structure for Lagrange multiplier-related part of stiffness matrix (Lagrange multiplier-related matri...