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