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