Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
output_controller.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2025, 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 use mpi_f08, only : mpi_wtime, mpi_barrier
45 implicit none
46 private
47
48
53 type, public :: output_controller_t
55 type(output_ptr_t), allocatable :: output_list(:)
57 type(time_based_controller_t), allocatable :: controllers(:)
59 integer :: n
61 integer :: size
63 real(kind=rp) :: time_end
64 contains
66 procedure, pass(this) :: init => output_controller_init
68 procedure, pass(this) :: free => output_controller_free
70 procedure, pass(this) :: add => output_controller_add
72 procedure, pass(this) :: execute => output_controller_execute
74 procedure, pass(this) :: set_counter => output_controller_set_counter
75 end type output_controller_t
76
77contains
78
83 subroutine output_controller_init(this, time_end, size)
84 class(output_controller_t), intent(inout) :: this
85 integer, intent(in), optional :: size
86 real(kind=rp), intent(in) :: time_end
87 character(len=LOG_SIZE) :: log_buf
88 integer :: n, i
89
90 call this%free()
91
92 if (present(size)) then
93 n = size
94 else
95 n = 1
96 end if
97
98 allocate(this%output_list(n))
99 allocate(this%controllers(n))
100
101 do i = 1, n
102 this%output_list(i)%ptr => null()
103 end do
104
105 this%size = n
106 this%n = 0
107 this%time_end = time_end
108
109 end subroutine output_controller_init
110
112 subroutine output_controller_free(this)
113 class(output_controller_t), intent(inout) :: this
114
115 if (allocated(this%output_list)) then
116 deallocate(this%output_list)
117 end if
118 if (allocated(this%controllers)) then
119 deallocate(this%controllers)
120 end if
121
122 this%n = 0
123 this%size = 0
124
125 end subroutine output_controller_free
126
134 subroutine output_controller_add(this, out, write_par, write_control, &
135 start_time)
136 class(output_controller_t), intent(inout) :: this
137 class(output_t), intent(inout), target :: out
138 real(kind=rp), intent(in) :: write_par
139 character(len=*), intent(in) :: write_control
140 real(kind=rp), optional, intent(in) :: start_time
141 real(kind=rp) :: start_time_
142 type(output_ptr_t), allocatable :: tmp(:)
143 type(time_based_controller_t), allocatable :: tmp_ctrl(:)
144 character(len=LOG_SIZE) :: log_buf
145 integer :: n, nexecutions
146 class(*), pointer :: ft
147
148 if (present(start_time)) then
149 start_time_ = start_time
150 else
151 start_time_ = 0.0_rp
152 end if
153
154
155 if (this%n .ge. this%size) then
156 allocate(tmp(this%size * 2))
157 tmp(1:this%size) = this%output_list
158 call move_alloc(tmp, this%output_list)
159
160 allocate(tmp_ctrl(this%size * 2))
161 tmp_ctrl(1:this%size) = this%controllers
162 call move_alloc(tmp_ctrl, this%controllers)
163
164 this%size = this%size * 2
165 end if
166
167
168 this%n = this%n + 1
169 n = this%n
170 this%output_list(this%n)%ptr => out
171
172 if (trim(write_control) .eq. "org") then
173 this%controllers(n) = this%controllers(1)
174 else
175 call this%controllers(n)%init(start_time_, this%time_end, &
176 write_control, write_par)
177 end if
178
179 ! The code below only prints to console
180 call neko_log%section('Adding write output')
181 call neko_log%message('File name : '// &
182 trim(this%output_list(this%n)%ptr%file_%file_type%get_fname()))
183 call neko_log%message('Write control : '//trim(write_control))
184
185 ! Show the output precision if we are outputting an fld file
186 select type (ft => out%file_%file_type)
187 type is (fld_file_t)
188 if (ft%dp_precision) then
189 call neko_log%message('Output precision : double')
190 else
191 call neko_log%message('Output precision : single')
192 end if
193 end select
194
195 if (trim(write_control) .eq. 'simulationtime') then
196 write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
197 this%controllers(n)%frequency
198 call neko_log%message(log_buf)
199 write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
200 this%controllers(n)%time_interval
201 call neko_log%message(log_buf)
202 else if (trim(write_control) .eq. 'nsamples') then
203 write(log_buf, '(A,I13)') 'Total samples: ', int(write_par)
204 call neko_log%message(log_buf)
205 write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
206 this%controllers(n)%frequency
207 call neko_log%message(log_buf)
208 write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
209 this%controllers(n)%time_interval
210 call neko_log%message(log_buf)
211 else if (trim(write_control) .eq. 'tsteps') then
212 write(log_buf, '(A,I13)') 'Time step interval: ', int(write_par)
213 call neko_log%message(log_buf)
214 else if (trim(write_control) .eq. 'org') then
215 write(log_buf, '(A)') &
216 'Write control not set, defaulting to first output settings'
217 call neko_log%message(log_buf)
218 end if
219
220 call neko_log%end_section()
221 end subroutine output_controller_add
222
228 subroutine output_controller_execute(this, time, ifforce)
229 class(output_controller_t), intent(inout) :: this
230 type(time_state_t), intent(in) :: time
231 logical, intent(in), optional :: ifforce
232 real(kind=dp) :: sample_start_time, sample_end_time
233 real(kind=dp) :: sample_time
234 character(len=LOG_SIZE) :: log_buf
235 character(len=1024) :: output_fname
236 integer :: i, ierr
237 logical :: force, write_output, write_output_test
238
239 if (present(ifforce)) then
240 force = ifforce
241 else
242 force = .false.
243 end if
244
245 call profiler_start_region('Output controller', 22)
246 !Do we need this Barrier?
247 call mpi_barrier(neko_comm, ierr)
248 sample_start_time = mpi_wtime()
249
250 write_output = .false.
251 ! Determine if at least one output needs to be written
252 ! We should not need this extra select block, and it works great
253 ! without it for GNU, Intel and NEC, but breaks horribly on Cray
254 ! (>11.0.x) when using high opt. levels.
255 select type (samp => this)
256 type is (output_controller_t)
257 do i = 1, samp%n
258 if (this%controllers(i)%check(time, force)) then
259 write_output = .true.
260 exit
261 end if
262 end do
263 end select
264
265 if (write_output) then
266 call neko_log%section('Writer output ')
267 end if
268
269 ! Loop through the outputs and write if necessary.
270 ! We should not need this extra select block, and it works great
271 ! without it for GNU, Intel and NEC, but breaks horribly on Cray
272 ! (>11.0.x) when using high opt. levels.
273 select type (samp => this)
274 type is (output_controller_t)
275 do i = 1, this%n
276 if (this%controllers(i)%check(time, force)) then
277 output_fname = &
278 samp%output_list(i)%ptr%file_%file_type% &
279 get_next_output_fname()
280 call neko_log%message('File name : '//trim(output_fname))
281
282 write(log_buf, '(A,I6)') 'Output number :', &
283 int(this%controllers(i)%nexecutions)
284 call neko_log%message(log_buf)
285
286 call samp%output_list(i)%ptr%sample(time%t)
287
288 call this%controllers(i)%register_execution()
289 end if
290 end do
291 class default
292 call neko_error('Invalid output_controller output list')
293 end select
294
295 call mpi_barrier(neko_comm, ierr)
296 sample_end_time = mpi_wtime()
297
298 sample_time = sample_end_time - sample_start_time
299 if (write_output) then
300 write(log_buf, '(A16,1x,F12.6,A,F9.6)') 'Writing at time:', time%t, &
301 ' Output time (s): ', sample_time
302 call neko_log%message(log_buf)
303 call neko_log%end_section()
304 end if
305 call profiler_end_region('Output controller', 22)
306 end subroutine output_controller_execute
307
310 subroutine output_controller_set_counter(this, time)
311 class(output_controller_t), intent(inout) :: this
312 type(time_state_t), intent(in) :: time
313 integer :: i, nexecutions
314
315
316 do i = 1, this%n
317 if (this%controllers(i)%nsteps .eq. 0) then
318 call this%controllers(i)%set_counter(time)
319 nexecutions = this%controllers(i)%nexecutions
320 call this%output_list(i)%ptr%set_counter(-1)
321 call this%output_list(i)%ptr%set_start_counter(nexecutions)
322 end if
323 end do
324
325 end subroutine output_controller_set_counter
326
329 subroutine output_controller_set_write_count(this, counter)
330 class(output_controller_t), intent(inout) :: this
331 integer, intent(in) :: counter
332 integer :: i
333
334 do i = 1, this%n
335 this%controllers(i)%nexecutions = counter
336 call this%output_list(i)%ptr%set_counter(counter)
337 call this%output_list(i)%ptr%set_start_counter(counter)
338 end do
339
341
342
343end module output_controller
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
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:80
integer, parameter, public log_size
Definition log.f90:46
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:79
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition profiler.F90:116
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:66
Wrapper around an output_t pointer.
Definition output.f90:53
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.