FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
surf_ele.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 !-------------------------------------------------------------------------------
9  use hecmw_util
10  use elementinfo
11  use m_utilities
12  use bucket_search
13 
14  implicit none
15 
16  integer(kind=kint), parameter :: l_max_surface_node =20
17  integer(kind=kint), parameter :: l_max_elem_node = 100
18  integer(kind=kint), parameter :: l_max_elem_surf = 6
19 
20  integer(kind=kint), parameter :: n_neighbor_max_init = 8
21 
24  integer(kind=kint) :: eid
25  integer(kind=kint) :: etype
26  integer(kind=kint), pointer :: nodes(:)=>null()
27  integer(kind=kint) :: n_neighbor
28  integer(kind=kint) :: n_neighbor_max
29  integer(kind=kint), pointer :: neighbor(:)=>null()
30  real(kind=kreal) :: reflen
31  real(kind=kreal) :: xavg(3)
32  real(kind=kreal) :: dmax
33  integer(kind=kint) :: bktid
34  real(kind=kreal), pointer :: vertex_normals(:,:)=>null()
35  real(kind=kreal), pointer :: intermediate_points(:,:)=>null()
36  end type tsurfelement
37 
38  integer(kind=kint), parameter, private :: debug = 0
39 
40 contains
41 
43  subroutine initialize_surf( eid, etype, nsurf, surf )
44  integer(kind=kint), intent(in) :: eid
45  integer(kind=kint), intent(in) :: etype
46  integer(kind=kint), intent(in) :: nsurf
47  type(tsurfelement), intent(inout) :: surf
48  integer(kind=kint) :: i, n, outtype, nodes(100)
49  surf%eid = eid
50 
51  if( nsurf > 0 ) then
52  call getsubface( etype, nsurf, outtype, nodes )
53  surf%etype = outtype
54  n=getnumberofnodes( outtype )
55  else !treat 3d master element as it is
56  surf%etype = etype
57  n=getnumberofnodes( etype )
58  do i=1,n
59  nodes(i) = i
60  enddo
61  endif
62  allocate( surf%nodes(n) )
63  surf%nodes(1:n)=nodes(1:n)
64  surf%n_neighbor = 0
65  surf%n_neighbor_max = 0
66  surf%reflen = -1.d0
67  surf%xavg(:) = 0.d0
68  surf%dmax = -1.d0
69  surf%bktID = -1
70  allocate( surf%vertex_normals(3,n) )
71  surf%vertex_normals(:,:) = 0.d0
72  end subroutine
73 
75  subroutine finalize_surf( surf )
76  type(tsurfelement), intent(inout) :: surf
77  if( associated(surf%nodes) ) deallocate( surf%nodes )
78  if( associated(surf%neighbor) ) deallocate( surf%neighbor )
79  if( associated(surf%vertex_normals) ) deallocate( surf%vertex_normals )
80  if( associated(surf%intermediate_points) ) deallocate( surf%intermediate_points )
81  end subroutine
82 
84  subroutine write_surf( file, surf )
85  integer(kind=kint), intent(in) :: file
86  type(tsurfelement), intent(in) :: surf
87  integer(kind=kint) :: i
88  write(file,*) "Element:",surf%eid,"Surface type=",surf%etype
89  if( associated( surf%nodes ) ) &
90  write(file,*) ( surf%nodes(i),i=1,size(surf%nodes) )
91  if( associated( surf%neighbor ) ) &
92  write(file,*) ( surf%neighbor(i),i=1,surf%n_neighbor )
93  end subroutine
94 
96  subroutine find_surface_neighbor( surf, bktDB )
97  type(tsurfelement), intent(inout) :: surf(:)
98  type(bucketdb), intent(in) :: bktDB
99  integer(kind=kint) :: i, j, ii,jj, nd1, nd2, nsurf
100  integer(kind=kint) :: k, oldsize, newsize
101  integer(kind=kint), pointer :: dumarray(:) => null()
102  integer(kind=kint) :: bktID, ncand, js
103  integer(kind=kint), allocatable :: indexSurf(:)
104  if (debug >= 1) write(0,*) 'DEBUG: find_surface_neighbor: start'
105 
106  nsurf = size(surf)
107 
108  !$omp parallel do default(none), &
109  !$omp&private(i,ii,nd1,j,jj,nd2,oldsize,newsize,dumarray,k,bktID,ncand,indexSurf,js), &
110  !$omp&shared(nsurf,surf,bktDB)
111  do i=1,nsurf
112  bktid = bucketdb_getbucketid(bktdb, surf(i)%xavg)
113  ncand = bucketdb_getnumcand(bktdb, bktid)
114  if (ncand == 0) cycle
115  allocate(indexsurf(ncand))
116  call bucketdb_getcand(bktdb, bktid, ncand, indexsurf)
117  jloop: do js=1,ncand
118  j = indexsurf(js)
119  if( i==j ) cycle
120  if( associated(surf(i)%neighbor) ) then
121  if ( any( surf(i)%neighbor(1:surf(i)%n_neighbor)==j ) ) cycle
122  endif
123  do ii=1, size(surf(i)%nodes)
124  nd1 = surf(i)%nodes(ii)
125  do jj=1, size(surf(j)%nodes)
126  nd2 = surf(j)%nodes(jj)
127  if( nd1==nd2 ) then
128  surf(i)%n_neighbor = surf(i)%n_neighbor+1
129 
130  if( .not. associated(surf(i)%neighbor) ) then
131  allocate( surf(i)%neighbor(n_neighbor_max_init) )
132  surf(i)%n_neighbor_max = n_neighbor_max_init
133  surf(i)%neighbor(1) = j
134  else if( surf(i)%n_neighbor > surf(i)%n_neighbor_max ) then
135  oldsize = surf(i)%n_neighbor_max
136  newsize = oldsize * 2
137  dumarray => surf(i)%neighbor
138  allocate( surf(i)%neighbor(newsize) )
139  surf(i)%n_neighbor_max = newsize
140  do k=1,oldsize
141  surf(i)%neighbor(k) = dumarray(k)
142  enddo
143  surf(i)%neighbor(oldsize+1) = j
144  deallocate( dumarray )
145  else
146  surf(i)%neighbor(surf(i)%n_neighbor) = j
147  endif
148 
149  cycle jloop
150  endif
151  enddo
152  enddo
153  enddo jloop
154  deallocate(indexsurf)
155  enddo
156  !$omp end parallel do
157 
158  if (debug >= 1) write(0,*) 'DEBUG: find_surface_neighbor: end'
159  end subroutine
160 
162  integer(kind=kint) function next_position( surf, cpos )
163  type(tsurfelement), intent(in) :: surf
164  real(kind=kreal), intent(in) :: cpos(2)
165 
166  integer(kind=kint) :: i
167  real(kind=kreal) :: maxv(3)
168  next_position = surf%eid
169  if( .not. associated(surf%neighbor) ) return ! do nothing when not initialized
170  maxv(:) = 0.d0
171  select case(surf%etype)
172  case( fe_tri3n, fe_tri6n )
173  if( all(cpos>0.d0) .and. all(cpos<1.d0) ) return
174  if( size(surf%neighbor)<3 ) return
175  if( all(cpos(:)>0.d0) ) return
176  do i=1,3
177  if( cpos(i)< 0.d0 ) maxv(i) = -cpos(i)
178  enddo
179  next_position = maxloc(maxv,1)
180  case( fe_quad4n, fe_quad8n )
181  if( all(cpos>-1.d0) .and. all(cpos<1.d0) ) return
182  if( size(surf%neighbor)<4 ) return
183  if( cpos(1)<-1.d0 .and. dabs(cpos(2))<1.d0 ) then
184  next_position = 1
185  elseif( cpos(1)>1.d0 .and. dabs(cpos(2))<1.d0 ) then
186  next_position = 3
187  elseif( dabs(cpos(1))<1.d0 .and. cpos(2)<-1.d0 ) then
188  next_position = 2
189  elseif( dabs(cpos(1))<1.d0 .and. cpos(2)>1.d0 ) then
190  next_position = 4
191  elseif( cpos(1)<-1.d0 .and. cpos(2)<-1.d0 ) then
192  if( cpos(1)>cpos(2) ) then
193  next_position = 2
194  else
195  next_position = 1
196  endif
197  elseif( cpos(1)<-1.d0 .and. cpos(2)>1.d0 ) then
198  if( dabs(cpos(1))>cpos(2) ) then
199  next_position = 1
200  else
201  next_position = 4
202  endif
203  elseif( cpos(1)>1.d0 .and. cpos(2)<-1.d0 ) then
204  if( cpos(1)>dabs(cpos(2)) ) then
205  next_position = 3
206  else
207  next_position = 2
208  endif
209  elseif( cpos(1)>1.d0 .and. cpos(2)>1.d0 ) then
210  if( cpos(1)>cpos(2) ) then
211  next_position = 3
212  else
213  next_position = 4
214  endif
215  endif
216  case default
217  stop "type of surface element not defined"
218  end select
219  next_position = surf%neighbor( next_position )
220 
221  end function next_position
222 
224  subroutine update_surface_reflen( surf, coord )
225  type(tsurfelement), intent(inout) :: surf(:)
226  real(kind=kreal), intent(in) :: coord(:)
227  real(kind=kreal) :: elem(3, l_max_surface_node), r0(2)
228  integer(kind=kint) :: nn, i, j, iss
229  !$omp parallel do default(none) private(j,nn,i,iss,elem,r0) shared(surf,coord)
230  do j=1,size(surf)
231  nn = size(surf(j)%nodes)
232  do i=1,nn
233  iss = surf(j)%nodes(i)
234  elem(1:3,i) = coord(3*iss-2:3*iss)
235  enddo
236  call getelementcenter( surf(j)%etype, r0 )
237  surf(j)%reflen = getreferencelength( surf(j)%etype, nn, r0, elem )
238  enddo
239  !$omp end parallel do
240  end subroutine update_surface_reflen
241 
243  subroutine update_surface_box_info( surf, currpos )
244  type(tsurfelement), intent(inout) :: surf(:)
245  real(kind=kreal), intent(in) :: currpos(:)
246  integer(kind=kint) :: nn, i, j, iss
247  real(kind=kreal) :: elem(3,l_max_surface_node),xmin(3), xmax(3), xsum(3), lx(3)
248  !$omp parallel do default(none) private(i,nn,iss,elem,xmin,xmax,xsum,lx) shared(surf,currpos)
249  do j=1, size(surf)
250  nn = size(surf(j)%nodes)
251  do i=1,nn
252  iss = surf(j)%nodes(i)
253  elem(1:3,i) = currpos(3*iss-2:3*iss)
254  enddo
255  do i=1,3
256  xmin(i) = minval(elem(i,1:nn))
257  xmax(i) = maxval(elem(i,1:nn))
258  xsum(i) = sum(elem(i,1:nn))
259  enddo
260  surf(j)%xavg(:) = xsum(:) / nn
261  lx(:) = xmax(:) - xmin(:)
262  surf(j)%dmax = maxval(lx) * 0.5d0
263  enddo
264  !$omp end parallel do
265  end subroutine update_surface_box_info
266 
268  logical function is_in_surface_box(surf, x0, exp_rate)
269  type(tsurfelement), intent(inout) :: surf
270  real(kind=kreal), intent(in) :: x0(3)
271  real(kind=kreal), intent(in) :: exp_rate
272  real(kind=kreal) :: dist(3), er
273  er = max(exp_rate, 1.d0)
274  dist(:) = abs(x0(:) - surf%xavg(:))
275  if ( maxval(dist(:)) < surf%dmax * er ) then
276  is_in_surface_box = .true.
277  else
278  is_in_surface_box = .false.
279  endif
280  end function is_in_surface_box
281 
283  subroutine update_surface_bucket_info(surf, bktDB)
284  type(tsurfelement), intent(inout) :: surf(:)
285  type(bucketdb), intent(inout) :: bktDB
286  real(kind=kreal) :: x_min(3), x_max(3), d_max
287  integer(kind=kint) :: nsurf, i, j
288  if (debug >= 1) write(0,*) 'DEBUG: update_surface_bucket_info: start'
289  nsurf = size(surf)
290  if (nsurf == 0) return
291  x_min(:) = surf(1)%xavg(:)
292  x_max(:) = surf(1)%xavg(:)
293  d_max = surf(1)%dmax*2.d0
294  do i = 2, nsurf
295  do j = 1, 3
296  if (surf(i)%xavg(j) < x_min(j)) x_min(j) = surf(i)%xavg(j)
297  if (surf(i)%xavg(j) > x_max(j)) x_max(j) = surf(i)%xavg(j)
298  if (surf(i)%dmax > d_max) d_max = surf(i)%dmax
299  enddo
300  enddo
301  do j = 1, 3
302  x_min(j) = x_min(j) - d_max
303  x_max(j) = x_max(j) + d_max
304  enddo
305  call bucketdb_setup(bktdb, x_min, x_max, d_max, nsurf)
306  !$omp parallel do default(none) private(i) shared(nsurf,surf,bktDB)
307  do i = 1, nsurf
308  surf(i)%bktID = bucketdb_getbucketid(bktdb, surf(i)%xavg)
309  call bucketdb_registerpre(bktdb, surf(i)%bktID)
310  enddo
311  !$omp end parallel do
312  call bucketdb_allocate(bktdb)
313  do i = 1, nsurf
314  call bucketdb_register(bktdb, surf(i)%bktID, i)
315  enddo
316  if (debug >= 1) write(0,*) 'DEBUG: update_surface_bucket_info: end'
317  end subroutine update_surface_bucket_info
318 
320  subroutine calc_surf_vertex_normals( surf, elem )
322  type(tsurfelement), intent(inout) :: surf
323  real(kind=kreal), intent(in) :: elem(3,*)
324 
325  integer(kind=kint) :: j, nn, etype
326  real(kind=kreal) :: cnpos(2), normal(3)
327 
328  etype = surf%etype
329  nn = size(surf%nodes)
330 
331  do j = 1, nn
332  call getvertexcoord(etype, j, cnpos)
333  normal = surfacenormal(etype, nn, cnpos, elem)
334  normal = normal / dsqrt(dot_product(normal, normal))
335  surf%vertex_normals(:, j) = normal
336  enddo
337 
338  end subroutine calc_surf_vertex_normals
339 
341  subroutine calc_all_surf_vertex_normals( surf, currpos )
342  type(tsurfelement), intent(inout) :: surf(:)
343  real(kind=kreal), intent(in) :: currpos(:)
344 
345  integer(kind=kint) :: i, j, nn, iss
346  real(kind=kreal) :: elem(3, l_max_elem_node)
347 
348  !$omp parallel do default(none) private(i,j,nn,iSS,elem) shared(surf,currpos)
349  do i = 1, size(surf)
350  nn = size(surf(i)%nodes)
351  do j = 1, nn
352  iss = surf(i)%nodes(j)
353  elem(1:3, j) = currpos(3*iss-2:3*iss)
354  enddo
355  call calc_surf_vertex_normals(surf(i), elem(1:3,1:nn))
356  enddo
357  !$omp end parallel do
358 
359  end subroutine calc_all_surf_vertex_normals
360 
361 end module msurfelement
This module provides bucket-search functionality It provides definition of bucket info and its access...
subroutine, public bucketdb_allocate(bktdb)
Allocate memory before actually registering members Before allocating memory, bucketDB_registerPre ha...
subroutine, public bucketdb_registerpre(bktdb, bid)
Pre-register for just counting members to be actually registered Bucket ID has to be obtained with bu...
integer(kind=kint) function, public bucketdb_getbucketid(bktdb, x)
Get bucket ID that includes given point.
subroutine, public bucketdb_register(bktdb, bid, sid)
Register member Before actually register, bucketDB_allocate has to be called.
integer(kind=kint) function, public bucketdb_getnumcand(bktdb, bid)
Get number of candidates within neighboring buckets of a given bucket Bucket ID has to be obtained wi...
subroutine, public bucketdb_getcand(bktdb, bid, ncand, cand)
Get candidates within neighboring buckets of a given bucket Number of candidates has to be obtained w...
subroutine, public bucketdb_setup(bktdb, x_min, x_max, dmin, n_tot)
Setup basic info of buckets.
This module encapsulate the basic functions of all elements provide by this software.
Definition: element.f90:43
integer(kind=kind(2)) function getnumberofnodes(etype)
Obtain number of nodes of the element.
Definition: element.f90:131
subroutine getelementcenter(fetype, localcoord)
Return natural coordinate of the center of element.
Definition: element.f90:1012
integer, parameter fe_tri6n
Definition: element.f90:70
subroutine getsubface(intype, innumber, outtype, nodes)
Find the definition of surface of the element.
Definition: element.f90:193
subroutine getvertexcoord(fetype, cnode, localcoord)
Get the natural coord of a vertex node.
Definition: element.f90:1143
integer, parameter fe_tri3n
Definition: element.f90:69
integer, parameter fe_quad4n
Definition: element.f90:72
real(kind=kreal) function, dimension(3) surfacenormal(fetype, nn, localcoord, elecoord)
Calculate normal of 3d-surface.
Definition: element.f90:870
real(kind=kreal) function getreferencelength(fetype, nn, localcoord, elecoord)
This function calculates reference length at a point in surface.
Definition: element.f90:1266
integer, parameter fe_quad8n
Definition: element.f90:73
I/O and Utility.
Definition: hecmw_util_f.F90:7
integer(kind=4), parameter kreal
This module provides aux functions.
Definition: utilities.f90:6
This module manages surface elements in 3D It provides basic definition of surface elements (triangla...
Definition: surf_ele.f90:8
subroutine initialize_surf(eid, etype, nsurf, surf)
Initializer.
Definition: surf_ele.f90:44
integer(kind=kint), parameter l_max_elem_node
Definition: surf_ele.f90:17
subroutine calc_surf_vertex_normals(surf, elem)
Compute vertex normals for a single surface element (geometric calculation only)
Definition: surf_ele.f90:321
subroutine update_surface_reflen(surf, coord)
Compute reference length of surface elements.
Definition: surf_ele.f90:225
subroutine write_surf(file, surf)
Write out elemental surface.
Definition: surf_ele.f90:85
subroutine update_surface_box_info(surf, currpos)
Update info of cubic box including surface elements.
Definition: surf_ele.f90:244
integer(kind=kint), parameter l_max_elem_surf
Definition: surf_ele.f90:18
subroutine find_surface_neighbor(surf, bktDB)
Find neighboring surface elements.
Definition: surf_ele.f90:97
integer(kind=kint), parameter n_neighbor_max_init
Definition: surf_ele.f90:20
subroutine update_surface_bucket_info(surf, bktDB)
Update bucket info for searching surface elements.
Definition: surf_ele.f90:284
integer(kind=kint), parameter l_max_surface_node
Definition: surf_ele.f90:16
subroutine finalize_surf(surf)
Memory management subroutine.
Definition: surf_ele.f90:76
logical function is_in_surface_box(surf, x0, exp_rate)
Check if given point is within cubic box including surface element.
Definition: surf_ele.f90:269
subroutine calc_all_surf_vertex_normals(surf, currpos)
Calculate vertex normals for all surface elements (geometric calculation only)
Definition: surf_ele.f90:342
integer(kind=kint) function next_position(surf, cpos)
Tracing next contact position.
Definition: surf_ele.f90:163
Structure to define surface group.
Definition: surf_ele.f90:23