Neko 0.9.99
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fld_file.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2023, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
36 use num_types, only: rp, dp, sp, i8
38 use field, only: field_t
39 use field_list, only: field_list_t
40 use dofmap, only: dofmap_t
41 use space, only: space_t
42 use structs, only: array_ptr_t
43 use vector, only: vector_t
45 use mean_flow, only: mean_flow_t
47 use vector, only : vector_t
48 use space, only : space_t
49 use mesh, only : mesh_t
51 use utils, only: neko_error
52 use comm
53 use datadist, only: linear_dist_t
54 use math, only: vlmin, vlmax
57 implicit none
58 private
59
60 real(kind=dp), private, allocatable :: tmp_dp(:)
61 real(kind=sp), private, allocatable :: tmp_sp(:)
62
64 type, public, extends(generic_file_t) :: fld_file_t
65 logical :: dp_precision = .false.
66 contains
67 procedure :: read => fld_file_read
68 procedure :: write => fld_file_write
69 procedure :: set_precision => fld_file_set_precision
70 end type fld_file_t
71
72
73contains
74
77 subroutine fld_file_write(this, data, t)
78 class(fld_file_t), intent(inout) :: this
79 class(*), target, intent(in) :: data
80 real(kind=rp), intent(in), optional :: t
81 type(array_ptr_t) :: x, y, z, u, v, w, p, tem
82 real(kind=rp), allocatable, target :: tempo(:)
83 type(mesh_t), pointer :: msh
84 type(dofmap_t), pointer :: dof
85 type(space_t), pointer :: Xh
86 real(kind=dp) :: time
87 character(len= 132) :: hdr
88 character :: rdcode(10)
89 character(len=6) :: id_str
90 character(len= 1024) :: fname
91 character(len= 1024) :: start_field
92 integer :: i, ierr, n, suffix_pos, tslash_pos
93 integer :: lx, ly, lz, lxyz, gdim, glb_nelv, nelv, offset_el
94 integer, allocatable :: idx(:)
95 type(mpi_status) :: status
96 type(mpi_file) :: fh
97 integer (kind=MPI_OFFSET_KIND) :: mpi_offset, byte_offset, temp_offset
98 real(kind=sp), parameter :: test_pattern = 6.54321
99 type(array_ptr_t), allocatable :: scalar_fields(:)
100 logical :: write_mesh, write_velocity, write_pressure, write_temperature
101 integer :: fld_data_size, n_scalar_fields
102
103 if (present(t)) then
104 time = real(t, dp)
105 else
106 time = 0d0
107 end if
108
109 nullify(msh)
110 nullify(dof)
111 nullify(xh)
112 n_scalar_fields = 0
113 write_pressure = .false.
114 write_velocity = .false.
115 write_temperature = .false.
116
117 select type (data)
118 type is (fld_file_data_t)
119 nelv = data%nelv
120 lx = data%lx
121 ly = data%ly
122 lz = data%lz
123 gdim = data%gdim
124 glb_nelv = data%glb_nelv
125 offset_el = data%offset_el
126
127 if (data%x%n .gt. 0) x%ptr => data%x%x
128 if (data%y%n .gt. 0) y%ptr => data%y%x
129 if (data%z%n .gt. 0) z%ptr => data%z%x
130 if (gdim .eq. 2) z%ptr => data%y%x
131 if (data%u%n .gt. 0) then
132 u%ptr => data%u%x
133 write_velocity = .true.
134 end if
135 if (data%v%n .gt. 0) v%ptr => data%v%x
136 if (data%w%n .gt. 0) w%ptr => data%w%x
137 if (data%p%n .gt. 0) then
138 p%ptr => data%p%x
139 write_pressure = .true.
140 end if
141 if (data%t%n .gt. 0) then
142 write_temperature = .true.
143 tem%ptr => data%t%x
144 end if
145 ! If gdim = 2 and Z-velocity component exists,
146 ! it is stored in last scalar field
147 if (gdim .eq. 2 .and. data%w%n .gt. 0) then
148 n_scalar_fields = data%n_scalars + 1
149 allocate(scalar_fields(n_scalar_fields))
150 do i = 1, n_scalar_fields -1
151 scalar_fields(i)%ptr => data%s(i)%x
152 end do
153 scalar_fields(n_scalar_fields)%ptr => data%w%x
154 else
155 n_scalar_fields = data%n_scalars
156 allocate(scalar_fields(n_scalar_fields+1))
157 do i = 1, n_scalar_fields
158 scalar_fields(i)%ptr => data%s(i)%x
159 end do
160 scalar_fields(n_scalar_fields+1)%ptr => data%w%x
161 end if
162 ! This is very stupid...
163 ! Some compilers cannot handle that these pointers dont point to anything
164 ! (although they are not used) this fixes a segfault due to this.
165 if (nelv .eq. 0) then
166 allocate(tempo(1))
167 x%ptr => tempo
168 y%ptr => tempo
169 z%ptr => tempo
170 u%ptr => tempo
171 v%ptr => tempo
172 w%ptr => tempo
173 p%ptr => tempo
174 tem%ptr => tempo
175 end if
176
177 allocate(idx(nelv))
178 do i = 1, nelv
179 idx(i) = data%idx(i)
180 end do
181 type is (field_t)
182 p%ptr => data%x(:,1,1,1)
183 dof => data%dof
184 write_pressure = .true.
185 write_velocity = .false.
186 type is (field_list_t)
187 select case (data%size())
188 case (1)
189 p%ptr => data%items(1)%ptr%x(:,1,1,1)
190 write_pressure = .true.
191 write_velocity = .false.
192 case (2)
193 p%ptr => data%items(1)%ptr%x(:,1,1,1)
194 tem%ptr => data%items(2)%ptr%x(:,1,1,1)
195 write_pressure = .true.
196 write_temperature = .true.
197 case (3)
198 u%ptr => data%items(1)%ptr%x(:,1,1,1)
199 v%ptr => data%items(2)%ptr%x(:,1,1,1)
200 w%ptr => data%items(3)%ptr%x(:,1,1,1)
201 write_velocity = .true.
202 case (4)
203 p%ptr => data%items(1)%ptr%x(:,1,1,1)
204 u%ptr => data%items(2)%ptr%x(:,1,1,1)
205 v%ptr => data%items(3)%ptr%x(:,1,1,1)
206 w%ptr => data%items(4)%ptr%x(:,1,1,1)
207 write_pressure = .true.
208 write_velocity = .true.
209 case (5:99)
210 p%ptr => data%items(1)%ptr%x(:,1,1,1)
211 u%ptr => data%items(2)%ptr%x(:,1,1,1)
212 v%ptr => data%items(3)%ptr%x(:,1,1,1)
213 w%ptr => data%items(4)%ptr%x(:,1,1,1)
214 tem%ptr => data%items(5)%ptr%x(:,1,1,1)
215 n_scalar_fields = data%size() - 5
216 allocate(scalar_fields(n_scalar_fields))
217 do i = 1, n_scalar_fields
218 scalar_fields(i)%ptr => data%items(i+5)%ptr%x(:,1,1,1)
219 end do
220 write_pressure = .true.
221 write_velocity = .true.
222 write_temperature = .true.
223 case default
224 call neko_error('This many fields not supported yet, fld_file')
225 end select
226 dof => data%dof(1)
227
228 type is (mean_flow_t)
229 u%ptr => data%u%mf%x(:,1,1,1)
230 v%ptr => data%v%mf%x(:,1,1,1)
231 w%ptr => data%w%mf%x(:,1,1,1)
232 p%ptr => data%p%mf%x(:,1,1,1)
233 dof => data%u%mf%dof
234 write_pressure = .true.
235 write_velocity = .true.
236 type is (mean_sqr_flow_t)
237 u%ptr => data%uu%mf%x(:,1,1,1)
238 v%ptr => data%vv%mf%x(:,1,1,1)
239 w%ptr => data%ww%mf%x(:,1,1,1)
240 p%ptr => data%pp%mf%x(:,1,1,1)
241 dof => data%pp%mf%dof
242 write_pressure = .true.
243 write_velocity = .true.
244 class default
245 call neko_error('Invalid data')
246 end select
247 ! Fix things for pointers that do not exist in all data types...
248 if (associated(dof)) then
249 x%ptr => dof%x(:,1,1,1)
250 y%ptr => dof%y(:,1,1,1)
251 z%ptr => dof%z(:,1,1,1)
252 msh => dof%msh
253 xh => dof%Xh
254 end if
255
256 if (associated(msh)) then
257 nelv = msh%nelv
258 glb_nelv = msh%glb_nelv
259 offset_el = msh%offset_el
260 gdim = msh%gdim
261 ! Store global idx of each element
262 allocate(idx(msh%nelv))
263 do i = 1, msh%nelv
264 idx(i) = msh%elements(i)%e%id()
265 end do
266 end if
267
268 if (associated(xh)) then
269 lx = xh%lx
270 ly = xh%ly
271 lz = xh%lz
272 end if
273
274 lxyz = lx*ly*lz
275 n = nelv*lxyz
276
277 if (this%dp_precision) then
278 fld_data_size = mpi_double_precision_size
279 else
280 fld_data_size = mpi_real_size
281 end if
282 if (this%dp_precision) then
283 allocate(tmp_dp(gdim*n))
284 else
285 allocate(tmp_sp(gdim*n))
286 end if
287
288
289 !
290 ! Create fld header for NEKTON's multifile output
291 !
292
293 write_mesh = (this%counter .eq. this%start_counter)
294 call mpi_allreduce(mpi_in_place, write_mesh, 1, &
295 mpi_logical, mpi_lor, neko_comm)
296 call mpi_allreduce(mpi_in_place, write_velocity, 1, &
297 mpi_logical, mpi_lor, neko_comm)
298 call mpi_allreduce(mpi_in_place, write_pressure, 1, &
299 mpi_logical, mpi_lor, neko_comm)
300 call mpi_allreduce(mpi_in_place, write_temperature, 1, &
301 mpi_logical, mpi_lor, neko_comm)
302 call mpi_allreduce(mpi_in_place, n_scalar_fields, 1, &
303 mpi_integer, mpi_max, neko_comm)
304
305 ! Build rdcode note that for field_t, we only support scalar
306 ! fields at the moment
307 rdcode = ' '
308 i = 1
309 if (write_mesh) then
310 rdcode(i) = 'X'
311 i = i + 1
312 end if
313 if (write_velocity) then
314 rdcode(i) = 'U'
315 i = i + 1
316 end if
317 if (write_pressure) then
318 rdcode(i) = 'P'
319 i = i + 1
320 end if
321 if (write_temperature) then
322 rdcode(i) = 'T'
323 i = i + 1
324 end if
325 if (n_scalar_fields .gt. 0 ) then
326 rdcode(i) = 'S'
327 i = i + 1
328 write(rdcode(i), '(i1)') (n_scalar_fields)/10
329 i = i + 1
330 write(rdcode(i), '(i1)') (n_scalar_fields) - 10*((n_scalar_fields)/10)
331 i = i + 1
332 end if
333
335 write(hdr, 1) fld_data_size, lx, ly, lz, glb_nelv, glb_nelv,&
336 time, this%counter, 1, 1, (rdcode(i),i = 1, 10)
3371 format('#std', 1x, i1, 1x, i2, 1x, i2, 1x, i2, 1x, i10, 1x, i10, &
338 1x, e20.13, 1x, i9, 1x, i6, 1x, i6, 1x, 10a)
339
340 ! Change to NEKTON's fld file format
341 suffix_pos = filename_suffix_pos(this%fname)
342 write(id_str, '(a,i5.5)') 'f', this%counter
343 fname = trim(this%fname(1:suffix_pos-1))//'0.'//id_str
344
345 call mpi_file_open(neko_comm, trim(fname), &
346 mpi_mode_wronly + mpi_mode_create, mpi_info_null, fh, &
347 ierr)
348
349 call mpi_file_write_all(fh, hdr, 132, mpi_character, status, ierr)
350 mpi_offset = 132 * mpi_character_size
351
352 call mpi_file_write_all(fh, test_pattern, 1, mpi_real, status, ierr)
353 mpi_offset = mpi_offset + mpi_real_size
354
355 byte_offset = mpi_offset + &
356 int(offset_el, i8) * int(mpi_integer_size, i8)
357 call mpi_file_write_at_all(fh, byte_offset, idx, nelv, &
358 mpi_integer, status, ierr)
359 mpi_offset = mpi_offset + int(glb_nelv, i8) * int(mpi_integer_size, i8)
360 deallocate(idx)
361 if (write_mesh) then
362
363 byte_offset = mpi_offset + int(offset_el, i8) * &
364 (int(gdim*lxyz, i8) * &
365 int(fld_data_size, i8))
366 call fld_file_write_vector_field(this, fh, byte_offset, &
367 x%ptr, y%ptr, z%ptr, &
368 n, gdim, lxyz, nelv)
369 mpi_offset = mpi_offset + int(glb_nelv, i8) * &
370 (int(gdim *lxyz, i8) * &
371 int(fld_data_size, i8))
372 end if
373 if (write_velocity) then
374 byte_offset = mpi_offset + int(offset_el, i8) * &
375 (int(gdim * (lxyz), i8) * int(fld_data_size, i8))
376 call fld_file_write_vector_field(this, fh, byte_offset, &
377 u%ptr, v%ptr, w%ptr, n, gdim, lxyz, nelv)
378
379 mpi_offset = mpi_offset + int(glb_nelv, i8) * &
380 (int(gdim * (lxyz), i8) * &
381 int(fld_data_size, i8))
382
383 end if
384
385 if (write_pressure) then
386 byte_offset = mpi_offset + int(offset_el, i8) * &
387 (int((lxyz), i8) * int(fld_data_size, i8))
388 call fld_file_write_field(this, fh, byte_offset, p%ptr, n)
389 mpi_offset = mpi_offset + int(glb_nelv, i8) * &
390 (int((lxyz), i8) * int(fld_data_size, i8))
391 end if
392
393 if (write_temperature) then
394 byte_offset = mpi_offset + int(offset_el, i8) * &
395 (int((lxyz), i8) * &
396 int(fld_data_size, i8))
397 call fld_file_write_field(this, fh, byte_offset, tem%ptr, n)
398 mpi_offset = mpi_offset + int(glb_nelv, i8) * &
399 (int((lxyz), i8) * &
400 int(fld_data_size, i8))
401 end if
402
403 temp_offset = mpi_offset
404
405 do i = 1, n_scalar_fields
406 ! Without this redundant if statement Cray optimizes this loop to
407 ! Oblivion
408 if (i .eq. 2) then
409 mpi_offset = int(temp_offset, i8) + int(1_i8*glb_nelv, i8) * &
410 (int(lxyz, i8) * int(fld_data_size, i8))
411 end if
412 byte_offset = int(mpi_offset, i8) + int(offset_el, i8) * &
413 (int((lxyz), i8) * &
414 int(fld_data_size, i8))
415 call fld_file_write_field(this, fh, byte_offset, scalar_fields(i)%ptr, n)
416 mpi_offset = int(mpi_offset, i8) + int(glb_nelv, i8) * &
417 (int(lxyz, i8) * &
418 int(fld_data_size, i8))
419 end do
420
421 if (gdim .eq. 3) then
422
424 if (write_mesh) then
425 !The offset is:
426 ! mpioff + element_off * 2(min max value)
427 ! * 4(single precision) * gdim(dimensions)
428 byte_offset = int(mpi_offset, i8) + &
429 int(offset_el, i8) * &
430 int(2, i8) * &
431 int(mpi_real_size, i8) * &
432 int(gdim, i8)
433 call fld_file_write_metadata_vector(this, fh, byte_offset, &
434 x%ptr, y%ptr, z%ptr, gdim, lxyz, nelv)
435 mpi_offset = int(mpi_offset, i8) + &
436 int(glb_nelv, i8) * &
437 int(2, i8) * &
438 int(mpi_real_size, i8) * &
439 int(gdim, i8)
440 end if
441
442 if (write_velocity) then
443 byte_offset = int(mpi_offset, i8) + &
444 int(offset_el, i8) * &
445 int(2, i8) * &
446 int(mpi_real_size, i8) * &
447 int(gdim, i8)
448 call fld_file_write_metadata_vector(this, fh, byte_offset, &
449 u%ptr, v%ptr, w%ptr, gdim, lxyz, nelv)
450 mpi_offset = int(mpi_offset, i8) + &
451 int(glb_nelv, i8) * &
452 int(2, i8) * &
453 int(mpi_real_size, i8) * &
454 int(gdim, i8)
455
456 end if
457
458 if (write_pressure) then
459 byte_offset = int(mpi_offset, i8) + &
460 int(offset_el, i8) * &
461 int(2, i8) * &
462 int(mpi_real_size, i8)
463 call fld_file_write_metadata_scalar(this, fh, byte_offset, &
464 p%ptr, lxyz, nelv)
465 mpi_offset = int(mpi_offset, i8) + &
466 int(glb_nelv, i8) * &
467 int(2, i8) * &
468 int(mpi_real_size, i8)
469
470 end if
471
472 if (write_temperature) then
473 byte_offset = int(mpi_offset, i8) + &
474 int(offset_el, i8) * &
475 int(2, i8) * &
476 int(mpi_real_size, i8)
477 call fld_file_write_metadata_scalar(this, fh, byte_offset, &
478 tem%ptr, lxyz, nelv)
479 mpi_offset = int(mpi_offset, i8) + &
480 int(glb_nelv, i8) * &
481 int(2, i8) * &
482 int(mpi_real_size, i8)
483
484 end if
485
486
487
488 temp_offset = mpi_offset
489
490 do i = 1, n_scalar_fields
491 ! Without this redundant if statement, Cray optimizes this loop to
492 ! Oblivion
493 if (i .eq. 2) then
494 mpi_offset = int(temp_offset, i8) + &
495 int(1_i8*glb_nelv, i8) * &
496 int(2, i8) * &
497 int(mpi_real_size, i8)
498 end if
499
500 byte_offset = int(mpi_offset, i8) + &
501 int(offset_el, i8) * &
502 int(2, i8) * &
503 int(mpi_real_size, i8)
504 call fld_file_write_metadata_scalar(this, fh, byte_offset, &
505 scalar_fields(i)%ptr, lxyz, nelv)
506 mpi_offset = int(mpi_offset, i8) + &
507 int(glb_nelv, i8) * &
508 int(2, i8) * &
509 int(mpi_real_size, i8)
510 end do
511 end if
512
513
514 call mpi_file_sync(fh, ierr)
515 call mpi_file_close(fh, ierr)
516 ! Write metadata file
517 if (pe_rank .eq. 0) then
518 tslash_pos = filename_tslash_pos(this%fname)
519 write(start_field, "(I5,A8)") this%start_counter, '.nek5000'
520 open(unit = 9, &
521 file = trim(this%fname(1:suffix_pos-1)) // &
522 trim(adjustl(start_field)), status = 'replace')
523 write(9, fmt = '(A,A,A)') 'filetemplate: ', &
524 this%fname(tslash_pos+1:suffix_pos-1), '%01d.f%05d'
525 write(9, fmt = '(A,i5)') 'firsttimestep: ', this%start_counter
526 write(9, fmt = '(A,i5)') 'numtimesteps: ', &
527 (this%counter + 1) - this%start_counter
528 close(9)
529 end if
530
531 this%counter = this%counter + 1
532
533 if (allocated(tmp_dp)) deallocate(tmp_dp)
534 if (allocated(tmp_sp)) deallocate(tmp_sp)
535 end subroutine fld_file_write
536
537 subroutine fld_file_write_metadata_vector(this, fh, byte_offset, x, y, z, &
538 gdim, lxyz, nelv)
539 class(fld_file_t), intent(inout) :: this
540 type(mpi_file), intent(inout) :: fh
541 integer, intent(in) :: gdim, lxyz, nelv
542 real(kind=rp), intent(in) :: x(lxyz, nelv), y(lxyz, nelv), z(lxyz, nelv)
543 integer (kind=MPI_OFFSET_KIND), intent(in) :: byte_offset
544 integer :: el, j, ierr, nout
545 type(mpi_status) :: status
546 real(kind=sp) :: buffer(2*gdim*nelv)
547
548 j = 1
549 do el = 1, nelv
550 buffer(j+0) = real(vlmin(x(1, el), lxyz), sp)
551 buffer(j+1) = real(vlmax(x(1, el), lxyz), sp)
552 buffer(j+2) = real(vlmin(y(1, el), lxyz), sp)
553 buffer(j+3) = real(vlmax(y(1, el), lxyz), sp)
554 j = j + 4
555 if (gdim .eq. 3) then
556 buffer(j+0) = real(vlmin(z(1, el), lxyz), sp)
557 buffer(j+1) = real(vlmax(z(1, el), lxyz), sp)
558 j = j + 2
559 end if
560 end do
561
562 ! write out data
563 nout = 2*gdim*nelv
564
565 call mpi_file_write_at_all(fh, byte_offset, buffer, nout, &
566 mpi_real, status, ierr)
567
568 end subroutine fld_file_write_metadata_vector
569
570 subroutine fld_file_write_metadata_scalar(this, fh, byte_offset, x, lxyz, &
571 nelv)
572 class(fld_file_t), intent(inout) :: this
573 type(mpi_file), intent(inout) :: fh
574 integer, intent(in) :: lxyz, nelv
575 real(kind=rp), intent(in) :: x(lxyz, nelv)
576 integer (kind=MPI_OFFSET_KIND), intent(in) :: byte_offset
577 integer :: el, j, ierr, nout
578 type(mpi_status) :: status
579 real(kind=sp) :: buffer(2*nelv)
580
581 j = 1
582 do el = 1, nelv
583 buffer(j+0) = real(vlmin(x(1, el), lxyz), sp)
584 buffer(j+1) = real(vlmax(x(1, el), lxyz), sp)
585 j = j + 2
586 end do
587
588 ! write out data
589 nout = 2*nelv
590
591 call mpi_file_write_at_all(fh, byte_offset, buffer, nout, &
592 mpi_real, status, ierr)
593
594 end subroutine fld_file_write_metadata_scalar
595
596 subroutine fld_file_write_field(this, fh, byte_offset, p, n)
597 class(fld_file_t), intent(inout) :: this
598 type(mpi_file), intent(inout) :: fh
599 integer, intent(inout) :: n
600 real(kind=rp), intent(inout) :: p(n)
601 integer (kind=MPI_OFFSET_KIND), intent(in) :: byte_offset
602 integer :: i, ierr
603 type(mpi_status) :: status
604
605 if ( this%dp_precision) then
606 do i = 1, n
607 tmp_dp(i) = real(p(i), dp)
608 end do
609
610 call mpi_file_write_at_all(fh, byte_offset, tmp_dp, n, &
611 mpi_double_precision, status, ierr)
612 else
613 do i = 1, n
614 tmp_sp(i) = real(p(i), sp)
615 end do
616 call mpi_file_write_at_all(fh, byte_offset, tmp_sp, n, &
617 mpi_real, status, ierr)
618 end if
619
620 end subroutine fld_file_write_field
621
622 subroutine fld_file_write_vector_field(this, fh, byte_offset, x, y, z, n, &
623 gdim, lxyz, nelv)
624 class(fld_file_t), intent(inout) :: this
625 type(mpi_file), intent(inout) :: fh
626 integer, intent(in) :: n, gdim, lxyz, nelv
627 real(kind=rp), intent(in) :: x(lxyz, nelv), y(lxyz, nelv), z(lxyz, nelv)
628 integer (kind=MPI_OFFSET_KIND), intent(in) :: byte_offset
629 integer :: i, el, j, ierr
630 type(mpi_status) :: status
631
632 if (this%dp_precision) then
633 i = 1
634 do el = 1, nelv
635 do j = 1, lxyz
636 tmp_dp(i) = real(x(j, el), dp)
637 i = i +1
638 end do
639 do j = 1, lxyz
640 tmp_dp(i) = real(y(j, el), dp)
641 i = i +1
642 end do
643 if (gdim .eq. 3) then
644 do j = 1, lxyz
645 tmp_dp(i) = real(z(j, el), dp)
646 i = i +1
647 end do
648 end if
649 end do
650 call mpi_file_write_at_all(fh, byte_offset, tmp_dp, gdim*n, &
651 mpi_double_precision, status, ierr)
652 else
653 i = 1
654 do el = 1, nelv
655 do j = 1, lxyz
656 tmp_sp(i) = real(x(j, el), sp)
657 i = i +1
658 end do
659 do j = 1, lxyz
660 tmp_sp(i) = real(y(j, el), sp)
661 i = i +1
662 end do
663 if (gdim .eq. 3) then
664 do j = 1, lxyz
665 tmp_sp(i) = real(z(j, el), sp)
666 i = i +1
667 end do
668 end if
669 end do
670 call mpi_file_write_at_all(fh, byte_offset, tmp_sp, gdim*n, &
671 mpi_real, status, ierr)
672 end if
673
674
675 end subroutine fld_file_write_vector_field
676
678 subroutine fld_file_read(this, data)
679 class(fld_file_t) :: this
680 class(*), target, intent(inout) :: data
681 character(len= 132) :: hdr
682 integer :: ierr, suffix_pos, i, j
683 type(mpi_file) :: fh
684 type(mpi_status) :: status
685 character(len= 1024) :: fname, meta_fname, string, path
686 logical :: meta_file, read_mesh, read_velocity, read_pressure
687 logical :: read_temp
688 character(len=6) :: id_str
689 integer (kind=MPI_OFFSET_KIND) :: mpi_offset, byte_offset
690 integer :: lx, ly, lz, glb_nelv, counter, lxyz
691 integer :: FLD_DATA_SIZE, n_scalars, n
692 real(kind=rp) :: time
693 real(kind=sp) :: temp
694 type(linear_dist_t) :: dist
695 real(kind=sp), parameter :: test_pattern = 6.54321
696 character :: rdcode(10), temp_str(4)
697
698 select type (data)
699 type is (fld_file_data_t)
700 call filename_chsuffix(this%fname, meta_fname, 'nek5000')
701
702 inquire(file = trim(meta_fname), exist = meta_file)
703 if (meta_file .and. data%meta_nsamples .eq. 0) then
704 if (pe_rank .eq. 0) then
705 open(unit = 9, file = trim(meta_fname))
706 read(9, fmt = '(A)') string
707 read(string(14:), fmt = '(A)') string
708 string = trim(string)
709 data%fld_series_fname = string(:scan(trim(string), '%')-1)
710 data%fld_series_fname = adjustl(data%fld_series_fname)
711 data%fld_series_fname = trim(data%fld_series_fname)//'0'
712 read(9, fmt = '(A)') string
713 read(string(scan(string, ':')+1:), *) data%meta_start_counter
714 read(9, fmt = '(A)') string
715 read(string(scan(string, ':')+1:), *) data%meta_nsamples
716
717 close(9)
718 write(*,*) 'Reading meta file for fld series'
719 write(*,*) 'Name: ', trim(data%fld_series_fname)
720 write(*,*) 'Start counter: ', data%meta_start_counter, &
721 'Nsamples: ', data%meta_nsamples
722 end if
723 call mpi_bcast(data%fld_series_fname, 1024, mpi_character, 0, &
724 neko_comm, ierr)
725 call mpi_bcast(data%meta_start_counter, 1, mpi_integer, 0, &
726 neko_comm, ierr)
727 call mpi_bcast(data%meta_nsamples, 1, mpi_integer, 0, &
728 neko_comm, ierr)
729 if (this%counter .eq. 0) this%counter = data%meta_start_counter
730 end if
731
732 if (meta_file) then
733 write(id_str, '(a,i5.5)') 'f', this%counter
734 path = trim(meta_fname(1:scan(meta_fname, '/', .true. )))
735 fname = trim(path)//trim(data%fld_series_fname)//'.'//id_str
736 if (this%counter .ge. data%meta_nsamples+data%meta_start_counter) then
737 call neko_error('Trying to read more fld files than exist')
738 end if
739 else
740 suffix_pos = filename_suffix_pos(this%fname)
741 write(id_str, '(a,i5.5)') 'f', this%counter
742 fname = trim(this%fname(1:suffix_pos-1))//'.'//id_str
743 end if
744 call mpi_file_open(neko_comm, trim(fname), &
745 mpi_mode_rdonly, mpi_info_null, fh, ierr)
746
747 if (ierr .ne. 0) call neko_error("Could not read "//trim(fname))
748
749 call mpi_file_read_all(fh, hdr, 132, mpi_character, status, ierr)
750 ! This read can prorbably be done wihtout the temp variables,
751 ! temp_str, i, j
752
753 read(hdr, 1) temp_str, fld_data_size, lx, ly, lz, glb_nelv, glb_nelv, &
754 time, counter, i, j, (rdcode(i), i = 1, 10)
7551 format(4a, 1x, i1, 1x, i2, 1x, i2, 1x, i2, 1x, i10, 1x, i10, &
756 1x, e20.13, 1x, i9, 1x, i6, 1x, i6, 1x, 10a)
757 if (data%nelv .eq. 0) then
758 dist = linear_dist_t(glb_nelv, pe_rank, pe_size, neko_comm)
759 data%nelv = dist%num_local()
760 data%offset_el = dist%start_idx()
761 end if
762 data%lx = lx
763 data%ly = ly
764 data%lz = lz
765 data%glb_nelv = glb_nelv
766 data%t_counter = counter
767 data%time = time
768 lxyz = lx * ly * lz
769 n = lxyz * data%nelv
770
771 if (lz .eq. 1) then
772 data%gdim = 2
773 else
774 data%gdim = 3
775 end if
776
777
778 if (fld_data_size .eq. mpi_double_precision_size) then
779 this%dp_precision = .true.
780 else
781 this%dp_precision = .false.
782 end if
783 if (this%dp_precision) then
784 allocate(tmp_dp(data%gdim*n))
785 else
786 allocate(tmp_sp(data%gdim*n))
787 end if
788
789
790 i = 1
791 read_mesh = .false.
792 read_velocity = .false.
793 read_pressure = .false.
794 read_temp = .false.
795 if (rdcode(i) .eq. 'X') then
796 read_mesh = .true.
797 if (data%x%n .ne. n) call data%x%init(n)
798 if (data%y%n .ne. n) call data%y%init(n)
799 if (data%z%n .ne. n) call data%z%init(n)
800 i = i + 1
801 end if
802 if (rdcode(i) .eq. 'U') then
803 read_velocity = .true.
804 if (data%u%n .ne. n) call data%u%init(n)
805 if (data%v%n .ne. n) call data%v%init(n)
806 if (data%w%n .ne. n) call data%w%init(n)
807 i = i + 1
808 end if
809 if (rdcode(i) .eq. 'P') then
810 read_pressure = .true.
811 if (data%p%n .ne. n) call data%p%init(n)
812 i = i + 1
813 end if
814 if (rdcode(i) .eq. 'T') then
815 read_temp = .true.
816 if (data%t%n .ne. n) call data%t%init(n)
817 i = i + 1
818 end if
819 n_scalars = 0
820 if (rdcode(i) .eq. 'S') then
821 i = i + 1
822 read(rdcode(i),*) n_scalars
823 n_scalars = n_scalars*10
824 i = i + 1
825 read(rdcode(i),*) j
826 n_scalars = n_scalars+j
827 i = i + 1
828 if (allocated(data%s)) then
829 if (data%n_scalars .ne. n_scalars) then
830 do j = 1, data%n_scalars
831 call data%s(j)%free()
832 end do
833 deallocate(data%s)
834 data%n_scalars = n_scalars
835 allocate(data%s(n_scalars))
836 do j = 1, data%n_scalars
837 call data%s(j)%init(n)
838 end do
839 end if
840 else
841 data%n_scalars = n_scalars
842 allocate(data%s(data%n_scalars))
843 do j = 1, data%n_scalars
844 call data%s(j)%init(n)
845 end do
846 end if
847 i = i + 1
848 end if
849
850 mpi_offset = 132 * mpi_character_size
851 call mpi_file_read_at_all(fh, mpi_offset, temp, 1, &
852 mpi_real, status, ierr)
853 if (temp .ne. test_pattern) then
854 call neko_error('Incorrect format for fld file, &
855 &test pattern does not match.')
856 end if
857 mpi_offset = mpi_offset + mpi_real_size
858
859
860 if (allocated(data%idx)) then
861 if (size(data%idx) .ne. data%nelv) then
862 deallocate(data%idx)
863 allocate(data%idx(data%nelv))
864 end if
865 else
866 allocate(data%idx(data%nelv))
867 end if
868
869 byte_offset = mpi_offset + &
870 int(data%offset_el, i8) * int(mpi_integer_size, i8)
871
872 call mpi_file_read_at_all(fh, byte_offset, data%idx, data%nelv, &
873 mpi_integer, status, ierr)
874
875 mpi_offset = mpi_offset + &
876 int(data%glb_nelv, i8) * int(mpi_integer_size, i8)
877
878 if (read_mesh) then
879 byte_offset = mpi_offset + int(data%offset_el, i8) * &
880 (int(data%gdim*lxyz, i8) * &
881 int(fld_data_size, i8))
882 call fld_file_read_vector_field(this, fh, byte_offset, &
883 data%x, data%y, data%z, data)
884 mpi_offset = mpi_offset + int(data%glb_nelv, i8) * &
885 (int(data%gdim *lxyz, i8) * &
886 int(fld_data_size, i8))
887 end if
888
889 if (read_velocity) then
890 byte_offset = mpi_offset + int(data%offset_el, i8) * &
891 (int(data%gdim*lxyz, i8) * &
892 int(fld_data_size, i8))
893 call fld_file_read_vector_field(this, fh, byte_offset, &
894 data%u, data%v, data%w, data)
895 mpi_offset = mpi_offset + int(data%glb_nelv, i8) * &
896 (int(data%gdim *lxyz, i8) * &
897 int(fld_data_size, i8))
898 end if
899
900 if (read_pressure) then
901 byte_offset = mpi_offset + int(data%offset_el, i8) * &
902 (int(lxyz, i8) * &
903 int(fld_data_size, i8))
904 call fld_file_read_field(this, fh, byte_offset, data%p, data)
905 mpi_offset = mpi_offset + int(data%glb_nelv, i8) * &
906 (int(lxyz, i8) * &
907 int(fld_data_size, i8))
908 end if
909
910 if (read_temp) then
911 byte_offset = mpi_offset + int(data%offset_el, i8) * &
912 (int(lxyz, i8) * &
913 int(fld_data_size, i8))
914 call fld_file_read_field(this, fh, byte_offset, data%t, data)
915 mpi_offset = mpi_offset + int(data%glb_nelv, i8) * &
916 (int(lxyz, i8) * &
917 int(fld_data_size, i8))
918 end if
919
920 do i = 1, n_scalars
921 byte_offset = mpi_offset + int(data%offset_el, i8) * &
922 (int(lxyz, i8) * &
923 int(fld_data_size, i8))
924 call fld_file_read_field(this, fh, byte_offset, data%s(i), data)
925 mpi_offset = mpi_offset + int(data%glb_nelv, i8) * &
926 (int(lxyz, i8) * &
927 int(fld_data_size, i8))
928 end do
929
930 this%counter = this%counter + 1
931
932 if (allocated(tmp_dp)) deallocate(tmp_dp)
933 if (allocated(tmp_sp)) deallocate(tmp_sp)
934 class default
935 call neko_error('Currently we only read into fld_file_data_t, &
936 &please use that data structure instead.')
937 end select
938
939 end subroutine fld_file_read
940
941 subroutine fld_file_read_field(this, fh, byte_offset, x, fld_data)
942 class(fld_file_t), intent(inout) :: this
943 type(vector_t), intent(inout) :: x
944 type(fld_file_data_t) :: fld_data
945 integer(kind=MPI_OFFSET_KIND) :: byte_offset
946 type(mpi_file) :: fh
947 type(mpi_status) :: status
948 integer :: n, ierr, lxyz, i
949
950 n = x%n
951 lxyz = fld_data%lx*fld_data%ly*fld_data%lz
952
953 if (this%dp_precision) then
954 call mpi_file_read_at_all(fh, byte_offset, tmp_dp, n, &
955 mpi_double_precision, status, ierr)
956 else
957 call mpi_file_read_at_all(fh, byte_offset, tmp_sp, n, &
958 mpi_real, status, ierr)
959 end if
960
961 if (this%dp_precision) then
962 do i = 1, n
963 x%x(i) = tmp_dp(i)
964 end do
965 else
966 do i = 1, n
967 x%x(i) = tmp_sp(i)
968 end do
969 end if
970
971
972 end subroutine fld_file_read_field
973
974
975 subroutine fld_file_read_vector_field(this, fh, byte_offset, &
976 x, y, z, fld_data)
977 class(fld_file_t), intent(inout) :: this
978 type(vector_t), intent(inout) :: x, y, z
979 type(fld_file_data_t) :: fld_data
980 integer(kind=MPI_OFFSET_KIND) :: byte_offset
981 type(mpi_file) :: fh
982 type(mpi_status) :: status
983 integer :: n, ierr, lxyz, i, j, e, nd
984
985 n = x%n
986 nd = n*fld_data%gdim
987 lxyz = fld_data%lx*fld_data%ly*fld_data%lz
988
989 if (this%dp_precision) then
990 call mpi_file_read_at_all(fh, byte_offset, tmp_dp, nd, &
991 mpi_double_precision, status, ierr)
992 else
993 call mpi_file_read_at_all(fh, byte_offset, tmp_sp, nd, &
994 mpi_real, status, ierr)
995 end if
996
997
998 if (this%dp_precision) then
999 i = 1
1000 do e = 1, fld_data%nelv
1001 do j = 1, lxyz
1002 x%x((e-1)*lxyz+j) = tmp_dp(i)
1003 i = i +1
1004 end do
1005 do j = 1, lxyz
1006 y%x((e-1)*lxyz+j) = tmp_dp(i)
1007 i = i +1
1008 end do
1009 if (fld_data%gdim .eq. 3) then
1010 do j = 1, lxyz
1011 z%x((e-1)*lxyz+j) = tmp_dp(i)
1012 i = i +1
1013 end do
1014 end if
1015 end do
1016 else
1017 i = 1
1018 do e = 1, fld_data%nelv
1019 do j = 1, lxyz
1020 x%x((e-1)*lxyz+j) = tmp_sp(i)
1021 i = i +1
1022 end do
1023 do j = 1, lxyz
1024 y%x((e-1)*lxyz+j) = tmp_sp(i)
1025 i = i +1
1026 end do
1027 if (fld_data%gdim .eq. 3) then
1028 do j = 1, lxyz
1029 z%x((e-1)*lxyz+j) = tmp_sp(i)
1030 i = i +1
1031 end do
1032 end if
1033 end do
1034 end if
1035
1036 end subroutine fld_file_read_vector_field
1037
1038 subroutine fld_file_set_precision(this, precision)
1039 class(fld_file_t) :: this
1040 integer, intent(in) :: precision
1041
1042 if (precision .eq. dp) then
1043 this%dp_precision = .true.
1044 else if (precision .eq. sp) then
1045 this%dp_precision = .false.
1046 else
1047 call neko_error('Invalid precision')
1048 end if
1049
1050 end subroutine fld_file_set_precision
1051
1052
1053end module fld_file
double real
Definition comm.F90:1
integer pe_rank
MPI rank.
Definition comm.F90:28
type(mpi_comm) neko_comm
MPI communicator.
Definition comm.F90:16
integer pe_size
MPI size of communicator.
Definition comm.F90:31
Defines practical data distributions.
Definition datadist.f90:34
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
Module for file I/O operations.
Definition file.f90:34
Simple module to handle fld file series. Provides an interface to the different fields sotred in a fl...
NEKTON fld file format.
Definition fld_file.f90:35
real(kind=dp), dimension(:), allocatable, private tmp_dp
Definition fld_file.f90:60
subroutine fld_file_set_precision(this, precision)
subroutine fld_file_read_vector_field(this, fh, byte_offset, x, y, z, fld_data)
Definition fld_file.f90:977
subroutine fld_file_read(this, data)
Load a field from a NEKTON fld file.
Definition fld_file.f90:679
subroutine fld_file_write_vector_field(this, fh, byte_offset, x, y, z, n, gdim, lxyz, nelv)
Definition fld_file.f90:624
subroutine fld_file_write_metadata_vector(this, fh, byte_offset, x, y, z, gdim, lxyz, nelv)
Definition fld_file.f90:539
real(kind=sp), dimension(:), allocatable, private tmp_sp
Definition fld_file.f90:61
subroutine fld_file_read_field(this, fh, byte_offset, x, fld_data)
Definition fld_file.f90:942
subroutine fld_file_write_field(this, fh, byte_offset, p, n)
Definition fld_file.f90:597
subroutine fld_file_write_metadata_scalar(this, fh, byte_offset, x, lxyz, nelv)
Definition fld_file.f90:572
subroutine fld_file_write(this, data, t)
Write fields to a NEKTON fld file.
Definition fld_file.f90:78
Definition math.f90:60
real(kind=rp) function, public vlmin(vec, n)
minimun value of a vector of length n
Definition math.f90:462
real(kind=rp) function, public vlmax(vec, n)
maximum value of a vector of length n
Definition math.f90:451
Defines a mean flow field.
Definition mean_flow.f90:34
Defines a mean squared flow field.
Defines a mesh.
Definition mesh.f90:34
MPI derived types.
Definition mpi_types.f90:34
integer, public mpi_double_precision_size
Size of MPI type double precision.
Definition mpi_types.f90:61
integer, public mpi_character_size
Size of MPI type character.
Definition mpi_types.f90:62
integer, public mpi_real_size
Size of MPI type real.
Definition mpi_types.f90:60
integer, public mpi_integer_size
Size of MPI type integer.
Definition mpi_types.f90:63
integer, parameter, public i2
Definition num_types.f90:5
integer, parameter, public i8
Definition num_types.f90:7
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a function space.
Definition space.f90:34
Defines structs that are used... Dont know if we should keep it though.
Definition structs.f90:2
Utilities.
Definition utils.f90:35
subroutine, public filename_chsuffix(fname, new_fname, new_suffix)
Change a filename's suffix.
Definition utils.f90:77
pure integer function, public filename_tslash_pos(fname)
Find position (in the string) of a filename's trailing slash.
Definition utils.f90:63
pure integer function, public filename_suffix_pos(fname)
Find position (in the string) of a filename's suffix.
Definition utils.f90:56
Defines a vector.
Definition vector.f90:34
Load-balanced linear distribution .
Definition datadist.f90:50
field_list_t, To be able to group fields together
Interface for NEKTON fld files.
Definition fld_file.f90:64
A generic file handler.
The function space for the SEM solution fields.
Definition space.f90:62
Pointer to array.
Definition structs.f90:14