Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a56282d
Create temp
jainprana May 30, 2025
65e172e
Add files via upload
jainprana May 30, 2025
b74c870
fix format
malihass May 30, 2025
e1382f6
fix typos in readme
malihass May 30, 2025
00bdb3d
typo in pickle import
malihass May 30, 2025
a310482
add dependencies to setup
malihass May 30, 2025
3dbb892
add doc and type hinting
malihass May 30, 2025
5c0c719
split surrogate and optimization
malihass May 30, 2025
188e7b6
doc string type hinting and reuse surrogate functions
malihass May 30, 2025
753582e
ignore pdf from codespelling
malihass May 30, 2025
aabba8c
Merge pull request #107 from jainprana/Discrete_Optimization
malihass May 30, 2025
a9644c6
save optim results to folder, and remove tmp files
malihass Jun 5, 2025
73245fe
add script to generate paper figures
malihass Jun 9, 2025
220de6b
Merge pull request #109 from NREL/optimformat
malihass Jun 9, 2025
0b29067
remove tabs
malihass Jun 16, 2025
5af30ba
add a check for tabs in yaml files
malihass Jun 16, 2025
c4a09ec
use the yaml parse function instead of rewriting it
malihass Jun 16, 2025
eff5636
Merge pull request #110 from NREL/strerr
malihass Jun 17, 2025
7b1bfff
update the ci to test python 3.13
malihass Jun 17, 2025
9e0db3b
remove intermediate python tests
malihass Jun 17, 2025
2b950b3
Merge pull request #111 from NREL/pyupdate
malihass Jun 17, 2025
c5e1fa6
document ofio
malihass Jul 8, 2025
c5b79b2
remove data from package
malihass Jul 8, 2025
26a51f5
add tests for dictionary reading
malihass Jul 8, 2025
ac71303
show how to read a control dict
malihass Jul 8, 2025
4134b94
remove too strict assertion
malihass Jul 8, 2025
73e1cb9
format
malihass Jul 8, 2025
587ec49
update version
malihass Jul 8, 2025
fd69f6b
remove config files
malihass Jul 8, 2025
bac6e15
remove unused imports and format
malihass Jul 9, 2025
e5f7f10
docstring for tests
malihass Jul 9, 2025
f017303
Merge pull request #112 from NREL/ofio_cleanup
malihass Jul 9, 2025
2511102
centralize postprocess
malihass Jul 9, 2025
d0d77b9
test bubble diameter calculation
malihass Jul 9, 2025
1789d0c
remove rogue val dict
malihass Jul 9, 2025
1f7c87c
push to pypi to pass test
malihass Jul 9, 2025
8f7cc18
Merge pull request #113 from NREL/postcleanup
malihass Jul 9, 2025
7069e23
superficial velocity calculation
malihass Jul 9, 2025
a139d17
update bird version
malihass Jul 9, 2025
393e338
add flat panel reactor tutorial and add it to the ci
malihass Jul 9, 2025
4706d99
adding ref and only run 1 timestep
malihass Jul 9, 2025
0b5b7be
Merge pull request #114 from NREL/flat_panel
malihass Jul 9, 2025
bdda423
add a better contributing guideline
malihass Jul 10, 2025
dc55a82
add description of python interface
malihass Jul 10, 2025
483b731
fix display of python versions
malihass Jul 10, 2025
4baca52
Merge pull request #115 from NREL/pythoninterfacedoc
malihass Jul 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/linters/.codespellrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[codespell]
skip = None, .git,OFsolvers,tutorial_cases,experimental_cases,build,_build,__pycache__,data_conditional_mean,Figures,assets
skip = None, .git,OFsolvers,*.pdf, tutorial_cases,experimental_cases,build,_build,__pycache__,data_conditional_mean,Figures,assets
ignore-words = .github/linters/.codespell-ignore-words
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12']
python-version: ['3.10', '3.13']
os: ['ubuntu-latest', 'macos-latest']
defaults:
run:
Expand Down Expand Up @@ -176,4 +176,9 @@ jobs:
cd tutorial_cases/airlift_40m
bash run.sh
cd ../../
- name: Run flat panel reactor tutorial
run: |
cd tutorial_cases/FlatPanel_250L_ASU
bash run.sh
cd ../../

