diff --git a/LICENSE.rst b/LICENSE.rst index b2197857..6417a961 100644 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -3,7 +3,7 @@ License The MIT License (MIT) -Copyright (c) 2016-2018 by EZyRB contributors. +Copyright (c) 2016-current by EZyRB contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/source/_tutorials/tutorial-1/output_20_0.png b/docs/source/_tutorials/tutorial-1/output_20_0.png new file mode 100644 index 00000000..4f32b62e Binary files /dev/null and b/docs/source/_tutorials/tutorial-1/output_20_0.png differ diff --git a/docs/source/_tutorials/tutorial-1/output_8_1.png b/docs/source/_tutorials/tutorial-1/output_8_1.png new file mode 100644 index 00000000..a6c33820 Binary files /dev/null and b/docs/source/_tutorials/tutorial-1/output_8_1.png differ diff --git a/docs/source/_tutorials/tutorial-1/tutorial-1.rst b/docs/source/_tutorials/tutorial-1/tutorial-1.rst new file mode 100644 index 00000000..059c5c0f --- /dev/null +++ b/docs/source/_tutorials/tutorial-1/tutorial-1.rst @@ -0,0 +1,306 @@ +Build and query a simple reduced order model +============================================ + +In this tutorial we will show the typical workflow for the construcion +of the Reduced Order Model based only on the outputs of the higher-order +model. In detail, we consider here a POD-RBF framework (Proper +Orthogonal Decomposition for dimensionality reduction and Radial Basis +Function for manifold approximation), but the tutorial can be easily +extended to other methods thanks to the modularity nature of **EZyRB**. + +We consider a parametric steady heat conduction problem in a +two-dimensional domain :math:`\Omega`. While in this tutorial we are +going to focus on the data-driven approach, the same problem can be +tackled in an intrusive manner (with the Reduced Basis method) using the +`RBniCS `__, as demonstrated in this +`RBniCS +tutorial `__. +This book is therefore exhaustively discussed in the book *Certified +reduced basis methods for parametrized partial differential equations*, +J.S. Hesthaven, G. Rozza, B. Stamm, 2016, Springer. An additional +description is available also at +`https://rbnics.gitlab.io/RBniCS-jupyter/tutorial_thermal_block.html <>`__. + +Since the good documentation already available for this problem and +since the data-driven methodologies we will take into consideration, we +just summarize the model to allow a better understanding. + +The domain is depicted below: + +where: - the first parameter :math:`\mu_o` controls the conductivity in +the circular subdomain :math:`\Omega_0`; - the second parameter +:math:`\mu_1` controls the flux over :math:`\Gamma_\text{base}`. + +Initial setting +~~~~~~~~~~~~~~~ + +First of all import the required packages: we need the standard Numpy +and Matplotlib, and some classes from EZyRB. In the EZyRB framework, we +need three main ingredients to construct a reduced order model: - an +initial database where the snapshots are stored; - a reduction method to +reduce the dimensionality of the system, in this tutorial we will use +the proper orthogonal decomposition (POD) method; - an approximation +method to extrapolate the parametric solution for new parameters, in +this tutorial we will use a radial basis function (RBF) interpolation. + +.. code:: ipython3 + + !pip install ezyrb datasets + + +.. parsed-literal:: + + Requirement already satisfied: ezyrb in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (1.3.2) + Requirement already satisfied: datasets in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (4.4.2) + Requirement already satisfied: future in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.0.0) + Requirement already satisfied: numpy in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (2.2.0) + Requirement already satisfied: scipy in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.14.1) + Requirement already satisfied: matplotlib in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (3.10.0) + Requirement already satisfied: scikit-learn in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.8.0) + Requirement already satisfied: torch in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (2.5.1) + Requirement already satisfied: filelock in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.16.1) + Requirement already satisfied: pyarrow>=21.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (22.0.0) + Requirement already satisfied: dill<0.4.1,>=0.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.4.0) + Requirement already satisfied: pandas in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.2.3) + Requirement already satisfied: requests>=2.32.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.32.3) + Requirement already satisfied: httpx<1.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.28.1) + Requirement already satisfied: tqdm>=4.66.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (4.67.1) + Requirement already satisfied: xxhash in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.6.0) + Requirement already satisfied: multiprocess<0.70.19 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.70.18) + Requirement already satisfied: fsspec<=2025.10.0,>=2023.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2025.10.0) + Requirement already satisfied: huggingface-hub<2.0,>=0.25.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (1.2.3) + Requirement already satisfied: packaging in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (24.2) + Requirement already satisfied: pyyaml>=5.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (6.0.2) + Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (3.11.10) + Requirement already satisfied: anyio in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (4.8.0) + Requirement already satisfied: certifi in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (2024.12.14) + Requirement already satisfied: httpcore==1.* in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (1.0.7) + Requirement already satisfied: idna in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (3.10) + Requirement already satisfied: h11<0.15,>=0.13 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpcore==1.*->httpx<1.0.0->datasets) (0.14.0) + Requirement already satisfied: hf-xet<2.0.0,>=1.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.2.0) + Requirement already satisfied: shellingham in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.5.4) + Requirement already satisfied: typer-slim in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (0.20.1) + Requirement already satisfied: typing-extensions>=3.7.4.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (4.12.2) + Requirement already satisfied: charset-normalizer<4,>=2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (3.4.0) + Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (2.2.3) + Requirement already satisfied: contourpy>=1.0.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.3.1) + Requirement already satisfied: cycler>=0.10 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (0.12.1) + Requirement already satisfied: fonttools>=4.22.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (4.55.3) + Requirement already satisfied: kiwisolver>=1.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.4.7) + Requirement already satisfied: pillow>=8 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (11.0.0) + Requirement already satisfied: pyparsing>=2.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (3.2.0) + Requirement already satisfied: python-dateutil>=2.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (2.9.0.post0) + Requirement already satisfied: pytz>=2020.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1) + Requirement already satisfied: tzdata>=2022.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1) + Requirement already satisfied: joblib>=1.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (1.5.3) + Requirement already satisfied: threadpoolctl>=3.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (3.6.0) + Requirement already satisfied: networkx in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.4.2) + Requirement already satisfied: jinja2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.1.4) + Requirement already satisfied: setuptools in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (75.6.0) + Requirement already satisfied: sympy==1.13.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (1.13.1) + Requirement already satisfied: mpmath<1.4,>=1.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from sympy==1.13.1->torch->ezyrb) (1.3.0) + Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2.4.4) + Requirement already satisfied: aiosignal>=1.1.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.3.2) + Requirement already satisfied: attrs>=17.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (24.3.0) + Requirement already satisfied: frozenlist>=1.1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.5.0) + Requirement already satisfied: multidict<7.0,>=4.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (6.1.0) + Requirement already satisfied: propcache>=0.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (0.2.1) + Requirement already satisfied: yarl<2.0,>=1.17.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.18.3) + Requirement already satisfied: six>=1.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib->ezyrb) (1.17.0) + Requirement already satisfied: sniffio>=1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from anyio->httpx<1.0.0->datasets) (1.3.1) + Requirement already satisfied: MarkupSafe>=2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from jinja2->torch->ezyrb) (3.0.2) + Requirement already satisfied: click>=8.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from typer-slim->huggingface-hub<2.0,>=0.25.0->datasets) (8.3.1) + + [notice] A new release of pip is available: 24.3.1 -> 25.3 + [notice] To update, run: pip install --upgrade pip + + +.. code:: ipython3 + + import numpy as np + import matplotlib.tri as mtri + import matplotlib.pyplot as plt + from ezyrb import POD, RBF, Database + from ezyrb import ReducedOrderModel as ROM + %matplotlib inline + +Offline phase +------------- + +In the *offline* phase, we need some samples of the parametric +high-fidelity model. In this case, we extract 8 snapshots from the +numerical model implemented in **FEniCS**, and we import them and the +related parameters. + +.. code:: ipython3 + + from datasets import load_dataset + data_path = "kshitij-pandey/termal_dataset" + snapshots_hf = load_dataset(data_path, "snapshots", split="train") + param_hf = load_dataset(data_path, "params", split="train") + triangles_hf = load_dataset(data_path, "triangles", split="train") + coords_hf = load_dataset(data_path, "coords", split="train") + + + # convert the dict files into numpy + + import pandas as pd + + def hf_to_numpy(ds): + return ds.to_pandas().to_numpy() + + + snapshots = hf_to_numpy(snapshots_hf) + param = hf_to_numpy(param_hf) + triangles = hf_to_numpy(triangles_hf) + coords = hf_to_numpy(coords_hf) + print(snapshots.shape, param.shape) + + +.. parsed-literal:: + + (8, 304) (8, 2) + + +Moreover, to visualize the solution (both the higher-order one and the +reduced one), we import also the mesh information to be able to create +the triangulation. We underline this additional step is related only to +plotting purpose, and not mandatory for the reduced space generation. + +.. code:: ipython3 + + x, y = coords + from matplotlib.tri import Triangulation + triang = Triangulation(x, y, triangles) + triang = triang + +For the sake of clarity the snapshots are plotted. + +.. code:: ipython3 + + fig, ax = plt.subplots(nrows=2, ncols=4, figsize=(16, 6), sharey=True, sharex=True) + ax = ax.flatten() + for i in range(8): + ax[i].triplot(triang, 'b-', lw=0.1) + cm = ax[i].tripcolor(triang, snapshots[i]) + fig.colorbar(cm, ax=ax[i]) + ax[i].set_title('($\mu_0={:5.2f}, \mu_1={:5.2f})$'.format(*param[i])) + + +.. image:: output_8_1.png + + +First of all, we create a ``Database`` object from the parameters and +the snapshots. + +.. code:: ipython3 + + db = Database(param, snapshots) + +Then we need a reduction object. In this case we use the proper +orthogonal decomposition so we create a ``POD`` object. We use here all +the default parameters, but for the complete list of available arguments +we refer to original documentation of +`POD `__ class. + +.. code:: ipython3 + + pod = POD('svd') + +Then we instantiate the ``RBF`` class for interpolating the solution +manifold. Also in this case, +`RBF `__ documentation is the +perfect starting point to explore such class. + +.. code:: ipython3 + + rbf = RBF() + +Few lines of code and our reduced model is created! To complete +everything, we create the ``ReducedOrderModel`` (aliased to ``ROM`` in +this tutorial) object by passing the already created objects. For +clarity, we puntualize that we need to pass the **instances** and not +the classes. Simply changing such line (with different objects) allows +to test different frameworks in a very modular way. The ``fit()`` +function computes the reduced model, meaning that the original snapshots +in the database are projected onto the POD space and the RBF +interpolator is created. + +.. code:: ipython3 + + rom = ROM(db, pod, rbf) + rom.fit(); + +Online phase +------------ + +In the *online* phase we can query our model in order to predict the +solution for a new parameter :math:`\mu_\text{new}` that is not in the +training set. We just need to pass the new parameters as input of the +``predict()`` function. + +.. code:: ipython3 + + new_mu = [8, 1] + pred_sol = rom.predict(new_mu) + +We can so plot the predicted solution for a fixed parameter… + +.. code:: ipython3 + + plt.figure(figsize=(7, 5)) + plt.triplot(triang, 'b-', lw=0.1) + plt.tripcolor(triang, *pred_sol) + plt.colorbar(); + + + +.. image:: output_20_0.png + + +Error Approximation & Improvement +--------------------------------- + +At the moment, we used a database which is composed by 8 files. we would +have an idea of the approximation accuracy we are able to reach with +these high-fidelity solutions. Using the *leave-one-out* strategy, an +error is computed for each parametric point in our database and these +values are returned as array. + +.. code:: ipython3 + + for pt, error in zip(rom.database.parameters_matrix, rom.loo_error()): + print(pt, error) + + +.. parsed-literal:: + + [ 0.5 -0.2] 0.3830555986412087 + [8.6 0.1] 0.5972596749801533 + [5.3 0.8] 0.8082744257222089 + [9.4 0.1] 0.4105803285232253 + [ 7.3 -0.8] 0.5505863544054451 + [0.2 0.8] 0.07567485849711765 + [ 3.5 -0.5] 0.66949247698686 + [0.3 0.6] 0.06478619218562698 + + +Moreover, we can use the information about the errors to locate the +parametric points where we have to compute the new high-fidelity +solutions and add these to the database in order to optimally improve +the accuracy. + +.. code:: ipython3 + + rom.optimal_mu() + + + + +.. parsed-literal:: + + array([[ 5.2487694 , -0.06339911]]) + + + +These function can be used to achieve the wanted (estimated) accuracy. diff --git a/docs/source/_tutorials/tutorial-2/output_12_0.png b/docs/source/_tutorials/tutorial-2/output_12_0.png new file mode 100644 index 00000000..26da21e6 Binary files /dev/null and b/docs/source/_tutorials/tutorial-2/output_12_0.png differ diff --git a/docs/source/_tutorials/tutorial-2/output_8_0.png b/docs/source/_tutorials/tutorial-2/output_8_0.png new file mode 100644 index 00000000..1a1d6082 Binary files /dev/null and b/docs/source/_tutorials/tutorial-2/output_8_0.png differ diff --git a/docs/source/_tutorials/tutorial-2/tutorial-2.rst b/docs/source/_tutorials/tutorial-2/tutorial-2.rst new file mode 100644 index 00000000..1a4f238c --- /dev/null +++ b/docs/source/_tutorials/tutorial-2/tutorial-2.rst @@ -0,0 +1,491 @@ +Test several frameworks at once +================================ + +In this tutorial, we will explain step by step how to use the **EZyRB** +library to test different techniques for building the reduced order +model. We will compare different methods of dimensionality reduction, +interpolation and accuracy assessment. + +We consider here a computational fluid dynamics problem described by the +(incompressible) Navier Stokes equations. We will be using the **Navier +Stokes Dataset** that contains the output data from a full order flow +simulation and can be found on **Hugging Face Datasets** + +The package can be installed using ``python -m pip install datasets``, +but for a detailed description about installation and usage we refer to +original `Github page `__. + +First of all, we just import the package and instantiate the dataset +object. + +.. code:: ipython3 + + !pip install datasets ezyrb + + +.. parsed-literal:: + + Requirement already satisfied: datasets in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (4.4.2) + Requirement already satisfied: ezyrb in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (1.3.2) + Requirement already satisfied: filelock in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.16.1) + Requirement already satisfied: numpy>=1.17 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.2.0) + Requirement already satisfied: pyarrow>=21.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (22.0.0) + Requirement already satisfied: dill<0.4.1,>=0.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.4.0) + Requirement already satisfied: pandas in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.2.3) + Requirement already satisfied: requests>=2.32.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.32.3) + Requirement already satisfied: httpx<1.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.28.1) + Requirement already satisfied: tqdm>=4.66.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (4.67.1) + Requirement already satisfied: xxhash in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.6.0) + Requirement already satisfied: multiprocess<0.70.19 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.70.18) + Requirement already satisfied: fsspec<=2025.10.0,>=2023.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2025.10.0) + Requirement already satisfied: huggingface-hub<2.0,>=0.25.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (1.2.3) + Requirement already satisfied: packaging in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (24.2) + Requirement already satisfied: pyyaml>=5.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (6.0.2) + Requirement already satisfied: future in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.0.0) + Requirement already satisfied: scipy in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.14.1) + Requirement already satisfied: matplotlib in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (3.10.0) + Requirement already satisfied: scikit-learn in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.8.0) + Requirement already satisfied: torch in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (2.5.1) + Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (3.11.10) + Requirement already satisfied: anyio in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (4.8.0) + Requirement already satisfied: certifi in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (2024.12.14) + Requirement already satisfied: httpcore==1.* in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (1.0.7) + Requirement already satisfied: idna in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (3.10) + Requirement already satisfied: h11<0.15,>=0.13 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpcore==1.*->httpx<1.0.0->datasets) (0.14.0) + Requirement already satisfied: hf-xet<2.0.0,>=1.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.2.0) + Requirement already satisfied: shellingham in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.5.4) + Requirement already satisfied: typer-slim in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (0.20.1) + Requirement already satisfied: typing-extensions>=3.7.4.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (4.12.2) + Requirement already satisfied: charset-normalizer<4,>=2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (3.4.0) + Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (2.2.3) + Requirement already satisfied: contourpy>=1.0.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.3.1) + Requirement already satisfied: cycler>=0.10 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (0.12.1) + Requirement already satisfied: fonttools>=4.22.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (4.55.3) + Requirement already satisfied: kiwisolver>=1.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.4.7) + Requirement already satisfied: pillow>=8 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (11.0.0) + Requirement already satisfied: pyparsing>=2.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (3.2.0) + Requirement already satisfied: python-dateutil>=2.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (2.9.0.post0) + Requirement already satisfied: pytz>=2020.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1) + Requirement already satisfied: tzdata>=2022.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1) + Requirement already satisfied: joblib>=1.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (1.5.3) + Requirement already satisfied: threadpoolctl>=3.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (3.6.0) + Requirement already satisfied: networkx in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.4.2) + Requirement already satisfied: jinja2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.1.4) + Requirement already satisfied: setuptools in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (75.6.0) + Requirement already satisfied: sympy==1.13.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (1.13.1) + Requirement already satisfied: mpmath<1.4,>=1.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from sympy==1.13.1->torch->ezyrb) (1.3.0) + Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2.4.4) + Requirement already satisfied: aiosignal>=1.1.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.3.2) + Requirement already satisfied: attrs>=17.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (24.3.0) + Requirement already satisfied: frozenlist>=1.1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.5.0) + Requirement already satisfied: multidict<7.0,>=4.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (6.1.0) + Requirement already satisfied: propcache>=0.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (0.2.1) + Requirement already satisfied: yarl<2.0,>=1.17.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.18.3) + Requirement already satisfied: six>=1.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib->ezyrb) (1.17.0) + Requirement already satisfied: sniffio>=1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from anyio->httpx<1.0.0->datasets) (1.3.1) + Requirement already satisfied: MarkupSafe>=2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from jinja2->torch->ezyrb) (3.0.2) + Requirement already satisfied: click>=8.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from typer-slim->huggingface-hub<2.0,>=0.25.0->datasets) (8.3.1) + + [notice] A new release of pip is available: 24.3.1 -> 25.3 + [notice] To update, run: pip install --upgrade pip + + +.. code:: ipython3 + + from datasets import load_dataset + data_path = "kshitij-pandey/navier_stokes_datasets" + snapshots_hf = load_dataset(data_path, "snapshots_split", split="train") + param_hf = load_dataset(data_path, "params", split="train") + triangles_hf = load_dataset(data_path, "triangles", split="train") + coords_hf = load_dataset(data_path, "coords", split="train") + import numpy as np + snapshots = {name: np.array(snapshots_hf[name]) for name in ['vx', 'vy', 'mag(v)', 'p']} + # convert the dict files into numpy + + import pandas as pd + + def hf_to_numpy(ds): + return ds.to_pandas().to_numpy() + + + params = hf_to_numpy(param_hf) + triangles = hf_to_numpy(triangles_hf) + coords = hf_to_numpy(coords_hf) + + +The ``NavierStokesDataset()`` class contains the attribute: - +``snapshots``: the matrices of snapshots stored by row (one matrix for +any output field) - ``params``: the matrix of corresponding parameters - +``pts_coordinates``: the coordinates of all nodes of the discretize +space - ``faces``: the actual topology of the discretize space - +``triang``: the triangulation, useful especially for rendering purposes. + +In the details, ``snapshots`` is a dictionary with the following output +of interest: - **vx:** velocity in the X-direction. - **vy:** velocity +in the Y-direction. - **mag(v):** velocity magnitude. - **p:** pressure +value. + +In total, the dataset contains 500 parametric configurations in a space +of 1639 degrees of freedom. In this case, we have just one parameter, +which is the velocity (along :math:`x`) we impose at the inlet. + +.. code:: ipython3 + + for name in ['vx', 'vy', 'p', 'mag(v)']: + print('Shape of {:7s} snapshots matrix: {}'.format(name, snapshots[name].shape)) + + print('Shape of parameters matrix: {}'.format(params.shape)) + + + +.. parsed-literal:: + + Shape of vx snapshots matrix: (500, 1639) + Shape of vy snapshots matrix: (500, 1639) + Shape of p snapshots matrix: (500, 1639) + Shape of mag(v) snapshots matrix: (500, 1639) + Shape of parameters matrix: (500, 1) + + +Initial setting +~~~~~~~~~~~~~~~ + +First of all, we import the required packages. + +From ``EZyRB`` we need: 1. The ``ROM`` class, which performs the model +order reduction process. 2. A module such as ``Database``, where the +matrices of snapshots and parameters are stored. 3. A dimensionality +reduction method such as Proper Orthogonal Decomposition ``POD`` or +Auto-Encoder network ``AE``. 4. An interpolation method to obtain an +approximation for the parametric solution for a new set of parameters +such as the Radial Basis Function ``RBF``, Gaussian Process Regression +``GPR``, K-Neighbors Regressor ``KNeighborsRegressor``, Radius Neighbors +Regressor ``RadiusNeighborsRegressor`` or Multidimensional Linear +Interpolator ``Linear``. + +We also need to import: \* ``numpy:`` to handle arrays and matrices we +will be working with. \* ``torch:`` to enable the usage of Neural +Networks \* ``matplotlib.pyplot:`` to handle the plotting environment. +\* ``matplotlib.tri:`` for plotting of the triangular grid. + +.. code:: ipython3 + + # Database module + from ezyrb import Database + + # Dimensionality reduction methods + from ezyrb import POD, AE + + # Approximation/interpolation methods + from ezyrb import RBF, GPR, KNeighborsRegressor, RadiusNeighborsRegressor, Linear, ANN + + # Model order reduction calss + from ezyrb import ReducedOrderModel as ROM + import torch + import torch.nn as nn + + import matplotlib.tri as mtri + import matplotlib.pyplot as plt + + import warnings + warnings.filterwarnings("ignore", message="Ill-conditioned matrix ") + %matplotlib inline + +Before starting with the reduced order model, we visualize some of the +snapshots in our dataset. + +.. code:: ipython3 + + x, y = coords + from matplotlib.tri import Triangulation + triang = Triangulation(x, y, triangles) + fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(16, 8), sharey=True, sharex=True) + ax = ax.flatten() + for i in range(9): + ax[i].tricontourf(triang, snapshots['vx'][i], levels=16) + ax[i].set_title('Original snapshot at inlet velocity = {}'.format(*params[i].round(2))) + + + +.. image:: output_8_0.png + + +In this step, we perform the model order reduction to obtain a reduced +space from the full order space. We refer to `Tutorial +1 `__ +for the description of the basic workflow, here we just quickly describe +the steps implemented in the next cell. + +We start by passing the matrices of the parameters and snapshots to the +``Database()`` class. It must be said that at this time we create the +ROM for the ``vx`` field. We also instantiate the ``POD`` and ``RBF`` +object to have a benchmark ROM. + +.. code:: ipython3 + + db = Database(params, snapshots['vx']) + rom = ROM(db, POD(), RBF()) + rom.fit(); + +Three lines for a data-driven reduced order model, not bad! + +Just to have a visual check that everything is going well, we plot the +approximation for new parameters in the range :math:`[1, 80]`. + +.. code:: ipython3 + + new_params = np.random.uniform(size=(2))*79.+1. + + fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 3)) + for i, param in enumerate(new_params): + ax[i].tricontourf(triang, *rom.predict([param])) + ax[i].set_title('Predicted snapshots at inlet velocity = {}'.format(param)) + + + +.. image:: output_12_0.png + + +We are now calculating the approximation error to see how close is our +reduced solution to the full-order solution/simulation using the +**k-fold Cross-Validation** strategy by passing the number of splits to +the ``ReducedOrderModel.kfold_cv_error(n_splits)`` method, which +operates as follows: + +1. Split the dataset (parameters/snapshots) into :math:`k`-number of + groups/folds. +2. Use :math:`k-1` groups to calculate the reduced space and leave one + group for testing. +3. Use the approximation/interpolation method to predict each snapshot + in the testing group. +4. Calculate the error for each snapshot in the testing group by taking + the difference between the predicted and the original snapshot. +5. Average the errors for predicting snapshots of the testing + group/fold. +6. Repeat this procedure using different groups for testing and the + remaining :math:`k-1` groups to calculate the reduced space. +7. In the end, we will have :math:`k`-number errors for predicting each + group/fold that we can average them to have one value for the error. + +.. code:: ipython3 + + errors = rom.kfold_cv_error(n_splits = 5) + print('Average error for each fold:') + for e in errors: + print(' ',e) + print('\nAverage error = {}'.format(errors.mean())) + + +.. parsed-literal:: + + Average error for each fold: + 4.945136635258633e-07 + 9.860761253488605e-07 + 3.894778057436833e-06 + 5.303642035538002e-06 + 1.2984622088905908e-07 + + Average error = 2.1617712205477237e-06 + + +Another strategy for calculating the approximation error is called +**leave-one-out** by using the ``ReducedOrderModel.loo_error()`` method, +which is similar to setting the number of folds equal to the number of +snapshots (eg. in this case setting ``n_splits`` = 500) and it operates +as follows: 1. Combine all the snapshots except one. 2. Calculate the +reduced space. 3. Use the approximation/interpolation method to predict +the removed snapshot. 4. Calculate the error by taking the difference +between the predicted snapshot and the original removed one. 5. The +error vector is obtained by repeating this procedure for each snapshot +in the database. + +It is worth mentioning that it consumes more time because we have 500 +snapshots and the algorithm will perform space order reduction and +calculate the approximation error 500 times. For this reason, we +commented the next line of code, in order to limit the computational +effort needed to run this tutorial. Uncomment it only if you are a +really brave person! + +.. code:: ipython3 + + # errors = rom.loo_error() + +Comparison between different methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One of the advantages of the data-driven reduced order modeling is the +modular nature of the method. Practically speaking, we need - a method +for reducing the dimensionality of input snapshots; - a method for +approximate the solution manifold; + +allowing in principle a large variety of combinations. + +The list of implemented **reduction methods** in EZyRB contains: - +``POD``: *proper orthogonal decomposition* - ``AE``: *autoencoder* + +while the list of implemented **approximation methods** contains: - +``RBF``: *radial basis function interpolation* - ``GPR``: *gaussian +process regression* - ``KNeighborsRegressor``: *k-neighbors regression* +- ``RadiusNeighborsRegressor``: *radius neighbors regression* - +``Linear``: *multidimensional linear interpolation* + +Moreover, new state-of-the-art methods will arrive, so we invite you to +read the `documentation `__ for the +complete list of all the possibilities! + +In the next cell, we create two dictionaries with the objects, such that +we can easily test everything with simple ``for`` cycles. **WARNING** +since several methods require the solution of an optimization problem +(eg. GPR, ANN, AE), the cell may require some minutes to be run. + +.. code:: ipython3 + + reductions = { + 'POD': POD('svd',rank=10), + 'AE': AE([200, 100, 10], [10, 100, 200], nn.Tanh(), nn.Tanh(), 10, frequency_print=-10), + } + + approximations = { + # 'Linear': Linear(), + 'RBF': RBF(), + 'GPR': GPR(), + 'KNeighbors': KNeighborsRegressor(), + 'RadiusNeighbors': RadiusNeighborsRegressor(), + 'ANN': ANN([20, 20], nn.Tanh(), 10, frequency_print=-10), + } + + s = '\n\n{:10s}'.format('') + for name in approximations: + s += ' {:>15s}'.format(name) + s += '\n' + + for redname, redclass in reductions.items(): + row = '{:10s}'.format(redname) + for approxname, approxclass in approximations.items(): + rom = ROM(db, redclass, approxclass) + print(f"Processing {redname}-{approxname}") + rom.fit() + row += ' {:15e}'.format(rom.kfold_cv_error(n_splits=5).mean()) + + s += f'{row}\n' + + print(s) + + +.. parsed-literal:: + + Processing POD-RBF + Processing POD-GPR + Processing POD-KNeighbors + Processing POD-RadiusNeighbors + Processing POD-ANN + [epoch 1] 9.546327e+04 + [epoch 10] 9.538811e+04 + [epoch 1] 9.522560e+04 + [epoch 10] 9.515077e+04 + [epoch 1] 9.766096e+04 + [epoch 10] 9.758415e+04 + [epoch 1] 9.519630e+04 + [epoch 10] 9.512106e+04 + [epoch 1] 9.567339e+04 + [epoch 10] 9.559758e+04 + [epoch 1] 9.314678e+04 + [epoch 10] 9.307255e+04 + Processing AE-RBF + [epoch 1] 5.823453e+02 + [epoch 10] 5.556604e+02 + [epoch 1] 5.812169e+02 + [epoch 10] 8.230733e+01 + [epoch 1] 5.957941e+02 + [epoch 10] 9.019125e+01 + [epoch 1] 5.806075e+02 + [epoch 10] 6.687416e+01 + [epoch 1] 5.835210e+02 + [epoch 10] 7.294649e+01 + [epoch 1] 5.700542e+02 + [epoch 10] 7.343178e+01 + Processing AE-GPR + [epoch 1] 5.834352e+02 + [epoch 10] 7.699603e+01 + [epoch 1] 5.847290e+02 + [epoch 10] 1.470968e+02 + [epoch 1] 5.948226e+02 + [epoch 10] 7.184375e+01 + [epoch 1] 5.802390e+02 + [epoch 10] 7.155777e+01 + [epoch 1] 5.853676e+02 + [epoch 10] 1.150479e+02 + [epoch 1] 5.690804e+02 + [epoch 10] 6.931157e+01 + Processing AE-KNeighbors + [epoch 1] 5.819167e+02 + [epoch 10] 6.814513e+01 + [epoch 1] 5.820450e+02 + [epoch 10] 9.533990e+01 + [epoch 1] 5.980317e+02 + [epoch 10] 1.218049e+02 + [epoch 1] 5.849615e+02 + [epoch 10] 9.724957e+01 + [epoch 1] 5.848712e+02 + [epoch 10] 1.151645e+02 + [epoch 1] 5.692266e+02 + [epoch 10] 7.778555e+01 + Processing AE-RadiusNeighbors + [epoch 1] 5.845089e+02 + [epoch 10] 1.057290e+02 + [epoch 1] 5.836143e+02 + [epoch 10] 8.220594e+01 + [epoch 1] 5.969666e+02 + [epoch 10] 8.701730e+01 + [epoch 1] 5.823361e+02 + [epoch 10] 9.751357e+01 + [epoch 1] 5.850589e+02 + [epoch 10] 9.528002e+01 + [epoch 1] 5.675153e+02 + [epoch 10] 6.384907e+01 + Processing AE-ANN + [epoch 1] 5.835621e+02 + [epoch 10] 1.136382e+02 + [epoch 1] 4.710647e+03 + [epoch 10] 4.693913e+03 + [epoch 1] 5.837049e+02 + [epoch 10] 1.006396e+02 + [epoch 1] 6.297388e+03 + [epoch 10] 6.277451e+03 + [epoch 1] 6.003340e+02 + [epoch 10] 9.461213e+01 + [epoch 1] 3.808644e+03 + [epoch 10] 3.790863e+03 + [epoch 1] 5.810663e+02 + [epoch 10] 8.357424e+01 + [epoch 1] 5.692258e+03 + [epoch 10] 5.670917e+03 + [epoch 1] 5.863652e+02 + [epoch 10] 1.553782e+02 + [epoch 1] 4.325479e+03 + [epoch 10] 4.307963e+03 + [epoch 1] 5.707682e+02 + [epoch 10] 9.925204e+01 + [epoch 1] 5.734101e+03 + [epoch 10] 5.716063e+03 + + + RBF GPR KNeighbors RadiusNeighbors ANN + POD 1.204641e-05 2.970147e-05 8.032581e-03 1.091257e-02 9.975237e-01 + AE 3.301131e-01 3.514848e-01 3.619394e-01 3.477732e-01 9.939129e-01 + + + +In a very compact way, we tested several frameworks - like POD-RBF, +POD-GPR, POD-NN -, showing the accuracy reached by any of them. + +We can also note that the frameworks that involve neural networks +(``AE`` and ``ANN``) show a very poor precision. This is due to the fact +of the limited number of epochs we impose in the learning procedure. You +can try to increase the number of epochs as we shown in the next cell in +order to obtain better results, at the cost of a longer training phase. + +.. code:: ipython3 + + reductions['AE'] = AE([100, 10], [10, 100], nn.ReLU(), nn.ReLU(), 30000) + approximations['ANN'] = ANN([50, 10], nn.ReLU(), 30000) diff --git a/docs/source/_tutorials/tutorial-3/output_10_0.png b/docs/source/_tutorials/tutorial-3/output_10_0.png new file mode 100644 index 00000000..29c0b66f Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_10_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/output_12_0.png b/docs/source/_tutorials/tutorial-3/output_12_0.png new file mode 100644 index 00000000..55524107 Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_12_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/output_13_0.png b/docs/source/_tutorials/tutorial-3/output_13_0.png new file mode 100644 index 00000000..91cde0ab Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_13_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/output_14_0.png b/docs/source/_tutorials/tutorial-3/output_14_0.png new file mode 100644 index 00000000..415827b5 Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_14_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/output_16_0.png b/docs/source/_tutorials/tutorial-3/output_16_0.png new file mode 100644 index 00000000..80938e41 Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_16_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/output_6_0.png b/docs/source/_tutorials/tutorial-3/output_6_0.png new file mode 100644 index 00000000..b5bdb305 Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_6_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/output_7_0.png b/docs/source/_tutorials/tutorial-3/output_7_0.png new file mode 100644 index 00000000..37a7e4c4 Binary files /dev/null and b/docs/source/_tutorials/tutorial-3/output_7_0.png differ diff --git a/docs/source/_tutorials/tutorial-3/tutorial-3.rst b/docs/source/_tutorials/tutorial-3/tutorial-3.rst new file mode 100644 index 00000000..e3aa3504 --- /dev/null +++ b/docs/source/_tutorials/tutorial-3/tutorial-3.rst @@ -0,0 +1,434 @@ +Using Plugin for implementing NNsPOD-ROM +======================================== + +In this tutorial we will explain how to use the **NNsPOD-ROM** algorithm +implemented in **EZyRB** library. + +NNsPOD algorithm is purely a data-driven machine learning method that +seeks for an optimal mapping of the various snapshots to a reference +configuration via an automatic detection [1] and seeking for the +low-rank linear approximation subspace of the solution manifold. The +nonlinear transformation of the manifold leads to an accelerated KnW +decay, resulting in a low-dimensional linear approximation subspace, and +enabling the construction of efficient and accurate reduced order +models. The complete workflow of the NNsPOD-ROM algorithm, comprising of +both the offline and online phases is presented in [2]. + +References: + +[1] Papapicco, D., Demo, N., Girfoglio, M., Stabile, G., & Rozza, +G.(2022). The Neural Network shifted-proper orthogonal decomposition: A +machine learning approach for non-linear reduction of hyperbolic +equations.Computer Methods in Applied Mechanics and Engineering, 392, +114687 - https://doi.org/10.1016/j.cma.2022.114687 + +[2] Gowrachari, H., Demo, N., Stabile, G., & Rozza, G. (2024). +Non-intrusive model reduction of advection-dominated hyperbolic problems +using neural network shift augmented manifold transformations. arXiv +preprint - https://arxiv.org/abs/2407.18419. + +Problem defintion +~~~~~~~~~~~~~~~~~ + +We consider **1D gaussian distribution functions**, in wihch :math:`x` +is random variable, $ :raw-latex:`\mu `$ is mean and $ +:raw-latex:`\sigma`^2 $ is variance, where $ :raw-latex:`\sigma `$ is +the standard deviation or the width of gaussian. + +.. math:: + + + f(x)=\frac{1}{\sigma \sqrt{2 \pi}} e^{-(x-\mu)^2 /\left(2 \sigma^2\right)} + +To mimic travelling waves, here we parameterize the mean :math:`\mu` +values, where changing :math:`\mu` shifts the distribution along x-axis, + +Initial setting +~~~~~~~~~~~~~~~ + +First of all import the required packages: We need the standard Numpy, +Torch, Matplotlib, and some classes from EZyRB. + +- ``numpy:`` to handle arrays and matrices we will be working with. +- ``torch:`` to enable the usage of Neural Networks +- ``matplotlib:`` to handle the plotting environment. + +From ``EZyRB`` we need: 1. The ``ROM`` class, which performs the model +order reduction process. 2. A module such as ``Database``, where the +matrices of snapshots and parameters are stored. 3. A dimensionality +reduction method such as Proper Orthogonal Decomposition ``POD`` 4. An +interpolation method to obtain an approximation for the parametric +solution for a new set of parameters such as the Radial Basis Function +``RBF``, or Multidimensional Linear Interpolator ``Linear``. + +.. code:: ipython3 + + import numpy as np + import torch + from scipy import spatial + from matplotlib import pyplot as plt + + from ezyrb import POD, RBF, Database, Snapshot, Parameter, Linear, ANN + from ezyrb import ReducedOrderModel as ROM + from ezyrb.plugin import AutomaticShiftSnapshots + +.. code:: ipython3 + + def gaussian(x, mu, sig): + return np.exp(-np.power(x - mu, 2.) / (2 * np.power(sig, 2.))) + + def wave(t, res=256): + x = np.linspace(0, 11, res) + return x, gaussian(x, t, 0.2).T # parameterizing mean value + +Offline phase +------------- + +In this case, we obtain 15 snapshots from the analytical model. + +.. code:: ipython3 + + n_params = 20 + params = np.linspace(0.75, 10.25, n_params).reshape(-1, 1) + + pod = POD(rank=1) + rbf = RBF() + db = Database() + + for param in params: + space, values = wave(param) + snap = Snapshot(values=values.T, space=space) + db.add(Parameter(param), snap) + + print("Snapshot shape : ", db.snapshots_matrix.shape) + print("Parameter shape : ", db.parameters_matrix.shape) + + +.. parsed-literal:: + + Snapshot shape : (20, 256) + Parameter shape : (20, 1) + + +.. code:: ipython3 + + db_train, db_test = db.split([0.7,0.3]) + print("Lenght of training data set:", len(db_train)) + print(f"Parameters of training set: \n {db_train.parameters_matrix.flatten()}") + + print("Lenght of test data set:", len(db_test)) + print(f"Parameters of testing set: \n {db_test.parameters_matrix.flatten()}") + + +.. parsed-literal:: + + Lenght of training data set: 12 + Parameters of training set: + [ 0.75 1.25 2.25 2.75 4.75 5.25 7.25 7.75 8.25 9.25 9.75 10.25] + Lenght of test data set: 8 + Parameters of testing set: + [1.75 3.25 3.75 4.25 5.75 6.25 6.75 8.75] + + +.. code:: ipython3 + + plt.rcParams.update({ + "text.usetex": True, + "font.family": "serif", + "font.serif": ["Times New Roman"], + }) + + fig1 = plt.figure(figsize=(5,5)) + ax = fig1.add_subplot(111,projection='3d') + + for param in params: + space, values = wave(param) + snap = Snapshot(values=values.T, space=space) + ax.plot(space, param*np.ones(space.shape), values, label = f"{param}") + ax.set_xlabel('x') + ax.set_ylabel('t') + ax.set_zlabel('$f_{g}$(t)') + ax.set_xlim(0,11) + ax.set_ylim(0,11) + ax.set_zlim(0,1) + ax.legend(loc="upper center", ncol=7, prop = { "size": 7}) + ax.grid(False) + ax.view_init(elev=20, azim=-60, roll=0) + ax.set_title("Snapshots at original position") + plt.show() + + + +.. image:: output_6_0.png + + +.. code:: ipython3 + + #%% 3D PLOT : db_train snpashots at original position + fig2 = plt.figure(figsize=(5,5)) + ax = fig2.add_subplot(111, projection='3d') + + for i in range(len(db_train)): + ax.plot(space,(db_train.parameters_matrix[i]*np.ones(space.shape)), db_train.snapshots_matrix[i], label = db_train.parameters_matrix[i]) + ax.set_xlabel('x') + ax.set_ylabel('t') + ax.set_zlabel('$f_{g}$(t)') + ax.set_xlim(0,11) + ax.set_ylim(0,11) + ax.set_zlim(0,1) + ax.legend(loc="upper center", ncol=7, prop = { "size": 7}) + ax.grid(False) + ax.view_init(elev=20, azim=-60, roll=0) + ax.set_title("Training set snapshots at original position") + plt.show() + + + +.. image:: output_7_0.png + + +``InterpNet:`` must learn the reference configuration in the best +possible way w.r.t its grid point distribution such that it will be able +to reconstruct field values for every shifted centroid disrtribution. + +``ShiftNet:`` will learn the shift operator for a given problem, which +quantifies the optimal-shift, resulting in shifted space that transports +all the snapshots to the reference frame. + +``Training:`` The training of ShiftNet and InterpNet are seperated with +the latter being trained first. Once the network has learned the +best-possible reconstruct of the solution field of the reference +configuration, its forward map will be used for the training of Shiftnet +as well, in a cascaded fashion. For this reason, we must optimise the +loss of interpnet considerably more than ShiftNet’s. + +.. code:: ipython3 + + torch.manual_seed(1) + + interp = ANN([10,10], torch.nn.Softplus(), [1e-6, 200000], frequency_print=1000, lr=0.03) + shift = ANN([], torch.nn.LeakyReLU(), [1e-4, 10000], optimizer=torch.optim.Adam, frequency_print=500, l2_regularization=0, lr=0.0023) + + rom = ROM( + database=db_train, + reduction=pod, + approximation=rbf, + plugins=[ + AutomaticShiftSnapshots( + shift_network= shift, + interp_network=interp, + interpolator=Linear(fill_value=0), + reference_index=4, + parameter_index=4, + barycenter_loss=20.) + ] + ) + rom.fit() + + +.. parsed-literal:: + + [epoch 1] 9.325559e-02 + [epoch 1000] 1.529361e-03 + [epoch 2000] 4.970222e-04 + [epoch 3000] 4.387998e-04 + [epoch 4000] 4.628130e-04 + [epoch 5000] 3.835012e-04 + [epoch 6000] 3.140604e-04 + [epoch 7000] 3.919086e-04 + [epoch 8000] 4.268886e-04 + [epoch 9000] 9.304365e-05 + [epoch 10000] 4.048840e-04 + [epoch 11000] 3.448661e-04 + [epoch 12000] 1.810824e-04 + [epoch 13000] 1.608639e-04 + [epoch 14000] 1.410103e-04 + [epoch 15000] 1.369342e-04 + [epoch 16000] 3.215274e-04 + [epoch 17000] 1.686200e-05 + [epoch 18000] 1.850619e-04 + [epoch 19000] 5.792178e-05 + [epoch 20000] 1.031569e-05 + [epoch 21000] 5.006416e-04 + [epoch 22000] 7.024280e-06 + [epoch 23000] 3.728175e-06 + [epoch 24000] 2.684203e-06 + [epoch 25000] 2.088043e-05 + [epoch 26000] 2.364460e-05 + [epoch 27000] 5.422693e-05 + [epoch 28000] 8.736612e-06 + [epoch 29000] 1.406125e-03 + [epoch 29941] 9.978612e-07 + [epoch 1] 1.996005e+01 + [epoch 500] 3.647174e+00 + [epoch 1000] 2.648998e+00 + [epoch 1500] 1.878768e+00 + [epoch 2000] 1.296257e+00 + [epoch 2500] 8.012146e-01 + [epoch 3000] 3.615186e-01 + [epoch 3500] 8.892784e-03 + [epoch 4000] 4.733771e-03 + [epoch 4500] 2.296455e-03 + [epoch 5000] 9.881203e-04 + [epoch 5500] 3.655896e-04 + [epoch 6000] 1.145256e-04 + [epoch 6055] 9.997654e-05 + + + + +.. parsed-literal:: + + + + + +.. code:: ipython3 + + #%% Snapshots shifted reference position after training + for i in range(len(db_train.parameters_matrix)): + plt.plot(space, rom.shifted_database.snapshots_matrix[i], label = f"t = {db_train.parameters_matrix[i]}") #rom._shifted_reference_database.parameters_matrix + plt.legend(prop={'size': 8}) + plt.ylabel('$f_{g}$(t)') + plt.xlabel('X') + plt.title(f'After training : Snapshot of db_train set shifted to reference snapshot {db_train.parameters_matrix[5]}') + plt.show() + + + +.. image:: output_10_0.png + + +Showing the snapshots before (left) and after pre-processing (right) of +solution manifold + +.. code:: ipython3 + + fig3 = plt.figure(figsize=(10, 5)) + + # First subplot + ax1 = fig3.add_subplot(121, projection='3d') + for i in range(len(db_train)): + ax1.plot(space, (db_train.parameters_matrix[i] * np.ones(space.shape)), db_train.snapshots_matrix[i]) + ax1.set_xlabel('x') + ax1.set_ylabel('t') + ax1.set_zlabel('$f_{g}$(t)') + ax1.set_xlim(0,11) + ax1.set_ylim(0,11) + ax1.set_zlim(0,1) + ax1.grid(False) + ax1.view_init(elev=20, azim=-60, roll=0) + + # Second subplot + ax2 = fig3.add_subplot(122, projection='3d') + for i in range(len(rom.shifted_database)): + ax2.plot(space, (rom.shifted_database.parameters_matrix[i] * np.ones(space.shape)), + rom.shifted_database.snapshots_matrix[i], label=rom.shifted_database.parameters_matrix[i]) + ax2.set_xlabel('x') + ax2.set_ylabel('t') + ax2.set_zlabel('$f_{g}$(t)') + ax2.set_xlim(0, 11) + ax2.set_ylim(0, 11) + ax2.set_zlim(0, 1) + ax2.grid(False) + ax2.view_init(elev=20, azim=-60, roll=0) + handles, labels = ax2.get_legend_handles_labels() + fig3.legend(handles, labels, loc='center right', ncol=1, prop={'size': 8}) + plt.show() + + + +.. image:: output_12_0.png + + +.. code:: ipython3 + + #%% Singular values of original snapshots and shifted snapshots + U, s = np.linalg.svd(db.snapshots_matrix.T, full_matrices=False)[:2] + N_modes = np.linspace(1, len(s),len(s)) + + # Singular values of shifted snapshots + U_shifted , s_shifted = np.linalg.svd(rom.shifted_database.snapshots_matrix.T, full_matrices=False)[:2] + N_modes_shifted = np.linspace(1, len(s_shifted),len(s_shifted)) + + # Compare singular values + plt.figure(figsize=(6,4)) + plt.plot(N_modes[:10], s[:10]/np.max(s),"-s",color = "blue", label='POD') + plt.plot(N_modes_shifted, s_shifted/np.max(s_shifted),"-o", color = "red", label='NNsPOD') + plt.ylabel('$\sigma/\sigma_{1}$', size=15) + plt.xlabel('Modes', size=15) + plt.xlim(0, 11) + plt.legend(fontsize=12) + plt.xticks(fontsize=15) + plt.yticks(fontsize=15) + plt.show() + + + +.. image:: output_13_0.png + + +.. code:: ipython3 + + #%% POD MODES + modes = pod.modes + plt.figure(figsize=(6,4)) + plt.plot(space, modes*-1) + plt.ylabel('$f_{g}$(t)', size=15) + plt.xlabel('x', size=15) + plt.title('NNsPOD mode', size=15) + plt.xticks(fontsize=15) + plt.yticks(fontsize=15) + plt.show() + + + +.. image:: output_14_0.png + + +Online phase +------------ + +.. code:: ipython3 + + #%% Test set predictions using NNsPOD + pred = rom.predict(db_test.parameters_matrix) # Calculate predicted solution for given mu + + fig5 = plt.figure(figsize=(5,5)) + ax = fig5.add_subplot(111, projection='3d') + for i in range(len(pred)): + space, orig = wave(db_test.parameters_matrix[i]) + ax.plot(space,(db_test.parameters_matrix[i]*np.ones(space.shape)), pred.snapshots_matrix[i], label = f'Predict={db_test.parameters_matrix[i]}') + ax.plot(space,(db_test.parameters_matrix[i]*np.ones(space.shape)), orig, '--', label = f'Truth={db_test.parameters_matrix[i]}') + ax.set_xlabel('x') + ax.set_ylabel('t') + ax.set_zlabel('$f_{g}$(t)') + ax.set_xlim(0,11) + ax.set_ylim(0,11) + ax.set_zlim(0,1) + ax.legend(loc="upper center", ncol=5, prop = { "size": 7}) + ax.grid(False) + ax.view_init(elev=20, azim=-60, roll=0) + ax.set_title('Predicted Snapshots for db_test set parameters') + plt.show() + + + +.. image:: output_16_0.png + + +.. code:: ipython3 + + #%% Reconstruction and prediction error + train_err = rom.test_error(db_train) + test_err = rom.test_error(db_test) + + print('Mean Train error: ', train_err) + print('Mean Test error: ', test_err) + + +.. parsed-literal:: + + Mean Train error: 0.18585298603714098 + Mean Test error: 0.11119321870633797 + diff --git a/docs/source/_tutorials/tutorial-4/output_10_0.png b/docs/source/_tutorials/tutorial-4/output_10_0.png new file mode 100644 index 00000000..c0816ff0 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_10_0.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_10_1.png b/docs/source/_tutorials/tutorial-4/output_10_1.png new file mode 100644 index 00000000..eba59c18 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_10_1.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_19_1.png b/docs/source/_tutorials/tutorial-4/output_19_1.png new file mode 100644 index 00000000..d90f1f65 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_19_1.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_19_2.png b/docs/source/_tutorials/tutorial-4/output_19_2.png new file mode 100644 index 00000000..13441332 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_19_2.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_27_0.png b/docs/source/_tutorials/tutorial-4/output_27_0.png new file mode 100644 index 00000000..3ede3f98 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_27_0.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_27_1.png b/docs/source/_tutorials/tutorial-4/output_27_1.png new file mode 100644 index 00000000..1fa35b2f Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_27_1.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_29_0.png b/docs/source/_tutorials/tutorial-4/output_29_0.png new file mode 100644 index 00000000..359a1b39 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_29_0.png differ diff --git a/docs/source/_tutorials/tutorial-4/output_29_1.png b/docs/source/_tutorials/tutorial-4/output_29_1.png new file mode 100644 index 00000000..921635c9 Binary files /dev/null and b/docs/source/_tutorials/tutorial-4/output_29_1.png differ diff --git a/docs/source/_tutorials/tutorial-4/tutorial-4.rst b/docs/source/_tutorials/tutorial-4/tutorial-4.rst new file mode 100644 index 00000000..773c5f62 --- /dev/null +++ b/docs/source/_tutorials/tutorial-4/tutorial-4.rst @@ -0,0 +1,738 @@ +Build a Multi Reduced Order Model (MultiROM) +============================================ + +In this tutorial, we will show how to aggregate the predictions of +different ROMs following the method presented in the `paper by Ivagnes +et +al. `__ + +Let’s call :math:`\boldsymbol{\eta}=(\boldsymbol{x}, \boldsymbol{\mu})` +the problem’s features, namely the space coordinates and the parameters. + +The idea is to build and combine a set of ROMs +:math:`\{\mathcal{M}_1, \mathcal{M}_2, \dots, \mathcal{M}_{N}\}`, to +approximate a specific high-fidelity field, for instance the +parametrized velocity :math:`\boldsymbol{u}(\boldsymbol{\eta})`. The +individual ROMs differ in the reduction approach and/or in the +approximation technique. The **MultiROM prediction** will then be a +convex combination of the predictions of the pre-trained individual +ROMs. If the :math:`i`-th ROM prediction is +:math:`\tilde{\boldsymbol{u}}^{(i)}(\boldsymbol{\eta})`, then the +MultiROM prediction will be: + +.. math:: \tilde{\boldsymbol{u}}(\boldsymbol{\eta}) = \sum_{i=1}^{N} w^{(i)}(\boldsymbol{\eta}) \tilde{\boldsymbol{u}}^{(i)}(\boldsymbol{\eta}) , + +where the weights associated with each ROM in the convex combination are +space- and parameter-dependent. In this way, the **MultiROM** should +effectively and automatically identify the ROM with the optimal +performance across various regions of the spatial and parameter domains. + +To build the model, we have to design a method to compute the weights, +also in unseen settings. We here consider a dataset from the library +**Smithers** (``NavierStokesDataset``), and we divide it into three +subsets: - the **training** dataset (composed of +:math:`M_{\text{train}}` instances): used to train the individual ROMs; +- the **evaluation** dataset (composed of :math:`M_{\text{evaluation}}` +instances): used to compute the optimal weights; - the **test** dataset +(composed of :math:`M_{\text{test}}` instances): used to test our +methodology, where the weights are approximated with a regression +technique. + +Now the question is: *How to compute the weights?* We here consider two +different approaches: - **XMA** (as in `de Zordo-Banliat et +al. `__), +where the weights are computed in the evaluation set, using the +following expression: + +.. math:: + + w^{(i)}(\boldsymbol{\eta})=\dfrac{g^{(i)}(\boldsymbol{\eta})}{\sum_{i=1}^N g^{(i)}(\boldsymbol{\eta})}, \, g^{(i)}(\boldsymbol{\eta})=\text{exp}\left( - \dfrac{1}{2} \dfrac{(\tilde{\boldsymbol{u}}^{(i)}(\boldsymbol{\eta}) - \boldsymbol{u}(\boldsymbol{\eta}))^2}{\sigma^2} \right),\, \text{for } \boldsymbol{\eta}=\boldsymbol{\eta}_{\text{evaluation}}. + + +\ In the test set, a regression approach (``KNN``) is used to +approximate the weights at unseen +:math:`\boldsymbol{\eta}=\boldsymbol{\eta}_{\text{test}}`. + +- **ANN**: a neural network takes as input :math:`\boldsymbol{\eta}`, + and gives as output directly the weights + :math:`w^{(i)}, i=1, \dots, N,` of the convex combination. It is + trained to minimize the following loss: + + .. math:: \mathcal{L}=\frac{1}{M_{\textrm{test}}} \sum_{j=1}^{M_{\textrm{test}}}\left(\sum_{i=1}^N \left(w^{(i)}(\boldsymbol{\eta}_j) \tilde{\boldsymbol{u}}^{(i)}(\boldsymbol{\eta}_j)\right) - \boldsymbol{u}(\boldsymbol{\eta}_j) \right)^2 + +Let’s begin the tutorial with some useful imports. + +.. code:: ipython3 + + import numpy as np + import copy + %pip install -e ../ + from ezyrb import Database + from ezyrb import POD, AE, PODAE + from ezyrb import RBF, GPR, ANN, KNeighborsRegressor + from ezyrb import ReducedOrderModel as ROM + from ezyrb import MultiReducedOrderModel as MultiROM + from ezyrb.plugin import Aggregation, DatabaseSplitter + import matplotlib.pyplot as plt + import torch + import torch.nn as nn + from matplotlib.colors import LogNorm + import matplotlib.tri as tri + import matplotlib + from mpl_toolkits.axes_grid1 import make_axes_locatable + + +.. parsed-literal:: + + Obtaining file:///Users/aivagnes/Desktop/Work/Packages/EZyRB + Preparing metadata (setup.py) ... [?25ldone + [?25hRequirement already satisfied: future in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from ezyrb==1.3.0) (0.18.3) + Requirement already satisfied: numpy in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from ezyrb==1.3.0) (1.24.4) + Requirement already satisfied: scipy in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from ezyrb==1.3.0) (1.10.1) + Requirement already satisfied: matplotlib in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from ezyrb==1.3.0) (3.7.1) + Requirement already satisfied: scikit-learn>=1.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from ezyrb==1.3.0) (1.3.2) + Requirement already satisfied: torch in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from ezyrb==1.3.0) (2.0.1) + Requirement already satisfied: joblib>=1.1.1 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from scikit-learn>=1.0->ezyrb==1.3.0) (1.2.0) + Requirement already satisfied: threadpoolctl>=2.0.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from scikit-learn>=1.0->ezyrb==1.3.0) (3.1.0) + Requirement already satisfied: contourpy>=1.0.1 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (1.0.7) + Requirement already satisfied: cycler>=0.10 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (0.11.0) + Requirement already satisfied: fonttools>=4.22.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (4.39.0) + Requirement already satisfied: kiwisolver>=1.0.1 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (1.4.4) + Requirement already satisfied: packaging>=20.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (23.0) + Requirement already satisfied: pillow>=6.2.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (9.4.0) + Requirement already satisfied: pyparsing>=2.3.1 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (3.0.9) + Requirement already satisfied: python-dateutil>=2.7 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (2.8.2) + Requirement already satisfied: importlib-resources>=3.2.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from matplotlib->ezyrb==1.3.0) (5.12.0) + Requirement already satisfied: filelock in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from torch->ezyrb==1.3.0) (3.15.4) + Requirement already satisfied: typing-extensions in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from torch->ezyrb==1.3.0) (4.11.0) + Requirement already satisfied: sympy in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from torch->ezyrb==1.3.0) (1.11.1) + Requirement already satisfied: networkx in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from torch->ezyrb==1.3.0) (3.1) + Requirement already satisfied: jinja2 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from torch->ezyrb==1.3.0) (3.1.2) + Requirement already satisfied: zipp>=3.1.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from importlib-resources>=3.2.0->matplotlib->ezyrb==1.3.0) (3.15.0) + Requirement already satisfied: six>=1.5 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from python-dateutil>=2.7->matplotlib->ezyrb==1.3.0) (1.16.0) + Requirement already satisfied: MarkupSafe>=2.0 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from jinja2->torch->ezyrb==1.3.0) (2.1.2) + Requirement already satisfied: mpmath>=0.19 in /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages (from sympy->torch->ezyrb==1.3.0) (1.3.0) + Installing collected packages: ezyrb + Attempting uninstall: ezyrb + Found existing installation: ezyrb 1.3.0 + Uninstalling ezyrb-1.3.0: + Successfully uninstalled ezyrb-1.3.0 + Running setup.py develop for ezyrb + Successfully installed ezyrb-1.3.0 + + [notice] A new release of pip is available: 24.1.1 -> 25.0.1 + [notice] To update, run: pip install --upgrade pip + Note: you may need to restart the kernel to use updated packages. + + +Before starting with the core part of the tutorial, we define a useful +function for plotting the solutions on a 2D mesh. + +.. code:: ipython3 + + def plot_multiple_internal(db, fields_list, titles_list, figsize=None, + logscale=False, lim_x=(-0.5, 2), lim_y=(-1, 1), + different_cbar=True, clims=None): + ''' + Plot multiple internal fields in one figure. + + Parameters + ---------- + db : PinaDataModule + The data module. + fields_list : list + The list of fields to plot. + titles_list : list + The list of titles for each field. + figsize : tuple (optional, default=(16, 16/len(fields_list)) + The size of the figure. + logscale : bool (optional, default=False) + Whether to use a logarithmic color scale. + lim_x : tuple (optional, default=(-0.5, 2)) + The x-axis limits. + lim_y : tuple (optional, default=(-1, 1)) + The y-axis limits. + different_cbar : bool (optional, default=True) + Whether to use a different colorbar for each field. + + Returns + ---------- + None (shows figures) + ''' + triang = db.auxiliary_triang + + if figsize is None: + figsize = (16, 16/len(fields_list)) + fig, axs = plt.subplots(1, len(fields_list), figsize=figsize) + for e, a in enumerate(axs): + field = fields_list[e] + title = titles_list[e] + if clims is None: + clims = fields_list[0].min(), fields_list[0].max() + if logscale: + lognorm = matplotlib.colors.LogNorm(vmin=clims[0]+1e-12, + vmax=clims[1]) + c = a.tripcolor(triang, field, cmap='rainbow', + shading='gouraud', norm=lognorm) + else: + c = a.tripcolor(triang, field, cmap='rainbow', + shading='gouraud', vmin=clims[0], + vmax=clims[1]) + a.plot(db._coords_airfoil()[0], db._coords_airfoil()[1], + color='black', lw=0.5) + a.plot(db._coords_airfoil(which='neg')[0], + db._coords_airfoil(which='neg')[1], + color='black', lw=0.5) + a.set_aspect('equal') + if lim_x is not None: + a.set_xlim(lim_x) + if lim_y is not None: + a.set_ylim(lim_y) + if title is not None: + a.set_title(title) + if different_cbar: + divider = make_axes_locatable(a) + cax = divider.append_axes("right", size= "5%", pad=0.1) + plt.colorbar(c, cax=cax) + a.set_xticks([]) + a.set_yticks([]) + if not different_cbar: + divider = make_axes_locatable(axs[0]) + cax = divider.append_axes("left", size= "1%", pad=0.1) + plt.colorbar(c, cax=cax) + plt.tight_layout() + plt.show() + +Now, we define a simple neural network class, which will be useful in +the multiROM-ANN case. This networks takes as input the spatial +coordinates and the problem parameters, and gives as output the weights +of our multiROM. This class is inherited from the ``ANN`` one, with a +newly defined ``fit`` function. In this case, in the loss function we +have the discrepancy between the multiROM prediction and the FOM +reference. Moreover, the power of this technique is that it is +continuous in space, so we can train the NN on a reduced amount of +spatial data, gaining time also in the training itself. + +.. code:: ipython3 + + class ANN_weights(ANN): + def __init__(self, mrom, layers, function, stop_training, loss=None, + optimizer=torch.optim.Adam, lr=0.001, l2_regularization=0, + frequency_print=500, last_identity=True): + super().__init__(layers, function, stop_training, loss=None, + optimizer=torch.optim.Adam, lr=0.001, l2_regularization=0, + frequency_print=10, last_identity=True) + + # import useful data from multirom and roms predictions + self.mrom = mrom + self.params = list(self.mrom.roms.values())[0].validation_full_database.parameters_matrix + + self.frequency_print = frequency_print + self.lr = lr + self.l2_regularization = l2_regularization + + # import ROMs and validation predictions of all ROMs + self.rom_validation_predictions = {} + for rom in self.mrom.roms: + rom_pred = self.mrom.roms[rom] + rom_pred = rom_pred.predict(self.params) + rom_pred = rom_pred.reshape(rom_pred.shape[0]*rom_pred.shape[1], 1) + self.rom_validation_predictions[rom] = self._convert_numpy_to_torch(rom_pred) + + # Device configuration + self.device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu') + print(f"Using device: 💻 {self.device}") + + def _build_model_(self, points): + layers = self.layers.copy() + layers.insert(0, points.shape[1]) + layers.append(len(self.mrom.roms)) + self.model = self._list_to_sequential(layers, self.function) + + # Move the model to the device + self.model.to(self.device) + + def fit(self, points, values): # points=(x, mu) and values=(snapshots) + self._build_model_(points) + optimizer = self.optimizer( + self.model.parameters(), + lr=self.lr, weight_decay=self.l2_regularization) + + #scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.9, patience=1000) + + points = self._convert_numpy_to_torch(points) + values = self._convert_numpy_to_torch(values) + + # Move everything to the device + points = points.to(self.device) + values = values.to(self.device) + self.rom_validation_predictions = {rom: pred.to(self.device) for rom, pred in self.rom_validation_predictions.items()} + + # train the neural network + n_epoch = 1 + flag = True + while flag: + # compute output of ANN + y_pred = self.model(points) + + # compute aggregated solution from output weights of ANN + aggr_pred = torch.zeros(values.shape, device=self.device) + for i, rom in enumerate(self.mrom.roms): + weight = y_pred.clone()[..., i].unsqueeze(-1) + aggr_pred += weight*self.rom_validation_predictions[rom] + + # difference between aggregated solution and exact solution + loss = self.loss(aggr_pred, values) + + optimizer.zero_grad() + loss.backward() + optimizer.step() + + scalar_loss = loss.item() + self.loss_trend.append(scalar_loss) + + #scheduler.step(scalar_loss) + + for criteria in self.stop_training: + if isinstance(criteria, int): # stop criteria is an integer + if n_epoch == criteria: + flag = False + elif isinstance(criteria, float): # stop criteria is float + if scalar_loss < criteria: + flag = False + + if (flag is False or + n_epoch == 1 or n_epoch % self.frequency_print == 0): + print(f'[epoch {n_epoch:6d}]\t{scalar_loss:e}') + n_epoch += 1 + + return optimizer + + def predict(self, x): + + # Move the model to the device + x = self._convert_numpy_to_torch(np.array(x)) + x = x.to(self.device) + y_new = self.model(x) + ynew = y_new.cpu().detach().numpy() + return ynew + +Now we can introduce the dataset, taken from the library +`Smithers `__. + +The test case here considered is ``AirfoilTransonicDataset``, namely the +transonic flow over an airfoil (NACA 0012), with the angle of attack +varying in the range [:math:`0^{\circ}`, :math:`10^{\circ}`] at the +Reynolds number :math:`Re=10^7`. + +This test case is quite challenging, as it presents shocks, and the +shock position varies a lot from one snapshot to the other. The full +order implementation has been done in OpenFOAM (using a finite volume +discretization) and has been validated with the results in +https://ntrs.nasa.gov/citations/19850019511 and in +https://doi.org/10.2514/1.J051329. + +The ``AirfoilTransonicDataset`` is a dictionary including: + +- ``pts_coordinates``: the points’ coordinates, divided into: + + - ``pts_coordinates['internal']``: x-y coordinates in internal mesh; + - ``pts_coordinates['airfoil']``: x-y coordinates on the airfoil; + +- ``params``: the parameters, in our case only the angle of attack; +- ``snapshots``: the snapshots’ fields, divided into: + + - ``snapshots['internal']``: the fields evaluated on the 2D internal + mesh (we will focus on the velocity magnitude ``mag(v)``); + - ``snapshots['airfoil']``: the fields on the airfoil (1D fields). + +We focus here on the 2D ``mag(v)`` field. Let’s try to read the dataset! + +.. code:: ipython3 + + from smithers.dataset import NavierStokesDataset, AirfoilTransonicDataset + data = AirfoilTransonicDataset() + field = 'mag(v)' + coords = data.pts_coordinates["internal"].T + params = data.params + snaps = data.snapshots["internal"][field] + snaps_max = np.max(snaps) + snaps /= snaps_max + print("Shape of parameters vector: ", params.shape) + print("Shape of snapshots matrix: ", snaps.shape) + + +.. parsed-literal:: + + Shape of parameters vector: (100, 1) + Shape of snapshots matrix: (100, 45448) + + +Let’s try now to visualize the 2D spatial coordinates and the velocity +magnitude snapshots for the two extreme parameters. + +.. code:: ipython3 + + idx = 0 + # Plot coordinates + fig, ax = plt.subplots(1, 2, figsize=(15, 5)) + ax[0].scatter(data.pts_coordinates["internal"][0, :], + data.pts_coordinates["internal"][1, :], s=5) + ax[1].scatter(data.pts_coordinates["internal"][0, :], + data.pts_coordinates["internal"][1, :], s=5) + ax[1].set_xlim(-0.5, 2) + ax[1].set_ylim(-1, 1) + + for a in ax: + a.grid() + a.set_aspect("equal") + plt.show() + plot_multiple_internal(data, [snaps[0], snaps[-1]], [f"Snapshot at alpha={params[0]}", f"Snapshot at alpha={params[-1]}"], + figsize=None, logscale=False, lim_x=(-0.5, 2), lim_y=(-1, 1), different_cbar=True) + + + +.. image:: output_10_0.png + + + +.. image:: output_10_1.png + + +Then, we can create the database for the ROMs and initialize the +reduction and approximation approaches. Here, we decide to consider POD +and PODAE as reduction techniques, RBF and GPR as approximation +strategies. In the end, we are considering four ROMs: POD-RBF, POD-GPR, +PODAE-RBF, PODAE-GPR. + +.. code:: ipython3 + + # Create the database + db_all = Database(params, snaps, coords) + + # Define some reduction and approximation methods to test + rank = 3 + pod_for_podae = POD('svd', rank=80) + ae_for_podae = AE([30, 10, rank], [rank, 10, 30], nn.Softplus(), nn.Softplus(), 50000, lr=1e-3, frequency_print=2000) + reduction_methods = { + 'POD': POD('svd', rank=rank), + 'PODAE': PODAE(pod_for_podae, ae_for_podae) + } + approximation_methods = { + 'RBF': RBF(), + 'GPR': GPR() + } + +We now define the ROMs (store into a simple dictionary). Note that we +use the ``DatabaseSplitter`` plugin to split our database into train, +validation, test, and predict sets. Here we will only use the train, +validation, and predict sets. + +.. code:: ipython3 + + # Define a dictionary to store the ROMs + roms_dict = {} + db_splitter_plugin = DatabaseSplitter(train=0.6, validation=0.3, test=0., + predict=0.1, seed=42) + # Train a ROM for each combination of reduction and approximation + for redname, redclass in reduction_methods.items(): + for approxname, approxclass in approximation_methods.items(): + rom = ROM(copy.deepcopy(db_all), + copy.deepcopy(redclass), + copy.deepcopy(approxclass), + plugins=[db_splitter_plugin]) + roms_dict[f'{redname}_{approxname}'] = rom + +Then, the definition of the ``MultiROM`` follows. We can now fit the +MultiROM, which coincides with fitting the individual ROMs separately. + +.. code:: ipython3 + + # Build a simple multiROM without aggregation and save it + multirom_noagg = MultiROM(roms_dict) + # Fit the multiROM (this step may take some time) + multirom_noagg.fit() + + +.. parsed-literal:: + + [epoch 1] 2.469141e+02 + [epoch 2000] 1.377898e-01 + [epoch 4000] 1.071991e-01 + [epoch 6000] 7.265408e-02 + [epoch 8000] 4.396581e-02 + [epoch 10000] 3.937927e-02 + [epoch 12000] 3.674430e-02 + [epoch 14000] 4.076399e-02 + [epoch 16000] 2.940542e-02 + [epoch 18000] 2.764397e-02 + [epoch 20000] 2.988867e-02 + [epoch 22000] 2.159446e-02 + [epoch 24000] 2.006776e-02 + [epoch 26000] 1.967250e-02 + [epoch 28000] 1.194988e-02 + [epoch 30000] 9.829493e-03 + [epoch 32000] 9.823296e-03 + [epoch 34000] 8.634089e-03 + [epoch 36000] 8.533438e-03 + [epoch 38000] 8.409876e-03 + [epoch 40000] 1.002743e-02 + [epoch 42000] 1.035028e-02 + [epoch 44000] 8.028184e-03 + [epoch 46000] 8.383193e-03 + [epoch 48000] 7.963227e-03 + [epoch 50000] 1.061061e-02 + [epoch 1] 2.433394e+02 + [epoch 2000] 2.430486e-01 + [epoch 4000] 8.800354e-02 + [epoch 6000] 6.279282e-02 + [epoch 8000] 4.753726e-02 + [epoch 10000] 4.444053e-02 + [epoch 12000] 4.448576e-02 + [epoch 14000] 4.391388e-02 + [epoch 16000] 4.341885e-02 + [epoch 18000] 3.927369e-02 + [epoch 20000] 3.098299e-02 + [epoch 22000] 2.612145e-02 + [epoch 24000] 2.182353e-02 + [epoch 26000] 2.140819e-02 + [epoch 28000] 2.090856e-02 + [epoch 30000] 2.038679e-02 + [epoch 32000] 1.961394e-02 + [epoch 34000] 1.646917e-02 + [epoch 36000] 1.557970e-02 + [epoch 38000] 1.507105e-02 + [epoch 40000] 1.453493e-02 + [epoch 42000] 1.511188e-02 + [epoch 44000] 1.419082e-02 + [epoch 46000] 1.334900e-02 + [epoch 48000] 1.282931e-02 + [epoch 50000] 1.201333e-02 + + + + +.. parsed-literal:: + + + + + +After fitting the individual models in the train database, we can now +read the validation and test databases, and, for example, visualize the +ROM predictions for some test parameters. + +.. code:: ipython3 + + # Get the dictionary of ROMs + roms_dict = multirom_noagg.roms + + # Extract one ROM from the dictionary, and read the validation and test databases + rom_one = list(multirom_noagg.roms.values())[0] + db_validation = rom_one.validation_full_database + db_test = rom_one.predict_full_database + +.. code:: ipython3 + + # Visualize the results of each ROM in the multiROM without aggregation on + # a new parameter + j = 0 # we choose an index to plot the solution and the weights + p = db_test.parameters_matrix[j] + print("Test parameter for plotting: ", p) + fields = [] + roms_pred = [rom.predict([p]).flatten() for rom in roms_dict.values()] + roms_pred.append(db_test.snapshots_matrix[j]) + errs = [np.abs(r - db_test.snapshots_matrix[j])+1e-10 for r in roms_pred[:-1]] + labels = [f'{key}' for key in roms_dict.keys()] + labels.append("FOM") + plot_multiple_internal(data, roms_pred, labels, different_cbar=False) + plot_multiple_internal(data, errs, [f"{l} - abs. error" for l in labels], logscale=True, different_cbar=False) + + +.. parsed-literal:: + + Test parameter for plotting: [0.2] + + + +.. image:: output_19_1.png + + + +.. image:: output_19_2.png + + +We can see that the ``POD_*`` solutions are more overdiffusive, while +the ``PODAE_*`` solutions better capture the discontinuity, even if they +still exhibit imprecisions. + +We now initialize two novel ``multiROM``\ s using the plugin +``Aggregation``. One model is for the standard XMA aggregation +(indicated with ``fit_function=None``) and uses ``KNN`` as regressor. +The other model uses the ``ANN_weights`` class to compute the weights +starting from the individual ROM prediction. In both cases, the weights +are trained in the validation set. + +.. code:: ipython3 + + print("Fitting multiROM with KNN aggregation...") + knn = KNeighborsRegressor() + multirom_KNN = MultiROM(roms_dict, plugins=[Aggregation(fit_function=None, predict_function=knn), db_splitter_plugin]) + multirom_KNN.fit() + + +.. parsed-literal:: + + Fitting multiROM with KNN aggregation... + Optimal sigma value in weights: [0.009994] + + + + +.. parsed-literal:: + + + + + +.. code:: ipython3 + + print("Fitting multiROM with ANN aggregation...") + ann = ANN_weights(multirom_noagg, [64, 64, 64],[nn.Softplus(), nn.Softplus(), nn.Softplus(), nn.Softmax(dim=-1)], + stop_training=1000, lr=1e-3, frequency_print=100, l2_regularization=0) + multirom_ANN = MultiROM(roms_dict, plugins=[Aggregation(fit_function=ann), db_splitter_plugin]) + multirom_ANN.fit() + + +.. parsed-literal:: + + Fitting multiROM with ANN aggregation... + Using device: 💻 mps + [epoch 1] 1.110127e-04 + [epoch 100] 2.332629e-05 + [epoch 200] 2.292044e-05 + [epoch 300] 2.286620e-05 + [epoch 400] 2.281346e-05 + [epoch 500] 2.274650e-05 + [epoch 600] 2.265942e-05 + [epoch 700] 2.256762e-05 + [epoch 800] 2.250623e-05 + [epoch 900] 2.247204e-05 + [epoch 1000] 2.244576e-05 + + + + +.. parsed-literal:: + + + + + +Let’s now quantify the relative error on test parameters for the +individual ROMs and for the multiROM strategies. + +.. code:: ipython3 + + multiroms = {} + multiroms["KNN"] = multirom_KNN + multiroms["ANN"] = multirom_ANN + + header = '{:10s}'.format('') + for name in approximation_methods: + header += ' {:>16s}'.format(name) + print(header) + for redname, redclass in reduction_methods.items(): + row = '{:10s}'.format(redname) + for approxname, approxclass in approximation_methods.items(): + rom = roms_dict[redname+'_'+approxname] + row += ' {:16e}'.format(rom.test_error(db_test)) + print(row) + print('-'*len(row)) + for model_name in multiroms: + row = '{:10s}'.format(model_name) + multirom_ = multiroms[model_name] + row += '- MultiROM {:16e}'.format(multirom_.test_error(db_test)) + print(row) + + +.. parsed-literal:: + + RBF GPR + POD 5.263353e-02 5.263348e-02 + -------------------------------------------- + PODAE 9.785834e-03 9.695809e-03 + -------------------------------------------- + KNN - MultiROM 1.304681e-02 + ANN - MultiROM 9.233725e-03 + + +We can try now to visualize the predicted multiROMs solutions for a test +parameters, and the errors with respect to the corresponding FOM +reference. The multiROM automatically detects the best method in +different spatial coordinates. + +.. code:: ipython3 + + fields = [] + roms_pred = [] + for rom in multiroms.values(): + roms_pred.append(rom.predict(np.array([p]).reshape(-1, 1)).flatten()) + roms_pred.append(db_test.snapshots_matrix[j].flatten()) + errs = [np.abs(r - db_test.snapshots_matrix[j])+1e-10 for r in roms_pred[:-1]] + labels = list(multiroms.keys()) + labels.append("FOM") + # visualize fields + plot_multiple_internal(data, roms_pred, labels, + figsize=None, logscale=False, lim_x=(-0.5, 2), lim_y=(-1, 1)) + # visualize errors in log scale + plot_multiple_internal(data, errs, [f"{l} - abs. error" for l in labels], + figsize=None, logscale=True, lim_x=(-0.5, 2), lim_y=(-1, 1)) + + + +.. image:: output_27_0.png + + + +.. image:: output_27_1.png + + +We finally try to visualize the weights, for example for the standard +XMA multiROM strategy, for the same test parameter as before. + +.. code:: ipython3 + + for mrom in multiroms.values(): + weights_list = [] + for rom in roms_dict.keys(): + weights_list.append(mrom.weights_predict[rom].flatten()) + plot_multiple_internal(data, weights_list, list(roms_dict.keys()), + figsize=None, logscale=False, lim_x=(-0.5, 2), lim_y=(-1, 1), different_cbar=False, clims=[0, 1]) + + + +.. image:: output_29_0.png + + + +.. image:: output_29_1.png + + +We can immediately see that the standard aggregation algorithm is +“activating” the nonlinear reduction approaches (PODAE) in the spatial +regions close to the shock and to the wake, while in the rest part of +the domain the weights are 50% for POD methods and 50% for PODAE +methods. The ANN strategy instead converges to weights with less +space-dependency. This highly depends on the architecture of the ANN, +and on all the hyperparameters (activation function, learning rate, +weight decay). + +What’s next? +~~~~~~~~~~~~ + +There’s still a lot to do like: - improving the training of the ANN by +adding a negative loss contribution depending on the spatial variability +of the weights. In this way we try to enforce more space variability; - +try to combine FOM and ROM together (multifidelity aggregation). + diff --git a/docs/source/ae.rst b/docs/source/ae.rst index 9b74d2d8..6a0ed15e 100644 --- a/docs/source/ae.rst +++ b/docs/source/ae.rst @@ -9,14 +9,6 @@ AE :toctree: _summaries :nosignatures: - AE - AE.fit - AE.reduce - AE.expand - AE.transform - AE.inverse_transform - AE._build_model - .. autoclass:: AE :members: :private-members: diff --git a/docs/source/aggregation.rst b/docs/source/aggregation.rst new file mode 100644 index 00000000..dbbe6987 --- /dev/null +++ b/docs/source/aggregation.rst @@ -0,0 +1,17 @@ +Aggregation +===================== + +.. currentmodule:: ezyrb.plugin.aggregation + +.. automodule:: ezyrb.plugin.aggregation + +.. autosummary:: + :toctree: _summaries + :nosignatures: + +.. autoclass:: Aggregation + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: diff --git a/docs/source/ann.rst b/docs/source/ann.rst index 23c455c6..5bd393fe 100644 --- a/docs/source/ann.rst +++ b/docs/source/ann.rst @@ -9,13 +9,6 @@ ANN :toctree: _summaries :nosignatures: - ANN - ANN.fit - ANN.predict - ANN._convert_numpy_to_torch - ANN._convert_torch_to_numpy - ANN._build_model - .. autoclass:: ANN :members: :private-members: diff --git a/docs/source/approximation.rst b/docs/source/approximation.rst index f6d6cf24..dec8fc9a 100644 --- a/docs/source/approximation.rst +++ b/docs/source/approximation.rst @@ -9,10 +9,6 @@ Approximation :toctree: _summaries :nosignatures: - Approximation - Approximation.fit - Approximation.predict - .. autoclass:: Approximation :members: :private-members: diff --git a/docs/source/automatic_shift_snapshots.rst b/docs/source/automatic_shift_snapshots.rst new file mode 100644 index 00000000..c4057407 --- /dev/null +++ b/docs/source/automatic_shift_snapshots.rst @@ -0,0 +1,17 @@ +AutomaticShiftSnapshots +======================= + +.. currentmodule:: ezyrb.plugin.automatic_shift + +.. automodule:: ezyrb.plugin.automatic_shift + +.. autosummary:: + :toctree: _summaries + :nosignatures: + +.. autoclass:: AutomaticShiftSnapshots + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: diff --git a/docs/source/code.rst b/docs/source/code.rst index 33d275b1..328d5f0a 100644 --- a/docs/source/code.rst +++ b/docs/source/code.rst @@ -1,23 +1,53 @@ Code Documentation ================== +Core Classes +------------ + .. toctree:: :maxdepth: 2 database parameter snapshot + reducedordermodel + +Approximation Methods +--------------------- + +.. toctree:: + :maxdepth: 2 + approximation linear rbf - radius_neighbors_regressor - kneighbors_regressor - neighbors_regressor gpr ann + neighbors_regressor + kneighbors_regressor + radius_neighbors_regressor + regular_grid + +Reduction Methods +----------------- + +.. toctree:: + :maxdepth: 2 + reduction pod ae podae - reducedordermodel - regular_grid + +Plugin System +------------- + +.. toctree:: + :maxdepth: 2 + + plugin + database_scaler + database_splitter + shift_snapshots + automatic_shift_snapshots + aggregation diff --git a/docs/source/conf.py b/docs/source/conf.py index 3c584b31..c4d555b3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -176,7 +176,7 @@ # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -html_extra_path = ['_tutorials'] +html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff --git a/docs/source/database.rst b/docs/source/database.rst index 80fd33fa..8416162c 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -9,11 +9,6 @@ Database :toctree: _summaries :nosignatures: - Database - Database.__getitem__ - Database.__len__ - Database.add - .. autoclass:: Database :members: :private-members: diff --git a/docs/source/database_scaler.rst b/docs/source/database_scaler.rst new file mode 100644 index 00000000..7d4cecf8 --- /dev/null +++ b/docs/source/database_scaler.rst @@ -0,0 +1,17 @@ +DatabaseScaler +===================== + +.. currentmodule:: ezyrb.plugin.scaler + +.. automodule:: ezyrb.plugin.scaler + +.. autosummary:: + :toctree: _summaries + :nosignatures: + +.. autoclass:: DatabaseScaler + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: diff --git a/docs/source/database_splitter.rst b/docs/source/database_splitter.rst new file mode 100644 index 00000000..682c6163 --- /dev/null +++ b/docs/source/database_splitter.rst @@ -0,0 +1,24 @@ +DatabaseSplitter +===================== + +.. currentmodule:: ezyrb.plugin.database_splitter + +.. automodule:: ezyrb.plugin.database_splitter + +.. autosummary:: + :toctree: _summaries + :nosignatures: + +.. autoclass:: DatabaseSplitter + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: + +.. autoclass:: DatabaseDictionarySplitter + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: diff --git a/docs/source/gpr.rst b/docs/source/gpr.rst index 6ce12699..2ab7412c 100644 --- a/docs/source/gpr.rst +++ b/docs/source/gpr.rst @@ -9,11 +9,6 @@ GPR :toctree: _summaries :nosignatures: - GPR - GPR.fit - GPR.predict - GPR.optimal_mu - .. autoclass:: GPR :members: :private-members: diff --git a/docs/source/index.rst b/docs/source/index.rst index b029c7d6..fb25650f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,4 +1,4 @@ -Welcome to EZyRB's documentation! +EZyRB - Easy Reduced Basis =================================================== .. image:: _static/logo_EZyRB.png @@ -6,64 +6,47 @@ Welcome to EZyRB's documentation! :width: 150 px :align: right -Easy Reduced Basis method. +**Easy Reduced Basis method for Model Order Reduction** +EZyRB is a Python library for **Model Order Reduction** based on various reduction and approximation techniques. It provides a flexible framework for creating fast surrogate models from high-fidelity simulations. -Description -^^^^^^^^^^^^ - -EZyRB is a python library for the Model Order Reduction based on baricentric triangulation for the selection of the parameter points and on Proper Orthogonal Decomposition for the selection of the modes. It is ideally suited for actual industrial problems, since its structure can interact with several simulation software simply providing the output file of the simulations. The software uses a POD interpolation approach in which the solutions are projected on the low dimensional space spanned by the POD modes (see "Bui-Thanh et al. - Proper orthogonal decomposition extensions for parametric applications in compressible aerodynamics" and "Chinesta et al. - Model Order Reduction: a survey"). The new solution is then obtained by interpolating the low rank solutions into the parametric space. This approach makes the package non intrusive with respect to the high fidelity solver actually used. This allows an easy integration into existing simulation pipelines, and it can deal with both vtk files and matlab files. - -In the EZyRB package we implemented in Python the algorithms described above. We also provide tutorials that show all the characteristics of the software, from the offline part in which it is possible to construct the database of snapshots, to the online part for fast evaluations of the fields for new parameters. There are also modules to allow the consistency of all the solutions (often with different degrees of freedom) in order to process them. - - -Installation --------------------- -EZyRB requires numpy, scipy, matplotlib, and sphinx (for the documentation). They can be easily installed via pip. Moreover EZyRB depends on vtk. The code is compatible with Python 2.7. It can be installed directly from the source code. - - -The `official distribution `_ is on GitHub, and you can clone the repository using -:: - - git clone https://github.com/mathLab/EZyRB - -To install the package just type: -:: - python setup.py install +Key Features +^^^^^^^^^^^^ -To uninstall the package you have to rerun the installation and record the installed files in order to remove them: +- **Multiple Reduction Methods**: POD, Autoencoders (AE), POD-AE +- **Flexible Approximation**: RBF, Linear, GPR, ANN, K-Neighbors, and more +- **Non-Intrusive Approach**: Works with any simulation output format +- **Plugin System**: Extensible architecture for preprocessing and postprocessing +- **Easy Integration**: Simple API for building reduced order models +- **Database Management**: Built-in tools for handling parameter-snapshot pairs -:: - python setup.py install --record installed_files.txt - cat installed_files.txt | xargs rm -rf +User Guide +---------- +.. toctree:: + :maxdepth: 2 + :caption: User Guide + Installation + Quick Start + API Documentation + Tutorials -Developer's Guide --------------------- +Developer Info +-------------- .. toctree:: :maxdepth: 1 + :caption: Developer Info - code - contact contributing + contact LICENSE - -Tutorials -^^^^^^^^^^ - -We made some tutorial examples: - -- `Tutorial 1 `_ shows how to construct a simple reduced order model for a heat conduction problem. -- `Tutorial 2 `_ shows how test different methods for reduced order modeling on a NavierStokes 2D problem. - - Indices and tables ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 00000000..146f1057 --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,69 @@ +Installation +============ + +Requirements +------------ + +EZyRB requires: + +- Python >= 3.8 +- numpy +- scipy +- matplotlib +- scikit-learn +- torch (for neural network-based methods) + +Install via pip +--------------- + +The easiest way to install EZyRB is using pip: + +.. code-block:: bash + + pip install ezyrb + +This will automatically install all required dependencies. + + +Install from source +------------------- + +To get the latest development version, clone the repository from GitHub: + +.. code-block:: bash + + git clone https://github.com/mathLab/EZyRB + cd EZyRB + pip install . + +For development purposes, you can install in editable mode: + +.. code-block:: bash + + pip install -e . + + +Optional Dependencies +--------------------- + +For additional features, you may want to install: + +- **vtk**: For reading/writing VTK files +- **GPy**: For advanced Gaussian Process Regression + +Install them with: + +.. code-block:: bash + + pip install vtk GPy + + +Verify Installation +------------------- + +To verify that EZyRB is correctly installed, run: + +.. code-block:: python + + import ezyrb + print(ezyrb.__version__) diff --git a/docs/source/kneighbors_regressor.rst b/docs/source/kneighbors_regressor.rst index eb525f9a..e672e4d2 100644 --- a/docs/source/kneighbors_regressor.rst +++ b/docs/source/kneighbors_regressor.rst @@ -9,10 +9,6 @@ KNeighborsRegressor :toctree: _summaries :nosignatures: - KNeighborsRegressor - KNeighborsRegressor.fit - KNeighborsRegressor.predict - .. autoclass:: KNeighborsRegressor :members: :private-members: diff --git a/docs/source/linear.rst b/docs/source/linear.rst index 2aa014c0..6949ea78 100644 --- a/docs/source/linear.rst +++ b/docs/source/linear.rst @@ -9,10 +9,6 @@ Linear :toctree: _summaries :nosignatures: - Linear - Linear.fit - Linear.predict - .. autoclass:: Linear :members: :private-members: diff --git a/docs/source/neighbors_regressor.rst b/docs/source/neighbors_regressor.rst index 827fe177..01594411 100644 --- a/docs/source/neighbors_regressor.rst +++ b/docs/source/neighbors_regressor.rst @@ -9,10 +9,6 @@ NeighborsRegressor :toctree: _summaries :nosignatures: - NeighborsRegressor - NeighborsRegressor.fit - NeighborsRegressor.predict - .. autoclass:: NeighborsRegressor :members: :private-members: diff --git a/docs/source/plugin.rst b/docs/source/plugin.rst new file mode 100644 index 00000000..71103d67 --- /dev/null +++ b/docs/source/plugin.rst @@ -0,0 +1,17 @@ +Plugin +===================== + +.. currentmodule:: ezyrb.plugin.plugin + +.. automodule:: ezyrb.plugin.plugin + +.. autosummary:: + :toctree: _summaries + :nosignatures: + +.. autoclass:: Plugin + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: diff --git a/docs/source/pod.rst b/docs/source/pod.rst index 7f61ec5b..7531f13d 100644 --- a/docs/source/pod.rst +++ b/docs/source/pod.rst @@ -9,18 +9,6 @@ POD :toctree: _summaries :nosignatures: - POD - POD.modes - POD.singular_values - POD.reduce - POD.expand - POD.transform - POD.inverse_transform - POD._truncation - POD._svd - POD._rsvd - POD._corrm - .. autoclass:: POD :members: :private-members: diff --git a/docs/source/podae.rst b/docs/source/podae.rst index f22266c7..73c8d78a 100644 --- a/docs/source/podae.rst +++ b/docs/source/podae.rst @@ -9,13 +9,6 @@ PODAE :toctree: _summaries :nosignatures: - PODAE - PODAE.fit - PODAE.reduce - PODAE.expand - PODAE.transform - PODAE.inverse_transform - .. autoclass:: PODAE :members: :private-members: diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst new file mode 100644 index 00000000..2c249c04 --- /dev/null +++ b/docs/source/quickstart.rst @@ -0,0 +1,110 @@ +Quick Start +=========== + +This guide will help you get started with EZyRB in just a few minutes. + + +Basic Workflow +-------------- + +The typical workflow for using EZyRB consists of three main steps: + +1. **Create a Database**: Collect your parameter-snapshot pairs +2. **Build a ROM**: Choose reduction and approximation methods +3. **Make Predictions**: Evaluate the ROM at new parameter values + + +Minimal Example +--------------- + +Here's a complete example to get you started: + +.. code-block:: python + + import numpy as np + from ezyrb import POD, RBF, Database, ReducedOrderModel + + # Step 1: Create a database + params = np.array([[1.0], [2.0], [3.0], [4.0]]) + snapshots = np.random.rand(4, 100) # 4 snapshots of size 100 + db = Database(params, snapshots) + + # Step 2: Build a ROM + pod = POD(rank=5) # Use 5 POD modes + rbf = RBF() # Radial Basis Function interpolation + rom = ReducedOrderModel(db, pod, rbf) + rom.fit() + + # Step 3: Predict for new parameters + new_param = np.array([[2.5]]) + prediction = rom.predict(new_param) + print(prediction.snapshots_matrix.shape) # (1, 100) + + +Understanding the Components +----------------------------- + +Database +^^^^^^^^ + +The ``Database`` class stores parameter-snapshot pairs: + +.. code-block:: python + + from ezyrb import Database, Parameter, Snapshot + + # Simple creation + db = Database(parameters, snapshots) + + # Or add pairs individually + db = Database() + db.add(Parameter([1.0, 2.0]), Snapshot(values)) + + +Reduction Methods +^^^^^^^^^^^^^^^^^ + +Reduce the dimensionality of your snapshots: + +.. code-block:: python + + from ezyrb import POD, AE + + # Proper Orthogonal Decomposition + pod = POD(rank=10) + + # Autoencoder + import torch + ae = AE([100, 50, 10], [10, 50, 100], + torch.nn.Tanh(), torch.nn.Tanh(), 1000) + + +Approximation Methods +^^^^^^^^^^^^^^^^^^^^^ + +Interpolate in the reduced space: + +.. code-block:: python + + from ezyrb import RBF, GPR, ANN, Linear + + # Radial Basis Functions + rbf = RBF() + + # Gaussian Process Regression + gpr = GPR() + + # Artificial Neural Network + import torch + ann = ANN([10, 20, 10], torch.nn.Tanh(), 1000) + + # Linear interpolation + linear = Linear() + + +Next Steps +---------- + +- Check out the :doc:`tutorials` for detailed examples +- Explore the :doc:`code` for complete API reference +- Learn about :doc:`plugin` system for advanced customization diff --git a/docs/source/radius_neighbors_regressor.rst b/docs/source/radius_neighbors_regressor.rst index 30368ba2..9b7070a6 100644 --- a/docs/source/radius_neighbors_regressor.rst +++ b/docs/source/radius_neighbors_regressor.rst @@ -1,5 +1,5 @@ RadiusNeighborsRegressor -===================== +======================== .. currentmodule:: ezyrb.approximation.radius_neighbors_regressor @@ -9,10 +9,6 @@ RadiusNeighborsRegressor :toctree: _summaries :nosignatures: - RadiusNeighborsRegressor - RadiusNeighborsRegressor.fit - RadiusNeighborsRegressor.predict - .. autoclass:: RadiusNeighborsRegressor :members: :private-members: diff --git a/docs/source/rbf.rst b/docs/source/rbf.rst index 1cd4d5a1..fff9a8c9 100644 --- a/docs/source/rbf.rst +++ b/docs/source/rbf.rst @@ -9,10 +9,6 @@ RBF :toctree: _summaries :nosignatures: - RBF - RBF.fit - RBF.predict - .. autoclass:: RBF :members: :private-members: diff --git a/docs/source/reducedordermodel.rst b/docs/source/reducedordermodel.rst index 0373a2a5..436dced3 100644 --- a/docs/source/reducedordermodel.rst +++ b/docs/source/reducedordermodel.rst @@ -9,15 +9,6 @@ ReducedOrderModel :toctree: _summaries :nosignatures: - ReducedOrderModel - ReducedOrderModel.fit - ReducedOrderModel.predict - ReducedOrderModel.test_error - ReducedOrderModel.kfold_cv_error - ReducedOrderModel.loo_error - ReducedOrderModel.optimal_mu - ReducedOrderModel._simplex_volume - .. autoclass:: ReducedOrderModel :members: :private-members: diff --git a/docs/source/reduction.rst b/docs/source/reduction.rst index b6ee47ad..6dda535c 100644 --- a/docs/source/reduction.rst +++ b/docs/source/reduction.rst @@ -9,12 +9,6 @@ Reduction :toctree: _summaries :nosignatures: - Reduction - Reduction.reduce - Reduction.expand - Reduction.transform - Reduction.inverse_transform - .. autoclass:: Reduction :members: :private-members: diff --git a/docs/source/regular_grid.rst b/docs/source/regular_grid.rst index 2b1901ec..34388af4 100644 --- a/docs/source/regular_grid.rst +++ b/docs/source/regular_grid.rst @@ -9,11 +9,6 @@ RegularGrid :toctree: _summaries :nosignatures: - RegularGrid - RegularGrid.get_grid_axes - RegularGrid.fit - RegularGrid.predict - .. autoclass:: RegularGrid :members: :private-members: diff --git a/docs/source/shift_snapshots.rst b/docs/source/shift_snapshots.rst new file mode 100644 index 00000000..3f3cc161 --- /dev/null +++ b/docs/source/shift_snapshots.rst @@ -0,0 +1,17 @@ +ShiftSnapshots +===================== + +.. currentmodule:: ezyrb.plugin.shift + +.. automodule:: ezyrb.plugin.shift + +.. autosummary:: + :toctree: _summaries + :nosignatures: + +.. autoclass:: ShiftSnapshots + :members: + :private-members: + :undoc-members: + :show-inheritance: + :noindex: diff --git a/docs/source/tutorials.rst b/docs/source/tutorials.rst new file mode 100644 index 00000000..068f8a64 --- /dev/null +++ b/docs/source/tutorials.rst @@ -0,0 +1,22 @@ +Tutorials +================= + +.. toctree:: + :maxdepth: 1 + + _tutorials/tutorial-1/tutorial-1 + +.. toctree:: + :maxdepth: 1 + + _tutorials/tutorial-2/tutorial-2 + +.. toctree:: + :maxdepth: 1 + + _tutorials/tutorial-3/tutorial-3 + +.. toctree:: + :maxdepth: 1 + + _tutorials/tutorial-4/tutorial-4 diff --git a/ezyrb/approximation/ann.py b/ezyrb/approximation/ann.py index af98b207..d9525632 100755 --- a/ezyrb/approximation/ann.py +++ b/ezyrb/approximation/ann.py @@ -50,6 +50,19 @@ class ANN(Approximation): def __init__(self, layers, function, stop_training, loss=None, optimizer=torch.optim.Adam, lr=0.001, l2_regularization=0, frequency_print=10, last_identity=True): + """ + Initialize an Artificial Neural Network. + + :param list layers: Ordered list with the number of neurons of each hidden layer. + :param function: Activation function(s) for each layer. + :param stop_training: Stopping criteria for training (iterations and/or tolerance). + :param loss: Loss function to use. Default is MSELoss. + :param optimizer: Optimizer class to use. Default is Adam. + :param float lr: Learning rate. Default is 0.001. + :param float l2_regularization: L2 regularization coefficient. Default is 0. + :param int frequency_print: Frequency of printing during training. Default is 10. + :param bool last_identity: Whether the last activation is identity. Default is True. + """ if loss is None: loss = torch.nn.MSELoss() @@ -121,15 +134,13 @@ def _list_to_sequential(layers, functions): def _build_model(self, points, values): """ - Build the torch model. - Considering the number of neurons per layer (self.layers), a - feed-forward NN is defined: - - activation function from layer i>=0 to layer i+1: - self.function[i]; activation function at the output layer: - Identity (by default). - :param numpy.ndarray points: the coordinates of the given (training) - points. - :param numpy.ndarray values: the (training) values in the points. + Build the torch neural network model. + + Constructs a feed-forward neural network with the specified layers + and activation functions. + + :param numpy.ndarray points: The coordinates of the training points. + :param numpy.ndarray values: The training values at the points. """ layers = self.layers.copy() layers.insert(0, points.shape[1]) diff --git a/ezyrb/approximation/gpr.py b/ezyrb/approximation/gpr.py index c97c84ad..97322896 100644 --- a/ezyrb/approximation/gpr.py +++ b/ezyrb/approximation/gpr.py @@ -38,6 +38,14 @@ class GPR(Approximation): """ def __init__(self, kern=None, normalizer=True, optimization_restart=20): + """ + Initialize a Gaussian Process Regressor. + + :param kern: Kernel object from sklearn. Default is None. + :param bool normalizer: Whether to normalize values. Default is True. + :param int optimization_restart: Number of restarts for optimization. + Default is 20. + """ self.X_sample = None self.Y_sample = None diff --git a/ezyrb/approximation/kneighbors_regressor.py b/ezyrb/approximation/kneighbors_regressor.py index 62b2f318..0e18586e 100644 --- a/ezyrb/approximation/kneighbors_regressor.py +++ b/ezyrb/approximation/kneighbors_regressor.py @@ -7,10 +7,26 @@ class KNeighborsRegressor(NeighborsRegressor): """ - K-Neighbors Regressor. + K-Neighbors Regressor for multidimensional approximation. :param kwargs: arguments passed to the internal instance of KNeighborsRegressor. + + :Example: + + >>> import numpy as np + >>> from ezyrb import KNeighborsRegressor + >>> x = np.random.uniform(-1, 1, size=(20, 2)) + >>> y = np.array([np.sin(x[:, 0]), np.cos(x[:, 1])]).T + >>> knn = KNeighborsRegressor(n_neighbors=3) + >>> knn.fit(x, y) + >>> new_x = np.array([[0.5, 0.5]]) + >>> y_pred = knn.predict(new_x) """ def __init__(self, **kwargs): + """ + Initialize a K-Neighbors Regressor. + + :param kwargs: Arguments passed to sklearn's KNeighborsRegressor. + """ self.regressor = Regressor(**kwargs) diff --git a/ezyrb/approximation/linear.py b/ezyrb/approximation/linear.py index 6b07d627..d2bd0d18 100644 --- a/ezyrb/approximation/linear.py +++ b/ezyrb/approximation/linear.py @@ -18,6 +18,12 @@ class Linear(Approximation): default is numpy.nan. """ def __init__(self, fill_value=np.nan): + """ + Initialize a Linear interpolator. + + :param float fill_value: Value for points outside the convex hull. + Default is numpy.nan. + """ self.fill_value = fill_value self.interpolator = None diff --git a/ezyrb/approximation/neighbors_regressor.py b/ezyrb/approximation/neighbors_regressor.py index f98ffb2a..5fab2195 100644 --- a/ezyrb/approximation/neighbors_regressor.py +++ b/ezyrb/approximation/neighbors_regressor.py @@ -7,9 +7,21 @@ class NeighborsRegressor(Approximation): """ A generic superclass for wrappers of *NeighborsRegressor from sklearn. + + This class provides a common interface for neighbor-based regression methods. - :param kwargs: arguments passed to the internal instance of + :param kwargs: Arguments passed to the internal instance of *NeighborsRegressor. + + :Example: + + >>> import numpy as np + >>> from ezyrb import KNeighborsRegressor + >>> x = np.random.uniform(-1, 1, size=(20, 2)) + >>> y = np.sin(x[:, 0]) + np.cos(x[:, 1]) + >>> knn = KNeighborsRegressor(n_neighbors=5) + >>> knn.fit(x, y) + >>> y_pred = knn.predict(x[:5]) """ def fit(self, points, values): """ diff --git a/ezyrb/approximation/radius_neighbors_regressor.py b/ezyrb/approximation/radius_neighbors_regressor.py index 2a988096..26cfb100 100644 --- a/ezyrb/approximation/radius_neighbors_regressor.py +++ b/ezyrb/approximation/radius_neighbors_regressor.py @@ -7,10 +7,26 @@ class RadiusNeighborsRegressor(NeighborsRegressor): """ - Radius Neighbors Regressor. + Radius Neighbors Regressor for multidimensional approximation. :param kwargs: arguments passed to the internal instance of RadiusNeighborsRegressor. + + :Example: + + >>> import numpy as np + >>> from ezyrb import RadiusNeighborsRegressor + >>> x = np.random.uniform(-1, 1, size=(20, 2)) + >>> y = np.sin(x[:, 0]) * np.cos(x[:, 1]) + >>> rnn = RadiusNeighborsRegressor(radius=0.5) + >>> rnn.fit(x, y) + >>> new_x = np.array([[0.0, 0.0]]) + >>> y_pred = rnn.predict(new_x) """ def __init__(self, **kwargs): + """ + Initialize a Radius Neighbors Regressor. + + :param kwargs: Arguments passed to sklearn's RadiusNeighborsRegressor. + """ self.regressor = Regressor(**kwargs) diff --git a/ezyrb/database.py b/ezyrb/database.py index 8768d05b..96725d88 100644 --- a/ezyrb/database.py +++ b/ezyrb/database.py @@ -7,7 +7,7 @@ class Database(): """ - Database class + Database class for storing parameter-snapshot pairs. :param array_like parameters: the input parameters :param array_like snapshots: the input snapshots @@ -16,6 +16,20 @@ class Database(): :param Scale scaler_snapshots: the scaler for the snapshots. Default is None meaning no scaling. :param array_like space: the input spatial data + + :Example: + + >>> import numpy as np + >>> from ezyrb import Database, Parameter, Snapshot + >>> params = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + >>> snapshots = np.random.rand(3, 100) + >>> db = Database(params, snapshots) + >>> print(len(db)) + 3 + >>> print(db.parameters_matrix.shape) + (3, 2) + >>> print(db.snapshots_matrix.shape) + (3, 100) """ def __init__(self, parameters=None, snapshots=None, space=None): self._pairs = [] diff --git a/ezyrb/parameter.py b/ezyrb/parameter.py index 58549b25..d29d5986 100644 --- a/ezyrb/parameter.py +++ b/ezyrb/parameter.py @@ -2,8 +2,33 @@ import numpy as np class Parameter: + """ + Class for representing a parameter in the reduced order model. + + This class encapsulates parameter values and provides validation + to ensure parameters are 1-dimensional arrays. + + :param array_like values: The parameter values as a 1D array. + + :Example: + + >>> import numpy as np + >>> from ezyrb import Parameter + >>> param = Parameter([1.0, 2.5, 3.0]) + >>> print(param.values) + [1. 2.5 3. ] + >>> param2 = Parameter(np.array([4.5, 5.5])) + >>> print(param2.values) + [4.5 5.5] + """ def __init__(self, values): + """ + Initialize a Parameter object. + + :param array_like values: The parameter values. Can be a Parameter + instance or an array-like object that can be converted to a 1D numpy array. + """ if isinstance(values, Parameter): self.values = values.values else: @@ -16,6 +41,12 @@ def values(self): @values.setter def values(self, new_values): + """ + Set the parameter values with validation. + + :param array_like new_values: The new parameter values. + :raises ValueError: If the new values are not a 1D array. + """ if np.asarray(new_values).ndim != 1: raise ValueError('only 1D array are usable as parameter.') diff --git a/ezyrb/plugin/aggregation.py b/ezyrb/plugin/aggregation.py index fb51481b..440cde97 100644 --- a/ezyrb/plugin/aggregation.py +++ b/ezyrb/plugin/aggregation.py @@ -42,6 +42,14 @@ class Aggregation(Plugin): """ def __init__(self, fit_function=None, predict_function=Linear()): + """ + Initialize the Aggregation plugin. + + :param fit_function: Regression model to fit weights in validation set. + If None, uses standard space-dependent methods. Default is None. + :param predict_function: Regression model to predict weights in test set. + Default is Linear(). + """ super().__init__() self.fit_function = fit_function self.predict_function = predict_function diff --git a/ezyrb/plugin/automatic_shift.py b/ezyrb/plugin/automatic_shift.py index 8e2c5dce..9cb32a4f 100644 --- a/ezyrb/plugin/automatic_shift.py +++ b/ezyrb/plugin/automatic_shift.py @@ -50,6 +50,16 @@ class AutomaticShiftSnapshots(Plugin): """ def __init__(self, shift_network, interp_network, interpolator, parameter_index=0, reference_index=0, barycenter_loss=0): + """ + Initialize the AutomaticShiftSnapshots plugin. + + :param shift_network: Neural network for learning the shift function. + :param interp_network: Neural network for interpolation. + :param Approximation interpolator: Interpolator for shifted snapshots evaluation. + :param int parameter_index: Index of parameter component. Default is 0. + :param int reference_index: Index of reference snapshot. Default is 0. + :param float barycenter_loss: Weight for barycenter loss term. Default is 0. + """ super().__init__() self.interpolator = interpolator @@ -61,6 +71,7 @@ def __init__(self, shift_network, interp_network, interpolator, def _train_interp_network(self): """ + Train the interpolation network on the reference snapshot. """ self.interp_network.fit( self.reference_snapshot.space.reshape(-1, 1), @@ -69,6 +80,9 @@ def _train_interp_network(self): def _train_shift_network(self, db): """ + Train the shift network using the database snapshots. + + :param Database db: The database containing snapshots. """ ref_center = torch.tensor(np.average( self.reference_snapshot.space * self.reference_snapshot.values)) diff --git a/ezyrb/plugin/database_splitter.py b/ezyrb/plugin/database_splitter.py index d99c67e5..90a7ab69 100644 --- a/ezyrb/plugin/database_splitter.py +++ b/ezyrb/plugin/database_splitter.py @@ -4,10 +4,46 @@ class DatabaseSplitter(Plugin): + """ + Plugin for splitting the database into training, test, validation, and prediction sets. + + This plugin automatically splits the database according to specified ratios + before the fitting process begins. + + :param float train: Ratio or number of samples for training set. Default is 0.9. + :param float test: Ratio or number of samples for test set. Default is 0.1. + :param float validation: Ratio or number of samples for validation set. Default is 0.0. + :param float predict: Ratio or number of samples for prediction set. Default is 0.0. + :param int seed: Random seed for reproducibility. Default is None. + + :Example: + + >>> from ezyrb import ReducedOrderModel as ROM + >>> from ezyrb import POD, RBF, Database + >>> from ezyrb.plugin import DatabaseSplitter + >>> import numpy as np + >>> params = np.random.rand(100, 2) + >>> snapshots = np.random.rand(100, 50) + >>> db = Database(params, snapshots) + >>> pod = POD(rank=5) + >>> rbf = RBF() + >>> splitter = DatabaseSplitter(train=0.7, test=0.2, validation=0.1) + >>> rom = ROM(db, pod, rbf, plugins=[splitter]) + >>> rom.fit() + """ def __init__(self, train=0.9, test=0.1, validation=0.0, predict=0.0, seed=None): + """ + Initialize the DatabaseSplitter plugin. + + :param float train: Ratio for training set. Default is 0.9. + :param float test: Ratio for test set. Default is 0.1. + :param float validation: Ratio for validation set. Default is 0.0. + :param float predict: Ratio for prediction set. Default is 0.0. + :param int seed: Random seed. Default is None. + """ super().__init__() self.train = train @@ -17,6 +53,11 @@ def __init__(self, train=0.9, test=0.1, validation=0.0, predict=0.0, self.seed = seed def fit_preprocessing(self, rom): + """ + Split the database before fitting begins. + + :param ReducedOrderModel rom: The ROM instance. + """ db = rom._database if isinstance(db, Database): train, test, validation, predict = db.split( @@ -43,17 +84,39 @@ def fit_preprocessing(self, rom): #print('predict', predict.snapshots_matrix.shape) class DatabaseDictionarySplitter(Plugin): - """ This plugin class is used to define the train, test, validation and predict databases when the databases are already split: train, test, validation and predict are already database objects stored in a dictionary. Given the desired keys of the dictionary as input, the plugin will assign the corresponding database objects to the train, test, validation and predict attributes of the ROM. + + :Example: + + >>> from ezyrb import ReducedOrderModel as ROM + >>> from ezyrb import POD, RBF, Database + >>> from ezyrb.plugin import DatabaseDictionarySplitter + >>> db_dict = { + ... 'train': Database(train_params, train_snaps), + ... 'test': Database(test_params, test_snaps) + ... } + >>> pod = POD(rank=5) + >>> rbf = RBF() + >>> splitter = DatabaseDictionarySplitter(train_key='train', test_key='test') + >>> rom = ROM(db_dict['train'], pod, rbf, plugins=[splitter]) + >>> rom.fit() """ def __init__(self, train_key=None, test_key=None, validation_key=None, predict_key=None): + """ + Initialize the DatabaseDictionarySplitter plugin. + + :param str train_key: Dictionary key for training database. Default is None. + :param str test_key: Dictionary key for test database. Default is None. + :param str validation_key: Dictionary key for validation database. Default is None. + :param str predict_key: Dictionary key for prediction database. Default is None. + """ super().__init__() self.train_key = train_key self.test_key = test_key @@ -61,6 +124,12 @@ def __init__(self, train_key=None, test_key=None, validation_key=None, self.predict_key = predict_key def fit_preprocessing(self, rom): + """ + Assign the database splits from the dictionary before fitting. + + :param ReducedOrderModel rom: The ROM instance. + :raises ValueError: If the database is not a dictionary. + """ db = rom._database if isinstance(db, dict): if self.train_key is not None: diff --git a/ezyrb/plugin/plugin.py b/ezyrb/plugin/plugin.py index 926c31e4..1eb739cb 100644 --- a/ezyrb/plugin/plugin.py +++ b/ezyrb/plugin/plugin.py @@ -5,57 +5,105 @@ class Plugin(ABC): """ - The abstract `Approximation` class. - - All the classes that implement the input-output mapping should be inherited - from this class. + The abstract Plugin class for ROM preprocessing and postprocessing. + + All plugin classes should inherit from this class and override the + methods corresponding to the stages where they need to intervene. """ def fit_preprocessing(self, rom): - """ Void """ + """ + Execute before the fit process begins. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def fit_before_reduction(self, rom): - """ Void """ + """ + Execute before the reduction step during fit. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def fit_after_reduction(self, rom): - """ Void """ + """ + Execute after the reduction step during fit. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def fit_before_approximation(self, rom): - """ Void """ + """ + Execute before the approximation step during fit. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def fit_after_approximation(self, rom): - """ Void """ + """ + Execute after the approximation step during fit. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def fit_postprocessing(self, rom): - """ Void """ + """ + Execute after the fit process completes. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def predict_preprocessing(self, rom): - """ Void """ + """ + Execute before the prediction process begins. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def predict_before_approximation(self, rom): - """ Void """ + """ + Execute before the approximation step during prediction. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def predict_after_approximation(self, rom): - """ Void """ + """ + Execute after the approximation step during prediction. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def predict_before_expansion(self, rom): - """ Void """ + """ + Execute before the expansion step during prediction. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def predict_after_expansion(self, rom): - """ Void """ + """ + Execute after the expansion step during prediction. + + :param ReducedOrderModel rom: The ROM instance. + """ pass def predict_postprocessing(self, rom): - """ Void """ + """ + Execute after the prediction process completes. + + :param ReducedOrderModel rom: The ROM instance. + """ pass diff --git a/ezyrb/plugin/scaler.py b/ezyrb/plugin/scaler.py index 5f3012a0..012f5e42 100644 --- a/ezyrb/plugin/scaler.py +++ b/ezyrb/plugin/scaler.py @@ -19,8 +19,28 @@ class DatabaseScaler(Plugin): applied at the full order ('full') or at the reduced one ('reduced'). :param {'parameters', 'snapshots'} params: define if the rescaling has to be applied to the parameters or to the snapshots. + + :Example: + + >>> from ezyrb import ReducedOrderModel as ROM + >>> from ezyrb import POD, RBF, Database + >>> from ezyrb.plugin import DatabaseScaler + >>> from sklearn.preprocessing import StandardScaler + >>> pod = POD(rank=10) + >>> rbf = RBF() + >>> db = Database(params, snapshots) + >>> scaler = DatabaseScaler(StandardScaler(), 'full', 'snapshots') + >>> rom = ROM(db, pod, rbf, plugins=[scaler]) + >>> rom.fit() """ def __init__(self, scaler, mode, target) -> None: + """ + Initialize the DatabaseScaler plugin. + + :param scaler: Scaler object with fit, transform, and inverse_transform methods. + :param str mode: 'full' or 'reduced' - where to apply the scaling. + :param str target: 'parameters' or 'snapshots' - what to scale. + """ super().__init__() self.scaler = scaler @@ -60,10 +80,20 @@ def mode(self, new_mode): self._mode = new_mode def _select_matrix(self, db): - """ Helper function to select the proper matrix to rescale. """ + """ + Helper function to select the proper matrix to rescale. + + :param Database db: The database object. + :return: The selected matrix (parameters or snapshots). + """ return getattr(db, f'{self.target}_matrix') def rom_preprocessing(self, rom): + """ + Apply scaling to the reduced database before ROM processing. + + :param ReducedOrderModel rom: The ROM instance. + """ if self.mode != 'reduced': return diff --git a/ezyrb/plugin/shift.py b/ezyrb/plugin/shift.py index f077b36c..e4c92c81 100644 --- a/ezyrb/plugin/shift.py +++ b/ezyrb/plugin/shift.py @@ -46,6 +46,14 @@ class ShiftSnapshots(Plugin): """ def __init__(self, shift_function, interpolator, parameter_index=0, reference_index=0): + """ + Initialize the ShiftSnapshots plugin. + + :param callable shift_function: Function that returns the shift for a parameter. + :param Approximation interpolator: Interpolator for evaluating shifted snapshots. + :param int parameter_index: Index of parameter component for shift. Default is 0. + :param int reference_index: Index of reference snapshot. Default is 0. + """ super().__init__() self.__shift_function = shift_function @@ -54,6 +62,11 @@ def __init__(self, shift_function, interpolator, parameter_index=0, self.reference_index = reference_index def fit_preprocessing(self, rom): + """ + Shift snapshots to a reference space during fit preprocessing. + + :param ReducedOrderModel rom: The ROM instance. + """ db = rom.database reference_snapshot = db._pairs[self.reference_index][1] @@ -71,6 +84,11 @@ def fit_preprocessing(self, rom): rom.database = db def predict_postprocessing(self, rom): + """ + Shift predicted snapshots back to their original space. + + :param ReducedOrderModel rom: The ROM instance. + """ for param, snap in rom.predicted_full_database._pairs: snap.space = ( rom.database._pairs[self.reference_index][1].space + diff --git a/ezyrb/reducedordermodel.py b/ezyrb/reducedordermodel.py index 928dbbd9..31e2f83c 100644 --- a/ezyrb/reducedordermodel.py +++ b/ezyrb/reducedordermodel.py @@ -14,6 +14,26 @@ from abc import ABC, abstractmethod class ReducedOrderModelInterface(ABC): + """ + Abstract interface for Reduced Order Model classes. + + This class defines the common interface and plugin execution mechanism + for all ROM implementations. + + :Example: + + >>> from ezyrb import ReducedOrderModel as ROM + >>> from ezyrb import POD, RBF, Database + >>> import numpy as np + >>> params = np.array([[1.0], [2.0], [3.0]]) + >>> snapshots = np.random.rand(3, 100) + >>> db = Database(params, snapshots) + >>> pod = POD(rank=5) + >>> rbf = RBF() + >>> rom = ROM(db, pod, rbf) + >>> rom.fit() + >>> prediction = rom.predict([[1.5]]) + """ def _execute_plugins(self, when): """ @@ -73,6 +93,14 @@ class ReducedOrderModel(ReducedOrderModelInterface): """ def __init__(self, database, reduction, approximation, plugins=None): + """ + Initialize a Reduced Order Model. + + :param Database database: The database for training. + :param Reduction reduction: The reduction method. + :param Approximation approximation: The approximation method. + :param list plugins: List of plugins. Default is None. + """ self.database = database self.reduction = reduction @@ -86,6 +114,12 @@ def __init__(self, database, reduction, approximation, self.clean() def clean(self): + """ + Clean all internal databases used during training and prediction. + + This method resets all training, prediction, test, and validation + databases to None. + """ self.train_full_database = None self.train_reduced_database = None self.predict_full_database = None @@ -160,6 +194,14 @@ def n_approximation(self): return len(value_) if isinstance(value_, class_) else 1 def fit_reduction(self): + """ + Fit the reduction method on the training database. + + This method applies the reduction technique to the snapshots matrix + of the training database. + + :raises RuntimeError: If the training database has not been set. + """ # for k, rom_ in self.roms.items(): # rom_['reduction'].fit(rom_['database'].snapshots_matrix.T) @@ -169,12 +211,27 @@ def fit_reduction(self): self.reduction.fit(self.train_full_database.snapshots_matrix.T) def _reduce_database(self, db): + """ + Reduce a database using the fitted reduction method. + + :param Database db: The database to reduce. + :return: A new database with reduced snapshots. + :rtype: Database + """ return Database( db.parameters_matrix, self.reduction.transform(db.snapshots_matrix.T).T ) def fit_approximation(self): + """ + Fit the approximation method on the reduced training database. + + This method trains the approximation technique on the reduced space + representation of the snapshots. + + :raises RuntimeError: If the reduced training database has not been created. + """ if not hasattr(self, 'train_reduced_database'): raise RuntimeError @@ -525,6 +582,18 @@ class MultiReducedOrderModel(ReducedOrderModelInterface): """ def __init__(self, *args, plugins=None, rom_plugin=None): + """ + Initialize a Multi-ROM with multiple databases and methods. + + Supports multiple initialization signatures: + - (database_dict, reduction_dict, approximation_dict) + - (database, roms_dict) + - (roms_dict,) + + :param args: Variable arguments for different initialization modes. + :param list plugins: Global plugins for the Multi-ROM. Default is None. + :param rom_plugin: Plugin to add to each individual ROM. Default is None. + """ if len(args) == 3: self.database = args[0] diff --git a/ezyrb/reduction/pod.py b/ezyrb/reduction/pod.py index 3bde17a0..f0a547a9 100755 --- a/ezyrb/reduction/pod.py +++ b/ezyrb/reduction/pod.py @@ -94,10 +94,12 @@ def singular_values(self): def fit(self, X): """ - Create the reduced space for the given snapshots `X` using the - specified method - - :param numpy.ndarray X: the input snapshots matrix (stored by column) + Create the reduced space for the given snapshots using POD. + + Computes the POD modes and singular values using the specified method. + + :param numpy.ndarray X: The input snapshots matrix (stored by column). + :return: self """ if self._method is None: m = self.available_methods @@ -198,16 +200,17 @@ def _svd(self, X): def _rsvd(self, X): """ Truncated randomized Singular Value Decomposition. - - :param numpy.ndarray X: the matrix to decompose. - :return: the truncated left-singular vectors matrix, the truncated - singular values array, the truncated right-singular vectors matrix. - :rtype: numpy.ndarray, numpy.ndarray, numpy.ndarray - + + Computes an approximate SVD using randomized algorithms for efficiency. + + :param numpy.ndarray X: The matrix to decompose. + :return: Tuple of (truncated left-singular vectors, truncated singular values). + :rtype: tuple(numpy.ndarray, numpy.ndarray) + References: - Finding structure with randomness: probabilistic algorithms for - constructing approximate matrix decompositions. N. Halko, P. G. - Martinsson, J. A. Tropp. + Finding structure with randomness: probabilistic algorithms for + constructing approximate matrix decompositions. N. Halko, P. G. + Martinsson, J. A. Tropp. """ if ( self.omega_rank == 0 diff --git a/ezyrb/reduction/pod_ae.py b/ezyrb/reduction/pod_ae.py index c3c2d83a..e2e30149 100644 --- a/ezyrb/reduction/pod_ae.py +++ b/ezyrb/reduction/pod_ae.py @@ -11,14 +11,31 @@ class PODAE(POD, AE): """ - Feed-Forward AutoEncoder class with POD (AE) + Combined POD and AutoEncoder reduction class. + + This class first applies POD to reduce the dimensionality, then uses + an autoencoder for further reduction in the latent space. + + :param POD pod: The POD instance for initial reduction. + :param AE ae: The AutoEncoder instance for latent space reduction. """ def __init__(self, pod, ae): + """ + Initialize the PODAE reducer. + + :param POD pod: The POD instance. + :param AE ae: The AutoEncoder instance. + """ self.pod = pod self.ae = ae def fit(self, X): """ + Fit the PODAE on the snapshots. + + First applies POD, then trains the autoencoder on POD coefficients. + + :param numpy.ndarray X: The input snapshots matrix (stored by column). """ self.pod.fit(X) coefficients = self.pod.transform(X) diff --git a/ezyrb/reduction/reduction.py b/ezyrb/reduction/reduction.py index 05b8f2bb..a5bc15c6 100644 --- a/ezyrb/reduction/reduction.py +++ b/ezyrb/reduction/reduction.py @@ -5,9 +5,9 @@ class Reduction(ABC): """ - The abstract `Approximation` class. + The abstract Reduction class. - All the classes that implement the input-output mapping should be inherited + All the classes that implement dimensionality reduction should be inherited from this class. """ @abstractmethod diff --git a/ezyrb/regular_grid.py b/ezyrb/regular_grid.py index 01f28700..eab82f43 100644 --- a/ezyrb/regular_grid.py +++ b/ezyrb/regular_grid.py @@ -27,7 +27,7 @@ class RegularGrid(Approximation): >>> xg, yg, zg = np.meshgrid(x, y, z, indexing='ij') >>> points = np.c_[xg.ravel(), yg.ravel(), zg.ravel()] >>> data_mode_x = f(xg, yg, zg).reshape(-1, 1) - # lets assume we have 2 modes, i.e. a rank 2 model + >>> # lets assume we have 2 modes, i.e. a rank 2 model >>> data = np.concatenate((data_mode_x, data_mode_x/10), axis=1) >>> rgi = ezyrb.RegularGrid() >>> rgi.fit(points, data, method="linear") @@ -47,6 +47,11 @@ class RegularGrid(Approximation): """ def __init__(self): + """ + Initialize a RegularGrid interpolator. + + The interpolator will be configured during the fit method. + """ self.interpolator = None def get_grid_axes(self, pts_scrmbld, vals_scrmbld): diff --git a/ezyrb/snapshot.py b/ezyrb/snapshot.py index 1c907526..122231d4 100644 --- a/ezyrb/snapshot.py +++ b/ezyrb/snapshot.py @@ -5,8 +5,37 @@ class Snapshot: + """ + Class for representing a discretized solution snapshot. + + This class encapsulates solution values and their spatial coordinates, + providing methods for manipulation and visualization. + + :param array_like values: The solution values. + :param array_like space: The spatial coordinates corresponding to the values. + Default is None. + + :Example: + + >>> import numpy as np + >>> from ezyrb import Snapshot + >>> space = np.linspace(0, 1, 50) + >>> values = np.sin(2 * np.pi * space) + >>> snap = Snapshot(values, space) + >>> print(snap.values.shape) + (50,) + >>> print(snap.space.shape) + (50,) + """ def __init__(self, values, space=None): + """ + Initialize a Snapshot object. + + :param values: The solution values. Can be a Snapshot instance or + an array-like object. + :param space: The spatial coordinates. Default is None. + """ if isinstance(values, Snapshot): self.values = values.values self.space = values.space @@ -23,6 +52,12 @@ def values(self): @values.setter def values(self, new_values): + """ + Set the snapshot values with validation. + + :param array_like new_values: The new snapshot values. + :raises ValueError: If the length of new values doesn't match the space. + """ if hasattr(self, 'space') and self.space is not None: if len(self.space) != len(new_values): raise ValueError('invalid ndof for the current space.') @@ -38,6 +73,12 @@ def space(self): @space.setter def space(self, new_space): + """ + Set the snapshot space with validation. + + :param array_like new_space: The new spatial coordinates. + :raises ValueError: If the length of new space doesn't match the values. + """ if hasattr(self, 'values') and self.values is not None: if new_space is not None and len(self.values) != len(new_space): raise ValueError('invalid ndof for the current space.') diff --git a/pyproject.toml b/pyproject.toml index bd8f2305..48b8a998 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ezyrb" -version = "1.3.2" +version = "1.3.3" description = "Easy Reduced Basis" readme = "README.md" authors = [ diff --git a/tutorials/tutorial-1.ipynb b/tutorials/tutorial-1.ipynb index 2ba0c8a7..5a8a4303 100644 --- a/tutorials/tutorial-1.ipynb +++ b/tutorials/tutorial-1.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -53,10 +53,79 @@ "id": "crgTIhQYE6eg", "outputId": "6d45b951-fe2a-43c6-ce6f-68d3c6473080" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: ezyrb in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (1.3.2)\n", + "Requirement already satisfied: datasets in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (4.4.2)\n", + "Requirement already satisfied: future in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.0.0)\n", + "Requirement already satisfied: numpy in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (2.2.0)\n", + "Requirement already satisfied: scipy in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.14.1)\n", + "Requirement already satisfied: matplotlib in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (3.10.0)\n", + "Requirement already satisfied: scikit-learn in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.8.0)\n", + "Requirement already satisfied: torch in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (2.5.1)\n", + "Requirement already satisfied: filelock in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.16.1)\n", + "Requirement already satisfied: pyarrow>=21.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (22.0.0)\n", + "Requirement already satisfied: dill<0.4.1,>=0.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.4.0)\n", + "Requirement already satisfied: pandas in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.2.3)\n", + "Requirement already satisfied: requests>=2.32.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.32.3)\n", + "Requirement already satisfied: httpx<1.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.28.1)\n", + "Requirement already satisfied: tqdm>=4.66.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (4.67.1)\n", + "Requirement already satisfied: xxhash in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.6.0)\n", + "Requirement already satisfied: multiprocess<0.70.19 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.70.18)\n", + "Requirement already satisfied: fsspec<=2025.10.0,>=2023.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2025.10.0)\n", + "Requirement already satisfied: huggingface-hub<2.0,>=0.25.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (1.2.3)\n", + "Requirement already satisfied: packaging in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (24.2)\n", + "Requirement already satisfied: pyyaml>=5.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (6.0.2)\n", + "Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (3.11.10)\n", + "Requirement already satisfied: anyio in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (4.8.0)\n", + "Requirement already satisfied: certifi in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (2024.12.14)\n", + "Requirement already satisfied: httpcore==1.* in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (1.0.7)\n", + "Requirement already satisfied: idna in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (3.10)\n", + "Requirement already satisfied: h11<0.15,>=0.13 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpcore==1.*->httpx<1.0.0->datasets) (0.14.0)\n", + "Requirement already satisfied: hf-xet<2.0.0,>=1.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.2.0)\n", + "Requirement already satisfied: shellingham in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.5.4)\n", + "Requirement already satisfied: typer-slim in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (0.20.1)\n", + "Requirement already satisfied: typing-extensions>=3.7.4.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (4.12.2)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (3.4.0)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (2.2.3)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.3.1)\n", + "Requirement already satisfied: cycler>=0.10 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (4.55.3)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.4.7)\n", + "Requirement already satisfied: pillow>=8 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (11.0.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (3.2.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1)\n", + "Requirement already satisfied: tzdata>=2022.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1)\n", + "Requirement already satisfied: joblib>=1.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (1.5.3)\n", + "Requirement already satisfied: threadpoolctl>=3.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (3.6.0)\n", + "Requirement already satisfied: networkx in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.4.2)\n", + "Requirement already satisfied: jinja2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.1.4)\n", + "Requirement already satisfied: setuptools in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (75.6.0)\n", + "Requirement already satisfied: sympy==1.13.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (1.13.1)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from sympy==1.13.1->torch->ezyrb) (1.3.0)\n", + "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2.4.4)\n", + "Requirement already satisfied: aiosignal>=1.1.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.3.2)\n", + "Requirement already satisfied: attrs>=17.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (24.3.0)\n", + "Requirement already satisfied: frozenlist>=1.1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.5.0)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (6.1.0)\n", + "Requirement already satisfied: propcache>=0.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (0.2.1)\n", + "Requirement already satisfied: yarl<2.0,>=1.17.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.18.3)\n", + "Requirement already satisfied: six>=1.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib->ezyrb) (1.17.0)\n", + "Requirement already satisfied: sniffio>=1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from anyio->httpx<1.0.0->datasets) (1.3.1)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from jinja2->torch->ezyrb) (3.0.2)\n", + "Requirement already satisfied: click>=8.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from typer-slim->huggingface-hub<2.0,>=0.25.0->datasets) (8.3.1)\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.3.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.3\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], "source": [ - "!pip install git+https://github.com/mathLab/EZyRB.git\n", - "!pip install -U datasets huggingface_hub fsspec" + "!pip install ezyrb datasets" ] }, { @@ -98,7 +167,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -218,7 +287,15 @@ "id": "tPd-yhZxE6eh", "outputId": "0129fa04-7392-4e37-bdfd-c898b56c1c3e" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(8, 304) (8, 2)\n" + ] + } + ], "source": [ "from datasets import load_dataset\n", "data_path = \"kshitij-pandey/termal_dataset\"\n", @@ -304,10 +381,19 @@ "user_tz": -120 }, "id": "vz5WNjekE6eh", - "outputId": "e475b58b-4498-40e8-8ce6-bf93eab3bf9e", - "scrolled": false + "outputId": "e475b58b-4498-40e8-8ce6-bf93eab3bf9e" }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:7: SyntaxWarning: invalid escape sequence '\\m'\n", + "<>:7: SyntaxWarning: invalid escape sequence '\\m'\n", + "/var/folders/ls/wr1b_2ln19z7mjq6cg0gc04w0000gn/T/ipykernel_79367/955619631.py:7: SyntaxWarning: invalid escape sequence '\\m'\n", + " ax[i].set_title('($\\mu_0={:5.2f}, \\mu_1={:5.2f})$'.format(*param[i]))\n" + ] + }, { "data": { "image/png": "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n/+MBx98EAcccICW/bz66qvYf//9pc/HYGDRjnFy48aNmDFjRt37pVIJALgz3y5atAgPPPBAbTIdAhGnpORnusTJpH53aJiYZ2hV2jEWsghrPllImd327dsBmFgoep6iv00q+zGx0NBI2jkezpgxA+985ztrfz/44IPYdddda+dE4/XXX4fruvjEJz6BT3ziE3Wf77HHHrj44ouxevVqEw+NNjRIYIxKBkuWLAEAPPnkk7Ugu2nTJmzevLnm0BO++tWvYsuWLYEZvl566SV0d3cHekYPOuggPPfcc9T96RgP4oMf/CCuu+463Hrrrfj0pz8NoDKL2e23347FixdjwYIFAIDx8XG89tprmDVrVmAm6c2bN9eNq/E///M/+MlPfoJjjz0Wtm1L7YeHzPWURddYdirIXJ/wd+E4Dk455RSsXbsW9957b+0+jLsfAHjqqadw+umnaz1Xw/SmHePkW97yFvx//9//hz//+c+BHvLvf//7sG27dh6sOPmhD30IX/nKV/Cd73wH73nPe2rvf/vb30Y6na7N3Dpd4mSceCeLiXmGVqUdY6Go5mM9t5s2baplkhNKpRL+/d//HR0dHbVOVhMLxWKh6G+TyvU0sdDQSNoxHtK455578Pvf/x7XXXddZDw88MAD8aMf/ahu/SuuuAI7duzATTfdhL322guAiYdGGxqk8AxMDjzwQO+0006r/f3ggw96ALyenh7v4x//uHfTTTd5p512mjcwMOAB8P7v//2/3u9+9zvP8zzv0Ucf9XbffffA9j7/+c97H/vYxxI95pNPPtlLp9PeZz7zGe+b3/ymd8QRR3jpdNp75JFHasv86le/8gB4K1asCKz77ne/2zvuuOO8L3/5y96tt97qffKTn/Q6Ozu9vr4+709/+pP0fggAvCOPPLLufZnr6edjH/tY3bG3GqLXJ/xdXHzxxR4A7/jjj/e+973v1b1U9/Pkk096ALwHH3wwsXM2TE/aLU4+8sgjXiqV8ubMmeNdeeWV3i233OIde+yxHgDv3HPPrS3HipOe53kf/ehHPQDehz70Ie+WW27xTj75ZA+Ad/nllweWmy5xUjXeEW6++Wbvqquu8j7+8Y97ALwTTzzRu+qqq7yrrrrKGx4eVtqXiXmGRtNusVBU87Ge2xNOOMF7z3ve461cudL71re+5V111VXefvvt5wHwrr/++sCyJhbyY6Hob5PMfjzPxEJDc2i3ePjII494733ve71//dd/9b797W975557rpdKpbxjjjnGK5VKteWitGGYI4880nvrW99a976Jh0YbGsQwRmUEN9xwg9fd3e2Nj497nud5N954o5dKpbz77rvP22uvvbx8Pu/9wz/8g/fss896e+21l7frrrt669at8zzP85566ilvxowZge0tX77c+9SnPpXoMU9MTHif/vSnvcHBQS+Xy3nveMc7vPvvvz+wDCsg3HTTTd7hhx/uDQwMeOl02ps3b573kY98xHvppZeU9uN5nrdjxw4PgHfqqafWfSZzPf20g1Epen3C38WRRx7pAWC+VPfz2c9+1tttt90813W1n6thetOOcfLxxx/3jj32WG9wcNDLZDLeW97yFu/qq68WFqPFYtFbuXKlt/vuu3uZTMbbe++9vRtvvLFuuekSJ1XjHWH33XdnxrxXX31VaV8m5hkaTbvFQlHNx3puv//973tLly715s6d66XTaW/GjBne0qVLvXvvvbduXyYWBmFdU5HfJpn9eJ6JhYbm0G7x8OWXX/aOPvpob9asWV4ul/P2228/b9WqVV6hUAgsp8OoNPEwiNGGBhbGqIxgeHjYGxgY8L797W97nud555xzjrfPPvsIrbtjxw4vk8l4//u//1t776ijjvJuu+22RI61Vbnvvvs8y7K8Z555pu4zmevppx2MylZicnLSGxwc9FavXt3sQzHshJg4GR8TJ/ViYp6hGZhYGB8TC/ViYqGhWZh4GB8TD/Vi4mH7YceoGt/p6evrw2WXXYZrr70Wruvi2WefZU5sEqa7uxsf+MAHsGLFCkxMTOBnP/sZnnnmGXzgAx9I+Khbi1/96lc49dRTqWNlyFxPoDKQ+OTkJBzHCfzfEM3tt9+OTCaDCy64oNmHYtgJMXEyPiZO6sXEPEMzMLEwPiYW6sXEQkOzMPEwPiYe6sXEwzak2U5pu+C6rtfd3V03BlkUmzZt8o499livo6PD22effbwHHnggwSNsL1Su54oVK+pSv2+//fbkDtJgMEhh4qReTJw0GNoTEwv1YmKhwdC+mHioFxMPDdMFy/M8r/H2aPvxyiuvYK+99sL3vvc9fOQjH2n24bQ95noaDDsf5rnWi7meBkN7Yp5dvZjraTC0L+b51Yu5nobpgjEqDQaDwWAwGAwGg8FgMBgMBkPT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pk0oFos49dRT8c1vfrNDLeWjcw5333132+ddLBY72Np2/uVf/gVvfvObsWHDBnieh6997WvSbR5++GG87nWvQ6FQwAknnIC777479XY6OoPrC7vTFwKuP+x2f+j6Qkcc1x86bWhKP/eFgOsPHVFcX+i0YRL6uT90fWFvsqqMykqlgre97W14//vfr7zNpz/9adx222248847sWfPHgwNDWHbtm0olUoptpTPJZdcgp/+9Kd46KGH8E//9E/4l3/5F1x55ZXS7a644gq89NJLreXTn/50B1oLPPDAA7jmmmtw/fXX40c/+hFOP/10bNu2Dfv372eu/4Mf/ADvfOc7cfnll+PHP/4xLrroIlx00UV48sknO9JeFrrnAACjo6ORz/uXv/xlB1vczuLiIk4//XTccccdSus/++yzeNOb3oTf+I3fwOOPP46rrroK733ve/Gtb30r5ZY6OoHrCzvfFwKuP+yF/tD1hY44rj902tCEfu8LAdcfOqK4vtBpQ1P6vT90fWGPEq5C/uZv/iYcGxuTrhcEQTg1NRX+2Z/9Weu12dnZsFAohH/3d3+XYgvZ/Pu//3sIIPzhD3/Yeu3//J//E3qeF77wwgvc7V7/+teHf/iHf9iBFrZzzjnnhP/rf/2v1t/1ej3csGFDeNNNNzHXf/vb3x6+6U1viry2efPm8H3ve1+q7RShew6q91e3ABA++OCDwnU+/OEPh6997Wsjr73jHe8It23blmLLHJ3G9YWdxfWHvYXrCx00rj/sHK4v7D1cf+gguL6ws7j+sLdwfWHvsKoiKnV59tlnMT09ja1bt7ZeGxsbw+bNm7F79+6Ot2f37t0YHx/H2Wef3Xpt69at8H0fe/bsEW577733Yt26dfi1X/s1XHvttVhaWkq7uahUKnjssccin5/v+9i6dSv389u9e3dkfQDYtm1bVz5vwOwcAGBhYQHHHHMMNm7ciLe85S346U9/2onmWqPXroOju7i+MDmuP+zP/rDXroGj+7j+MBmuL+zPvhDovevg6C6uL0yO6w/7sz/stWtwuJLtdgN6menpaQDA+vXrI6+vX7++9V6n23PEEUdEXstms5iYmBC253d/93dxzDHHYMOGDfjJT36CP/qjP8LevXvx1a9+NdX2vvLKK6jX68zP72c/+xlzm+np6Z75vAGzczjppJNw11134bTTTsOhQ4dw880349xzz8VPf/pTHH300Z1odmJ412Fubg7Ly8sYGBjoUssc3cD1hclx/WF/9oeuL3TEcf1hMlxf2J99IeD6Q0cU1xcmx/WH/dkfur6wM/R9ROWOHTvairHGF96XpFdI+xyuvPJKbNu2DaeeeiouueQS3HPPPXjwwQfxzDPPWDwLB2HLli249NJLccYZZ+D1r389vvrVr2JychJ/+Zd/2e2mOQ5jXF8ox/WFncf1h45u4PpDOa4/7CyuL3R0A9cXynF9Yedx/aFDhb6PqPzgBz+I97znPcJ1jj/+eKN9T01NAQD27duHI488svX6vn37cMYZZxjtk4XqOUxNTbUVpa3VapiZmWm1VYXNmzcDAJ5++mm8+tWv1m6vKuvWrUMmk8G+ffsir+/bt4/b3qmpKa3108bkHOLkcjmceeaZePrpp9NoYirwrsPo6KgbJepRXF/Yu30h4PpDQr/1h64v7E9cf9i7/aHrCxv0W18IuP6wH3F9Ye/2hYDrDwn91h+6vrAz9L1ROTk5icnJyVT2fdxxx2Fqagq7du1qdbhzc3PYs2eP1oxoMlTPYcuWLZidncVjjz2Gs846CwDwne98B0EQtDpVFR5//HEAiDxU0iCfz+Oss87Crl27cNFFFwEAgiDArl27sH37duY2W7Zswa5du3DVVVe1XnvooYewZcuWVNvKw+Qc4tTrdTzxxBO48MILU2ypXbZs2YJvfvObkde6eR0cclxf2Lt9IeD6Q0K/9YeuL+xPXH/Yu/2h6wsb9FtfCLj+sB9xfWHv9oWA6w8J/dYfur6wQ3R7Np9O8stf/jL88Y9/HN5www3h8PBw+OMf/zj88Y9/HM7Pz7fWOemkk8KvfvWrrb//9E//NBwfHw//4R/+IfzJT34SvuUtbwmPO+64cHl5uRunEF5wwQXhmWeeGe7Zsyf83ve+F5544onhO9/5ztb7v/rVr8KTTjop3LNnTxiGYfj000+HN954Y/joo4+Gzz77bPgP//AP4fHHHx/++q//ekfae//994eFQiG8++67w3//938Pr7zyynB8fDycnp4OwzAM3/Wud4U7duxorf/9738/zGaz4c033xw+9dRT4fXXXx/mcrnwiSee6Eh7Weieww033BB+61vfCp955pnwscceCy+++OKwWCyGP/3pT7t1CuH8/HzrfgcQfvaznw1//OMfh7/85S/DMAzDHTt2hO9617ta6//iF78IBwcHww996EPhU089Fd5xxx1hJpMJd+7c2a1TcFjE9YWd7wvD0PWHvdAfur7QEcf1h04bmtDvfWEYuv7QEcX1hU4bmtLv/aHrC3uTVWVUvvvd7w4BtC3f/e53W+sACP/mb/6m9XcQBOFHP/rRcP369WGhUAjPP//8cO/evZ1vfJMDBw6E73znO8Ph4eFwdHQ0vOyyyyIPkGeffTZyTs8991z467/+6+HExERYKBTCE044IfzQhz4UHjp0qGNtvv3228NXvepVYT6fD88555zw//2//9d67/Wvf3347ne/O7L+l770pfA1r3lNmM/nw9e+9rXhN77xjY61lYfOOVx11VWtddevXx9eeOGF4Y9+9KMutHqF7373u8x7n7T73e9+d/j617++bZszzjgjzOfz4fHHHx/5Xjj6G9cXdqcvDEPXH3a7P3R9oSOO6w+dNjSln/vCMHT9oSOK6wudNkxCP/eHri/sTbwwDEO7MZoOh8PhcDgcDofD4XA4HA6Hw6FH38/67XA4HA6Hw+FwOBwOh8PhcDj6H2dUOhwOh8PhcDgcDofD4XA4HI6u44xKh8PhcDgcDofD4XA4HA6Hw9F1nFHpcDgcDofD4XA4HA6Hw+FwOLqOMyodDofD4XA4HA6Hw+FwOBwOR9dxRqXD4XA4HA6Hw+FwOBwOh8Ph6DrOqHQ4HA6Hw+FwOBwOh8PhcDgcXccZlQ6Hw+FwOBwOh8PhcDgcDoej6zij0uFwOBwOh8PhcDgcDofD4XB0HWdUOhwOh8PhcDgcDofD4XA4HI6u44xKh8PhcDgcDofD4XA4HA6Hw9F1nFHpcDgcDofD4XA4HA6Hw+FwOLrO/w8Cgp5R7C2KcAAAAABJRU5ErkJggg==", @@ -444,8 +530,7 @@ }, "user_tz": -120 }, - "id": "gCFG7gMEE6ei", - "scrolled": false + "id": "gCFG7gMEE6ei" }, "outputs": [], "source": [ @@ -482,7 +567,7 @@ "outputs": [], "source": [ "new_mu = [8, 1]\n", - "pred_sol = rom.predict(new_mu).snapshots_matrix" + "pred_sol = rom.predict(new_mu)" ] }, { @@ -535,78 +620,6 @@ "plt.colorbar();" ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "Yzlin7bTE6ei" - }, - "source": [ - "... or interactively touch the input parameters to visualize the corresponding (approximated) output. For a fancy result, we need a bit of IPython black magic ([https://ipywidgets.readthedocs.io/en/latest/]())." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 663, - "referenced_widgets": [ - "daac6623145c47238e1d8b6c100d12b6", - "23ec282b04404d979c21c6289e7d5e6e", - "9c9af003b41d4beb88930932284195d2", - "208fda4c41724814ac8af35c7d0f9730", - "95a5b6690a7947d7919e392ddbb01e5e", - "7dc03b84a506423bad15f48c99df25c6", - "779c185c4ab24f6eaa6b8224266d1c35", - "d8cadba81b6a403987682dfff2c8db7d", - "0bf1b44a7d7d4264a879100646d73dc1", - "349cc36fda8d4aec899d0522853af301" - ] - }, - "executionInfo": { - "elapsed": 272, - "status": "ok", - "timestamp": 1753304413556, - "user": { - "displayName": "Kshitij Kumar Pandey", - "userId": "07153743731363514895" - }, - "user_tz": -120 - }, - "id": "X0Rjkqu8E6ei", - "outputId": "eab78d99-3155-4495-b964-3f1d8bacb40a" - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "daac6623145c47238e1d8b6c100d12b6", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=8, description='mu0', max=24, min=-8), IntSlider(value=1, description='m\u2026" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from ipywidgets import interact\n", - "\n", - "def plot_solution(mu0, mu1):\n", - " new_mu = [mu0, mu1]\n", - " pred_sol = rom.predict(new_mu).snapshots_matrix\n", - " plt.figure(figsize=(8, 7))\n", - " plt.triplot(triang, 'b-', lw=0.1)\n", - " plt.tripcolor(triang, *pred_sol)\n", - " plt.colorbar()\n", - "\n", - "interact(plot_solution, mu0=8, mu1=1);" - ] - }, { "cell_type": "markdown", "metadata": { @@ -620,7 +633,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -644,14 +657,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "[ 0.5 -0.2] 0.3830555986412092\n", - "[8.6 0.1] 0.5972596749801184\n", - "[5.3 0.8] 0.8082744257222021\n", - "[9.4 0.1] 0.4105803285232642\n", - "[ 7.3 -0.8] 0.550586354405444\n", - "[0.2 0.8] 0.07567485849711783\n", - "[ 3.5 -0.5] 0.6694924769868595\n", - "[0.3 0.6] 0.0647861921856285\n" + "[ 0.5 -0.2] 0.3830555986412087\n", + "[8.6 0.1] 0.5972596749801533\n", + "[5.3 0.8] 0.8082744257222089\n", + "[9.4 0.1] 0.4105803285232253\n", + "[ 7.3 -0.8] 0.5505863544054451\n", + "[0.2 0.8] 0.07567485849711765\n", + "[ 3.5 -0.5] 0.66949247698686\n", + "[0.3 0.6] 0.06478619218562698\n" ] } ], @@ -671,7 +684,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -696,7 +709,7 @@ "array([[ 5.2487694 , -0.06339911]])" ] }, - "execution_count": 14, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -720,7 +733,7 @@ "provenance": [] }, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -734,9 +747,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.12.8" } }, "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file + "nbformat_minor": 4 +} diff --git a/tutorials/tutorial-2.ipynb b/tutorials/tutorial-2.ipynb index 369d0a8c..d90edbd8 100644 --- a/tutorials/tutorial-2.ipynb +++ b/tutorials/tutorial-2.ipynb @@ -1,17 +1,5 @@ { "cells": [ - { - "cell_type": "markdown", - "id": "43a48f08", - "metadata": { - "id": "43a48f08", - "toc": true - }, - "source": [ - "

