diff --git a/ezyrb/plugin/scaler.py b/ezyrb/plugin/scaler.py index 10dc6bf..5f3012a 100644 --- a/ezyrb/plugin/scaler.py +++ b/ezyrb/plugin/scaler.py @@ -26,7 +26,7 @@ def __init__(self, scaler, mode, target) -> None: self.scaler = scaler self.mode = mode self.target = target - + @property def target(self): """ @@ -141,5 +141,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/ezyrb/reducedordermodel.py b/ezyrb/reducedordermodel.py index 2a89f25..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))) @@ -312,3 +317,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_reduct = rom.reconstruction_error(relative=True) + >>> err_test_reduct = 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_approx = rom.approximation_error(relative=True) + >>> err_test_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) + diff --git a/tests/test_scaler.py b/tests/test_scaler.py index 2de2b62..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 @@ -18,22 +18,30 @@ 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'), + DatabaseScaler(StandardScaler(), 'full', 'parameters') + ]) + rom.fit() + test_param = param[2] + truth_sol = db.snapshots_matrix[2] + predicted_sol = rom.predict(test_param).snapshots_matrix[0] + np.testing.assert_allclose(predicted_sol, truth_sol, + rtol=1e-5, atol=1e-5)