| 19 XBound, |
20 XBound, |
| 20 ) |
21 ) |
| 21 from pointsource_pde.laser_sampling import LaserSampling |
22 from pointsource_pde.laser_sampling import LaserSampling |
| 22 from pointsource_pde.quadratic_dataterm import QuadraticDataTerm |
23 from pointsource_pde.quadratic_dataterm import QuadraticDataTerm |
| 23 |
24 |
| |
25 from dolfinx_access import eval_Function_f64 |
| |
26 |
| 24 # Give name to the problem |
27 # Give name to the problem |
| 25 name = "laser_and_mirrors_aux" |
28 name = "laser_and_mirrors_aux" |
| 26 |
29 |
| 27 # Fine-tune algorithms |
30 # Fine-tune algorithms |
| 28 alg_finetune = { |
31 alg_finetune = { |
| 29 "tau0": 0.99, |
32 "tau0": 0.02, |
| 30 "tautheta": 100, |
33 "sigmap0": 0.0001, |
| 31 "gradv_lipest_mult": 1.3, |
34 "tautheta": 0.07, |
| 32 "transport_tolerance": 10, |
35 "gradv_lipest_mult": 1, |
| 33 "inner_method": "PP", |
36 "transport_tolerance": 1e5, |
| 34 "inner_pdps_τσ0": (19.8, 0.05), |
37 "inner_method": "Exact", |
| 35 "inner_pp_τ": [1000.0, 1000.0], |
|
| 36 "merge": True, |
38 "merge": True, |
| 37 "fitness_merging": True, |
39 "fitness_merging": True, |
| 38 "merge_radius": 0.1, |
40 "merge_radius": 0.1, |
| 39 "merge_interp": False, |
41 "merge_interp": False, |
| |
42 "scaling_heuristic": None, |
| |
43 "extra_weight_optimisation_steps": None, |
| 40 } |
44 } |
| 41 |
45 |
| 42 algorithm_overrides = { |
46 algorithm_overrides = { |
| 43 "RadonFB": alg_finetune, |
47 "RadonFB": alg_finetune, |
| 44 "RadonSlidingFB": alg_finetune, |
48 "RadonSlidingFB": alg_finetune, |
| 45 "RadonPDPS": alg_finetune, |
49 "RadonPDPS": alg_finetune, |
| 46 "RadonSlidingPDPS": alg_finetune, |
50 "RadonSlidingPDPS": alg_finetune, |
| |
51 } |
| |
52 |
| |
53 reg_params = { |
| |
54 "alpha": 2e-3, |
| |
55 "alpha_k": 60, |
| |
56 "alpha_c": 0.06, |
| |
57 "c_noise": 0.02, |
| |
58 "k_noise": 0.02, |
| |
59 "seed": 2393, |
| |
60 "true_init": False, |
| |
61 "true_target": False, |
| |
62 "noise": 0.01, |
| |
63 "sim_oversample": 2, |
| |
64 "sim_oversample_time": 2, |
| |
65 "scale_cstep": 300, |
| |
66 "do_non_sliding": True, |
| 47 } |
67 } |
| 48 |
68 |
| 49 |
69 |
| 50 # Setup shared between experiment with known/unknown conductivity and diffusivity |
70 # Setup shared between experiment with known/unknown conductivity and diffusivity |
| 51 def generic_setup( |
71 def generic_setup( |
| 56 [([0.1, 0.3], 0.08), ([0.4, 0.25], 0.05), ([0.25, 0.13], 0.06)] |
76 [([0.1, 0.3], 0.08), ([0.4, 0.25], 0.05), ([0.25, 0.13], 0.06)] |
| 57 ), |
77 ), |
| 58 k=0.01, |
78 k=0.01, |
| 59 r=0.5, |
79 r=0.5, |
| 60 θ=30 * np.pi / 180, |
80 θ=30 * np.pi / 180, |
| |
81 c_noise=reg_params["c_noise"], |
| |
82 k_noise=reg_params["k_noise"], |
| |
83 noise=reg_params["noise"], |
| |
84 sim_oversample=reg_params["sim_oversample"], |
| |
85 sim_oversample_time=reg_params["sim_oversample_time"], |
| |
86 scale_cstep=reg_params["scale_cstep"], |
| 61 ): |
87 ): |
| |
88 |
| |
89 u0 = lambda x: 0.0 * x[1] |
| |
90 g = lambda x: 0.0 * x[1] |
| |
91 domain_dims = [[0, 0.5], [0, 0.5]] |
| |
92 num_steps = 50 |
| |
93 res = 32 |
| 62 |
94 |
| 63 # Create convection-diffusion PDE |
95 # Create convection-diffusion PDE |
| 64 pde = ConvectionDiffusion( |
96 pde = ConvectionDiffusion( |
| 65 u0=lambda x: 0.0 * x[1], |
97 u0=u0, |
| 66 g=lambda x: 0.0 * x[1], |
98 g=g, |
| 67 domain_size=[0, 0.5, 0, 0.5], |
99 domain_dims=domain_dims, |
| 68 num_steps=50, |
100 num_steps=num_steps, |
| 69 # override_lipschitz=4.0, |
101 nx=res, |
| 70 # override_lipschitz_pair=(4.0, 40.0), |
102 ny=res, |
| |
103 ) |
| |
104 |
| |
105 # Create convection-diffusion PDE for simulation, to avoid inverse crimes |
| |
106 pde_sim = ConvectionDiffusion( |
| |
107 u0=u0, |
| |
108 g=g, |
| |
109 domain_dims=domain_dims, |
| |
110 # num_steps=(sim_oversample-1) * (num_steps + 1) + num_steps, |
| |
111 num_steps=sim_oversample_time * (num_steps - 1) + 1, |
| |
112 nx=res * sim_oversample, |
| |
113 ny=res * sim_oversample, |
| 71 ) |
114 ) |
| 72 |
115 |
| 73 # Set up lasers and mirrors |
116 # Set up lasers and mirrors |
| 74 lasers = [ |
117 lasers = [ |
| 75 np.array([0.1, 0.1]), |
118 np.array([0.1, 0.1]), |
| 122 c2.interpolate(velocity_y) |
169 c2.interpolate(velocity_y) |
| 123 k = fem.Function(pde.V) |
170 k = fem.Function(pde.V) |
| 124 k0 = 1.0 |
171 k0 = 1.0 |
| 125 k.interpolate(lambda x: k0 + 0.2 * np.sin(5 * x[0]) * np.cos(5 * x[1])) # k is |
172 k.interpolate(lambda x: k0 + 0.2 * np.sin(5 * x[0]) * np.cos(5 * x[1])) # k is |
| 126 |
173 |
| |
174 c1_sim = fem.Function(pde_sim.V) |
| |
175 c1_sim.interpolate(velocity_x) |
| |
176 c2_sim = fem.Function(pde_sim.V) |
| |
177 c2_sim.interpolate(velocity_y) |
| |
178 k_sim = fem.Function(pde_sim.V) |
| |
179 k0 = 1.0 |
| |
180 k_sim.interpolate( |
| |
181 lambda x: k0 + 0.2 * np.sin(5 * x[0]) * np.cos(5 * x[1]) |
| |
182 ) # k is |
| |
183 |
| 127 auxtrue = (k, (c1, c2)) |
184 auxtrue = (k, (c1, c2)) |
| 128 |
185 |
| 129 # Simulate measurements |
186 # Simulate measurements |
| |
187 u_n_list_sim = pde_sim.apply((μ_true, (k_sim, (c1_sim, c2_sim)))) |
| 130 u_n_list = pde.apply((μ_true, (k, (c1, c2)))) |
188 u_n_list = pde.apply((μ_true, (k, (c1, c2)))) |
| 131 b_true = [L_i.apply(u) for u in u_n_list] |
189 |
| |
190 b_true = [L_i_sim.apply(u) for u in u_n_list_sim[0::sim_oversample_time]] |
| |
191 |
| |
192 # Add noise |
| |
193 level_k = abs(k) |
| |
194 level_c = r |
| |
195 k_noisy = max(0.001, relnoise(k, k_noise, rng, level=level_k)) |
| |
196 c1_noisy, c2_noisy = relnoise((c1, c2), c_noise, rng, level=level_c) |
| |
197 aux_noisy = (k_noisy, (c1_noisy, c2_noisy)) |
| 132 b = [ |
198 b = [ |
| 133 b_i + L_i.noise(0.01 * norm(b_i) / np.sqrt(np.size(b_i)), rng) for b_i in b_true |
199 b_i + L_i_sim.noise(noise * norm(b_i) / np.sqrt(np.size(b_i)), rng) |
| |
200 for b_i in b_true |
| 134 ] |
201 ] |
| 135 |
202 |
| 136 # Estimate bounds on domains and values |
203 # Estimate bounds on domains and values |
| 137 dat_bound = 2 * max([norm(b_i) for b_i in b]) |
204 dat_bound = 2 * max([norm(b_i) for b_i in b]) |
| 138 μ_bound = 1.3 * sum([alpha for _point, alpha in μ_true.iter_padded()]) |
205 μ_bound = 1.3 * sum([alpha for _point, alpha in μ_true.iter_padded()]) |
| 152 for data in b |
219 for data in b |
| 153 ], |
220 ], |
| 154 ), |
221 ), |
| 155 pde, |
222 pde, |
| 156 ) |
223 ) |
| |
224 if scale_cstep is not None: |
| |
225 dat = ComposeFnWithOperator(dat, ScaleAuxStepHack((1.0, scale_cstep))) |
| |
226 |
| 157 dat.curvature_bound_components = lambda: (None, None, None) |
227 dat.curvature_bound_components = lambda: (None, None, None) |
| 158 |
228 |
| 159 # Save true and initial data |
229 # Save true and initial data |
| 160 plot_factory = PlotFactory(pde) |
230 plot_factory = PlotFactory(pde) |
| 161 plotter = plot_factory.produce(prefix) |
231 plotter = plot_factory.produce(prefix) |
| 162 ω, _ = dat.diff((DiscreteMeasure_2_f64([]), auxtrue)) |
232 ω, _ = dat.diff((DiscreteMeasure_2_f64([]), auxtrue)) |
| 163 ω_true, _ = dat.diff((μ_true, auxtrue)) |
233 ω_true, (dk, (dc1, dc2)) = dat.diff((μ_true, auxtrue)) |
| 164 np.savez_compressed( |
234 np.savez_compressed( |
| 165 "%s/omega_0.npz" % prefix, |
235 "%s/omega_0.npz" % prefix, |
| 166 true_mu=[[point[0], point[1], alpha] for point, alpha in μ_true.iter_padded()], |
236 true_mu=[[point[0], point[1], alpha] for point, alpha in μ_true.iter_padded()], |
| 167 omega0=ω.x.array, |
237 omega0=ω.x.array, |
| 168 true_omega=ω_true.x.array, |
238 true_omega=ω_true.x.array, |
| 169 k=k, |
239 k_true=k, |
| 170 c1=c1, |
240 c1_true=c1, |
| 171 c2=c2, |
241 c2_true=c2, |
| |
242 k_noisy=k_noisy, |
| |
243 c1_noisy=c1_noisy, |
| |
244 c2_noisy=c2_noisy, |
| 172 true_u_n_list_array=[u_n_list[i].x.array for i in plotter.plot_frames], |
245 true_u_n_list_array=[u_n_list[i].x.array for i in plotter.plot_frames], |
| 173 ) |
246 ) |
| 174 |
247 |
| 175 return dat, auxtrue, μ_bound, μ_true, plot_factory, pde |
248 delta = 0.001 * k |
| |
249 dk_est = ( |
| |
250 dat.apply((μ_true, (k + delta, (c1, c2)))) - dat.apply((μ_true, auxtrue)) |
| |
251 ) / delta |
| |
252 print("k-diff-test:", dk, ", ", dk_est) |
| |
253 delta = 0.001 * c1 |
| |
254 dc1_est = ( |
| |
255 dat.apply((μ_true, (k, (c1 + delta, c2)))) - dat.apply((μ_true, auxtrue)) |
| |
256 ) / delta |
| |
257 print("c1-diff-test:", dc1, ", ", dc1_est) |
| |
258 delta = 0.001 |
| |
259 μ_perturb = DiscreteMeasure_2_f64( |
| |
260 [([0.1, 0.3], 0.08 + delta), ([0.4, 0.25], 0.05), ([0.25, 0.13], 0.06)] |
| |
261 ) |
| |
262 dcμ_est = (dat.apply((μ_perturb, auxtrue)) - dat.apply((μ_true, auxtrue))) / delta |
| |
263 print( |
| |
264 "μ-diff-test:", |
| |
265 eval_Function_f64(ω_true._cpp_object, [0.1, 0.3, 0.0]), |
| |
266 ", ", |
| |
267 dcμ_est, |
| |
268 ) |
| |
269 |
| |
270 return dat, auxtrue, aux_noisy, μ_bound, μ_true, plot_factory, pde |
| 176 |
271 |
| 177 |
272 |
| 178 def relnoise(v, σ, rng, level=None): |
273 def relnoise(v, σ, rng, level=None): |
| 179 if level is None: |
274 if isinstance(v, float): |
| 180 level = abs(v) |
275 return float(rng.normal(v, σ * (abs(v) if level is None else level))) |
| 181 return float(rng.normal(v, σ * level)) |
276 else: |
| |
277 return map( |
| |
278 float, rng.normal(v, σ * (np.linalg.norm(v) if level is None else level)) |
| |
279 ) |
| 182 |
280 |
| 183 |
281 |
| 184 # Setup the problem |
282 # Setup the problem |
| 185 def setup(prefix): |
283 def setup( |
| 186 rng = np.random.default_rng(seed=31337) |
284 prefix, |
| 187 |
285 alpha=reg_params["alpha"], |
| 188 dat, auxtrue, _μ_bound, μ_true, plot_factory, pde = generic_setup(prefix, rng=rng) |
286 alpha_k=reg_params["alpha_k"], |
| 189 |
287 alpha_c=reg_params["alpha_c"], |
| 190 # Override Lipschitz parameter |
288 c_noise=reg_params["c_noise"], |
| 191 pde.override_lipschitz = (4.0,) |
289 k_noise=reg_params["k_noise"], |
| 192 pde.override_lipschitz_pair = (4.0, 4.0) |
290 noise=reg_params["noise"], |
| 193 # print("diff_chain_lipschitz_factor (modified)", pde.diff_chain_lipschitz_factor()) |
291 seed=reg_params["seed"], |
| 194 # l1, l2 = pde.diff_chain_lipschitz_factor_pair() |
292 sim_oversample=reg_params["sim_oversample"], |
| 195 # print("diff_chain_lipschitz_factor_pair (modified) ", l1, ", ", l2) |
293 sim_oversample_time=reg_params["sim_oversample_time"], |
| 196 |
294 true_init=False, |
| 197 reg = RegTerm.NonnegRadon(1.5e-6) |
295 true_target=False, |
| |
296 scale_cstep=reg_params["scale_cstep"], |
| |
297 ): |
| |
298 rng = np.random.default_rng(seed=seed) |
| |
299 |
| |
300 dat, auxtrue, aux0, _μ_bound, μ_true, plot_factory, pde = generic_setup( |
| |
301 prefix, |
| |
302 rng=rng, |
| |
303 c_noise=c_noise, |
| |
304 k_noise=k_noise, |
| |
305 noise=noise, |
| |
306 sim_oversample=sim_oversample, |
| |
307 sim_oversample_time=sim_oversample_time, |
| |
308 scale_cstep=scale_cstep, |
| |
309 ) |
| |
310 |
| |
311 # Override Lipschitz parameter to use direct step length choice |
| |
312 dat.override_lipschitz = 1.0 |
| |
313 dat.override_lipschitz_pair = (0.0, 0.0) |
| |
314 |
| |
315 reg = RegTerm.NonnegRadon(alpha) |
| 198 |
316 |
| 199 μ0 = DiscreteMeasure_2_f64([]) |
317 μ0 = DiscreteMeasure_2_f64([]) |
| 200 (k, (c1, c2)) = auxtrue |
318 |
| 201 aux0 = ( |
|
| 202 max(0.001, relnoise(k, 0.02, rng)), |
|
| 203 ( |
|
| 204 relnoise(c1, 0.2, rng), |
|
| 205 relnoise(c2, 0.2, rng), |
|
| 206 ), |
|
| 207 ) |
|
| 208 print("aux init ", aux0) |
319 print("aux init ", aux0) |
| 209 aux = BoxedQuadraticRegularisation((0.001, -1.0), (1.0, 1.0), (3.0, 0.0005), aux0) |
320 aux = BoxedQuadraticRegularisation( |
| 210 ax = aux.apply(aux0) |
321 (0.005, -1.0), |
| 211 inival = dat.apply((μ0, aux0)) |
322 (1.0, 1.0), |
| 212 print("Initial data term value:", inival + ax) |
323 (alpha_k, alpha_c), |
| 213 print("Data term value at true μ:", dat.apply((μ_true, auxtrue)) + ax) |
324 auxtrue if true_target else aux0, |
| 214 |
325 (1, scale_cstep) if scale_cstep is not None else None, |
| 215 return Problem(dat, reg, aux, aux0, μ0, plot_factory=plot_factory) |
326 ) |
| |
327 print("Initial value:", dat.apply((μ0, aux0)) + aux.apply(aux0)) |
| |
328 print("Value at true μ:", dat.apply((μ_true, auxtrue)) + aux.apply(auxtrue)) |
| |
329 |
| |
330 return Problem( |
| |
331 dat, |
| |
332 reg, |
| |
333 aux, |
| |
334 auxtrue if true_init else aux0, |
| |
335 μ0, |
| |
336 plot_factory=plot_factory, |
| |
337 domain=pde.domain_dims, |
| |
338 ) |