25 changes: 25 additions & 0 deletions bird/meshing/_mesh_tools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os
import sys
from pathlib import Path

Expand All @@ -12,7 +13,31 @@ def parseJsonFile(input_filename):
return inpt


def check_for_tabs_in_yaml(file_path: str) -> None:
"""
Checks if a YAML file contains any tab characters.
Raises a ValueError if tabs found.

Parameters
----------
file_path: str
path to yaml filename
"""

with open(file_path, "r", encoding="utf-8") as f:
lines = f.readlines()
for iline, line in enumerate(lines):
if "\t" in line:
raise ValueError(
f"Tab character found on line {iline} of '{file_path}'. "
"YAML files must use spaces for indentation."
)


def parseYAMLFile(input_filename):
if not os.path.exists(input_filename):
raise FileNotFoundError(input_filename)
check_for_tabs_in_yaml(input_filename)
yaml = YAML(typ="safe")
inpt = yaml.load(Path(input_filename))
return inpt
Expand Down
10 changes: 3 additions & 7 deletions bird/meshing/_stirred_tank_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from pathlib import Path

import numpy as np
from ruamel.yaml import YAML

from bird.meshing._mesh_tools import parseYAMLFile


class StirredTankReactor:
Expand Down Expand Up @@ -133,11 +134,6 @@ def __init__(
def from_file(cls, yamlfile):
if ".yaml" not in yamlfile:
yamlfile += ".yaml"
if os.path.exists(yamlfile):
yamlpath = Path(yamlfile)
else:
raise FileNotFoundError(yamlfile)
yaml = YAML(typ="safe")
in_dict = yaml.load(yamlpath)
in_dict = parseYAMLFile(yamlfile)
react_dict = {**in_dict["geometry"], **in_dict["mesh"]}
return cls(**react_dict)
34 changes: 17 additions & 17 deletions bird/meshing/stirred_tank_mesh_templates/base_tank/tank_par.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
geometry:
Dt: 0.26 # Tank diameter [m]
Da: 0.0866667 # Impleller tip Diameter [m]
H: 0.39 # Height of the reactor [m]
nimpellers: 1
C: [0.0866667] # height of the center of impellers [m]
W: 0.026 # impeller blade width [m]
L: 0.013 # impeller blade length (beyond the hub) [m]
Lin: 0.013 # impeller blade length (inside the hub)
J: 0.026 # Baffle width
Wh: 0.0026 # Hub height (Width)
polyrad: 0.00866667 # Stem radius (R_shaft)
Z0: 0.0 # bottom of reactor
nbaffles: 6 # number of baffles and impeller fins
Dt: 0.26 # Tank diameter [m]
Da: 0.0866667 # Impleller tip Diameter [m]
H: 0.39 # Height of the reactor [m]
nimpellers: 1
C: [0.0866667] # height of the center of impellers [m]
W: 0.026 # impeller blade width [m]
L: 0.013 # impeller blade length (beyond the hub) [m]
Lin: 0.013 # impeller blade length (inside the hub)
J: 0.026 # Baffle width
Wh: 0.0026 # Hub height (Width)
polyrad: 0.00866667 # Stem radius (R_shaft)
Z0: 0.0 # bottom of reactor
nbaffles: 6 # number of baffles and impeller fins

mesh:
nr: 120 # mesh points per unit radial length
nz: 240 # mesh points per unit axial length
Npoly: 4 # mesh points in the polygon at the axis
Na: 6 # mesh points in the azimuthal direction
nr: 120 # mesh points per unit radial length
nz: 240 # mesh points per unit axial length
Npoly: 4 # mesh points in the polygon at the axis
Na: 6 # mesh points in the azimuthal direction



49 changes: 49 additions & 0 deletions bird/postprocess/SA_optimization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Surrogate-Based Optimization with Simulated Annealing

## Install dependencies

```
conda create --name bird python=3.10
conda activate bird
git clone https://github.com/NREL/BioReactorDesign.git
cd BioReactorDesign
pip install -e .[optim]
```

## Examples

Implementation of surrogate-based design optimization with Simulated Annealing (SA). It supports three surrogate models:
- Radial Basis Function Interpolator ('rbf')
- Random Forest ('rf')
- Neural Network ('nn')

The SA optimizer operates on discrete feature values (0,1,2) with an option to restrict the number of spargers (1) to a fixed value (max_spargers).

- Preprocessing the data (`get_csv.py`)
- reads the `configs.pkl` and `results.pkl` files from a study
- saves the configuration in `Xdata_{study_name}.csv` file
- save the qoi and qoi_error in `ydata_{study_name}.csv` file

- Surrogate modeling and optimization (`get_optimal.py` and `get_optimal_with_constraints.py`)
- run_optimization(...) function sets up the surrogate-based optimization:
- Inputs:
- X: read from `Xdata_{study_name}.csv` file
- y: read from `ydata_{study_name}.csv` file
- model_type: type of surrogate model (default = `rbf`)
- model_type = `rbf`: Radial Basis Function
- model_type = `rf`: Random Forest
- model_type = `nn`: Neural Network
- max_spargers: maximum number of spargers (only in `get_optimal_with_constraints.py`) (default = 8)
- n_runs: number of bootstrap runs (default = 10)
- max_iters: maximum number of iterations of SA (default = 1000)
- bootstrap_size: sample size of each bootstrap (default = 100)
- For each bootstrap run, the model hyperparameters are tuned using 5-fold cross validation.
- The simulated_annealing_surrogate(...) function runs the optimization:
- If SA is too slow or fails to converge, you can change the following parameters:
- temp: maximum temperature of SA. Controls exploration.
- alpha: the rate at which temperature changes every iteration.
- It returns the optimal solutions along with the optimization logs which are used to make plots in postprocessing.
- Once the optimization is done the best solution is saved in a csv file and the following plots are made:
- Mean-CI plot of the objective function (qoi)
- Mean-CI plot of the distance of an iterate from the optimal solution (this is not done in `get_optimal_with_constraints.py`).

61 changes: 61 additions & 0 deletions bird/postprocess/SA_optimization/get_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import csv
import os
import pickle as pkl

import numpy as np


def get_config_result(study_fold: str = ".") -> None:
"""
Read the configs.pkl and results.pkl files from a study
Saves the configuration in Xdata_{study_fold}.csv file
Save the qoi and qoi_error in ydata_{study_fold}.csv file

Parameters
----------
study_fold : str
Folder that contains the study results

Returns
----------
None

"""
# Read results
with open(os.path.join(study_fold, "results.pkl"), "rb") as f:
results = pkl.load(f)
with open(os.path.join(study_fold, "configs.pkl"), "rb") as f:
configs = pkl.load(f)

Xdata = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], np.int64)
count = 0

# Save data into CSV files
xfname = os.path.join(study_fold, f"Xdata.csv")
yfname = os.path.join(study_fold, f"ydata.csv")
with open(xfname, "w", newline="") as csvfile:
writer = csv.writer(csvfile)
for sims in results:
b0 = configs[sims][0]
b1 = configs[sims][1]
b2 = configs[sims][2]
raw_data = np.concatenate((b0, b1, b2), axis=None)
writer.writerow(raw_data)

with open(yfname, "w", newline="") as csvfile:
writer = csv.writer(csvfile)
for sims in results:
q0 = results[sims]["qoi"]
q1 = results[sims]["qoi_err"]
y_data = np.concatenate((q0, q1), axis=None)
writer.writerow(y_data)


if __name__ == "__main__":
studies = {
"study_scaleup_0_4vvm_3000W": r"608$m^3$ 0.4vvm 3000W",
"study_scaleup_0_1vvm_6000W": r"608$m^3$ 0.1vvm 6000W",
"study_0_4vvm_1W": r"0.00361$m^3$ 0.4vvm 1W",
}
for study in studies:
get_config_result(study)
Loading