From dbf8c4a834fdb7e3dcd9f438eddb4535368e62b2 Mon Sep 17 00:00:00 2001 From: Gerry Knapp Date: Tue, 16 Jun 2026 15:13:47 -0400 Subject: [PATCH 1/5] minor cleanup of existing CI syntax --- .github/workflows/CI.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6bc2e9c0..dc010ad6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -7,7 +7,7 @@ on: branches: - main concurrency: - group: ${ {github.event_name }}-${{ github.workflow }}-${{ github.ref }} + group: ${{ github.event_name }}-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{github.event_name == 'pull_request'}} jobs: CI: @@ -34,8 +34,7 @@ jobs: - name: Test AdditiveFOAM run: | . /opt/openfoam13/etc/bashrc || true - cp -r tutorials/AMB2018-02-B userCase - cd userCase + cd tutorials/AMB2018-02-B blockMesh decomposePar mpirun -n 6 --oversubscribe --allow-run-as-root additiveFoam -parallel From 1fdecad99181d726dcaf8c08b9f174eddfa3e77c Mon Sep 17 00:00:00 2001 From: Gerry Knapp Date: Tue, 16 Jun 2026 15:18:55 -0400 Subject: [PATCH 2/5] add script and CI to pull material files from myna and generate mist files - pull request CI enforces that the material files haven't been manually changed - weekly chron job checks the main branch of the Myna repo for any changes, updates if so --- .github/workflows/CI.yml | 7 +- .github/workflows/update-materials.yml | 48 +++++ tools/materials/generate_mist_materials.py | 219 +++++++++++++++++++++ 3 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/update-materials.yml create mode 100644 tools/materials/generate_mist_materials.py diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index dc010ad6..2a37fe93 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -25,7 +25,12 @@ jobs: options: --user root steps: - name: Checkout AdditiveFOAM - uses: actions/checkout@v2 + uses: actions/checkout@v4 + - name: Verify generated material data + run: | + python3 -m pip install --upgrade pip + python3 tools/materials/generate_mist_materials.py --from-manifest --install-mist + git diff --exit-code -- materials - name: Build AdditiveFOAM run: | . /opt/openfoam13/etc/bashrc || true diff --git a/.github/workflows/update-materials.yml b/.github/workflows/update-materials.yml new file mode 100644 index 00000000..fa5544c9 --- /dev/null +++ b/.github/workflows/update-materials.yml @@ -0,0 +1,48 @@ +name: Update Mist Materials + +on: + schedule: + - cron: '0 8 * * 1' + workflow_dispatch: + +concurrency: + group: update-mist-materials + cancel-in-progress: false + +permissions: + contents: write + pull-requests: write + +jobs: + update-materials: + runs-on: ubuntu-latest + steps: + - name: Checkout AdditiveFOAM + uses: actions/checkout@v4 + - name: Generate material files + run: | + python3 -m pip install --upgrade pip + python3 tools/materials/generate_mist_materials.py --myna-ref main --mist-ref main --install-mist + - name: Check for material changes + id: material-changes + run: | + if [ -z "$(git status --porcelain -- materials)" ]; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "No material changes detected." + else + echo "changed=true" >> "$GITHUB_OUTPUT" + git status --short -- materials + fi + - name: Open update pull request + if: steps.material-changes.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v6 + with: + branch: automation/update-mist-materials + commit-message: Update generated Mist material files + title: Update generated Mist material files + body: | + Regenerates AdditiveFOAM material configuration files from Myna Mist material data. + + This PR was created by the weekly material update workflow. + add-paths: | + materials diff --git a/tools/materials/generate_mist_materials.py b/tools/materials/generate_mist_materials.py new file mode 100644 index 00000000..de7d1881 --- /dev/null +++ b/tools/materials/generate_mist_materials.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 +"""Generate AdditiveFOAM material inputs from Myna Mist material data.""" + +from __future__ import annotations + +import argparse +import json +import os +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[2] +DEFAULT_MYNA_URL = "https://github.com/ORNL-MDF/Myna.git" +DEFAULT_MIST_URL = "https://github.com/ORNL-MDF/mist.git" + + +def run(cmd: list[str], cwd: Path | None = None) -> str: + return subprocess.check_output(cmd, cwd=cwd, text=True).strip() + + +def load_manifest(output_dir: Path) -> dict: + manifest_path = output_dir / "manifest.json" + if not manifest_path.exists(): + return {} + with manifest_path.open(encoding="utf-8") as f: + return json.load(f) + + +def clone_repo(url: str, ref: str, destination: Path) -> str: + run(["git", "clone", "--quiet", url, str(destination)]) + run(["git", "checkout", "--quiet", ref], cwd=destination) + return run(["git", "rev-parse", "HEAD"], cwd=destination) + + +def install_mist(mist_url: str, mist_ref: str) -> str: + with tempfile.TemporaryDirectory() as tmp: + mist_dir = Path(tmp) / "mist" + resolved_ref = clone_repo(mist_url, mist_ref, mist_dir) + subprocess.check_call( + [sys.executable, "-m", "pip", "install", "--quiet", str(mist_dir)] + ) + return resolved_ref + + +def import_mistlib(install: bool, mist_url: str, mist_ref: str) -> tuple[object, str]: + resolved_ref = mist_ref + if install: + resolved_ref = install_mist(mist_url, mist_ref) + + try: + import mistlib as mist # type: ignore + except ImportError as exc: + raise SystemExit( + "mistlib is not importable. Re-run with --install-mist or install Mist." + ) from exc + + return mist, resolved_ref + + +def material_files(myna_dir: Path) -> list[Path]: + data_dir = myna_dir / "src" / "myna" / "mist_material_data" + if not data_dir.is_dir(): + raise SystemExit(f"Myna material data directory not found: {data_dir}") + return sorted(data_dir.glob("*.json")) + + +def display_path(path: Path) -> str: + try: + return str(path.relative_to(REPO_ROOT)) + except ValueError: + return str(path) + + +def generate_material( + mist: object, + material_json: Path, + myna_dir: Path, + output_dir: Path, +) -> dict: + material_name = material_json.stem + material_dir = output_dir / material_name + material_dir.mkdir(parents=True, exist_ok=True) + + mat = mist.core.MaterialInformation(str(material_json)) + transport_file = material_dir / "transportProperties" + thermo_file = material_dir / "thermoPath" + mat.write_additivefoam_input( + transport_file=str(transport_file), + thermo_file=str(thermo_file), + ) + + return { + "name": material_name, + "source": str(material_json.relative_to(myna_dir)), + "files": [ + display_path(transport_file), + display_path(thermo_file), + ], + } + + +def write_manifest( + output_dir: Path, + myna_url: str, + myna_ref: str, + myna_sha: str, + mist_url: str, + mist_ref: str, + mist_sha: str, + materials: list[dict], +) -> None: + manifest = { + "generated_by": "tools/materials/generate_mist_materials.py", + "sources": { + "myna": { + "url": myna_url, + "ref": myna_ref, + "sha": myna_sha, + "material_data_path": "src/myna/mist_material_data", + }, + "mist": { + "url": mist_url, + "ref": mist_ref, + "sha": mist_sha, + "package": "mistlib", + }, + }, + "materials": materials, + } + with (output_dir / "manifest.json").open("w", encoding="utf-8") as f: + json.dump(manifest, f, indent=2) + f.write("\n") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output-dir", default=str(REPO_ROOT / "materials")) + parser.add_argument("--myna-url", default=DEFAULT_MYNA_URL) + parser.add_argument("--mist-url", default=DEFAULT_MIST_URL) + parser.add_argument("--myna-ref", default="main") + parser.add_argument("--mist-ref", default="main") + parser.add_argument("--myna-dir", default=None) + parser.add_argument( + "--from-manifest", + action="store_true", + help="Use source URLs and SHAs from materials/manifest.json.", + ) + parser.add_argument( + "--install-mist", + action="store_true", + help="Install Mist from the selected Git ref before generation.", + ) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + output_dir = Path(args.output_dir).resolve() + output_dir.mkdir(parents=True, exist_ok=True) + myna_checkout_ref = args.myna_ref + mist_install_ref = args.mist_ref + + if args.from_manifest: + manifest = load_manifest(output_dir) + sources = manifest.get("sources", {}) + myna = sources.get("myna", {}) + mist = sources.get("mist", {}) + args.myna_url = myna.get("url", args.myna_url) + args.myna_ref = myna.get("ref", args.myna_ref) + myna_checkout_ref = myna.get("sha", args.myna_ref) + args.mist_url = mist.get("url", args.mist_url) + args.mist_ref = mist.get("ref", args.mist_ref) + mist_install_ref = mist.get("sha", args.mist_ref) + + mist_module, mist_sha = import_mistlib( + args.install_mist, + args.mist_url, + mist_install_ref, + ) + + with tempfile.TemporaryDirectory() as tmp: + if args.myna_dir: + myna_dir = Path(args.myna_dir).resolve() + myna_sha = run(["git", "rev-parse", "HEAD"], cwd=myna_dir) + else: + myna_dir = Path(tmp) / "Myna" + myna_sha = clone_repo(args.myna_url, myna_checkout_ref, myna_dir) + + for path in output_dir.iterdir(): + if path.name == "manifest.json": + continue + if path.is_dir(): + shutil.rmtree(path) + else: + path.unlink() + + materials = [ + generate_material(mist_module, material_json, myna_dir, output_dir) + for material_json in material_files(myna_dir) + ] + + write_manifest( + output_dir, + args.myna_url, + args.myna_ref, + myna_sha, + args.mist_url, + args.mist_ref, + mist_sha, + materials, + ) + + +if __name__ == "__main__": + main() From cef21fef0716fe726a568c413027b0b537e594ef Mon Sep 17 00:00:00 2001 From: Gerry Knapp Date: Tue, 16 Jun 2026 15:19:22 -0400 Subject: [PATCH 3/5] add initial pull of myna material files --- materials/IN625/thermoPath | 4 +++ materials/IN625/transportProperties | 40 ++++++++++++++++++++++ materials/IN718/thermoPath | 4 +++ materials/IN718/transportProperties | 40 ++++++++++++++++++++++ materials/SS316H/thermoPath | 4 +++ materials/SS316H/transportProperties | 40 ++++++++++++++++++++++ materials/SS316L/thermoPath | 4 +++ materials/SS316L/transportProperties | 40 ++++++++++++++++++++++ materials/manifest.json | 51 ++++++++++++++++++++++++++++ 9 files changed, 227 insertions(+) create mode 100644 materials/IN625/thermoPath create mode 100644 materials/IN625/transportProperties create mode 100644 materials/IN718/thermoPath create mode 100644 materials/IN718/transportProperties create mode 100644 materials/SS316H/thermoPath create mode 100644 materials/SS316H/transportProperties create mode 100644 materials/SS316L/thermoPath create mode 100644 materials/SS316L/transportProperties create mode 100644 materials/manifest.json diff --git a/materials/IN625/thermoPath b/materials/IN625/thermoPath new file mode 100644 index 00000000..61f9157e --- /dev/null +++ b/materials/IN625/thermoPath @@ -0,0 +1,4 @@ +( +1563.0000 1.0000 +1623.0000 0.0000 +) \ No newline at end of file diff --git a/materials/IN625/transportProperties b/materials/IN625/transportProperties new file mode 100644 index 00000000..dc69bfcd --- /dev/null +++ b/materials/IN625/transportProperties @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------- + AdditiveFOAM template input file (compatible with 1.0, OpenFOAM 10) + + Created with Mist + ---------------------------------------------------------------------------*/ + FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object transportProperties; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + solid +{ + kappa (4.5847 0.0163 0.0); + Cp (338.39 0.2441 0.0); +} + +liquid +{ + kappa (30.078 0.0 0.0); + Cp (709.25 0.0 0.0); +} + +powder +{ + kappa (4.5847 0.0163 0.0); + Cp (338.39 0.2441 0.0); +} + +rho [1 -3 0 0 0 0 0] 8440; +mu [1 -1 -1 0 0 0 0] 0.007; +beta [0 0 0 -1 0 0 0] 5e-05; +DAS [0 1 0 0 0 0 0] 10e-6; +Lf [0 2 -2 0 0 0 0] 2.90e+05; + +// ************************************************************************* // \ No newline at end of file diff --git a/materials/IN718/thermoPath b/materials/IN718/thermoPath new file mode 100644 index 00000000..61f9157e --- /dev/null +++ b/materials/IN718/thermoPath @@ -0,0 +1,4 @@ +( +1563.0000 1.0000 +1623.0000 0.0000 +) \ No newline at end of file diff --git a/materials/IN718/transportProperties b/materials/IN718/transportProperties new file mode 100644 index 00000000..c72ef77d --- /dev/null +++ b/materials/IN718/transportProperties @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------- + AdditiveFOAM template input file (compatible with 1.0, OpenFOAM 10) + + Created with Mist + ---------------------------------------------------------------------------*/ + FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object transportProperties; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + solid +{ + kappa (5.291 0.0152 1.382e-06); + Cp (362.0 0.2118 0.0); +} + +liquid +{ + kappa (30.0 0.0 0.0); + Cp (775.0 0.0 0.0); +} + +powder +{ + kappa (5.291 0.0152 1.382e-06); + Cp (362.0 0.2118 0.0); +} + +rho [1 -3 0 0 0 0 0] 8170; +mu [1 -1 -1 0 0 0 0] 0.007; +beta [0 0 0 -1 0 0 0] 1.07e-05; +DAS [0 1 0 0 0 0 0] 10e-6; +Lf [0 2 -2 0 0 0 0] 1.96e+05; + +// ************************************************************************* // \ No newline at end of file diff --git a/materials/SS316H/thermoPath b/materials/SS316H/thermoPath new file mode 100644 index 00000000..998e5b3a --- /dev/null +++ b/materials/SS316H/thermoPath @@ -0,0 +1,4 @@ +( +1471.0000 1.0000 +1709.0000 0.0000 +) \ No newline at end of file diff --git a/materials/SS316H/transportProperties b/materials/SS316H/transportProperties new file mode 100644 index 00000000..679a90b9 --- /dev/null +++ b/materials/SS316H/transportProperties @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------- + AdditiveFOAM template input file (compatible with 1.0, OpenFOAM 10) + + Created with Mist + ---------------------------------------------------------------------------*/ + FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object transportProperties; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + solid +{ + kappa (9.248 0.01571 0.0); + Cp (386.7 0.1329 0.0); +} + +liquid +{ + kappa (12.41 0.003279 0.0); + Cp (770.4 0.0 0.0); +} + +powder +{ + kappa (9.248 0.01571 0.0); + Cp (386.7 0.1329 0.0); +} + +rho [1 -3 0 0 0 0 0] 7955; +mu [1 -1 -1 0 0 0 0] 0.002188; +beta [0 0 0 -1 0 0 0] 3.101e-05; +DAS [0 1 0 0 0 0 0] 10e-6; +Lf [0 2 -2 0 0 0 0] 2.68e+05; + +// ************************************************************************* // \ No newline at end of file diff --git a/materials/SS316L/thermoPath b/materials/SS316L/thermoPath new file mode 100644 index 00000000..998e5b3a --- /dev/null +++ b/materials/SS316L/thermoPath @@ -0,0 +1,4 @@ +( +1471.0000 1.0000 +1709.0000 0.0000 +) \ No newline at end of file diff --git a/materials/SS316L/transportProperties b/materials/SS316L/transportProperties new file mode 100644 index 00000000..679a90b9 --- /dev/null +++ b/materials/SS316L/transportProperties @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------- + AdditiveFOAM template input file (compatible with 1.0, OpenFOAM 10) + + Created with Mist + ---------------------------------------------------------------------------*/ + FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object transportProperties; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + solid +{ + kappa (9.248 0.01571 0.0); + Cp (386.7 0.1329 0.0); +} + +liquid +{ + kappa (12.41 0.003279 0.0); + Cp (770.4 0.0 0.0); +} + +powder +{ + kappa (9.248 0.01571 0.0); + Cp (386.7 0.1329 0.0); +} + +rho [1 -3 0 0 0 0 0] 7955; +mu [1 -1 -1 0 0 0 0] 0.002188; +beta [0 0 0 -1 0 0 0] 3.101e-05; +DAS [0 1 0 0 0 0 0] 10e-6; +Lf [0 2 -2 0 0 0 0] 2.68e+05; + +// ************************************************************************* // \ No newline at end of file diff --git a/materials/manifest.json b/materials/manifest.json new file mode 100644 index 00000000..401c5953 --- /dev/null +++ b/materials/manifest.json @@ -0,0 +1,51 @@ +{ + "generated_by": "tools/materials/generate_mist_materials.py", + "sources": { + "myna": { + "url": "https://github.com/ORNL-MDF/Myna.git", + "ref": "main", + "sha": "9063f10338dd7bed5e89b9ba5b938ab38044ddff", + "material_data_path": "src/myna/mist_material_data" + }, + "mist": { + "url": "https://github.com/ORNL-MDF/mist.git", + "ref": "main", + "sha": "bc712df400a1e8abe7944839c4d0df676c7e7eaa", + "package": "mistlib" + } + }, + "materials": [ + { + "name": "IN625", + "source": "src/myna/mist_material_data/IN625.json", + "files": [ + "materials/IN625/transportProperties", + "materials/IN625/thermoPath" + ] + }, + { + "name": "IN718", + "source": "src/myna/mist_material_data/IN718.json", + "files": [ + "materials/IN718/transportProperties", + "materials/IN718/thermoPath" + ] + }, + { + "name": "SS316H", + "source": "src/myna/mist_material_data/SS316H.json", + "files": [ + "materials/SS316H/transportProperties", + "materials/SS316H/thermoPath" + ] + }, + { + "name": "SS316L", + "source": "src/myna/mist_material_data/SS316L.json", + "files": [ + "materials/SS316L/transportProperties", + "materials/SS316L/thermoPath" + ] + } + ] +} From 9fc63d5746379c092f77ffda3be2fc021d499c9d Mon Sep 17 00:00:00 2001 From: Gerry Knapp Date: Tue, 16 Jun 2026 16:16:37 -0400 Subject: [PATCH 4/5] update thermoPath format and AMB2018-02-B tutorial to use config - thermoPath is now a FoamDict, allowing it to use the #include syntax - transportProperties also now uses the #include syntax - function objects now set isoValues to default to thermoPath values, if not directly set by the user - some updates to the build files due to functionObjects now depending on the readThermoPath utility - Allrun provides setting the path to the AdditiveFOAM repo to find the materials config file folder --- applications/solvers/additiveFoam/Allwmake | 2 +- .../solvers/additiveFoam/additiveFoam.C | 1 + .../solvers/additiveFoam/createFields.H | 15 +-- .../functionObjects/ExaCA/ExaCA.C | 10 +- .../additiveFoam/functionObjects/Make/files | 1 + .../additiveFoam/functionObjects/Make/options | 4 + .../meltPoolDimensions/meltPoolDimensions.C | 11 ++- .../solidificationData/solidificationData.C | 11 ++- .../functionObjects/thermoPathIsoDefaults.C | 67 +++++++++++++ .../functionObjects/thermoPathIsoDefaults.H | 52 ++++++++++ .../solvers/additiveFoam/readThermoPath.H | 94 +++++++++++++++++++ tutorials/AMB2018-02-B/Allrun | 10 +- tutorials/AMB2018-02-B/README.md | 11 +++ tutorials/AMB2018-02-B/constant/thermoPath | 25 ++++- .../AMB2018-02-B/constant/transportProperties | 25 +---- tutorials/AMB2018-02-B/system/controlDict | 3 - 16 files changed, 294 insertions(+), 48 deletions(-) create mode 100644 applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.C create mode 100644 applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.H create mode 100644 applications/solvers/additiveFoam/readThermoPath.H diff --git a/applications/solvers/additiveFoam/Allwmake b/applications/solvers/additiveFoam/Allwmake index 9735535b..d9b9ff30 100755 --- a/applications/solvers/additiveFoam/Allwmake +++ b/applications/solvers/additiveFoam/Allwmake @@ -27,8 +27,8 @@ export ADDITIVEFOAM_BUILD_FLAGS="-DGIT_MODULE_ENABLED=1" #------------------------------------------------------------------------------ # Build libraries and solver -wmake $targetType functionObjects wmake $targetType utilities +wmake $targetType functionObjects wmake $targetType movingHeatSource wmake $targetType diff --git a/applications/solvers/additiveFoam/additiveFoam.C b/applications/solvers/additiveFoam/additiveFoam.C index 4abf2906..f3386aed 100644 --- a/applications/solvers/additiveFoam/additiveFoam.C +++ b/applications/solvers/additiveFoam/additiveFoam.C @@ -59,6 +59,7 @@ Description #include "movingHeatSourceModel.H" #include "graph.H" #include "interpolateXY.H" +#include "readThermoPath.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/applications/solvers/additiveFoam/createFields.H b/applications/solvers/additiveFoam/createFields.H index 4a45b0ba..412229a4 100644 --- a/applications/solvers/additiveFoam/createFields.H +++ b/applications/solvers/additiveFoam/createFields.H @@ -43,19 +43,10 @@ volScalarField alpha1 zeroGradientFvPatchScalarField::typeName ); -IFstream thermoFile -( - runTime.rootPath()/runTime.globalCaseName() - /runTime.constant()/"thermoPath" -); +Info<< "Reading thermoPath\n" << endl; -graph thermo -( - "thermo", - "T", - "alpha1", - thermoFile -); +autoPtr thermoPtr(readThermoPath(mesh)); +graph& thermo = thermoPtr(); dimensionedScalar Tliq ( diff --git a/applications/solvers/additiveFoam/functionObjects/ExaCA/ExaCA.C b/applications/solvers/additiveFoam/functionObjects/ExaCA/ExaCA.C index 73846a94..1ecf503f 100644 --- a/applications/solvers/additiveFoam/functionObjects/ExaCA/ExaCA.C +++ b/applications/solvers/additiveFoam/functionObjects/ExaCA/ExaCA.C @@ -38,6 +38,7 @@ License #include "polyTopoChangeMap.H" #include "polyMeshMap.H" #include "polyDistributionMap.H" +#include "thermoPathIsoDefaults.H" #include @@ -400,7 +401,14 @@ bool Foam::functionObjects::ExaCA::read(const dictionary& dict) { box_ = dict.lookup("box"); - isoValue_ = dict.lookup("isoValue"); + if (dict.found("isoValue")) + { + isoValue_ = dict.lookup("isoValue"); + } + else + { + isoValue_ = thermoPathLiquidus(mesh_); + } dx_ = dict.lookup("dx"); diff --git a/applications/solvers/additiveFoam/functionObjects/Make/files b/applications/solvers/additiveFoam/functionObjects/Make/files index b513dbe0..83f09108 100644 --- a/applications/solvers/additiveFoam/functionObjects/Make/files +++ b/applications/solvers/additiveFoam/functionObjects/Make/files @@ -1,5 +1,6 @@ ExaCA/ExaCA.C solidificationData/solidificationData.C meltPoolDimensions/meltPoolDimensions.C +thermoPathIsoDefaults.C LIB = $(FOAM_USER_LIBBIN)/libadditiveFoamFunctionObjects diff --git a/applications/solvers/additiveFoam/functionObjects/Make/options b/applications/solvers/additiveFoam/functionObjects/Make/options index a3ae8da8..9f4d57cb 100644 --- a/applications/solvers/additiveFoam/functionObjects/Make/options +++ b/applications/solvers/additiveFoam/functionObjects/Make/options @@ -1,7 +1,11 @@ EXE_INC = \ + -I.. \ + -I../utilities/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude LIB_LIBS = \ + -L$(FOAM_USER_LIBBIN) \ + -ladditiveFoamUtilities \ -lfiniteVolume \ -lmeshTools diff --git a/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C index 6e661ec1..b61ccead 100644 --- a/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C +++ b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C @@ -34,6 +34,7 @@ License #include "OSspecific.H" #include "labelVector.H" #include "treeBoundBox.H" +#include "thermoPathIsoDefaults.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -111,7 +112,15 @@ Foam::functionObjects::meltPoolDimensions::~meltPoolDimensions() bool Foam::functionObjects::meltPoolDimensions::read(const dictionary& dict) { - isoValues_ = dict.lookup("isoValues"); + if (dict.found("isoValues")) + { + isoValues_ = dict.lookup("isoValues"); + } + else + { + isoValues_ = thermoPathTemperatureList(mesh_); + } + scanPathAngle_ = dict.lookupOrDefault("scanPathAngle", 0.0); return true; diff --git a/applications/solvers/additiveFoam/functionObjects/solidificationData/solidificationData.C b/applications/solvers/additiveFoam/functionObjects/solidificationData/solidificationData.C index 27c36521..55b139d8 100644 --- a/applications/solvers/additiveFoam/functionObjects/solidificationData/solidificationData.C +++ b/applications/solvers/additiveFoam/functionObjects/solidificationData/solidificationData.C @@ -34,6 +34,7 @@ License #include "OFstream.H" #include "OSspecific.H" #include "labelVector.H" +#include "thermoPathIsoDefaults.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -102,7 +103,15 @@ Foam::functionObjects::solidificationData::~solidificationData() bool Foam::functionObjects::solidificationData::read(const dictionary& dict) { box_ = dict.lookup("box"); - isoValue_ = dict.lookup("isoValue"); + + if (dict.found("isoValue")) + { + isoValue_ = dict.lookup("isoValue"); + } + else + { + isoValue_ = thermoPathLiquidus(mesh_); + } return true; } diff --git a/applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.C b/applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.C new file mode 100644 index 00000000..9baa9831 --- /dev/null +++ b/applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.C @@ -0,0 +1,67 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2024 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2026 Oak Ridge National Laboratory +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +\*---------------------------------------------------------------------------*/ + +#include "thermoPathIsoDefaults.H" +#include "readThermoPath.H" +#include "graph.H" +#include "interpolateXY.H" + +namespace Foam +{ +namespace functionObjects +{ + +scalar thermoPathLiquidus(const fvMesh& mesh) +{ + autoPtr thermoPtr(readThermoPath(mesh)); + const graph& thermo = thermoPtr(); + + return interpolateXY(0.0, thermo.y(), thermo.x()); +} + + +scalar thermoPathSolidus(const fvMesh& mesh) +{ + autoPtr thermoPtr(readThermoPath(mesh)); + const graph& thermo = thermoPtr(); + + return interpolateXY(1.0, thermo.y(), thermo.x()); +} + + +scalarList thermoPathTemperatureList(const fvMesh& mesh) +{ + autoPtr thermoPtr(readThermoPath(mesh)); + const graph& thermo = thermoPtr(); + + return scalarList(thermo.x()); +} + +} +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.H b/applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.H new file mode 100644 index 00000000..b76159f9 --- /dev/null +++ b/applications/solvers/additiveFoam/functionObjects/thermoPathIsoDefaults.H @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2024 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2026 Oak Ridge National Laboratory +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +\*---------------------------------------------------------------------------*/ + +#ifndef thermoPathIsoDefaults_H +#define thermoPathIsoDefaults_H + +#include "scalarList.H" + +namespace Foam +{ + +class fvMesh; + +namespace functionObjects +{ + +scalar thermoPathLiquidus(const fvMesh& mesh); + +scalar thermoPathSolidus(const fvMesh& mesh); + +scalarList thermoPathTemperatureList(const fvMesh& mesh); + +} +} + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/readThermoPath.H b/applications/solvers/additiveFoam/readThermoPath.H new file mode 100644 index 00000000..a74f021d --- /dev/null +++ b/applications/solvers/additiveFoam/readThermoPath.H @@ -0,0 +1,94 @@ +#ifndef readThermoPath_H +#define readThermoPath_H + +#include "Time.H" +#include "fvMesh.H" +#include "IFstream.H" +#include "IOdictionary.H" +#include "graph.H" + +namespace Foam +{ + +inline autoPtr readThermoPath(const fvMesh& mesh) +{ + const Time& runTime = mesh.time(); + + const fileName thermoPathFile + ( + runTime.rootPath()/runTime.globalCaseName()/runTime.constant() + /"thermoPath" + ); + + IFstream thermoHeaderStream(thermoPathFile); + + if (!thermoHeaderStream.good()) + { + FatalErrorInFunction + << "Cannot read thermoPath file " << thermoPathFile + << exit(FatalError); + } + + token firstToken(thermoHeaderStream); + + // Check if thermoPath is legacy AdditiveFOAM v1* version (raw list) + if (firstToken == token::BEGIN_LIST) + { + IFstream thermoFile(thermoPathFile); + + return autoPtr + ( + new graph("thermo", "T", "alpha1", thermoFile) + ); + } + // Otherwise, should be a foamFile + else if + ( + firstToken.isWord() + && firstToken.wordToken() == IOobject::foamFile + ) + { + IOdictionary thermoPathDict + ( + IOobject + ( + "thermoPath", + runTime.constant(), + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE + ) + ); + + const dictionary& thermoPathSubDict = + thermoPathDict.subDict("thermoPath"); + + if (!thermoPathSubDict.found("values")) + { + FatalErrorInFunction + << "FoamFile-style thermoPath must contain a 'values' entry " + << "in sub-dictionary thermoPath" + << exit(FatalError); + } + + ITstream& valuesStream = thermoPathSubDict.lookup("values"); + + return autoPtr + ( + new graph("thermo", "T", "alpha1", valuesStream) + ); + } + + FatalErrorInFunction + << "Unsupported thermoPath format in " << thermoPathFile + << ". Expected a legacy list or a FoamFile dictionary." + << exit(FatalError); + + return autoPtr(); +} + +} + +#endif + +// ************************************************************************* // diff --git a/tutorials/AMB2018-02-B/Allrun b/tutorials/AMB2018-02-B/Allrun index 60a58425..dce3925f 100755 --- a/tutorials/AMB2018-02-B/Allrun +++ b/tutorials/AMB2018-02-B/Allrun @@ -5,6 +5,14 @@ cd ${0%/*} || exit 1 # Run from this directory . $WM_PROJECT_DIR/bin/tools/RunFunctions application=`getApplication` +if [ -z "$ADDITIVEFOAM_INST_DIR" ]; then + if [ -d "../../materials" ]; then + export ADDITIVEFOAM_INST_DIR="$(cd ../.. && pwd -P)" + else + export ADDITIVEFOAM_INST_DIR="$WM_PROJECT_INST_DIR/AdditiveFOAM" + fi +fi + # Parse arguments withExaCA=false while [ "$#" -gt 0 ]; do @@ -26,7 +34,7 @@ done #export ENABLE_SOLIDIFICATION_DATA=true # meltPoolDimensions (optional - default: false) -#export ENABLE_MELTPOOL_DIMENSIONS=true +export ENABLE_MELTPOOL_DIMENSIONS=true # Enable ExaCA function object for '-withExaCA' flag if [ "$withExaCA" = true ]; then diff --git a/tutorials/AMB2018-02-B/README.md b/tutorials/AMB2018-02-B/README.md index 2933b737..a3a99489 100644 --- a/tutorials/AMB2018-02-B/README.md +++ b/tutorials/AMB2018-02-B/README.md @@ -26,6 +26,8 @@ The important files for this tutorial are: ```text constant/heatSourceDict constant/scanPath +constant/transportProperties +constant/thermoPath constant/dynamicMeshDict system/blockMeshDict ``` @@ -42,6 +44,15 @@ constant/scanPath Defines the laser path, laser power, and scan speed or dwell time. +```text +constant/transportProperties +constant/thermoPath +``` + +Reference the shared IN625 material configuration in `materials/IN625`. +Those files are generated from Myna Mist material data using Mist's +AdditiveFOAM writer. + ```text constant/dynamicMeshDict ``` diff --git a/tutorials/AMB2018-02-B/constant/thermoPath b/tutorials/AMB2018-02-B/constant/thermoPath index fdcd4be0..bcdeaf1a 100644 --- a/tutorials/AMB2018-02-B/constant/thermoPath +++ b/tutorials/AMB2018-02-B/constant/thermoPath @@ -1,4 +1,21 @@ -( -1410.0000 1.0000 -1620.0000 0.0000 -) +/*--------------------------------*- C++ -*----------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Version: 13 + \\/ M anipulation | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object thermoPath; +} + +thermoPath +{ + values #include "$ADDITIVEFOAM_INST_DIR/materials/IN625/thermoPath"; +} + +// ************************************************************************* // diff --git a/tutorials/AMB2018-02-B/constant/transportProperties b/tutorials/AMB2018-02-B/constant/transportProperties index 12e004ab..052677be 100644 --- a/tutorials/AMB2018-02-B/constant/transportProperties +++ b/tutorials/AMB2018-02-B/constant/transportProperties @@ -15,29 +15,6 @@ FoamFile // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -solid -{ - kappa (8.275 0.01472 0.0); - Cp (579.28 0.0 0.0); -} - -liquid -{ - kappa (4.889 0.014743 0.0); - Cp (750.65 0.0 0.0); -} - -powder -{ - kappa (-0.07707 0.00075 0.0); - Cp (747.568 0.0 0.0); -} - -//- fluid flow properties -rho [1 -3 0 0 0 0 0] 7569.92; -mu [1 -1 -1 0 0 0 0] 0.003032; -beta [0 0 0 -1 0 0 0] 1.2e-4; -DAS [0 1 0 0 0 0 0] 10e-6; -Lf [0 2 -2 0 0 0 0] 2.1754e5; +#include "$ADDITIVEFOAM_INST_DIR/materials/IN625/transportProperties" // ************************************************************************* // diff --git a/tutorials/AMB2018-02-B/system/controlDict b/tutorials/AMB2018-02-B/system/controlDict index 53ccaa7b..0b971304 100644 --- a/tutorials/AMB2018-02-B/system/controlDict +++ b/tutorials/AMB2018-02-B/system/controlDict @@ -63,7 +63,6 @@ functions type solidificationData; box (-1 -1 -1) (1 1 1); - isoValue 1620; } #endif; @@ -76,7 +75,6 @@ functions box (0 -0.0001 -0.0002) (0.002 0.0001 0); dx 2.5e-6; - isoValue 1620; } #endif; @@ -87,7 +85,6 @@ functions type meltPoolDimensions; - isoValues (1620 1410); scanPathAngle 0.0; } #endif; From 36dcbc8691241f734e41bf6e164c55c2b2c76946 Mon Sep 17 00:00:00 2001 From: Gerry Knapp Date: Tue, 16 Jun 2026 16:26:59 -0400 Subject: [PATCH 5/5] directly define main as the target branch for update-materials CI - not really needed, but the intent is clearer --- .github/workflows/update-materials.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/update-materials.yml b/.github/workflows/update-materials.yml index fa5544c9..7feeee73 100644 --- a/.github/workflows/update-materials.yml +++ b/.github/workflows/update-materials.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout AdditiveFOAM uses: actions/checkout@v4 + with: + ref: main - name: Generate material files run: | python3 -m pip install --upgrade pip @@ -37,6 +39,7 @@ jobs: if: steps.material-changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v6 with: + base: main branch: automation/update-mist-materials commit-message: Update generated Mist material files title: Update generated Mist material files