From e38eaf99f7976516a8278ed1eb17cf06364174be Mon Sep 17 00:00:00 2001 From: Malik Date: Fri, 17 Oct 2025 09:14:25 -0600 Subject: [PATCH 01/19] use pathlib instead of makedirs to handle intermediate directory creation --- bird/calibration/param_nn.py | 5 +++-- bird/preprocess/json_gen/generate_designs.py | 5 +++-- bird/utilities/folderManagement.py | 8 -------- tests/meshing/test_block_cyl_mesh.py | 2 +- tests/meshing/test_block_rect_mesh.py | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/bird/calibration/param_nn.py b/bird/calibration/param_nn.py index c0cc8255..5847fdb0 100644 --- a/bird/calibration/param_nn.py +++ b/bird/calibration/param_nn.py @@ -1,6 +1,7 @@ import argparse import os import time +from pathlib import Path import joblib import numpy as np @@ -306,8 +307,8 @@ def load(self, weight_file): self.model.load_weights(weight_file) def prepareLog(self): - os.makedirs(self.model_folder, exist_ok=True) - os.makedirs(self.log_loss_folder, exist_ok=True) + Path(self.model_folder).mkdir(parents=True, exist_ok=True) + Path(self.log_loss_folder).mkdir(parents=True, exist_ok=True) try: os.remove(os.path.join(self.log_loss_folder, "log.csv")) except FileNotFoundError as err: diff --git a/bird/preprocess/json_gen/generate_designs.py b/bird/preprocess/json_gen/generate_designs.py index cdf06514..862de36a 100644 --- a/bird/preprocess/json_gen/generate_designs.py +++ b/bird/preprocess/json_gen/generate_designs.py @@ -1,6 +1,7 @@ import os import pickle import shutil +from pathlib import Path import numpy as np @@ -174,7 +175,7 @@ def generate_small_reactor_cases( shutil.rmtree(study_folder) except: pass - os.makedirs(study_folder) + Path(study_folder).mkdir(parents=True, exist_ok=True) for sim_id in config_dict: sim_folder = id2simfolder(sim_id) shutil.copytree( @@ -292,7 +293,7 @@ def generate_scaledup_reactor_cases( shutil.rmtree(study_folder) except: pass - os.makedirs(study_folder) + Path(study_folder).mkdir(parents=True, exist_ok=True) for sim_id in config_dict: sim_folder = id2simfolder(sim_id) shutil.copytree( diff --git a/bird/utilities/folderManagement.py b/bird/utilities/folderManagement.py index 3c31efa1..1147900b 100644 --- a/bird/utilities/folderManagement.py +++ b/bird/utilities/folderManagement.py @@ -4,14 +4,6 @@ from bird import logger -def makeRecursiveFolder(path): - folder_list = path.split("/") - localFolder = "" - for folder in folder_list: - localFolder = os.path.join(localFolder, folder) - os.makedirs(localFolder, exist_ok=True) - - def getManyFolders(rootFolder, prefix="flat_donut"): # Read Time fold_tmp = os.listdir(rootFolder) diff --git a/tests/meshing/test_block_cyl_mesh.py b/tests/meshing/test_block_cyl_mesh.py index c5d181a1..c9924ef9 100644 --- a/tests/meshing/test_block_cyl_mesh.py +++ b/tests/meshing/test_block_cyl_mesh.py @@ -13,7 +13,7 @@ def base_mesh(input_file, topo_file, output_folder): - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) geomDict = assemble_geom(input_file, topo_file) meshDict = assemble_mesh(input_file, geomDict) writeBlockMeshDict(output_folder, geomDict, meshDict) diff --git a/tests/meshing/test_block_rect_mesh.py b/tests/meshing/test_block_rect_mesh.py index 32e7c855..f651161f 100644 --- a/tests/meshing/test_block_rect_mesh.py +++ b/tests/meshing/test_block_rect_mesh.py @@ -13,7 +13,7 @@ def base_mesh(input_file, output_folder): - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) geomDict = assemble_geom(input_file) meshDict = assemble_mesh(input_file) writeBlockMeshDict(output_folder, geomDict, meshDict) From 387de5ae0274cc360a5b600c1509aeafc8edcba3 Mon Sep 17 00:00:00 2001 From: Malik Date: Fri, 17 Oct 2025 10:47:16 -0600 Subject: [PATCH 02/19] remove folderManagement and path appends --- bird/utilities/folderManagement.py | 28 ------------- papers/co2_model/validation/compareToExp.py | 4 +- papers/sparger/process_geom/compare_qoi.py | 13 +++--- papers/sparger/process_geom/plot_cond.py | 38 +++++++++++++---- .../process_geom/plot_cond_multiFold.py | 13 +++--- papers/sparger/process_geom/plot_qoi.py | 42 ++++++++++++++----- .../process_geom/plot_qoi_multiFold.py | 15 +++---- 7 files changed, 80 insertions(+), 73 deletions(-) delete mode 100644 bird/utilities/folderManagement.py diff --git a/bird/utilities/folderManagement.py b/bird/utilities/folderManagement.py deleted file mode 100644 index 1147900b..00000000 --- a/bird/utilities/folderManagement.py +++ /dev/null @@ -1,28 +0,0 @@ -import os -import re - -from bird import logger - - -def getManyFolders(rootFolder, prefix="flat_donut"): - # Read Time - fold_tmp = os.listdir(rootFolder) - fold_num = [] - # remove non floats - for i, entry in reversed(list(enumerate(fold_tmp))): - if not entry.startswith(prefix) or entry.endswith("N2"): - a = fold_tmp.pop(i) - # print('removed ', a) - for entry in fold_tmp: - num = re.findall(r"\d+", entry) - if len(num) > 1: - msg = f"Cannot find num of folder {entry}." - msg += "\nDo not trust the spearman stat" - logger.warning(msg) - else: - fold_num.append(int(num[0])) - - sortedFold = [ - x for _, x in sorted(zip(fold_num, fold_tmp), key=lambda pair: pair[0]) - ] - return sortedFold diff --git a/papers/co2_model/validation/compareToExp.py b/papers/co2_model/validation/compareToExp.py index 5291917a..6f6964c3 100644 --- a/papers/co2_model/validation/compareToExp.py +++ b/papers/co2_model/validation/compareToExp.py @@ -1,11 +1,11 @@ import argparse import os import sys +from pathlib import Path import numpy as np from prettyPlot.plotting import plt, pretty_labels, pretty_legend -from bird.utilities.folderManagement import * from bird.utilities.ofio import * parser = argparse.ArgumentParser(description="Case folder") @@ -50,7 +50,7 @@ figureFolder = "Figures" figureFolder = os.path.join(figureFolder, args.figureFolder) -makeRecursiveFolder(figureFolder) +Path(figureFolder).mkdir(exist_ok=True, parents=True) conv17 = np.load(os.path.join(args.caseFolder17, "convergence_gh.npz")) conv19 = np.load(os.path.join(args.caseFolder19, "convergence_gh.npz")) diff --git a/papers/sparger/process_geom/compare_qoi.py b/papers/sparger/process_geom/compare_qoi.py index f526e344..e0e607b9 100644 --- a/papers/sparger/process_geom/compare_qoi.py +++ b/papers/sparger/process_geom/compare_qoi.py @@ -1,17 +1,14 @@ import argparse -import sys - -import numpy as np - -sys.path.append("../utilities") import os import pickle +import sys +from pathlib import Path -from folderManagement import * -from ofio import * +import numpy as np from prettyPlot.plotting import plt, pretty_labels, pretty_legend from bird.utilities.label_plot import label_conv +from bird.utilities.ofio import * parser = argparse.ArgumentParser(description="Compare Qoi") parser.add_argument( @@ -88,7 +85,7 @@ dataFiles = args.dataFiles mode = args.mode -makeRecursiveFolder(figureFolder) +Path(figureFolder).mkdir(parents=True, exist_ok=True) data_structs = [np.load(dataFile) for dataFile in dataFiles] symbol_list = ["o", "s", "^"] diff --git a/papers/sparger/process_geom/plot_cond.py b/papers/sparger/process_geom/plot_cond.py index 04bf9c0a..91f6cda0 100644 --- a/papers/sparger/process_geom/plot_cond.py +++ b/papers/sparger/process_geom/plot_cond.py @@ -1,17 +1,39 @@ import argparse -import sys - -import numpy as np - -sys.path.append("../utilities") import os import pickle +import sys +from pathlib import Path -from folderManagement import * -from ofio import * +import numpy as np from prettyPlot.plotting import plt, pretty_labels from bird.utilities.label_plot import label_conv +from bird.utilities.ofio import * + + +def getManyFolders(rootFolder, prefix="flat_donut"): + # Read Time + fold_tmp = os.listdir(rootFolder) + fold_num = [] + # remove non floats + for i, entry in reversed(list(enumerate(fold_tmp))): + if not entry.startswith(prefix) or entry.endswith("N2"): + a = fold_tmp.pop(i) + # print('removed ', a) + for entry in fold_tmp: + num = re.findall(r"\d+", entry) + if len(num) > 1: + msg = f"Cannot find num of folder {entry}." + msg += "\nDo not trust the spearman stat" + logger.warning(msg) + else: + fold_num.append(int(num[0])) + + sortedFold = [ + x for _, x in sorted(zip(fold_num, fold_tmp), key=lambda pair: pair[0]) + ] + return sortedFold + parser = argparse.ArgumentParser(description="Plot cond qoi") parser.add_argument( @@ -96,7 +118,7 @@ args = parser.parse_args() figureFolder = "Figures" figureFolder = os.path.join(figureFolder, args.figureFolder, "cond") -makeRecursiveFolder(figureFolder) +Path(figureFolder).mkdir(parents=True, exist_ok=True) field_names = args.field_list param_file = args.paramFile study_folder = args.studyFolder diff --git a/papers/sparger/process_geom/plot_cond_multiFold.py b/papers/sparger/process_geom/plot_cond_multiFold.py index b2ef5582..01ec82dc 100644 --- a/papers/sparger/process_geom/plot_cond_multiFold.py +++ b/papers/sparger/process_geom/plot_cond_multiFold.py @@ -1,17 +1,14 @@ import argparse -import sys - -import numpy as np - -sys.path.append("../utilities") import os import pickle +import sys +from pathlib import Path -from folderManagement import * -from ofio import * +import numpy as np from prettyPlot.plotting import plt, pretty_labels from bird.utilities.label_plot import label_conv +from bird.utilities.ofio import * parser = argparse.ArgumentParser(description="Plot cond qoi") parser.add_argument( @@ -80,7 +77,7 @@ args = parser.parse_args() figureFolder = "Figures" figureFolder = os.path.join(figureFolder, args.figureFolder, "cond") -makeRecursiveFolder(figureFolder) +Path(figureFolder).mkdir(exist_ok=True, parents=True) field_names = args.field_list param_name = args.param_name param_vals = args.param_value diff --git a/papers/sparger/process_geom/plot_qoi.py b/papers/sparger/process_geom/plot_qoi.py index 76227422..0a5a9d54 100644 --- a/papers/sparger/process_geom/plot_qoi.py +++ b/papers/sparger/process_geom/plot_qoi.py @@ -1,17 +1,39 @@ import argparse -import sys - -import numpy as np - -sys.path.append("../utilities") import os import pickle +import sys +from pathlib import Path -from folderManagement import * -from ofio import * +import numpy as np from prettyPlot.plotting import plt, pretty_labels from bird.utilities.label_plot import label_conv +from bird.utilities.ofio import * + + +def getManyFolders(rootFolder, prefix="flat_donut"): + # Read Time + fold_tmp = os.listdir(rootFolder) + fold_num = [] + # remove non floats + for i, entry in reversed(list(enumerate(fold_tmp))): + if not entry.startswith(prefix) or entry.endswith("N2"): + a = fold_tmp.pop(i) + # print('removed ', a) + for entry in fold_tmp: + num = re.findall(r"\d+", entry) + if len(num) > 1: + msg = f"Cannot find num of folder {entry}." + msg += "\nDo not trust the spearman stat" + logger.warning(msg) + else: + fold_num.append(int(num[0])) + + sortedFold = [ + x for _, x in sorted(zip(fold_num, fold_tmp), key=lambda pair: pair[0]) + ] + return sortedFold + parser = argparse.ArgumentParser(description="Plot Qoi") parser.add_argument( @@ -124,9 +146,9 @@ ) -makeRecursiveFolder(figure_qoi_folder) -makeRecursiveFolder(figure_qoiNP_folder) -makeRecursiveFolder(figure_qoiConv_folder) +Path(figure_qoi_folder).mkdir(exist_ok=True, parents=True) +Path(figure_qoiNP_folder).mkdir(exist_ok=True, parents=True) +Path(figure_qoiConv_folder).mkdir(exist_ok=True, parents=True) var_names = args.var_list vmin = args.vmin vmax = args.vmax diff --git a/papers/sparger/process_geom/plot_qoi_multiFold.py b/papers/sparger/process_geom/plot_qoi_multiFold.py index 587ea49b..c3ad48ff 100644 --- a/papers/sparger/process_geom/plot_qoi_multiFold.py +++ b/papers/sparger/process_geom/plot_qoi_multiFold.py @@ -1,17 +1,14 @@ import argparse -import sys - -import numpy as np - -sys.path.append("../utilities") import os import pickle +import sys +from pathlib import Path -from folderManagement import * -from ofio import * +import numpy as np from prettyPlot.plotting import plt, pretty_labels from bird.utilities.label_plot import label_conv +from bird.utilities.ofio import * parser = argparse.ArgumentParser(description="Plot Qoi") parser.add_argument( @@ -82,8 +79,8 @@ figure_qoiConv_Folder = os.path.join( figureFolder, args.figureFolder, "qoi_conv" ) -makeRecursiveFolder(figure_qoi_Folder) -makeRecursiveFolder(figure_qoiConv_Folder) +Path(figure_qoi_Folder).mkdir(parents=True, exist_ok=True) +Path(figure_qoiConv_Folder).mkdir(parents=True, exist_ok=True) var_names = args.var_list param_name = args.param_name param_vals = args.param_value From a45d4ff50830c7bba7935f7d0bae0dc4d622b573 Mon Sep 17 00:00:00 2001 From: Malik Date: Fri, 17 Oct 2025 10:52:40 -0600 Subject: [PATCH 03/19] print bird on warning --- bird/logging_config.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bird/logging_config.py b/bird/logging_config.py index 0df52260..5e246367 100644 --- a/bird/logging_config.py +++ b/bird/logging_config.py @@ -6,9 +6,7 @@ class ConditionalFormatter(logging.Formatter): def format(self, record): """Change how to log if it is an INFO or a WARNING/ERROR""" if record.levelno >= logging.WARNING: - self._style._fmt = ( - "%(asctime)s [%(levelname)s] %(name)s: %(message)s" - ) + self._style._fmt = "%(asctime)s [%(levelname)s] bird: %(message)s" else: self._style._fmt = "%(asctime)s [%(levelname)s] bird: %(message)s" return super().format(record) From 7ff751576685c45357cab5743172977801b6a593 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 10:23:29 -0600 Subject: [PATCH 04/19] remove value error warning --- bird/postprocess/early_pred.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bird/postprocess/early_pred.py b/bird/postprocess/early_pred.py index d96edf26..2ce81e1a 100644 --- a/bird/postprocess/early_pred.py +++ b/bird/postprocess/early_pred.py @@ -102,7 +102,9 @@ def multi_data_load(data_root, tmax=600, data_files=None, color_files=None): A = np.loadtxt(filename) data_dict[datf] = {} data_dict[datf]["t"] = A[:, 0] - data_dict[datf]["y"] = A[:, 5] / (A[:, 4] * 16 / 44 + A[:, 5]) + data_dict[datf]["y"] = A[:, 5] / np.clip( + (A[:, 4] * 16 / 44 + A[:, 5]), a_min=1e-12, a_max=None + ) # chop data before increase and right after t=10s increase_ind_arr = np.argwhere(np.diff(data_dict[datf]["y"]) > 0) increase_ind = increase_ind_arr[ From 5c0143090227096929dac3af6f94c42a6907643b Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 10:25:00 -0600 Subject: [PATCH 05/19] remove more bird utilities --- applications/write_stl_patch.py | 4 ++-- bird/utilities/stl_plotting.py | 24 +++++++++++++++---- papers/sparger/process_geom/compare_qoi.py | 3 ++- .../sparger/process_geom}/label_plot.py | 0 papers/sparger/process_geom/plot_cond.py | 3 ++- .../process_geom/plot_cond_multiFold.py | 3 ++- papers/sparger/process_geom/plot_qoi.py | 3 ++- .../process_geom/plot_qoi_multiFold.py | 3 ++- tests/preprocess/test_stl_patch.py | 8 +++---- 9 files changed, 36 insertions(+), 15 deletions(-) rename {bird/utilities => papers/sparger/process_geom}/label_plot.py (100%) diff --git a/applications/write_stl_patch.py b/applications/write_stl_patch.py index fe7d9f24..655156a2 100644 --- a/applications/write_stl_patch.py +++ b/applications/write_stl_patch.py @@ -32,8 +32,8 @@ if args.verbose: # plot - from bird.utilities.stl_plotting import plotSTL, plt, pretty_labels + from bird.utilities.stl_plotting import plot_stl, plt, pretty_labels - axes = plotSTL("inlets.stl") + axes = plot_stl("inlets.stl") pretty_labels("x", "y", zlabel="z", fontsize=14, ax=axes) plt.show() diff --git a/bird/utilities/stl_plotting.py b/bird/utilities/stl_plotting.py index 19fdaabb..e6b8b835 100644 --- a/bird/utilities/stl_plotting.py +++ b/bird/utilities/stl_plotting.py @@ -1,10 +1,25 @@ +import matplotlib import numpy as np +from mpl_toolkits import mplot3d from prettyPlot.plotting import plt, pretty_labels, pretty_legend +from stl import mesh -def plotSTL(stl_file): - from mpl_toolkits import mplot3d - from stl import mesh +def plot_stl(stl_file: str) -> matplotlib.axes.Axes: + """ + Plot a 2D STL file with matplotlib + This is useful to check boundary condition definition with STL + + Parameters + ---------- + stl_file: str + Name of the STL file to display + + Returns + ---------- + axes: matplotlib.axes.Axes + Axes of the plot created + """ # Create a new plot figure = plt.figure() @@ -25,7 +40,8 @@ def plotSTL(stl_file): max_z = np.amax(your_mesh.points[:, 2]) amp = np.array([max_x - min_x, max_y - min_y, max_z - min_z]) - # 2D view + + # Rotate so we have a 2D view if abs(amp[0]) < 1e-12: axes.view_init(0, 90) elif abs(amp[1]) < 1e-12: diff --git a/papers/sparger/process_geom/compare_qoi.py b/papers/sparger/process_geom/compare_qoi.py index e0e607b9..0f5d3012 100644 --- a/papers/sparger/process_geom/compare_qoi.py +++ b/papers/sparger/process_geom/compare_qoi.py @@ -7,9 +7,10 @@ import numpy as np from prettyPlot.plotting import plt, pretty_labels, pretty_legend -from bird.utilities.label_plot import label_conv from bird.utilities.ofio import * +from .label_plot import label_conv + parser = argparse.ArgumentParser(description="Compare Qoi") parser.add_argument( "-df", diff --git a/bird/utilities/label_plot.py b/papers/sparger/process_geom/label_plot.py similarity index 100% rename from bird/utilities/label_plot.py rename to papers/sparger/process_geom/label_plot.py diff --git a/papers/sparger/process_geom/plot_cond.py b/papers/sparger/process_geom/plot_cond.py index 91f6cda0..6bebeb5d 100644 --- a/papers/sparger/process_geom/plot_cond.py +++ b/papers/sparger/process_geom/plot_cond.py @@ -7,9 +7,10 @@ import numpy as np from prettyPlot.plotting import plt, pretty_labels -from bird.utilities.label_plot import label_conv from bird.utilities.ofio import * +from .label_plot import label_conv + def getManyFolders(rootFolder, prefix="flat_donut"): # Read Time diff --git a/papers/sparger/process_geom/plot_cond_multiFold.py b/papers/sparger/process_geom/plot_cond_multiFold.py index 01ec82dc..a571a62f 100644 --- a/papers/sparger/process_geom/plot_cond_multiFold.py +++ b/papers/sparger/process_geom/plot_cond_multiFold.py @@ -7,9 +7,10 @@ import numpy as np from prettyPlot.plotting import plt, pretty_labels -from bird.utilities.label_plot import label_conv from bird.utilities.ofio import * +from .label_plot import label_conv + parser = argparse.ArgumentParser(description="Plot cond qoi") parser.add_argument( "-sf", diff --git a/papers/sparger/process_geom/plot_qoi.py b/papers/sparger/process_geom/plot_qoi.py index 0a5a9d54..81e4ec4f 100644 --- a/papers/sparger/process_geom/plot_qoi.py +++ b/papers/sparger/process_geom/plot_qoi.py @@ -7,9 +7,10 @@ import numpy as np from prettyPlot.plotting import plt, pretty_labels -from bird.utilities.label_plot import label_conv from bird.utilities.ofio import * +from .label_plot import label_conv + def getManyFolders(rootFolder, prefix="flat_donut"): # Read Time diff --git a/papers/sparger/process_geom/plot_qoi_multiFold.py b/papers/sparger/process_geom/plot_qoi_multiFold.py index c3ad48ff..6f2e2547 100644 --- a/papers/sparger/process_geom/plot_qoi_multiFold.py +++ b/papers/sparger/process_geom/plot_qoi_multiFold.py @@ -7,9 +7,10 @@ import numpy as np from prettyPlot.plotting import plt, pretty_labels -from bird.utilities.label_plot import label_conv from bird.utilities.ofio import * +from .label_plot import label_conv + parser = argparse.ArgumentParser(description="Plot Qoi") parser.add_argument( "-sf", diff --git a/tests/preprocess/test_stl_patch.py b/tests/preprocess/test_stl_patch.py index ea339480..f76c2309 100644 --- a/tests/preprocess/test_stl_patch.py +++ b/tests/preprocess/test_stl_patch.py @@ -7,7 +7,7 @@ from bird.preprocess.stl_patch.stl_bc import write_boundaries from bird.utilities.parser import parse_json -from bird.utilities.stl_plotting import plotSTL +from bird.utilities.stl_plotting import plot_stl def test_spider_sparger(): @@ -28,7 +28,7 @@ def test_spider_sparger(): # Output to temporary directory and delete when done with tempfile.TemporaryDirectory() as tmpdirname: write_boundaries(input_dict, output_folder=tmpdirname) - axes = plotSTL(os.path.join(tmpdirname, "inlets.stl")) + axes = plot_stl(os.path.join(tmpdirname, "inlets.stl")) pretty_labels("x", "y", zlabel="z", fontsize=14, ax=axes) @@ -51,7 +51,7 @@ def test_loop_reactor(): # Output to temporary directory and delete when done with tempfile.TemporaryDirectory() as tmpdirname: write_boundaries(input_dict, output_folder=tmpdirname) - axes = plotSTL(os.path.join(tmpdirname, "inlets.stl")) + axes = plot_stl(os.path.join(tmpdirname, "inlets.stl")) pretty_labels("x", "y", zlabel="z", fontsize=14, ax=axes) @@ -73,7 +73,7 @@ def test_loop_reactor_branch(): # Output to temporary directory and delete when done with tempfile.TemporaryDirectory() as tmpdirname: write_boundaries(input_dict, output_folder=tmpdirname) - axes = plotSTL(os.path.join(tmpdirname, "inlets.stl")) + axes = plot_stl(os.path.join(tmpdirname, "inlets.stl")) pretty_labels("x", "y", zlabel="z", fontsize=14, ax=axes) From 33a92d9a55df87fdbb19db98988442c1482d8670 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 10:25:27 -0600 Subject: [PATCH 06/19] move bissection to mathtools --- bird/meshing/_mesh_tools.py | 66 +++++++++++-------------------------- bird/utilities/mathtools.py | 60 +++++++++++++++++++++++++++++++++ bird/version.py | 2 +- 3 files changed, 80 insertions(+), 48 deletions(-) diff --git a/bird/meshing/_mesh_tools.py b/bird/meshing/_mesh_tools.py index 0fef1067..bc4955a1 100644 --- a/bird/meshing/_mesh_tools.py +++ b/bird/meshing/_mesh_tools.py @@ -1,6 +1,7 @@ import numpy as np from bird import logger +from bird.utilities.mathtools import bissection def make_walls_from_topo(topo_dict: dict) -> dict: @@ -70,8 +71,8 @@ def make_bound_from_topo(topo_dict): } -def stretch_fun(G, N1): - result = (1.0 - G) / (G * (1 - np.power(G, 1.0 / N1))) +def stretch_fun(G, N): + result = (1.0 - G) / (G * (1 - np.power(G, 1.0 / N))) return result @@ -80,29 +81,6 @@ def stretch_fun(G, N1): # return result -def bissection(val, stretch_fun, N1): - Gmin = 0.00001 - Gmax = 1000000 - resultmin = stretch_fun(Gmin, N1) - val - resultmax = stretch_fun(Gmax, N1) - val - if resultmin * resultmax > 0: - error_msg = "Initial bounds of grading do not encompass the solution" - logger.error(error_msg) - raise ValueError(error_msg) - - for i in range(1000): - Gmid = 0.5 * (Gmax + Gmin) - resultmid = stretch_fun(Gmid, N1) - val - if resultmid * resultmax < 0: - Gmin = Gmid - resultmin = resultmid - else: - Gmax = Gmid - resultmax = resultmid - - return Gmid - - def is_wall(l_wall: list[int], r_wall: list[int], ir: int, il: int) -> int: """ Is the present block a wall (not meshed) @@ -223,9 +201,8 @@ def verticalCoarsening( raise ValueError(error_msg) if ratio_dir[ind] == "+": - gradVert[ind] = 1.0 / bissection( - length / deltaE, stretch_fun, NVert[ind] - ) + nl_func = lambda x: stretch_fun(x, NVert[ind]) + gradVert[ind] = 1.0 / bissection(length / deltaE, nl_func) iterate = False origNVert = NVert[ind] while gradVert[ind] < 1 and NVert[ind] > 1: @@ -233,9 +210,8 @@ def verticalCoarsening( NVert[ind] = max( int(round(min(0.99 * NVert[ind], NVert[ind] - 1))), 1 ) - gradVert[ind] = 1.0 / bissection( - length / deltaE, stretch_fun, NVert[ind] - ) + nl_func = lambda x: stretch_fun(x, NVert[ind]) + gradVert[ind] = 1.0 / bissection(length / deltaE, nl_func) if iterate: logger.warning( f"reduced NVert[{ind}] from {origNVert} to {NVert[ind]}" @@ -245,9 +221,8 @@ def verticalCoarsening( elif ratio_dir[ind] == "-": deltaE = block_cell_minus_length[ind - 1] - gradVert[ind] = bissection( - length / deltaE, stretch_fun, NVert[ind] - ) + nl_func = lambda x: stretch_fun(x, NVert[ind]) + gradVert[ind] = bissection(length / deltaE, nl_func) iterate = False origNVert = NVert[ind] @@ -256,9 +231,8 @@ def verticalCoarsening( NVert[ind] = max( int(round(min(0.99 * NVert[ind], NVert[ind] - 1))), 1 ) - gradVert[ind] = bissection( - length / deltaE, stretch_fun, NVert[ind] - ) + nl_func = lambda x: stretch_fun(x, NVert[ind]) + gradVert[ind] = bissection(length / deltaE, nl_func) if iterate: logger.warning( f"reduced NVert[{ind}] from {origNVert} to {NVert[ind]}" @@ -337,9 +311,8 @@ def radialCoarsening( raise ValueError(error_msg) if ratio_dir[ind] == "+": - gradR[ind] = 1.0 / bissection( - length / deltaE, stretch_fun, NR[ind] - ) + nl_func = lambda x: stretch_fun(x, NR[ind]) + gradR[ind] = 1.0 / bissection(length / deltaE, nl_func) iterate = False origNR = NR[ind] while gradR[ind] < 1 and NR[ind] > 1: @@ -347,9 +320,8 @@ def radialCoarsening( NR[ind] = max( int(round(min(0.99 * NR[ind], NR[ind] - 1))), 1 ) - gradR[ind] = 1.0 / bissection( - length / deltaE, stretch_fun, NR[ind] - ) + nl_func = lambda x: stretch_fun(x, NR[ind]) + gradR[ind] = 1.0 / bissection(length / deltaE, nl_func) if iterate: logger.warning( f"reduced NR[{ind}] from {origNR} to {NR[ind]}" @@ -359,15 +331,15 @@ def radialCoarsening( elif ratio_dir[ind] == "-": deltaE = block_cell_minus_length[ind - 1] - gradR[ind] = bissection(length / deltaE, stretch_fun, NR[ind]) + nl_func = lambda x: stretch_fun(x, NR[ind]) + gradR[ind] = bissection(length / deltaE, nl_func) iterate = False origNR = NR[ind] while gradR[ind] > 1 and NR[ind] > 1: iterate = True NR[ind] = max(int(round(min(0.99 * NR[ind], -1))), 1) - gradR[ind] = bissection( - length / deltaE, stretch_fun, NR[ind] - ) + nl_func = lambda x: stretch_fun(x, NR[ind]) + gradR[ind] = bissection(length / deltaE, nl_func) if iterate: logger.warning( f"reduced NR[{ind}] from {origNR} to {NR[ind]}" diff --git a/bird/utilities/mathtools.py b/bird/utilities/mathtools.py index 159d8b88..27e97307 100644 --- a/bird/utilities/mathtools.py +++ b/bird/utilities/mathtools.py @@ -1,3 +1,5 @@ +from typing import Callable + import numpy as np from bird import logger @@ -90,3 +92,61 @@ def conditional_average( y_cond = weightVal / (weight) return x_cond, y_cond + + +def bissection( + func_val: float, + nonlin_fun: Callable, + num_iter: int = 1000, + x_min: float = 1e-6, + x_max: float = 1e6, +): + """ + Solve a 1D non linear equation with a bissection method + This is useful for adjusting the mesh grading so that mesh size varies smoothly + + Parameters + ---------- + func_val: + Target value for the non linear function + nonlin_fun: + Non linear function + num_iter: int + Number of bissection iterations + Defaults to 1000 + x_min : float + Lower bound of the search interval + Defaults to 1e-6 + x_max : float + Upper bound of the search interval + Defaults to 1e6 + + + Returns + ---------- + x_mid: float + The argument that achieves the desired function value + """ + + # Make sure residual sign changes over the search interval + residual_min = nonlin_fun(x_min) - func_val + residual_max = nonlin_fun(x_max) - func_val + if residual_min * residual_max > 0: + error_msg = "No guaranteed bissection solution" + error_msg += ( + "\nSearch interval [{x_min:.4g}, {x_max:.4g}] may be too narrow" + ) + raise ValueError(error_msg) + + # Do the bissection search + for i in range(num_iter): + x_mid = 0.5 * (x_max + x_min) + residual_mid = nonlin_fun(x_mid) - func_val + if residual_mid * residual_max < 0: + x_min = x_mid + residual_min = residual_mid + else: + x_max = x_mid + residual_max = residual_mid + + return x_mid diff --git a/bird/version.py b/bird/version.py index 68c45d06..460ec86b 100644 --- a/bird/version.py +++ b/bird/version.py @@ -1,3 +1,3 @@ """Bio reactor design version""" -__version__ = "0.0.45" +__version__ = "0.0.47" From e9b6b43feb8edd450ad7788ba6e7d04f6a970a27 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 10:33:44 -0600 Subject: [PATCH 07/19] consistency func/fun --- bird/utilities/mathtools.py | 12 ++++++------ bird/version.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bird/utilities/mathtools.py b/bird/utilities/mathtools.py index 27e97307..4cf528ea 100644 --- a/bird/utilities/mathtools.py +++ b/bird/utilities/mathtools.py @@ -95,19 +95,19 @@ def conditional_average( def bissection( - func_val: float, + fun_val: float, nonlin_fun: Callable, num_iter: int = 1000, x_min: float = 1e-6, x_max: float = 1e6, -): +) -> float: """ Solve a 1D non linear equation with a bissection method This is useful for adjusting the mesh grading so that mesh size varies smoothly Parameters ---------- - func_val: + fun_val: Target value for the non linear function nonlin_fun: Non linear function @@ -129,8 +129,8 @@ def bissection( """ # Make sure residual sign changes over the search interval - residual_min = nonlin_fun(x_min) - func_val - residual_max = nonlin_fun(x_max) - func_val + residual_min = nonlin_fun(x_min) - fun_val + residual_max = nonlin_fun(x_max) - fun_val if residual_min * residual_max > 0: error_msg = "No guaranteed bissection solution" error_msg += ( @@ -141,7 +141,7 @@ def bissection( # Do the bissection search for i in range(num_iter): x_mid = 0.5 * (x_max + x_min) - residual_mid = nonlin_fun(x_mid) - func_val + residual_mid = nonlin_fun(x_mid) - fun_val if residual_mid * residual_max < 0: x_min = x_mid residual_min = residual_mid diff --git a/bird/version.py b/bird/version.py index 460ec86b..24558041 100644 --- a/bird/version.py +++ b/bird/version.py @@ -1,3 +1,3 @@ """Bio reactor design version""" -__version__ = "0.0.47" +__version__ = "0.0.48" From ef7a482374988372316f9f056954f61658e3370e Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:09:39 -0600 Subject: [PATCH 08/19] test size group read and make sure bubble size groups are correctly read from phaseProperties --- bird/utilities/ofio.py | 126 +++++++++++++++++++++++--------- tests/io/test_read_foam_dict.py | 37 ++++++++++ tests/io/test_read_ndf.py | 26 +++++++ 3 files changed, 156 insertions(+), 33 deletions(-) create mode 100644 tests/io/test_read_ndf.py diff --git a/bird/utilities/ofio.py b/bird/utilities/ofio.py index 776c1204..a1e51b3c 100644 --- a/bird/utilities/ofio.py +++ b/bird/utilities/ofio.py @@ -479,47 +479,92 @@ def read_field( return field, field_dict -def readSizeGroups(file): - sizeGroup = {} - f = open(file, "r") - lines = f.readlines() - f.close() - begin = None - for iline, line in enumerate(lines): - if "sizeGroups" in line: - begin = iline + 2 - if not begin is None and ");" in line: - end = iline - 1 - break - for line in lines[begin : end + 1]: - tmp = line.split("{") - name = tmp[0].strip() - size = tmp[1].split(";")[0].split()[1] - sizeGroup[name] = float(size) - # Sort by size - sizeGroup = dict(sorted(sizeGroup.items(), key=lambda item: item[1])) - binGroup = {} - groups = list(sizeGroup.keys()) - for igroup, group in enumerate(groups): +def read_size_groups(case_folder: str) -> dict: + """ + Get the bubble size groups represented by the number density fields (fX.gas) + + Parameters + ---------- + case_folder: str + Path to case folder + + Returns + ---------- + ndf_groups: dict + Dictionary describing the number density fields + Key is the name of the number density field (fX) + Value is a dictionary with keys 'diam' and 'bin_size' + corresponding to the bubble diameter and the bin size in m + """ + + phaseProperties_file = os.path.join( + case_folder, "constant", "phaseProperties" + ) + phaseProperties = read_openfoam_dict(phaseProperties_file) + + # Make sure that population balance is used + try: + assert phaseProperties["populationBalances"] == ["bubbles"] + assert phaseProperties["gas"]["diameterModel"] == "velocityGroup" + assert ( + phaseProperties["gas"]["velocityGroupCoeffs"]["populationBalance"] + == "bubbles" + ) + except AssertionError: + logger.warning( + "Reading size groups for a case where population balance is not used" + ) + + size_grouptmp = phaseProperties["gas"]["velocityGroupCoeffs"]["sizeGroups"] + logger.debug(f"Found {len(size_grouptmp)} number density fields") + + # Associate number density field to size + size_group = {} + for name in size_grouptmp: + size_group[name] = float(size_grouptmp[name]["dSph"]) + + # Sort by size in ascending order + size_group = dict(sorted(size_group.items(), key=lambda item: item[1])) + + # Get the bin size + bin_size_group = {} + group_names = list(size_group.keys()) + logger.warning( + "The bin sizes definition make assumption of uniformity and need to be revisited if used" + ) + for igroup, name in enumerate(group_names): if igroup == 0: bin_size = ( - sizeGroup[groups[igroup + 1]] - sizeGroup[groups[igroup]] + size_group[group_names[igroup + 1]] + - size_group[group_names[igroup]] ) - elif igroup == len(groups) - 1: + elif igroup == len(group_names) - 1: bin_size = ( - sizeGroup[groups[igroup]] - sizeGroup[groups[igroup - 1]] + size_group[group_names[igroup]] + - size_group[group_names[igroup - 1]] ) else: bin_size_p = ( - sizeGroup[groups[igroup + 1]] - sizeGroup[groups[igroup]] + size_group[group_names[igroup + 1]] + - size_group[group_names[igroup]] ) bin_size_m = ( - sizeGroup[groups[igroup]] - sizeGroup[groups[igroup - 1]] + size_group[group_names[igroup]] + - size_group[group_names[igroup - 1]] ) assert abs(bin_size_p - bin_size_m) < 1e-12 bin_size = bin_size_m - binGroup[group] = bin_size - return sizeGroup, binGroup + bin_size_group[name] = bin_size + + # Put size and bin size together + ndf_groups = {} + for name in group_names: + ndf_groups[name] = { + "diam": size_group[name], + "bin_size": bin_size_group[name], + } + + return ndf_groups def get_case_times( @@ -748,15 +793,30 @@ def parse_block(index: int) -> tuple: index += 1 result[key] = dictlist else: - # Standard list + # Standard list or dict-like list (e.g. sizeGroups) lst = [] + dictlist = {} + while tokens[index] != ")": - lst.append(tokens[index]) + label = tokens[index] index += 1 - index += 1 + + if index < len(tokens) and tokens[index] == "{": + # Inline dict entry like: f1 { dSph 1e-3; value 0.0; } + index += 1 + subdict, index = parse_block(index) + dictlist[label] = subdict + else: + # Skip semicolons if present (e.g. in lists like species) + if label != ";": + lst.append(label) + + index += 1 # skip ')' if index < len(tokens) and tokens[index] == ";": index += 1 - result[key] = lst + + # Choose dictlist only if it has content; otherwise, use lst + result[key] = dictlist if dictlist else lst # key followed by scalar elif index < len(tokens): diff --git a/tests/io/test_read_foam_dict.py b/tests/io/test_read_foam_dict.py index b8051d24..fe5989a1 100644 --- a/tests/io/test_read_foam_dict.py +++ b/tests/io/test_read_foam_dict.py @@ -41,6 +41,41 @@ def test_read_phaseProperties(): ) +def test_read_ndf(): + """ + Test for reading content of `constant/phaseProperties` with population balance + """ + const_folder = os.path.join( + Path(__file__).parent, + "..", + "..", + "bird", + "postprocess", + "data_conditional_mean", + "constant", + ) + # Read non uniform field + foam_dict = read_openfoam_dict( + filename=os.path.join(const_folder, "phaseProperties") + ) + + assert foam_dict["phases"] == ["gas", "liquid"] + assert foam_dict["populationBalances"] == ["bubbles"] + assert foam_dict["gas"]["diameterModel"] == "velocityGroup" + assert len(foam_dict["gas"]["velocityGroupCoeffs"]["sizeGroups"]) == 21 + assert ( + abs( + float( + foam_dict["gas"]["velocityGroupCoeffs"]["sizeGroups"]["f4"][ + "dSph" + ] + ) + - 2.5e-3 + ) + < 1e-12 + ) + + def test_read_thermophysicalProperties(): """ Test for reading content of `constant/thermophysicalProperties` @@ -58,6 +93,7 @@ def test_read_thermophysicalProperties(): filename=os.path.join(const_folder, "thermophysicalProperties.gas") ) + print(foam_dict) assert foam_dict["species"] == ["H2", "CO2", "N2"] assert ( foam_dict["CO2"]["thermodynamics"]["highCpCoeffs"][0] == "3.85746029" @@ -108,6 +144,7 @@ def test_read_controlDict(): if __name__ == "__main__": + test_read_thermophysicalProperties() test_read_phaseProperties() test_read_thermophysicalProperties() test_read_momentumTransport() diff --git a/tests/io/test_read_ndf.py b/tests/io/test_read_ndf.py new file mode 100644 index 00000000..2ea0b069 --- /dev/null +++ b/tests/io/test_read_ndf.py @@ -0,0 +1,26 @@ +import os +from pathlib import Path + +import numpy as np + +from bird.utilities.ofio import read_size_groups + + +def test_read_size_groups(): + """ + Test for getting size group info + """ + case_folder = os.path.join( + Path(__file__).parent, + "..", + "..", + "bird", + "postprocess", + "data_conditional_mean", + ) + ndf_groups = read_size_groups(case_folder) + + assert len(ndf_groups) == 21 + assert abs(ndf_groups["f4"]["diam"] - 2.5e-3) < 1e-12 + assert abs(ndf_groups["f20"]["diam"] - 10.5e-3) < 1e-12 + # Place holder for bin size From 15d89983c272ce37f37cff848f7d726edfa3804e Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:10:56 -0600 Subject: [PATCH 09/19] update version --- bird/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bird/version.py b/bird/version.py index 24558041..a0013d91 100644 --- a/bird/version.py +++ b/bird/version.py @@ -1,3 +1,3 @@ """Bio reactor design version""" -__version__ = "0.0.48" +__version__ = "0.0.49" From 123c91b36bf8f2b1f0815fee2659efca5e840abc Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:19:16 -0600 Subject: [PATCH 10/19] add a retry in case conda fails --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03f0bc95..b9bb1f0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,6 +76,10 @@ jobs: - name: Install dependencies run: | + conda config --set remote_read_timeout_secs 60 + conda config --set remote_connect_timeout_secs 30 + conda config --set retry_max 10 + conda config --set retry_wait_seconds 10 conda install -y -c conda-forge paraview pip install --upgrade pip pip install . @@ -112,6 +116,10 @@ jobs: - name: Install dependencies run: | + conda config --set remote_read_timeout_secs 60 + conda config --set remote_connect_timeout_secs 30 + conda config --set retry_max 10 + conda config --set retry_wait_seconds 10 conda install -y -c conda-forge paraview pip install --upgrade pip pip install nrel-bird @@ -151,6 +159,10 @@ jobs: - name: Install dependencies run: | + conda config --set remote_read_timeout_secs 60 + conda config --set remote_connect_timeout_secs 30 + conda config --set retry_max 10 + conda config --set retry_wait_seconds 10 conda install -y -c conda-forge paraview pip install --upgrade pip pip install . From e13e9737c971ddf860709e97f6bdabdc56824588 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:23:40 -0600 Subject: [PATCH 11/19] add a retry in case conda fails --- .github/workflows/ci.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9bb1f0b..2dc955e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,13 +73,14 @@ jobs: python-version: ${{matrix.python-version}} channels: conda-forge channel-priority: strict - - - name: Install dependencies run: | conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 - conda config --set retry_max 10 + conda config --set remote_max_retries 10 conda config --set retry_wait_seconds 10 + + - name: Install dependencies + run: | conda install -y -c conda-forge paraview pip install --upgrade pip pip install . @@ -113,13 +114,14 @@ jobs: python-version: ${{matrix.python-version}} channels: conda-forge channel-priority: strict - - - name: Install dependencies run: | conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 - conda config --set retry_max 10 + conda config --set remote_max_retries 10 conda config --set retry_wait_seconds 10 + + - name: Install dependencies + run: | conda install -y -c conda-forge paraview pip install --upgrade pip pip install nrel-bird @@ -156,13 +158,14 @@ jobs: python-version: ${{matrix.python-version}} channels: conda-forge channel-priority: strict - - - name: Install dependencies run: | conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 - conda config --set retry_max 10 + conda config --set remote_max_retries 10 conda config --set retry_wait_seconds 10 + + - name: Install dependencies + run: | conda install -y -c conda-forge paraview pip install --upgrade pip pip install . From cb7e6ad397a26660572dd99d4a860ac19aa338bd Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:28:48 -0600 Subject: [PATCH 12/19] add a retry in case conda fails --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2dc955e1..a389767b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,8 @@ jobs: python-version: ${{matrix.python-version}} channels: conda-forge channel-priority: strict + + - name: Configure conda retries run: | conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 @@ -114,6 +116,8 @@ jobs: python-version: ${{matrix.python-version}} channels: conda-forge channel-priority: strict + + - name: Configure conda retries run: | conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 @@ -158,6 +162,8 @@ jobs: python-version: ${{matrix.python-version}} channels: conda-forge channel-priority: strict + + - name: Configure conda retries run: | conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 From d64b53470f29744bffe3a6fc7dc90a07bc883eb8 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:33:09 -0600 Subject: [PATCH 13/19] add a retry in case conda fails --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a389767b..1d95b6ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,7 +79,6 @@ jobs: conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 conda config --set remote_max_retries 10 - conda config --set retry_wait_seconds 10 - name: Install dependencies run: | @@ -122,7 +121,6 @@ jobs: conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 conda config --set remote_max_retries 10 - conda config --set retry_wait_seconds 10 - name: Install dependencies run: | @@ -168,7 +166,6 @@ jobs: conda config --set remote_read_timeout_secs 60 conda config --set remote_connect_timeout_secs 30 conda config --set remote_max_retries 10 - conda config --set retry_wait_seconds 10 - name: Install dependencies run: | From 79bbf48213c89d363daefed853619c0e8779f6b6 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 12:55:20 -0600 Subject: [PATCH 14/19] try with mamba instead --- .github/workflows/ci.yml | 59 +++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d95b6ad..14f066c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,25 +66,22 @@ jobs: with: python-version: ${{matrix.python-version}} - - name: Set up Miniconda - uses: conda-incubator/setup-miniconda@v3 + - name: Set up micromamba + uses: mamba-org/setup-micromamba@v1 with: - activate-environment: test-env - python-version: ${{matrix.python-version}} + environment-name: test-env + create-args: >- + python=${{ matrix.python-version }} channels: conda-forge channel-priority: strict - - - name: Configure conda retries - run: | - conda config --set remote_read_timeout_secs 60 - conda config --set remote_connect_timeout_secs 30 - conda config --set remote_max_retries 10 + cache-downloads: true + cache-env: true - name: Install dependencies run: | - conda install -y -c conda-forge paraview + micromamba install --yes -n test-env -c conda-forge paraview pip install --upgrade pip - pip install . + pip install . pip install pytest - name: Test @@ -108,23 +105,20 @@ jobs: with: python-version: ${{matrix.python-version}} - - name: Set up Miniconda - uses: conda-incubator/setup-miniconda@v3 + - name: Set up micromamba + uses: mamba-org/setup-micromamba@v1 with: - activate-environment: test-env - python-version: ${{matrix.python-version}} + environment-name: test-env + create-args: >- + python=${{ matrix.python-version }} channels: conda-forge channel-priority: strict - - - name: Configure conda retries - run: | - conda config --set remote_read_timeout_secs 60 - conda config --set remote_connect_timeout_secs 30 - conda config --set remote_max_retries 10 + cache-downloads: true + cache-env: true - name: Install dependencies run: | - conda install -y -c conda-forge paraview + micromamba install --yes -n test-env -c conda-forge paraview pip install --upgrade pip pip install nrel-bird pip install pytest @@ -153,23 +147,20 @@ jobs: with: openfoam-version: 9 - - name: Set up Miniconda - uses: conda-incubator/setup-miniconda@v3 + - name: Set up micromamba + uses: mamba-org/setup-micromamba@v1 with: - activate-environment: test-env - python-version: ${{matrix.python-version}} + environment-name: test-env + create-args: >- + python=${{ matrix.python-version }} channels: conda-forge channel-priority: strict - - - name: Configure conda retries - run: | - conda config --set remote_read_timeout_secs 60 - conda config --set remote_connect_timeout_secs 30 - conda config --set remote_max_retries 10 + cache-downloads: true + cache-env: true - name: Install dependencies run: | - conda install -y -c conda-forge paraview + micromamba install --yes -n test-env -c conda-forge paraview pip install --upgrade pip pip install . From caf77ab2815064131b463ee456253ed4f87edafb Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 13:02:23 -0600 Subject: [PATCH 15/19] switch everything to mamba --- .github/workflows/build_docs.yml | 15 +++++++++------ .github/workflows/codecov.yml | 13 ++++++++----- .github/workflows/deploy_docs.yml | 15 +++++++++------ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 40f3315a..3497584c 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -25,19 +25,22 @@ jobs: python-version: '3.10' cache: 'pip' - - name: Set up Miniconda - uses: conda-incubator/setup-miniconda@v3 + - name: Set up micromamba + uses: mamba-org/setup-micromamba@v1 with: - activate-environment: test-env - python-version: ${{matrix.python-version}} + environment-name: test-env + create-args: >- + python=${{ matrix.python-version }} channels: conda-forge channel-priority: strict + cache-downloads: true + cache-env: true - name: Install dependencies run: | - conda install -y -c conda-forge paraview + micromamba install --yes -n test-env -c conda-forge paraview python -m pip install --upgrade pip - pip install -e . + pip install -e . pip install sphinx sphinx_rtd_theme sphinx-autodoc-typehints - name: Build documentation diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 6defac05..28e9b622 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -27,17 +27,20 @@ jobs: python-version: '3.13' cache: 'pip' - - name: Set up Miniconda - uses: conda-incubator/setup-miniconda@v3 + - name: Set up micromamba + uses: mamba-org/setup-micromamba@v1 with: - activate-environment: test-env - python-version: ${{matrix.python-version}} + environment-name: test-env + create-args: >- + python=${{ matrix.python-version }} channels: conda-forge channel-priority: strict + cache-downloads: true + cache-env: true - name: Install dependencies run: | - conda install -y -c conda-forge paraview + micromamba install --yes -n test-env -c conda-forge paraview pip install --upgrade pip pip install pytest pip install pytest-cov diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index ef1ee504..3751c0dc 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -26,18 +26,21 @@ jobs: with: python-version: '3.10' cache: 'pip' - - - name: Set up Miniconda - uses: conda-incubator/setup-miniconda@v3 + + - name: Set up micromamba + uses: mamba-org/setup-micromamba@v1 with: - activate-environment: test-env - python-version: ${{matrix.python-version}} + environment-name: test-env + create-args: >- + python=${{ matrix.python-version }} channels: conda-forge channel-priority: strict + cache-downloads: true + cache-env: true - name: Install dependencies run: | - conda install -y -c conda-forge paraview + micromamba install --yes -n test-env -c conda-forge paraview pip install --upgrade pip pip install -e . pip install sphinx sphinx_rtd_theme sphinx-autodoc-typehints From 744ee1a6664d507c05931c773ebe17130eda6e40 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 16:30:07 -0600 Subject: [PATCH 16/19] remove in file tests --- bird/meshing/block_cyl_mesh.py | 9 --------- bird/postprocess/early_pred.py | 10 ---------- bird/postprocess/kla_utils.py | 4 ---- bird/preprocess/dynamic_mixer/mixing_fvModels.py | 6 ------ bird/preprocess/species_gen/setup_thermo_prop.py | 9 --------- bird/preprocess/stl_patch/stl_bc.py | 11 ----------- tests/io/test_case.py | 5 ----- tests/io/test_read_foam_dict.py | 7 ------- tests/io/test_read_foam_fields.py | 3 --- tests/io/test_read_global_vars.py | 3 --- tests/postprocess/test_cond_mean.py | 3 --- tests/postprocess/test_post_quantities.py | 7 ------- tests/preprocess/test_stl_patch.py | 6 ------ 13 files changed, 83 deletions(-) diff --git a/bird/meshing/block_cyl_mesh.py b/bird/meshing/block_cyl_mesh.py index 8dbf25c2..518ba23d 100644 --- a/bird/meshing/block_cyl_mesh.py +++ b/bird/meshing/block_cyl_mesh.py @@ -550,12 +550,3 @@ def writeBlockMeshDict(out_folder, geom_dict, mesh_dict): fw.close() - -def main(input_file, topo_file, output_folder): - geom_dict = assemble_geom(input_file, topo_file) - mesh_dict = assemble_mesh(input_file, geom_dict) - writeBlockMeshDict(output_folder, geom_dict, mesh_dict) - - -if __name__ == "__main__": - main() diff --git a/bird/postprocess/early_pred.py b/bird/postprocess/early_pred.py index 2ce81e1a..2e491048 100644 --- a/bird/postprocess/early_pred.py +++ b/bird/postprocess/early_pred.py @@ -266,13 +266,3 @@ def bayes_fit(data_dict, num_warmup=1000, num_samples=500): return data_dict - -if __name__ == "__main__": - from bird import BIRD_EARLY_PRED_DATA_DIR - - data_dict, color_files = multi_data_load(BIRD_EARLY_PRED_DATA_DIR) - data_dict = fit_and_ext(data_dict) - plotAllEarly(data_dict, color_files=color_files, chop=True, extrap=True) - bayes_fit(data_dict) - plotAllEarly_uq(data_dict, color_files=color_files) - plt.show() diff --git a/bird/postprocess/kla_utils.py b/bird/postprocess/kla_utils.py index b08bfd65..c7a5af4d 100644 --- a/bird/postprocess/kla_utils.py +++ b/bird/postprocess/kla_utils.py @@ -371,7 +371,3 @@ def print_res_dict(res_dict: dict) -> None: logger.info(f"\tkla = {kla_nb*3600:.4g} +/- {kla_err_nb*3600:.4g} [h-1]") logger.info(f"\tcstar = {cs_nb:.4g} +/- {cs_err_nb:.4g} [mol/m3]") - -if __name__ == "__main__": - res_dict = compute_kla("data_kla/volume_avg.dat", time_ind=0, conc_ind=1) - print_res_dict(res_dict) diff --git a/bird/preprocess/dynamic_mixer/mixing_fvModels.py b/bird/preprocess/dynamic_mixer/mixing_fvModels.py index 80b0df2b..69cc48f4 100644 --- a/bird/preprocess/dynamic_mixer/mixing_fvModels.py +++ b/bird/preprocess/dynamic_mixer/mixing_fvModels.py @@ -55,9 +55,3 @@ def write_fvModel(input_dict, output_folder=".", force_sign=False): write_end(output_folder) - -if __name__ == "__main__": - input_dict = parse_json( - os.path.join("mixing_template", "loop_reactor_list", "mixers.json"), - ) - write_fvModel(input_dict) diff --git a/bird/preprocess/species_gen/setup_thermo_prop.py b/bird/preprocess/species_gen/setup_thermo_prop.py index 95ff2138..31c68dc6 100644 --- a/bird/preprocess/species_gen/setup_thermo_prop.py +++ b/bird/preprocess/species_gen/setup_thermo_prop.py @@ -420,12 +420,3 @@ def write_species_properties(case_folder: str, phase: str = "gas") -> None: ) write_openfoam_dict(thermo_properties_update, filename=filename) - -if __name__ == "__main__": - from bird import BIRD_DIR - - case_folder = os.path.join(BIRD_DIR, "../experimental_cases/deckwer17") - write_species_properties(case_folder, phase="gas") - write_species_properties(case_folder, phase="liquid") - # fill_global_prop(os.path.join(BIRD_DIR,"../experimental_cases_new/disengagement/bubble_column_pbe_20L/")) - # fill_global_prop(os.path.join(BIRD_DIR, "../experimental_cases_new/deckwer17")) diff --git a/bird/preprocess/stl_patch/stl_bc.py b/bird/preprocess/stl_patch/stl_bc.py index 216c762c..855c09cb 100644 --- a/bird/preprocess/stl_patch/stl_bc.py +++ b/bird/preprocess/stl_patch/stl_bc.py @@ -47,14 +47,3 @@ def write_boundaries(input_dict, output_folder="."): boundary_mesh.save( os.path.join(output_folder, f"{boundary_name}.stl") ) - - -if __name__ == "__main__": - input_dict = parse_json( - "bc_patch_mesh_template/loop_reactor_expl/inlets_outlets.json" - ) - write_boundaries(input_dict) - input_dict = parse_json( - "bc_patch_mesh_template/loop_reactor_branch/inlets_outlets.json" - ) - write_boundaries(input_dict) diff --git a/tests/io/test_case.py b/tests/io/test_case.py index 2d80f37f..b0b9c636 100644 --- a/tests/io/test_case.py +++ b/tests/io/test_case.py @@ -80,8 +80,3 @@ def test_mesh_vol(): assert np.linalg.norm(volumes - volumes2) < 1e-12 - -if __name__ == "__main__": - test_case_time() - test_mesh() - test_mesh_vol() diff --git a/tests/io/test_read_foam_dict.py b/tests/io/test_read_foam_dict.py index fe5989a1..b93f7e23 100644 --- a/tests/io/test_read_foam_dict.py +++ b/tests/io/test_read_foam_dict.py @@ -142,10 +142,3 @@ def test_read_controlDict(): assert foam_dict["writeControl"] == "adjustableRunTime" assert foam_dict["maxCo"] == "0.5" - -if __name__ == "__main__": - test_read_thermophysicalProperties() - test_read_phaseProperties() - test_read_thermophysicalProperties() - test_read_momentumTransport() - test_read_controlDict() diff --git a/tests/io/test_read_foam_fields.py b/tests/io/test_read_foam_fields.py index 44afb59e..e75f1ce4 100644 --- a/tests/io/test_read_foam_fields.py +++ b/tests/io/test_read_foam_fields.py @@ -213,6 +213,3 @@ def test_read_mu_liquid(): os.path.join(case_folder, "80", "thermo:mu.liquid"), ) - -if __name__ == "__main__": - test_read_mu_liquid() diff --git a/tests/io/test_read_global_vars.py b/tests/io/test_read_global_vars.py index edc164c8..560e7bd4 100644 --- a/tests/io/test_read_global_vars.py +++ b/tests/io/test_read_global_vars.py @@ -105,6 +105,3 @@ def test_read_global_vars(): < 1e-3 ) - -if __name__ == "__main__": - test_read_global_vars() diff --git a/tests/postprocess/test_cond_mean.py b/tests/postprocess/test_cond_mean.py index a3ec6785..f89e6c6f 100644 --- a/tests/postprocess/test_cond_mean.py +++ b/tests/postprocess/test_cond_mean.py @@ -44,6 +44,3 @@ def test_compute_cond(): pretty_labels(plot_name, "y [m]", 14) plt.close() - -if __name__ == "__main__": - test_compute_cond() diff --git a/tests/postprocess/test_post_quantities.py b/tests/postprocess/test_post_quantities.py index 9ecde554..faf8e205 100644 --- a/tests/postprocess/test_post_quantities.py +++ b/tests/postprocess/test_post_quantities.py @@ -367,10 +367,3 @@ def test_fitted_kla(): for time_folder in [str(entry) for entry in range(81, 91)]: shutil.rmtree(os.path.join(case_folder, time_folder)) - -if __name__ == "__main__": - # test_compute_superficial_gas_velocity() - # test_compute_gh() - # test_ave_y_liq() - # test_ave_conc_liq() - test_fitted_kla() diff --git a/tests/preprocess/test_stl_patch.py b/tests/preprocess/test_stl_patch.py index f76c2309..bb5f9e90 100644 --- a/tests/preprocess/test_stl_patch.py +++ b/tests/preprocess/test_stl_patch.py @@ -76,9 +76,3 @@ def test_loop_reactor_branch(): axes = plot_stl(os.path.join(tmpdirname, "inlets.stl")) pretty_labels("x", "y", zlabel="z", fontsize=14, ax=axes) - -if __name__ == "__main__": - from prettyPlot.plotting import plt - - test_spider_sparger() - plt.show() From 67a1ae68fd789dec7d00461f9e065f05d41814b5 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 16:30:21 -0600 Subject: [PATCH 17/19] report 95% confidence --- bird/postprocess/stats.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bird/postprocess/stats.py b/bird/postprocess/stats.py index 34565b47..e79f69b0 100644 --- a/bird/postprocess/stats.py +++ b/bird/postprocess/stats.py @@ -153,6 +153,10 @@ def calc_mean( """ Compute mean and the uncertainty about the mean, from a time-series + Following Trenberth, "Some Effects of Finite Sample Size and Persistence on Meteorological Statistics. Part I: Autocorrelations", 1984 + And Oliver et al., "Estimating uncertainties in statistics computed from direct numerical simulation", 2014 + + Parameters ---------- time_series: np.ndarray @@ -167,7 +171,7 @@ def calc_mean( mean_val: float Mean value of the time_series unc_val: float - 68% uncertainty (1 sigma) about the mean + 95% uncertainty (1.96 sigma) about the mean """ @@ -181,4 +185,4 @@ def calc_mean( sigsq = np.var(time_series) * N / (N - T0) unc_val = np.sqrt(sigsq * T0 / N) - return mean_val, unc_val + return mean_val, unc_val * 1.96 From 6943225681b352c876cb33dd316d06424cc2fccb Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 16:30:52 -0600 Subject: [PATCH 18/19] cleanup public facing API doc --- docs/source/bird.postprocess.rst | 47 ++++++++++++++++---------------- docs/source/bird.rst | 8 ++++-- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/docs/source/bird.postprocess.rst b/docs/source/bird.postprocess.rst index 9ac22476..8dfe4b94 100644 --- a/docs/source/bird.postprocess.rst +++ b/docs/source/bird.postprocess.rst @@ -1,29 +1,30 @@ bird.postprocess package ======================== -bird.postprocess.conditional\_mean module ------------------------------------------ - -.. automodule:: bird.postprocess.conditional_mean - :members: - :undoc-members: - :show-inheritance: - -bird.postprocess.early\_pred module ------------------------------------ - -.. automodule:: bird.postprocess.early_pred - :members: - :undoc-members: - :show-inheritance: - -bird.postprocess.kla\_utils module ----------------------------------- - -.. automodule:: bird.postprocess.kla_utils - :members: - :undoc-members: - :show-inheritance: +.. comment API for now + bird.postprocess.conditional\_mean module + ----------------------------------------- + + .. automodule:: bird.postprocess.conditional_mean + :members: + :undoc-members: + :show-inheritance: + + bird.postprocess.early\_pred module + ----------------------------------- + + .. automodule:: bird.postprocess.early_pred + :members: + :undoc-members: + :show-inheritance: + + bird.postprocess.kla\_utils module + ---------------------------------- + + .. automodule:: bird.postprocess.kla_utils + :members: + :undoc-members: + :show-inheritance: bird.postprocess.post\_quantities module ---------------------------------------- diff --git a/docs/source/bird.rst b/docs/source/bird.rst index e8fb4a96..9d4cc2d5 100644 --- a/docs/source/bird.rst +++ b/docs/source/bird.rst @@ -7,9 +7,11 @@ Subpackages .. toctree:: :maxdepth: 1 - bird.calibration - bird.meshing + .. comment API for now + bird.calibration + bird.meshing + bird.preprocess + bird.postprocess - bird.preprocess bird.utilities From bcf48d8f362657d519ff7e963b585fa455e2cc04 Mon Sep 17 00:00:00 2001 From: Malik Date: Sun, 19 Oct 2025 16:31:02 -0600 Subject: [PATCH 19/19] update v --- bird/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bird/version.py b/bird/version.py index a0013d91..6825d034 100644 --- a/bird/version.py +++ b/bird/version.py @@ -1,3 +1,3 @@ """Bio reactor design version""" -__version__ = "0.0.49" +__version__ = "0.0.50"