Neko  0.8.99
A portable framework for high-order spectral element flow simulations
sampler.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 !
34 module sampler
35  use output, only: output_t
36  use fld_file, only: fld_file_t
37  use comm
38  use logger, only : neko_log, log_size
39  use utils, only : neko_error
41  use num_types, only : rp, dp
43  implicit none
44  private
45 
47  type, private :: outp_t
48  class(output_t), pointer :: outp
49  end type outp_t
50 
52  type, public :: sampler_t
54  type(outp_t), allocatable :: output_list(:)
56  type(time_based_controller_t), allocatable :: controllers(:)
58  integer :: n
60  integer :: size
62  real(kind=rp) :: t_end
63  contains
65  procedure, pass(this) :: init => sampler_init
67  procedure, pass(this) :: free => sampler_free
69  procedure, pass(this) :: add => sampler_add
71  procedure, pass(this) :: sample => sampler_sample
73  procedure, pass(this) :: set_counter => sampler_set_counter
74  end type sampler_t
75 
76 contains
77 
79  subroutine sampler_init(this, T_end, size)
80  class(sampler_t), intent(inout) :: this
81  integer, intent(in), optional :: size
82  real(kind=rp), intent(in) :: t_end
83  character(len=LOG_SIZE) :: log_buf
84  integer :: n, i
85 
86 
87  call this%free()
88 
89  if (present(size)) then
90  n = size
91  else
92  n = 1
93  end if
94 
95  allocate(this%output_list(n))
96  allocate(this%controllers(n))
97 
98  do i = 1, n
99  this%output_list(i)%outp => null()
100  end do
101 
102  this%size = n
103  this%n = 0
104  this%T_end = t_end
105 
106  end subroutine sampler_init
107 
109  subroutine sampler_free(this)
110  class(sampler_t), intent(inout) :: this
111 
112  if (allocated(this%output_list)) then
113  deallocate(this%output_list)
114  end if
115  if (allocated(this%controllers)) then
116  deallocate(this%controllers)
117  end if
118 
119  this%n = 0
120  this%size = 0
121 
122  end subroutine sampler_free
123 
125  subroutine sampler_add(this, out, write_par, write_control)
126  class(sampler_t), intent(inout) :: this
127  class(output_t), intent(inout), target :: out
128  real(kind=rp), intent(in) :: write_par
129  character(len=*), intent(in) :: write_control
130  type(outp_t), allocatable :: tmp(:)
131  type(time_based_controller_t), allocatable :: tmp_ctrl(:)
132  character(len=LOG_SIZE) :: log_buf
133  integer :: n
134  class(*), pointer :: ft
135 
136  if (this%n .ge. this%size) then
137  allocate(tmp(this%size * 2))
138  tmp(1:this%size) = this%output_list
139  call move_alloc(tmp, this%output_list)
140 
141  allocate(tmp_ctrl(this%size * 2))
142  tmp_ctrl(1:this%size) = this%controllers
143  call move_alloc(tmp_ctrl, this%controllers)
144 
145  this%size = this%size * 2
146  end if
147 
148  this%n = this%n + 1
149  n = this%n
150  this%output_list(this%n)%outp => out
151 
152  if (trim(write_control) .eq. "org") then
153  this%controllers(n) = this%controllers(1)
154  else
155  call this%controllers(n)%init(this%T_end, write_control, write_par)
156  end if
157 
158  ! The code below only prints to console
159  call neko_log%section('Adding write output')
160  call neko_log%message('File name : '// &
161  trim(this%output_list(this%n)%outp%file_%file_type%fname))
162  call neko_log%message('Write control : '//trim(write_control))
163 
164  ! Show the output precision if we are outputting an fld file
165  select type(ft => out%file_%file_type)
166  type is (fld_file_t)
167  if (ft%dp_precision) then
168  call neko_log%message('Output precision : double')
169  else
170  call neko_log%message('Output precision : single')
171  end if
172  end select
173 
174  if (trim(write_control) .eq. 'simulationtime') then
175  write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
176  this%controllers(n)%frequency
177  call neko_log%message(log_buf)
178  write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
179  this%controllers(n)%time_interval
180  call neko_log%message(log_buf)
181  else if (trim(write_control) .eq. 'nsamples') then
182  write(log_buf, '(A,I13)') 'Total samples: ', int(write_par)
183  call neko_log%message(log_buf)
184  write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
185  this%controllers(n)%frequency
186  call neko_log%message(log_buf)
187  write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
188  this%controllers(n)%time_interval
189  call neko_log%message(log_buf)
190  else if (trim(write_control) .eq. 'tsteps') then
191  write(log_buf, '(A,I13)') 'Time step interval: ', int(write_par)
192  call neko_log%message(log_buf)
193  else if (trim(write_control) .eq. 'org') then
194  write(log_buf, '(A)') &
195  'Write control not set, defaulting to first output settings'
196  call neko_log%message(log_buf)
197  end if
198 
199  call neko_log%end_section()
200  end subroutine sampler_add
201 
203  subroutine sampler_sample(this, t, tstep, ifforce)
204  class(sampler_t), intent(inout) :: this
205  real(kind=rp), intent(in) :: t
206  integer, intent(in) :: tstep
207  logical, intent(in), optional :: ifforce
208  real(kind=dp) :: sample_start_time, sample_end_time
209  real(kind=dp) :: sample_time
210  character(len=LOG_SIZE) :: log_buf
211  integer :: i, ierr
212  logical :: force, write_output, write_output_test
213 
214  if (present(ifforce)) then
215  force = ifforce
216  else
217  force = .false.
218  end if
219 
220  call profiler_start_region('Sampler', 22)
221  !Do we need this Barrier?
222  call mpi_barrier(neko_comm, ierr)
223  sample_start_time = mpi_wtime()
224 
225  write_output = .false.
226  ! Determine if at least one output needs to be written
227  ! We should not need this extra select block, and it works great
228  ! without it for GNU, Intel and NEC, but breaks horribly on Cray
229  ! (>11.0.x) when using high opt. levels.
230  select type (samp => this)
231  type is (sampler_t)
232  do i = 1, samp%n
233  if (this%controllers(i)%check(t, tstep, force)) then
234  write_output = .true.
235  exit
236  end if
237  end do
238  end select
239 
240  if (write_output) then
241  call neko_log%section('Writer output ')
242  end if
243 
244  ! Loop through the outputs and write if necessary.
245  ! We should not need this extra select block, and it works great
246  ! without it for GNU, Intel and NEC, but breaks horribly on Cray
247  ! (>11.0.x) when using high opt. levels.
248  select type (samp => this)
249  type is (sampler_t)
250  do i = 1, this%n
251  if (this%controllers(i)%check(t, tstep, force)) then
252  call neko_log%message('File name : '// &
253  trim(samp%output_list(i)%outp%file_%file_type%fname))
254 
255  write(log_buf, '(A,I6)') 'Output number :', &
256  int(this%controllers(i)%nexecutions)
257  call neko_log%message(log_buf)
258 
259  call samp%output_list(i)%outp%sample(t)
260 
261  call this%controllers(i)%register_execution()
262  end if
263  end do
264  class default
265  call neko_error('Invalid sampler output list')
266  end select
267 
268  call mpi_barrier(neko_comm, ierr)
269  sample_end_time = mpi_wtime()
270 
271  sample_time = sample_end_time - sample_start_time
272  if (write_output) then
273  write(log_buf,'(A16,1x,F10.6,A,F9.6)') 'Writing at time:', t, &
274  ' Output time (s): ', sample_time
275  call neko_log%message(log_buf)
276  call neko_log%end_section()
277  end if
278  call profiler_end_region('Sampler', 22)
279  end subroutine sampler_sample
280 
282  subroutine sampler_set_counter(this, t)
283  class(sampler_t), intent(inout) :: this
284  real(kind=rp), intent(in) :: t
285  integer :: i
286 
287 
288  do i = 1, this%n
289  if (this%controllers(i)%nsteps .eq. 0) then
290  this%controllers(i)%nexecutions = &
291  int(t / this%controllers(i)%time_interval) + 1
292 
293  call this%output_list(i)%outp%set_counter(this%controllers(i)%nexecutions)
294  call this%output_list(i)%outp%set_start_counter(this%controllers(i)%nexecutions)
295  end if
296  end do
297 
298  end subroutine sampler_set_counter
299 
301  subroutine sampler_set_sample_count(this, sample_number)
302  class(sampler_t), intent(inout) :: this
303  integer, intent(in) :: sample_number
304  integer :: i
305 
306  do i = 1, this%n
307  this%controllers(i)%nexecutions = sample_number
308  call this%output_list(i)%outp%set_counter(this%controllers(i)%nexecutions)
309  call this%output_list(i)%outp%set_start_counter(this%controllers(i)%nexecutions)
310  end do
311 
312  end subroutine sampler_set_sample_count
313 
314 
315 end module sampler
Definition: comm.F90:1
type(mpi_comm) neko_comm
MPI communicator.
Definition: comm.F90:16
NEKTON fld file format.
Definition: fld_file.f90:35
Logging routines.
Definition: log.f90:34
type(log_t), public neko_log
Global log stream.
Definition: log.f90:61
integer, parameter, public log_size
Definition: log.f90:40
integer, parameter, public dp
Definition: num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition: num_types.f90:12
Defines an output.
Definition: output.f90:34
Profiling interface.
Definition: profiler.F90:34
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
Definition: profiler.F90:78
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition: profiler.F90:109
Defines a sampler.
Definition: sampler.f90:34
subroutine sampler_add(this, out, write_par, write_control)
Add an output out to the sampler.
Definition: sampler.f90:126
subroutine sampler_sample(this, t, tstep, ifforce)
Sample all outputs in the sampler.
Definition: sampler.f90:204
subroutine sampler_set_sample_count(this, sample_number)
Set sampling counter (after restart) explicitly.
Definition: sampler.f90:302
subroutine sampler_free(this)
Deallocate a sampler.
Definition: sampler.f90:110
subroutine sampler_set_counter(this, t)
Set sampling counter based on time (after restart)
Definition: sampler.f90:283
subroutine sampler_init(this, T_end, size)
Initialize a sampler.
Definition: sampler.f90:80
Contains the time_based_controller_t type.
Utilities.
Definition: utils.f90:35
Interface for NEKTON fld files.
Definition: fld_file.f90:64
Abstract type defining an output type.
Definition: output.f90:41
Pointer to an arbitrary output.
Definition: sampler.f90:47
A utility type for determening whether an action should be executed based on the current time value....