Skip to content

Commit 3121318

Browse files
authored
Added the reconstruction and approximation errors (#263)
* Added the reconstraction and approximation errors * Added test for the scaling and possible problem with param scaling
1 parent 5f2900d commit 3121318

File tree

3 files changed

+131
-14
lines changed

3 files changed

+131
-14
lines changed

ezyrb/plugin/scaler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, scaler, mode, target) -> None:
2626
self.scaler = scaler
2727
self.mode = mode
2828
self.target = target
29-
29+
3030
@property
3131
def target(self):
3232
"""
@@ -141,5 +141,5 @@ def rom_postprocessing(self, rom):
141141
db.parameters_matrix,
142142
self.scaler.inverse_transform(self._select_matrix(db)),
143143
)
144-
144+
145145
rom._reduced_database = new_db

ezyrb/reducedordermodel.py

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ def predict(self, mu):
9999
:rtype: Database
100100
"""
101101
mu = np.atleast_2d(mu)
102-
102+
103+
for plugin in self.plugins:
104+
if plugin.target == 'parameters':
105+
mu = plugin.scaler.transform(mu)
106+
107+
103108
self._reduced_database = Database(
104109
mu, np.atleast_2d(self.approximation.predict(mu)))
105110

@@ -312,3 +317,107 @@ def _simplex_volume(self, vertices):
312317
distance = np.transpose([vertices[0] - vi for vi in vertices[1:]])
313318
return np.abs(
314319
np.linalg.det(distance) / math.factorial(vertices.shape[1]))
320+
321+
def reconstruction_error(self, db=None, relative=True, eps=1e-12):
322+
"""
323+
Calculate the reconstruction error between the original snapshots and
324+
the ones reconstructed by the ROM.
325+
326+
:param database.Database db: the database to use to compute the error.
327+
If None, the error is computed on the training database.
328+
Default is None.
329+
:param bool relative: True if the error computed is relative. Default is
330+
True.
331+
:param float eps: small number to avoid division by zero in relative
332+
error computation. Default is 1e-12.
333+
:return: the vector containing the reconstruction errors.
334+
335+
Esempio:
336+
>>> from ezyrb import ReducedOrderModel as ROM
337+
>>> from ezyrb import POD, RBF, Database
338+
>>> db = Database(param, snapshots) # param and snapshots are assumed
339+
to be declared
340+
>>> db_train = db[:10] # training database
341+
>>> db_test = db[10:] # test database
342+
>>> pod = POD()
343+
>>> rbf = RBF()
344+
>>> rom = ROM(db_train, pod, rbf)
345+
>>> rom.fit()
346+
>>> err_train_reduct = rom.reconstruction_error(relative=True)
347+
>>> err_test_reduct = rom.reconstruction_error(db_test, relative=True)
348+
"""
349+
350+
errs = []
351+
if db is None:
352+
db = self.database
353+
snap = db.snapshots_matrix
354+
snap_red = self.reduction.transform(snap.T)
355+
snap_full = self.reduction.inverse_transform(snap_red).T
356+
357+
E = snap - snap_full
358+
359+
if relative:
360+
num = np.linalg.norm(E, axis=1)
361+
den = np.linalg.norm(snap, axis=1) + eps
362+
363+
err = float(np.mean(num/den))
364+
else:
365+
err = float(np.mean(np.linalg.norm(E, axis=1)))
366+
errs.append(err)
367+
368+
return np.array(errs)
369+
370+
def approximation_error(self, db=None, relative=True, eps=1e-12):
371+
"""
372+
Calculate the approximation error between the true modal coefficients
373+
and the approximated ones.
374+
375+
:param database.Database db: the database to use to compute the error.
376+
If None, the error is computed on the training database.
377+
Default is None.
378+
:param bool relative: True if the error computed is relative. Default is
379+
True.
380+
:param float eps: small number to avoid division by zero in relative
381+
error computation. Default is 1e-12.
382+
383+
:return: the vector containing the approximation errors.
384+
385+
Esempio:
386+
>>> from ezyrb import ReducedOrderModel as ROM
387+
>>> from ezyrb import POD, RBF, Database
388+
>>> db = Database(param, snapshots) # param and snapshots are assumed
389+
to be declared
390+
>>> db_train = db[:10] # training database
391+
>>> db_test = db[10:] # test database
392+
>>> pod = POD()
393+
>>> rbf = RBF()
394+
>>> rom = ROM(db_train, pod, rbf)
395+
>>> rom.fit()
396+
>>> err_train_approx = rom.approximation_error(relative=True)
397+
>>> err_test_approx = rom.approximation_error(db_test, relative=True)
398+
399+
"""
400+
errs = []
401+
if db is None:
402+
db = self.database
403+
404+
snap = db.snapshots_matrix
405+
params_true = self.reduction.transform(snap.T).T
406+
407+
params = db.parameters_matrix
408+
409+
params_approx = self.approximation.predict(params)
410+
411+
E = params_true - params_approx
412+
413+
if relative:
414+
num = np.linalg.norm(E, axis=1)
415+
den = np.linalg.norm(params_true, axis=1) + eps
416+
417+
err = float(np.mean(num/den))
418+
else:
419+
err = float(np.mean(np.linalg.norm(E, axis=1)))
420+
errs.append(err)
421+
422+
return np.array(errs)
423+

