CUQIpy 0.4.0__tar.gz → 0.4.0.post0.dev19__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of CUQIpy might be problematic. Click here for more details.
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/CUQIpy.egg-info/PKG-INFO +1 -1
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/PKG-INFO +1 -1
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/_version.py +3 -3
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/pde/_pde.py +59 -16
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_pde.py +87 -14
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/CUQIpy.egg-info/SOURCES.txt +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/CUQIpy.egg-info/dependency_links.txt +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/CUQIpy.egg-info/requires.txt +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/CUQIpy.egg-info/top_level.txt +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/LICENSE +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/README.md +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/_messages.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/array/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/array/_array.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/config.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/data/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/data/_data.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/data/astronaut.npz +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/data/camera.npz +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/data/cat.npz +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/data/satellite.mat +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/density/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/density/_density.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/diagnostics.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_beta.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_cauchy.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_cmrf.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_custom.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_distribution.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_gamma.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_gaussian.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_gmrf.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_inverse_gamma.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_joint_distribution.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_laplace.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_lmrf.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_lognormal.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_normal.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_posterior.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/distribution/_uniform.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/geometry/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/geometry/_geometry.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/likelihood/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/likelihood/_likelihood.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/model/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/model/_model.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/operator/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/operator/_operator.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/pde/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/problem/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/problem/_problem.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_conjugate.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_conjugate_approx.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_cwmh.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_gibbs.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_hmc.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_langevin_algorithm.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_laplace_approximation.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_mh.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_pcn.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_rto.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/sampler/_sampler.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/samples/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/samples/_samples.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/solver/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/solver/_solver.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/testproblem/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/testproblem/_testproblem.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/utilities/__init__.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/utilities/_get_python_variable_name.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/cuqi/utilities/_utilities.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/pyproject.toml +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/requirements.txt +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/setup.cfg +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/setup.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_abstract_distribution_density.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_bayesian_inversion.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_density.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_distribution.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_geometry.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_joint_distribution.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_likelihood.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_model.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_problem.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_sampler.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_samples.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_solver.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_testproblem.py +0 -0
- {CUQIpy-0.4.0 → CUQIpy-0.4.0.post0.dev19}/tests/test_utilities.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: CUQIpy
|
|
3
|
-
Version: 0.4.0
|
|
3
|
+
Version: 0.4.0.post0.dev19
|
|
4
4
|
Summary: Computational Uncertainty Quantification for Inverse problems in Python
|
|
5
5
|
Maintainer-email: "Nicolai A. B. Riis" <nabr@dtu.dk>, "Jakob S. Jørgensen" <jakj@dtu.dk>, "Amal M. Alghamdi" <amaal@dtu.dk>
|
|
6
6
|
License: Apache License
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: CUQIpy
|
|
3
|
-
Version: 0.4.0
|
|
3
|
+
Version: 0.4.0.post0.dev19
|
|
4
4
|
Summary: Computational Uncertainty Quantification for Inverse problems in Python
|
|
5
5
|
Maintainer-email: "Nicolai A. B. Riis" <nabr@dtu.dk>, "Jakob S. Jørgensen" <jakj@dtu.dk>, "Amal M. Alghamdi" <amaal@dtu.dk>
|
|
6
6
|
License: Apache License
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2023-
|
|
11
|
+
"date": "2023-06-09T10:16:49+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.4.0"
|
|
14
|
+
"full-revisionid": "d7e4a312b9c749d530f7cf3c06068857ab6b2fe2",
|
|
15
|
+
"version": "0.4.0.post0.dev19"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -84,6 +84,8 @@ class PDE(ABC):
|
|
|
84
84
|
|
|
85
85
|
@grid_obs.setter
|
|
86
86
|
def grid_obs(self,value):
|
|
87
|
+
if value is None:
|
|
88
|
+
value = self.grid_sol
|
|
87
89
|
self._grids_equal = self._compare_grid(value,self.grid_sol)
|
|
88
90
|
self._grid_obs = value
|
|
89
91
|
|
|
@@ -186,7 +188,10 @@ class TimeDependentLinearPDE(LinearPDE):
|
|
|
186
188
|
Callable function with signature `PDE_form(parameter, t)` where `parameter` is the Bayesian parameter and `t` is the time at which the PDE form is evaluated. The function returns a tuple of (`differential_operator`, `source_term`, `initial_condition`) where `differential_operator` is the linear operator at time `t`, `source_term` is the source term at time `t`, and `initial_condition` is the initial condition. The types of `differential_operator` and `source_term` are determined by what the method :meth:`linalg_solve` accepts as linear operator and right-hand side, respectively. The type of `initial_condition` should be the same type as the solution returned by :meth:`linalg_solve`.
|
|
187
189
|
|
|
188
190
|
time_steps : ndarray
|
|
189
|
-
An array of the discretized times corresponding to the time steps that starts with the initial time and ends with the final time
|
|
191
|
+
An array of the discretized times corresponding to the time steps that starts with the initial time and ends with the final time
|
|
192
|
+
|
|
193
|
+
time_obs : array_like or str
|
|
194
|
+
If passed as an array_like, it is an array of the times at which the solution is observed. If passed as a string it can be set to `final` to observe at the final time step, or `all` to observe at all time steps. Default is `final`.
|
|
190
195
|
|
|
191
196
|
method: str
|
|
192
197
|
Time stepping method. Currently two options are available `forward_euler` and `backward_euler`.
|
|
@@ -199,12 +204,25 @@ class TimeDependentLinearPDE(LinearPDE):
|
|
|
199
204
|
See demos/demo34_TimeDependentLinearPDE.py for 1D heat and 1D wave equations.
|
|
200
205
|
"""
|
|
201
206
|
|
|
202
|
-
def __init__(self, PDE_form, time_steps, method='forward_euler', **kwargs):
|
|
207
|
+
def __init__(self, PDE_form, time_steps, time_obs='final', method='forward_euler', **kwargs):
|
|
203
208
|
super().__init__(PDE_form, **kwargs)
|
|
204
209
|
|
|
205
210
|
self.time_steps = time_steps
|
|
206
211
|
self.method = method
|
|
207
212
|
|
|
213
|
+
# Set time_obs
|
|
214
|
+
if time_obs is None:
|
|
215
|
+
raise ValueError("time_obs cannot be None")
|
|
216
|
+
elif isinstance(time_obs, str):
|
|
217
|
+
if time_obs.lower() == 'final':
|
|
218
|
+
time_obs = time_steps[-1:]
|
|
219
|
+
elif time_obs.lower() == 'all':
|
|
220
|
+
time_obs = time_steps
|
|
221
|
+
else:
|
|
222
|
+
raise ValueError("if time_obs is a string, it can only be set "
|
|
223
|
+
+"to `final` or `all`")
|
|
224
|
+
self._time_obs = time_obs
|
|
225
|
+
|
|
208
226
|
@property
|
|
209
227
|
def method(self):
|
|
210
228
|
return self._method
|
|
@@ -226,37 +244,62 @@ class TimeDependentLinearPDE(LinearPDE):
|
|
|
226
244
|
|
|
227
245
|
def solve(self):
|
|
228
246
|
"""Solve PDE by time-stepping"""
|
|
247
|
+
# initialize time-dependent solution
|
|
248
|
+
self.assemble_step(self.time_steps[0])
|
|
249
|
+
u = np.empty((len(self.initial_condition), len(self.time_steps)))
|
|
250
|
+
u[:, 0] = self.initial_condition
|
|
229
251
|
|
|
230
252
|
if self.method == 'forward_euler':
|
|
231
253
|
for idx, t in enumerate(self.time_steps[:-1]):
|
|
232
254
|
dt = self.time_steps[idx+1] - t
|
|
233
255
|
self.assemble_step(t)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
u = (dt*self.diff_op + np.eye(len(u)))@u + dt*self.rhs # from u at time t, gives u at t+dt
|
|
256
|
+
u_pre = u[:, idx]
|
|
257
|
+
u[:, idx+1] = (dt*self.diff_op + np.eye(len(u_pre)))@u_pre + dt*self.rhs # from u at time t, gives u at t+dt
|
|
237
258
|
info = None
|
|
238
259
|
|
|
239
260
|
if self.method == 'backward_euler':
|
|
240
261
|
for idx, t in enumerate(self.time_steps[1:]):
|
|
241
262
|
dt = t - self.time_steps[idx]
|
|
242
263
|
self.assemble_step(t)
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
A = np.eye(len(u)) - dt*self.diff_op
|
|
264
|
+
u_pre = u[:, idx]
|
|
265
|
+
A = np.eye(len(u_pre)) - dt*self.diff_op
|
|
246
266
|
# from u at time t-dt, gives u at t
|
|
247
|
-
u, info = self._solve_linear_system(
|
|
248
|
-
A,
|
|
267
|
+
u[:, idx+1], info = self._solve_linear_system(
|
|
268
|
+
A, u_pre + dt*self.rhs, self._linalg_solve, self._linalg_solve_kwargs)
|
|
249
269
|
|
|
250
270
|
return u, info
|
|
251
271
|
|
|
252
272
|
def observe(self, solution):
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
273
|
+
|
|
274
|
+
# If observation grid is the same as solution grid and observation time
|
|
275
|
+
# is the final time step then no need to interpolate
|
|
276
|
+
if self.grids_equal and np.all(self.time_steps[-1:] == self._time_obs):
|
|
277
|
+
solution_obs = solution[..., -1]
|
|
278
|
+
|
|
279
|
+
# Interpolate solution in time and space to the observation
|
|
280
|
+
# time and space
|
|
256
281
|
else:
|
|
257
|
-
|
|
282
|
+
# Raise error if solution is 2D or 3D in space
|
|
283
|
+
if len(solution.shape) > 2:
|
|
284
|
+
raise ValueError("Interpolation of solutions of 2D and 3D "+
|
|
285
|
+
"space dimensions based on the provided "+
|
|
286
|
+
"grid_obs and time_obs are not supported. "+
|
|
287
|
+
"You can, instead, pass a custom "+
|
|
288
|
+
"observation_map and pass grid_obs and "+
|
|
289
|
+
"time_obs as None.")
|
|
290
|
+
|
|
291
|
+
# Interpolate solution in space and time to the observation
|
|
292
|
+
# time and space
|
|
293
|
+
solution_obs = scipy.interpolate.RectBivariateSpline(
|
|
294
|
+
self.grid_sol, self.time_steps, solution)(self.grid_obs,
|
|
295
|
+
self._time_obs)
|
|
258
296
|
|
|
297
|
+
# Apply observation map
|
|
259
298
|
if self.observation_map is not None:
|
|
260
299
|
solution_obs = self.observation_map(solution_obs)
|
|
261
|
-
|
|
262
|
-
|
|
300
|
+
|
|
301
|
+
# squeeze if only one time observation
|
|
302
|
+
if len(self._time_obs) == 1:
|
|
303
|
+
solution_obs = solution_obs.squeeze()
|
|
304
|
+
|
|
305
|
+
return solution_obs
|
|
@@ -181,14 +181,26 @@ def test_observe():
|
|
|
181
181
|
assert(np.all(np.isclose(observed_sol, expected_observed_sol)))
|
|
182
182
|
|
|
183
183
|
|
|
184
|
-
@pytest.mark.parametrize(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
184
|
+
@pytest.mark.parametrize(
|
|
185
|
+
"method, time_steps, parametrization, expected_sol",
|
|
186
|
+
[('forward_euler', 'fixed', 'initial_condition', 'sol1'),
|
|
187
|
+
('backward_euler', 'fixed', 'initial_condition', 'sol2'),
|
|
188
|
+
('backward_euler', 'varying',
|
|
189
|
+
'initial_condition', 'sol3'),
|
|
190
|
+
('backward_euler', 'fixed', 'source_term1', 'sol4'),
|
|
191
|
+
('backward_euler', 'fixed', 'source_term2', 'sol5')])
|
|
192
|
+
@pytest.mark.parametrize(
|
|
193
|
+
"grid_obs, time_obs, observation_map, expected_obs",
|
|
194
|
+
[(None, 'final', None, 'obs1'),
|
|
195
|
+
(None, 'final', lambda x: x**2, 'obs2'),
|
|
196
|
+
('half_grid', 'FINAL', None, 'obs3'),
|
|
197
|
+
('half_grid', 'every_5', None, 'obs4'),
|
|
198
|
+
(None, 'every_5', lambda x: x**2, 'obs5'),
|
|
199
|
+
(np.array([3, 4.9]), np.array([0.9, 1]), lambda x: x**2, 'obs6')])
|
|
200
|
+
def test_TimeDependentLinearPDE_heat1D(copy_reference, method, time_steps,
|
|
201
|
+
parametrization, expected_sol,
|
|
202
|
+
grid_obs, time_obs, observation_map,
|
|
203
|
+
expected_obs):
|
|
192
204
|
""" Compute the final time solution of a 1D heat equation and
|
|
193
205
|
compare it with previously stored solution (for 5 different set up choices).
|
|
194
206
|
"""
|
|
@@ -197,6 +209,7 @@ def test_TimeDependentLinearPDE_heat1D(copy_reference, method, time_steps, param
|
|
|
197
209
|
L = 5 # 1D domain length
|
|
198
210
|
max_time = 1 # Final time
|
|
199
211
|
dx = L/(dim+1) # Space step size
|
|
212
|
+
grid_sol = np.linspace(dx, L-dx, dim) # Solution grid
|
|
200
213
|
|
|
201
214
|
if method == 'forward_euler':
|
|
202
215
|
cfl = 5/11 # The cfl condition to have a stable solution
|
|
@@ -234,18 +247,78 @@ def test_TimeDependentLinearPDE_heat1D(copy_reference, method, time_steps, param
|
|
|
234
247
|
elif parametrization == 'source_term2':
|
|
235
248
|
parameters = np.ones(dim)
|
|
236
249
|
|
|
237
|
-
# 4.
|
|
250
|
+
# 4. Set up the observation parameters
|
|
251
|
+
if grid_obs == 'half_grid':
|
|
252
|
+
grid_obs = grid_sol[int(dim/2):]
|
|
253
|
+
|
|
254
|
+
if time_obs == 'every_5':
|
|
255
|
+
time_obs = time_steps[::5]
|
|
256
|
+
|
|
257
|
+
# 5. Create a PDE object
|
|
238
258
|
PDE = cuqi.pde.TimeDependentLinearPDE(
|
|
239
|
-
PDE_form, time_steps, method=method
|
|
259
|
+
PDE_form, time_steps, method=method,
|
|
260
|
+
grid_sol=grid_sol,
|
|
261
|
+
grid_obs=grid_obs, time_obs=time_obs,
|
|
262
|
+
observation_map=observation_map)
|
|
240
263
|
|
|
241
|
-
#
|
|
264
|
+
# 6. Solve the PDE
|
|
242
265
|
PDE.assemble(parameters)
|
|
243
266
|
sol, info = PDE.solve()
|
|
244
267
|
|
|
245
|
-
#
|
|
246
|
-
solution_file = copy_reference("data/Heat1D_5solutions.npz")
|
|
268
|
+
# 7. Compare the obtained solution with previously stored solution
|
|
269
|
+
solution_file = copy_reference("data/Heat1D_data/Heat1D_5solutions.npz")
|
|
247
270
|
expected_sols = np.load(solution_file)
|
|
248
|
-
assert(np.allclose(sol, expected_sols[expected_sol]))
|
|
271
|
+
assert (np.allclose(sol[:, -1], expected_sols[expected_sol]))
|
|
272
|
+
|
|
273
|
+
# 8. Compute the observed solution and compare it with previously
|
|
274
|
+
# stored solution
|
|
275
|
+
|
|
276
|
+
# compute the observed solution using the PDE object
|
|
277
|
+
obs_sol = PDE.observe(sol)
|
|
278
|
+
|
|
279
|
+
# compute the expected observed solution (for comparison)
|
|
280
|
+
if isinstance(time_obs, str) and time_obs.lower() == 'final':
|
|
281
|
+
time_obs = time_steps[-1:]
|
|
282
|
+
if grid_obs is None:
|
|
283
|
+
grid_obs = grid_sol
|
|
284
|
+
|
|
285
|
+
idx_x = [True if x in grid_obs else False for x in grid_sol]
|
|
286
|
+
idx_t = [True if t in time_obs else False for t in time_steps]
|
|
287
|
+
|
|
288
|
+
if sum(idx_x) != len(grid_obs) or sum(idx_t) != len(time_obs):
|
|
289
|
+
expected_observed_sol = scipy.interpolate.RectBivariateSpline(
|
|
290
|
+
grid_sol, time_steps, sol)(grid_obs, time_obs
|
|
291
|
+
)
|
|
292
|
+
else:
|
|
293
|
+
expected_observed_sol = sol[idx_x, :][:, idx_t]
|
|
294
|
+
|
|
295
|
+
if observation_map is not None:
|
|
296
|
+
expected_observed_sol = observation_map(expected_observed_sol)
|
|
297
|
+
|
|
298
|
+
if len(PDE._time_obs) == 1:
|
|
299
|
+
expected_observed_sol = expected_observed_sol.squeeze()
|
|
300
|
+
|
|
301
|
+
# load expected observed solution (for comparison)
|
|
302
|
+
# Skip sol1 due to its large size (not stored in file to save space)
|
|
303
|
+
if expected_sol != 'sol1':
|
|
304
|
+
obs_sol_file = copy_reference("data/Heat1D_data/Heat1D_obs_sol_"
|
|
305
|
+
+ expected_sol+"_"
|
|
306
|
+
+ expected_obs+".npz")
|
|
307
|
+
expected_observed_sol_from_file = np.load(obs_sol_file)["obs_sol"]
|
|
308
|
+
|
|
309
|
+
if len(PDE._time_obs) == 1:
|
|
310
|
+
expected_observed_sol_from_file = \
|
|
311
|
+
expected_observed_sol_from_file.squeeze()
|
|
312
|
+
|
|
313
|
+
# Compare the observed solution with the two expected observed solution
|
|
314
|
+
# (computed and loaded from file)
|
|
315
|
+
assert (np.allclose(obs_sol, expected_observed_sol))
|
|
316
|
+
|
|
317
|
+
if expected_sol != 'sol1':
|
|
318
|
+
assert (np.allclose(obs_sol, expected_observed_sol_from_file))
|
|
319
|
+
else:
|
|
320
|
+
assert expected_sol == 'sol1'
|
|
321
|
+
|
|
249
322
|
|
|
250
323
|
@pytest.mark.xfail(reason="Test fails due to difficult to compare values (1e-6 to 1e-42)")
|
|
251
324
|
def test_TimeDependentLinearPDE_wave1D(copy_reference):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|