Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
base_functional.f90
Go to the documentation of this file.
1
34
37 use design, only: design_t
38 use json_module, only: json_file
39 use json_utils, only: json_get
40 use num_types, only: rp, dp, xp
41 use point_zone, only: point_zone_t
42 use simulation_m, only: simulation_t
43 use time_state, only: time_state_t
44 use vector, only: vector_t
45 use utils, only: neko_error
46 use scratch_registry, only: neko_scratch_registry
47 use vector_math, only: vector_copy, vector_add3s2, vector_rzero
48 implicit none
49 private
50
61 type, abstract, public :: base_functional_t
62
65 character(len=:), allocatable :: name
66
68 real(kind=rp) :: value = 0.0_dp
70 type(vector_t) :: sensitivity
72 logical :: has_mask = .false.
74 class(point_zone_t), pointer :: mask => null()
75
76 ! ----------------------------------------------------------------------- !
77 ! Variables related to time averaging of the functional value and
78 ! sensitivity
79
81 real(kind=dp) :: start_time = 0.0_dp
83 real(kind=dp) :: end_time = huge(0.0_dp)
86 real(kind=xp) :: value_weight = 0.0_xp
89 real(kind=xp) :: sensitivity_weight = 0.0_xp
90
91 contains
92
93 ! ----------------------------------------------------------------------- !
94 ! Derived class interfaces
95
97 generic :: init => init_json, init_json_sim
98
100 procedure, pass(this) :: init_json => functional_init_json
102 procedure, pass(this) :: init_json_sim => functional_init_json_sim
104 procedure(functional_free), pass(this), deferred :: free
105
107 procedure(functional_update_value), pass(this), deferred :: update_value
109 procedure(functional_update_sensitivity), pass(this), deferred :: &
110 update_sensitivity
111
113 procedure, pass(this) :: get_name => functional_get_name
115 procedure, pass(this) :: get_value => functional_get_value
117 procedure, pass(this) :: get_sensitivity => functional_get_sensitivity
119 procedure, pass(this) :: get_log_size => functional_get_log_size
121 procedure, pass(this) :: get_log_headers => functional_get_log_headers
123 procedure, pass(this) :: get_log_values => functional_get_log_values
125 procedure, pass(this) :: reset_value => functional_reset_value
127 procedure, pass(this) :: reset_sensitivity => functional_reset_sensitivity
129 procedure, pass(this) :: accumulate_value => functional_accumulate_value
131 procedure, pass(this) :: accumulate_sensitivity => &
132 functional_accumulate_sensitivity
133
135 procedure, private, pass(this) :: in_window => functional_in_window
136 end type base_functional_t
137
138 ! -------------------------------------------------------------------------- !
139 ! Interface specifications for the derived types, these are the constructors
140 ! for the different types of objective functions.
141
142 abstract interface
143
145 subroutine functional_free(this)
146 import base_functional_t
147 class(base_functional_t), intent(inout) :: this
148 end subroutine functional_free
149
151 subroutine functional_update_value(this, design)
153 class(base_functional_t), intent(inout) :: this
154 class(design_t), intent(in) :: design
155 end subroutine functional_update_value
156
158 subroutine functional_update_sensitivity(this, design)
160 class(base_functional_t), intent(inout) :: this
161 class(design_t), intent(in) :: design
162 end subroutine functional_update_sensitivity
163
164 end interface
165
166contains
167
169 subroutine functional_init_json(this, json, design)
170 class(base_functional_t), intent(inout) :: this
171 type(json_file), intent(inout) :: json
172 class(design_t), intent(in) :: design
173 character(len=:), allocatable :: type
174
175 call json_get(json, 'type', type)
176 call neko_error("Functional type: '" // type // &
177 "' does not support initialization without simulation")
178 end subroutine functional_init_json
179
181 subroutine functional_init_json_sim(this, json, design, simulation)
182 class(base_functional_t), intent(inout) :: this
183 type(json_file), intent(inout) :: json
184 class(design_t), intent(in) :: design
185 type(simulation_t), target, intent(inout) :: simulation
186 character(len=:), allocatable :: type
187
188 call json_get(json, 'type', type)
189 call neko_error("Functional type: '" // type // &
190 "' does not support initialization with simulation")
191 end subroutine functional_init_json_sim
192
196 function functional_get_name(this) result(name)
197 class(base_functional_t), intent(in) :: this
198 character(len=:), allocatable :: name
199
200 if (allocated(this%name)) then
201 name = this%name
202 else
203 name = ""
204 end if
205 end function functional_get_name
206
208 function functional_get_value(this) result(v)
209 class(base_functional_t), intent(in) :: this
210 real(kind=rp) :: v
211
212 v = this%value
213 end function functional_get_value
214
216 subroutine functional_get_sensitivity(this, sensitivity)
217 class(base_functional_t), intent(in) :: this
218 type(vector_t), intent(inout) :: sensitivity
219
220 sensitivity = this%sensitivity
221 end subroutine functional_get_sensitivity
222
226 function functional_get_log_size(this) result(n)
227 class(base_functional_t), intent(in) :: this
228 integer :: n
229
230 n = 1
231 end function functional_get_log_size
232
236 subroutine functional_get_log_headers(this, headers)
237 class(base_functional_t), intent(in) :: this
238 character(len=*), intent(out) :: headers(:)
239
240 if (size(headers) .eq. 0) return
241 headers(1) = this%get_name()
242 end subroutine functional_get_log_headers
243
247 subroutine functional_get_log_values(this, values)
248 class(base_functional_t), intent(in) :: this
249 real(kind=rp), intent(out) :: values(:)
250
251 if (size(values) .eq. 0) return
252 values(1) = this%value
253 end subroutine functional_get_log_values
254
256 subroutine functional_reset_value(this)
257 class(base_functional_t), intent(inout) :: this
258
259 this%value = 0.0_dp
260 this%value_weight = 0.0_dp
261 end subroutine functional_reset_value
262
264 subroutine functional_reset_sensitivity(this)
265 class(base_functional_t), intent(inout) :: this
266
267 call vector_rzero(this%sensitivity)
268 this%sensitivity_weight = 0.0_dp
269 end subroutine functional_reset_sensitivity
270
284 subroutine functional_accumulate_value(this, design, time)
285 class(base_functional_t), intent(inout) :: this
286 class(design_t), intent(in) :: design
287 type(time_state_t), intent(in) :: time
288 real(kind=xp) :: value_new, value_old, weight_new, weight_old, dt
289
290 if (.not. this%in_window(time)) return
291
292 ! Store the old value and compute the new value.
293 value_old = real(this%value, kind=xp)
294 call this%update_value(design)
295 value_new = real(this%value, kind=xp)
296
297 ! Compute the weights for the old and new values.
298 dt = real(time%dt, kind=xp)
299 weight_new = dt / (this%value_weight + dt)
300 weight_old = this%value_weight / (this%value_weight + dt)
301
302 ! Rectangle rule; could potentially use higher order trapezoidal/Simpson
303 ! etc, but this should suffice.
304 this%value = real(value_old * weight_old + value_new * weight_new, kind=rp)
305 this%value_weight = this%value_weight + dt
306 end subroutine functional_accumulate_value
307
315 subroutine functional_accumulate_sensitivity(this, design, time)
316 class(base_functional_t), intent(inout) :: this
317 class(design_t), intent(in) :: design
318 type(time_state_t), intent(in) :: time
319 real(kind=xp) :: weight_new, weight_old, dt
320 type(vector_t), pointer :: sensitivity_new, sensitivity_old
321 integer :: n, idx(2)
322
323 if (.not. this%in_window(time)) return
324
325 n = this%sensitivity%size()
326 call neko_scratch_registry%request(sensitivity_new, idx(1), n, .false.)
327 call neko_scratch_registry%request(sensitivity_old, idx(2), n, .false.)
328
329 ! Store old sensitivity and compute new sensitivity.
330 call vector_copy(sensitivity_old, this%sensitivity)
331 call this%update_sensitivity(design)
332 call vector_copy(sensitivity_new, this%sensitivity)
333
334 ! Compute the weights for the old and new sensitivities.
335 dt = real(time%dt, kind=xp)
336 weight_new = dt / (this%sensitivity_weight + dt)
337 weight_old = this%sensitivity_weight / (this%sensitivity_weight + dt)
338
339 ! Rectangle rule; could potentially use higher order trapezoidal/Simpson
340 ! etc, but this should suffice.
341 call vector_add3s2(this%sensitivity, &
342 sensitivity_new, sensitivity_old, weight_new, weight_old)
343 this%sensitivity_weight = this%sensitivity_weight + dt
344
345 nullify(sensitivity_new)
346 nullify(sensitivity_old)
347 call neko_scratch_registry%relinquish(idx)
348 end subroutine functional_accumulate_sensitivity
349
350 ! -------------------------------------------------------------------------- !
351 ! Private helper methods
352
362 pure function functional_in_window(this, time) result(inside)
363 class(base_functional_t), intent(in) :: this
364 type(time_state_t), intent(in) :: time
365 logical :: inside
366 real(kind=rp) :: tol
367
368 tol = 1.0e-6_rp * time%dt
369 inside = time%t .ge. this%start_time - tol .and. &
370 time%t .le. this%end_time + tol
371 end function functional_in_window
372end module base_functional
Defines the abstract the base_functional_t type.
Implements the design_t.
Definition design.f90:36
Implements the steady_problem_t type.
An abstract design type.
Definition design.f90:53