diff --git a/examples/burgers1d.ipynb b/examples/burgers1d.ipynb index c5f5d0f..1cff602 100644 --- a/examples/burgers1d.ipynb +++ b/examples/burgers1d.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "d67dad03-9d76-4891-82ff-7e19d1369a24", "metadata": {}, "outputs": [], @@ -46,6 +46,7 @@ "trainer, param_space, physics, autoencoder, sindy = initialize_trainer(config)\n", "\n", "# generate initial training/test data\n", + "pick_samples(trainer, config)\n", "run_samples(trainer, config)\n", "# initial training given training data\n", "trainer.train()\n", @@ -77,7 +78,7 @@ "outputs": [], "source": [ "# Specify the restart file you have.\n", - "filename = 'lasdi_09_18_2024_20_51.npy'\n", + "filename = 'lasdi_10_01_2024_17_09.npy'\n", "\n", "import yaml\n", "from lasdi.workflow import initialize_trainer\n", @@ -110,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "dcdac0c2", "metadata": {}, "outputs": [], diff --git a/examples/burgers1d.offline.bash b/examples/burgers1d.offline.bash index 028a011..70e029c 100644 --- a/examples/burgers1d.offline.bash +++ b/examples/burgers1d.offline.bash @@ -1,29 +1,48 @@ #!/usr/bin/bash -# First stage will be RunSamples, which will produce parameter point files in hdf5 format. +check_result () { + # $1: Result output of the previous command ($?) + # $2: Name of the previous command + if [ $1 -eq 0 ]; then + echo "$2 succeeded" + else + echo "$2 failed" + exit -1 + fi +} + +# First stage will be PickSample, which will produce parameter point files in hdf5 format. # Each lasdi command will save a restart file, which will be read on the next lasdi command. # So all stages are run by the same command, directed differently by the restart file. lasdi burgers1d.offline.yml +check_result $? initial-picksample # Run/save FOM solution with offline FOM solver. burgers1d burgers1d.offline.yml +check_result $? initial-runsample # Collect FOM solution. lasdi burgers1d.offline.yml +check_result $? initial-collect # Train latent dynamics model. lasdi burgers1d.offline.yml +check_result $? initial-train for k in {0..8} do # Pick a new sample from greedy sampling lasdi burgers1d.offline.yml + check_result $? pick-sample - # A cycle of RunSamples/offline FOM/CollectSamples - lasdi burgers1d.offline.yml + # A cycle of offline FOM/CollectSamples burgers1d burgers1d.offline.yml + check_result $? run-sample + lasdi burgers1d.offline.yml + check_result $? collect-sample # Train latent dynamics model. lasdi burgers1d.offline.yml + check_result $? train done diff --git a/src/lasdi/gplasdi.py b/src/lasdi/gplasdi.py index 27f2d16..ac3d046 100644 --- a/src/lasdi/gplasdi.py +++ b/src/lasdi/gplasdi.py @@ -257,7 +257,7 @@ def get_new_sample_point(self): m_index = get_fom_max_std(ae, Zis) - new_sample = ps.test_space[m_index, :] + new_sample = ps.test_space[m_index, :].reshape(1, -1) print('New param: ' + str(np.round(new_sample, 4)) + '\n') self.timer.end("new_sample") diff --git a/src/lasdi/physics/__init__.py b/src/lasdi/physics/__init__.py index ddd97c5..1aa7e84 100644 --- a/src/lasdi/physics/__init__.py +++ b/src/lasdi/physics/__init__.py @@ -57,6 +57,7 @@ def generate_solutions(self, params): params.shape[1] must match the required size of parameters for the specific physics. ''' + assert(params.ndim == 2) n_param = len(params) print("Generating %d samples" % n_param) diff --git a/src/lasdi/workflow.py b/src/lasdi/workflow.py index a1c9b7a..3d20fc1 100644 --- a/src/lasdi/workflow.py +++ b/src/lasdi/workflow.py @@ -48,7 +48,7 @@ def main(): result = restart_file['result'] else: restart_file = None - current_step = NextStep.RunSample + current_step = NextStep.PickSample result = Result.Unexecuted trainer, param_space, physics, latent_space, latent_dynamics = initialize_trainer(config, restart_file) @@ -92,7 +92,7 @@ def main(): np.save(save_file, save_dict) - return result + return def step(trainer, next_step, config, use_restart=False): @@ -200,20 +200,71 @@ def initialize_physics(config, param_name): return physics +''' + Perform greedy sampling to pick a new parameter point. + if physics is offline solver, save parameter points to a hdf file that fom solver can read. +''' def pick_samples(trainer, config): - new_sample = trainer.get_new_sample_point() + # for initial step, get initial parameter points from parameter space. + if (trainer.X_train.size(0) == 0): + new_sample = trainer.param_space.train_space + else: + # for greedy sampling, get a new parameter and append training space. + new_sample = trainer.get_new_sample_point() + trainer.param_space.appendTrainSpace(new_sample) + + # for initial step, get initial parameter points from parameter space. + new_tests = 0 + if (trainer.X_test.size(0) == 0): + new_test_params = trainer.param_space.test_space + new_tests = new_test_params.shape[0] + # TODO(kevin): greedy sampling for a new test parameter? + + # For online physics solver, we go directly obtain new solutions. + if not trainer.physics.offline: + next_step, result = NextStep.RunSample, Result.Success + return result, next_step + + # Save parameter points in hdf5 format, for offline fom solver to read and run simulations. + from os.path import dirname, exists + from os import remove + from pathlib import Path + cfg_parser = InputParser(config) + + train_param_file = cfg_parser.getInput(['workflow', 'offline_greedy_sampling', 'train_param_file'], fallback="new_train.h5") + Path(dirname(train_param_file)).mkdir(parents=True, exist_ok=True) + + with h5py.File(train_param_file, 'w') as f: + f.create_dataset("train_params", new_sample.shape, data=new_sample) + f.create_dataset("parameters", (len(trainer.param_space.param_name),), data=trainer.param_space.param_name) + f.attrs["n_params"] = trainer.param_space.n_param + f.attrs["new_points"] = new_sample.shape[0] - trainer.param_space.appendTrainSpace(new_sample) + # clean up the previous test parameter point file. + test_param_file = cfg_parser.getInput(['workflow', 'offline_greedy_sampling', 'test_param_file'], fallback="new_test.h5") + Path(dirname(test_param_file)).mkdir(parents=True, exist_ok=True) + if exists(test_param_file): + remove(test_param_file) - next_step, result = NextStep.RunSample, Result.Success + if (new_tests > 0): + with h5py.File(test_param_file, 'w') as f: + f.create_dataset("test_params", new_test_params.shape, data=new_test_params) + f.create_dataset("parameters", (len(trainer.param_space.param_name),), data=trainer.param_space.param_name) + f.attrs["n_params"] = trainer.param_space.n_param + f.attrs["new_points"] = new_test_params.shape[0] + + # Next step is to collect sample from the offline FOM simulation. + next_step, result = NextStep.CollectSample, Result.Success return result, next_step ''' update trainer.X_train and trainer.X_test based on param_space.train_space and param_space.test_space. - if physics is offline solver, save parameter points to a hdf file that fom solver can read. ''' def run_samples(trainer, config): + if trainer.physics.offline: + raise RuntimeError("Current physics solver is offline. RunSamples stage cannot be run online!") + cfg_parser = InputParser(config) new_trains = trainer.param_space.n_train() - trainer.X_train.size(0) @@ -224,53 +275,20 @@ def run_samples(trainer, config): if (new_tests > 0): new_test_params = trainer.param_space.test_space[-new_tests:, :] - if trainer.physics.offline: - # Save parameter points in hdf5 format, for offline fom solver to read and run simulations. - from os.path import dirname, exists - from os import remove - from pathlib import Path - - train_param_file = cfg_parser.getInput(['workflow', 'offline_greedy_sampling', 'train_param_file'], fallback="new_train.h5") - Path(dirname(train_param_file)).mkdir(parents=True, exist_ok=True) - - with h5py.File(train_param_file, 'w') as f: - f.create_dataset("train_params", new_train_params.shape, data=new_train_params) - f.create_dataset("parameters", (len(trainer.param_space.param_name),), data=trainer.param_space.param_name) - f.attrs["n_params"] = trainer.param_space.n_param - f.attrs["new_points"] = new_train_params.shape[0] - - # clean up the previous test parameter point file. - test_param_file = cfg_parser.getInput(['workflow', 'offline_greedy_sampling', 'test_param_file'], fallback="new_test.h5") - Path(dirname(test_param_file)).mkdir(parents=True, exist_ok=True) - if exists(test_param_file): - remove(test_param_file) - - if (new_tests > 0): - with h5py.File(test_param_file, 'w') as f: - f.create_dataset("test_params", new_test_params.shape, data=new_test_params) - f.create_dataset("parameters", (len(trainer.param_space.param_name),), data=trainer.param_space.param_name) - f.attrs["n_params"] = trainer.param_space.n_param - f.attrs["new_points"] = new_test_params.shape[0] - - # Next step is to collect sample from the offline FOM simulation. - next_step, result = NextStep.CollectSample, Result.Success - return result, next_step - - else: - # We run FOM simulation directly here. + # We run FOM simulation directly here. - new_X = trainer.physics.generate_solutions(new_train_params) - trainer.X_train = torch.cat([trainer.X_train, new_X], dim = 0) - assert(trainer.X_train.size(0) == trainer.param_space.n_train()) + new_X = trainer.physics.generate_solutions(new_train_params) + trainer.X_train = torch.cat([trainer.X_train, new_X], dim = 0) + assert(trainer.X_train.size(0) == trainer.param_space.n_train()) - if (new_tests > 0): - new_X = trainer.physics.generate_solutions(new_test_params) - trainer.X_test = torch.cat([trainer.X_test, new_X], dim = 0) - assert(trainer.X_test.size(0) == trainer.param_space.n_test()) + if (new_tests > 0): + new_X = trainer.physics.generate_solutions(new_test_params) + trainer.X_test = torch.cat([trainer.X_test, new_X], dim = 0) + assert(trainer.X_test.size(0) == trainer.param_space.n_test()) - # Since FOM simulations are already collected, we go to training phase directly. - next_step, result = NextStep.Train, Result.Success - return result, next_step + # Since FOM simulations are already collected, we go to training phase directly. + next_step, result = NextStep.Train, Result.Success + return result, next_step def collect_samples(trainer, config): cfg_parser = InputParser(config)