src/full_sampling.py

Thu, 26 Feb 2026 09:32:12 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Thu, 26 Feb 2026 09:32:12 -0500
changeset 1
a4137aedcb3a
child 3
c3a4f4bb87f7
permissions
-rw-r--r--

Initial working version for known convectivity and diffusivity

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
a4137aedcb3a Initial working version for known convectivity and diffusivity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
79 def diff_adj_lipschitz_factor(self, *args):
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

mercurial