experiments/laser_and_mirrors_aux.py

changeset 12
a0d61ac3719e
parent 11
c4f923017349
child 18
ddd24b5c2715
equal deleted inserted replaced
11:c4f923017349 12:a0d61ac3719e
8 from measures import DiscreteMeasure_2_f64 8 from measures import DiscreteMeasure_2_f64
9 from numpy.linalg import norm 9 from numpy.linalg import norm
10 from pointsource_pde import Problem, RegTerm 10 from pointsource_pde import Problem, RegTerm
11 from pointsource_pde.compose import ( 11 from pointsource_pde.compose import (
12 ComposeFnWithOperator, 12 ComposeFnWithOperator,
13 ScaleAuxStepHack,
13 SumOfSeparableFunctions, 14 SumOfSeparableFunctions,
14 ) 15 )
15 from pointsource_pde.convection_diffusion import ( 16 from pointsource_pde.convection_diffusion import (
16 BoxedQuadraticRegularisation, 17 BoxedQuadraticRegularisation,
17 ConvectionDiffusion, 18 ConvectionDiffusion,
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]),
77 np.array([0.4, 0.1]), 120 np.array([0.4, 0.1]),
78 np.array([0.4, 0.1]), 121 np.array([0.4, 0.1]),
79 ] 122 ]
80 mirrors_per_side = 10 123 mirrors_per_side = 10
81 x0, x1, y0, y1 = ( 124 x0, x1, y0, y1 = (
82 pde.domain_size[0], 125 pde.domain_dims[0][0],
83 pde.domain_size[1], 126 pde.domain_dims[0][1],
84 pde.domain_size[2], 127 pde.domain_dims[1][0],
85 pde.domain_size[3], 128 pde.domain_dims[1][1],
86 ) 129 )
87 beams = [ 130 beams = [
88 (src, np.array(dst)) 131 (src, np.array(dst))
89 for src in lasers 132 for src in lasers
90 for i in range(0, mirrors_per_side) 133 for i in range(0, mirrors_per_side)
95 [x0, z * (y1 - y0) + y0], 138 [x0, z * (y1 - y0) + y0],
96 [x1, z * (y1 - y0) + y0], 139 [x1, z * (y1 - y0) + y0],
97 ] 140 ]
98 ] 141 ]
99 L_i = LaserSampling(pde.V, pde.domain, pde.nx, pde.ny, beams) 142 L_i = LaserSampling(pde.V, pde.domain, pde.nx, pde.ny, beams)
143 L_i_sim = LaserSampling(pde_sim.V, pde_sim.domain, pde_sim.nx, pde_sim.ny, beams)
100 144
101 v0 = 1.0 145 v0 = 1.0
102 146
103 if simple: 147 if simple:
104 # Scalar convectivity and diffusivity 148 # Scalar convectivity and diffusivity
105 c1 = r * np.cos(θ) 149 c1 = r * np.cos(θ)
106 c2 = r * np.sin(θ) 150 c2 = r * np.sin(θ)
107 # k = 0.001 # high wind 151 # k = 0.001 # high wind
108 print("True aux variables: k = %f, c1 = %f, c2 = %f" % (k, c1, c2)) 152 print("True aux variables: k = %f, c1 = %f, c2 = %f" % (k, c1, c2))
153 k_sim = k
154 c1_sim = c1
155 c2_sim = c2
109 else: 156 else:
110 # Convectivity and diffusivity fields 157 # Convectivity and diffusivity fields
111 def velocity_x(x): 158 def velocity_x(x):
112 r = np.sqrt(x[0] ** 2 + x[1] ** 2 + 1e-10) 159 r = np.sqrt(x[0] ** 2 + x[1] ** 2 + 1e-10)
113 return v0 * x[0] / r 160 return v0 * x[0] / r
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 )

mercurial