Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
mma_simcomp.f90
Go to the documentation of this file.
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
33 ! Implements the `mma_comp_t` type.
35 use num_types, only: rp
36 use case, only: case_t
37 use json_module, only: json_file
38 use json_utils, only: json_get_or_default
39 use simulation_component, only: simulation_component_t
40 use field, only: field_t
41 use logger, only: neko_log
42 use vector, only: vector_t
43 use matrix, only: matrix_t
44 use mma, only: mma_t
45
46 use device, only: device_memcpy, host_to_device, device_to_host
47 use mpi_f08, only: mpi_allreduce, mpi_integer, mpi_sum, mpi_comm_world, &
48 mpi_min, mpi_max, mpi_in_place
49 use comm, only: pe_rank, neko_comm, mpi_real_precision
50 implicit none
51 private
52
53 ! An empty user defined simulation component.
54 ! This is a simple example of a user-defined simulation component.
55 type, public, extends(simulation_component_t) :: mma_comp_t
56
58 type(field_t) :: designx
59
61 integer :: m
62
63 real(kind=rp) :: scale
64 logical :: auto_scale
65
67 type(mma_t) :: mma
68
69 contains
70 ! Constructor from json, wrapping the actual constructor.
71 procedure, pass(this) :: init => simcomp_test_init_from_json
72 ! Destructor.
73 procedure, pass(this) :: free => simcomp_test_free
74 ! Compute the simcomp_test field.
75 procedure, pass(this) :: compute_ => simcomp_test_compute
76 end type mma_comp_t
77
78contains
79 ! Constructor from json.
80 subroutine simcomp_test_init_from_json(this, json, case)
81 class(mma_comp_t), intent(inout) :: this
82 type(json_file), intent(inout) :: json
83 class(case_t), intent(inout), target :: case
84 integer :: nloc
85
86 call this%init_base(json, case)
87 call this%designx%init(case%msh, case%fluid%Xh, "designx")
88
89 call json_get_or_default(json, "m", this%m, 2)
90 nloc = this%designx%dof%size()
91
92 ! initial design
93 this%designx%x = 1.0
94
95 call this%mma%init( reshape(this%designx%x, [nloc]), &
96 nloc, this%m, case%params, this%scale, this%auto_scale)
97 end subroutine simcomp_test_init_from_json
98
99
100 ! Destructor.
101 subroutine simcomp_test_free(this)
102 class(mma_comp_t), intent(inout) :: this
103 call this%mma%free()
104 call this%free_base()
105 end subroutine simcomp_test_free
106
107 ! Computations.
108 subroutine simcomp_test_compute(this, t, tstep)
109 implicit none
110 class(mma_comp_t), intent(inout) :: this
111 real(kind=rp), intent(in) :: t
112 integer, intent(in) :: tstep
113
114 integer :: iter, i, ierr, rank, size, nglobal
115 integer, allocatable :: recv_counts(:), displs(:)
116
117 real(kind=rp) :: start_time, end_time
118 real(kind=rp), dimension(this%mma%get_n()) :: x
119 real(kind=rp) :: f0val
120 type(vector_t) :: df0dx, fval
121 type(matrix_t) :: dfdx
122
123 real(kind=rp), dimension(this%mma%get_n(), 4) :: stuff
124
125
126 real(kind=rp), allocatable :: all_stuff(:, :)
127 integer, allocatable :: nloc_all(:)
128
129 call df0dx%init(this%mma%get_n())
130 call fval%init(this%mma%get_m())
131 call dfdx%init(this%mma%get_m(), this%mma%get_n())
132
133
134 call cpu_time(start_time)
135 x = reshape(this%designx%x, [this%mma%get_n()])
136 call func1(this, this%mma%get_n(), this%mma%get_m(), &
137 f0val, df0dx%x, fval%x, dfdx%x)
138 ! update the device pointer
139 call device_memcpy(df0dx%x, df0dx%x_d, this%mma%get_n(), &
140 host_to_device, sync = .false.)
141 call device_memcpy(fval%x, fval%x_d, this%mma%get_m(), &
142 host_to_device, sync = .false.)
143 call device_memcpy(dfdx%x, dfdx%x_d, this%mma%get_n()*this%mma%get_m(), &
144 host_to_device, sync = .false.)
145
146 if (pe_rank .eq. 0) then
147 print *, 'iter = ', 0, &
148 '-------, f0val = ', f0val, ', fval = ', fval%x
149 end if
150
151 stuff(:, 1) = reshape(this%designx%dof%x, [this%mma%get_n()])
152 stuff(:, 2) = reshape(this%designx%dof%y, [this%mma%get_n()])
153 stuff(:, 3) = reshape(this%designx%dof%z, [this%mma%get_n()])
154 stuff(:, 4) = reshape(this%designx%x, [this%mma%get_n()])
155
156 call mpi_comm_size(neko_comm, size, ierr)
157 call mpi_comm_rank(neko_comm, rank, ierr)
158 allocate(recv_counts(size))
159 allocate(displs(size))
160 call mpi_allreduce(this%mma%get_n(), nglobal, 1, &
161 mpi_integer, mpi_sum, neko_comm, ierr)
162
163 allocate(nloc_all(size))
164 !!!!Use MPI_Allgather to gather the `nloc` from each process into `nloc_all`
165 call mpi_allgather(this%mma%get_n(), 1, mpi_integer, nloc_all, &
166 1, mpi_integer, mpi_comm_world, ierr)
167 recv_counts = this%mma%get_n()
168 displs(1) = 0
169 do i = 2, size
170 displs(i) = displs(i-1) + nloc_all(i-1)
171 end do
172 allocate(all_stuff(nglobal, 4))
173 ! Gather data from all processes to the root process
174 call mpi_gatherv(stuff(:, 1), this%mma%get_n(), mpi_real_precision, &
175 all_stuff(:, 1), recv_counts, displs, mpi_real_precision, &
176 0, neko_comm, ierr)
177 call mpi_gatherv(stuff(:, 2), this%mma%get_n(), mpi_real_precision, &
178 all_stuff(:, 2), recv_counts, displs, mpi_real_precision, &
179 0, neko_comm, ierr)
180 call mpi_gatherv(stuff(:, 3), this%mma%get_n(), mpi_real_precision, &
181 all_stuff(:, 3), recv_counts, displs, mpi_real_precision, &
182 0, neko_comm, ierr)
183 call mpi_gatherv(stuff(:, 4), this%mma%get_n(), mpi_real_precision, &
184 all_stuff(:, 4), recv_counts, displs, mpi_real_precision, &
185 0, neko_comm, ierr)
186 ! Only root process writes the file
187 if (pe_rank .eq. 0) then
188 call write_stuff_vtk(all_stuff, nglobal, "stuff_init.vtk")
189 end if
190 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
191 ! The optimization loop
192 do iter = 1, 100 !10
193 call this%mma%update(iter, x, df0dx, fval, dfdx)
194 this%designx%x = reshape(x, shape(this%designx%x))
195
196 call func1(this, this%mma%get_n(), this%mma%get_m(), &
197 f0val, df0dx%x, fval%x, dfdx%x)
198 ! update the device pointer
199 call device_memcpy(df0dx%x, df0dx%x_d, this%mma%get_n(), &
200 host_to_device, sync = .false.)
201 call device_memcpy(fval%x, fval%x_d, this%mma%get_m(), &
202 host_to_device, sync = .false.)
203 call device_memcpy(dfdx%x, dfdx%x_d, &
204 this%mma%get_n()*this%mma%get_m(), host_to_device, sync = .false.)
205
206 call this%mma%KKT(this%designx%x, df0dx, fval, dfdx)
207
208 if (pe_rank .eq. 0) then
209 print *, 'iter = ', iter, &
210 '-------, f0val = ', f0val, ', fval = ', fval%x(1), &
211 ', KKTmax = ', this%mma%get_residumax(), &
212 ', KKTnorm2 = ', this%mma%get_residunorm()
213 end if
214
215 if (this%mma%get_residumax() .lt. 1.0e-3_rp) exit
216 end do
217
218 call cpu_time(end_time)
219
220 print *, 'Elapsed Time: ', end_time - start_time, ' seconds'
221 print *, "this%designx%x is updated"
222
223
224 stuff(:, 1) = reshape(this%designx%dof%x, [this%mma%get_n()])
225 stuff(:, 2) = reshape(this%designx%dof%y, [this%mma%get_n()])
226 stuff(:, 3) = reshape(this%designx%dof%z, [this%mma%get_n()])
227 stuff(:, 4) = reshape(this%designx%x, [this%mma%get_n()])
228
229 call mpi_gatherv(stuff(:, 1), this%mma%get_n(), mpi_real_precision, &
230 all_stuff(:, 1), recv_counts, displs, mpi_real_precision, &
231 0, neko_comm, ierr)
232 call mpi_gatherv(stuff(:, 2), this%mma%get_n(), mpi_real_precision, &
233 all_stuff(:, 2), recv_counts, displs, mpi_real_precision, &
234 0, neko_comm, ierr)
235 call mpi_gatherv(stuff(:, 3), this%mma%get_n(), mpi_real_precision, &
236 all_stuff(:, 3), recv_counts, displs, mpi_real_precision, &
237 0, neko_comm, ierr)
238 call mpi_gatherv(stuff(:, 4), this%mma%get_n(), mpi_real_precision, &
239 all_stuff(:, 4), recv_counts, displs, mpi_real_precision, &
240 0, neko_comm, ierr)
241 ! Only root process writes the file
242 if (pe_rank .eq. 0) then
243 call write_stuff_vtk(all_stuff, nglobal, "stuff_final.vtk")
244 end if
245
246 end subroutine simcomp_test_compute
247
248 subroutine write_stuff_vtk(stuff, n, filename)
249 ! ----------------------------------------------------------- !
250 ! This subroutine writes a nx4 array into a vtk file. !
251 ! The array is called stuff(n, 4) holding the coordinates of !
252 ! all points and thier corresponding scalar value !
253 ! For a given point n, the array is defined as follows: !
254 ! x = stuff(n, 1), y = stuff(n, 2), z = stuff(n, 3) !
255 ! scalar field value = stuff(n, 4) !
256 ! ----------------------------------------------------------- !
257 integer, intent(in) :: n ! Number of design variables
259 real(kind=rp), dimension(n, 4), intent(in) :: stuff
260 character(len=*), intent(in) :: filename ! Filename to save the VTK data
261
262 integer :: i ! Loop variable
263 integer :: unit ! File unit number
264
265 ! Open the VTK file for writing
266 open(newunit = unit, file = filename, status = "replace", action = "write")
267
268 ! Write VTK header
269 write(unit, '(A)') '# vtk DataFile Version 3.0'
270 write(unit, '(A)') 'Stuff data'
271 write(unit, '(A)') 'ASCII'
272 write(unit, '(A)') 'DATASET POLYDATA'
273
274 ! Write the points (x, y, z coordinates)
275 write(unit, '(A, I8)') 'POINTS ', n, ' double'
276 do i = 1, n
277 write(unit, '(3(ES15.8, 1X))') stuff(i, 1), stuff(i, 2), stuff(i, 3)
278 end do
279
280 ! Write the temperature data associated with the points
281 write(unit, '(A, I8)') 'POINT_DATA ', n
282 write(unit, '(A)') 'SCALARS Temperature double 1'
283 write(unit, '(A)') 'LOOKUP_TABLE default'
284 do i = 1, n
285 write(unit, '(ES15.8)') stuff(i, 4)
286 end do
287
288 ! Close the file
289 close(unit)
290
291 end subroutine write_stuff_vtk
292
293 subroutine func1(this, n, m, f0val, df0dx, fval, dfdx)
294 ! ----------------------------------------------------------- !
295 ! This subroutine calculates function values and gradients !
296 ! for "toy problem 3": !
297 ! !
298 ! minimize sum_(j = 1, .., n) xj/n !
299 ! subject to sum_(j = 1, .., n) {(xj - Xj_GLL)^2} = 0 !
300 ! ----------------------------------------------------------- !
301 implicit none
302 class(mma_comp_t), intent(inout) :: this
303
304 integer, intent(in) :: n, m
305 real(kind=rp), intent(inout) :: f0val
306 real(kind=rp), dimension(n), intent(inout) :: df0dx
307 real(kind=rp), dimension(m), intent(inout) :: fval
308 real(kind=rp), dimension(m, n), intent(inout) :: dfdx
309
310 real(kind=rp), dimension(n) :: x, coordx
311 integer :: ierr, nglobal
312 real(kind=rp) :: globalf0val
313
314 call mpi_allreduce(n, nglobal, 1, &
315 mpi_integer, mpi_sum, neko_comm, ierr)
316
317 x = reshape(this%designx%x, [n])
318 coordx = reshape(this%designx%dof%x, [n])
319
320 f0val = sum(x) / nglobal
321 df0dx = 1.0_rp / nglobal
322 globalf0val = 0.0_rp
323 call mpi_allreduce(f0val, globalf0val, 1, &
324 mpi_real_precision, mpi_sum, neko_comm, ierr)
325 f0val = globalf0val
326 ! f0val = 0
327 ! df0dx = 0
328 fval(1) = sum((x-coordx)**2)
329 globalf0val = 0.0_rp
330 call mpi_allreduce(fval(1), globalf0val, 1, &
331 mpi_real_precision, mpi_sum, neko_comm, ierr)
332 fval(1) = globalf0val
333
334 dfdx(1, :) = 2.0_rp * (x - coordx)
335 fval(2) = - fval(1)
336 dfdx(2, :) = - dfdx(1, :)
337 end subroutine func1
338
339end module mma_simcomp
340
subroutine simcomp_test_init_from_json(this, json, case)
subroutine write_stuff_vtk(stuff, n, filename)
subroutine simcomp_test_free(this)
subroutine simcomp_test_compute(this, t, tstep)
subroutine func1(this, n, m, f0val, df0dx, fval, dfdx)
Definition mma.f90:34