MFC
Exascale flow solver
Loading...
Searching...
No Matches
m_model.fpp.f90
Go to the documentation of this file.
1# 1 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
2!>
3!! @file
4!! @author Henry Le Berre <hberre3@gatech.edu>
5!! @brief Contains module m_model
6
7# 1 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp" 1
8# 1 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp" 1
9# 1 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp" 1
10# 2 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
11# 3 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
12# 4 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
13# 5 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
14# 6 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
15
16# 8 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
17# 9 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
18# 10 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
19
20# 17 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
21
22# 46 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
23
24# 58 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
25
26# 68 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
27
28# 98 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
29
30# 110 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
31
32# 120 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
33! New line at end of file is required for FYPP
34# 2 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp" 2
35# 1 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp" 1
36# 1 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp" 1
37# 2 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
38# 3 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
39# 4 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
40# 5 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
41# 6 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
42
43# 8 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
44# 9 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
45# 10 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
46
47# 17 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
48
49# 46 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
50
51# 58 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
52
53# 68 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
54
55# 98 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
56
57# 110 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
58
59# 120 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
60! New line at end of file is required for FYPP
61# 2 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp" 2
62
63# 4 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
64# 5 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
65# 6 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
66# 7 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
67# 8 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
68
69# 20 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
70
71# 43 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
72
73# 48 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
74
75# 53 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
76
77# 58 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
78
79# 63 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
80
81# 68 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
82
83# 76 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
84
85# 81 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
86
87# 86 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
88
89# 91 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
90
91# 96 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
92
93# 101 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
94
95# 106 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
96
97# 111 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
98
99# 116 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
100
101# 121 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
102
103# 151 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
104
105# 192 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
106
107# 207 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
108
109# 232 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
110
111# 243 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
112
113# 245 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
114# 255 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
115
116# 283 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
117
118# 293 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
119
120# 303 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
121
122# 312 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
123
124# 329 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
125
126# 339 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
127
128# 346 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
129
130# 352 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
131
132# 358 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
133
134# 364 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
135
136# 370 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
137
138# 376 "/home/runner/work/MFC/MFC/src/common/include/omp_macros.fpp"
139! New line at end of file is required for FYPP
140# 3 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp" 2
141# 1 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp" 1
142# 1 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp" 1
143# 2 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
144# 3 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
145# 4 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
146# 5 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
147# 6 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
148
149# 8 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
150# 9 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
151# 10 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
152
153# 17 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
154
155# 46 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
156
157# 58 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
158
159# 68 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
160
161# 98 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
162
163# 110 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
164
165# 120 "/home/runner/work/MFC/MFC/src/common/include/shared_parallel_macros.fpp"
166! New line at end of file is required for FYPP
167# 2 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp" 2
168
169# 7 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
170
171# 17 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
172
173# 22 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
174
175# 27 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
176
177# 32 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
178
179# 37 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
180
181# 42 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
182
183# 47 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
184
185# 52 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
186
187# 57 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
188
189# 62 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
190
191# 73 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
192
193# 78 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
194
195# 83 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
196
197# 88 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
198
199# 103 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
200
201# 131 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
202
203# 160 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
204
205# 175 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
206
207# 192 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
208
209# 213 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
210
211# 241 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
212
213# 256 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
214
215# 266 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
216
217# 275 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
218
219# 291 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
220
221# 301 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
222
223# 308 "/home/runner/work/MFC/MFC/src/common/include/acc_macros.fpp"
224! New line at end of file is required for FYPP
225# 4 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp" 2
226
227# 21 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
228
229# 37 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
230
231# 50 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
232
233# 104 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
234
235# 119 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
236
237# 130 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
238
239# 143 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
240
241# 171 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
242
243# 182 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
244
245# 193 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
246
247# 204 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
248
249# 214 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
250
251# 225 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
252
253# 236 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
254
255# 246 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
256
257# 252 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
258
259# 258 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
260
261# 264 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
262
263# 270 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
264
265# 272 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
266# 273 "/home/runner/work/MFC/MFC/src/common/include/parallel_macros.fpp"
267! New line at end of file is required for FYPP
268# 2 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp" 2
269
270# 14 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
271
272! Caution:
273! This macro requires the use of a binding script to set CUDA_VISIBLE_DEVICES, such that we have one GPU device per MPI rank.
274! That's because for both cudaMemAdvise (preferred location) and cudaMemPrefetchAsync we use location = device_id = 0.
275! For an example see misc/nvidia_uvm/bind.sh.
276# 63 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
277
278# 81 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
279
280# 88 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
281
282# 111 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
283
284# 127 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
285
286# 153 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
287
288# 159 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
289
290# 167 "/home/runner/work/MFC/MFC/src/common/include/macros.fpp"
291! New line at end of file is required for FYPP
292# 7 "/home/runner/work/MFC/MFC/src/common/m_model.fpp" 2
293
294!> @brief Binary STL file reader and processor for immersed boundary geometry
296
297 use m_helper
298 use m_mpi_proxy
300
301 use iso_c_binding, only: c_char, c_int32_t, c_int16_t, c_float
302
303 implicit none
304
305 private
306
310
311 ! Subroutines for STL immersed boundaries
314
315#ifdef MFC_SIMULATION
317#endif
318
319 !! array of STL models that can be allocated and then used in IB marker and levelset compute
320 type(t_model_array), allocatable, target :: models(:)
321 !! GPU-friendly flat arrays for STL model data
322 integer, allocatable :: gpu_ntrs(:)
323 real(wp), allocatable, dimension(:, :, :, :) :: gpu_trs_v
324 real(wp), allocatable, dimension(:, :, :) :: gpu_trs_n
325 real(wp), allocatable, dimension(:, :, :, :) :: gpu_boundary_v
326 integer, allocatable :: gpu_boundary_edge_count(:)
327 integer, allocatable :: gpu_total_vertices(:)
328 real(wp), allocatable :: stl_bounding_boxes(:, :, :)
329
330# 43 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
331#if defined(MFC_OpenACC)
332# 43 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
333!$acc declare create(gpu_ntrs, gpu_trs_v, gpu_trs_n, gpu_boundary_v, gpu_boundary_edge_count, gpu_total_vertices)
334# 43 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
335#elif defined(MFC_OpenMP)
336# 43 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
337!$omp declare target (gpu_ntrs, gpu_trs_v, gpu_trs_n, gpu_boundary_v, gpu_boundary_edge_count, gpu_total_vertices)
338# 43 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
339#endif
340
341contains
342
343 !> This procedure reads a binary STL file.
344 !! @param filepath Path to the STL file.
345 !! @param model The binary of the STL file.
346 impure subroutine s_read_stl_binary(filepath, model)
347
348 character(LEN=*), intent(in) :: filepath
349 type(t_model), intent(out) :: model
350
351 integer :: i, iunit, iostat
352
353 character(kind=c_char, len=80) :: header
354 integer(kind=c_int32_t) :: ntriangles
355
356 real(kind=c_float) :: normal(3), v(3, 3), v_norm
357 integer(kind=c_int16_t) :: attribute
358
359 open (newunit=iunit, file=filepath, action='READ', &
360 form='UNFORMATTED', status='OLD', iostat=iostat, &
361 access='STREAM')
362
363 if (iostat /= 0) then
364 print *, "Error: could not open Binary STL file ", filepath
365
366 call s_mpi_abort()
367 end if
368
369 read (iunit, iostat=iostat) header, ntriangles
370
371 if (iostat /= 0) then
372 print *, "Error: could not read header from Binary STL file ", filepath
373
374 call s_mpi_abort()
375 end if
376
377 model%ntrs = ntriangles
378
379 allocate (model%trs(model%ntrs))
380
381 do i = 1, model%ntrs
382 read (iunit) normal(:), v(1, :), v(2, :), v(3, :), attribute
383
384 model%trs(i)%v = v
385 model%trs(i)%n = normal
386 v_norm = sqrt(normal(1)**2 + normal(2)**2 + normal(3)**2)
387 if (v_norm > 0._wp) model%trs(i)%n = normal/v_norm
388 end do
389
390 close (iunit)
391
392 end subroutine s_read_stl_binary
393
394 !> This procedure reads an ASCII STL file.
395 !! @param filepath Path to the STL file.
396 !! @param model the STL file.
397 impure subroutine s_read_stl_ascii(filepath, model)
398 character(LEN=*), intent(in) :: filepath
399 type(t_model), intent(out) :: model
400
401 integer :: i, j, iunit, iostat
402 character(80) :: line, buffered_line
403 logical :: is_buffered
404 real(wp) :: normal(3), v_norm
405
406 is_buffered = .false.
407
408 open (newunit=iunit, file=filepath, action='READ', &
409 form='FORMATTED', status='OLD', iostat=iostat, &
410 access='STREAM')
411
412 if (iostat /= 0) then
413 print *, "Error: could not open ASCII STL file ", filepath
414 call s_mpi_abort()
415 end if
416
417 model%ntrs = 0
418 do
419 if (is_buffered) then
420 line = buffered_line
421 is_buffered = .false.
422 else
423 if (.not. f_read_line(iunit, line)) exit
424 end if
425
426 if (line(1:6) == "facet ") then
427 model%ntrs = model%ntrs + 1
428 end if
429 end do
430
431 allocate (model%trs(model%ntrs))
432
433 rewind(iunit)
434
435 i = 1
436 do
437 if (is_buffered) then
438 line = buffered_line
439 is_buffered = .false.
440 else
441 if (.not. f_read_line(iunit, line)) exit
442 end if
443
444 if (line(1:5) == "solid") cycle
445 if (line(1:8) == "endsolid") exit
446
447 if (line(1:12) /= "facet normal") then
448 print *, "Error: expected facet normal in STL file ", filepath
449 call s_mpi_abort()
450 end if
451
452 call s_skip_ignored_lines(iunit, buffered_line, is_buffered)
453 read (line(13:), *) normal
454 v_norm = sqrt(normal(1)**2 + normal(2)**2 + normal(3)**2)
455 if (v_norm > 0._wp) model%trs(i)%n = normal/v_norm
456
457 call s_skip_ignored_lines(iunit, buffered_line, is_buffered)
458 if (is_buffered) then
459 line = buffered_line
460 is_buffered = .false.
461 else
462 read (iunit, '(A)') line
463 end if
464
465 do j = 1, 3
466 if (is_buffered) then
467 line = buffered_line
468 is_buffered = .false.
469 else
470 if (.not. f_read_line(iunit, line)) exit
471 end if
472
473 if (line(1:6) /= "vertex") then
474 print *, "Error: expected vertex in STL file ", filepath
475 call s_mpi_abort()
476 end if
477
478 call s_skip_ignored_lines(iunit, buffered_line, is_buffered)
479 read (line(7:), *) model%trs(i)%v(j, :)
480 end do
481
482 if (is_buffered) then
483 line = buffered_line
484 is_buffered = .false.
485 else
486 if (.not. f_read_line(iunit, line)) exit
487 end if
488
489 if (is_buffered) then
490 line = buffered_line
491 is_buffered = .false.
492 else
493 if (.not. f_read_line(iunit, line)) exit
494 end if
495
496 if (line(1:8) /= "endfacet") then
497 print *, "Error: expected endfacet in STL file ", filepath
498 call s_mpi_abort()
499 end if
500
501 i = i + 1
502 end do
503 end subroutine s_read_stl_ascii
504
505 !> This procedure reads an STL file.
506 !! @param filepath Path to the STL file.
507 !! @param model the STL file.
508 impure subroutine s_read_stl(filepath, model)
509
510 character(LEN=*), intent(in) :: filepath
511 type(t_model), intent(out) :: model
512
513 integer :: iunit, iostat
514
515 character(80) :: line
516
517 open (newunit=iunit, file=filepath, action='READ', &
518 form='FORMATTED', status='OLD', iostat=iostat, &
519 access='STREAM')
520
521 if (iostat /= 0) then
522 print *, "Error: could not open STL file ", filepath
523
524 call s_mpi_abort()
525 end if
526
527 read (iunit, '(A)') line
528
529 close (iunit)
530
531 if (line(1:5) == "solid") then
532 call s_read_stl_ascii(filepath, model)
533 else
534 call s_read_stl_binary(filepath, model)
535 end if
536
537 end subroutine s_read_stl
538
539 !> This procedure reads an OBJ file.
540 !! @param filepath Path to the odj file.
541 !! @param model The obj file.
542 impure subroutine s_read_obj(filepath, model)
543
544 character(LEN=*), intent(in) :: filepath
545 type(t_model), intent(out) :: model
546
547 integer :: i, j, k, l, iunit, iostat, nvertices
548
549 real(wp), dimension(1:3), allocatable :: vertices(:, :)
550
551 character(80) :: line
552
553 open (newunit=iunit, file=filepath, action='READ', &
554 form='FORMATTED', status='OLD', iostat=iostat, &
555 access='STREAM')
556
557 if (iostat /= 0) then
558 print *, "Error: could not open model file ", filepath
559
560 call s_mpi_abort()
561 end if
562
563 nvertices = 0
564 model%ntrs = 0
565 do
566 if (.not. f_read_line(iunit, line)) exit
567
568 select case (line(1:2))
569 case ("v ")
570 nvertices = nvertices + 1
571 case ("f ")
572 model%ntrs = model%ntrs + 1
573 end select
574 end do
575
576 rewind(iunit)
577
578 allocate (vertices(nvertices, 1:3))
579 allocate (model%trs(model%ntrs))
580
581 i = 1
582 j = 1
583
584 do
585 if (.not. f_read_line(iunit, line)) exit
586
587 select case (line(1:2))
588 case ("g ")
589 case ("vn")
590 case ("vt")
591 case ("l ")
592 case ("v ")
593 read (line(3:), *) vertices(i, :)
594 i = i + 1
595 case ("f ")
596 read (line(3:), *) k, l, j
597 model%trs(j)%v(1, :) = vertices(k, :)
598 model%trs(j)%v(2, :) = vertices(l, :)
599 model%trs(j)%v(3, :) = vertices(j, :)
600 j = j + 1
601 case default
602 print *, "Error: unknown line type in OBJ file ", filepath
603 print *, "Line: ", line
604
605 call s_mpi_abort()
606 end select
607 end do
608
609 deallocate (vertices)
610
611 close (iunit)
612
613 end subroutine s_read_obj
614
615 !> This procedure reads a mesh from a file.
616 !! @param filepath Path to the file to read.
617 !! @return The model read from the file.
618 impure function f_model_read(filepath) result(model)
619
620 character(LEN=*), intent(in) :: filepath
621
622 type(t_model) :: model
623
624 select case (filepath(len(trim(filepath)) - 3:len(trim(filepath))))
625 case (".stl")
626 call s_read_stl(filepath, model)
627 case (".obj")
628 call s_read_obj(filepath, model)
629 case default
630 print *, "Error: unknown model file format for file ", filepath
631
632 call s_mpi_abort()
633 end select
634
635 end function f_model_read
636
637 !> This procedure writes a binary STL file.
638 !! @param filepath Path to the STL file.
639 !! @param model STL to write
640 impure subroutine s_write_stl(filepath, model)
641
642 character(LEN=*), intent(in) :: filepath
643 type(t_model), intent(in) :: model
644
645 integer :: i, j, iunit, iostat
646
647 character(kind=c_char, len=80), parameter :: header = "Model file written by MFC."
648 integer(kind=c_int32_t) :: ntriangles
649 real(wp) :: normal(3), v(3)
650 integer(kind=c_int16_t) :: attribute
651
652 open (newunit=iunit, file=filepath, action='WRITE', &
653 form='UNFORMATTED', iostat=iostat, access='STREAM')
654
655 if (iostat /= 0) then
656 print *, "Error: could not open STL file ", filepath
657
658 call s_mpi_abort()
659 end if
660
661 ntriangles = model%ntrs
662 write (iunit, iostat=iostat) header, ntriangles
663
664 if (iostat /= 0) then
665 print *, "Error: could not write header to STL file ", filepath
666
667 call s_mpi_abort()
668 end if
669
670 do i = 1, model%ntrs
671 normal = model%trs(i)%n
672 write (iunit) normal
673
674 do j = 1, 3
675 v = model%trs(i)%v(j, :)
676 write (iunit) v(:)
677 end do
678
679 attribute = 0
680 write (iunit) attribute
681 end do
682
683 close (iunit)
684
685 end subroutine s_write_stl
686
687 !> This procedure writes an OBJ file.
688 !! @param filepath Path to the obj file.
689 !! @param model obj to write.
690 impure subroutine s_write_obj(filepath, model)
691
692 character(LEN=*), intent(in) :: filepath
693 type(t_model), intent(in) :: model
694
695 integer :: iunit, iostat
696
697 integer :: i, j
698
699 open (newunit=iunit, file=filepath, action='WRITE', &
700 form='FORMATTED', iostat=iostat, access='STREAM')
701
702 if (iostat /= 0) then
703 print *, "Error: could not open OBJ file ", filepath
704
705 call s_mpi_abort()
706 end if
707
708 write (iunit, '(A)') "# Model file written by MFC."
709
710 do i = 1, model%ntrs
711 do j = 1, 3
712 write (iunit, '(A, " ", (f30.20), " ", (f30.20), " ", (f30.20))') &
713 "v", model%trs(i)%v(j, 1), model%trs(i)%v(j, 2), model%trs(i)%v(j, 3)
714 end do
715
716 write (iunit, '(A, " ", I0, " ", I0, " ", I0)') &
717 "f", i*3 - 2, i*3 - 1, i*3
718 end do
719
720 close (iunit)
721
722 end subroutine s_write_obj
723
724 !> This procedure writes a binary STL file.
725 !! @param filepath Path to the file to write.
726 !! @param model Model to write.
727 impure subroutine s_model_write(filepath, model)
728
729 character(LEN=*), intent(in) :: filepath
730 type(t_model), intent(in) :: model
731
732 select case (filepath(len(trim(filepath)) - 3:len(trim(filepath))))
733 case (".stl")
734 call s_write_stl(filepath, model)
735 case (".obj")
736 call s_write_obj(filepath, model)
737 case default
738 print *, "Error: unknown model file format for file ", filepath
739
740 call s_mpi_abort()
741 end select
742
743 end subroutine s_model_write
744
745 !> This procedure frees the memory allocated for an STL mesh.
746 subroutine s_model_free(model)
747
748 type(t_model), intent(inout) :: model
749
750 deallocate (model%trs)
751
752 end subroutine s_model_free
753
754 impure function f_read_line(iunit, line) result(bIsLine)
755
756 integer, intent(in) :: iunit
757 character(80), intent(out) :: line
758
759 logical :: bisline
760 integer :: iostat
761
762 bisline = .true.
763
764 do
765 read (iunit, '(A)', iostat=iostat) line
766
767 if (iostat < 0) then
768 bisline = .false.
769 exit
770 end if
771
772 line = adjustl(trim(line))
773
774 if (len(trim(line)) == 0) cycle
775 if (line(1:5) == "solid") cycle
776 if (line(1:1) == "#") cycle
777
778 exit
779 end do
780
781 end function f_read_line
782
783 !> @brief Reads the next non-comment line from a model file, using a buffered look-ahead mechanism.
784 impure subroutine s_skip_ignored_lines(iunit, buffered_line, is_buffered)
785 integer, intent(in) :: iunit
786 character(80), intent(inout) :: buffered_line
787 logical, intent(inout) :: is_buffered
788
789 character(80) :: line
790
791 if (is_buffered) then
792 line = buffered_line
793 is_buffered = .false.
794 else
795 if (.not. f_read_line(iunit, line)) return
796 end if
797
798 buffered_line = line
799 is_buffered = .true.
800 end subroutine s_skip_ignored_lines
801
802 !> This function is used to replace the fortran random number
803 !! generator because the native generator is not compatible being called
804 !! from GPU routines/functions
805 function f_model_random_number(seed) result(rval)
806
807 ! $:GPU_ROUTINE(parallelism='[seq]')
808
809 integer, intent(inout) :: seed
810 real(wp) :: rval
811
812 seed = ieor(seed, ishft(seed, 13))
813 seed = ieor(seed, ishft(seed, -17))
814 seed = ieor(seed, ishft(seed, 5))
815
816 rval = abs(real(seed, wp))/real(huge(seed), wp)
817 end function f_model_random_number
818
819 !> This procedure, recursively, finds whether a point is inside an octree.
820 !! @param model Model to search in.
821 !! @param point Point to test.
822 !! @param spacing Space around the point to search in (grid spacing).
823 !! @param spc Number of samples per cell.
824 !! @return True if the point is inside the octree, false otherwise.
825 impure function f_model_is_inside(model, point, spacing, spc) result(fraction)
826
827 ! $:GPU_ROUTINE(parallelism='[seq]')
828
829 type(t_model), intent(in) :: model
830 real(wp), dimension(1:3), intent(in) :: point
831 real(wp), dimension(1:3), intent(in) :: spacing
832 integer, intent(in) :: spc
833 real(wp) :: phi, theta
834 integer :: rand_seed
835
836 real(wp) :: fraction
837
838 type(t_ray) :: ray
839 integer :: i, j, k, ninorout, nhits
840
841 real(wp), dimension(1:spc, 1:3) :: ray_origins, ray_dirs
842
843 rand_seed = int(point(1)*73856093._wp) + &
844 int(point(2)*19349663._wp) + &
845 int(point(3)*83492791._wp)
846 if (rand_seed == 0) rand_seed = 1
847
848 ! generate our random collection or rays
849 do i = 1, spc
850 do k = 1, 3
851 ! random jitter in the origin helps us estimate volume fraction instead of only at the cell center
852 ray_origins(i, k) = point(k) + (f_model_random_number(rand_seed) - 0.5_wp)*spacing(k)
853 ! cast sample rays in all directions
854 ray_dirs(i, k) = f_model_random_number(rand_seed) - 0.5_wp
855 end do
856 ray_dirs(i, :) = ray_dirs(i, :)/sqrt(sum(ray_dirs(i, :)*ray_dirs(i, :)))
857 end do
858
859 ! ray trace
860 ninorout = 0
861 do i = 1, spc
862 ray%o = ray_origins(i, :)
863 ray%d = ray_dirs(i, :)
864
865 nhits = 0
866 do j = 1, model%ntrs
867 ! count the number of triangles this ray intersects
868 if (f_intersects_triangle(ray, model%trs(j)) == 1) then
869 nhits = nhits + 1
870 end if
871 end do
872
873 ! if the ray hits an odd number of triangles on its way out, then
874 ! it must be on the inside of the model
875 ninorout = ninorout + mod(nhits, 2)
876 end do
877
878 fraction = real(ninorout)/real(spc)
879
880 end function f_model_is_inside
881
882 !> This procedure, given a cell center will determine if a point exists instide a surface
883 !! @param ntrs Number of triangles in the model
884 !! @param pid Patch ID od this model
885 !! @param point Point to test.
886 !! @return fraction The perfentage of candidate rays cast indicate that we are inside the model
887 function f_model_is_inside_flat(ntrs, pid, point) result(fraction)
888
889
890# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
891#if MFC_OpenACC
892# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
893!$acc routine seq
894# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
895#elif MFC_OpenMP
896# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
897
898# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
899
900# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
901!$omp declare target device_type(any)
902# 593 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
903#endif
904
905 integer, intent(in) :: ntrs
906 integer, intent(in) :: pid
907 real(wp), dimension(1:3), intent(in) :: point
908
909 real(wp) :: fraction
910 type(t_ray) :: ray
911 type(t_triangle) :: tri
912 integer :: i, j, k, q, ninorout, nhits
913
914 ! cast 26 rays from the point and count the number at leave the boundary
915 ninorout = 0
916 do i = -1, 1
917 do j = -1, 1
918 do k = -1, 1
919 if (i /= 0 .or. j /= 0 .or. k /= 0) then
920 ! We cannot get inersections if the ray is exactly in line with triangle plane
921 if (p == 0 .and. k == 0) cycle
922
923 ! generate the ray
924 ray%o = point
925 ray%d(:) = [real(i, wp), real(j, wp), real(k, wp)]
926 ray%d = ray%d/sqrt(real(abs(i) + abs(j) + abs(k), wp))
927
928 ! count the number of intersections
929 nhits = 0
930 do q = 1, ntrs
931 tri%v(:, :) = gpu_trs_v(:, :, q, pid)
932 tri%n(1:3) = gpu_trs_n(1:3, q, pid)
933 nhits = nhits + f_intersects_triangle(ray, tri)
934 end do
935 ! if the ray intersected an odd number of times, we must be inside
936 ninorout = ninorout + mod(nhits, 2)
937 end if
938 end do
939 end do
940 end do
941
942 if (p == 0) then
943 ! in 2D, we skipped 8 rays
944 fraction = real(ninorout)/18._wp
945 else
946 fraction = real(ninorout)/26._wp
947 end if
948
949 end function f_model_is_inside_flat
950
951 ! From https://www.scratchapixel.com/lessons/3e-basic-rendering/ray-tracing-rendering-a-triangle/ray-triangle-intersection-geometric-solution.html
952 !> This procedure checks if a ray intersects a triangle.
953 !! @param ray Ray.
954 !! @param triangle Triangle.
955 !! @return True if the ray intersects the triangle, false otherwise.
956 function f_intersects_triangle(ray, triangle) result(intersects)
957
958
959# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
960#if MFC_OpenACC
961# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
962!$acc routine seq
963# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
964#elif MFC_OpenMP
965# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
966
967# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
968
969# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
970!$omp declare target device_type(any)
971# 648 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
972#endif
973
974 type(t_ray), intent(in) :: ray
975 type(t_triangle), intent(in) :: triangle
976
977 integer :: intersects
978
979 real(wp) :: n(3), p(3), c(3), edge(3), vp(3)
980 real(wp) :: d, t, ndotraydirection
981
982 intersects = 0
983
984 n(1:3) = triangle%n(1:3)
985 ndotraydirection = dot_product(n(1:3), ray%d(1:3))
986 if (abs(ndotraydirection) < 0.0000001_wp) then
987 return
988 end if
989
990 d = -sum(n(:)*triangle%v(1, :))
991 t = -(sum(n(:)*ray%o(:)) + d)/ndotraydirection
992 if (t < 0) then
993 return
994 end if
995
996 p = ray%o + t*ray%d
997 edge = triangle%v(2, :) - triangle%v(1, :)
998 vp = p - triangle%v(1, :)
999 c = f_cross(edge, vp)
1000 if (sum(n(:)*c(:)) < 0) then
1001 return
1002 end if
1003
1004 edge = triangle%v(3, :) - triangle%v(2, :)
1005 vp = p - triangle%v(2, :)
1006 c = f_cross(edge, vp)
1007 if (sum(n(:)*c(:)) < 0) then
1008 return
1009 end if
1010
1011 edge = triangle%v(1, :) - triangle%v(3, :)
1012 vp = p - triangle%v(3, :)
1013 c = f_cross(edge, vp)
1014 if (sum(n(:)*c(:)) < 0) then
1015 return
1016 end if
1017
1018 intersects = 1
1019
1020 end function f_intersects_triangle
1021
1022 !> This procedure checks and labels edges shared by two or more triangles facets of the 2D STL model.
1023 !! @param model Model to search in.
1024 !! @param boundary_vertex_count Output total boundary vertex count
1025 subroutine s_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count)
1026
1027 type(t_model), intent(in) :: model
1028 real(wp), allocatable, intent(out), dimension(:, :, :) :: boundary_v !< Output boundary vertices/normals
1029 integer, intent(out) :: boundary_vertex_count, boundary_edge_count !< Output boundary vertex/edge count
1030
1031 integer :: i, j !< Model index iterator
1032 integer :: edge_count, edge_index, store_index !< Boundary edge index iterator
1033 real(wp), dimension(1:2, 1:2) :: edge !< Edge end points buffer
1034 real(wp), dimension(1:2) :: boundary_edge !< Boundary edge end points buffer
1035 real(wp), dimension(1:(3*model%ntrs), 1:2, 1:2) :: temp_boundary_v !< Temporary boundary vertex buffer
1036 integer, dimension(1:(3*model%ntrs)) :: edge_occurrence !< The manifoldness of the edges
1037 real(wp) :: edgetan, initial, v_norm, xnormal, ynormal !< The manifoldness of the edges
1038
1039 ! Total number of edges in 2D STL
1040 edge_count = 3*model%ntrs
1041
1042 ! Initialize edge_occurrence array to zero
1043 edge_occurrence = 0
1044 edge_index = 0
1045
1046 ! Collect all edges of all triangles and store them
1047 do i = 1, model%ntrs
1048 ! First edge (v1, v2)
1049 edge(1, 1:2) = model%trs(i)%v(1, 1:2)
1050 edge(2, 1:2) = model%trs(i)%v(2, 1:2)
1051 call s_register_edge(temp_boundary_v, edge, edge_index, edge_count)
1052
1053 ! Second edge (v2, v3)
1054 edge(1, 1:2) = model%trs(i)%v(2, 1:2)
1055 edge(2, 1:2) = model%trs(i)%v(3, 1:2)
1056 call s_register_edge(temp_boundary_v, edge, edge_index, edge_count)
1057
1058 ! Third edge (v3, v1)
1059 edge(1, 1:2) = model%trs(i)%v(3, 1:2)
1060 edge(2, 1:2) = model%trs(i)%v(1, 1:2)
1061 call s_register_edge(temp_boundary_v, edge, edge_index, edge_count)
1062 end do
1063
1064 ! Check all edges and count repeated edges
1065
1066# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1067
1068# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1069#if defined(MFC_OpenACC)
1070# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1071!$acc parallel loop collapse(2) gang vector default(present) private(i, j) copy(temp_boundary_v, edge_occurrence)
1072# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1073#elif defined(MFC_OpenMP)
1074# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1075
1076# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1077
1078# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1079
1080# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1081!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) collapse(2) defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) private(i, j) map(tofrom:temp_boundary_v, edge_occurrence)
1082# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1083#endif
1084# 741 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1085
1086 do i = 1, edge_count
1087 do j = 1, edge_count
1088 if (i /= j) then
1089 if (((abs(temp_boundary_v(i, 1, 1) - temp_boundary_v(j, 1, 1)) < threshold_edge_zero) .and. &
1090 (abs(temp_boundary_v(i, 1, 2) - temp_boundary_v(j, 1, 2)) < threshold_edge_zero) .and. &
1091 (abs(temp_boundary_v(i, 2, 1) - temp_boundary_v(j, 2, 1)) < threshold_edge_zero) .and. &
1092 (abs(temp_boundary_v(i, 2, 2) - temp_boundary_v(j, 2, 2)) < threshold_edge_zero)) .or. &
1093 ((abs(temp_boundary_v(i, 1, 1) - temp_boundary_v(j, 2, 1)) < threshold_edge_zero) .and. &
1094 (abs(temp_boundary_v(i, 1, 2) - temp_boundary_v(j, 2, 2)) < threshold_edge_zero) .and. &
1095 (abs(temp_boundary_v(i, 2, 1) - temp_boundary_v(j, 1, 1)) < threshold_edge_zero) .and. &
1096 (abs(temp_boundary_v(i, 2, 2) - temp_boundary_v(j, 1, 2)) < threshold_edge_zero))) then
1097
1098
1099# 754 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1100#if defined(MFC_OpenACC)
1101# 754 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1102!$acc atomic update
1103# 754 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1104#elif defined(MFC_OpenMP)
1105# 754 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1106!$omp atomic update
1107# 754 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1108#endif
1109 edge_occurrence(i) = edge_occurrence(i) + 1
1110 end if
1111 end if
1112 end do
1113 end do
1114
1115# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1116
1117# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1118#if defined(MFC_OpenACC)
1119# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1120!$acc end parallel loop
1121# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1122#elif defined(MFC_OpenMP)
1123# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1124
1125# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1126
1127# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1128!$omp end target teams loop
1129# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1130#endif
1131# 760 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1132
1133
1134 ! Count the number of boundary vertices/edges
1135 boundary_vertex_count = 0
1136 boundary_edge_count = 0
1137
1138 do i = 1, edge_count
1139 if (edge_occurrence(i) == 0) then
1140 boundary_vertex_count = boundary_vertex_count + 2
1141 boundary_edge_count = boundary_edge_count + 1
1142 end if
1143 end do
1144
1145 ! Allocate the boundary_v array based on the number of boundary edges
1146 allocate (boundary_v(boundary_edge_count, 1:3, 1:2))
1147
1148 ! Store boundary vertices
1149 store_index = 0
1150 do i = 1, edge_count
1151 if (edge_occurrence(i) == 0) then
1152 store_index = store_index + 1
1153 boundary_v(store_index, 1, 1:2) = temp_boundary_v(i, 1, 1:2)
1154 boundary_v(store_index, 2, 1:2) = temp_boundary_v(i, 2, 1:2)
1155 end if
1156 end do
1157
1158 ! Find/store the normal vector of the boundary edges
1159 do i = 1, boundary_edge_count
1160 boundary_edge(1) = boundary_v(i, 2, 1) - boundary_v(i, 1, 1)
1161 boundary_edge(2) = boundary_v(i, 2, 2) - boundary_v(i, 1, 2)
1162 edgetan = boundary_edge(1)/sign(max(sgm_eps, abs(boundary_edge(2))), boundary_edge(2))
1163
1164 if (abs(boundary_edge(2)) < threshold_vector_zero) then
1165 if (edgetan > 0._wp) then
1166 ynormal = -1
1167 xnormal = 0._wp
1168 else
1169 ynormal = 1
1170 xnormal = 0._wp
1171 end if
1172 else
1173 initial = boundary_edge(2)
1174 ynormal = -edgetan*initial
1175 xnormal = initial
1176 end if
1177
1178 v_norm = sqrt(xnormal**2 + ynormal**2)
1179 boundary_v(i, 3, 1) = xnormal/v_norm
1180 boundary_v(i, 3, 2) = ynormal/v_norm
1181 end do
1182
1183 end subroutine s_check_boundary
1184
1185 !> This procedure appends the edge end vertices to a temporary buffer.
1186 subroutine s_register_edge(temp_boundary_v, edge, edge_index, edge_count)
1187
1188 integer, intent(inout) :: edge_index !< Edge index iterator
1189 integer, intent(inout) :: edge_count !< Total number of edges
1190 real(wp), intent(in), dimension(1:2, 1:2) :: edge !< Edges end points to be registered
1191 real(wp), dimension(1:edge_count, 1:2, 1:2), intent(inout) :: temp_boundary_v !< Temporary edge end vertex buffer
1192
1193 ! Increment edge index and store the edge
1194 edge_index = edge_index + 1
1195 temp_boundary_v(edge_index, 1, 1:2) = edge(1, 1:2)
1196 temp_boundary_v(edge_index, 2, 1:2) = edge(2, 1:2)
1197
1198 end subroutine s_register_edge
1199
1200 !> This procedure determines the levelset distance and normals of 3D models
1201 !! by computing the exact closest point via projection onto triangle surfaces.
1202 !! @param ntrs Number of triangles for this patch
1203 !! @param trs_v Flat GPU array of triangle vertices for all patches
1204 !! @param trs_n Flat GPU array of triangle normals for all patches
1205 !! @param pid Patch index into the arrays
1206 !! @param point The cell center of the current levelset cell
1207 !! @param normals Output levelset normals
1208 !! @param distance Output levelset distance
1209 subroutine s_distance_normals_3d(ntrs, pid, point, normals, distance)
1210
1211# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1212#if MFC_OpenACC
1213# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1214!$acc routine seq
1215# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1216#elif MFC_OpenMP
1217# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1218
1219# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1220
1221# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1222!$omp declare target device_type(any)
1223# 838 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1224#endif
1225
1226 integer, intent(in) :: ntrs
1227 integer, intent(in) :: pid
1228 real(wp), dimension(1:3), intent(in) :: point
1229 real(wp), dimension(1:3), intent(out) :: normals
1230 real(wp), intent(out) :: distance
1231
1232 integer :: i, j, l
1233 real(wp) :: dist_min, dist_proj, dist_v, dist_e, t
1234 real(wp) :: v1(1:3), v2(1:3), v3(1:3)
1235 real(wp) :: e0(1:3), e1(1:3), pv(1:3)
1236 real(wp) :: n(1:3), proj(1:3), norm_vec(1:3)
1237 real(wp) :: d, ndot, denom, norm_mag
1238 real(wp) :: u, v_bary, w
1239 real(wp) :: l00, l01, l11, l20, l21
1240 real(wp) :: edge(1:3), pe(1:3)
1241 real(wp) :: verts(1:3, 1:3)
1242
1243 dist_min = initial_distance_buffer
1244 normals = 0._wp
1245
1246 do i = 1, ntrs
1247 ! Triangle vertices
1248 v1(:) = gpu_trs_v(1, :, i, pid)
1249 v2(:) = gpu_trs_v(2, :, i, pid)
1250 v3(:) = gpu_trs_v(3, :, i, pid)
1251
1252 ! Triangle normal
1253 n(:) = gpu_trs_n(:, i, pid)
1254
1255 ! Project point onto triangle plane
1256 pv(:) = point(:) - v1(:)
1257 d = dot_product(pv, n)
1258 if (abs(d) >= dist_min) cycle ! minimum distance is not small enough, no need to check validity
1259 proj(:) = point(:) - d*n(:)
1260
1261 ! Check if projection is inside triangle using barycentric coordinates
1262 e0(:) = v2(:) - v1(:)
1263 e1(:) = v3(:) - v1(:)
1264 pv(:) = proj(:) - v1(:)
1265
1266 l00 = dot_product(e0, e0)
1267 l01 = dot_product(e0, e1)
1268 l11 = dot_product(e1, e1)
1269 l20 = dot_product(pv, e0)
1270 l21 = dot_product(pv, e1)
1271
1272 denom = l00*l11 - l01*l01
1273
1274 ! compute the barycentric coordinates of the projection in the triangle
1275 if (abs(denom) > 0._wp) then
1276 v_bary = (l11*l20 - l01*l21)/denom
1277 w = (l00*l21 - l01*l20)/denom
1278 u = 1._wp - v_bary - w
1279 else
1280 u = -1._wp
1281 v_bary = -1._wp
1282 w = -1._wp
1283 end if
1284
1285 ! If projection is inside triangle
1286 if (u >= 0._wp .and. v_bary >= 0._wp .and. w >= 0._wp) then
1287 dist_proj = sqrt((point(1) - proj(1))**2 + &
1288 (point(2) - proj(2))**2 + &
1289 (point(3) - proj(3))**2)
1290
1291 if (dist_proj < dist_min) then
1292 dist_min = dist_proj
1293 normals(:) = n(:)
1294 end if
1295 else
1296 ! Projection outside triangle: check edges and vertices
1297 verts(:, 1) = v1(:)
1298 verts(:, 2) = v2(:)
1299 verts(:, 3) = v3(:)
1300
1301 ! Check three edges
1302 do j = 1, 3
1303 edge(:) = verts(:, mod(j, 3) + 1) - verts(:, j)
1304 pe(:) = point(:) - verts(:, j)
1305
1306 t = dot_product(pe, edge)/max(dot_product(edge, edge), 1.e-30_wp)
1307
1308 if (t >= 0._wp .and. t <= 1._wp) then
1309 proj(:) = verts(:, j) + t*edge(:)
1310 dist_e = sqrt((point(1) - proj(1))**2 + &
1311 (point(2) - proj(2))**2 + &
1312 (point(3) - proj(3))**2)
1313
1314 if (dist_e < dist_min) then
1315 dist_min = dist_e
1316 norm_vec(:) = proj(:) - point(:)
1317 if (dist_e > 0._wp) norm_vec = norm_vec/dist_e
1318 ! Snap to triangle normal if nearly parallel
1319 if (f_approx_equal(dot_product(norm_vec, n), 1._wp)) then
1320 normals(:) = n(:)
1321 else
1322 normals(:) = norm_vec(:)
1323 end if
1324 end if
1325 else if (t < 0._wp) then
1326 dist_v = sqrt((point(1) - verts(1, j))**2 + &
1327 (point(2) - verts(2, j))**2 + &
1328 (point(3) - verts(3, j))**2)
1329
1330 if (dist_v < dist_min) then
1331 dist_min = dist_v
1332 norm_vec(:) = verts(:, j) - point(:)
1333 norm_mag = sqrt(dot_product(norm_vec, norm_vec))
1334 if (norm_mag > 0._wp) norm_vec = norm_vec/norm_mag
1335 normals(:) = norm_vec(:)
1336 end if
1337 else
1338 dist_v = sqrt((point(1) - verts(1, mod(j, 3) + 1))**2 + &
1339 (point(2) - verts(2, mod(j, 3) + 1))**2 + &
1340 (point(3) - verts(3, mod(j, 3) + 1))**2)
1341
1342 if (dist_v < dist_min) then
1343 dist_min = dist_v
1344 norm_vec(:) = verts(:, mod(j, 3) + 1) - point(:)
1345 norm_mag = sqrt(dot_product(norm_vec, norm_vec))
1346 if (norm_mag > 0._wp) norm_vec = norm_vec/norm_mag
1347 normals(:) = norm_vec(:)
1348 end if
1349 end if
1350 end do
1351 end if
1352 end do
1353
1354 distance = dist_min
1355
1356 end subroutine s_distance_normals_3d
1357
1358 !> This procedure determines the levelset distance and normals of 2D models
1359 !! by computing the exact closest point via projection onto boundary edges.
1360 !! @param boundary_v Flat GPU array of boundary vertices/normals for all patches
1361 !! @param pid Patch index into the boundary_v array
1362 !! @param boundary_edge_count Total number of boundary edges for this patch
1363 !! @param point The cell center of the current levelset cell
1364 !! @param normals Output levelset normals
1365 !! @param distance Output levelset distance
1366 subroutine s_distance_normals_2d(pid, boundary_edge_count, point, normals, distance)
1367
1368# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1369#if MFC_OpenACC
1370# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1371!$acc routine seq
1372# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1373#elif MFC_OpenMP
1374# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1375
1376# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1377
1378# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1379!$omp declare target device_type(any)
1380# 981 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1381#endif
1382
1383 integer, intent(in) :: pid
1384 integer, intent(in) :: boundary_edge_count
1385 real(wp), dimension(1:3), intent(in) :: point
1386 real(wp), dimension(1:3), intent(out) :: normals
1387 real(wp), intent(out) :: distance
1388
1389 integer :: i
1390 real(wp) :: dist_min, dist, t, norm_mag
1391 real(wp) :: v1(1:2), v2(1:2), edge(1:2), pv(1:2)
1392 real(wp) :: edge_len_sq, proj(1:2), norm(1:2), c
1393
1394 dist_min = initial_distance_buffer
1395 normals = 0._wp
1396 norm = 0._wp
1397
1398 do i = 1, boundary_edge_count
1399 ! Edge endpoints
1400 v1(1) = gpu_boundary_v(i, 1, 1, pid)
1401 v1(2) = gpu_boundary_v(i, 1, 2, pid)
1402 v2(1) = gpu_boundary_v(i, 2, 1, pid)
1403 v2(2) = gpu_boundary_v(i, 2, 2, pid)
1404
1405 ! Edge vector and point-to-v1 vector
1406 edge = v2 - v1
1407 pv(1) = point(1) - v1(1)
1408 pv(2) = point(2) - v1(2)
1409 edge_len_sq = dot_product(edge, edge)
1410
1411 ! Parameter of projection onto the edge line
1412 if (edge_len_sq > 0._wp) then
1413 t = dot_product(pv, edge)/edge_len_sq
1414 else
1415 t = 0._wp
1416 end if
1417
1418 ! Check if projection falls within the segment
1419 if (t >= 0._wp .and. t <= 1._wp) then
1420 proj = v1 + t*edge
1421 dist = sqrt((point(1) - proj(1))**2 + (point(2) - proj(2))**2)
1422 norm(1) = gpu_boundary_v(i, 3, 1, pid)
1423 norm(2) = gpu_boundary_v(i, 3, 2, pid)
1424 else if (t < 0._wp) then ! negative t means that v1 is the closest point on the edge
1425 dist = sqrt((point(1) - v1(1))**2 + (point(2) - v1(2))**2)
1426 norm(1) = v1(1) - point(1)
1427 norm(2) = v1(2) - point(2)
1428 norm = norm/dist
1429 else ! t > 1 means that v2 is the closest point on the line edge
1430 dist = sqrt((point(1) - v2(1))**2 + (point(2) - v2(2))**2)
1431 norm(1) = v2(1) - point(1)
1432 norm(2) = v2(2) - point(2)
1433 norm = norm/dist
1434 end if
1435
1436 if (dist < dist_min) then
1437 dist_min = dist
1438 normals(1) = norm(1)
1439 normals(2) = norm(2)
1440 end if
1441 end do
1442
1443 distance = dist_min
1444
1445 end subroutine s_distance_normals_2d
1446
1447#ifdef MFC_SIMULATION
1448
1450
1451 ! Variables for IBM+STL
1452 real(wp) :: normals(1:3) !< Boundary normal buffer
1453 integer :: boundary_vertex_count, boundary_edge_count, total_vertices !< Boundary vertex
1454 real(wp), allocatable, dimension(:, :, :) :: boundary_v !< Boundary vertex buffer
1455 real(wp) :: dx_local, dy_local, dz_local !< Levelset distance buffer
1456
1457 integer :: i, j, k !< Generic loop iterators
1458 integer :: patch_id
1459
1460 type(t_bbox) :: bbox, bbox_old
1461 type(t_model) :: model
1462 type(ic_model_parameters) :: params
1463
1464 real(wp) :: eta
1465 real(wp), dimension(1:3) :: point, model_center
1466 real(wp) :: grid_mm(1:3, 1:2)
1467
1468 real(wp), dimension(1:4, 1:4) :: transform, transform_n
1469
1470 dx_local = minval(dx); dy_local = minval(dy)
1471 if (p /= 0) dz_local = minval(dz)
1472
1473 allocate (stl_bounding_boxes(num_ibs, 1:3, 1:3))
1474
1475 do patch_id = 1, num_ibs
1476 if (patch_ib(patch_id)%geometry == 5 .or. patch_ib(patch_id)%geometry == 12) then
1477 allocate (models(patch_id)%model)
1478 print *, " * Reading model: "//trim(patch_ib(patch_id)%model_filepath)
1479
1480 model = f_model_read(patch_ib(patch_id)%model_filepath)
1481 params%scale(:) = patch_ib(patch_id)%model_scale(:)
1482 params%translate(:) = patch_ib(patch_id)%model_translate(:)
1483 params%rotate(:) = patch_ib(patch_id)%model_rotate(:)
1484 params%spc = patch_ib(patch_id)%model_spc
1485 params%threshold = patch_ib(patch_id)%model_threshold
1486
1487 if (f_approx_equal(dot_product(params%scale, params%scale), 0._wp)) then
1488 params%scale(:) = 1._wp
1489 end if
1490
1491 if (proc_rank == 0) then
1492 print *, " * Transforming model."
1493 end if
1494
1495 ! Get the model center before transforming the model
1496 bbox_old = f_create_bbox(model)
1497 model_center(1:3) = (bbox_old%min(1:3) + bbox_old%max(1:3))/2._wp
1498
1499 ! Compute the transform matrices for vertices and normals
1500 transform = f_create_transform_matrix(params, model_center)
1501 transform_n = f_create_transform_matrix(params)
1502
1503 call s_transform_model(model, transform, transform_n)
1504
1505 ! Recreate the bounding box after transformation
1506 bbox = f_create_bbox(model)
1507
1508 ! Show the number of vertices in the original STL model
1509 if (proc_rank == 0) then
1510 print *, ' * Number of input model vertices:', 3*model%ntrs
1511 end if
1512
1513 ! Need the cells that form the boundary of the flat projection in 2D
1514 if (p == 0) call s_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count)
1515
1516 ! Show the number of edges and boundary edges in 2D STL models
1517 if (proc_rank == 0 .and. p == 0) then
1518 print *, ' * Number of 2D model boundary edges:', boundary_edge_count
1519 end if
1520
1521 if (proc_rank == 0) then
1522 write (*, "(A, 3(2X, F20.10))") " > Model: Min:", bbox%min(1:3)
1523 write (*, "(A, 3(2X, F20.10))") " > Cen:", (bbox%min(1:3) + bbox%max(1:3))/2._wp
1524 write (*, "(A, 3(2X, F20.10))") " > Max:", bbox%max(1:3)
1525
1526 grid_mm(1, :) = (/minval(x_cc(0:m)) - 0.5_wp*dx_local, maxval(x_cc(0:m)) + 0.5_wp*dx_local/)
1527 grid_mm(2, :) = (/minval(y_cc(0:n)) - 0.5_wp*dy_local, maxval(y_cc(0:n)) + 0.5_wp*dy_local/)
1528
1529 if (p > 0) then
1530 grid_mm(3, :) = (/minval(z_cc(0:p)) - 0.5_wp*dz_local, maxval(z_cc(0:p)) + 0.5_wp*dz_local/)
1531 else
1532 grid_mm(3, :) = (/0._wp, 0._wp/)
1533 end if
1534
1535 write (*, "(A, 3(2X, F20.10))") " > Domain: Min:", grid_mm(:, 1)
1536 write (*, "(A, 3(2X, F20.10))") " > Cen:", (grid_mm(:, 1) + grid_mm(:, 2))/2._wp
1537 write (*, "(A, 3(2X, F20.10))") " > Max:", grid_mm(:, 2)
1538 end if
1539
1540 stl_bounding_boxes(patch_id, 1, 1:3) = [bbox%min(1), (bbox%min(1) + bbox%max(1))/2._wp, bbox%max(1)]
1541 stl_bounding_boxes(patch_id, 2, 1:3) = [bbox%min(2), (bbox%min(2) + bbox%max(2))/2._wp, bbox%max(2)]
1542 stl_bounding_boxes(patch_id, 3, 1:3) = [bbox%min(3), (bbox%min(3) + bbox%max(3))/2._wp, bbox%max(3)]
1543
1544 models(patch_id)%model = model
1545 if (p == 0) then
1546 models(patch_id)%boundary_v = boundary_v
1547 models(patch_id)%boundary_edge_count = boundary_edge_count
1548 end if
1549 end if
1550 end do
1551
1552 ! Pack and upload flat arrays for GPU (AFTER the loop)
1553 block
1554 integer :: pid, max_ntrs
1555 integer :: max_bv1, max_bv2, max_bv3, max_iv1, max_iv2
1556
1557 max_ntrs = 0
1558 max_bv1 = 0; max_bv2 = 0; max_bv3 = 0
1559 max_iv1 = 0; max_iv2 = 0
1560
1561 do pid = 1, num_ibs
1562 if (allocated(models(pid)%model)) then
1563 call s_pack_model_for_gpu(models(pid))
1564 max_ntrs = max(max_ntrs, models(pid)%ntrs)
1565 end if
1566 if (allocated(models(pid)%boundary_v)) then
1567 max_bv1 = max(max_bv1, size(models(pid)%boundary_v, 1))
1568 max_bv2 = max(max_bv2, size(models(pid)%boundary_v, 2))
1569 max_bv3 = max(max_bv3, size(models(pid)%boundary_v, 3))
1570 end if
1571 end do
1572
1573 if (max_ntrs > 0) then
1574#ifdef MFC_DEBUG
1575# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1576 block
1577# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1578 use iso_fortran_env, only: output_unit
1579# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1580
1581# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1582 print *, 'm_model.fpp:1174: ', '@:ALLOCATE(gpu_ntrs(1:num_ibs))'
1583# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1584
1585# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1586 call flush (output_unit)
1587# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1588 end block
1589# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1590#endif
1591# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1592 allocate (gpu_ntrs(1:num_ibs))
1593# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1594
1595# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1596
1597# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1598#if defined(MFC_OpenACC)
1599# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1600!$acc enter data create(gpu_ntrs)
1601# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1602#elif defined(MFC_OpenMP)
1603# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1604!$omp target enter data map(always,alloc:gpu_ntrs)
1605# 1174 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1606#endif
1607#ifdef MFC_DEBUG
1608# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1609 block
1610# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1611 use iso_fortran_env, only: output_unit
1612# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1613
1614# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1615 print *, 'm_model.fpp:1175: ', '@:ALLOCATE(gpu_trs_v(1:3, 1:3, 1:max_ntrs, 1:num_ibs))'
1616# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1617
1618# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1619 call flush (output_unit)
1620# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1621 end block
1622# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1623#endif
1624# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1625 allocate (gpu_trs_v(1:3, 1:3, 1:max_ntrs, 1:num_ibs))
1626# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1627
1628# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1629
1630# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1631#if defined(MFC_OpenACC)
1632# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1633!$acc enter data create(gpu_trs_v)
1634# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1635#elif defined(MFC_OpenMP)
1636# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1637!$omp target enter data map(always,alloc:gpu_trs_v)
1638# 1175 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1639#endif
1640#ifdef MFC_DEBUG
1641# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1642 block
1643# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1644 use iso_fortran_env, only: output_unit
1645# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1646
1647# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1648 print *, 'm_model.fpp:1176: ', '@:ALLOCATE(gpu_trs_n(1:3, 1:max_ntrs, 1:num_ibs))'
1649# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1650
1651# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1652 call flush (output_unit)
1653# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1654 end block
1655# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1656#endif
1657# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1658 allocate (gpu_trs_n(1:3, 1:max_ntrs, 1:num_ibs))
1659# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1660
1661# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1662
1663# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1664#if defined(MFC_OpenACC)
1665# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1666!$acc enter data create(gpu_trs_n)
1667# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1668#elif defined(MFC_OpenMP)
1669# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1670!$omp target enter data map(always,alloc:gpu_trs_n)
1671# 1176 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1672#endif
1673#ifdef MFC_DEBUG
1674# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1675 block
1676# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1677 use iso_fortran_env, only: output_unit
1678# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1679
1680# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1681 print *, 'm_model.fpp:1177: ', '@:ALLOCATE(gpu_boundary_edge_count(1:num_ibs))'
1682# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1683
1684# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1685 call flush (output_unit)
1686# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1687 end block
1688# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1689#endif
1690# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1691 allocate (gpu_boundary_edge_count(1:num_ibs))
1692# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1693
1694# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1695
1696# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1697#if defined(MFC_OpenACC)
1698# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1699!$acc enter data create(gpu_boundary_edge_count)
1700# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1701#elif defined(MFC_OpenMP)
1702# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1703!$omp target enter data map(always,alloc:gpu_boundary_edge_count)
1704# 1177 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1705#endif
1706#ifdef MFC_DEBUG
1707# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1708 block
1709# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1710 use iso_fortran_env, only: output_unit
1711# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1712
1713# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1714 print *, 'm_model.fpp:1178: ', '@:ALLOCATE(gpu_total_vertices(1:num_ibs))'
1715# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1716
1717# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1718 call flush (output_unit)
1719# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1720 end block
1721# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1722#endif
1723# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1724 allocate (gpu_total_vertices(1:num_ibs))
1725# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1726
1727# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1728
1729# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1730#if defined(MFC_OpenACC)
1731# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1732!$acc enter data create(gpu_total_vertices)
1733# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1734#elif defined(MFC_OpenMP)
1735# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1736!$omp target enter data map(always,alloc:gpu_total_vertices)
1737# 1178 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1738#endif
1739
1740 gpu_ntrs = 0
1741 gpu_trs_v = 0._wp
1742 gpu_trs_n = 0._wp
1745
1746 if (max_bv1 > 0) then
1747#ifdef MFC_DEBUG
1748# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1749 block
1750# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1751 use iso_fortran_env, only: output_unit
1752# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1753
1754# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1755 print *, 'm_model.fpp:1187: ', '@:ALLOCATE(gpu_boundary_v(1:max_bv1, 1:max_bv2, 1:max_bv3, 1:num_ibs))'
1756# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1757
1758# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1759 call flush (output_unit)
1760# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1761 end block
1762# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1763#endif
1764# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1765 allocate (gpu_boundary_v(1:max_bv1, 1:max_bv2, 1:max_bv3, 1:num_ibs))
1766# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1767
1768# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1769
1770# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1771#if defined(MFC_OpenACC)
1772# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1773!$acc enter data create(gpu_boundary_v)
1774# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1775#elif defined(MFC_OpenMP)
1776# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1777!$omp target enter data map(always,alloc:gpu_boundary_v)
1778# 1187 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1779#endif
1780 gpu_boundary_v = 0._wp
1781 end if
1782
1783 do pid = 1, num_ibs
1784 if (allocated(models(pid)%model)) then
1785 gpu_ntrs(pid) = models(pid)%ntrs
1786 gpu_trs_v(:, :, 1:models(pid)%ntrs, pid) = models(pid)%trs_v
1787 gpu_trs_n(:, 1:models(pid)%ntrs, pid) = models(pid)%trs_n
1788 gpu_boundary_edge_count(pid) = models(pid)%boundary_edge_count
1789 gpu_total_vertices(pid) = models(pid)%total_vertices
1790 end if
1791 if (allocated(models(pid)%boundary_v) .and. p == 0) then
1792 gpu_boundary_v(1:size(models(pid)%boundary_v, 1), &
1793 1:size(models(pid)%boundary_v, 2), &
1794 1:size(models(pid)%boundary_v, 3), pid) = models(pid)%boundary_v
1795 end if
1796 end do
1797
1798
1799# 1206 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1800#if defined(MFC_OpenACC)
1801# 1206 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1802!$acc update device(gpu_ntrs, gpu_trs_v, gpu_trs_n, gpu_boundary_edge_count, gpu_total_vertices)
1803# 1206 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1804#elif defined(MFC_OpenMP)
1805# 1206 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1806!$omp target update to(gpu_ntrs, gpu_trs_v, gpu_trs_n, gpu_boundary_edge_count, gpu_total_vertices)
1807# 1206 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1808#endif
1809 if (allocated(gpu_boundary_v)) then
1810
1811# 1208 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1812#if defined(MFC_OpenACC)
1813# 1208 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1814!$acc update device(gpu_boundary_v)
1815# 1208 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1816#elif defined(MFC_OpenMP)
1817# 1208 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1818!$omp target update to(gpu_boundary_v)
1819# 1208 "/home/runner/work/MFC/MFC/src/common/m_model.fpp"
1820#endif
1821 end if
1822 end if
1823 end block
1824
1825 end subroutine s_instantiate_stl_models
1826
1827#endif
1828
1830 type(t_model_array), intent(inout) :: ma
1831 integer :: i
1832
1833 ma%ntrs = ma%model%ntrs
1834 allocate (ma%trs_v(1:3, 1:3, 1:ma%ntrs))
1835 allocate (ma%trs_n(1:3, 1:ma%ntrs))
1836
1837 do i = 1, ma%ntrs
1838 ma%trs_v(:, :, i) = ma%model%trs(i)%v(:, :)
1839 ma%trs_n(:, i) = ma%model%trs(i)%n(:)
1840 end do
1841 end subroutine
1842
1843end module m_model
integer, intent(in) k
integer, intent(in) j
integer, intent(in) l
Shared derived types for field data, patch geometry, bubble dynamics, and MPI I/O structures.
Utility routines for bubble model setup, coordinate transforms, array sampling, and special functions...
subroutine, public s_transform_model(model, matrix, matrix_n)
This procedure transforms a model by a matrix, one triangle at a time.
type(t_bbox) function, public f_create_bbox(model)
This procedure creates a bounding box for a model.
pure real(wp) function, dimension(3), public f_cross(a, b)
This procedure computes the cross product of two vectors.
real(wp) function, dimension(1:4, 1:4), public f_create_transform_matrix(param, center)
This procedure creates a transformation matrix.
Binary STL file reader and processor for immersed boundary geometry.
impure subroutine, public s_model_write(filepath, model)
This procedure writes a binary STL file.
impure subroutine s_write_stl(filepath, model)
This procedure writes a binary STL file.
integer function f_intersects_triangle(ray, triangle)
This procedure checks if a ray intersects a triangle.
impure logical function f_read_line(iunit, line)
integer, dimension(:), allocatable, public gpu_total_vertices
impure subroutine s_read_obj(filepath, model)
This procedure reads an OBJ file.
impure real(wp) function, public f_model_is_inside(model, point, spacing, spc)
This procedure, recursively, finds whether a point is inside an octree.
real(wp), dimension(:, :, :, :), allocatable, public gpu_trs_v
real(wp) function, public f_model_is_inside_flat(ntrs, pid, point)
This procedure, given a cell center will determine if a point exists instide a surface.
subroutine, public s_distance_normals_2d(pid, boundary_edge_count, point, normals, distance)
This procedure determines the levelset distance and normals of 2D models by computing the exact close...
impure subroutine s_skip_ignored_lines(iunit, buffered_line, is_buffered)
Reads the next non-comment line from a model file, using a buffered look-ahead mechanism.
subroutine, public s_model_free(model)
This procedure frees the memory allocated for an STL mesh.
integer, dimension(:), allocatable, public gpu_ntrs
subroutine, public s_register_edge(temp_boundary_v, edge, edge_index, edge_count)
This procedure appends the edge end vertices to a temporary buffer.
impure subroutine s_read_stl(filepath, model)
This procedure reads an STL file.
impure type(t_model) function, public f_model_read(filepath)
This procedure reads a mesh from a file.
real(wp), dimension(:, :, :, :), allocatable, public gpu_boundary_v
subroutine, public s_check_boundary(model, boundary_v, boundary_vertex_count, boundary_edge_count)
This procedure checks and labels edges shared by two or more triangles facets of the 2D STL model.
subroutine, public s_distance_normals_3d(ntrs, pid, point, normals, distance)
This procedure determines the levelset distance and normals of 3D models by computing the exact close...
type(t_model_array), dimension(:), allocatable, target, public models
impure subroutine s_write_obj(filepath, model)
This procedure writes an OBJ file.
real(wp), dimension(:, :, :), allocatable, public gpu_trs_n
real(wp), dimension(:, :, :), allocatable, public stl_bounding_boxes
impure subroutine s_read_stl_ascii(filepath, model)
This procedure reads an ASCII STL file.
impure subroutine s_read_stl_binary(filepath, model)
This procedure reads a binary STL file.
subroutine, public s_instantiate_stl_models()
subroutine, public s_pack_model_for_gpu(ma)
integer, dimension(:), allocatable, public gpu_boundary_edge_count
real(wp) function f_model_random_number(seed)
This function is used to replace the fortran random number generator because the native generator is ...
MPI gather and scatter operations for distributing post-process grid and flow-variable data.
Defines parameters for a Model Patch.