diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 85a97343..cf98addc 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -42,4 +42,4 @@ jobs: cd userCase blockMesh decomposePar - mpirun -n 6 --oversubscribe --allow-run-as-root additiveFoam -parallel + mpirun -n 8 --oversubscribe --allow-run-as-root additiveFoam -parallel diff --git a/Allwmake b/Allwmake index 830f8594..c00f9c61 100755 --- a/Allwmake +++ b/Allwmake @@ -10,7 +10,7 @@ cd ${0%/*} || exit 1 # Run from this directory #------------------------------------------------------------------------------ # AdditiveFOAM build information -GIT_DESCRIBE=$(git describe --tags --always 2>/dev/null) \ +GIT_DESCRIBE=$(git describe --tags --always --dirty 2>/dev/null) \ || GIT_DESCRIBE="undefined" GIT_SHA1=$(git rev-parse HEAD 2>/dev/null) \ diff --git a/CHANGELOG.md b/CHANGELOG.md index ab881938..1c5ef7f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,91 @@ +# Release 2.0.0 + +## Features + +- Ported AdditiveFOAM to OpenFOAM-14. +- Added dynamic refinement models and reusable material and heat-source + configuration files. +- Added a general projected heat source with super-Gaussian, nLight AFX, and + tabulated planar profiles and an exponential axial projection. +- Added conversion of PRIMES beam measurements with `primesToAdditiveFoam`. +- Added general planar-profile moment metrics, tabulated-profile inspection, + and automatic `D4Sigma` calculation. +- Added rotated elliptical analytic profiles, `e2` and `secondMoment` radius + definitions, and selectable area-equivalent, major, or minor `D4Sigma` + reference widths. +- Added model-specific heat-source bounds that retain at least + `1-tolerance` of the analytical source power. +- Added support-based heat-source quadrature. +- Added an adaptive Bayesian workflow with deterministic posterior quadrature + for calibrating the projected heat-source axial closure. +- Expanded the AMB2018, multi-beam, multi-layer, nLight AFX, and tabulated + tutorials. + +## Bug fixes + +- Made all heat sources one-sided, consistent with their analytic + normalization. +- Synchronized heat-source depth, shape parameters, normalization, and bounds + once before beam subcycling. +- Preserved the active-power fraction when a solver time step crosses the end + of a scan path. +- Restricted isotherm source-depth measurements to the planar source support + below the beam plane and removed a modified super-Gaussian endpoint + singularity. +- Added calculation-ROI reconstruction, coordinate-preserving support cropping, + and beam-statistics reporting to `primesToAdditiveFoam`. +- Preserved an explicitly configured Kelly `aspectRatioSwitch` value and + applied `etaMin` as a lower bound on the Kelly absorption curve. + +## Upgrade notes + +- AdditiveFOAM 2.0 requires OpenFOAM-14. Source the OpenFOAM-14 environment + before sourcing `etc/bashrc` and rebuild AdditiveFOAM with `./Allwmake`. +- Sources now use nested `absorption`, `heatSource`, `profile`, `projection`, + and `refinement` dictionaries with a `model` entry instead of `*Coeffs` + dictionaries. +- The former projected Gaussian, nLight AFX, and tabulated heat-source models + are profiles selected by the `projected` model. Their shared axial model is + selected in the `projection` dictionary. +- `superGaussian` remains a volumetric model and is also a planar profile. + `radius` is two-dimensional and `depth` is a separate scalar. +- The tabulated profile derives its D4Sigma metrics from the beam-profile + table. No user-supplied lateral dimensions are required. +- Profile metrics expose `D4Sigma` as `(major minor)`. Reference dimensions + select the scalar width and constant or isotherm depth used by aspect-ratio + closures. +- Aspect-ratio closures use a `D4Sigma` width reference, with selectable + `areaEquivalent`, `major`, or `minor` component, and a `constant` or + `isotherm` depth reference. +- The `A` and `B` projected-depth coefficients are named `nSlope` and + `nIntercept` in the `projection` dictionary. +- Python 3.10 through 3.12 and the packages in `requirements.txt` are required + only for the calibration and plotting utilities. + +## Full Changelog + +For a complete list of changes, see the [full changelog](https://github.com/ORNL/AdditiveFOAM/compare/1.2.0...2.0.0). + + +# Release 1.2.0 + +## Features + +- Added the projected Gaussian heat-source model. +- Added melt-pool-dimension and solidification-data function objects. +- Added optional implicit temperature limiting through the PIMPLE dictionary. +- Added multi-layer scan-path support and updated the ExaCA tutorials. +- Added the top-level build script for solvers and utilities. + +## Bug Fixes + +- Corrected thermophysical file handling for cases launched with `-case`. + +## Full Changelog + +For a complete list of changes, see the [full changelog](https://github.com/ORNL/AdditiveFOAM/compare/1.1.0...1.2.0). + + # Release 1.1 ## Features diff --git a/LICENSE b/LICENSE index f2f3c772..df2c378d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2023 Oak Ridge National Laboratory + Copyright (C) 2023-2026 Oak Ridge National Laboratory You may use, distribute and copy AdditiveFOAM under the terms of GNU General Public License version 3, which is displayed below, or diff --git a/README.md b/README.md index 2d0272c6..ccbbdc90 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,10 @@ The documentation for `AdditiveFOAM` is hosted on [GitHub Pages](https://ornl.gi ### Repository Features | Link | Description | |-----------------------------------------------------------|------------------------------------------| -| [solver](applications/solvers/additiveFoam) | Development version of the solver | +| [solver](applications/solvers/additiveFoam) | AdditiveFOAM solver source | | [tutorials](tutorials) | Tutorial cases | +| [calibration utility](bin/calibrateHeatSource) | Heat-source calibration command | +| [calibration tutorial](tutorials/heatSourceCalibration) | Projected heat-source calibration workflow | ## Installation [![OpenFOAM-14](https://img.shields.io/badge/OpenFOAM-14-blue.svg)](https://github.com/OpenFOAM/OpenFOAM-14) @@ -42,8 +44,28 @@ script from the repository root: ./Allwmake ``` -For regular use, source both environments in each new shell or add them to your -shell startup file: +The Python utilities require Python 3.10 through 3.12. To use a dedicated +virtual environment, create it and install the pinned dependencies from the +repository root: + +```sh +python3 -m venv .venv +. .venv/bin/activate +python -m pip install -r requirements.txt +python -m pip check +calibrateHeatSource --help +``` + +To use an existing Python environment instead, activate that environment and +install the same requirements into it: + +```sh +python -m pip install -r /path/to/AdditiveFOAM/requirements.txt +python -m pip check +``` + +The AdditiveFOAM environment does not create or activate a Python environment. +Source the OpenFOAM and AdditiveFOAM environments in each new shell: ```sh source /path/to/OpenFOAM-14/etc/bashrc diff --git a/applications/solvers/additiveFoam/additiveFoam.C b/applications/solvers/additiveFoam/additiveFoam.C index fadbc53f..cfd09367 100644 --- a/applications/solvers/additiveFoam/additiveFoam.C +++ b/applications/solvers/additiveFoam/additiveFoam.C @@ -42,6 +42,12 @@ Description #include "fvmDiv.H" #include "fvmDdt.H" +#include "fvcDdt.H" +#include "fvcFlux.H" +#include "fvcLaplacian.H" +#include "fvcMeshPhi.H" +#include "fvcReconstruct.H" +#include "fvcSnGrad.H" #include "fvcSurfaceIntegrate.H" #include "fvcVolumeIntegrate.H" #include "fvmLaplacian.H" @@ -56,7 +62,7 @@ Description #include "CrankNicolsonDdtScheme.H" #include "additiveFoamInfo.H" -#include "movingHeatSourceModel.H" +#include "movingHeatSources.H" #include "thermoPath.H" #include "interpolateXY.H" @@ -82,7 +88,7 @@ int main(int argc, char *argv[]) // Initialize time-stepping controls scalar DiNum = 0.0; scalar alphaCoNum = 0.0; - movingHeatSourceModel sources(mesh); + movingHeatSources sources(mesh); Info<< "\nStarting time loop\n" << endl; diff --git a/applications/solvers/additiveFoam/derivedFvPatchFields/marangoni/marangoniFvPatchVectorField.H b/applications/solvers/additiveFoam/derivedFvPatchFields/marangoni/marangoniFvPatchVectorField.H index c0315233..71c5ea32 100644 --- a/applications/solvers/additiveFoam/derivedFvPatchFields/marangoni/marangoniFvPatchVectorField.H +++ b/applications/solvers/additiveFoam/derivedFvPatchFields/marangoni/marangoniFvPatchVectorField.H @@ -36,8 +36,8 @@ SourceFiles \*---------------------------------------------------------------------------*/ -#ifndef BC_H -#define BC_H +#ifndef marangoniFvPatchVectorField_H +#define marangoniFvPatchVectorField_H #include "fvPatchFields.H" #include "transformFvPatchFields.H" diff --git a/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.C b/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.C index 6a4975ca..a196f1e1 100644 --- a/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.C +++ b/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.C @@ -78,7 +78,10 @@ mixedTemperatureFvPatchScalarField valueFraction() = 0.0; refValue() = scalarField("Tinf", dict, p.size()); - fvPatchScalarField::operator=(refValue()); + fvPatchScalarField::operator= + ( + scalarField("value", iF.dimensions(), dict, p.size()) + ); } diff --git a/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.H b/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.H index 6e5329f0..bd9a8a91 100644 --- a/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.H +++ b/applications/solvers/additiveFoam/derivedFvPatchFields/mixedTemperature/mixedTemperatureFvPatchScalarField.H @@ -47,6 +47,7 @@ Usage h | Uniform convection coeff | yes | emissivity | Uniform surface emissivity | no | transportProperties Tinf | Ambient temperature | yes | + value | Initial patch temperature | yes | \endtable Example of the boundary condition specification: @@ -55,6 +56,8 @@ Usage { type mixedTemperature; h 10.0; + Tinf uniform 300; + value uniform 300; } \endverbatim @@ -63,8 +66,8 @@ SourceFiles \*---------------------------------------------------------------------------*/ -#ifndef BC_H -#define BC_H +#ifndef mixedTemperatureFvPatchScalarField_H +#define mixedTemperatureFvPatchScalarField_H #include "mixedFvPatchFields.H" #include "Function1.H" diff --git a/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C index 855062ec..2dc768ca 100644 --- a/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C +++ b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C @@ -5,7 +5,7 @@ \\ / A nd | Copyright (C) 2024 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory + Copyright (C) 2023-2026 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -247,7 +247,7 @@ bool Foam::functionObjects::meltPoolDimensions::execute() // physical boundary : take face point if above iso value const vectorField& Cf = mesh_.Cf().boundaryField()[patchi]; - const scalarField& pif(TPf.patchInternalField()); + const scalarField pif(TPf.patchInternalField()); forAll(faceCells, facei) { diff --git a/applications/solvers/additiveFoam/moveMesh.H b/applications/solvers/additiveFoam/moveMesh.H index 4df8d27a..42ccbc04 100644 --- a/applications/solvers/additiveFoam/moveMesh.H +++ b/applications/solvers/additiveFoam/moveMesh.H @@ -28,6 +28,7 @@ if (pimple.firstPimpleIter() || pimple.moveMeshOuterCorrectors()) ); // Make the flux relative to the mesh motion + MRF.makeRelative(phi); fvc::makeRelative(phi, U); } diff --git a/applications/solvers/additiveFoam/movingHeatSource/Make/files b/applications/solvers/additiveFoam/movingHeatSource/Make/files index de7b98fe..0f3b7fcb 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/Make/files +++ b/applications/solvers/additiveFoam/movingHeatSource/Make/files @@ -7,13 +7,23 @@ pathVector/pathVector.C movingBeam/movingBeam.C +heatSourceModels/profileMetrics/profileMetrics.C heatSourceModels/heatSourceModel/heatSourceModel.C heatSourceModels/heatSourceModel/heatSourceModelNew.C +heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.C +heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfileNew.C +heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.C +heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.C +heatSourceModels/projected/profiles/tabulated/tabulatedProfile.C +heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.C +heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjectionNew.C +heatSourceModels/projected/projections/exponential/exponential.C heatSourceModels/superGaussian/superGaussian.C heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.C -heatSourceModels/projectedGaussian/projectedGaussian.C -heatSourceModels/nLightAFX/nLightAFX.C -heatSourceModels/tabulated/tabulated.C +heatSourceModels/projected/projected.C + +movingHeatSources/referenceDimensions.C +movingHeatSources/movingHeatSource.C refinementModels/refinementModel/refinementModel.C refinementModels/refinementModel/refinementModelNew.C @@ -22,6 +32,6 @@ refinementModels/timeStep/timeStep.C refinementModels/targetCellLoad/targetCellLoad.C refinementModels/uniformTimeIntervals/uniformTimeIntervals.C -movingHeatSourceModel/movingHeatSourceModel.C +movingHeatSources/movingHeatSources.C LIB = $(FOAM_USER_LIBBIN)/libmovingBeamModels diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.C b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.C index 9d83eb56..d17b7286 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.C +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.C @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,14 +20,11 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "KellyAbsorption.H" #include "addToRunTimeSelectionTable.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - namespace Foam { namespace absorptionModels @@ -39,96 +34,64 @@ namespace absorptionModels } } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - Foam::absorptionModels::Kelly::Kelly ( - const word& sourceName, const dictionary& dict, - const fvMesh& mesh + const fvMesh& ) : - absorptionModel(typeName, sourceName, dict, mesh), - geometry_(absorptionModelCoeffs_.lookup("geometry")), - eta0_("eta0", dimless, absorptionModelCoeffs_), - etaMin_("etaMin", dimless, absorptionModelCoeffs_), + geometry_(dict.lookup("geometry")), + eta0_("eta0", dimless, dict), + etaMin_("etaMin", dimless, dict), aspectRatioSwitch_ ( - absorptionModelCoeffs_.lookupOrDefault - ( - "aspectRatioSwitch", - 1.0 - ) + dict.lookupOrDefault("aspectRatioSwitch", 1.0) ) { - if ((geometry_ != "cone") && (geometry_ != "cylinder")) + if (geometry_ != "cone" && geometry_ != "cylinder") { - FatalErrorInFunction - << "Kelly absorption model geometry type " << geometry_ - << " not recognized. Choose either cylinder or cone." - << abort(FatalError); + FatalIOErrorInFunction(dict) + << "Kelly geometry must be cone or cylinder, found " << geometry_ + << exit(FatalIOError); } } -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -Foam::scalar -Foam::absorptionModels::Kelly::eta +Foam::scalar Foam::absorptionModels::Kelly::eta ( - const scalar& aspectRatio + const scalar aspectRatio ) const { - if (aspectRatio > aspectRatioSwitch_) + if (aspectRatio <= aspectRatioSwitch_) { - const scalar theta = Foam::atan(1.0 / aspectRatio); - - scalar F = 0.0; - scalar G = 0.0; + return etaMin_.value(); + } - if (geometry_ == "cone") - { - F = 0.25 * (3.0 * Foam::sin(theta) - Foam::sin(3.0 * theta)); - G = 1.0 / (1.0 + Foam::sqrt(1.0 + pow(aspectRatio, 2))); - } + const scalar theta = Foam::atan(1.0/aspectRatio); - else if (geometry_ == "cylinder") - { - F = 0.5 * (1.0 - Foam::cos(2.0 * theta)); - G = 0.5 / (1.0 + aspectRatio); - } + scalar F = 0; + scalar G = 0; - return (eta0_ * (1.0 + (1.0 - eta0_)*(G - F)) - / (1.0 - (1.0 - eta0_)*(1.0 - G))).value(); - } - else + if (geometry_ == "cone") { - return etaMin_.value(); + F = 0.25*(3.0*Foam::sin(theta) - Foam::sin(3.0*theta)); + G = 1.0/(1.0 + Foam::sqrt(1.0 + sqr(aspectRatio))); } -}; -bool Foam::absorptionModels::Kelly::read() -{ - if (absorptionModel::read()) + if (geometry_ == "cylinder") { - absorptionModelCoeffs_ = optionalSubDict(type() + "Coeffs"); + F = 0.5*(1.0 - Foam::cos(2.0*theta)); + G = 0.5/(1.0 + aspectRatio); + } - //- Mandatory entries - absorptionModelCoeffs_.lookup("geometry") >> geometry_; - absorptionModelCoeffs_.lookup("eta0") >> eta0_; - absorptionModelCoeffs_.lookup("etaMin") >> etaMin_; - aspectRatioSwitch_ = - absorptionModelCoeffs_.lookupOrDefault + return + max + ( + etaMin_.value(), ( - "aspectRatioSwitch", - 1.0 - ); - - return true; - } - else - { - return false; - } + eta0_*(1.0 + (1.0 - eta0_)*(G - F)) + / (1.0 - (1.0 - eta0_)*(1.0 - G)) + ).value() + ); } // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.H b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.H index 34ee0e49..fc09c292 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.H +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/Kelly/KellyAbsorption.H @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,25 +20,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - -Class - Foam::absorptionModel::Kelly - -Description - Kelly absorption model for the optical absorption due to multiple internal - reflections in simple geometric shapes (e.g. cone and cylinder). - - Reference: - \verbatim - F. J. Kelly, - "An Equation for the Local Thermal Emissivity at the - Vertex of a Diffuse Conical or V-Groove Cavity", - Applied Optics, Vol. 5, No. 6, June 1966. - \endverbatim - -SourceFiles - KellyAbsorption.C - \*---------------------------------------------------------------------------*/ #ifndef KellyAbsorption_H @@ -48,76 +27,38 @@ SourceFiles #include "absorptionModel.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - namespace Foam { namespace absorptionModels { -/*---------------------------------------------------------------------------*\ - Class Kelly -\*---------------------------------------------------------------------------*/ - class Kelly : public absorptionModel { - // Private Data + word geometry_; - //- Conical or cylindrical - word geometry_; + dimensionedScalar eta0_; - //- Fresnel absorption of the liquid metal - dimensionedScalar eta0_; + dimensionedScalar etaMin_; - //- Effective absorption in the conduction regime - dimensionedScalar etaMin_; - - //- Aspect ratio above which the Kelly multiple-reflection model is used - scalar aspectRatioSwitch_; + scalar aspectRatioSwitch_; public: - //- Runtime type information TypeName("Kelly"); + Kelly(const dictionary& dict, const fvMesh& mesh); - // Constructors - - //- Construct from components - Kelly - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - - //- Destructor virtual ~Kelly() {} - // Member Functions - - //- Return the absorption as a scalar field - virtual scalar eta - ( - const scalar& aspectRatio - ) const; - - //- Read the absorption properties - virtual bool read(); + virtual scalar eta(const scalar aspectRatio) const; }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - } // End namespace absorptionModels } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.C b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.C index 2e2bed52..f67dca2b 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.C +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.C @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,88 +20,14 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "absorptionModel.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - namespace Foam { defineTypeNameAndDebug(absorptionModel, 0); defineRunTimeSelectionTable(absorptionModel, dictionary); } -const Foam::word Foam::absorptionModel::heatSourceDictName -( - "heatSourceDict" -); - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -Foam::IOobject Foam::absorptionModel::createIOobject -( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh -) const -{ - typeIOobject io - ( - dict.name(), - mesh.time().name(), - mesh, - IOobject::MUST_READ, - IOobject::NO_WRITE - ); - - if (io.headerOk()) - { - io.readOpt() = IOobject::MUST_READ_IF_MODIFIED; - return io; - } - else - { - io.readOpt() = IOobject::NO_READ; - return io; - } -} - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::absorptionModel::absorptionModel -( - const word& type, - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh -) -: - IOdictionary(createIOobject(sourceName, dict, mesh)), - sourceName_(sourceName), - heatSourceDict_(dict), - mesh_(mesh), - - beamDict_(heatSourceDict_.optionalSubDict(sourceName_)), - absorptionModelCoeffs_(beamDict_.optionalSubDict(type + "Coeffs")) -{} - - -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -bool Foam::absorptionModel::read() -{ - if (regIOobject::read()) - { - absorptionModelCoeffs_ = optionalSubDict(type() + "Coeffs"); - - return true; - } - else - { - return false; - } -} - // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.H b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.H index c3f3fb36..a9b40b4b 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.H +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModel.H @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,143 +20,55 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - -Class - Foam::absorptionModel - -Description - Abstract base class for absorption models - -SourceFiles - absorptionModel.C - \*---------------------------------------------------------------------------*/ #ifndef absorptionModel_H #define absorptionModel_H +#include "autoPtr.H" #include "dictionary.H" -#include "volFields.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#include "fvMesh.H" +#include "runTimeSelectionTables.H" namespace Foam { -/*---------------------------------------------------------------------------*\ - Class absorptionModel Declaration -\*---------------------------------------------------------------------------*/ - class absorptionModel -: - public IOdictionary { - // Private member functions - - //- Construct the base IO object - IOobject createIOobject - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ) const; - -protected: - - // Protected data - - //- Name of beam - const word& sourceName_; - - //- Main heat source dictionary - const dictionary& heatSourceDict_; - - //- Pointer to mesh info - const fvMesh& mesh_; - - //- Individual beam dictionary - dictionary beamDict_; - - //- Absorption model coefficient dictionary - dictionary absorptionModelCoeffs_; - - public: - //- Runtime type information TypeName("absorptionModel"); - //- Default heatSourceProperties dictionary name - static const word heatSourceDictName; - - // Declare run-time constructor selection table declareRunTimeSelectionTable ( autoPtr, absorptionModel, dictionary, - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ), - (sourceName, dict, mesh) + (const dictionary& dict, const fvMesh& mesh), + (dict, mesh) ); - // Constructors - - //- Construct - absorptionModel - ( - const word& type, - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - //- Disallow default bitwise copy construction - absorptionModel(const absorptionModel&); - - // Selectors + absorptionModel() + {} - //- Return a reference to the selected absorption model - static autoPtr New - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); + absorptionModel(const absorptionModel&) = delete; + static autoPtr New + ( + const dictionary& dict, + const fvMesh& mesh + ); - //- Destructor virtual ~absorptionModel() {} + virtual scalar eta(const scalar aspectRatio) const = 0; - // Member Functions - - //- Return const-access to the absorption - virtual scalar eta - ( - const scalar& aspectRatio - ) const = 0; - - //- Read the absorption properties - virtual bool read(); - - // Member Operators - - //- Disallow default bitwise assignment - void operator=(const absorptionModel&) = delete; + void operator=(const absorptionModel&) = delete; }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModelNew.C b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModelNew.C index 39fae8ef..57caaff8 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModelNew.C +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/absorptionModel/absorptionModelNew.C @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,46 +20,35 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "absorptionModel.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - Foam::autoPtr Foam::absorptionModel::New ( - const word& sourceName, const dictionary& dict, const fvMesh& mesh ) { - //- Initialize modelType to a non-model word - word modelType("unselected"); - - //- Get model type from source subdict - dictionary sourceDict(dict.optionalSubDict(sourceName)); - sourceDict.lookup("absorptionModel") >> modelType; + const word modelType(dict.lookup("model")); Info<< "Selecting absorption model " << modelType << endl; - //- Look up model type from runtime selection table and throw error - // if it doesn't exist - dictionaryConstructorTable::iterator cstrIter = - dictionaryConstructorTablePtr_->find(modelType); + const auto cstrIter = dictionaryConstructorTablePtr_->find(modelType); if (cstrIter == dictionaryConstructorTablePtr_->end()) { - FatalErrorInFunction - << "Unknown " << absorptionModel::typeName<< " type " - << modelType << nl << nl - << "Valid absorptionModels are : " << endl + FatalIOErrorInFunction(dict) + << "Unknown absorption model " << modelType << nl << nl + << "Valid models are:" << endl << dictionaryConstructorTablePtr_->sortedToc() - << exit(FatalError); + << exit(FatalIOError); } - return autoPtr(cstrIter()(sourceName, dict, mesh)); + return autoPtr + ( + cstrIter()(dict, mesh) + ); } - // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.C b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.C index 8903608f..4621364d 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.C +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.C @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,14 +20,11 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "constantAbsorption.H" #include "addToRunTimeSelectionTable.H" -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - namespace Foam { namespace absorptionModels @@ -39,36 +34,13 @@ namespace absorptionModels } } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - Foam::absorptionModels::constant::constant ( - const word& sourceName, const dictionary& dict, - const fvMesh& mesh + const fvMesh& ) : - absorptionModel(typeName, sourceName, dict, mesh), - eta_("eta", dimless, absorptionModelCoeffs_) + eta_("eta", dimless, dict) {} -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -bool Foam::absorptionModels::constant::read() -{ - if (absorptionModel::read()) - { - absorptionModelCoeffs_ = optionalSubDict(type() + "Coeffs"); - - //- Mandatory entries - absorptionModelCoeffs_.lookup("eta") >> eta_; - - return true; - } - else - { - return false; - } -} - // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.H b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.H index 88f388ec..0aaf43bb 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.H +++ b/applications/solvers/additiveFoam/movingHeatSource/absorptionModels/constant/constantAbsorption.H @@ -1,11 +1,9 @@ /*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,16 +20,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - -Class - Foam::absorptionModels::constant - -Description - constant absorption model. - -SourceFiles - constantAbsorption.C - \*---------------------------------------------------------------------------*/ #ifndef constantAbsorption_H @@ -39,70 +27,35 @@ SourceFiles #include "absorptionModel.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - namespace Foam { namespace absorptionModels { -/*---------------------------------------------------------------------------*\ - Class constant -\*---------------------------------------------------------------------------*/ - class constant : public absorptionModel { - // Private Data - - //- Constant absorption scalar - dimensionedScalar eta_; + dimensionedScalar eta_; public: - //- Runtime type information TypeName("constant"); + constant(const dictionary& dict, const fvMesh& mesh); - // Constructors - - //- Construct from components - constant - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - - //- Destructor virtual ~constant() {} - // Member Functions - - //- Return the absorption as a scalar field - virtual scalar eta - ( - const scalar& aspectRatio - ) const - { - return eta_.value(); - }; - - //- Read the absorption properties - virtual bool read(); + inline virtual scalar eta(const scalar) const + { + return eta_.value(); + } }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - } // End namespace absorptionModels } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.C index aed14633..dff2d184 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.C +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.C @@ -22,16 +22,9 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "heatSourceModel.H" -#include "labelVector.H" -#include "hexMatcher.H" -#include "treeBoundBox.H" -#include "thermoPath.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { @@ -39,365 +32,17 @@ namespace Foam defineRunTimeSelectionTable(heatSourceModel, dictionary); } -const Foam::word Foam::heatSourceModel::heatSourceDictName -( - "heatSourceDict" -); - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -Foam::IOobject Foam::heatSourceModel::createIOobject -( - const dictionary& dict, - const fvMesh& mesh -) const -{ - typeIOobject io - ( - dict.name(), - mesh.time().constant(), - mesh, - IOobject::MUST_READ, - IOobject::NO_WRITE - ); - - if (io.headerOk()) - { - io.readOpt() = IOobject::MUST_READ_IF_MODIFIED; - return io; - } - else - { - io.readOpt() = IOobject::NO_READ; - return io; - } -} - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - Foam::heatSourceModel::heatSourceModel ( - const word& type, - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh + const dictionary& dict ) : - IOdictionary(createIOobject(dict, mesh)), - - sourceName_(sourceName), - heatSourceDict_(dict), - sourceDict_(heatSourceDict_.optionalSubDict(sourceName_)), - heatSourceModelCoeffs_(sourceDict_.optionalSubDict(type + "Coeffs")), - mesh_(mesh), - absorptionModel_(nullptr), - movingBeam_(nullptr) -{ - absorptionModel_ = - absorptionModel::New(sourceName_, heatSourceDict_, mesh_); - - movingBeam_ = - movingBeam::New(sourceName_, heatSourceDict_, mesh_.time()); - - dimensions_ = - heatSourceModelCoeffs_.lookup("dimensions"); - - staticDimensions_ = dimensions_; - - transient_ = - heatSourceModelCoeffs_.lookupOrDefault("transient", false); - - isoValue_ = great; - - if - ( - transient_ - && !heatSourceModelCoeffs_.readIfPresent("isoValue", isoValue_) - ) - { - isoValue_ = thermoPath(mesh_).liquidus(); - } - else - { - heatSourceModelCoeffs_.readIfPresent("isoValue", isoValue_); - } - - nPoints_ = - heatSourceModelCoeffs_.lookupOrDefault - ( - "nPoints", - vector::one - ); -} - - -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -void Foam::heatSourceModel::updateDimensions() -{ - if (!transient_ ) - { - Info << "maxDepth: " << dimensions_.z() << endl; - return; - } - - const vector position_ = movingBeam_->position(); - - const scalar searchRadius - ( - max(staticDimensions_.x(), staticDimensions_.y()) - ); - - // find maximum isotherm depth within supplied beam radius - // depth is defined as the z-distance from the heat source centre - const volScalarField& T = mesh_.lookupObject("T"); - - const labelUList& owner = mesh_.owner(); - const labelUList& neighbour = mesh_.neighbour(); - - const volVectorField& cc = mesh_.C(); - - scalar maxDepth = staticDimensions_.z(); - - // isocontour location evaluated linearly across faces - for (label facei=0; facei < mesh_.nInternalFaces(); facei++) - { - const label own = owner[facei]; - const label nei = neighbour[facei]; - - scalar minFace = min(T[own], T[nei]); - scalar maxFace = max(T[own], T[nei]); - - if ((minFace < isoValue_) && (maxFace >= isoValue_)) - { - vector d = cc[nei] - cc[own]; - vector p = cc[own] + d*(isoValue_ - T[own])/(T[nei] - T[own]); - - p = cmptMag(p - position_); - - scalar pxy = Foam::sqrt(p.x()*p.x() + p.y()*p.y()); - - if (pxy <= searchRadius) - { - maxDepth = max(p.z(), maxDepth); - } - } - } - - // isocontour location evaluated linearly across processor faces - const volScalarField::Boundary& TBf = T.boundaryField(); - - forAll(TBf, patchi) - { - const fvPatchScalarField& TPf = TBf[patchi]; - - const labelUList& faceCells = TPf.patch().faceCells(); - - if (TPf.coupled()) - { - const vectorField ccn - ( - cc.boundaryField()[patchi].patchNeighbourField() - ); - const scalarField Tn(TPf.patchNeighbourField()); - - forAll(faceCells, facei) - { - label own = faceCells[facei]; - - scalar minFace = min(T[own], Tn[facei]); - scalar maxFace = max(T[own], Tn[facei]); - - if ((minFace < isoValue_) && (maxFace >= isoValue_)) - { - vector d = ccn[facei] - cc[own]; - vector p = - cc[own] + d*(isoValue_ - T[own])/(Tn[facei] - T[own]); - - p = cmptMag(p - position_); - - scalar pxy = Foam::sqrt(p.x()*p.x() + p.y()*p.y()); - - if (pxy <= searchRadius) - { - maxDepth = max(p.z(), maxDepth); - } - } - } - } - } - - reduce(maxDepth, maxOp()); - - dimensions_ = - vector(staticDimensions_.x(), staticDimensions_.y(), maxDepth); - - Info << "maxDepth: " << dimensions_.z() << endl; -} - -Foam::tmpFoam::heatSourceModel::qDot() -{ - tmp tqDot - ( - new volScalarField - ( - IOobject - ( - "qDot_", - mesh_.time().name(), - mesh_, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - mesh_, - dimensionedScalar("Zero", dimPower/dimVolume, 0.0) - ) - ); - volScalarField& qDot_ = tqDot.ref(); - - // sample gaussian distribution at desired resolution - const scalar power_ = movingBeam_->power(); - - if (power_ > small) - { - const vector position_ = movingBeam_->position(); - - // udpate the absorbed power and heat source normalization term - const scalar aspectRatio = - dimensions_.z() / min(dimensions_.x(), dimensions_.y()); - - const dimensionedScalar absorbedPower - ( - "etaP", - dimPower, - absorptionModel_->eta(aspectRatio)*power_ - ); - - dimensionedScalar volume = V0(); - - // integrate the heat source in each overlapping cell - volScalarField weights - ( - IOobject - ( - "weights", - mesh_.time().name(), - mesh_, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - mesh_, - dimensionedScalar("Zero", dimless, 0.0) - ); - - const pointField& points = mesh_.points(); - - treeBoundBox beamBb - ( - position_ - 1.5*dimensions_, - position_ + 1.5*dimensions_ - ); - - hexMatcher hex; - - forAll(mesh_.cells(), celli) - { - treeBoundBox cellBb(point::max, point::min); - - const labelList& vertices = mesh_.cellPoints()[celli]; - - forAll(vertices, i) - { - cellBb.min() = min(cellBb.min(), points[vertices[i]]); - cellBb.max() = max(cellBb.max(), points[vertices[i]]); - } - - if (cellBb.overlaps(beamBb)) - { - if (hex.isA(mesh_, celli)) - { - vector dx_ = cmptDivide(dimensions_, vector(nPoints_)); - - labelVector nCellPoints = - max - ( - cmptDivide(cellBb.span() + small*vector::one, dx_), - vector::one - ); - - dx_ = cmptDivide(cellBb.span(), vector(nCellPoints)); - - scalar dVi = dx_.x() * dx_.y() * dx_.z(); - - scalar wi = 0.0; - - for (label k=0; k < nCellPoints.z(); ++k) - { - for (label j=0; j < nCellPoints.y(); ++j) - { - for (label i=0; i < nCellPoints.x(); ++i) - { - const point pt - ( - cellBb.max() - - cmptMultiply - ( - vector(i + 0.5, j + 0.5, k + 0.5), - dx_ - ) - ); - - treeBoundBox ptBb(pt - 0.5*dx_, pt + 0.5*dx_); - - // calculate weight for point in beam bound box - if (beamBb.overlaps(ptBb)) - { - wi += weight(pt - position_) * dVi; - } - } - } - } - - weights[celli] = wi / mesh_.V()[celli]; - } - else - { - // cell is not hexahedral, evaluate at centre - point d = cmptMag(mesh_.cellCentres()[celli] - position_); - - weights[celli] = weight(d); - } - } - } - - // stabilize numerical integration errors within 95% of applied power - dimensionedScalar sumWeights = fvc::domainIntegrate(weights); - scalar residual = (sumWeights / volume).value(); - - if (mag(1 - residual) < 0.05) - { - volume = sumWeights; - } - - qDot_ = absorbedPower * weights / volume; - } - - return tqDot; -} - - -bool Foam::heatSourceModel::read() -{ - if (regIOobject::read()) - { - heatSourceModelCoeffs_ = optionalSubDict(type() + "Coeffs"); - - return true; - } - else - { - return false; - } -} + nPoints_(dict.lookupOrDefault("nPoints", vector::one)), + tolerance_(dict.lookupOrDefault("tolerance", 1.0e-3)), + depth_(dict.lookup("depth")), + sourceDepth_(depth_), + bounds_(point::zero, point::zero), + V0_("V0", dimVolume, 0) +{} // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.H index e74d3d9a..ff3f2287 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.H +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModel.H @@ -24,210 +24,112 @@ License along with OpenFOAM. If not, see . Class - Foam::heatSourceModels::heatSourceModel + Foam::heatSourceModel Description - Abstract base class for heatSource models + Common interface for volumetric heat-source distributions. Profile metrics + always describe the intensity footprint in the beam plane at z=0. SourceFiles heatSourceModel.C + heatSourceModelNew.C \*---------------------------------------------------------------------------*/ #ifndef heatSourceModel_H #define heatSourceModel_H +#include "autoPtr.H" +#include "profileMetrics.H" +#include "boundBox.H" #include "dictionary.H" -#include "volFields.H" -#include "movingBeam.H" -#include "absorptionModel.H" +#include "fvMesh.H" #include "labelVector.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#include "runTimeSelectionTables.H" namespace Foam { -/*---------------------------------------------------------------------------*\ - Class heatSourceModel Declaration -\*---------------------------------------------------------------------------*/ - class heatSourceModel -: - public IOdictionary { - // Private member functions - - //- Construct the base IO object - IOobject createIOobject - ( - const dictionary& dict, - const fvMesh& mesh - ) const; - protected: - // Protected data - - //- Name of heat source - const word& sourceName_; + labelVector nPoints_; - //- Main heat source dictionary - const dictionary& heatSourceDict_; + scalar tolerance_; - //- Sub-dict for individual heat source - dictionary sourceDict_; + scalar depth_; - //- Heat source model coefficient sub-dict - dictionary heatSourceModelCoeffs_; + scalar sourceDepth_; - //- Pointer to mesh info - const fvMesh& mesh_; + boundBox bounds_; - //- Flag for transient or static heat source dimensions - Switch transient_; + dimensionedScalar V0_; - //- Isotherm depth tracked in transient heat source model - scalar isoValue_; - - //- Dimensions of the heat source (dynamic) - vector dimensions_; - - //- Dimensions of the heat source (static) - vector staticDimensions_; - - //- Number of points along heat source dimensions resolved by sampling - labelVector nPoints_; - - //- AutoPtrs to absorption model and moving beam instances - autoPtr absorptionModel_; - autoPtr movingBeam_; + heatSourceModel(const dictionary& dict); public: - //- Runtime type information TypeName("heatSourceModel"); - //- Default heatSourceProperties dictionary name - static const word heatSourceDictName; - - // Declare run-time constructor selection table declareRunTimeSelectionTable ( autoPtr, heatSourceModel, dictionary, ( - const word& sourceName, const dictionary& dict, const fvMesh& mesh ), - (sourceName, dict, mesh) + (dict, mesh) ); + heatSourceModel(const heatSourceModel&) = delete; - // Constructors - - //- Construct for mixture - heatSourceModel - ( - const word& type, - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - //- Disallow default bitwise copy construction - heatSourceModel(const heatSourceModel&); - - // Selectors - - //- Return a reference to the selected heatSource model - static autoPtr New - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); + static autoPtr New + ( + const dictionary& dict, + const fvMesh& mesh + ); - //- Destructor virtual ~heatSourceModel() {} + virtual void update + ( + const scalar depth, + const scalar aspectRatio + ) = 0; - // Member Functions - - //- Return access to the movingBeam instance - inline movingBeam& beam() - { - return movingBeam_(); - } - - //- Return const access to the movingBeam instance - inline const movingBeam& beam() const - { - return movingBeam_(); - } - - //- Return the heat source name - inline const word& sourceName() const - { - return sourceName_; - } - - //- Return boolean of heat source type - inline Switch transient() const - { - return transient_; - } - - //- Return scalar of the isovalue - inline scalar isoValue() const - { - return isoValue_; - } - - //- Return vector of current heat source dimensions - inline vector dimensions() const - { - return dimensions_; - } - - //- Return vector of original heat source dimensions - inline vector staticDimensions() const - { - return staticDimensions_; - } - - //- Update the transient heat source dimensions - void updateDimensions(); - - //- Return the volumetric heating field - virtual tmp qDot(); + virtual scalar weight(const vector& r) const = 0; - //- Return the weight of the heat source distribution at a given point - virtual scalar weight(const vector& d) = 0; + virtual const profileMetrics& metrics() const = 0; - //- Return the normalization volume for the integrated distribution - virtual dimensionedScalar V0() = 0; + inline scalar depth() const + { + return depth_; + } - //- Read the heat source dictionary - virtual bool read() = 0; + inline const labelVector& nPoints() const + { + return nPoints_; + } + inline const boundBox& bounds() const + { + return bounds_; + } - // Member Operators + inline const dimensionedScalar& V0() const + { + return V0_; + } - //- Disallow default bitwise assignment - void operator=(const heatSourceModel&) = delete; + void operator=(const heatSourceModel&) = delete; }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModelNew.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModelNew.C index c5c5accf..ec9b38b9 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModelNew.C +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/heatSourceModel/heatSourceModelNew.C @@ -22,46 +22,32 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "heatSourceModel.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - Foam::autoPtr Foam::heatSourceModel::New ( - const word& sourceName, const dictionary& dict, const fvMesh& mesh ) { - //- Initialize modelType to a non-model word - word modelType("unselected"); + const word modelType(dict.lookup("model")); - //- Get model type from source subdict - dictionary sourceDict(dict.optionalSubDict(sourceName)); - sourceDict.lookup("heatSourceModel") >> modelType; + Info<< "Selecting heat source model " << modelType << endl; - Info<< "Selecting heatSource model " << modelType << endl; - - //- Look up model type from runtime selection table and throw error - // if it doesn't exist - dictionaryConstructorTable::iterator cstrIter = - dictionaryConstructorTablePtr_->find(modelType); + const auto cstrIter = dictionaryConstructorTablePtr_->find(modelType); if (cstrIter == dictionaryConstructorTablePtr_->end()) { - FatalErrorInFunction - << "Unknown " << heatSourceModel::typeName<< " type " - << modelType << nl << nl - << "Valid heatSourceModels are : " << endl + FatalIOErrorInFunction(dict) + << "Unknown heat source model " << modelType << nl << nl + << "Valid models are:" << endl << dictionaryConstructorTablePtr_->sortedToc() - << exit(FatalError); + << exit(FatalIOError); } - return autoPtr(cstrIter()(sourceName, dict, mesh)); + return autoPtr(cstrIter()(dict, mesh)); } - // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.C index 95b2d750..3452e11a 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.C +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.C @@ -5,7 +5,7 @@ \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory + Copyright (C) 2023-2026 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,13 +22,12 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "modifiedSuperGaussian.H" +#include "superGaussianProfile.H" #include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +#include "mathematicalConstants.H" namespace Foam { @@ -46,86 +45,131 @@ namespace heatSourceModels using Foam::constant::mathematical::pi; -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - Foam::heatSourceModels::modifiedSuperGaussian::modifiedSuperGaussian ( - const word& sourceName, const dictionary& dict, const fvMesh& mesh ) : - heatSourceModel(typeName, sourceName, dict, mesh), - mesh_(mesh) -{ - k_ = heatSourceModelCoeffs_.lookup("k"); - m_ = heatSourceModelCoeffs_.lookup("m"); -} - - -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -inline Foam::scalar -Foam::heatSourceModels::modifiedSuperGaussian::weight(const vector& d) -{ - scalar a = Foam::pow(2.0, 1.0/k_); - - vector s = cmptDivide(dimensions_, vector(a, a, 1.0)); - - const scalar z = mag(d.z()); - - if (z < s.z()) - { - s *= Foam::pow(1.0 - Foam::pow(z / s.z(), m_), 1.0/m_); - - vector di = vector(d.x(), d.y(), 0.0); - - scalar x = Foam::pow(magSqr(cmptDivide(di, s)), k_/2.0); - - return Foam::exp(-x); - } - else - { - return 0.0; - } -} - -inline Foam::dimensionedScalar -Foam::heatSourceModels::modifiedSuperGaussian::V0() + heatSourceModel(dict), + radius_(dict.lookup("radius")), + k_(dict.lookup("k")), + m_(dict.lookup("m")), + coefficient_ + ( + heatSourceProfiles::superGaussian::coefficient(dict, k_) + ), + cosTheta_(0), + sinTheta_(0), + metrics_() { - const scalar a = Foam::pow(2.0, 1.0/k_); - - const vector s = cmptDivide(dimensions_, vector(a, a, 1.0)); - - const dimensionedScalar V0 + const scalar variance = + 0.5*Foam::tgamma(4.0/k_)/Foam::tgamma(2.0/k_); + + const scalar azimuth = + dict.lookupOrDefault("azimuth", 0)*pi/180.0; + cosTheta_ = Foam::cos(azimuth); + sinTheta_ = Foam::sin(azimuth); + const scalar sx2 = sqr(radius_.x())/coefficient_; + const scalar sy2 = sqr(radius_.y())/coefficient_; + + const scalar integral = + pi*radius_.x()*radius_.y()/coefficient_ + *Foam::tgamma(1.0 + 2.0/k_); + const scalar varianceX = + sqr(cosTheta_)*sx2*variance + + sqr(sinTheta_)*sy2*variance; + const scalar varianceY = + sqr(sinTheta_)*sx2*variance + + sqr(cosTheta_)*sy2*variance; + const scalar covariance = + cosTheta_*sinTheta_*(sx2 - sy2)*variance; + + metrics_.reset ( - "V0", - dimVolume, - s.x()*s.y()*s.z()*pi*Foam::tgamma(1.0 + 2.0/k_) - * Foam::tgamma(1.0 + 1.0/m_)*Foam::tgamma(1.0 + 2.0/m_) - / Foam::tgamma(1.0 + 3.0/m_) + integral, + 0, + 0, + integral*varianceX, + integral*varianceY, + integral*covariance ); - return V0; + update(depth_, 0); } -bool Foam::heatSourceModels::modifiedSuperGaussian::read() + +void Foam::heatSourceModels::modifiedSuperGaussian::update +( + const scalar depth, + const scalar +) { - if (heatSourceModel::read()) - { - heatSourceModelCoeffs_ = optionalSubDict(type() + "Coeffs"); + sourceDepth_ = depth; + + const scalar fMax = + Foam::pow + ( + invIncGammaRatio_P(2.0/k_, 1.0 - tolerance_), + 1.0/k_ + ); + const scalar xMax = + fMax/Foam::sqrt(coefficient_) + *Foam::sqrt + ( + sqr(radius_.x()*cosTheta_) + + sqr(radius_.y()*sinTheta_) + ); + const scalar yMax = + fMax/Foam::sqrt(coefficient_) + *Foam::sqrt + ( + sqr(radius_.x()*sinTheta_) + + sqr(radius_.y()*cosTheta_) + ); + + bounds_ = + boundBox + ( + point(-xMax, -yMax, -sourceDepth_), + point(xMax, yMax, 0) + ); + + V0_ = + dimensionedScalar + ( + "V0", + dimVolume, + metrics_.integral()*sourceDepth_ + *Foam::tgamma(1.0 + 1.0/m_)*Foam::tgamma(1.0 + 2.0/m_) + /Foam::tgamma(1.0 + 3.0/m_) + ); +} - //- Mandatory entries - heatSourceModelCoeffs_.lookup("k") >> k_; - heatSourceModelCoeffs_.lookup("m") >> m_; - return true; - } - else +Foam::scalar Foam::heatSourceModels::modifiedSuperGaussian::weight +( + const vector& r +) const +{ + if (r.z() > 0 || r.z() <= -sourceDepth_) { - return false; + return 0; } -} + const scalar g = + Foam::pow + ( + 1.0 - Foam::pow(-r.z()/sourceDepth_, m_), + 1.0/m_ + ); + const scalar x = cosTheta_*r.x() + sinTheta_*r.y(); + const scalar y = -sinTheta_*r.x() + cosTheta_*r.y(); + const scalar radiusSqr = + coefficient_ + *(sqr(x/radius_.x()) + sqr(y/radius_.y())); + + return Foam::exp(-Foam::pow(radiusSqr/sqr(g), k_/2.0)); +} // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.H index 6cff6f9b..8c56ae9e 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.H +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/modifiedSuperGaussian/modifiedSuperGaussian.H @@ -5,7 +5,7 @@ \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory + Copyright (C) 2023-2026 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,11 +27,7 @@ Class Foam::heatSourceModels::modifiedSuperGaussian Description - modifiedSuperGaussian model. - - Reference: - \verbatim - \endverbatim + One-sided modified super-Gaussian heat source with finite depth. SourceFiles modifiedSuperGaussian.C @@ -43,72 +39,53 @@ SourceFiles #include "heatSourceModel.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - namespace Foam { namespace heatSourceModels { -/*---------------------------------------------------------------------------*\ - Class modifiedSuperGaussian -\*---------------------------------------------------------------------------*/ - class modifiedSuperGaussian : public heatSourceModel { - // Private Data - - //- Pointer to mesh information - const fvMesh& mesh_; - - //- Distribution shape coefficient of modifiedSuperGaussian distribution - scalar k_; - - //- Geometric shape coefficient of modifiedSuperGaussian distribution - scalar m_; + vector2D radius_; + scalar k_; + scalar m_; + scalar coefficient_; + scalar cosTheta_; + scalar sinTheta_; + profileMetrics metrics_; public: - //- Runtime type information TypeName("modifiedSuperGaussian"); + modifiedSuperGaussian + ( + const dictionary& dict, + const fvMesh& mesh + ); - // Constructors - - //- Construct from components - modifiedSuperGaussian - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - - //- Destructor virtual ~modifiedSuperGaussian() {} + virtual void update + ( + const scalar depth, + const scalar aspectRatio + ); - // Member Functions - - inline virtual scalar weight(const vector& d); + virtual scalar weight(const vector& r) const; - inline virtual dimensionedScalar V0(); - - //- Read the heatSourceProperties dictionary - virtual bool read(); + inline virtual const profileMetrics& metrics() const + { + return metrics_; + } }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - } // End namespace heatSourceModels } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/nLightAFX/nLightAFX.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/nLightAFX/nLightAFX.C deleted file mode 100644 index d1155341..00000000 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/nLightAFX/nLightAFX.C +++ /dev/null @@ -1,210 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023-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 "nLightAFX.H" -#include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ -namespace heatSourceModels -{ - defineTypeNameAndDebug(nLightAFX, 0); - addToRunTimeSelectionTable(heatSourceModel, nLightAFX, dictionary); -} -} - -using Foam::constant::mathematical::pi; - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::heatSourceModels::nLightAFX::nLightAFX -( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh -) -: - heatSourceModel(typeName, sourceName, dict, mesh), - mesh_(mesh) -{ - const dictionary innerDict - ( - heatSourceModelCoeffs_.optionalSubDict("inner") - ); - - const dictionary outerDict - ( - heatSourceModelCoeffs_.optionalSubDict("outer") - ); - - alpha_ = heatSourceModelCoeffs_.lookup("alpha"); - - r0_ = innerDict.lookup("radius"); - sigma0_ = innerDict.lookup("sigma"); - A0_ = innerDict.lookup("A"); - B0_ = innerDict.lookup("B"); - - r1_ = outerDict.lookup("radius"); - sigma1_ = outerDict.lookup("sigma"); - A1_ = outerDict.lookup("A"); - B1_ = outerDict.lookup("B"); - - const scalar d = dimensions_.z(); - - const scalar x = - max - ( - d/min(staticDimensions_.x(), staticDimensions_.y()), - 0.001 - ); - - const scalar p0 = min(max(A0_*std::log2(x) + B0_, 0.0), 9.0); - const scalar p1 = min(max(A1_*std::log2(x) + B1_, 0.0), 9.0); - - n0_ = Foam::pow(2.0, p0); - n1_ = Foam::pow(2.0, p1); - - a0_ = ai(r0_, sigma0_, d, n0_); - a1_ = ai(r1_, sigma1_, d, n1_); -} - - -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -inline Foam::scalar -Foam::heatSourceModels::nLightAFX::weight(const vector& x) -{ - const scalar z = Foam::mag(x.z()); - - const scalar r = Foam::sqrt(x.x()*x.x() + x.y()*x.y()); - - const scalar d = dimensions_.z(); - - const scalar x0 = - std::exp(-0.5*Foam::sqr((r - r0_)/sigma0_)) - + std::exp(-0.5*Foam::sqr((r + r0_)/sigma0_)); - - const scalar x1 = - std::exp(-0.5*Foam::sqr((r - r1_)/sigma1_)) - + std::exp(-0.5*Foam::sqr((r + r1_)/sigma1_)); - - const scalar s0 = - std::exp(-3.0*Foam::pow(mag(z/d), n0_)); - - const scalar s1 = - std::exp(-3.0*Foam::pow(mag(z/d), n1_)); - - return ((1.0 - alpha_)*x0*s0*a1_) + (alpha_*x1*s1*a0_); -} - - -inline Foam::scalar -Foam::heatSourceModels::nLightAFX::ai -( - scalar x, - scalar s, - scalar d, - scalar n -) -{ - const scalar t1 = - 2.0*pi*s*d*Foam::tgamma(1.0/n) - / (n*Foam::pow(3.0, 1.0/n)); - - const scalar t2 = - 2.0*s*std::exp(-0.5*Foam::sqr(x/s)) - + Foam::sqrt(2.0*pi)*x*Foam::erf(x/(Foam::sqrt(2.0)*s)); - - return t1*t2; -} - - -inline Foam::dimensionedScalar -Foam::heatSourceModels::nLightAFX::V0() -{ - const scalar d = dimensions_.z(); - - const scalar x = - max - ( - d/min(staticDimensions_.x(), staticDimensions_.y()), - 0.001 - ); - - const scalar p0 = min(max(A0_*std::log2(x) + B0_, 0.0), 9.0); - const scalar p1 = min(max(A1_*std::log2(x) + B1_, 0.0), 9.0); - - n0_ = Foam::pow(2.0, p0); - n1_ = Foam::pow(2.0, p1); - - a0_ = ai(r0_, sigma0_, d, n0_); - a1_ = ai(r1_, sigma1_, d, n1_); - - return dimensionedScalar("V0", dimVolume, a0_*a1_); -} - - -bool Foam::heatSourceModels::nLightAFX::read() -{ - if (heatSourceModel::read()) - { - heatSourceModelCoeffs_ = optionalSubDict(type() + "Coeffs"); - - const dictionary innerDict - ( - heatSourceModelCoeffs_.optionalSubDict("inner") - ); - - const dictionary outerDict - ( - heatSourceModelCoeffs_.optionalSubDict("outer") - ); - - heatSourceModelCoeffs_.lookup("alpha") >> alpha_; - - innerDict.lookup("radius") >> r0_; - innerDict.lookup("sigma") >> sigma0_; - innerDict.lookup("A") >> A0_; - innerDict.lookup("B") >> B0_; - - outerDict.lookup("radius") >> r1_; - outerDict.lookup("sigma") >> sigma1_; - outerDict.lookup("A") >> A1_; - outerDict.lookup("B") >> B1_; - - return true; - } - else - { - return false; - } -} - - -// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/nLightAFX/nLightAFX.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/nLightAFX/nLightAFX.H deleted file mode 100644 index bd18c90c..00000000 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/nLightAFX/nLightAFX.H +++ /dev/null @@ -1,145 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023-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 . - -Class - Foam::heatSourceModels::nLightAFX - -Description - nLight AFX heat source model for additive manufacturing - -SourceFiles - nLightAFX.C - -\*---------------------------------------------------------------------------*/ - -#ifndef nLightAFX_H -#define nLightAFX_H - -#include "heatSourceModel.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ -namespace heatSourceModels -{ - -/*---------------------------------------------------------------------------*\ - Class nLightAFX -\*---------------------------------------------------------------------------*/ - -class nLightAFX -: - public heatSourceModel -{ - // Private Data - - //- Pointer to mesh information - const fvMesh& mesh_; - - //- Fraction of power applied to the outer component - scalar alpha_; - - //- Radius of the inner Gaussian ring - scalar r0_; - - //- Radius of the outer Gaussian ring - scalar r1_; - - //- Standard deviation of the inner Gaussian ring - scalar sigma0_; - - //- Standard deviation of the outer Gaussian ring - scalar sigma1_; - - //- Inner axial decay coefficient in the form n = Alog2(x) + B - scalar A0_; - - //- Inner axial decay coefficient in the form n = Alog2(x) + B - scalar B0_; - - //- Outer axial decay coefficient in the form n = Alog2(x) + B - scalar A1_; - - //- Outer axial decay coefficient in the form n = Alog2(x) + B - scalar B1_; - - //- Inner axial decay exponent - scalar n0_; - - //- Outer axial decay exponent - scalar n1_; - - //- Inner normalization factor - scalar a0_; - - //- Outer normalization factor - scalar a1_; - -public: - - //- Runtime type information - TypeName("nLightAFX"); - - - // Constructors - - //- Construct from components - nLightAFX - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - - //- Destructor - virtual ~nLightAFX() - {} - - - // Member Functions - - inline virtual scalar weight(const vector& d); - - inline scalar ai(scalar x, scalar s, scalar d, scalar n); - - inline virtual dimensionedScalar V0(); - - //- Read the heatSourceProperties dictionary - virtual bool read(); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace heatSourceModels -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/profileMetrics/profileMetrics.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/profileMetrics/profileMetrics.C new file mode 100644 index 00000000..1c7a4bf1 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/profileMetrics/profileMetrics.C @@ -0,0 +1,97 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "profileMetrics.H" + +Foam::profileMetrics::profileMetrics() +: + integral_(0), + centroid_(vector2D::zero), + covariance_(symmTensor2D::zero), + D4Sigma_(vector2D::zero), + azimuth_(0) +{} + + +void Foam::profileMetrics::reset +( + const scalar M00, + const scalar M10, + const scalar M01, + const scalar M20, + const scalar M02, + const scalar M11 +) +{ + if (!(M00 > 0)) + { + FatalErrorInFunction + << "Profile integral must be positive, found " << M00 + << exit(FatalError); + } + + integral_ = M00; + + centroid_.x() = M10/M00; + + centroid_.y() = M01/M00; + + scalar varianceX = M20/M00 - sqr(centroid_.x()); + + scalar varianceY = M02/M00 - sqr(centroid_.y()); + + const scalar covariance = M11/M00 - centroid_.x()*centroid_.y(); + + varianceX = max(varianceX, 0.0); + + varianceY = max(varianceY, 0.0); + + covariance_ = symmTensor2D(varianceX, covariance, varianceY); + + const scalar meanVariance = 0.5*(varianceX + varianceY); + + const scalar delta = + Foam::sqrt(0.25*sqr(varianceX - varianceY) + sqr(covariance)); + + const scalar majorVariance = meanVariance + delta; + + scalar minorVariance = meanVariance - delta; + + minorVariance = max(minorVariance, 0.0); + + D4Sigma_.x() = 4.0*Foam::sqrt(majorVariance); + + D4Sigma_.y() = 4.0*Foam::sqrt(minorVariance); + + const scalar circularTolerance = rootSmall*max(meanVariance, VSMALL); + + azimuth_ = + delta > circularTolerance + ? 0.5*Foam::atan2(2.0*covariance, varianceX - varianceY) + : 0.0; +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/profileMetrics/profileMetrics.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/profileMetrics/profileMetrics.H new file mode 100644 index 00000000..4a704b29 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/profileMetrics/profileMetrics.H @@ -0,0 +1,104 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::profileMetrics + +Description + Integral and second-moment metrics of an intensity distribution in the + beam plane. D4Sigma is ordered (major, minor). + +SourceFiles + profileMetrics.C + +\*---------------------------------------------------------------------------*/ + +#ifndef profileMetrics_H +#define profileMetrics_H + +#include "scalar.H" +#include "symmTensor2D.H" +#include "vector2D.H" + +namespace Foam +{ + +class profileMetrics +{ + scalar integral_; + + vector2D centroid_; + + symmTensor2D covariance_; + + vector2D D4Sigma_; + + scalar azimuth_; + +public: + + profileMetrics(); + + void reset + ( + const scalar M00, + const scalar M10, + const scalar M01, + const scalar M20, + const scalar M02, + const scalar M11 + ); + + inline scalar integral() const + { + return integral_; + } + + inline const vector2D& centroid() const + { + return centroid_; + } + + inline const symmTensor2D& covariance() const + { + return covariance_; + } + + inline const vector2D& D4Sigma() const + { + return D4Sigma_; + } + + inline scalar azimuth() const + { + return azimuth_; + } +}; + +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.C new file mode 100644 index 00000000..6e64d25d --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.C @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "heatSourceProfile.H" + +namespace Foam +{ + defineTypeNameAndDebug(heatSourceProfile, 0); + defineRunTimeSelectionTable(heatSourceProfile, dictionary); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.H new file mode 100644 index 00000000..3bb61f93 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfile.H @@ -0,0 +1,115 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::heatSourceProfile + +Description + Abstract base class for planar heat source profiles. + +SourceFiles + heatSourceProfile.C + heatSourceProfileNew.C + +\*---------------------------------------------------------------------------*/ + +#ifndef heatSourceProfile_H +#define heatSourceProfile_H + +#include "autoPtr.H" +#include "boundBox.H" +#include "dictionary.H" +#include "profileMetrics.H" +#include "runTimeSelectionTables.H" + +namespace Foam +{ + +class fvMesh; + +class heatSourceProfile +{ +public: + + //- Runtime type information + TypeName("heatSourceProfile"); + + // Declare run-time constructor selection table + declareRunTimeSelectionTable + ( + autoPtr, + heatSourceProfile, + dictionary, + ( + const dictionary& dict, + const fvMesh& mesh, + const scalar tolerance + ), + (dict, mesh, tolerance) + ); + + // Constructors + + heatSourceProfile() + {} + + //- Disallow default bitwise copy construction + heatSourceProfile(const heatSourceProfile&); + + // Selectors + + static autoPtr New + ( + const dictionary& dict, + const fvMesh& mesh, + const scalar tolerance + ); + + //- Destructor + virtual ~heatSourceProfile() + {} + + // Member Functions + + //- Return the profile weight + virtual scalar weight(const scalar x, const scalar y) const = 0; + + //- Return metrics of the intensity profile in the beam plane + virtual const profileMetrics& metrics() const = 0; + + //- Return the planar profile bounds + virtual const boundBox& bounds() const = 0; + + // Member Operators + + //- Disallow default bitwise assignment + void operator=(const heatSourceProfile&) = delete; +}; + +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfileNew.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfileNew.C new file mode 100644 index 00000000..678bb609 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/heatSourceProfile/heatSourceProfileNew.C @@ -0,0 +1,59 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "heatSourceProfile.H" + +Foam::autoPtr Foam::heatSourceProfile::New +( + const dictionary& dict, + const fvMesh& mesh, + const scalar tolerance +) +{ + const word profileType(dict.lookup("model")); + + Info<< "Selecting heatSourceProfile " << profileType << endl; + + const auto cstrIter = dictionaryConstructorTablePtr_->find(profileType); + + if (cstrIter == dictionaryConstructorTablePtr_->end()) + { + FatalErrorInFunction + << "Unknown " << heatSourceProfile::typeName << " type " + << profileType << nl << nl + << "Valid heatSourceProfiles are:" << endl + << dictionaryConstructorTablePtr_->sortedToc() + << exit(FatalError); + } + + return autoPtr + ( + cstrIter()(dict, mesh, tolerance) + ); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.C new file mode 100644 index 00000000..ba6db1a1 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.C @@ -0,0 +1,201 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "nLightAFXProfile.H" +#include "addToRunTimeSelectionTable.H" +#include "mathematicalConstants.H" + +namespace Foam +{ +namespace heatSourceProfiles +{ + defineTypeNameAndDebug(nLightAFX, 0); + addToRunTimeSelectionTable + ( + heatSourceProfile, + nLightAFX, + dictionary + ); +} +} + +using Foam::constant::mathematical::pi; + + +Foam::heatSourceProfiles::nLightAFX::nLightAFX +( + const dictionary& dict, + const fvMesh&, + const scalar epsilon +) +: + alpha_(0), + r0_(0), + sigma0_(0), + r1_(0), + sigma1_(0), + J0_(0), + J1_(0), + metrics_(), + bounds_(point::zero, point::zero) +{ + alpha_ = dict.lookup("alpha"); + + r0_ = dict.lookup("r0"); + sigma0_ = dict.lookup("sigma0"); + + r1_ = dict.lookup("r1"); + sigma1_ = dict.lookup("sigma1"); + + J0_ = J(0, r0_, sigma0_); + J1_ = J(0, r1_, sigma1_); + + const scalar integral = 2.0*pi*J0_; + + const scalar r2 = + (1.0 - alpha_)*K(r0_, sigma0_)/J0_ + + alpha_*K(r1_, sigma1_)/J1_; + + metrics_.reset + ( + integral, + 0, + 0, + 0.5*integral*r2, + 0.5*integral*r2, + 0 + ); + + scalar rMax = + max + ( + cutoff(r0_, sigma0_, J0_, epsilon), + cutoff(r1_, sigma1_, J1_, epsilon) + ); + + scalar rMin = 0; + + // Bisect to radial tolerance + const label nIter = ceil(std::log2(1/small)); + + for (label i=0; i1e-8; ++i) + { + const scalar R = 0.5*(rMin + rMax); + + const scalar epsilonR = + (1.0 - alpha_)*J(R, r0_, sigma0_)/J0_ + + alpha_*J(R, r1_, sigma1_)/J1_; + + (epsilonR > epsilon ? rMin : rMax) = R; + } + + bounds_ = + boundBox + ( + point(-rMax, -rMax, 0), + point(rMax, rMax, 0) + ); +} + + +inline Foam::scalar Foam::heatSourceProfiles::nLightAFX::J +( + const scalar R, + const scalar r, + const scalar sigma +) const +{ + return + Foam::sqr(sigma) + *( + std::exp(-0.5 * Foam::sqr((R - r) / sigma)) + + std::exp(-0.5 * Foam::sqr((R + r) / sigma)) + ) + + r*sigma*Foam::sqrt(0.5*pi) + *( + Foam::erfc((R - r)/(Foam::sqrt(2.0)*sigma)) + - Foam::erfc((R + r)/(Foam::sqrt(2.0)*sigma)) + ); +} + + +inline Foam::scalar Foam::heatSourceProfiles::nLightAFX::K +( + const scalar r, + const scalar sigma +) const +{ + const scalar f = std::exp(-0.5*Foam::sqr(r/sigma)); + const scalar e = Foam::erf(r/(Foam::sqrt(2.0)*sigma)); + + return + 2.0*Foam::sqr(sigma) + *(Foam::sqr(r) + 2.0*Foam::sqr(sigma))*f + + r*sigma*Foam::sqrt(2.0*pi) + *(Foam::sqr(r) + 3.0*Foam::sqr(sigma))*e; +} + + +inline Foam::scalar Foam::heatSourceProfiles::nLightAFX::cutoff +( + const scalar r, + const scalar sigma, + const scalar J0, + const scalar epsilon +) const +{ + // J(r + sigma*u) <= C*exp(-u^2/2) + const scalar C = + 2.0*Foam::sqr(sigma) + + r*sigma*Foam::sqrt(0.5*pi); + + const scalar u2 = 2.0*max(std::log(C/(epsilon*J0)), 0.0); + + return r + sigma*Foam::sqrt(u2); +} + + +inline Foam::scalar Foam::heatSourceProfiles::nLightAFX::weight +( + const scalar x, + const scalar y +) const +{ + const scalar r = Foam::sqrt(x*x + y*y); + + const scalar I0 = + std::exp(-0.5*Foam::sqr((r - r0_)/sigma0_)) + + std::exp(-0.5*Foam::sqr((r + r0_)/sigma0_)); + + const scalar I1 = + std::exp(-0.5*Foam::sqr((r - r1_)/sigma1_)) + + std::exp(-0.5*Foam::sqr((r + r1_)/sigma1_)); + + return (1.0 - alpha_)*I0 + alpha_*I1*J0_/J1_; +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.H new file mode 100644 index 00000000..32740bcf --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/nLightAFX/nLightAFXProfile.H @@ -0,0 +1,147 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::heatSourceProfiles::nLightAFX + +Description + Two-component nLight AFX planar heat source profile. + +SourceFiles + nLightAFXProfile.C + +\*---------------------------------------------------------------------------*/ + +#ifndef nLightAFXProfile_H +#define nLightAFXProfile_H + +#include "heatSourceProfile.H" + +namespace Foam +{ +namespace heatSourceProfiles +{ + +class nLightAFX +: + public heatSourceProfile +{ + // Private Data + + //- Fraction of power applied to Gaussian component 1 + scalar alpha_; + + //- Radius of Gaussian component 0 + scalar r0_; + + //- Standard deviation of Gaussian component 0 + scalar sigma0_; + + //- Radius of Gaussian component 1 + scalar r1_; + + //- Standard deviation of Gaussian component 1 + scalar sigma1_; + + //- J_0(0) + scalar J0_; + + //- J_1(0) + scalar J1_; + + //- Exact planar moments and derived beam metrics + profileMetrics metrics_; + + //- Planar profile bounds + boundBox bounds_; + + + // Private Member Functions + + //- Return J(R) = integral_R^infinity I(r)*r dr + inline scalar J + ( + const scalar R, + const scalar r, + const scalar sigma + ) const; + + //- Return K = integral_0^infinity I(r)*r^3 dr + inline scalar K(const scalar r, const scalar sigma) const; + + //- Guaranteed upper bound where J(R)/J(0) <= epsilon + inline scalar cutoff + ( + const scalar r, + const scalar sigma, + const scalar J0, + const scalar epsilon + ) const; + +public: + + //- Runtime type information + TypeName("nLightAFX"); + + + // Constructors + + nLightAFX + ( + const dictionary& dict, + const fvMesh& mesh, + const scalar tolerance + ); + + //- Destructor + virtual ~nLightAFX() + {} + + // Member Functions + + inline virtual scalar weight + ( + const scalar x, + const scalar y + ) const; + + inline virtual const profileMetrics& metrics() const + { + return metrics_; + } + + inline virtual const boundBox& bounds() const + { + return bounds_; + } + +}; + +} // End namespace heatSourceProfiles +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.C new file mode 100644 index 00000000..f4e11ee9 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.C @@ -0,0 +1,161 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "superGaussianProfile.H" +#include "addToRunTimeSelectionTable.H" +#include "mathematicalConstants.H" + +namespace Foam +{ +namespace heatSourceProfiles +{ + defineTypeNameAndDebug(superGaussian, 0); + addToRunTimeSelectionTable + ( + heatSourceProfile, + superGaussian, + dictionary + ); +} +} + +using Foam::constant::mathematical::pi; + +Foam::scalar +Foam::heatSourceProfiles::superGaussian::coefficient +( + const dictionary& dict, + const scalar k +) +{ + const word definition(dict.lookupOrDefault("definition", "e2")); + + if (definition == "e2") + { + return Foam::pow(2.0, 2.0/k); + } + if (definition == "secondMoment") + { + return + 2.0*Foam::tgamma(4.0/k)/Foam::tgamma(2.0/k); + } + + FatalIOErrorInFunction(dict) + << "definition must be e2 or secondMoment, found " << definition + << exit(FatalIOError); + + return 0; +} + + +Foam::heatSourceProfiles::superGaussian::superGaussian +( + const dictionary& dict, + const fvMesh&, + const scalar tolerance +) +: + radius_(dict.lookup("radius")), + k_(dict.lookup("k")), + coefficient_(coefficient(dict, k_)), + cosTheta_(0), + sinTheta_(0), + metrics_(), + bounds_(point::zero, point::zero) +{ + const scalar variance = + 0.5*Foam::tgamma(4.0/k_)/Foam::tgamma(2.0/k_); + const scalar azimuth = + dict.lookupOrDefault("azimuth", 0)*pi/180.0; + cosTheta_ = Foam::cos(azimuth); + sinTheta_ = Foam::sin(azimuth); + const scalar sx2 = sqr(radius_.x())/coefficient_; + const scalar sy2 = sqr(radius_.y())/coefficient_; + + const scalar integral = + pi*radius_.x()*radius_.y()/coefficient_ + *Foam::tgamma(1.0 + 2.0/k_); + const scalar varianceX = + sqr(cosTheta_)*sx2*variance + + sqr(sinTheta_)*sy2*variance; + const scalar varianceY = + sqr(sinTheta_)*sx2*variance + + sqr(cosTheta_)*sy2*variance; + const scalar covariance = + cosTheta_*sinTheta_*(sx2 - sy2)*variance; + + metrics_.reset + ( + integral, + 0, + 0, + integral*varianceX, + integral*varianceY, + integral*covariance + ); + + const scalar fMax = + Foam::pow + ( + invIncGammaRatio_P(2.0/k_, 1.0 - tolerance), + 1.0/k_ + ); + const scalar xMax = + fMax/Foam::sqrt(coefficient_) + *Foam::sqrt + ( + sqr(radius_.x()*cosTheta_) + + sqr(radius_.y()*sinTheta_) + ); + const scalar yMax = + fMax/Foam::sqrt(coefficient_) + *Foam::sqrt + ( + sqr(radius_.x()*sinTheta_) + + sqr(radius_.y()*cosTheta_) + ); + + bounds_ = + boundBox(point(-xMax, -yMax, 0), point(xMax, yMax, 0)); +} + + +Foam::scalar Foam::heatSourceProfiles::superGaussian::weight +( + const scalar x, + const scalar y +) const +{ + const scalar xr = cosTheta_*x + sinTheta_*y; + const scalar yr = -sinTheta_*x + cosTheta_*y; + const scalar radiusSqr = + coefficient_ + *(sqr(xr/radius_.x()) + sqr(yr/radius_.y())); + + return Foam::exp(-Foam::pow(radiusSqr, k_/2.0)); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.H new file mode 100644 index 00000000..1f93bcdb --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/superGaussian/superGaussianProfile.H @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::heatSourceProfiles::superGaussian + +Description + Planar elliptical super-Gaussian intensity profile. radius contains the + local x/y radii and need not be ordered. definition is e2 or secondMoment. + +SourceFiles + superGaussianProfile.C + +\*---------------------------------------------------------------------------*/ + +#ifndef superGaussianProfile_H +#define superGaussianProfile_H + +#include "heatSourceProfile.H" + +namespace Foam +{ +namespace heatSourceProfiles +{ + +class superGaussian +: + public heatSourceProfile +{ + vector2D radius_; + scalar k_; + scalar coefficient_; + scalar cosTheta_; + scalar sinTheta_; + profileMetrics metrics_; + boundBox bounds_; + +public: + + TypeName("superGaussian"); + + superGaussian + ( + const dictionary& dict, + const fvMesh& mesh, + const scalar tolerance + ); + + static scalar coefficient + ( + const dictionary& dict, + const scalar k + ); + + virtual ~superGaussian() + {} + + virtual scalar weight(const scalar x, const scalar y) const; + + inline virtual const profileMetrics& metrics() const + { + return metrics_; + } + + inline virtual const boundBox& bounds() const + { + return bounds_; + } +}; + +} // End namespace heatSourceProfiles +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/tabulated/tabulatedProfile.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/tabulated/tabulatedProfile.C new file mode 100644 index 00000000..2170372c --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/tabulated/tabulatedProfile.C @@ -0,0 +1,209 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "tabulatedProfile.H" +#include "addToRunTimeSelectionTable.H" +#include "fvMesh.H" +#include "IFstream.H" + +namespace Foam +{ +namespace heatSourceProfiles +{ + defineTypeNameAndDebug(tabulated, 0); + addToRunTimeSelectionTable + ( + heatSourceProfile, + tabulated, + dictionary + ); +} +} + +// * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::heatSourceProfiles::tabulated::tabulated() +: + nx_(0), + ny_(0), + x0_(0), + y0_(0), + dx_(0), + dy_(0), + x1_(0), + y1_(0), + invDx_(0), + invDy_(0), + values_(0), + metrics_(), + bounds_(point::zero, point::zero) +{} + +Foam::heatSourceProfiles::tabulated::tabulated(const fileName& profileFile) +: + tabulated() +{ + read(profileFile); +} + + +Foam::heatSourceProfiles::tabulated::tabulated +( + const dictionary& dict, + const fvMesh& mesh, + const scalar +) +: + tabulated() +{ + const fileName fName(dict.lookup("file")); + + const fileName tableFile + ( + mesh.time().rootPath() + /mesh.time().globalCaseName() + /mesh.time().constant() + /fName + ); + + read(tableFile); + + Info<< "Tabulated profile: integral=" << metrics_.integral() + << ", centroid=" << metrics_.centroid() << " m" + << ", D4Sigma (major minor)=" << metrics_.D4Sigma() << " m" + << ", azimuth=" << metrics_.azimuth() << " rad" << endl; +} + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * // + +void Foam::heatSourceProfiles::tabulated::integrate() +{ + // Raw moments M_pq = integral x^p*y^q*I(x,y) dx dy + scalar M00 = 0; + scalar M10 = 0; + scalar M01 = 0; + scalar M20 = 0; + scalar M02 = 0; + scalar M11 = 0; + + for (label j=0; j> nx_ >> ny_; + is >> x0_ >> y0_; + is >> dx_ >> dy_; + + if (nx_ < 2 || ny_ < 2 || dx_ <= 0 || dy_ <= 0) + { + FatalErrorInFunction + << "Tabulated profile requires nx, ny >= 2 and positive spacing; " + << "found nx=" << nx_ << ", ny=" << ny_ << ", dx=" << dx_ + << ", dy=" << dy_ << exit(FatalError); + } + + x1_ = x0_ + (nx_ - 1)*dx_; + y1_ = y0_ + (ny_ - 1)*dy_; + invDx_ = 1.0/dx_; + invDy_ = 1.0/dy_; + + values_.setSize(nx_*ny_); + + forAll(values_, i) + { + is >> values_[i]; + + if (!is.good() || values_[i] < 0) + { + FatalErrorInFunction + << "Tabulated profile values must be present and nonnegative; " + << "invalid value at index " << i << " in " << profileFile + << exit(FatalError); + } + } + + integrate(); + + bounds_ = + boundBox + ( + point(x0_, y0_, 0), + point(x1_, y1_, 0) + ); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/tabulated/tabulatedProfile.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/tabulated/tabulatedProfile.H new file mode 100644 index 00000000..3b51f93d --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/profiles/tabulated/tabulatedProfile.H @@ -0,0 +1,189 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::heatSourceProfiles::tabulated + +Description + Tabulated profile on a uniform two-dimensional grid, with exact integral + and second moments of its bilinear interpolant. + +SourceFiles + tabulatedProfile.C + +\*---------------------------------------------------------------------------*/ + +#ifndef tabulatedProfile_H +#define tabulatedProfile_H + +#include "fileName.H" +#include "heatSourceProfile.H" +#include "scalarField.H" + +namespace Foam +{ +namespace heatSourceProfiles +{ + +class tabulated +: + public heatSourceProfile +{ + // Private Data + + label nx_; + label ny_; + + scalar x0_; + scalar y0_; + scalar dx_; + scalar dy_; + scalar x1_; + scalar y1_; + scalar invDx_; + scalar invDy_; + + scalarField values_; + + profileMetrics metrics_; + + boundBox bounds_; + + // Private Member Functions + + void integrate(); + + +public: + //- Runtime type information + TypeName("tabulated"); + + // Constructors + + tabulated(); + + explicit tabulated(const fileName& profileFile); + + tabulated + ( + const dictionary& dict, + const fvMesh& mesh, + const scalar tolerance + ); + + // Member Functions + + void read(const fileName& profileFile); + + inline virtual scalar weight + ( + const scalar x, + const scalar y + ) const + { + return interpolate(x, y); + } + + inline scalar interpolate(const scalar x, const scalar y) const + { + const scalar xp = (x - x0_)*invDx_; + const scalar yp = (y - y0_)*invDy_; + + if (xp < 0 || xp > nx_ - 1 || yp < 0 || yp > ny_ - 1) + { + return 0; + } + + const label i = min(label(xp), nx_ - 2); + const label j = min(label(yp), ny_ - 2); + const scalar tx = xp - i; + const scalar ty = yp - j; + const label index = i + nx_*j; + + return + (1.0 - tx)*(1.0 - ty)*values_[index] + + tx*(1.0 - ty)*values_[index + 1] + + (1.0 - tx)*ty*values_[index + nx_] + + tx*ty*values_[index + nx_ + 1]; + } + + inline label nx() const + { + return nx_; + } + + inline label ny() const + { + return ny_; + } + + inline scalar x0() const + { + return x0_; + } + + inline scalar y0() const + { + return y0_; + } + + inline scalar x1() const + { + return x1_; + } + + inline scalar y1() const + { + return y1_; + } + + inline scalar dx() const + { + return dx_; + } + + inline scalar dy() const + { + return dy_; + } + + inline virtual const profileMetrics& metrics() const + { + return metrics_; + } + + inline virtual const boundBox& bounds() const + { + return bounds_; + } + +}; + +} // End namespace heatSourceProfiles +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projected.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projected.C new file mode 100644 index 00000000..bdf04f1f --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projected.C @@ -0,0 +1,112 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "projected.H" +#include "addToRunTimeSelectionTable.H" + +namespace Foam +{ +namespace heatSourceModels +{ + defineTypeNameAndDebug(projected, 0); + addToRunTimeSelectionTable + ( + heatSourceModel, + projected, + dictionary + ); +} +} + +Foam::heatSourceModels::projected::projected +( + const dictionary& dict, + const fvMesh& mesh +) +: + heatSourceModel(dict), + profile_ + ( + heatSourceProfile::New + ( + dict.subDict("profile"), + mesh, + tolerance_/(1.0 + Foam::sqrt(1.0 - tolerance_)) + ) + ), + projection_(heatSourceProjection::New(dict.subDict("projection"))), + componentTolerance_ + ( + tolerance_/(1.0 + Foam::sqrt(1.0 - tolerance_)) + ) +{ + bounds_ = profile_->bounds(); + + Info<< "Beam-plane D4Sigma (major minor)=" + << metrics().D4Sigma() << " m, azimuth=" + << metrics().azimuth() << " rad" << endl; +} + + +void Foam::heatSourceModels::projected::update +( + const scalar depth, + const scalar aspectRatio +) +{ + sourceDepth_ = depth; + + projection_->update + ( + sourceDepth_, + aspectRatio, + componentTolerance_ + ); + + bounds_.min().z() = projection_->zMin(); + bounds_.max().z() = 0; + + V0_ = + dimensionedScalar + ( + "V0", + dimVolume, + metrics().integral()*projection_->integral() + ); +} + + +Foam::scalar Foam::heatSourceModels::projected::weight +( + const vector& r +) const +{ + return + projection_->weight(r.z()) + *profile_->weight(r.x(), r.y()); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projected.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projected.H new file mode 100644 index 00000000..68e4130f --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projected.H @@ -0,0 +1,92 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::heatSourceModels::projected + +Description + Separable heat source constructed from a planar beam profile and a + one-sided axial projection. + +SourceFiles + projected.C + +\*---------------------------------------------------------------------------*/ + +#ifndef projected_H +#define projected_H + +#include "heatSourceModel.H" +#include "heatSourceProfile.H" +#include "heatSourceProjection.H" + +namespace Foam +{ +namespace heatSourceModels +{ + +class projected +: + public heatSourceModel +{ + autoPtr profile_; + + autoPtr projection_; + + scalar componentTolerance_; + +public: + + TypeName("projected"); + + projected + ( + const dictionary& dict, + const fvMesh& mesh + ); + + virtual ~projected() + {} + + virtual void update + ( + const scalar depth, + const scalar aspectRatio + ); + + virtual scalar weight(const vector& r) const; + + inline virtual const profileMetrics& metrics() const + { + return profile_->metrics(); + } +}; + +} // End namespace heatSourceModels +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/exponential/exponential.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/exponential/exponential.C new file mode 100644 index 00000000..f6dd6a42 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/exponential/exponential.C @@ -0,0 +1,112 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "exponential.H" +#include "addToRunTimeSelectionTable.H" + +namespace Foam +{ +namespace heatSourceProjections +{ + defineTypeNameAndDebug(exponential, 0); + addToRunTimeSelectionTable + ( + heatSourceProjection, + exponential, + dictionary + ); +} +} + +Foam::heatSourceProjections::exponential::exponential +( + const dictionary& dict +) +: + nSlope_(0), + nIntercept_(0), + depth_(0), + k_(1), + integral_(0), + zMin_(0) +{ + nSlope_ = dict.lookup("nSlope"); + nIntercept_ = dict.lookup("nIntercept"); + +} + + +void Foam::heatSourceProjections::exponential::update +( + const scalar depth, + const scalar aspectRatio, + const scalar tolerance +) +{ + depth_ = depth; + + const scalar n = + min + ( + max + ( + nSlope_*std::log2(max(aspectRatio, VSMALL)) + nIntercept_, + 0.0 + ), + 9.0 + ); + + k_ = Foam::pow(2.0, n); + + integral_ = + depth_*Foam::tgamma(1.0/k_) + /(k_*Foam::pow(3.0, 1.0/k_)); + + zMin_ = + -depth_ + *Foam::pow + ( + invIncGammaRatio_P(1.0/k_, 1.0 - tolerance)/3.0, + 1.0/k_ + ); +} + + +inline Foam::scalar Foam::heatSourceProjections::exponential::weight +( + const scalar z +) const +{ + if (z > 0) + { + return 0; + } + + return Foam::exp(-3.0*Foam::pow(-z/depth_, k_)); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projectedGaussian/projectedGaussian.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/exponential/exponential.H similarity index 52% rename from applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projectedGaussian/projectedGaussian.H rename to applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/exponential/exponential.H index d6106887..38a9e830 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projectedGaussian/projectedGaussian.H +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/exponential/exponential.H @@ -5,7 +5,7 @@ \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2023-2026 Oak Ridge National Laboratory + Copyright (C) 2026 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -24,88 +24,90 @@ License along with OpenFOAM. If not, see . Class - Foam::heatSourceModels::projectedGaussian + Foam::heatSourceProjections::exponential Description - projectedGaussian heat source model for additive manufacting + One-sided generalized exponential projection applied in the negative z + direction from the beam plane. SourceFiles - projectedGaussian.C + exponential.C \*---------------------------------------------------------------------------*/ -#ifndef projectedGaussian_H -#define projectedGaussian_H +#ifndef exponential_H +#define exponential_H -#include "heatSourceModel.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#include "heatSourceProjection.H" namespace Foam { -namespace heatSourceModels +namespace heatSourceProjections { -/*---------------------------------------------------------------------------*\ - Class projectedGaussian -\*---------------------------------------------------------------------------*/ - -class projectedGaussian +class exponential : - public heatSourceModel + public heatSourceProjection { // Private Data - //- Pointer to mesh information - const fvMesh& mesh_; + //- nSlope in n = nSlope*log2(a) + nIntercept + scalar nSlope_; + + //- nIntercept in n = nSlope*log2(a) + nIntercept + scalar nIntercept_; - //- weights for axial decay of 2D gaussian distribution in the form: - //- n = Alog2(x) + B - scalar A_; - scalar B_; + //- Projection depth + scalar depth_; + //- Axial decay exponent scalar k_; + //- Projection integral + scalar integral_; + + //- Lower projection bound + scalar zMin_; + public: //- Runtime type information - TypeName("projectedGaussian"); + TypeName("exponential"); // Constructors - //- Construct from components - projectedGaussian - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - + explicit exponential(const dictionary& dict); //- Destructor - virtual ~projectedGaussian() + virtual ~exponential() {} - // Member Functions - inline virtual scalar weight(const vector& d); - - inline virtual dimensionedScalar V0(); + virtual void update + ( + const scalar depth, + const scalar aspectRatio, + const scalar tolerance + ); - //- Read the heatSourceProperties dictionary - virtual bool read(); -}; + inline virtual scalar weight(const scalar z) const; + inline virtual scalar integral() const + { + return integral_; + } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + inline virtual scalar zMin() const + { + return zMin_; + } +}; -} // End namespace heatSourceModels +} // End namespace heatSourceProjections } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.C new file mode 100644 index 00000000..0fdfa0f1 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.C @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "heatSourceProjection.H" + +namespace Foam +{ + defineTypeNameAndDebug(heatSourceProjection, 0); + defineRunTimeSelectionTable(heatSourceProjection, dictionary); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.H new file mode 100644 index 00000000..2be30b2c --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjection.H @@ -0,0 +1,110 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 . + +Class + Foam::heatSourceProjection + +Description + Abstract base class for one-dimensional heat source projections. + +SourceFiles + heatSourceProjection.C + heatSourceProjectionNew.C + +\*---------------------------------------------------------------------------*/ + +#ifndef heatSourceProjection_H +#define heatSourceProjection_H + +#include "autoPtr.H" +#include "dictionary.H" +#include "runTimeSelectionTables.H" + +namespace Foam +{ + +class heatSourceProjection +{ +public: + + //- Runtime type information + TypeName("heatSourceProjection"); + + // Declare run-time constructor selection table + declareRunTimeSelectionTable + ( + autoPtr, + heatSourceProjection, + dictionary, + (const dictionary& dict), + (dict) + ); + + // Constructors + + heatSourceProjection() + {} + + //- Disallow default bitwise copy construction + heatSourceProjection(const heatSourceProjection&); + + // Selectors + + static autoPtr New(const dictionary& dict); + + //- Destructor + virtual ~heatSourceProjection() + {} + + // Member Functions + + //- Update the projection state + virtual void update + ( + const scalar depth, + const scalar aspectRatio, + const scalar tolerance + ) = 0; + + //- Return the projection weight + virtual scalar weight(const scalar z) const = 0; + + //- Return the projection integral + virtual scalar integral() const = 0; + + //- Return the lower projection bound + virtual scalar zMin() const = 0; + + // Member Operators + + //- Disallow default bitwise assignment + void operator=(const heatSourceProjection&) = delete; +}; + +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjectionNew.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjectionNew.C new file mode 100644 index 00000000..609a1529 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projected/projections/heatSourceProjection/heatSourceProjectionNew.C @@ -0,0 +1,57 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2022 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 "heatSourceProjection.H" + +Foam::autoPtr Foam::heatSourceProjection::New +( + const dictionary& dict +) +{ + const word projectionType(dict.lookup("model")); + + Info<< "Selecting heatSourceProjection " << projectionType << endl; + + const auto cstrIter = dictionaryConstructorTablePtr_->find(projectionType); + + if (cstrIter == dictionaryConstructorTablePtr_->end()) + { + FatalErrorInFunction + << "Unknown " << heatSourceProjection::typeName << " type " + << projectionType << nl << nl + << "Valid heatSourceProjections are:" << endl + << dictionaryConstructorTablePtr_->sortedToc() + << exit(FatalError); + } + + return autoPtr + ( + cstrIter()(dict) + ); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projectedGaussian/projectedGaussian.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projectedGaussian/projectedGaussian.C deleted file mode 100644 index 62a40899..00000000 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/projectedGaussian/projectedGaussian.C +++ /dev/null @@ -1,139 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023-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 "projectedGaussian.H" -#include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ -namespace heatSourceModels -{ - defineTypeNameAndDebug(projectedGaussian, 0); - addToRunTimeSelectionTable(heatSourceModel, projectedGaussian, dictionary); -} -} - -using Foam::constant::mathematical::pi; - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::heatSourceModels::projectedGaussian::projectedGaussian -( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh -) -: - heatSourceModel(typeName, sourceName, dict, mesh), - mesh_(mesh) -{ - A_ = heatSourceModelCoeffs_.lookup("A"); - B_ = heatSourceModelCoeffs_.lookup("B"); - - // set initial shape function - const scalar x_ = - max - ( - dimensions_.z() - / min(staticDimensions_.x(), staticDimensions_.y()), - 0.001 - ); - const scalar n_ = min(max(A_*std::log2(x_) + B_, 0.0), 9.0); - k_ = std::pow(2.0, n_); -} - - -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // - -inline Foam::scalar -Foam::heatSourceModels::projectedGaussian::weight(const vector& d) -{ - const scalar f_ = - std::exp - ( - -2.0 - * ( - Foam::sqr(d.x() / dimensions_.x()) - + Foam::sqr(d.y() / dimensions_.y()) - ) - ); - - const scalar s_ = - std::exp(-3.0 * std::pow(mag(mag(d.z()) / dimensions_.z()), k_)); - - return f_ * s_; -} - -inline Foam::dimensionedScalar -Foam::heatSourceModels::projectedGaussian::V0() -{ - const scalar x_ = - max - ( - dimensions_.z() - / min(staticDimensions_.x(), staticDimensions_.y()), - 0.001 - ); - - const scalar n_ = min(max(A_*std::log2(x_) + B_, 0.0), 9.0); - - k_ = std::pow(2.0, n_); - - const dimensionedScalar V0 - ( - "V0", - dimVolume, - 0.5 * pi * dimensions_.x() * dimensions_.y() * dimensions_.z() - * Foam::tgamma(1.0 / k_) - / ( k_ * std::pow(3.0, 1.0 / k_) ) - ); - - return V0; -} - -bool Foam::heatSourceModels::projectedGaussian::read() -{ - if (heatSourceModel::read()) - { - heatSourceModelCoeffs_ = optionalSubDict(type() + "Coeffs"); - - //- Mandatory entries - heatSourceModelCoeffs_.lookup("A") >> A_; - heatSourceModelCoeffs_.lookup("B") >> B_; - - return true; - } - else - { - return false; - } -} - - -// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.C index 822e1781..99d00dd8 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.C +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.C @@ -5,7 +5,7 @@ \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory + Copyright (C) 2023-2026 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -22,13 +22,12 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . - \*---------------------------------------------------------------------------*/ #include "superGaussian.H" +#include "superGaussianProfile.H" #include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +#include "mathematicalConstants.H" namespace Foam { @@ -41,65 +40,140 @@ namespace heatSourceModels using Foam::constant::mathematical::pi; -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - Foam::heatSourceModels::superGaussian::superGaussian ( - const word& sourceName, const dictionary& dict, const fvMesh& mesh ) : - heatSourceModel(typeName, sourceName, dict, mesh), - mesh_(mesh) + heatSourceModel(dict), + radius_(dict.lookup("radius")), + k_(dict.lookup("k")), + coefficient_ + ( + heatSourceProfiles::superGaussian::coefficient(dict, k_) + ), + cosTheta_(0), + sinTheta_(0), + metrics_() { - k_ = heatSourceModelCoeffs_.lookup("k"); -} + const scalar variance = + 0.5*Foam::tgamma(4.0/k_)/Foam::tgamma(2.0/k_); + const scalar azimuth = + dict.lookupOrDefault("azimuth", 0)*pi/180.0; -// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + cosTheta_ = Foam::cos(azimuth); -inline Foam::scalar -Foam::heatSourceModels::superGaussian::weight(const vector& d) -{ - vector s = dimensions_ / Foam::pow(2.0, 1.0/k_); + sinTheta_ = Foam::sin(azimuth); - scalar x = Foam::pow(magSqr(cmptDivide(d, s)), k_/2.0); + const scalar sx2 = sqr(radius_.x())/coefficient_; - return Foam::exp(-x); -} + const scalar sy2 = sqr(radius_.y())/coefficient_; -inline Foam::dimensionedScalar -Foam::heatSourceModels::superGaussian::V0() -{ - vector s = dimensions_ / Foam::pow(2.0, 1.0/k_); + const scalar integral = + pi*radius_.x()*radius_.y()/coefficient_ + *Foam::tgamma(1.0 + 2.0/k_); + + const scalar varianceX = + sqr(cosTheta_)*sx2*variance + + sqr(sinTheta_)*sy2*variance; + + const scalar varianceY = + sqr(sinTheta_)*sx2*variance + + sqr(cosTheta_)*sy2*variance; - const dimensionedScalar V0 + const scalar covariance = + cosTheta_*sinTheta_*(sx2 - sy2)*variance; + + metrics_.reset ( - "V0", - dimVolume, - (2.0 / 3.0)*s.x()*s.y()*s.z()*pi*Foam::tgamma(1.0 + 3.0/k_) + integral, + 0, + 0, + integral*varianceX, + integral*varianceY, + integral*covariance ); - return V0; + update(depth_, 0); } -bool Foam::heatSourceModels::superGaussian::read() + +void Foam::heatSourceModels::superGaussian::update +( + const scalar depth, + const scalar +) { - if (heatSourceModel::read()) - { - heatSourceModelCoeffs_ = optionalSubDict(type() + "Coeffs"); + sourceDepth_ = depth; + + const scalar fMax = + Foam::pow + ( + invIncGammaRatio_P(3.0/k_, 1.0 - tolerance_), + 1.0/k_ + ); + + const scalar xMax = + fMax/Foam::sqrt(coefficient_) + *Foam::sqrt + ( + sqr(radius_.x()*cosTheta_) + + sqr(radius_.y()*sinTheta_) + ); + + const scalar yMax = + fMax/Foam::sqrt(coefficient_) + *Foam::sqrt + ( + sqr(radius_.x()*sinTheta_) + + sqr(radius_.y()*cosTheta_) + ); + + const scalar zMax = fMax*sourceDepth_/Foam::pow(2.0, 1.0/k_); + + bounds_ = + boundBox + ( + point(-xMax, -yMax, -zMax), + point(xMax, yMax, 0) + ); + + V0_ = + dimensionedScalar + ( + "V0", + dimVolume, + (2.0/3.0)*pi*radius_.x()*radius_.y()*sourceDepth_ + /(coefficient_*Foam::pow(2.0, 1.0/k_)) + *Foam::tgamma(1.0 + 3.0/k_) + ); +} - //- Mandatory entries - heatSourceModelCoeffs_.lookup("k") >> k_; - return true; - } - else +Foam::scalar Foam::heatSourceModels::superGaussian::weight +( + const vector& r +) const +{ + if (r.z() > 0) { - return false; + return 0; } -} + const scalar x = cosTheta_*r.x() + sinTheta_*r.y(); + + const scalar y = -sinTheta_*r.x() + cosTheta_*r.y(); + + const scalar radiusSqr = + sqr(x/radius_.x()) + sqr(y/radius_.y()); + + const scalar f = + coefficient_*radiusSqr + + Foam::pow(2.0, 2.0/k_)*sqr(r.z()/sourceDepth_); + + return Foam::exp(-Foam::pow(f, k_/2.0)); +} // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.H index 1532552a..3090eb57 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.H +++ b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/superGaussian/superGaussian.H @@ -5,7 +5,7 @@ \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2023 Oak Ridge National Laboratory + Copyright (C) 2023-2026 Oak Ridge National Laboratory ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,7 +27,8 @@ Class Foam::heatSourceModels::superGaussian Description - superGaussian heat source model for additive manufacting + One-sided volumetric super-Gaussian heat source. definition applies to + radius; depth always specifies the axial depth. SourceFiles superGaussian.C @@ -39,69 +40,57 @@ SourceFiles #include "heatSourceModel.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - namespace Foam { namespace heatSourceModels { -/*---------------------------------------------------------------------------*\ - Class superGaussian -\*---------------------------------------------------------------------------*/ - class superGaussian : public heatSourceModel { - // Private Data + vector2D radius_; - //- Pointer to mesh information - const fvMesh& mesh_; + scalar k_; - //- Shape coefficient of supergaussian distribution - scalar k_; + scalar coefficient_; -public: + scalar cosTheta_; - //- Runtime type information - TypeName("superGaussian"); + scalar sinTheta_; + profileMetrics metrics_; - // Constructors +public: - //- Construct from components - superGaussian - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); + TypeName("superGaussian"); + superGaussian + ( + const dictionary& dict, + const fvMesh& mesh + ); - //- Destructor virtual ~superGaussian() {} + virtual void update + ( + const scalar depth, + const scalar aspectRatio + ); - // Member Functions - - inline virtual scalar weight(const vector& d); - - inline virtual dimensionedScalar V0(); + virtual scalar weight(const vector& r) const; - //- Read the heatSourceProperties dictionary - virtual bool read(); + inline virtual const profileMetrics& metrics() const + { + return metrics_; + } }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - } // End namespace heatSourceModels } // End namespace Foam -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/tabulated/tabulated.C b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/tabulated/tabulated.C deleted file mode 100644 index 92717465..00000000 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/tabulated/tabulated.C +++ /dev/null @@ -1,243 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023-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 "tabulated.H" -#include "addToRunTimeSelectionTable.H" -#include "IFstream.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ -namespace heatSourceModels -{ - defineTypeNameAndDebug(tabulated, 0); - addToRunTimeSelectionTable(heatSourceModel, tabulated, dictionary); -} -} - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::heatSourceModels::tabulated::tabulated -( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh -) -: - heatSourceModel(typeName, sourceName, dict, mesh), - mesh_(mesh), - A_(Zero), - B_(Zero), - k_(Zero), - x0_(Zero), - y0_(Zero), - dx_(Zero), - dy_(Zero), - invDx_(Zero), - invDy_(Zero), - nx_(Zero), - ny_(Zero), - f_(0), - Axy_(Zero) -{ - A_ = heatSourceModelCoeffs_.lookup("A"); - B_ = heatSourceModelCoeffs_.lookup("B"); - - const fileName fName(heatSourceModelCoeffs_.lookup("file")); - - const fileName tableFile - ( - mesh_.time().rootPath() - /mesh_.time().globalCaseName() - /mesh_.time().constant() - /fName - ); - - readTable(tableFile); - integrateTable(); - - const scalar x = - max - ( - dimensions_.z()/min(staticDimensions_.x(), staticDimensions_.y()), - 0.001 - ); - - const scalar n = min(max(A_*std::log2(x) + B_, 0.0), 9.0); - - k_ = std::pow(2.0, n); -} - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -void Foam::heatSourceModels::tabulated::readTable(const fileName& tableFile) -{ - IFstream is(tableFile); - - if (!is.good()) - { - FatalIOErrorInFunction(heatSourceModelCoeffs_) - << "Cannot find tabulated heat source file " << tableFile - << exit(FatalIOError); - } - - is >> nx_ >> ny_; - is >> x0_ >> y0_; - is >> dx_ >> dy_; - - invDx_ = 1.0/dx_; - invDy_ = 1.0/dy_; - - f_.setSize(nx_*ny_); - - forAll(f_, i) - { - is >> f_[i]; - } -} - - -void Foam::heatSourceModels::tabulated::integrateTable() -{ - Axy_ = Zero; - - for (label j=0; j nx_ - 1 || yp < 0.0 || yp > ny_ - 1) - { - return 0.0; - } - - label i = label(xp); - label j = label(yp); - - i = min(i, nx_ - 2); - j = min(j, ny_ - 2); - - const scalar tx = xp - i; - const scalar ty = yp - j; - - const label id = i + nx_*j; - - const scalar f = - (1.0 - tx)*(1.0 - ty)*f_[id] - + tx*(1.0 - ty)*f_[id + 1] - + (1.0 - tx)*ty*f_[id + nx_] - + tx*ty*f_[id + nx_ + 1]; - - const scalar s = - std::exp(-3.0*std::pow(mag(d.z()/dimensions_.z()), k_)); - - return f*s; -} - - -inline Foam::dimensionedScalar -Foam::heatSourceModels::tabulated::V0() -{ - const scalar x = - max - ( - dimensions_.z()/min(staticDimensions_.x(), staticDimensions_.y()), - 0.001 - ); - - const scalar n = min(max(A_*std::log2(x) + B_, 0.0), 9.0); - - k_ = std::pow(2.0, n); - - const dimensionedScalar V0 - ( - "V0", - dimVolume, - Axy_*dimensions_.z()*Foam::tgamma(1.0/k_) - / (k_*std::pow(3.0, 1.0/k_)) - ); - - return V0; -} - - -bool Foam::heatSourceModels::tabulated::read() -{ - if (heatSourceModel::read()) - { - heatSourceModelCoeffs_ = optionalSubDict(type() + "Coeffs"); - - heatSourceModelCoeffs_.lookup("A") >> A_; - heatSourceModelCoeffs_.lookup("B") >> B_; - - const fileName fName(heatSourceModelCoeffs_.lookup("file")); - - const fileName tableFile - ( - mesh_.time().rootPath() - /mesh_.time().globalCaseName() - /mesh_.time().constant() - /fName - ); - - readTable(tableFile); - integrateTable(); - - return true; - } - else - { - return false; - } -} - - -// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/tabulated/tabulated.H b/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/tabulated/tabulated.H deleted file mode 100644 index 4239c3cd..00000000 --- a/applications/solvers/additiveFoam/movingHeatSource/heatSourceModels/tabulated/tabulated.H +++ /dev/null @@ -1,153 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2023-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 . - -Class - Foam::heatSourceModels::tabulated - -Description - Tabulated 2D heat source model with a projected axial distribution - -SourceFiles - tabulated.C - -\*---------------------------------------------------------------------------*/ - -#ifndef tabulated_H -#define tabulated_H - -#include "heatSourceModel.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ -namespace heatSourceModels -{ - -/*---------------------------------------------------------------------------*\ - Class tabulated -\*---------------------------------------------------------------------------*/ - -class tabulated -: - public heatSourceModel -{ - // Private Data - - //- Pointer to mesh information - const fvMesh& mesh_; - - //- Axial decay coefficient in the form n = Alog2(x) + B - scalar A_; - - //- Axial decay coefficient in the form n = Alog2(x) + B - scalar B_; - - //- Axial decay exponent - scalar k_; - - //- Minimum x coordinate of the table - scalar x0_; - - //- Minimum y coordinate of the table - scalar y0_; - - //- Uniform x spacing - scalar dx_; - - //- Uniform y spacing - scalar dy_; - - //- Inverse uniform x spacing - scalar invDx_; - - //- Inverse uniform y spacing - scalar invDy_; - - //- Number of x points - label nx_; - - //- Number of y points - label ny_; - - //- Tabulated planar intensity, stored as i + nx*j - scalarField f_; - - //- Integrated planar distribution - scalar Axy_; - - - // Private Member Functions - - //- Read tabulated planar distribution - void readTable(const fileName& tableFile); - - //- Integrate tabulated planar distribution - void integrateTable(); - - -public: - - //- Runtime type information - TypeName("tabulated"); - - - // Constructors - - //- Construct from components - tabulated - ( - const word& sourceName, - const dictionary& dict, - const fvMesh& mesh - ); - - - //- Destructor - virtual ~tabulated() - {} - - - // Member Functions - - inline virtual scalar weight(const vector& d); - - inline virtual dimensionedScalar V0(); - - //- Read the heatSourceProperties dictionary - virtual bool read(); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace heatSourceModels -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.C b/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.C index aeaba037..464bb153 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.C +++ b/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.C @@ -26,6 +26,7 @@ License \*---------------------------------------------------------------------------*/ #include "movingBeam.H" +#include #include // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -35,22 +36,17 @@ const Foam::scalar Foam::movingBeam::eps = 1e-10; namespace Foam { defineTypeNameAndDebug(movingBeam, 0); - defineRunTimeSelectionTable(movingBeam, dictionary); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::movingBeam::movingBeam ( - const word& sourceName, - const dictionary& dict, + const dictionary& sourceDict, const Time& runTime ) : - sourceName_(sourceName), - dict_(dict), runTime_(runTime), - beamDict_(dict_.optionalSubDict(sourceName_)), path_(0), index_(0), position_(Zero), @@ -60,16 +56,16 @@ Foam::movingBeam::movingBeam hitPathIntervals_(true) { //- Get beam parameters - deltaT_ = beamDict_.lookupOrDefault("deltaT", GREAT); + deltaT_ = sourceDict.lookupOrDefault("deltaT", GREAT); - hitPathIntervals_ = beamDict_.lookupOrDefault + hitPathIntervals_ = sourceDict.lookupOrDefault ( "hitPathIntervals", true ); //- Read scan path file - readPath(); + readPath(sourceDict.lookup("path")); //- Initialize path index if (path_.size()) @@ -99,27 +95,28 @@ Foam::movingBeam::movingBeam // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -void Foam::movingBeam::readPath() +void Foam::movingBeam::readPath(const fileName& pathName) { - const word pName_(beamDict_.lookup("pathName")); - - const fileName pFile_ + const fileName pathFile ( - runTime_.rootPath()/runTime_.globalCaseName()/runTime_.constant()/pName_ + runTime_.rootPath() + /runTime_.globalCaseName() + /runTime_.constant() + /pathName ); - std::ifstream is(pFile_); + std::ifstream is(pathFile); if (!is.good()) { FatalErrorInFunction - << "Cannot find file " << pFile_ + << "Cannot find file " << pathFile << nl << exit(FatalError); } else { - Info << "Reading scan path from: " << pFile_ << endl; + Info << "Reading scan path from: " << pathFile << endl; } std::string line; diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.H b/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.H index 2a558a1d..804ff959 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.H +++ b/applications/solvers/additiveFoam/movingHeatSource/movingBeam/movingBeam.H @@ -24,14 +24,13 @@ License along with OpenFOAM. If not, see . Class - Foam::movingBeams + Foam::movingBeam Description Class for individual moving beam heat sources SourceFiles movingBeam.C - calculateQDot.C \*---------------------------------------------------------------------------*/ @@ -40,13 +39,10 @@ SourceFiles // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#include -#include "fvc.H" -#include "pathVector.H" -#include "HashTable.H" -#include "absorptionModel.H" +#include "dictionary.H" #include "DynamicList.H" -#include "meshSearch.H" +#include "pathVector.H" +#include "Time.H" namespace Foam { @@ -61,18 +57,9 @@ private: // Private data - //- Name of beam - const word& sourceName_; - - //- Main moving heat source dictionary - const dictionary& dict_; - //- Run time information const Time& runTime_; - //- Individual beam sub-dict - const dictionary& beamDict_; - //- List of beam pathVectors DynamicList path_; @@ -104,49 +91,18 @@ public: //- Runtime type information TypeName("movingBeam"); - // Declare run-time constructor selection table - declareRunTimeSelectionTable - ( - autoPtr, - movingBeam, - dictionary, - ( - const word& sourceName, - const dictionary& dict, - const Time& runTime - ), - (sourceName, dict, runTime) - ); - // Constructors // Construct from time and dictionary movingBeam ( - const word& sourceName, - const dictionary& dict, + const dictionary& sourceDict, const Time& runTime ); //- Disallow default bitwise copy construction movingBeam(const movingBeam&); - // Selectors - - //- Return a reference to the selected phaseChange model - static autoPtr New - ( - const word& sourceName, - const dictionary& dict, - const Time& runTime - ) - { - return autoPtr - ( - new movingBeam(sourceName, dict, runTime) - ); - } - //- Destructor virtual ~movingBeam() {} @@ -196,7 +152,7 @@ public: void move(const scalar time); //- Read the path file - void readPath(); + void readPath(const fileName& pathName); }; diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSource.C b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSource.C new file mode 100644 index 00000000..7c30a118 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSource.C @@ -0,0 +1,210 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory + \\/ M anipulation | +------------------------------------------------------------------------------- +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 "movingHeatSource.H" +#include "fvc.H" +#include "hexMatcher.H" +#include "treeBoundBox.H" + +Foam::movingHeatSource::movingHeatSource +( + const word& name, + const dictionary& sourceDict, + const fvMesh& mesh +) +: + name_(name), + mesh_(mesh), + beam_(sourceDict, mesh_.time()), + absorption_(absorptionModel::New(sourceDict.subDict("absorption"), mesh_)), + heatSource_ + ( + heatSourceModel::New + ( + sourceDict.subDict("heatSource"), + mesh_ + ) + ), + references_(sourceDict, mesh_) +{ + update(); +} + + +void Foam::movingHeatSource::update() +{ + references_.update + ( + heatSource_->metrics(), + heatSource_->depth(), + beam_.position(), + heatSource_->bounds() + ); + + const scalar referenceDepth = references_.depth(); + const scalar sourceDepth = max(heatSource_->depth(), referenceDepth); + heatSource_->update(sourceDepth, references_.aspectRatio()); + + if (references_.isothermDepth()) + { + Info<< "referenceDepth: " << referenceDepth + << ", depth: " << sourceDepth << endl; + } +} + +Foam::tmp Foam::movingHeatSource::qDot() const +{ + tmp tqDot + ( + new volScalarField + ( + IOobject + ( + "qDot_" + name_, + mesh_.time().name(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar("zero", dimPower/dimVolume, 0) + ) + ); + volScalarField& qDot = tqDot.ref(); + + if (beam_.power() <= small) + { + return tqDot; + } + + const vector position = beam_.position(); + const boundBox& bounds = heatSource_->bounds(); + const labelVector& nPoints = heatSource_->nPoints(); + const dimensionedScalar absorbedPower + ( + "etaP", + dimPower, + absorption_->eta(references_.aspectRatio())*beam_.power() + ); + dimensionedScalar volume(heatSource_->V0()); + + volScalarField weights + ( + IOobject + ( + "weights_" + name_, + mesh_.time().name(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar("zero", dimless, 0) + ); + + const treeBoundBox currentBounds + ( + position + bounds.min(), + position + bounds.max() + ); + const pointField& points = mesh_.points(); + hexMatcher hex; + + forAll(mesh_.cells(), celli) + { + treeBoundBox cellBounds(point::max, point::min); + const labelList& vertices = mesh_.cellPoints()[celli]; + + forAll(vertices, i) + { + cellBounds.min() = min(cellBounds.min(), points[vertices[i]]); + cellBounds.max() = max(cellBounds.max(), points[vertices[i]]); + } + + if (!cellBounds.overlaps(currentBounds)) + { + continue; + } + + if (!hex.isA(mesh_, celli)) + { + weights[celli] = + heatSource_->weight(mesh_.cellCentres()[celli] - position); + continue; + } + + vector dx = cmptDivide(bounds.span(), vector(nPoints)); + const labelVector nSamples + ( + max + ( + cmptDivide(cellBounds.span() + small*vector::one, dx), + vector::one + ) + ); + dx = cmptDivide(cellBounds.span(), vector(nSamples)); + const scalar dVi = dx.x()*dx.y()*dx.z(); + scalar wi = 0; + + for (label k=0; kweight(pt - position)*dVi; + } + } + } + } + + weights[celli] = wi/mesh_.V()[celli]; + } + + const dimensionedScalar sumWeights = fvc::domainIntegrate(weights); + const scalar residual = (sumWeights/volume).value(); + + if (mag(1.0 - residual) < 0.05) + { + volume = sumWeights; + } + + qDot = absorbedPower*weights/volume; + return tqDot; +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSource.H b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSource.H new file mode 100644 index 00000000..782d78ab --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSource.H @@ -0,0 +1,87 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory + \\/ M anipulation | +------------------------------------------------------------------------------- +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 movingHeatSource_H +#define movingHeatSource_H + +#include "absorptionModel.H" +#include "heatSourceModel.H" +#include "movingBeam.H" +#include "referenceDimensions.H" +#include "volFields.H" + +namespace Foam +{ + +class movingHeatSource +{ + word name_; + const fvMesh& mesh_; + movingBeam beam_; + autoPtr absorption_; + autoPtr heatSource_; + referenceDimensions references_; +public: + + movingHeatSource + ( + const word& name, + const dictionary& sourceDict, + const fvMesh& mesh + ); + + movingHeatSource(const movingHeatSource&) = delete; + + inline const word& name() const + { + return name_; + } + + inline movingBeam& beam() + { + return beam_; + } + + inline const movingBeam& beam() const + { + return beam_; + } + + inline const heatSourceModel& heatSource() const + { + return heatSource_(); + } + + void update(); + + tmp qDot() const; + + void operator=(const movingHeatSource&) = delete; +}; + +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSourceModel/movingHeatSourceModel.C b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSources.C similarity index 68% rename from applications/solvers/additiveFoam/movingHeatSource/movingHeatSourceModel/movingHeatSourceModel.C rename to applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSources.C index 05b8c23d..c45623f9 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSourceModel/movingHeatSourceModel.C +++ b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSources.C @@ -25,13 +25,11 @@ License \*---------------------------------------------------------------------------*/ -#include "movingHeatSourceModel.H" -#include "DynamicList.H" -#include "OFstream.H" +#include "movingHeatSources.H" // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::movingHeatSourceModel::movingHeatSourceModel +Foam::movingHeatSources::movingHeatSources ( const fvMesh& mesh ) @@ -44,11 +42,10 @@ Foam::movingHeatSourceModel::movingHeatSourceModel "heatSourceDict", mesh_.time().constant(), mesh_, - IOobject::MUST_READ, + IOobject::MUST_READ_IF_MODIFIED, IOobject::NO_WRITE ) ), - sourceNames_(dict_.lookup("sources")), qDot_ ( IOobject @@ -62,37 +59,45 @@ Foam::movingHeatSourceModel::movingHeatSourceModel mesh_, dimensionedScalar(dimPower/dimVolume, 0.0) ), - refinementModel_(nullptr) + refinement_(nullptr) { - sources_.resize(sourceNames_.size()); + readSources(); +} + + +void Foam::movingHeatSources::readSources() +{ + const dictionary& sourcesDict = dict_.subDict("sources"); + const wordList names(sourcesDict.toc()); + sources_.clear(); + sources_.resize(names.size()); - //- Create new instance of movingBeam for each beam forAll(sources_, i) { - Info << "Adding heatSourceModel for " << sourceNames_[i] << endl; + Info << "Adding moving heat source " << names[i] << endl; sources_.set ( i, - heatSourceModel::New + new movingHeatSource ( - sourceNames_[i], - dict_, + names[i], + sourcesDict.subDict(names[i]), mesh_ - ).ptr() + ) ); } - refinementModel_ = refinementModel::New(sources_, dict_, mesh_); + refinement_ = refinementModel::New(sources_, dict_, mesh_); } // * * * * * * * * * * * * * * * Destructors * * * * * * * * * * * * * * * * // -Foam::movingHeatSourceModel::~movingHeatSourceModel() +Foam::movingHeatSources::~movingHeatSources() {} // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -void Foam::movingHeatSourceModel::adjustDeltaT(scalar& deltaT) +void Foam::movingHeatSources::adjustDeltaT(scalar& deltaT) { forAll(sources_, i) { @@ -100,29 +105,35 @@ void Foam::movingHeatSourceModel::adjustDeltaT(scalar& deltaT) } } -void Foam::movingHeatSourceModel::update() +void Foam::movingHeatSources::update() { - //- Subcycle each moving heat source in time and combine into a single field + if (dict_.readIfModified()) + { + readSources(); + } + qDot_ = dimensionedScalar("Zero", qDot_.dimensions(), 0.0); forAll(sources_, i) { if (sources_[i].beam().activePath()) { - sources_[i].updateDimensions(); + sources_[i].update(); - // integrate volumetric heat source over desired time step scalar pathTime = mesh_.time().value(); - const scalar nextTime = pathTime + mesh_.time().deltaTValue(); + const scalar deltaT = mesh_.time().deltaTValue(); + + const scalar nextTime = + min(pathTime + deltaT, sources_[i].beam().endTime()); - const scalar beam_dt = sources_[i].beam().deltaT(); + const scalar beamDeltaT = sources_[i].beam().deltaT(); - volScalarField qDoti + volScalarField sourceQDot ( IOobject ( - "qDoti", + "sourceQDot", mesh_.time().name(), mesh_ ), @@ -130,30 +141,26 @@ void Foam::movingHeatSourceModel::update() dimensionedScalar("Zero", qDot_.dimensions(), 0.0) ); - scalar sumWeights = 0.0; - while ((nextTime - pathTime) > small) { - scalar dt = min(beam_dt, max(0, nextTime - pathTime)); + scalar dt = min(beamDeltaT, max(0, nextTime - pathTime)); pathTime += dt; sources_[i].beam().move(pathTime); - qDoti += dt*sources_[i].qDot(); - - sumWeights += dt; + sourceQDot += dt*sources_[i].qDot(); } - qDoti /= sumWeights; + sourceQDot /= deltaT; - qDot_ += qDoti; + qDot_ += sourceQDot; } } qDot_.correctBoundaryConditions(); - refinementModel_->update(); + refinement_->update(); } // ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSourceModel/movingHeatSourceModel.H b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSources.H similarity index 83% rename from applications/solvers/additiveFoam/movingHeatSource/movingHeatSourceModel/movingHeatSourceModel.H rename to applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSources.H index 2e5e5b67..7f479857 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSourceModel/movingHeatSourceModel.H +++ b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/movingHeatSources.H @@ -24,34 +24,32 @@ License along with OpenFOAM. If not, see . Class - Foam::movingHeatSourceModel + Foam::movingHeatSources Description - Class for multiple moving beam heat sources + Aggregate of moving heat sources. SourceFiles - movingHeatSourceModel.C - calculateQDot.C + movingHeatSources.C \*---------------------------------------------------------------------------*/ -#ifndef movingHeatSourceModel_H -#define movingHeatSourceModel_H +#ifndef movingHeatSources_H +#define movingHeatSources_H // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#include "heatSourceModel.H" -#include "movingBeam.H" +#include "movingHeatSource.H" #include "refinementModel.H" namespace Foam { /*---------------------------------------------------------------------------*\ - Class movingHeatSourceModel Declaration + Class movingHeatSources Declaration \*---------------------------------------------------------------------------*/ -class movingHeatSourceModel +class movingHeatSources { private: @@ -63,30 +61,30 @@ private: //- Main movingHeatSourceDict IOdictionary dict_; - //- List of individual heat sources - wordList sourceNames_; - //- Total volumetric power of all beams volScalarField qDot_; //- Pointer list to each beam instance - PtrList sources_; + PtrList sources_; //- Pointer to refinement model - autoPtr refinementModel_; + autoPtr refinement_; + + //- Construct sources and refinement model from the dictionary + void readSources(); public: // Constructors // Construct from time and dictionary - movingHeatSourceModel + movingHeatSources ( const fvMesh& mesh ); //- Destructor - ~movingHeatSourceModel(); + ~movingHeatSources(); // Member Functions diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/referenceDimensions.C b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/referenceDimensions.C new file mode 100644 index 00000000..8adf3350 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/referenceDimensions.C @@ -0,0 +1,213 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory + \\/ M anipulation | +------------------------------------------------------------------------------- +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 "referenceDimensions.H" +#include "PstreamReduceOps.H" +#include "thermoPath.H" +#include "volFields.H" + +Foam::referenceDimensions::referenceDimensions +( + const dictionary& dict, + const fvMesh& mesh +) +: + mesh_(mesh), + widthReference_ + ( + dict.lookupOrDefault("widthReference", "D4Sigma") + ), + depthReference_ + ( + dict.lookupOrDefault("depthReference", "constant") + ), + component_(areaEquivalent), + isotherm_(0), + width_(0), + depth_(0) +{ + if (widthReference_ != "D4Sigma") + { + FatalIOErrorInFunction(dict) + << "widthReference must be D4Sigma, found " + << widthReference_ << exit(FatalIOError); + } + + const word D4Sigma + ( + dict.lookupOrDefault("D4Sigma", "areaEquivalent") + ); + + if (D4Sigma == "major") + { + component_ = major; + } + else if (D4Sigma == "minor") + { + component_ = minor; + } + else if (D4Sigma != "areaEquivalent") + { + FatalIOErrorInFunction(dict) + << "D4Sigma must be areaEquivalent, major, or minor, found " + << D4Sigma << exit(FatalIOError); + } + + if (depthReference_ == "isotherm") + { + isotherm_ = + dict.lookupOrDefault + ( + "isotherm", + thermoPath(mesh_).liquidus() + ); + } + else if (depthReference_ != "constant") + { + FatalIOErrorInFunction(dict) + << "depthReference must be constant or isotherm, found " + << depthReference_ << exit(FatalIOError); + } +} + + +void Foam::referenceDimensions::update +( + const profileMetrics& metrics, + const scalar depth, + const vector& position, + const boundBox& bounds +) +{ + const vector2D& D4Sigma = metrics.D4Sigma(); + + if (component_ == major) + { + width_ = D4Sigma.x(); + } + else if (component_ == minor) + { + width_ = D4Sigma.y(); + } + else + { + width_ = Foam::sqrt(D4Sigma.x()*D4Sigma.y()); + } + + if (depthReference_ == "constant") + { + depth_ = depth; + return; + } + + const volScalarField& T = mesh_.lookupObject("T"); + const labelUList& owner = mesh_.owner(); + const labelUList& neighbour = mesh_.neighbour(); + const volVectorField& cc = mesh_.C(); + depth_ = 0; + + for (label facei=0; facei= isotherm_ + ) + { + const vector p = + cc[own] + + (cc[nei] - cc[own]) + *(isotherm_ - T[own])/(T[nei] - T[own]) + - position; + + if + ( + p.x() >= bounds.min().x() + && p.x() <= bounds.max().x() + && p.y() >= bounds.min().y() + && p.y() <= bounds.max().y() + && p.z() <= 0 + ) + { + depth_ = max(depth_, -p.z()); + } + } + } + + const volScalarField::Boundary& TBf = T.boundaryField(); + + forAll(TBf, patchi) + { + const fvPatchScalarField& TPf = TBf[patchi]; + + if (!TPf.coupled()) + { + continue; + } + + const labelUList& faceCells = TPf.patch().faceCells(); + const vectorField ccn + ( + cc.boundaryField()[patchi].patchNeighbourField() + ); + const scalarField Tn(TPf.patchNeighbourField()); + + forAll(faceCells, facei) + { + const label own = faceCells[facei]; + + if + ( + min(T[own], Tn[facei]) < isotherm_ + && max(T[own], Tn[facei]) >= isotherm_ + ) + { + const vector p = + cc[own] + + (ccn[facei] - cc[own]) + *(isotherm_ - T[own])/(Tn[facei] - T[own]) + - position; + + if + ( + p.x() >= bounds.min().x() + && p.x() <= bounds.max().x() + && p.y() >= bounds.min().y() + && p.y() <= bounds.max().y() + && p.z() <= 0 + ) + { + depth_ = max(depth_, -p.z()); + } + } + } + } + + reduce(depth_, maxOp()); +} + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/referenceDimensions.H b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/referenceDimensions.H new file mode 100644 index 00000000..70f7bf52 --- /dev/null +++ b/applications/solvers/additiveFoam/movingHeatSource/movingHeatSources/referenceDimensions.H @@ -0,0 +1,96 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2026 Oak Ridge National Laboratory + \\/ M anipulation | +------------------------------------------------------------------------------- +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 referenceDimensions_H +#define referenceDimensions_H + +#include "boundBox.H" +#include "dictionary.H" +#include "fvMesh.H" +#include "profileMetrics.H" + +namespace Foam +{ + +class referenceDimensions +{ + enum D4SigmaComponent + { + areaEquivalent, + major, + minor + }; + + const fvMesh& mesh_; + + word widthReference_; + + word depthReference_; + + D4SigmaComponent component_; + + scalar isotherm_; + + scalar width_; + + scalar depth_; + +public: + + referenceDimensions(const dictionary& dict, const fvMesh& mesh); + + void update + ( + const profileMetrics& metrics, + const scalar depth, + const vector& position, + const boundBox& bounds + ); + + inline scalar width() const + { + return width_; + } + + inline scalar depth() const + { + return depth_; + } + + inline scalar aspectRatio() const + { + return 2.0*depth_/width_; + } + + inline bool isothermDepth() const + { + return depthReference_ == "isotherm"; + } +}; + +} // End namespace Foam + +#endif + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.C b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.C index 9a9403c3..e385050f 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.C +++ b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.C @@ -43,7 +43,7 @@ namespace refinementModels Foam::refinementModels::noRefinementModel::noRefinementModel ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ) diff --git a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.H b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.H index f95af438..686d56a2 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.H +++ b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/noRefinementModel/noRefinementModel.H @@ -24,13 +24,13 @@ License along with OpenFOAM. If not, see . Class - Foam::refinementModel::none + Foam::refinementModels::noRefinementModel Description No refinement. SourceFiles - none.C + noRefinementModel.C \*---------------------------------------------------------------------------*/ @@ -66,7 +66,7 @@ public: //- Default empty constructor noRefinementModel ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ); @@ -79,11 +79,9 @@ public: // Member Functions - //- Return true - virtual bool update() - { - return true; - } + //- Do nothing + virtual void update() + {} //- Return true virtual bool read() @@ -95,7 +93,7 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace refinementModel +} // End namespace refinementModels } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.C b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.C index 9dc7f4bf..5dfd4233 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.C +++ b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.C @@ -20,7 +20,7 @@ License FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the the GNU General Public License + You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ @@ -36,11 +36,6 @@ namespace Foam defineRunTimeSelectionTable(refinementModel, dictionary); } -const Foam::word Foam::refinementModel::refinementModelDictName -( - "refinementModelDict" -); - // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::IOobject Foam::refinementModel::createIOobject @@ -100,7 +95,7 @@ void Foam::refinementModel::readSourceBuffers() forAll(sources_, sourcei) { - buffersDict.lookup(sources_[sourcei].sourceName()) + buffersDict.lookup(sources_[sourcei].name()) >> sourceBuffers_[sourcei]; } } @@ -432,7 +427,7 @@ Foam::scalar Foam::refinementModel::minimumScanPathRefineVolume Foam::refinementModel::refinementModel ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ) @@ -441,8 +436,7 @@ Foam::refinementModel::refinementModel sources_(sources), mesh_(mesh), - heatSourceDict_(dict), - refinementDict_(heatSourceDict_.optionalSubDict("refinementModel")), + refinementDict_(dict.optionalSubDict("refinement")), maxRefinementLevel_(0), refinementTemperature_(GREAT), sourceBuffers_(sources.size(), vector::zero), @@ -466,7 +460,7 @@ Foam::refinementModel::refinementModel Foam::refinementModel::refinementModel ( const word& type, - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ) @@ -475,8 +469,7 @@ Foam::refinementModel::refinementModel sources_(sources), mesh_(mesh), - heatSourceDict_(dict), - refinementDict_(heatSourceDict_.subDict("refinementModel")), + refinementDict_(dict.subDict("refinement")), maxRefinementLevel_(readMaxRefinementLevel()), refinementTemperature_ ( @@ -513,7 +506,7 @@ Foam::refinementModel::refinementModel forAll(sources_, sourcei) { Info << "refinementModel: Refinement buffer for " - << sources_[sourcei].sourceName() << " " + << sources_[sourcei].name() << " " << sourceBuffers_[sourcei] << endl; } } @@ -763,7 +756,7 @@ bool Foam::refinementModel::read() { if (regIOobject::read()) { - refinementDict_ = optionalSubDict("refinementModel"); + refinementDict_ = optionalSubDict("refinement"); maxRefinementLevel_ = readMaxRefinementLevel(); diff --git a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.H b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.H index 842f923b..1ebead1a 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.H +++ b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModel.H @@ -20,7 +20,7 @@ License FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the the GNU General Public License + You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Class @@ -30,7 +30,7 @@ Description Base class for models that populate the refinementField used by the OpenFOAM dynamic mesh refiner. - If no refinementModel dictionary is present in heatSourceDict, the + If no refinement dictionary is present in heatSourceDict, the no-refinement model is selected and no AdditiveFOAM refinement controls are required. @@ -52,7 +52,7 @@ SourceFiles #include "volFields.H" #include "movingBeam.H" #include "treeBoundBox.H" -#include "heatSourceModel.H" +#include "movingHeatSource.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -124,15 +124,12 @@ protected: // Protected Data //- PtrList to heatSourceModels - const PtrList& sources_; + const PtrList& sources_; //- Pointer to mesh information const fvMesh& mesh_; - //- Main heat source dictionary - const dictionary& heatSourceDict_; - - //- Sub-dictionary for refinementModel entries + //- Refinement controls dictionary refinementDict_; //- Maximum dynamic-mesh refinement level @@ -180,9 +177,6 @@ public: //- Runtime type information TypeName("refinementModel"); - //- Default refinement model dictionary name - static const word refinementModelDictName; - // Declare run-time constructor selection table declareRunTimeSelectionTable ( @@ -190,7 +184,7 @@ public: refinementModel, dictionary, ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ), @@ -203,7 +197,7 @@ public: //- Construct inactive refinement model refinementModel ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ); @@ -212,7 +206,7 @@ public: refinementModel ( const word& type, - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ); @@ -226,7 +220,7 @@ public: //- Return a reference to the selected refinement model static autoPtr New ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ); @@ -270,7 +264,7 @@ public: } //- Update refinementField - virtual bool update() = 0; + virtual void update() = 0; //- Read the heat source dictionary virtual bool read() = 0; diff --git a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModelNew.C b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModelNew.C index 0c848e8c..cf97ceb8 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModelNew.C +++ b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/refinementModel/refinementModelNew.C @@ -31,22 +31,22 @@ License Foam::autoPtr Foam::refinementModel::New ( - const PtrList& sources, + const PtrList& sources, const dictionary& dict, const fvMesh& mesh ) { word modelType("none"); - if (dict.found("refinementModel")) + if (dict.found("refinement")) { const dictionary& refinementModelDict = - dict.subDict("refinementModel"); + dict.subDict("refinement"); modelType = refinementModelDict.lookupOrDefault ( - "refinementModel", + "model", "none" ); } diff --git a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/targetCellLoad/targetCellLoad.C b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/targetCellLoad/targetCellLoad.C index 083f9cbc..9a6b1ee5 100644 --- a/applications/solvers/additiveFoam/movingHeatSource/refinementModels/targetCellLoad/targetCellLoad.C +++ b/applications/solvers/additiveFoam/movingHeatSource/refinementModels/targetCellLoad/targetCellLoad.C @@ -20,7 +20,7 @@ License FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the the GNU General Public License + You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ @@ -47,39 +47,47 @@ namespace refinementModels // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -void Foam::refinementModels::targetCellLoad::readCoeffs() +void Foam::refinementModels::targetCellLoad::readControls() { targetCellsPerProc_ = - coeffs_.lookupOrDefault