Loading [MathJax]/extensions/tex2jax.js
Neko 0.9.99
A portable framework for high-order spectral element flow simulations
All Classes Namespaces Files Functions Variables Typedefs Enumerator Macros Pages
output_controller.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 use output, only: output_t, output_ptr_t
36 use fld_file, only: fld_file_t
37 use comm
38 use time_state, only : time_state_t
39 use logger, only : neko_log, log_size
40 use utils, only : neko_error
42 use num_types, only : rp, dp
44 implicit none
45 private
46
47
52 type, public :: output_controller_t
54 type(output_ptr_t), allocatable :: output_list(:)
56 type(time_based_controller_t), allocatable :: controllers(:)
58 integer :: n
60 integer :: size
62 real(kind=rp) :: time_end
63 contains
65 procedure, pass(this) :: init => output_controller_init
67 procedure, pass(this) :: free => output_controller_free
69 procedure, pass(this) :: add => output_controller_add
71 procedure, pass(this) :: execute => output_controller_execute
73 procedure, pass(this) :: set_counter => output_controller_set_counter
74 end type output_controller_t
75
76contains
77
82 subroutine output_controller_init(this, time_end, size)
83 class(output_controller_t), intent(inout) :: this
84 integer, intent(in), optional :: size
85 real(kind=rp), intent(in) :: time_end
86 character(len=LOG_SIZE) :: log_buf
87 integer :: n, i
88
89 call this%free()
90
91 if (present(size)) then
92 n = size
93 else
94 n = 1
95 end if
96
97 allocate(this%output_list(n))
98 allocate(this%controllers(n))
99
100 do i = 1, n
101 this%output_list(i)%ptr => null()
102 end do
103
104 this%size = n
105 this%n = 0
106 this%time_end = time_end
107
108 end subroutine output_controller_init
109
111 subroutine output_controller_free(this)
112 class(output_controller_t), intent(inout) :: this
113
114 if (allocated(this%output_list)) then
115 deallocate(this%output_list)
116 end if
117 if (allocated(this%controllers)) then
118 deallocate(this%controllers)
119 end if
120
121 this%n = 0
122 this%size = 0
123
124 end subroutine output_controller_free
125
133 subroutine output_controller_add(this, out, write_par, write_control, &
134 start_time)
135 class(output_controller_t), intent(inout) :: this
136 class(output_t), intent(inout), target :: out
137 real(kind=rp), intent(in) :: write_par
138 character(len=*), intent(in) :: write_control
139 real(kind=rp), optional, intent(in) :: start_time
140 type(output_ptr_t), allocatable :: tmp(:)
141 type(time_based_controller_t), allocatable :: tmp_ctrl(:)
142 character(len=LOG_SIZE) :: log_buf
143 integer :: n, nexecutions
144 class(*), pointer :: ft
145
146 if (this%n .ge. this%size) then
147 allocate(tmp(this%size * 2))
148 tmp(1:this%size) = this%output_list
149 call move_alloc(tmp, this%output_list)
150
151 allocate(tmp_ctrl(this%size * 2))
152 tmp_ctrl(1:this%size) = this%controllers
153 call move_alloc(tmp_ctrl, this%controllers)
154
155 this%size = this%size * 2
156 end if
157
158
159 this%n = this%n + 1
160 n = this%n
161 this%output_list(this%n)%ptr => out
162
163 if (trim(write_control) .eq. "org") then
164 this%controllers(n) = this%controllers(1)
165 else
166 call this%controllers(n)%init(this%time_end, write_control, write_par)
167 end if
168
169 if (present(start_time)) then
170 if (start_time .gt. 0.0_rp) then
171 nexecutions = int(start_time / this%controllers(n)%time_interval) + 1
172 this%controllers(n)%nexecutions = nexecutions
173 call this%output_list(n)%ptr%set_counter(nexecutions)
174 call this%output_list(n)%ptr%set_start_counter(nexecutions)
175 end if
176 end if
177 ! The code below only prints to console
178 call neko_log%section('Adding write output')
179 call neko_log%message('File name : '// &
180 trim(this%output_list(this%n)%ptr%file_%file_type%fname))
181 call neko_log%message('Write control : '//trim(write_control))
182
183 ! Show the output precision if we are outputting an fld file
184 select type (ft => out%file_%file_type)
185 type is (fld_file_t)
186 if (ft%dp_precision) then
187 call neko_log%message('Output precision : double')
188 else
189 call neko_log%message('Output precision : single')
190 end if
191 end select
192
193 if (trim(write_control) .eq. 'simulationtime') then
194 write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
195 this%controllers(n)%frequency
196 call neko_log%message(log_buf)
197 write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
198 this%controllers(n)%time_interval
199 call neko_log%message(log_buf)
200 else if (trim(write_control) .eq. 'nsamples') then
201 write(log_buf, '(A,I13)') 'Total samples: ', int(write_par)
202 call neko_log%message(log_buf)
203 write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
204 this%controllers(n)%frequency
205 call neko_log%message(log_buf)
206 write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
207 this%controllers(n)%time_interval
208 call neko_log%message(log_buf)
209 else if (trim(write_control) .eq. 'tsteps') then
210 write(log_buf, '(A,I13)') 'Time step interval: ', int(write_par)
211 call neko_log%message(log_buf)
212 else if (trim(write_control) .eq. 'org') then
213 write(log_buf, '(A)') &
214 'Write control not set, defaulting to first output settings'
215 call neko_log%message(log_buf)
216 end if
217
218 call neko_log%end_section()
219 end subroutine output_controller_add
220
226 subroutine output_controller_execute(this, time, ifforce)
227 class(output_controller_t), intent(inout) :: this
228 type(time_state_t), intent(in) :: time
229 logical, intent(in), optional :: ifforce
230 real(kind=dp) :: sample_start_time, sample_end_time
231 real(kind=dp) :: sample_time
232 character(len=LOG_SIZE) :: log_buf
233 integer :: i, ierr
234 logical :: force, write_output, write_output_test
235
236 if (present(ifforce)) then
237 force = ifforce
238 else
239 force = .false.
240 end if
241
242 call profiler_start_region('Output controller', 22)
243 !Do we need this Barrier?
244 call mpi_barrier(neko_comm, ierr)
245 sample_start_time = mpi_wtime()
246
247 write_output = .false.
248 ! Determine if at least one output needs to be written
249 ! We should not need this extra select block, and it works great
250 ! without it for GNU, Intel and NEC, but breaks horribly on Cray
251 ! (>11.0.x) when using high opt. levels.
252 select type (samp => this)
253 type is (output_controller_t)
254 do i = 1, samp%n
255 if (this%controllers(i)%check(time, force)) then
256 write_output = .true.
257 exit
258 end if
259 end do
260 end select
261
262 if (write_output) then
263 call neko_log%section('Writer output ')
264 end if
265
266 ! Loop through the outputs and write if necessary.
267 ! We should not need this extra select block, and it works great
268 ! without it for GNU, Intel and NEC, but breaks horribly on Cray
269 ! (>11.0.x) when using high opt. levels.
270 select type (samp => this)
271 type is (output_controller_t)
272 do i = 1, this%n
273 if (this%controllers(i)%check(time, force)) then
274 call neko_log%message('File name : '// &
275 trim(samp%output_list(i)%ptr%file_%file_type%fname))
276
277 write(log_buf, '(A,I6)') 'Output number :', &
278 int(this%controllers(i)%nexecutions)
279 call neko_log%message(log_buf)
280
281 call samp%output_list(i)%ptr%sample(time%t)
282
283 call this%controllers(i)%register_execution()
284 end if
285 end do
286 class default
287 call neko_error('Invalid output_controller output list')
288 end select
289
290 call mpi_barrier(neko_comm, ierr)
291 sample_end_time = mpi_wtime()
292
293 sample_time = sample_end_time - sample_start_time
294 if (write_output) then
295 write(log_buf, '(A16,1x,F12.6,A,F9.6)') 'Writing at time:', time%t, &
296 ' Output time (s): ', sample_time
297 call neko_log%message(log_buf)
298 call neko_log%end_section()
299 end if
300 call profiler_end_region('Output controller', 22)
301 end subroutine output_controller_execute
302
305 subroutine output_controller_set_counter(this, time)
306 class(output_controller_t), intent(inout) :: this
307 type(time_state_t), intent(in) :: time
308 integer :: i, nexecutions
309
310
311 do i = 1, this%n
312 if (this%controllers(i)%nsteps .eq. 0) then
313 call this%controllers(i)%set_counter(time)
314 nexecutions =this%controllers(i)%nexecutions
315 call this%output_list(i)%ptr%set_counter(nexecutions)
316 call this%output_list(i)%ptr%set_start_counter(nexecutions)
317 end if
318 end do
319
320 end subroutine output_controller_set_counter
321
324 subroutine output_controller_set_write_count(this, counter)
325 class(output_controller_t), intent(inout) :: this
326 integer, intent(in) :: counter
327 integer :: i
328
329 do i = 1, this%n
330 this%controllers(i)%nexecutions = counter
331 call this%output_list(i)%ptr%set_counter(counter)
332 call this%output_list(i)%ptr%set_start_counter(counter)
333 end do
334
336
337
338end module output_controller
Definition comm.F90:1
type(mpi_comm) neko_comm
MPI communicator.
Definition comm.F90:38
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:65
integer, parameter, public log_size
Definition log.f90:42
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements output_controller_t
subroutine output_controller_execute(this, time, ifforce)
Query each of the controllers whether it is time to write, and if so, do so for the corresponding out...
subroutine output_controller_free(this)
Destructor.
subroutine output_controller_init(this, time_end, size)
Constructor.
subroutine output_controller_add(this, out, write_par, write_control, start_time)
Add an output out to the controller.
subroutine output_controller_set_counter(this, time)
Set write counter based on time (after restart)
subroutine output_controller_set_write_count(this, counter)
Set write counter (after restart) explicitly.
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
Contains the time_based_controller_t type.
Module with things related to the simulation time.
Utilities.
Definition utils.f90:35
Interface for NEKTON fld files.
Definition fld_file.f90:64
Wrapper around an output_t pointer.
Definition output.f90:51
Abstract type defining an output type.
Definition output.f90:41
Centralized controller for a list of outputs.
A utility type for determining whether an action should be executed based on the current time value....
A struct that contains all info about the time, expand as needed.