-
Notifications
You must be signed in to change notification settings - Fork 37
Data loading #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Data loading #90
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
a4e88a6
added data_gen_script and adapted it to the project's architecture
XanderBys ced344f
Updated basics tutorial with data importation
XanderBys 7929083
Included argument for filename in data_gen_script
XanderBys 40e02da
Wrote data download script
XanderBys e371b21
Included venv in gitignore
XanderBys c74402a
Fixed syntax error that stopped doc compilation in Python 3.10
XanderBys e4b06d2
Specified jupyter-book<2.0 to properly manage the dependency
XanderBys a9c1fdb
Fixed mistakes in the tutorial and made the download data button pret…
XanderBys b51cbb4
Created .python-version
XanderBys 7db79f5
Updated link in download data button to connect to the data file
XanderBys 41e8168
Updated tutorial to reflect not using a FOM
XanderBys 9f6edd2
Added support for models with external inputs
XanderBys 47d5df9
Added macro definitions to the tutorials to help rendering in VSCode
XanderBys 8b523fb
Fixed two minor typos in contributor guidelines:
XanderBys 5053363
Changed tutorial data file naming convention to be "[tutorial name]_d…
XanderBys 08069d6
Removed docs/data directory and restructured data download bash scrip…
XanderBys d49cec4
Moved data_gen_script.py
XanderBys 6a8a41e
Set default to generate all data instead of only 'basics' data
XanderBys 546e114
Changed data_gen_script.py to generate data for various initial condi…
XanderBys 5f50575
Changed wording in notebook to reflect new data treatment
XanderBys 33cce5f
Added "U" dataset to inputs data
XanderBys e8fa532
Updated inputs tutorial to load external inputs data in the first part
XanderBys c3f6359
Fixed minor bugs in data for inputs tutorial
XanderBys ef91128
Wrote help message
XanderBys 61176d1
MInor wording changes in tutorials
XanderBys 4e8e559
Fixed formatting in "Problem Statement"
XanderBys 541d029
Updated data download bash script with better directory organization
XanderBys 0a3bd3b
Minor wording changes
XanderBys 352aab2
Changed data format to include titles as metadata
XanderBys e2eeaaa
Removed mu from discretization details (unnecessary for input data)
XanderBys 2b2063b
Removed unnecessary str casting in f-string
XanderBys f1cf263
Deleted .python-version
XanderBys 519aa86
Changed data download link to direct to main OpInf repo instead of Xa…
XanderBys e909710
Updated to clone from main OpInf repo instead of Xander's fork
XanderBys 44a1a63
Minor changes to indexing and titles
XanderBys 0a90c19
Added documentation, changed docs to follow NumpyDoc, used'with' inst…
XanderBys de27e88
Renamed script to `data_generation.py`
XanderBys 7fe8bfe
Added documentation, used variables to save directories
XanderBys 98d1859
Minor updates to contributor guidelines
XanderBys 3a64706
Removed comparison to Galerkin intrusive ROM
XanderBys fbbf982
Added test data generation for inputs tutorial
XanderBys File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,3 +57,5 @@ html/ | |
| Notes/ | ||
| tests/add_endclause.py | ||
| docs/use_mathjax_shortcuts.py | ||
| *.code-workspace | ||
| .venv/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Many of the tutorials and examples in this function rely on pre-generated data. | ||
| # This script is meant to be run automatically as a GitHub Action to download | ||
| # necessary data, but it can also be run manually if you need to regenerate the data. | ||
|
|
||
| # NOTE: this script should be run from the root of the opinf directory | ||
| # Example usage: bash docs/data_download.sh | ||
|
|
||
| # remove the temp_data directory if it already exists | ||
| if [ -d "temp_data" ]; then | ||
| echo "Removing existing temp_data/ directory..." | ||
| rm -rf temp_data/ | ||
| fi | ||
|
|
||
| # Clone into the repository and download only the data branch | ||
| DATA_URL="https://github.com/operator-inference/opinf.git" | ||
| echo "Cloning into the data branch of ${DATA_URL}..." | ||
| git clone -b data --single-branch --depth=1 ${DATA_URL} temp_data/ | ||
|
|
||
| # move docs files into docs/source/api/ directory | ||
| DOC_DIR="docs/source/" | ||
| API_DIR="${DOC_DIR}api/" | ||
| echo "Moving basis_example.npy, pre_example.npy, and lstsq_example.npz into ${API_DIR} directory..." | ||
| mv temp_data/basis_example.npy ${API_DIR} | ||
| mv temp_data/lstsq_example.npz ${API_DIR} | ||
| mv temp_data/pre_example.npy ${API_DIR} | ||
|
|
||
| # move tutorial data files into docs/source/tutorials/ directory | ||
| TUTORIALS_DIR="${DOC_DIR}tutorials/" | ||
| echo "Moving basics_data.h5, inputs_data.h5, and parametric_data.h5 into ${TUTORIALS_DIR} directory..." | ||
| mv temp_data/basics_data.h5 ${TUTORIALS_DIR} | ||
| mv temp_data/inputs_data.h5 ${TUTORIALS_DIR} | ||
| mv temp_data/parametric_data.h5 ${TUTORIALS_DIR} | ||
|
|
||
| echo "Removing empty temp_data/ directory..." | ||
| rm -rf temp_data/ | ||
|
|
||
| echo "Done!" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,298 @@ | ||
| from collections.abc import Callable | ||
| import argparse | ||
| import pathlib | ||
| import h5py | ||
|
|
||
| import numpy as np | ||
| import scipy | ||
| import opinf | ||
|
|
||
|
|
||
| def generate_training_data( | ||
| n_samples: int, | ||
| n_timesteps: int, | ||
| q_0: Callable[[np.ndarray], np.ndarray], | ||
| u: Callable[[int], np.ndarray] | None = None, | ||
| ): | ||
| """Generate training data using a continuous dynamical system model. | ||
|
|
||
| Solves a parametrized advection-diffusion equation subject to external | ||
| inputs and saves the time-evolved state snapshots. Uses the Operator | ||
| Inference library to construct and evaluate a continuous model. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| n_samples : int | ||
| Number of spatial grid points (excluding boundary points). | ||
| n_timesteps : int | ||
| Number of time steps at which to evaluate the solution. | ||
| q_0 : Callable[[np.ndarray], np.ndarray] | ||
| Initial condition function. Takes an array of spatial locations | ||
| and returns initial values at those locations. | ||
| u : callable or None, optional | ||
| External input function. Takes a time value (float) and returns | ||
| the input values at that time. If None, the system has no external | ||
| inputs and defaults to a zero function. Default is None. | ||
|
|
||
| Returns | ||
| ------- | ||
| t : np.ndarray | ||
| Time points, shape (n_timesteps,). | ||
| Q : np.ndarray | ||
| Snapshots of the state solution, shape (n_samples, n_timesteps). | ||
|
|
||
| Notes | ||
| ----- | ||
| The model is based on an advection-diffusion equation with a discrete | ||
| Laplacian operator on the domain [0, 1] with homogeneous Dirichlet | ||
| boundary conditions. The solution is computed using the BDF method. | ||
| """ | ||
| external_inputs = True | ||
| if u is None: | ||
| external_inputs = False | ||
|
|
||
| def u(t): | ||
| return 0 | ||
|
|
||
| # construct the spatial and temporal domains | ||
| x = np.linspace(0, 1, n_samples + 2)[1:-1] | ||
| dx = x[1] - x[0] | ||
| t = np.linspace(0, 1, n_timesteps) | ||
|
|
||
| # construct the matrix of linear operators | ||
| diags = np.array([1, -2, 1]) / dx**2 | ||
| A = scipy.sparse.diags(diags, [-1, 0, 1], (n_samples, n_samples)) | ||
|
|
||
| # construct the matrix of external input operators | ||
| B = np.zeros_like(x) | ||
| B[0], B[-1] = 1 / dx**2, 1 / dx**2 | ||
|
|
||
| fom = opinf.models.ContinuousModel( | ||
| operators=[ | ||
| opinf.operators.LinearOperator(A), | ||
| opinf.operators.InputOperator(B), | ||
| ] | ||
| ) | ||
|
|
||
| initial_values = q_0(x) | ||
| initial_values = ( | ||
| initial_values if not external_inputs else initial_values * u(0) | ||
| ) | ||
|
|
||
| return t, fom.predict(initial_values, t, input_func=u, method="BDF") | ||
|
|
||
|
|
||
| def generate_basics_data(filepath: str = "basics_data.h5"): | ||
| """Generate training data with various initial conditions | ||
| for the basics tutorial. | ||
|
|
||
| Creates datasets with solutions to the advection-diffusion equation using | ||
| six different initial condition functions. Results are saved to an HDF5 | ||
| file with separate datasets for each initial condition. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| filepath : str, optional | ||
| Path where the generated HDF5 file will be saved. | ||
| Default is "basics_data.h5". | ||
|
|
||
| Returns | ||
| ------- | ||
| None | ||
|
|
||
| Notes | ||
| ----- | ||
| The generated file contains: | ||
| - "t": time points for all simulations | ||
| - "default": snapshots for the default initial condition q_0(x) = x(1-x) | ||
| - "Experiment 1" through "Experiment 6": snapshots for alternative | ||
| initial conditions, each with a "title" attribute for reference | ||
|
|
||
| The spatial domain is [0, 1] with 512 interior grid points, and the | ||
| temporal domain extends from t=0 to t=1 with 401 time steps. | ||
| """ | ||
| # set up basic parameters | ||
| n_samples = 512 | ||
| n_timesteps = 401 | ||
|
|
||
| # define the various initial conditions used in the tutorial | ||
| def q_0_default(x): | ||
| return x * (1 - x) | ||
|
|
||
| initial_conditions = [ | ||
| (r"$q_{0}(x) = 10 x (1 - x)$", lambda x: 10 * x * (1 - x)), | ||
| ( | ||
| r"$q_{0}(x) = 5 x^{2} (1 - x)^{2}$", | ||
| lambda x: 5 * x**2 * (1 - x) ** 2, | ||
| ), | ||
| ( | ||
| r"$q_{0}(x) = 50 x^{4} (1 - x)^{4}$", | ||
| lambda x: 50 * x**4 * (1 - x) ** 4, | ||
| ), | ||
| ( | ||
| r"$q_{0}(x) = \frac{1}{2}\sqrt{x (1 - x)}$", | ||
| lambda x: 0.5 * np.sqrt(x * (1 - x)), | ||
| ), | ||
| ( | ||
| r"$q_{0}(x) = \frac{1}{4}\sqrt[4]{x (1 - x)}$", | ||
| lambda x: 0.25 * np.sqrt(np.sqrt(x * (1 - x))), | ||
| ), | ||
| ( | ||
| r"$q_{0}(x) = \frac{1}{3}\sin(\pi x) + \frac{1}{5}\sin(5\pi x)$", | ||
| lambda x: np.sin(np.pi * x) / 3 + np.sin(5 * np.pi * x) / 5, | ||
| ), | ||
| ] | ||
|
|
||
| # initialize the file we will write the data to | ||
| with h5py.File(filepath, "w") as f: | ||
| # generate and save data for the default initial condition | ||
| # also save the data for the time dimension | ||
| t, Q_default = generate_training_data( | ||
| n_samples, n_timesteps, q_0_default | ||
| ) | ||
| f.create_dataset("t", data=t) | ||
| f.create_dataset("default", data=Q_default) | ||
|
|
||
| f.attrs["num_experiments"] = len(initial_conditions) | ||
| for idx, (title, func) in enumerate(initial_conditions): | ||
| # for each initial condition, | ||
| # generate the data for that condition | ||
| # and save it as a new dataset | ||
| _, Q = generate_training_data(n_samples, n_timesteps, func) | ||
| dset = f.create_dataset(f"Experiment {idx+1}", data=Q) | ||
| dset.attrs["title"] = title | ||
|
|
||
| print(f"Training data saved to {filepath}") | ||
|
|
||
|
|
||
| def generate_external_inputs_data(filepath: str = "inputs_data.h5"): | ||
| """Generate training data with external input functions for | ||
| the inputs tutorial. | ||
|
|
||
| Creates datasets with solutions to the advection-diffusion equation subject | ||
| to three different external input functions. Each input function has both | ||
| training and test variants to facilitate learning external input operators. | ||
| Results are saved to an HDF5 file organized in training and test groups. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| filepath : str, optional | ||
| Path where the generated HDF5 file will be saved. | ||
| Default is "inputs_data.h5". | ||
|
|
||
| Returns | ||
| ------- | ||
| None | ||
|
|
||
| Notes | ||
| ----- | ||
| The generated file contains: | ||
| - "t": time points for all simulations | ||
| - "Q": snapshots for the default external input function | ||
| - "U": the default external input values | ||
| - "train" group: contains Q_0, U_0, Q_1, U_1, Q_2, U_2 datasets | ||
| - "test" group: contains Q_0, U_0, Q_1, U_1, Q_2, U_2 datasets | ||
|
|
||
| The spatial domain is [0, 1] with 1023 interior grid points, and the | ||
| temporal domain extends from t=0 to t=1 with 1001 time steps. The initial | ||
| condition depends on an exponential-based function with | ||
| parameter alpha=100. | ||
| """ | ||
| n_samples = 1023 | ||
| n_timesteps = 1001 | ||
|
|
||
| alpha = 100 | ||
|
|
||
| # the part of the initial condition independent of u(t) | ||
| def q_0(x): | ||
| return np.exp(alpha * (x - 1)) + np.exp(-alpha * x) - np.exp(-alpha) | ||
|
|
||
| # the define the external inputs functions | ||
| def u(t): | ||
| return np.ones_like(t) + np.sin(4 * np.pi * t) / 4 | ||
|
|
||
| def u_test(t): | ||
| return 1 + t * (1 - t) | ||
|
|
||
| train_inputs = [ | ||
| lambda t: np.exp(-t), | ||
| lambda t: 1 + t**2 / 2, | ||
| lambda t: 1 - np.sin(np.pi * t) / 2, | ||
| ] | ||
| test_inputs = [ | ||
| lambda t: 1 - np.sin(3 * np.pi * t) / 3, | ||
| lambda t: 1 + 25 * (t * (t - 1)) ** 3, | ||
| lambda t: 1 + np.exp(-2 * t) * np.sin(np.pi * t), | ||
| ] | ||
|
|
||
| # initialize the h5 file to write to | ||
| with h5py.File(filepath, "w") as f: | ||
| # generate training data for the beginning of the tutorial | ||
| t, Q = generate_training_data(n_samples, n_timesteps, q_0, u) | ||
| U = u(t) | ||
|
|
||
| _, Q_test = generate_training_data(n_samples, n_timesteps, q_0, u_test) | ||
| U_test = u_test(t) | ||
|
|
||
| f.create_dataset("t", data=t) | ||
| f.create_dataset("Q", data=Q) | ||
| f.create_dataset("U", data=U) | ||
| f.create_dataset("Q_test", data=Q_test) | ||
| f.create_dataset("U_test", data=U_test) | ||
|
|
||
| train_grp = f.create_group("train") | ||
| test_grp = f.create_group("test") | ||
|
|
||
| train_grp.attrs["num_input_functions"] = len(train_inputs) | ||
| test_grp.attrs["num_input_functions"] = len(test_inputs) | ||
|
|
||
| # for each input function, generate data for the inputs and snapshots | ||
| # then, save that data to a new dataset in the file | ||
| for idx, [train_input, test_input] in enumerate( | ||
| zip(train_inputs, test_inputs) | ||
| ): | ||
| _, Q_train = generate_training_data( | ||
| n_samples, n_timesteps, q_0, train_input | ||
| ) | ||
| U_train = train_input(t) | ||
| _, Q_test = generate_training_data( | ||
| n_samples, n_timesteps, q_0, test_input | ||
| ) | ||
| U_test = test_input(t) | ||
|
|
||
| train_grp.create_dataset(f"Q_{idx}", data=Q_train) | ||
| train_grp.create_dataset(f"U_{idx}", data=U_train) | ||
| test_grp.create_dataset(f"Q_{idx}", data=Q_test) | ||
| test_grp.create_dataset(f"U_{idx}", data=U_test) | ||
|
|
||
| print(f"Training data saved to {filepath}") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser( | ||
| description="Generate training data for Operator Inference tutorials." | ||
| ) | ||
| parser.add_argument( | ||
| "dataset", | ||
| nargs="?", | ||
| default="all", | ||
| choices=["basics", "inputs", "parametric", "all"], | ||
| help="Dataset to generate (default: all)", | ||
| ) | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| BASE_DIR = pathlib.Path(__file__).resolve().parent | ||
|
|
||
| if args.dataset == "basics" or args.dataset == "all": | ||
| generate_basics_data( | ||
| str(BASE_DIR / "source" / "tutorials" / "basics_data.h5") | ||
| ) | ||
| if args.dataset == "inputs" or args.dataset == "all": | ||
| generate_external_inputs_data( | ||
| str(BASE_DIR / "source" / "tutorials" / "inputs_data.h5") | ||
| ) | ||
| if args.dataset == "parametric" or args.dataset == "all": | ||
| raise NotImplementedError( | ||
| "The parametric dataset has not been implemented yet." | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.