Table of Contents

\n", - "" - ] - }, { "cell_type": "markdown", "id": "b0c39fb4", @@ -25,10 +13,9 @@ "In this tutorial, we will explain step by step how to use the **EZyRB** library to test different techniques for building the reduced order model. We will compare different methods of dimensionality reduction, interpolation and accuracy assessment.\n", "\n", "We consider here a computational fluid dynamics problem described by the (incompressible) Navier Stokes equations.\n", - "We will be using the **Navier Stokes Dataset** that contains the output data from a full order flow simulation and can be found on **GitHub** under [Smithers library](https://github.com/mathLab/Smithers).\n", - "**Smithers** is developed by **SISSA mathlab** and it contains some useful datasets and a multi-purpose toolbox that inherits functionality from other packages to make the process of dealing with these datasets much easier with more compact coding.\n", + "We will be using the **Navier Stokes Dataset** that contains the output data from a full order flow simulation and can be found on **Hugging Face Datasets**\n", "\n", - "The package can be installed using `python -m pip install smithers -U`, but for a detailed description about installation and usage we refer to original [Github page](https://github.com/mathLab/Smithers/blob/master/README.md).\n", + "The package can be installed using `python -m pip install datasets`, but for a detailed description about installation and usage we refer to original [Github page](https://huggingface.co/docs/datasets/index).\n", "\n", "First of all, we just import the package and instantiate the dataset object." ] @@ -41,7 +28,6 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "collapsed": true, "executionInfo": { "elapsed": 114377, "status": "ok", @@ -60,200 +46,79 @@ "name": "stdout", "output_type": "stream", "text": [ - "Requirement already satisfied: datasets in /usr/local/lib/python3.11/dist-packages (2.14.4)\n", - "Collecting datasets\n", - " Downloading datasets-4.0.0-py3-none-any.whl.metadata (19 kB)\n", - "Requirement already satisfied: huggingface_hub in /usr/local/lib/python3.11/dist-packages (0.33.4)\n", - "Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (2025.7.0)\n", - "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from datasets) (3.18.0)\n", - "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/dist-packages (from datasets) (2.0.2)\n", - "Requirement already satisfied: pyarrow>=15.0.0 in /usr/local/lib/python3.11/dist-packages (from datasets) (18.1.0)\n", - "Requirement already satisfied: dill<0.3.9,>=0.3.0 in /usr/local/lib/python3.11/dist-packages (from datasets) (0.3.7)\n", - "Requirement already satisfied: pandas in /usr/local/lib/python3.11/dist-packages (from datasets) (2.2.2)\n", - "Requirement already satisfied: requests>=2.32.2 in /usr/local/lib/python3.11/dist-packages (from datasets) (2.32.3)\n", - "Requirement already satisfied: tqdm>=4.66.3 in /usr/local/lib/python3.11/dist-packages (from datasets) (4.67.1)\n", - "Requirement already satisfied: xxhash in /usr/local/lib/python3.11/dist-packages (from datasets) (3.5.0)\n", - "Requirement already satisfied: multiprocess<0.70.17 in /usr/local/lib/python3.11/dist-packages (from datasets) (0.70.15)\n", - "Collecting fsspec\n", - " Downloading fsspec-2025.3.0-py3-none-any.whl.metadata (11 kB)\n", - "Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from datasets) (25.0)\n", - "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.11/dist-packages (from datasets) (6.0.2)\n", - "Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.11/dist-packages (from huggingface_hub) (4.14.1)\n", - "Requirement already satisfied: hf-xet<2.0.0,>=1.1.2 in /usr/local/lib/python3.11/dist-packages (from huggingface_hub) (1.1.5)\n", - "Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /usr/local/lib/python3.11/dist-packages (from fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (3.11.15)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (3.4.2)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (3.10)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (2.5.0)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (2025.7.14)\n", - "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas->datasets) (2.9.0.post0)\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas->datasets) (2025.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas->datasets) (2025.2)\n", - "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (2.6.1)\n", - "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (1.4.0)\n", - "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (25.3.0)\n", - "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (1.7.0)\n", - "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (6.6.3)\n", - "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (0.3.2)\n", - "Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (1.20.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.17.0)\n", - "Downloading datasets-4.0.0-py3-none-any.whl (494 kB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m494.8/494.8 kB\u001b[0m \u001b[31m9.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading fsspec-2025.3.0-py3-none-any.whl (193 kB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m193.6/193.6 kB\u001b[0m \u001b[31m12.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hInstalling collected packages: fsspec, datasets\n", - " Attempting uninstall: fsspec\n", - " Found existing installation: fsspec 2025.7.0\n", - " Uninstalling fsspec-2025.7.0:\n", - " Successfully uninstalled fsspec-2025.7.0\n", - " Attempting uninstall: datasets\n", - " Found existing installation: datasets 2.14.4\n", - " Uninstalling datasets-2.14.4:\n", - " Successfully uninstalled datasets-2.14.4\n", - "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", - "torch 2.6.0+cu124 requires nvidia-cublas-cu12==12.4.5.8; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cublas-cu12 12.5.3.2 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cuda-cupti-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cuda-cupti-cu12 12.5.82 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cuda-nvrtc-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cuda-nvrtc-cu12 12.5.82 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cuda-runtime-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cuda-runtime-cu12 12.5.82 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cudnn-cu12==9.1.0.70; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cudnn-cu12 9.3.0.75 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cufft-cu12==11.2.1.3; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cufft-cu12 11.2.3.61 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-curand-cu12==10.3.5.147; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-curand-cu12 10.3.6.82 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cusolver-cu12==11.6.1.9; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cusolver-cu12 11.6.3.83 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-cusparse-cu12==12.3.1.170; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-cusparse-cu12 12.5.1.3 which is incompatible.\n", - "torch 2.6.0+cu124 requires nvidia-nvjitlink-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\", but you have nvidia-nvjitlink-cu12 12.5.82 which is incompatible.\n", - "gcsfs 2025.7.0 requires fsspec==2025.7.0, but you have fsspec 2025.3.0 which is incompatible.\u001b[0m\u001b[31m\n", - "\u001b[0mSuccessfully installed datasets-4.0.0 fsspec-2025.3.0\n", - "Collecting git+https://github.com/mathLab/EZyRB.git\n", - " Cloning https://github.com/mathLab/EZyRB.git to /tmp/pip-req-build-zstm9rsm\n", - " Running command git clone --filter=blob:none --quiet https://github.com/mathLab/EZyRB.git /tmp/pip-req-build-zstm9rsm\n", - " Resolved https://github.com/mathLab/EZyRB.git to commit 0f4ffb73d2c32808cbf965f4f1d566f18ad54f1a\n", - " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: future in /usr/local/lib/python3.11/dist-packages (from ezyrb==1.3.0) (1.0.0)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.11/dist-packages (from ezyrb==1.3.0) (2.0.2)\n", - "Requirement already satisfied: scipy in /usr/local/lib/python3.11/dist-packages (from ezyrb==1.3.0) (1.16.0)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (from ezyrb==1.3.0) (3.10.0)\n", - "Requirement already satisfied: scikit-learn>=1.0 in /usr/local/lib/python3.11/dist-packages (from ezyrb==1.3.0) (1.6.1)\n", - "Requirement already satisfied: torch in /usr/local/lib/python3.11/dist-packages (from ezyrb==1.3.0) (2.6.0+cu124)\n", - "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.0->ezyrb==1.3.0) (1.5.1)\n", - "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.0->ezyrb==1.3.0) (3.6.0)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (1.3.2)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (4.59.0)\n", - "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (1.4.8)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (25.0)\n", - "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (11.3.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (3.2.3)\n", - "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib->ezyrb==1.3.0) (2.9.0.post0)\n", - "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (3.18.0)\n", - "Requirement already satisfied: typing-extensions>=4.10.0 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (4.14.1)\n", - "Requirement already satisfied: networkx in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (3.5)\n", - "Requirement already satisfied: jinja2 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (3.1.6)\n", - "Requirement already satisfied: fsspec in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (2025.3.0)\n", - "Collecting nvidia-cuda-nvrtc-cu12==12.4.127 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cuda-runtime-cu12==12.4.127 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cuda-cupti-cu12==12.4.127 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-cudnn-cu12==9.1.0.70 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-cublas-cu12==12.4.5.8 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cufft-cu12==11.2.1.3 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-curand-cu12==10.3.5.147 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cusolver-cu12==11.6.1.9 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-cusparse-cu12==12.3.1.170 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl.metadata (1.6 kB)\n", - "Requirement already satisfied: nvidia-cusparselt-cu12==0.6.2 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (0.6.2)\n", - "Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (2.21.5)\n", - "Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (12.4.127)\n", - "Collecting nvidia-nvjitlink-cu12==12.4.127 (from torch->ezyrb==1.3.0)\n", - " Downloading nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "Requirement already satisfied: triton==3.2.0 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (3.2.0)\n", - "Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.11/dist-packages (from torch->ezyrb==1.3.0) (1.13.1)\n", - "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy==1.13.1->torch->ezyrb==1.3.0) (1.3.0)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib->ezyrb==1.3.0) (1.17.0)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2->torch->ezyrb==1.3.0) (3.0.2)\n", - "Downloading nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl (363.4 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m363.4/363.4 MB\u001b[0m \u001b[31m4.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl (13.8 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m13.8/13.8 MB\u001b[0m \u001b[31m50.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl (24.6 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m24.6/24.6 MB\u001b[0m \u001b[31m31.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl (883 kB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m883.7/883.7 kB\u001b[0m \u001b[31m23.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl (664.8 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m664.8/664.8 MB\u001b[0m \u001b[31m3.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl (211.5 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m211.5/211.5 MB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl (56.3 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m56.3/56.3 MB\u001b[0m \u001b[31m11.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl (127.9 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m127.9/127.9 MB\u001b[0m \u001b[31m7.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl (207.5 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m207.5/207.5 MB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl (21.1 MB)\n", - "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m21.1/21.1 MB\u001b[0m \u001b[31m71.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hBuilding wheels for collected packages: ezyrb\n", - " Building wheel for ezyrb (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for ezyrb: filename=ezyrb-1.3.0-py3-none-any.whl size=67486 sha256=fdc14012a4b7bbfc70171c842e0069c594d8b72862d8a83b52f608da8c441d80\n", - " Stored in directory: /tmp/pip-ephem-wheel-cache-hz3_4hgh/wheels/76/b3/98/4e81f7f467dd86d4f665265261e62b782f718d6d1ce2919faa\n", - "Successfully built ezyrb\n", - "Installing collected packages: nvidia-nvjitlink-cu12, nvidia-curand-cu12, nvidia-cufft-cu12, nvidia-cuda-runtime-cu12, nvidia-cuda-nvrtc-cu12, nvidia-cuda-cupti-cu12, nvidia-cublas-cu12, nvidia-cusparse-cu12, nvidia-cudnn-cu12, nvidia-cusolver-cu12, ezyrb\n", - " Attempting uninstall: nvidia-nvjitlink-cu12\n", - " Found existing installation: nvidia-nvjitlink-cu12 12.5.82\n", - " Uninstalling nvidia-nvjitlink-cu12-12.5.82:\n", - " Successfully uninstalled nvidia-nvjitlink-cu12-12.5.82\n", - " Attempting uninstall: nvidia-curand-cu12\n", - " Found existing installation: nvidia-curand-cu12 10.3.6.82\n", - " Uninstalling nvidia-curand-cu12-10.3.6.82:\n", - " Successfully uninstalled nvidia-curand-cu12-10.3.6.82\n", - " Attempting uninstall: nvidia-cufft-cu12\n", - " Found existing installation: nvidia-cufft-cu12 11.2.3.61\n", - " Uninstalling nvidia-cufft-cu12-11.2.3.61:\n", - " Successfully uninstalled nvidia-cufft-cu12-11.2.3.61\n", - " Attempting uninstall: nvidia-cuda-runtime-cu12\n", - " Found existing installation: nvidia-cuda-runtime-cu12 12.5.82\n", - " Uninstalling nvidia-cuda-runtime-cu12-12.5.82:\n", - " Successfully uninstalled nvidia-cuda-runtime-cu12-12.5.82\n", - " Attempting uninstall: nvidia-cuda-nvrtc-cu12\n", - " Found existing installation: nvidia-cuda-nvrtc-cu12 12.5.82\n", - " Uninstalling nvidia-cuda-nvrtc-cu12-12.5.82:\n", - " Successfully uninstalled nvidia-cuda-nvrtc-cu12-12.5.82\n", - " Attempting uninstall: nvidia-cuda-cupti-cu12\n", - " Found existing installation: nvidia-cuda-cupti-cu12 12.5.82\n", - " Uninstalling nvidia-cuda-cupti-cu12-12.5.82:\n", - " Successfully uninstalled nvidia-cuda-cupti-cu12-12.5.82\n", - " Attempting uninstall: nvidia-cublas-cu12\n", - " Found existing installation: nvidia-cublas-cu12 12.5.3.2\n", - " Uninstalling nvidia-cublas-cu12-12.5.3.2:\n", - " Successfully uninstalled nvidia-cublas-cu12-12.5.3.2\n", - " Attempting uninstall: nvidia-cusparse-cu12\n", - " Found existing installation: nvidia-cusparse-cu12 12.5.1.3\n", - " Uninstalling nvidia-cusparse-cu12-12.5.1.3:\n", - " Successfully uninstalled nvidia-cusparse-cu12-12.5.1.3\n", - " Attempting uninstall: nvidia-cudnn-cu12\n", - " Found existing installation: nvidia-cudnn-cu12 9.3.0.75\n", - " Uninstalling nvidia-cudnn-cu12-9.3.0.75:\n", - " Successfully uninstalled nvidia-cudnn-cu12-9.3.0.75\n", - " Attempting uninstall: nvidia-cusolver-cu12\n", - " Found existing installation: nvidia-cusolver-cu12 11.6.3.83\n", - " Uninstalling nvidia-cusolver-cu12-11.6.3.83:\n", - " Successfully uninstalled nvidia-cusolver-cu12-11.6.3.83\n", - "Successfully installed ezyrb-1.3.0 nvidia-cublas-cu12-12.4.5.8 nvidia-cuda-cupti-cu12-12.4.127 nvidia-cuda-nvrtc-cu12-12.4.127 nvidia-cuda-runtime-cu12-12.4.127 nvidia-cudnn-cu12-9.1.0.70 nvidia-cufft-cu12-11.2.1.3 nvidia-curand-cu12-10.3.5.147 nvidia-cusolver-cu12-11.6.1.9 nvidia-cusparse-cu12-12.3.1.170 nvidia-nvjitlink-cu12-12.4.127\n" + "Requirement already satisfied: datasets in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (4.4.2)\n", + "Requirement already satisfied: ezyrb in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (1.3.2)\n", + "Requirement already satisfied: filelock in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.16.1)\n", + "Requirement already satisfied: numpy>=1.17 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.2.0)\n", + "Requirement already satisfied: pyarrow>=21.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (22.0.0)\n", + "Requirement already satisfied: dill<0.4.1,>=0.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.4.0)\n", + "Requirement already satisfied: pandas in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.2.3)\n", + "Requirement already satisfied: requests>=2.32.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (2.32.3)\n", + "Requirement already satisfied: httpx<1.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.28.1)\n", + "Requirement already satisfied: tqdm>=4.66.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (4.67.1)\n", + "Requirement already satisfied: xxhash in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (3.6.0)\n", + "Requirement already satisfied: multiprocess<0.70.19 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (0.70.18)\n", + "Requirement already satisfied: fsspec<=2025.10.0,>=2023.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2025.10.0)\n", + "Requirement already satisfied: huggingface-hub<2.0,>=0.25.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (1.2.3)\n", + "Requirement already satisfied: packaging in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (24.2)\n", + "Requirement already satisfied: pyyaml>=5.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from datasets) (6.0.2)\n", + "Requirement already satisfied: future in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.0.0)\n", + "Requirement already satisfied: scipy in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.14.1)\n", + "Requirement already satisfied: matplotlib in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (3.10.0)\n", + "Requirement already satisfied: scikit-learn in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (1.8.0)\n", + "Requirement already satisfied: torch in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from ezyrb) (2.5.1)\n", + "Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (3.11.10)\n", + "Requirement already satisfied: anyio in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (4.8.0)\n", + "Requirement already satisfied: certifi in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (2024.12.14)\n", + "Requirement already satisfied: httpcore==1.* in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (1.0.7)\n", + "Requirement already satisfied: idna in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpx<1.0.0->datasets) (3.10)\n", + "Requirement already satisfied: h11<0.15,>=0.13 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from httpcore==1.*->httpx<1.0.0->datasets) (0.14.0)\n", + "Requirement already satisfied: hf-xet<2.0.0,>=1.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.2.0)\n", + "Requirement already satisfied: shellingham in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (1.5.4)\n", + "Requirement already satisfied: typer-slim in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (0.20.1)\n", + "Requirement already satisfied: typing-extensions>=3.7.4.3 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from huggingface-hub<2.0,>=0.25.0->datasets) (4.12.2)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (3.4.0)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from requests>=2.32.2->datasets) (2.2.3)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.3.1)\n", + "Requirement already satisfied: cycler>=0.10 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (4.55.3)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (1.4.7)\n", + "Requirement already satisfied: pillow>=8 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (11.0.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (3.2.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from matplotlib->ezyrb) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1)\n", + "Requirement already satisfied: tzdata>=2022.7 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from pandas->datasets) (2025.1)\n", + "Requirement already satisfied: joblib>=1.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (1.5.3)\n", + "Requirement already satisfied: threadpoolctl>=3.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from scikit-learn->ezyrb) (3.6.0)\n", + "Requirement already satisfied: networkx in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.4.2)\n", + "Requirement already satisfied: jinja2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (3.1.4)\n", + "Requirement already satisfied: setuptools in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (75.6.0)\n", + "Requirement already satisfied: sympy==1.13.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from torch->ezyrb) (1.13.1)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from sympy==1.13.1->torch->ezyrb) (1.3.0)\n", + "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (2.4.4)\n", + "Requirement already satisfied: aiosignal>=1.1.2 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.3.2)\n", + "Requirement already satisfied: attrs>=17.3.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (24.3.0)\n", + "Requirement already satisfied: frozenlist>=1.1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.5.0)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (6.1.0)\n", + "Requirement already satisfied: propcache>=0.2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (0.2.1)\n", + "Requirement already satisfied: yarl<2.0,>=1.17.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.10.0,>=2023.1.0->datasets) (1.18.3)\n", + "Requirement already satisfied: six>=1.5 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib->ezyrb) (1.17.0)\n", + "Requirement already satisfied: sniffio>=1.1 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from anyio->httpx<1.0.0->datasets) (1.3.1)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from jinja2->torch->ezyrb) (3.0.2)\n", + "Requirement already satisfied: click>=8.0.0 in /Users/ndemo/miniconda3/envs/pina/lib/python3.12/site-packages (from typer-slim->huggingface-hub<2.0,>=0.25.0->datasets) (8.3.1)\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.3.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.3\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" ] } ], "source": [ - "!pip install -U datasets huggingface_hub fsspec\n", - "!pip install git+https://github.com/mathLab/EZyRB.git" + "!pip install datasets ezyrb" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "2b772df3", "metadata": { "colab": { @@ -361,7 +226,6 @@ "79288985ebdb4a55b872bb66b203dd39" ] }, - "collapsed": true, "executionInfo": { "elapsed": 157144, "status": "ok", @@ -375,146 +239,7 @@ "id": "2b772df3", "outputId": "661dd5fe-e38e-468b-ddf8-9300bb744bec" }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.11/dist-packages/huggingface_hub/utils/_auth.py:94: UserWarning: \n", - "The secret `HF_TOKEN` does not exist in your Colab secrets.\n", - "To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n", - "You will be able to reuse this secret in all of your notebooks.\n", - "Please note that authentication is recommended but still optional to access public models or datasets.\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "99f28686dd9746e4809bc8edf12f4fe1", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "README.md: 0.00B [00:00, ?B/s]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b2479d90ffd6411daa2f38c3c6814278", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "train-00000-of-00001.parquet: 0%| | 0.00/26.1M [00:00" ] @@ -809,7 +533,7 @@ "\n", "fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 3))\n", "for i, param in enumerate(new_params):\n", - " ax[i].tricontourf(triang, *rom.predict([param]).snapshots_matrix)\n", + " ax[i].tricontourf(triang, *rom.predict([param]))\n", " ax[i].set_title('Predicted snapshots at inlet velocity = {}'.format(param))" ] }, @@ -858,13 +582,13 @@ "output_type": "stream", "text": [ "Average error for each fold:\n", - " 4.945136597864199e-07\n", - " 9.86076102695249e-07\n", - " 3.894778059089648e-06\n", - " 5.3036420477734276e-06\n", - " 1.298462179837029e-07\n", + " 4.945136635258633e-07\n", + " 9.860761253488605e-07\n", + " 3.894778057436833e-06\n", + " 5.303642035538002e-06\n", + " 1.2984622088905908e-07\n", "\n", - "Average error = 2.1617712174656897e-06\n" + "Average error = 2.1617712205477237e-06\n" ] } ], @@ -972,100 +696,113 @@ "name": "stdout", "output_type": "stream", "text": [ + "Processing POD-RBF\n", + "Processing POD-GPR\n", + "Processing POD-KNeighbors\n", + "Processing POD-RadiusNeighbors\n", + "Processing POD-ANN\n", + "[epoch 1]\t9.546327e+04\n", + "[epoch 10]\t9.538811e+04\n", + "[epoch 1]\t9.522560e+04\n", + "[epoch 10]\t9.515077e+04\n", + "[epoch 1]\t9.766096e+04\n", + "[epoch 10]\t9.758415e+04\n", + "[epoch 1]\t9.519630e+04\n", + "[epoch 10]\t9.512106e+04\n", + "[epoch 1]\t9.567339e+04\n", + "[epoch 10]\t9.559758e+04\n", + "[epoch 1]\t9.314678e+04\n", + "[epoch 10]\t9.307255e+04\n", + "Processing AE-RBF\n", + "[epoch 1]\t5.823453e+02\n", + "[epoch 10]\t5.556604e+02\n", + "[epoch 1]\t5.812169e+02\n", + "[epoch 10]\t8.230733e+01\n", + "[epoch 1]\t5.957941e+02\n", + "[epoch 10]\t9.019125e+01\n", + "[epoch 1]\t5.806075e+02\n", + "[epoch 10]\t6.687416e+01\n", + "[epoch 1]\t5.835210e+02\n", + "[epoch 10]\t7.294649e+01\n", + "[epoch 1]\t5.700542e+02\n", + "[epoch 10]\t7.343178e+01\n", + "Processing AE-GPR\n", + "[epoch 1]\t5.834352e+02\n", + "[epoch 10]\t7.699603e+01\n", + "[epoch 1]\t5.847290e+02\n", + "[epoch 10]\t1.470968e+02\n", + "[epoch 1]\t5.948226e+02\n", + "[epoch 10]\t7.184375e+01\n", + "[epoch 1]\t5.802390e+02\n", + "[epoch 10]\t7.155777e+01\n", + "[epoch 1]\t5.853676e+02\n", + "[epoch 10]\t1.150479e+02\n", + "[epoch 1]\t5.690804e+02\n", + "[epoch 10]\t6.931157e+01\n", + "Processing AE-KNeighbors\n", + "[epoch 1]\t5.819167e+02\n", + "[epoch 10]\t6.814513e+01\n", + "[epoch 1]\t5.820450e+02\n", + "[epoch 10]\t9.533990e+01\n", + "[epoch 1]\t5.980317e+02\n", + "[epoch 10]\t1.218049e+02\n", + "[epoch 1]\t5.849615e+02\n", + "[epoch 10]\t9.724957e+01\n", + "[epoch 1]\t5.848712e+02\n", + "[epoch 10]\t1.151645e+02\n", + "[epoch 1]\t5.692266e+02\n", + "[epoch 10]\t7.778555e+01\n", + "Processing AE-RadiusNeighbors\n", + "[epoch 1]\t5.845089e+02\n", + "[epoch 10]\t1.057290e+02\n", + "[epoch 1]\t5.836143e+02\n", + "[epoch 10]\t8.220594e+01\n", + "[epoch 1]\t5.969666e+02\n", + "[epoch 10]\t8.701730e+01\n", + "[epoch 1]\t5.823361e+02\n", + "[epoch 10]\t9.751357e+01\n", + "[epoch 1]\t5.850589e+02\n", + "[epoch 10]\t9.528002e+01\n", + "[epoch 1]\t5.675153e+02\n", + "[epoch 10]\t6.384907e+01\n", + "Processing AE-ANN\n", + "[epoch 1]\t5.835621e+02\n", + "[epoch 10]\t1.136382e+02\n", + "[epoch 1]\t4.710647e+03\n", + "[epoch 10]\t4.693913e+03\n", + "[epoch 1]\t5.837049e+02\n", + "[epoch 10]\t1.006396e+02\n", + "[epoch 1]\t6.297388e+03\n", + "[epoch 10]\t6.277451e+03\n", + "[epoch 1]\t6.003340e+02\n", + "[epoch 10]\t9.461213e+01\n", + "[epoch 1]\t3.808644e+03\n", + "[epoch 10]\t3.790863e+03\n", + "[epoch 1]\t5.810663e+02\n", + "[epoch 10]\t8.357424e+01\n", + "[epoch 1]\t5.692258e+03\n", + "[epoch 10]\t5.670917e+03\n", + "[epoch 1]\t5.863652e+02\n", + "[epoch 10]\t1.553782e+02\n", + "[epoch 1]\t4.325479e+03\n", + "[epoch 10]\t4.307963e+03\n", + "[epoch 1]\t5.707682e+02\n", + "[epoch 10]\t9.925204e+01\n", + "[epoch 1]\t5.734101e+03\n", + "[epoch 10]\t5.716063e+03\n", + "\n", + "\n", " RBF GPR KNeighbors RadiusNeighbors ANN\n", - "[epoch 1]\t9.552292e+04\n", - "[epoch 10]\t9.546308e+04\n", - "[epoch 1]\t9.717124e+04\n", - "[epoch 10]\t9.394288e+04\n", - "[epoch 1]\t9.390123e+04\n", - "[epoch 10]\t9.070695e+04\n", - "[epoch 1]\t9.016239e+04\n", - "[epoch 10]\t8.747394e+04\n", - "[epoch 1]\t9.297216e+04\n", - "[epoch 10]\t9.052832e+04\n", - "[epoch 1]\t9.303061e+04\n", - "[epoch 10]\t9.086118e+04\n", - "POD 1.204641e-05 2.970147e-05 8.032581e-03 1.091257e-02 9.720516e-01\n", - "[epoch 1]\t5.825196e+02\n", - "[epoch 10]\t5.575154e+02\n", - "[epoch 1]\t5.816525e+02\n", - "[epoch 10]\t7.542178e+01\n", - "[epoch 1]\t5.960423e+02\n", - "[epoch 10]\t7.254456e+01\n", - "[epoch 1]\t5.821843e+02\n", - "[epoch 10]\t1.140573e+02\n", - "[epoch 1]\t5.850476e+02\n", - "[epoch 10]\t8.712418e+01\n", - "[epoch 1]\t5.703002e+02\n", - "[epoch 10]\t9.224741e+01\n", - "[epoch 1]\t5.838640e+02\n", - "[epoch 10]\t9.697124e+01\n", - "[epoch 1]\t5.824384e+02\n", - "[epoch 10]\t8.382781e+01\n", - "[epoch 1]\t5.972413e+02\n", - "[epoch 10]\t1.000489e+02\n", - "[epoch 1]\t5.824288e+02\n", - "[epoch 10]\t1.159946e+02\n", - "[epoch 1]\t5.844561e+02\n", - "[epoch 10]\t8.188377e+01\n", - "[epoch 1]\t5.686895e+02\n", - "[epoch 10]\t9.589268e+01\n", - "[epoch 1]\t5.829741e+02\n", - "[epoch 10]\t1.057218e+02\n", - "[epoch 1]\t5.854851e+02\n", - "[epoch 10]\t1.984348e+02\n", - "[epoch 1]\t5.978563e+02\n", - "[epoch 10]\t9.254156e+01\n", - "[epoch 1]\t5.820558e+02\n", - "[epoch 10]\t1.060469e+02\n", - "[epoch 1]\t5.856129e+02\n", - "[epoch 10]\t6.725970e+01\n", - "[epoch 1]\t5.690880e+02\n", - "[epoch 10]\t8.200848e+01\n", - "[epoch 1]\t5.835947e+02\n", - "[epoch 10]\t8.691646e+01\n", - "[epoch 1]\t5.812208e+02\n", - "[epoch 10]\t6.915376e+01\n", - "[epoch 1]\t5.960715e+02\n", - "[epoch 10]\t7.712676e+01\n", - "[epoch 1]\t5.812619e+02\n", - "[epoch 10]\t8.149507e+01\n", - "[epoch 1]\t5.874238e+02\n", - "[epoch 10]\t1.011458e+02\n", - "[epoch 1]\t5.688601e+02\n", - "[epoch 10]\t7.845106e+01\n", - "[epoch 1]\t5.836358e+02\n", - "[epoch 10]\t9.010907e+01\n", - "[epoch 1]\t3.542524e+03\n", - "[epoch 10]\t2.990850e+03\n", - "[epoch 1]\t5.814325e+02\n", - "[epoch 10]\t8.633266e+01\n", - "[epoch 1]\t5.281078e+03\n", - "[epoch 10]\t4.688614e+03\n", - "[epoch 1]\t5.971737e+02\n", - "[epoch 10]\t1.139824e+02\n", - "[epoch 1]\t3.950016e+03\n", - "[epoch 10]\t3.483226e+03\n", - "[epoch 1]\t5.805435e+02\n", - "[epoch 10]\t7.528350e+01\n", - "[epoch 1]\t4.465279e+03\n", - "[epoch 10]\t3.919339e+03\n", - "[epoch 1]\t5.843740e+02\n", - "[epoch 10]\t8.277487e+01\n", - "[epoch 1]\t3.716152e+03\n", - "[epoch 10]\t3.085733e+03\n", - "[epoch 1]\t5.690876e+02\n", - "[epoch 10]\t7.657240e+01\n", - "[epoch 1]\t3.638531e+03\n", - "[epoch 10]\t3.177635e+03\n", - "AE 3.486621e-01 3.575820e-01 3.740117e-01 3.356829e-01 9.407356e-01\n" + "POD 1.204641e-05 2.970147e-05 8.032581e-03 1.091257e-02 9.975237e-01\n", + "AE 3.301131e-01 3.514848e-01 3.619394e-01 3.477732e-01 9.939129e-01\n", + "\n" ] } ], "source": [ "reductions = {\n", " 'POD': POD('svd',rank=10),\n", - " 'AE': AE([200, 100, 10], [10, 100, 200], nn.Tanh(), nn.Tanh(), 10),\n", + " 'AE': AE([200, 100, 10], [10, 100, 200], nn.Tanh(), nn.Tanh(), 10, frequency_print=-10),\n", "}\n", "\n", "approximations = {\n", @@ -1074,22 +811,25 @@ " 'GPR': GPR(),\n", " 'KNeighbors': KNeighborsRegressor(),\n", " 'RadiusNeighbors': RadiusNeighborsRegressor(),\n", - " 'ANN': ANN([20, 20], nn.Tanh(), 10),\n", + " 'ANN': ANN([20, 20], nn.Tanh(), 10, frequency_print=-10),\n", "}\n", "\n", - "header = '{:10s}'.format('')\n", + "s = '\\n\\n{:10s}'.format('')\n", "for name in approximations:\n", - " header += ' {:>15s}'.format(name)\n", + " s += ' {:>15s}'.format(name)\n", + "s += '\\n'\n", "\n", - "print(header)\n", "for redname, redclass in reductions.items():\n", " row = '{:10s}'.format(redname)\n", " for approxname, approxclass in approximations.items():\n", " rom = ROM(db, redclass, approxclass)\n", + " print(f\"Processing {redname}-{approxname}\")\n", " rom.fit()\n", " row += ' {:15e}'.format(rom.kfold_cv_error(n_splits=5).mean())\n", + " \n", + " s += f'{row}\\n'\n", "\n", - " print(row)\n" + "print(s)" ] }, { @@ -1148,7 +888,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.8" }, "latex_envs": { "LaTeX_envs_menu_present": true, @@ -1225,4 +965,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/tutorials/tutorial-3.ipynb b/tutorials/tutorial-3.ipynb index 4190a453..e0664f6d 100644 --- a/tutorials/tutorial-3.ipynb +++ b/tutorials/tutorial-3.ipynb @@ -580,7 +580,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.12.8" }, "toc-autonumbering": true }, diff --git a/tutorials/tutorial-4.ipynb b/tutorials/tutorial-4.ipynb index f6a3c7a0..9b1ab3bf 100644 --- a/tutorials/tutorial-4.ipynb +++ b/tutorials/tutorial-4.ipynb @@ -941,7 +941,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.12.8" } }, "nbformat": 4,