|
| 1 | +using SSP: init, solve!, adjoint_solve! |
| 2 | +using SSP: Kernel, Pad, Convolve, Project |
| 3 | +using .Kernel: conickernel |
| 4 | +using .Pad: FillPadding, BoundaryPadding, Inner, PaddingProblem, DefaultPaddingAlgorithm |
| 5 | +using .Convolve: DiscreteConvolutionProblem, FFTConvolution |
| 6 | +using .Project: ProjectionProblem, SSP1_linear, SSP1, SSP2 |
| 7 | + |
| 8 | +using Random |
| 9 | +using CairoMakie |
| 10 | +using CairoMakie: colormap |
| 11 | +using NLopt |
| 12 | + |
| 13 | + |
| 14 | +Nx = Ny = 100 |
| 15 | +grid = ( |
| 16 | + range(-1, 1, length=Nx), |
| 17 | + range(-1, 1, length=Ny), |
| 18 | +) |
| 19 | +# Random.seed!(42) |
| 20 | +# design_vars = rand(Nx, Ny) |
| 21 | +# design_vars = [sinpi(x) * sinpi(y) for (x, y) in Iterators.product(grid...)] |
| 22 | +design_vars = let a = 0.5, b = 0.499 |
| 23 | + # Cassini oval |
| 24 | + [((x^2 + y^2)^2 - 2a^2 * (x^2 - y^2) + a^4 - b^4) + 0.5 for (x, y) in Iterators.product(grid...)] |
| 25 | +end |
| 26 | +radius = 0.1 |
| 27 | + |
| 28 | +kernel = conickernel(grid, radius) |
| 29 | + |
| 30 | +padprob = PaddingProblem(; |
| 31 | + data = design_vars, |
| 32 | + boundary = BoundaryPadding(size(kernel) .- 1, size(kernel) .- 1), |
| 33 | + # boundary = FillPadding(1.0, size(kernel) .- 1, size(kernel) .- 1), |
| 34 | +) |
| 35 | +padalg = DefaultPaddingAlgorithm() |
| 36 | +padsolver = init(padprob, padalg) |
| 37 | +padsol = solve!(padsolver) |
| 38 | + |
| 39 | +convprob = DiscreteConvolutionProblem(; |
| 40 | + data = padsol.value, |
| 41 | + kernel, |
| 42 | +) |
| 43 | + |
| 44 | +convalg = FFTConvolution() |
| 45 | +convsolver = init(convprob, convalg) |
| 46 | +convsol = solve!(convsolver) |
| 47 | + |
| 48 | +depadprob = PaddingProblem(; |
| 49 | + data = convsol.value, |
| 50 | + boundary = Inner(size(kernel) .- 1, size(kernel) .- 1), |
| 51 | +) |
| 52 | +depadalg = DefaultPaddingAlgorithm() |
| 53 | +depadsolver = init(depadprob, depadalg) |
| 54 | +depadsol = solve!(depadsolver) |
| 55 | + |
| 56 | +filtered_design_vars = depadsol.value |
| 57 | + |
| 58 | +# projection points need not be the same as design variable grid |
| 59 | +target_grid = ( |
| 60 | + range(-1, 1, length=Nx * 1), |
| 61 | + range(-1, 1, length=Ny * 1), |
| 62 | +) |
| 63 | +target_points = vec(collect(Iterators.product(target_grid...))) |
| 64 | +projprob = ProjectionProblem(; |
| 65 | + rho_filtered=filtered_design_vars, |
| 66 | + grid, |
| 67 | + target_points, |
| 68 | + beta = Inf, |
| 69 | + eta = 0.5, |
| 70 | +) |
| 71 | +# projalg = SSP1_linear() |
| 72 | +# projalg = SSP1() |
| 73 | +projalg = SSP2() |
| 74 | +projsolver = init(projprob, projalg) |
| 75 | +projsol = solve!(projsolver) |
| 76 | + |
| 77 | +projected_design_vars = projsol.value |
| 78 | + |
| 79 | +let |
| 80 | + fig = Figure() |
| 81 | + ax1 = Axis(fig[1,1]; title = "design variables", aspect=DataAspect()) |
| 82 | + h1 = heatmap!(grid..., design_vars; colormap=colormap("grays")) |
| 83 | + Colorbar(fig[1,2], h1) |
| 84 | + |
| 85 | + ax2 = Axis(fig[1,3]; title = "SSP2 output", aspect=DataAspect()) |
| 86 | + h2 = heatmap!(target_grid..., reshape(projected_design_vars, length.(target_grid)); colormap=colormap("grays")) |
| 87 | + Colorbar(fig[1,4], h2) |
| 88 | + save("design.png", fig) |
| 89 | +end |
| 90 | + |
| 91 | +function fom(data, grid) |
| 92 | + return sum(abs2, data) / length(data) |
| 93 | +end |
| 94 | +obj = fom(projected_design_vars, grid) |
| 95 | + |
| 96 | +function adjoint_fom(adj_fom, data, grid) |
| 97 | + adjoint_fom!(similar(data), adj_fom, data, grid) |
| 98 | +end |
| 99 | +function adjoint_fom!(adj_data, adj_fom, data, grid) |
| 100 | + adj_data .= (adj_fom / length(data)) .* 2 .* data |
| 101 | + return adj_data |
| 102 | +end |
| 103 | + |
| 104 | +adj_rho_projected = adjoint_fom(1.0, projected_design_vars, grid) |
| 105 | + |
| 106 | +adj_projsol = (; value=adj_rho_projected) |
| 107 | +adj_projprob = adjoint_solve!(projsolver, adj_projsol, projsol.tape) |
| 108 | +adj_depadsol = (; value=adj_projprob.rho_filtered) |
| 109 | +adj_depadprob = adjoint_solve!(depadsolver, adj_depadsol, depadsol.tape) |
| 110 | +adj_convsol = (; value=adj_depadprob.data) |
| 111 | +adj_convprob = adjoint_solve!(convsolver, adj_convsol, convsol.tape) |
| 112 | +adj_padsol = (; value=adj_convprob.data) |
| 113 | +adj_padprob = adjoint_solve!(padsolver, adj_padsol, padsol.tape) |
| 114 | +adj_design_vars = adj_padprob.data |
| 115 | + |
| 116 | +let |
| 117 | + fig = Figure() |
| 118 | + ax1 = Axis(fig[1,1]; title = "SSP2 output", aspect=DataAspect()) |
| 119 | + h1 = heatmap!(ax1, target_grid..., reshape(projected_design_vars, length.(target_grid)); colormap=colormap("grays")) |
| 120 | + Colorbar(fig[1,2], h1) |
| 121 | + |
| 122 | + ax2 = Axis(fig[1,3]; title = "design variables gradient", aspect=DataAspect()) |
| 123 | + h2 = heatmap!(ax2, grid..., adj_design_vars; colormap=colormap("RdBu")) |
| 124 | + Colorbar(fig[1,4], h2) |
| 125 | + save("design_gradient.png", fig) |
| 126 | +end |
| 127 | + |
| 128 | +fom_withgradient = let grid=grid, padsolver=padsolver, convsolver=convsolver, depadsolver=depadsolver, projsolver=projsolver, adj_rho_projected=adj_rho_projected |
| 129 | + function (design_vars) |
| 130 | + |
| 131 | + padsolver.data = design_vars |
| 132 | + padsol = solve!(padsolver) |
| 133 | + convsolver.data = padsol.value |
| 134 | + convsol = solve!(convsolver) |
| 135 | + depadsolver.data = convsol.value |
| 136 | + depadsol = solve!(depadsolver) |
| 137 | + projsolver.rho_filtered = depadsol.value |
| 138 | + projsol = solve!(projsolver) |
| 139 | + |
| 140 | + _fom = fom(projsol.value, grid) |
| 141 | + adjoint_fom!(adj_rho_projected, 1.0, projsol.value, grid) |
| 142 | + |
| 143 | + adj_projsol = (; value=adj_rho_projected) |
| 144 | + adj_projprob = adjoint_solve!(projsolver, adj_projsol, projsol.tape) |
| 145 | + adj_depadsol = (; value=adj_projprob.rho_filtered) |
| 146 | + adj_depadprob = adjoint_solve!(depadsolver, adj_depadsol, depadsol.tape) |
| 147 | + adj_convsol = (; value=adj_depadprob.data) |
| 148 | + adj_convprob = adjoint_solve!(convsolver, adj_convsol, convsol.tape) |
| 149 | + adj_padsol = (; value=adj_convprob.data) |
| 150 | + adj_padprob = adjoint_solve!(padsolver, adj_padsol, padsol.tape) |
| 151 | + adj_design_vars = adj_padprob.data |
| 152 | + return _fom, adj_design_vars |
| 153 | + end |
| 154 | +end |
| 155 | + |
| 156 | +h = 1e-6 |
| 157 | +Random.seed!(0) |
| 158 | +perturb = h * randn(size(design_vars)) |
| 159 | +fom_ph, = fom_withgradient(design_vars + perturb) |
| 160 | +fom_mh, = fom_withgradient(design_vars - perturb) |
| 161 | +dfomdh_fd = (fom_ph - fom_mh) / 2h |
| 162 | + |
| 163 | +fom_val, adj_design_vars = fom_withgradient(design_vars) |
| 164 | +dfomdh = 2sum(adj_design_vars .* perturb) / 2h |
| 165 | +@show dfomdh_fd dfomdh |
| 166 | + |
| 167 | +opt = NLopt.Opt(:LD_CCSAQ, length(design_vars)) |
| 168 | +evaluation_history = Float64[] |
| 169 | +my_objective_fn = let fom_withgradient=fom_withgradient, evaluation_history=evaluation_history, design_vars=design_vars |
| 170 | + function (x, grad) |
| 171 | + val, adj_design = fom_withgradient(reshape(x, size(design_vars))) |
| 172 | + if !isempty(grad) |
| 173 | + copy!(grad, vec(adj_design)) |
| 174 | + end |
| 175 | + push!(evaluation_history, val) |
| 176 | + return val |
| 177 | + end |
| 178 | +end |
| 179 | +NLopt.min_objective!(opt, my_objective_fn) |
| 180 | +NLopt.maxeval!(opt, 50) |
| 181 | +fmax, xmax, ret = NLopt.optimize(opt, vec(design_vars)) |
| 182 | + |
| 183 | +let |
| 184 | + padsolver.data = reshape(xmax, size(design_vars)) |
| 185 | + padsol = solve!(padsolver) |
| 186 | + convsolver.data = padsol.value |
| 187 | + convsol = solve!(convsolver) |
| 188 | + depadsolver.data = convsol.value |
| 189 | + depadsol = solve!(depadsolver) |
| 190 | + projsolver.rho_filtered = depadsol.value |
| 191 | + projsol = solve!(projsolver) |
| 192 | + |
| 193 | + fig = Figure() |
| 194 | + ax1 = Axis(fig[1,1]; title = "Objective history", yscale=log10, limits = (nothing, (1e-16, 1e1))) |
| 195 | + h1 = scatterlines!(ax1, evaluation_history) |
| 196 | + |
| 197 | + ax2 = Axis(fig[1,2]; title = "Final SSP2 design", aspect=DataAspect()) |
| 198 | + h2 = heatmap!(target_grid..., reshape(projsol.value, length.(target_grid)); colormap=colormap("grays")) |
| 199 | + Colorbar(fig[1,3], h2) |
| 200 | + save("optimization.png", fig) |
| 201 | +end |
0 commit comments