Skip to content

Commit

Permalink
docs: updating all docs
Browse files Browse the repository at this point in the history
  • Loading branch information
eckelsjd committed Nov 4, 2024
1 parent bf9b6e1 commit a1331b2
Show file tree
Hide file tree
Showing 45 changed files with 2,190 additions and 933 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
![build](https://img.shields.io/github/actions/workflow/status/eckelsjd/amisc/deploy.yml?logo=github)
![docs](https://img.shields.io/github/actions/workflow/status/eckelsjd/amisc/docs.yml?logo=materialformkdocs&logoColor=%2523cccccc&label=docs)
![tests](https://img.shields.io/github/actions/workflow/status/eckelsjd/amisc/tests.yml?logo=github&logoColor=%2523cccccc&label=tests)
![Code Coverage](https://img.shields.io/badge/coverage-47%25-orange?logo=codecov)
![Code Coverage](https://img.shields.io/badge/coverage-89%25-yellowgreen?logo=codecov)
[![Algorithm description](https://img.shields.io/badge/DOI-10.1002/nme.6958-blue)](https://doi.org/10.1002/nme.6958)

Efficient framework for building surrogates of multidisciplinary systems using the adaptive multi-index stochastic collocation ([AMISC](https://onlinelibrary.wiley.com/doi/full/10.1002/nme.6958)) technique.

## NOTICE: this branch is still undergoing major changes
Expect most things to not be working yet (documentation is also not up-to-date everywhere)

## ⚙️ Installation
Ensure you are using Python 3.11 or later. You can install the package from PyPI using pip:
```shell
pip install amisc
```
Expand All @@ -33,14 +31,18 @@ import numpy as np
from amisc import System

def fun1(x):
y1 = x * np.sin(np.pi * x)
return y1
y = x * np.sin(np.pi * x)
return y

def fun2(y1):
y2 = 1 / (1 + 25 * y1 ** 2)
return y2
def fun2(y):
z = 1 / (1 + 25 * y ** 2)
return z

system = System(fun1, fun2)

system.inputs()['x'].domain = (0, 1) # set domain of surrogate for `x`
system.outputs()['y'].domain = (0, 1) # set domain of surrogate for `y`

system.fit()

x_test = system.sample_inputs(10)
Expand Down
11 changes: 0 additions & 11 deletions TODO.md

This file was deleted.

37 changes: 0 additions & 37 deletions docs/TODOC.md

This file was deleted.

9 changes: 8 additions & 1 deletion docs/abbreviations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,12 @@
*[PDF]: Probability Distribution Function
*[MD]: Multidisciplinary
*[MF]: Multifidelity
*[MDMF]: Multi-Disciplinary Multi-Fidelity
*[MDMF]: Multi-Disciplinary / Multi-Fidelity
*[PDE]: Partial differential equation
*[SVD]: Singular value decomposition
*[QoIs]: Quantities of interest
*[DoF]: Degrees of freedom
*[MPI]: Message Passing Interface
*[API]: Application programming interface
*[FPI]: Fixed Point Iteration

File renamed without changes
Binary file added docs/assets/fire-sat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Two component system
Here is a simple example of a two-component multidisciplinary system.
```python
--8<-- "amisc/examples/tutorial.py:simple"
```
The first component computes $y=x\sin(\pi x)$. The second component takes the output of the first and computes $z=1 / (1 + 25y^2)$. Note that we must specify the domains of the variables over which we wish to build the surrogate (here they are just set to (0, 1)).

## Random variable
Here is an example of interpolating a function of a random variable $x\sim U(-1, 1)$. We manually construct the `Variable` and assign it a PDF. Then, we define the `Component` model and its inputs and outputs. Finally, we construct the MD system (which has just one component) and train the surrogate.
```python
--8<-- "amisc/examples/tutorial.py:single"
```
Note, the `data_fidelity` parameter sets the maximum refinement level for the surrogate.

## Fire detection satellite
Here is an example of a three-component fire detection satellite system from [Chauduri (2018)](https://dspace.mit.edu/handle/1721.1/117036):
![Fire satellite system diagram](assets/fire-sat.png)
We define the system in a yaml configuration file and load the `System` object using a helper function (see the source code for details). Since the fire-sat system has complicated couplings between models, we generate a test set and estimate the coupling variable bounds while training the surrogate. Finally, we plot some diagnostics to determine the performance of the surrogate.
```python
--8<-- "amisc/examples/tutorial.py:fire_sat"
```
Here is the output of `plot_slice()`:
![Fire satellite system results](assets/fire-sat-slice.png)
We see that the model has a smooth response over the inputs, and our surrogate is able to accurately approximate the high-fidelity model.

## Field quantity
A field quantity is specified as a `Variable` (just like a scalar), except it is given a `Compression` map that tells `amisc` how to reduce the field quantity to a set of "latent" coefficients over which to build the surrogate approximation. This would be desirable if you want to approximate the output of a high-dimensional solution, for example, from a PDE mesh.

In this example, we generate a random data matrix to simulate a high-dimensional field quantity, and construct a rank-4 SVD compression map. Note, we must provide the coordinates (Cartesian or otherwise) on which the field quantity is defined. We then approximate the field quantity as a function of the `x` scalar input.
```python
--8<-- "amisc/examples/tutorial.py:field_qty"
```
Note that the surrogate will predict the field quantity in its "latent" or compressed space. To obtain the full field quantity, we must reconstruct the field using the inverse of the compression map (which is stored in the `field_qty` variable). The `to_model_dataset` utility provided by `amisc` will do this for you.
10 changes: 5 additions & 5 deletions docs/gen_ref_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,21 @@
fd = mkdocs_gen_files.open(full_doc_path, "w")

if doc_path.name == index_file_name:
# Change md header for packages
# Change md header for the top-level init file
fd.write(f'# {pack_symbol_head} `{python_name}`\n')
fd.write(f'::: {python_name}\n')
fd.write(f' options:\n')
fd.write(f' show_root_heading: false\n')
fd.write(f' show_root_toc_entry: false\n')
fd.write(f' heading_level: 2\n')
fd.write(f' members:\n')
fd.write(f' - FileLoader\n')
fd.write(f' - YamlLoader\n')
else:
# Change md header for modules
fd.write(f'---\ntitle: {python_parts[-1]}\n---\n\n::: {python_name}\n')

if python_parts[-1] == 'interpolator':
fd.write(f' options:\n')
fd.write(f' filters: [""]\n')
if python_parts[-1] in ['component', 'variable']:
if python_parts[-1] in ['variable']:
fd.write(f' options:\n')
fd.write(f' members_order: source\n')
fd.close()
Expand Down
119 changes: 119 additions & 0 deletions docs/guides/config_file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
Configuration files can be written to define `amisc` objects using the text-based [YAML](https://pyyaml.org/) markup language. In general, YAML files contain mappings, sequences, and scalars, which correspond roughly to Python `dicts`, `lists`, and `strings`, respectively.

!!! Example "YAML configuration file"
```yaml
# Mapping (dictionary)
description: My grocery list
store: Winco foods
location: 1651 N 400 E
date: 11-4-2024

# Sequence (list)
items:
- Bananas
- Bread
- Milk
- Eggs

# Scalar (strings)
notes: All values like this one are treated as strings
block: |
Strings can also be written in "block" form
so that they may take up multiple lines.
numbers: 1.0 # numbers are also strings but will get converted upon loading
```

More complicated objects can be defined using YAML "tags", which are demarcated by an exclamation followed by the name of the object: `!ObjectName`. We provide access to three object tags for defining `amisc` objects in YAML: `!Variable`, `!Component`, and `!System`. The [`YamlLoader`][amisc.YamlLoader] class contains rules for loading these tags into the `amisc` framework.

## Variables
Variable objects are constructed with the `!Variable` tag followed by a mapping of the variable properties:
```yaml
!Variable
name: x
description: My custom variable
domain: (0, 1)
nominal: 0.5
distribution: U(0, 1)
norm: minmax
units: m/s
```
A list of variables may be defined with the `!VariableList` tag:
```yaml
!VariableList
- name: x1
domain: (0, 1)
- name: x2
description: another variable
- name: x3
```

## Components
Component objects are constructed with the `!Component` tag followed by a mapping of the component properties. Lists of variable inputs and outputs may be defined by nesting the `!VariableList` tag:
```yaml
!Component
name: My component
model: !!python/name:my.importable.model_function
model_kwargs:
extra_config: A config value
options: More options here passed as **kwarg to the model_function
inputs: !VariableList
- name: x1
- name: x2
outputs: !VariableList
- name: y1
- name: y2
data_fidelity: (2, 2)
vectorized: true
```

A list of components can be constructed by listing several components in a sequence underneath the `!Component` tag:
```yaml
!Component
- name: First component
model: !!python/name:amisc.examples.models.f1
- name: Second component
model: !!python/name:amisc.examples.models.f2
```

!!! Note "Defining callable functions in YAML"
In the examples above, we defined callable Python functions using the `!!python/name` tag followed by the import path of the function. The import path must be defined in a global scope so that a Python `import my.model_function` statement is valid. For example, you might define your function in a local importable package, or simply in the current working directory (which is always searched by the Python module finder). If you had a local `module.py` file that contained the `my_model` file, then you would specify this in YAML as `!!python/name:module.my_model`.

## System
The `System` surrogate object is constructed with the `!System` tag followed by a mapping of the system properties. Lists of components may be defined by nesting the `!Component` tag:
```yaml
!System
name: My multidisciplinary system
components: !Component
- name: My first component
model: !!python/name:path.to.first_model
inputs: !VariableList
- name: x1
- name: x2
outputs: !VariableList
- name: y1
- name: y2
- name: My second component
model: !!python/name:path.to.second_model
```

!!! Note "Duplicate variables"
If multiple components take the same input variable, you only need to define the variable once in the YAML file. Then, you may simply reference the variable's `name` for any other component that uses the variable. Upon loading from file, the `System` will use the same `Variable` object for all components that reference the same variable `name`.

## Loading from a configuration file
The [YamlLoader][amisc.YamlLoader] provides an interface for loading `amisc` objects from YAML config files:
```python
from amisc import YamlLoader
config_file = """
!VariableList
- name: x1
domain: (0, 1)
- name: x2
- name: x3
"""
variables = YamlLoader.load(config_file)
```

The [`load_from_file`][amisc.system.System.load_from_file] and [`save_to_file`][amisc.system.System.save_to_file] convenience methods are also provided for loading and saving `System` objects to file (i.e. during surrogate training). These surrogate save files closely mirror the YAML format used for configuration -- they contain all the base properties of the surrogate as well as extra internal data for storing the state of the surrogate. These save files can be edited directly in a text editor to change or view properties of the surrogate.
Loading

0 comments on commit a1331b2

Please sign in to comment.