tests/test_scaler.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ezyrb import ReducedOrderModel as ROM
77
from ezyrb.plugin.scaler import DatabaseScaler
88

9-
from sklearn.preprocessing import StandardScaler
9+
from sklearn.preprocessing import StandardScaler, MinMaxScaler
1010

1111
snapshots = np.load('tests/test_datasets/p_snapshots.npy').T
1212
pred_sol_tst = np.load('tests/test_datasets/p_predsol.npy').T
@@ -18,22 +18,30 @@ def test_constructor():
1818
pod = POD()
1919
import torch
2020
rbf = RBF()
21-
rbf = ANN([10, 10], function=torch.nn.Softplus(), stop_training=[1000])
21+
#rbf = ANN([10, 10], function=torch.nn.Softplus(), stop_training=[1000])
2222
db = Database(param, snapshots.T)
2323
# rom = ROM(db, pod, rbf, plugins=[DatabaseScaler(StandardScaler(), 'full', 'snapshots')])
2424
rom = ROM(db, pod, rbf, plugins=[
25-
DatabaseScaler(StandardScaler(), 'full', 'parameters'),
25+
DatabaseScaler(StandardScaler(), 'reduced', 'parameters'),
2626
DatabaseScaler(StandardScaler(), 'reduced', 'snapshots')
2727
])
2828
rom.fit()
29-
print(rom.predict(rom.database.parameters_matrix))
30-
print(rom.database.snapshots_matrix)
29+
30+
3131

3232

33-
# def test_values():
34-
# snap = Snapshot(test_value)
35-
# snap.values = test_value
36-
# snap = Snapshot(test_value, space=test_space)
37-
# with pytest.raises(ValueError):
38-
# snap.values = test_value[:-2]
33+
def test_values():
34+
pod = POD()
35+
rbf = RBF()
36+
db = Database(param, snapshots.T)
37+
rom = ROM(db, pod, rbf, plugins=[
38+
DatabaseScaler(StandardScaler(), 'reduced', 'snapshots'),
39+
DatabaseScaler(StandardScaler(), 'full', 'parameters')
40+
])
41+
rom.fit()
42+
test_param = param[2]
43+
truth_sol = db.snapshots_matrix[2]
44+
predicted_sol = rom.predict(test_param).snapshots_matrix[0]
45+
np.testing.assert_allclose(predicted_sol, truth_sol,
46+
rtol=1e-5, atol=1e-5)
3947

0 commit comments

Comments
 (0)