Wed, 22 Apr 2026 22:32:00 -0500
Dolfin update, fixes, additional experiment, build instructions.
|
1
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
1 | import numpy as np |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
2 | from dolfinx import fem |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
3 | from petsc4py import PETSc |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
4 | from pointsource_pde.dolfinx_extras import get_mass_matrix |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
5 | from slepc4py import SLEPc |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
6 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
7 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
8 | class FullSampling: |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
9 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
10 | A linear operator class for full sampling of a concentration (fem.Function) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
11 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
12 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
13 | def __init__( |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
14 | self, |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
15 | V, |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
16 | ): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
17 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
18 | M: number of laser beams |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
19 | num_points: number of discrete points per beam |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
20 | domain_size: [xmin, xmax, ymin, ymax] |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
21 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
22 | self.V = V |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
23 | self.M = V.dofmap.index_map.size_global |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
24 | A = get_mass_matrix(V) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
25 | solver = PETSc.KSP().create(A.comm) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
26 | solver.setOperators(A) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
27 | solver.setType(PETSc.KSP.Type.PREONLY) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
28 | solver.getPC().setType(PETSc.PC.Type.LU) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
29 | self.solver = solver |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
30 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
31 | # ‖x‖^2 = ‖Ax.array‖^2 |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
32 | # ‖Rx‖^2 = ‖x.array‖^2 = ‖A^{-1}Ax.array‖^2 ≤ ‖A^{-1}‖‖x‖^2, |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
33 | # so we need the inverse of the minimal eigenvalue. |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
34 | E = SLEPc.EPS().create(A.comm) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
35 | E.setOperators(A) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
36 | E.setProblemType(SLEPc.EPS.ProblemType.NHEP) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
37 | E.setWhichEigenpairs(SLEPc.EPS.Which.SMALLEST_MAGNITUDE) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
38 | # E.setWhichEigenpairs(SLEPc.EPS.Which.LARGEST_MAGNITUDE) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
39 | E.setFromOptions() |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
40 | E.solve() |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
41 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
42 | sigma = abs(E.getEigenvalue(0)) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
43 | self._opnorm = 1.0 / sigma |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
44 | print("Full sampling opnorm = %f" % self._opnorm) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
45 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
46 | def apply(self, x): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
47 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
48 | This does not work with MPI |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
49 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
50 | return x.x.array |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
51 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
52 | def diff_adjdir(self, j, _x): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
53 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
54 | This does not work with MPI |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
55 | """ |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
56 | # We need ⟨Rx,v⟩_{ℝ^n} = ⟨x,R^*v⟩_V |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
57 | # We have ⟨x,R^*v⟩_V = ⟨Ax.array,[R^*v].array⟩_{ℝ^m} |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
58 | # But Rx = x.array, so we need |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
59 | # ⟨x.array,v⟩_{ℝ^n} = ⟨Ax.array,[R^*v].array⟩_{ℝ^m} |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
60 | # Taking [R^*v].array=A^{-1}v, the conjugate works correctly. |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
61 | tmp = fem.Function(self.V) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
62 | tmp.x.array[:] = j |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
63 | tmp.x.scatter_forward() |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
64 | return tmp |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
65 | # TODO: is convection_diffusion actualy based on norms in ℝ^n? |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
66 | # res = fem.Function(self.V) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
67 | # res.x.array[:] = 0.0 |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
68 | # self.solver.solve(tmp.x.petsc_vec, res.x.petsc_vec) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
69 | # res.x.scatter_forward() |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
70 | # return res |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
71 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
72 | def opnorm(self, *args): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
73 | # raise NotImplementedError("Need mesh weighting?") |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
74 | return self._opnorm |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
75 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
76 | def lipschitz_factor(self, *args): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
77 | return self.opnorm(*args) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
78 | |
|
3
c3a4f4bb87f7
Dolfin update, fixes, additional experiment, build instructions.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
79 | def diff_chain_lipschitz_factor(self, *args): |
|
1
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
80 | return self.opnorm(*args) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
81 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
82 | def diff_bound(self, *args): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
83 | return self.opnorm(*args) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
84 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
85 | def bound(self, *args): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
86 | return self.opnorm(*args) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
87 | |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
88 | # Construct observation noise |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
89 | def noise(self, noise_level): |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
90 | M = self.M |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
91 | # Create diagonal covariance matrix Gamma_v_t of shape (M, M) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
92 | Gamma_v_t = np.diag((noise_level * np.random.rand(M)) ** 2) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
93 | # Use average variance from diagonal as scalar variance |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
94 | std = np.sqrt(np.mean(np.diag(Gamma_v_t))) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
95 | # Generate noise with shape (M, 1) using scalar standard deviation |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
96 | noise = np.random.normal(0, std, size=(M,)) |
|
a4137aedcb3a
Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff
changeset
|
97 | return noise |