88 real(kind=
dp) :: frequency = 0.0_dp
90 real(kind=
dp) :: time_interval = 0.0_dp
94 real(kind=
dp) :: start_time = 0.0_dp
96 real(kind=
dp) :: end_time = 0.0_dp
98 integer :: nexecutions = 0
100 logical :: never = .false.
103 character(len=:),
allocatable :: control_mode
105 real(kind=
dp) :: control_value = 0.0_dp
108 real(kind=
dp) :: anchor_time = 0.0_dp
113 logical :: write_at_start = .true.
115 integer(kind=i8) :: first_index = 0
117 logical :: start_is_scheduled = .false.
121 logical :: start_pending = .false.
124 integer :: next_index = 0
127 real(kind=
dp) :: direction = 1.0_dp
130 integer :: tstep_offset = 0
134 integer :: last_tstep = -1
144 procedure, pass(this) :: register_execution => &
147 procedure, pass(this) :: set_counter => &
173 control_mode, control_value, write_at_start, anchor_time, direction)
175 real(kind=
dp),
intent(in) :: start_time
176 real(kind=
dp),
intent(in) :: end_time
177 character(len=*),
intent(in) :: control_mode
178 real(kind=
dp),
intent(in) :: control_value
179 logical,
intent(in),
optional :: write_at_start
180 real(kind=
dp),
intent(in),
optional :: anchor_time
181 real(kind=
dp),
intent(in),
optional :: direction
182 real(kind=
dp) :: span, offset
186 this%start_time = start_time
187 this%end_time = end_time
188 this%control_mode = control_mode
189 this%control_value = control_value
191 if (
present(write_at_start))
then
192 this%write_at_start = write_at_start
194 this%write_at_start = .true.
197 if (
present(direction))
then
198 this%direction = sign(1.0_dp, direction)
200 this%direction = sign(1.0_dp, end_time - start_time)
203 span = this%direction * (end_time - start_time)
205 if (trim(control_mode) .eq.
'simulationtime')
then
206 if (control_value .le. 0.0_dp)
then
207 call neko_error(
"The output interval must be positive")
209 this%time_interval = control_value
210 this%frequency = 1.0_dp / this%time_interval
212 else if (trim(control_mode) .eq.
'nsamples')
then
213 if (control_value .le. 0.0_dp)
then
216 if (span .le. 0.0_dp)
then
217 call neko_error(
"nsamples requires the output to start before the &
218 &end of the simulation")
221 this%frequency = control_value / span
222 this%time_interval = 1.0_dp / this%frequency
226 this%anchor_time = start_time
227 else if (trim(control_mode) .eq.
'tsteps')
then
228 if (control_value .lt. 1.0_dp)
then
229 call neko_error(
"The output interval in time steps must be at &
232 this%nsteps = int(control_value)
234 this%frequency = 0.0_dp
235 this%time_interval = 0.0_dp
236 else if (trim(control_mode) .eq.
'never')
then
239 call neko_error(
"The control parameter must be simulationtime, nsamples&
240 & tsteps, or never, but received "//trim(control_mode))
243 if (
present(anchor_time)) this%anchor_time = anchor_time
248 this%start_is_scheduled = .true.
249 this%start_pending = .false.
251 if (this%time_interval .gt. 0.0_dp)
then
252 offset = this%direction * (start_time - this%anchor_time) / &
254 this%first_index = ceiling(offset -
span_tol *
max(1.0_dp, &
255 abs(offset)), kind =
i8)
256 this%start_is_scheduled = abs(
real(this%first_index,
dp) - offset) &
258 if (this%start_is_scheduled .and. .not. this%write_at_start)
then
259 this%first_index = this%first_index + 1_i8
261 this%start_pending = this%write_at_start .and. &
262 .not. this%start_is_scheduled
265 if (this%nsteps .gt. 0 .and. .not. this%write_at_start)
then
279 if (
allocated(this%control_mode))
then
280 deallocate(this%control_mode)
283 this%frequency = 0.0_dp
284 this%time_interval = 0.0_dp
286 this%start_time = 0.0_dp
287 this%end_time = 0.0_dp
290 this%control_value = 0.0_dp
291 this%write_at_start = .true.
292 this%anchor_time = 0.0_dp
294 this%start_is_scheduled = .false.
295 this%start_pending = .false.
297 this%direction = 1.0_dp
298 this%tstep_offset = 0
317 logical,
intent(in),
optional :: force
320 real(kind=
dp) :: progress, tol, t_next, t_start, t_end
323 if (
present(force))
then
332 if (this%last_tstep .eq. time%tstep)
return
335 if (this%never .and. .not. ifforce)
return
337 progress = this%direction * (time%t - this%anchor_time)
338 t_start = this%direction * (this%start_time - this%anchor_time)
339 tol = this%tolerance(time%dt)
342 if (progress .lt. t_start - tol)
return
346 else if (this%nsteps .gt. 0)
then
347 nstep = time%tstep - this%tstep_offset
348 check = nstep .ge. this%next_index * this%nsteps
349 else if (this%start_pending)
then
354 t_end = this%direction * (this%end_time - this%anchor_time)
355 t_next =
real(this%first_index + this%next_index,
dp) * &
360 if (t_next .gt. t_end +
span_tol *
max(abs(t_end), &
361 this%time_interval))
return
362 check = progress .ge. t_next - tol
377 real(kind=
dp) :: progress, tol
379 if (this%nsteps .gt. 0)
then
380 index = (time%tstep - this%tstep_offset) / this%nsteps + 1
381 else if (this%time_interval .gt. 0.0_dp)
then
382 progress = this%direction * (time%t - this%anchor_time)
383 tol = this%tolerance(time%dt)
384 index = int(floor((progress + tol) / this%time_interval, kind =
i8) &
385 - this%first_index) + 1
388 index = this%next_index
395 index =
max(index, 0)
422 real(kind=
dp) :: progress, tol, dt, t_start, t_first
425 if (this%never)
return
427 if (this%nsteps .gt. 0)
then
431 this%tstep_offset = time%tstep
433 this%start_pending = .false.
434 this%last_tstep = time%tstep
441 if (abs(time%dtlag(1)) .gt. 0.0_dp) dt = time%dtlag(1)
443 progress = this%direction * (time%t - this%anchor_time)
444 t_start = this%direction * (this%start_time - this%anchor_time)
445 tol = this%tolerance(dt)
447 if (progress .lt. t_start - tol)
then
452 n_passed = int(floor((progress + tol) / this%time_interval, &
453 kind =
i8) - this%first_index) + 1
454 this%next_index =
max(n_passed, 0)
455 this%nexecutions = this%next_index
456 if (this%start_pending)
then
461 t_first =
real(this%first_index,
dp) * this%time_interval
462 if (t_first .gt. t_start + tol)
then
463 this%nexecutions = this%nexecutions + 1
466 this%start_pending = .false.
471 this%last_tstep = time%tstep
subroutine time_based_controller_init(this, start_time, end_time, control_mode, control_value, write_at_start, anchor_time, direction)
Constructor.