Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
steady_simcomp.f90
1! Copyright (c) 2024, 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 simulation_component, only: simulation_component_t
36 use num_types, only: rp, dp
37 use field, only: field_t
38 use json_module, only: json_file
39 use json_utils, only: json_get_or_default
40 use case, only: case_t
41 use field_math, only: field_sub2, field_copy
42 use math, only: glsc3
43 use device_math, only: device_glsc3
44 use coefs, only: coef_t
45 use neko_config, only : neko_bcknd_device
46 use csv_file, only : csv_file_t
47 use vector, only: vector_t
48 use time_state, only: time_state_t
49 use utils, only: neko_error
50 implicit none
51 private
52
57 type, public, extends(simulation_component_t) :: steady_simcomp_t
58 private
59
60 ! Old fields
61 type(field_t) :: u_old, v_old, w_old, p_old, s_old
62 real(kind=dp) :: tol
63
64 logical :: have_scalar = .false.
65
67 type(csv_file_t) :: logger
69 integer :: log_frequency
70 ! vector to store the data being logged
71 type(vector_t) :: log_data
72
73 contains
74 ! Constructor from json, wrapping the actual constructor.
75 procedure, public, pass(this) :: init => steady_simcomp_init_from_json
76 ! Actual constructor.
77 procedure, public, pass(this) :: init_from_attributes => &
78 steady_simcomp_init_from_attributes
79 ! Destructor.
80 procedure, public, pass(this) :: free => steady_simcomp_free
81 ! Compute the steady_simcomp field.
82 procedure, public, pass(this) :: compute_ => steady_simcomp_compute
83 end type steady_simcomp_t
84
85contains
86
87 ! Constructor from json.
88 subroutine steady_simcomp_init_from_json(this, json, case)
89 class(steady_simcomp_t), intent(inout), target :: this
90 type(json_file), intent(inout) :: json
91 class(case_t), intent(inout), target :: case
92 real(kind=dp) :: tol
93 integer :: log_frequency
94
95 call this%init_base(json, case)
96
97 ! Read the tolerance
98 call json_get_or_default(json, "tol", tol, 1.0e-6_dp)
99 ! Read the log frequency
100 call json_get_or_default(json, "log_frequency", log_frequency, 50)
101 call json_get_or_default(json, "scalar_coupled", this%have_scalar, .false.)
102
103 call this%init_from_attributes(tol, log_frequency)
104
105 end subroutine steady_simcomp_init_from_json
106
107 ! Actual constructor.
108 subroutine steady_simcomp_init_from_attributes(this, tol, log_frequency)
109 class(steady_simcomp_t), intent(inout) :: this
110 real(kind=dp), intent(in) :: tol
111 integer, intent(in) :: log_frequency
112
113 this%tol = tol
114 this%log_frequency = log_frequency
115
116 ! initialize the logger
117 call this%logger%init('steady_state_data.csv')
118 call this%logger%set_header('iter,time,u,v,w,p,t')
119 call this%log_data%init(7)
120
121 ! Point local fields to the scratch fields
122 call this%u_old%init(this%case%fluid%u%dof)
123 call this%v_old%init(this%case%fluid%v%dof)
124 call this%w_old%init(this%case%fluid%w%dof)
125 call this%p_old%init(this%case%fluid%p%dof)
126
127 ! Check if the scalar field is allocated
128 if (this%have_scalar) then
129 call this%s_old%init(this%case%scalars%scalar_fields(1)%s%dof)
130 end if
131
132 end subroutine steady_simcomp_init_from_attributes
133
134 ! Destructor.
135 subroutine steady_simcomp_free(this)
136 class(steady_simcomp_t), intent(inout) :: this
137
138 call this%u_old%free()
139 call this%v_old%free()
140 call this%w_old%free()
141 call this%p_old%free()
142 call this%s_old%free()
143 call this%log_data%free()
144
145 call this%free_base()
146
147 end subroutine steady_simcomp_free
148
149 ! Compute the steady_simcomp field.
150 subroutine steady_simcomp_compute(this, time)
151 class(steady_simcomp_t), intent(inout) :: this
152 type(time_state_t), intent(in) :: time
153 integer :: tstep
154 real(kind=rp) :: t
155 real(kind=rp) :: dt
156
157 real(kind=rp), dimension(5) :: normed_diff
158 type(field_t), pointer :: u, v, w, p, s
159
160 ! A frozen field is not interesting to compute differences for.
161 if (this%case%fluid%freeze) return
162
163 ! Get the current time and time step
164 t = time%t
165 tstep = time%tstep
166 dt = this%case%time%dt
167
168 ! ------------------------------------------------------------------------ !
169 ! Computation of the maximal normed difference.
170 !
171 ! Our goal is to freeze the simulation when the normed difference between
172 ! the old and new fields is below a certain tolerance.
173
174 u => this%case%fluid%u
175 v => this%case%fluid%v
176 w => this%case%fluid%w
177 p => this%case%fluid%p
178
179 if (this%have_scalar) then
180 if (size(this%case%scalars%scalar_fields) .gt. 1) then
181 call neko_error('steady simcomp only works for a single scalar')
182 end if
183 s => this%case%scalars%scalar_fields(1)%s
184 else
185 s => null()
186 end if
187
188 ! Compute the difference between the old and new fields
189 call field_sub2(this%u_old, u)
190 call field_sub2(this%v_old, v)
191 call field_sub2(this%w_old, w)
192 call field_sub2(this%p_old, p)
193 if (this%have_scalar) then
194 call field_sub2(this%s_old, s)
195 end if
196
197 ! Here we compute the squared difference between the old and new fields
198 ! and store the result in the `normed_diff` array.
199 normed_diff(1) = energy_norm(this%u_old, this%case%fluid%C_Xh, dt)
200 normed_diff(2) = energy_norm(this%v_old, this%case%fluid%C_Xh, dt)
201 normed_diff(3) = energy_norm(this%w_old, this%case%fluid%C_Xh, dt)
202 normed_diff(4) = energy_norm(this%p_old, this%case%fluid%C_Xh, dt)
203 if (this%have_scalar) then
204 normed_diff(5) = energy_norm(this%s_old, this%case%fluid%C_Xh, dt)
205 else
206 normed_diff(5) = 0.0_rp
207 end if
208
209 ! If the normed difference is below the tolerance, we consider the
210 ! simulation to have converged. Otherwise, we copy the new fields to the
211 ! old fields and continue the simulation.
212 if (maxval(normed_diff) .gt. this%tol) then
213 call field_copy(this%u_old, u)
214 call field_copy(this%v_old, v)
215 call field_copy(this%w_old, w)
216 call field_copy(this%p_old, p)
217 if (this%have_scalar) then
218 call field_copy(this%s_old, s)
219 end if
220
221 ! this could be a csv, but I think it's nicer in the logfile, it can
222 ! always be greped out later if you want to plot.
223 if (mod(tstep, this%log_frequency) .eq. 0) then
224 this%log_data%x(1) = real(tstep, kind=rp)
225 this%log_data%x(2) = t
226 this%log_data%x(3) = normed_diff(1)
227 this%log_data%x(4) = normed_diff(2)
228 this%log_data%x(5) = normed_diff(3)
229 this%log_data%x(6) = normed_diff(4)
230 this%log_data%x(7) = normed_diff(5)
231 call this%logger%write(this%log_data)
232 end if
233
234 else
235 this%case%fluid%freeze = .true.
236 if (this%have_scalar) then
237 ! @todo
238 ! we should implement a freeze for the scalar too
239 !this%case%scalar%freeze = .true.
240 end if
241 end if
242
243
244 end subroutine steady_simcomp_compute
245
250 function energy_norm(delta_fld, coef, dt)
251 type(field_t), intent(in) :: delta_fld
252 type(coef_t), intent(in) :: coef
253 real(kind=rp), intent(in) :: dt
254 real(kind=rp) :: energy_norm, tmp
255 integer :: n
256
257 n = delta_fld%size()
258 if (neko_bcknd_device .eq. 1) then
259 tmp = device_glsc3(delta_fld%x_d, delta_fld%x_d, coef%B_d, n)
260 else
261 tmp = glsc3(delta_fld%x, delta_fld%x, coef%B, n)
262 end if
263 energy_norm = sqrt(tmp) / dt / coef%volume
264
265 end function energy_norm
266
267
268end module steady_simcomp
Implements the steady_simcomp_t type.
The steady_simcomp_t type is a simulation component that terminates a simulation when the normed diff...