From 7e61534cc2e7593cc3dc68efbd8b6421d9b43cf4 Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Thu, 25 Sep 2025 11:10:26 +0200 Subject: [PATCH 1/7] Added the reconstraction and approximation errors --- ezyrb/reducedordermodel.py | 104 +++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/ezyrb/reducedordermodel.py b/ezyrb/reducedordermodel.py index 2a89f25..ef0e15e 100644 --- a/ezyrb/reducedordermodel.py +++ b/ezyrb/reducedordermodel.py @@ -312,3 +312,107 @@ def _simplex_volume(self, vertices): distance = np.transpose([vertices[0] - vi for vi in vertices[1:]]) return np.abs( np.linalg.det(distance) / math.factorial(vertices.shape[1])) + + def reconstruction_error(self, db=None, relative=True, eps=1e-12): + """ + Calculate the reconstruction error between the original snapshots and + the ones reconstructed by the ROM. + + :param database.Database db: the database to use to compute the error. + If None, the error is computed on the training database. + Default is None. + :param bool relative: True if the error computed is relative. Default is + True. + :param float eps: small number to avoid division by zero in relative + error computation. Default is 1e-12. + :return: the vector containing the reconstruction errors. + + Esempio: + >>> from ezyrb import ReducedOrderModel as ROM + >>> from ezyrb import POD, RBF, Database + >>> db = Database(param, snapshots) # param and snapshots are assumed + to be declared + >>> db_train = db[:10] # training database + >>> db_test = db[10:] # test database + >>> pod = POD() + >>> rbf = RBF() + >>> rom = ROM(db_train, pod, rbf) + >>> rom.fit() + >>> err_train = rom.reconstruction_error(relative=True) + >>> err_rec = rom.reconstruction_error(db_test, relative=True) + """ + + errs = [] + if db is None: + db = self.database + snap = db.snapshots_matrix + snap_red = self.reduction.transform(snap.T) + snap_full = self.reduction.inverse_transform(snap_red).T + + E = snap - snap_full + + if relative: + num = np.linalg.norm(E, axis=1) + den = np.linalg.norm(snap, axis=1) + eps + + err = float(np.mean(num/den)) + else: + err = float(np.mean(np.linalg.norm(E, axis=1))) + errs.append(err) + + return np.array(errs) + + def approximation_error(self, db=None, relative=True, eps=1e-12): + """ + Calculate the approximation error between the true modal coefficients + and the approximated ones. + + :param database.Database db: the database to use to compute the error. + If None, the error is computed on the training database. + Default is None. + :param bool relative: True if the error computed is relative. Default is + True. + :param float eps: small number to avoid division by zero in relative + error computation. Default is 1e-12. + + :return: the vector containing the approximation errors. + + Esempio: + >>> from ezyrb import ReducedOrderModel as ROM + >>> from ezyrb import POD, RBF, Database + >>> db = Database(param, snapshots) # param and snapshots are assumed + to be declared + >>> db_train = db[:10] # training database + >>> db_test = db[10:] # test database + >>> pod = POD() + >>> rbf = RBF() + >>> rom = ROM(db_train, pod, rbf) + >>> rom.fit() + >>> err_train = rom.approximation_error(relative=True) + >>> err_approx = rom.approximation_error(db_test, relative=True) + + """ + errs = [] + if db is None: + db = self.database + + snap = db.snapshots_matrix + params_true = self.reduction.transform(snap.T).T + + params = db.parameters_matrix + + params_approx = self.approximation.predict(params) + + E = params_true - params_approx + + if relative: + num = np.linalg.norm(E, axis=1) + den = np.linalg.norm(params_true, axis=1) + eps + + err = float(np.mean(num/den)) + else: + err = float(np.mean(np.linalg.norm(E, axis=1))) + errs.append(err) + + return np.array(errs) + From e04bbf4abf228ac10ecc32d08e623d2ea83e9bd2 Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Thu, 25 Sep 2025 11:38:50 +0200 Subject: [PATCH 2/7] Small corrections --- ezyrb/reducedordermodel.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ezyrb/reducedordermodel.py b/ezyrb/reducedordermodel.py index ef0e15e..12b210b 100644 --- a/ezyrb/reducedordermodel.py +++ b/ezyrb/reducedordermodel.py @@ -338,8 +338,8 @@ def reconstruction_error(self, db=None, relative=True, eps=1e-12): >>> rbf = RBF() >>> rom = ROM(db_train, pod, rbf) >>> rom.fit() - >>> err_train = rom.reconstruction_error(relative=True) - >>> err_rec = rom.reconstruction_error(db_test, relative=True) + >>> err_train_reduct = rom.reconstruction_error(relative=True) + >>> err_test_reduct = rom.reconstruction_error(db_test, relative=True) """ errs = [] @@ -388,9 +388,9 @@ def approximation_error(self, db=None, relative=True, eps=1e-12): >>> rbf = RBF() >>> rom = ROM(db_train, pod, rbf) >>> rom.fit() - >>> err_train = rom.approximation_error(relative=True) - >>> err_approx = rom.approximation_error(db_test, relative=True) - + >>> err_train_approx = rom.approximation_error(relative=True) + >>> err_test_approx = rom.approximation_error(db_test, relative=True) + """ errs = [] if db is None: From b0a69351b2944909e16d04e83199f5606af23538 Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Thu, 25 Sep 2025 16:12:05 +0200 Subject: [PATCH 3/7] Added test for the scaling and possible problem with param scaling --- ezyrb/plugin/scaler.py | 5 ++++- tests/test_scaler.py | 29 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/ezyrb/plugin/scaler.py b/ezyrb/plugin/scaler.py index 10dc6bf..f6be1d3 100644 --- a/ezyrb/plugin/scaler.py +++ b/ezyrb/plugin/scaler.py @@ -26,6 +26,9 @@ def __init__(self, scaler, mode, target) -> None: self.scaler = scaler self.mode = mode self.target = target + + if target == 'parameters': #TODO + raise NotImplementedError("Scaling of parameters not implemented yet.") @property def target(self): @@ -141,5 +144,5 @@ def rom_postprocessing(self, rom): db.parameters_matrix, self.scaler.inverse_transform(self._select_matrix(db)), ) - + rom._reduced_database = new_db diff --git a/tests/test_scaler.py b/tests/test_scaler.py index 2de2b62..cde6a56 100644 --- a/tests/test_scaler.py +++ b/tests/test_scaler.py @@ -18,22 +18,31 @@ def test_constructor(): pod = POD() import torch rbf = RBF() - rbf = ANN([10, 10], function=torch.nn.Softplus(), stop_training=[1000]) + #rbf = ANN([10, 10], function=torch.nn.Softplus(), stop_training=[1000]) db = Database(param, snapshots.T) # rom = ROM(db, pod, rbf, plugins=[DatabaseScaler(StandardScaler(), 'full', 'snapshots')]) rom = ROM(db, pod, rbf, plugins=[ - DatabaseScaler(StandardScaler(), 'full', 'parameters'), + #DatabaseScaler(StandardScaler(), 'reduced', 'parameters'), DatabaseScaler(StandardScaler(), 'reduced', 'snapshots') ]) rom.fit() - print(rom.predict(rom.database.parameters_matrix)) - print(rom.database.snapshots_matrix) + + -# def test_values(): -# snap = Snapshot(test_value) -# snap.values = test_value -# snap = Snapshot(test_value, space=test_space) -# with pytest.raises(ValueError): -# snap.values = test_value[:-2] +def test_values(): + pod = POD() + rbf = RBF() + db = Database(param, snapshots.T) + rom = ROM(db, pod, rbf, plugins=[ + DatabaseScaler(StandardScaler(), 'reduced', 'snapshots') + ]) + rom.fit() + test_param = param[2] + truth_sol = db.snapshots_matrix[2] + predicted_sol = rom.predict(test_param).snapshots_matrix[0] + print(predicted_sol) + print(truth_sol) + np.testing.assert_allclose(predicted_sol, truth_sol, + rtol=1e-5, atol=1e-5) From e352f1f809454a7f5edf49900a2c280560f0ff58 Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Thu, 25 Sep 2025 16:13:48 +0200 Subject: [PATCH 4/7] Removed print --- tests/test_scaler.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_scaler.py b/tests/test_scaler.py index cde6a56..51b61ca 100644 --- a/tests/test_scaler.py +++ b/tests/test_scaler.py @@ -41,8 +41,6 @@ def test_values(): test_param = param[2] truth_sol = db.snapshots_matrix[2] predicted_sol = rom.predict(test_param).snapshots_matrix[0] - print(predicted_sol) - print(truth_sol) np.testing.assert_allclose(predicted_sol, truth_sol, rtol=1e-5, atol=1e-5) From d19dcc834cf4962f82cec9229e62683cbac3f885 Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Fri, 26 Sep 2025 14:58:29 +0200 Subject: [PATCH 5/7] Remove Assertion Error --- ezyrb/plugin/scaler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/ezyrb/plugin/scaler.py b/ezyrb/plugin/scaler.py index f6be1d3..5f3012a 100644 --- a/ezyrb/plugin/scaler.py +++ b/ezyrb/plugin/scaler.py @@ -27,9 +27,6 @@ def __init__(self, scaler, mode, target) -> None: self.mode = mode self.target = target - if target == 'parameters': #TODO - raise NotImplementedError("Scaling of parameters not implemented yet.") - @property def target(self): """ From ef394a9ddc8ae01707be6ab79d6c3f7ad6de7f4c Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Fri, 26 Sep 2025 14:59:13 +0200 Subject: [PATCH 6/7] Add the paramter scaling test --- tests/test_scaler.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_scaler.py b/tests/test_scaler.py index 51b61ca..5c8ad1c 100644 --- a/tests/test_scaler.py +++ b/tests/test_scaler.py @@ -6,7 +6,7 @@ from ezyrb import ReducedOrderModel as ROM from ezyrb.plugin.scaler import DatabaseScaler -from sklearn.preprocessing import StandardScaler +from sklearn.preprocessing import StandardScaler, MinMaxScaler snapshots = np.load('tests/test_datasets/p_snapshots.npy').T pred_sol_tst = np.load('tests/test_datasets/p_predsol.npy').T @@ -22,7 +22,7 @@ def test_constructor(): db = Database(param, snapshots.T) # rom = ROM(db, pod, rbf, plugins=[DatabaseScaler(StandardScaler(), 'full', 'snapshots')]) rom = ROM(db, pod, rbf, plugins=[ - #DatabaseScaler(StandardScaler(), 'reduced', 'parameters'), + DatabaseScaler(StandardScaler(), 'reduced', 'parameters'), DatabaseScaler(StandardScaler(), 'reduced', 'snapshots') ]) rom.fit() @@ -35,7 +35,8 @@ def test_values(): rbf = RBF() db = Database(param, snapshots.T) rom = ROM(db, pod, rbf, plugins=[ - DatabaseScaler(StandardScaler(), 'reduced', 'snapshots') + DatabaseScaler(StandardScaler(), 'reduced', 'snapshots'), + DatabaseScaler(StandardScaler(), 'full', 'parameters') ]) rom.fit() test_param = param[2] From ae577c394e0bb6e68292287c058caf7925ff2674 Mon Sep 17 00:00:00 2001 From: DavideDC95 Date: Fri, 26 Sep 2025 14:59:59 +0200 Subject: [PATCH 7/7] Add scaling of the new parameter in predict method --- ezyrb/reducedordermodel.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ezyrb/reducedordermodel.py b/ezyrb/reducedordermodel.py index 12b210b..cf8af2e 100644 --- a/ezyrb/reducedordermodel.py +++ b/ezyrb/reducedordermodel.py @@ -99,7 +99,12 @@ def predict(self, mu): :rtype: Database """ mu = np.atleast_2d(mu) - + + for plugin in self.plugins: + if plugin.target == 'parameters': + mu = plugin.scaler.transform(mu) + + self._reduced_database = Database( mu, np.atleast_2d(self.approximation.predict(mu)))