diff --git a/applications/solvers/additiveFoam/functionObjects/Make/files b/applications/solvers/additiveFoam/functionObjects/Make/files index 194ab9e..b513dbe 100644 --- a/applications/solvers/additiveFoam/functionObjects/Make/files +++ b/applications/solvers/additiveFoam/functionObjects/Make/files @@ -1,4 +1,5 @@ ExaCA/ExaCA.C solidificationData/solidificationData.C +meltPoolDimensions/meltPoolDimensions.C LIB = $(FOAM_USER_LIBBIN)/libadditiveFoamFunctionObjects diff --git a/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C new file mode 100644 index 0000000..c29fded --- /dev/null +++ b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.C @@ -0,0 +1,308 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2024 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023 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 "meltPoolDimensions.H" +#include "Time.H" +#include "fvMesh.H" +#include "addToRunTimeSelectionTable.H" +#include "volFields.H" +#include "fvc.H" +#include "OSspecific.H" +#include "labelVector.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + defineTypeNameAndDebug(meltPoolDimensions, 0); + + addToRunTimeSelectionTable + ( + functionObject, + meltPoolDimensions, + dictionary + ); +} +} + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::meltPoolDimensions::meltPoolDimensions +( + const word& name, + const Time& runTime, + const dictionary& dict +) +: + fvMeshFunctionObject(name, runTime, dict), + T_(mesh_.lookupObject>("T")) +{ + read(dict); + + if (Pstream::master()) + { + const fileName probeDir + ( + mesh_.time().rootPath()/mesh_.time().globalCaseName() + /"postProcessing"/"meltPoolDimensions" + ); + + mkDir(probeDir); + + logFilePtrs_.setSize(isoValues_.size()); + + forAll(isoValues_, i) + { + const fileName logFileName + ( + probeDir/Foam::name(isoValues_[i]) + ".csv" + ); + + Info<< "melt pool dimensions log file name: " + << logFileName << endl; + + logFilePtrs_.set + ( + i, + new OFstream(logFileName) + ); + + logFilePtrs_[i] << "time(s),length(m),width(m),depth(m)" << endl; + } + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::functionObjects::meltPoolDimensions::~meltPoolDimensions() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::functionObjects::meltPoolDimensions::read(const dictionary& dict) +{ + isoValues_ = dict.lookup("isoValues"); + scanPathAngle_ = dict.lookupOrDefault("scanPathAngle", 0.0); + + return true; +} + +Foam::wordList Foam::functionObjects::meltPoolDimensions::fields() const +{ + return wordList::null(); +} + +bool Foam::functionObjects::meltPoolDimensions::execute() +{ + const labelUList& owner = mesh_.owner(); + const labelUList& neighbour = mesh_.neighbour(); + + const volVectorField& cc = mesh_.C(); + + const scalar radians = + scanPathAngle_ * ( Foam::constant::mathematical::pi / 180.0 ); + + const scalar s = sin(radians); + const scalar c = cos(radians); + + List boundBoxes + ( + isoValues_.size(), + treeBoundBox(point::max, point::min) + ); + + // check internal 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]); + + forAll(isoValues_, i) + { + const scalar iso_ = isoValues_[i]; + + // update the bounding box + if ((minFace < iso_) && (maxFace >= iso_)) + { + vector d = cc[nei] - cc[own]; + + vector p = + cc[own] + d*(iso_ - T_[own])/(T_[nei] - T_[own]); + + vector p_rotated + ( + p.x() * c + p.y() * s, + p.y() * c - p.x() * s, + p.z() + ); + + boundBoxes[i].min() = + min(p_rotated, boundBoxes[i].min()); + + boundBoxes[i].max() = + max(p_rotated, boundBoxes[i].max()); + } + } + } + + // check boundary faces + const volScalarField::Boundary& TBf = T_.boundaryField(); + + forAll(TBf, patchi) + { + const fvPatchScalarField& TPf = TBf[patchi]; + + const labelUList& faceCells = TPf.patch().faceCells(); + + if (TPf.coupled()) + { + // processor boundary : interpolate across face + const vectorField ccn + ( + cc.boundaryField()[patchi].patchNeighbourField() + ); + + const scalarField fn(TPf.patchNeighbourField()); + + forAll(faceCells, facei) + { + label own = faceCells[facei]; + + scalar minFace = min(T_[own], fn[facei]); + scalar maxFace = max(T_[own], fn[facei]); + + + forAll(isoValues_, i) + { + const scalar iso_ = isoValues_[i]; + + // update the bounding box + if ((minFace < iso_) && (maxFace >= iso_)) + { + vector d = ccn[facei] - cc[own]; + + vector p = + cc[own] + d*(iso_ - T_[own])/(fn[facei] - T_[own]); + + vector p_rotated + ( + p.x() * c + p.y() * s, + p.y() * c - p.x() * s, + p.z() + ); + + boundBoxes[i].min() = + min(p_rotated, boundBoxes[i].min()); + + boundBoxes[i].max() = + max(p_rotated, boundBoxes[i].max()); + } + } + } + } + else + { + // physical boundary : take face point if above iso value + const vectorField& Cf = mesh_.Cf().boundaryField()[patchi]; + + const scalarField& pif(TPf.patchInternalField()); + + forAll(faceCells, facei) + { + scalar maxFace = max(pif[facei], TPf[facei]); + + forAll(isoValues_, i) + { + const scalar iso_ = isoValues_[i]; + + if (maxFace >= iso_) + { + const vector& p = Cf[facei]; + + vector p_rotated + ( + p.x() * c + p.y() * s, + p.y() * c - p.x() * s, + p.z() + ); + + boundBoxes[i].min() = + min(p_rotated, boundBoxes[i].min()); + + boundBoxes[i].max() = + max(p_rotated, boundBoxes[i].max()); + } + } + } + } + } + + forAll(isoValues_, i) + { + reduce(boundBoxes[i].min(), minOp()); + reduce(boundBoxes[i].max(), maxOp()); + } + + // update the melt pool dimensions log files + if (Pstream::master()) + { + forAll(isoValues_, i) + { + vector dimensions = max(boundBoxes[i].span(), vector::zero); + + OFstream& logFile = logFilePtrs_[i]; + + logFile<< mesh_.time().value() << "," + << dimensions.x() << "," + << dimensions.y() << "," + << dimensions.z() << endl; + } + } + + return true; +} + +bool Foam::functionObjects::meltPoolDimensions::end() +{ + return true; +} + + +bool Foam::functionObjects::meltPoolDimensions::write() +{ + return true; +} + + +// ************************************************************************* // diff --git a/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.H b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.H new file mode 100644 index 0000000..320b18f --- /dev/null +++ b/applications/solvers/additiveFoam/functionObjects/meltPoolDimensions/meltPoolDimensions.H @@ -0,0 +1,125 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2024 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023 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::functionObjects::meltPoolDimensions + +SourceFiles + meltPoolDimensions.C + +\*---------------------------------------------------------------------------*/ + +#ifndef meltPoolDimensions_H +#define meltPoolDimensions_H + +#include "fvMeshFunctionObject.H" +#include "volFields.H" +#include "OFstream.H" +#include "PtrList.H" +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + +/*---------------------------------------------------------------------------*\ + Class meltPoolDimensions Declaration +\*---------------------------------------------------------------------------*/ + +class meltPoolDimensions +: + public fvMeshFunctionObject +{ + // Private Data + + const volScalarField& T_; + scalarList isoValues_; + scalar scanPathAngle_; + + PtrList logFilePtrs_; + + // Private Member Functions + + +public: + + //- Runtime type information + TypeName("meltPoolDimensions"); + + + // Constructors + + //- Construct from Time and dictionary + meltPoolDimensions + ( + const word& name, + const Time& runTime, + const dictionary& dict + ); + + //- Disallow default bitwise copy construction + meltPoolDimensions(const meltPoolDimensions&) = delete; + + + //- Destructor + virtual ~meltPoolDimensions(); + + + // Member Functions + + //- Read the meltPoolDimensions data + virtual bool read(const dictionary&); + + //- Return the list of fields required + virtual wordList fields() const; + + //- Execute, currently does nothing + virtual bool execute(); + + //- Execute at the final time-loop + virtual bool end(); + + //- Write the meltPoolDimensions data + virtual bool write(); + + + // Member Operators + + //- Disallow default bitwise assignment + void operator=(const meltPoolDimensions&) = delete; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/tutorials/AMB2018-02-B/Allrun b/tutorials/AMB2018-02-B/Allrun index 9761b16..9052aa2 100755 --- a/tutorials/AMB2018-02-B/Allrun +++ b/tutorials/AMB2018-02-B/Allrun @@ -25,6 +25,9 @@ done # solidificationData (optional - default: false) #export ENABLE_SOLIDIFICATION_DATA=true +# meltPoolDimensions (optional - default: false) +#export ENABLE_MELTPOOL_DIMENSIONS=true + # Enable ExaCA function object for '-withExaCA' flag if [ "$withExaCA" = true ]; then export ENABLE_EXACA_DATA=true diff --git a/tutorials/AMB2018-02-B/system/controlDict b/tutorials/AMB2018-02-B/system/controlDict index 8ac7666..4e8669c 100644 --- a/tutorials/AMB2018-02-B/system/controlDict +++ b/tutorials/AMB2018-02-B/system/controlDict @@ -79,6 +79,18 @@ functions isoValue 1620; } #endif; + + #ifeq ${ENABLE_MELTPOOL_DIMENSIONS} true + meltPoolDimensions + { + libs ("libadditiveFoamFunctionObjects.so"); + + type meltPoolDimensions; + + isoValues (1620 1410); + scanPathAngle 0.0; + } + #endif; } // ************************************************************************* // diff --git a/tutorials/multiBeam/Allrun b/tutorials/multiBeam/Allrun index 9761b16..9052aa2 100755 --- a/tutorials/multiBeam/Allrun +++ b/tutorials/multiBeam/Allrun @@ -25,6 +25,9 @@ done # solidificationData (optional - default: false) #export ENABLE_SOLIDIFICATION_DATA=true +# meltPoolDimensions (optional - default: false) +#export ENABLE_MELTPOOL_DIMENSIONS=true + # Enable ExaCA function object for '-withExaCA' flag if [ "$withExaCA" = true ]; then export ENABLE_EXACA_DATA=true diff --git a/tutorials/multiBeam/system/controlDict b/tutorials/multiBeam/system/controlDict index 066c37d..d02773e 100644 --- a/tutorials/multiBeam/system/controlDict +++ b/tutorials/multiBeam/system/controlDict @@ -79,6 +79,19 @@ functions isoValue 1620; } #endif; + + + #ifeq ${ENABLE_MELTPOOL_DIMENSIONS} true + meltPoolDimensions + { + libs ("libadditiveFoamFunctionObjects.so"); + + type meltPoolDimensions; + + isoValues (1620 1410); + scanPathAngle 0.0; + } + #endif; } // ************************************************************************* // diff --git a/tutorials/multiLayerPBF/Allrun b/tutorials/multiLayerPBF/Allrun index 798db48..3f3a596 100755 --- a/tutorials/multiLayerPBF/Allrun +++ b/tutorials/multiLayerPBF/Allrun @@ -25,6 +25,9 @@ done # solidificationData (optional - default: false) #export ENABLE_SOLIDIFICATION_DATA=true +# meltPoolDimensions (optional - default: false) +#export ENABLE_MELTPOOL_DIMENSIONS=true + # Enable ExaCA function object for '-withExaCA' flag if [ "$withExaCA" = true ]; then export ENABLE_EXACA_DATA=true diff --git a/tutorials/multiLayerPBF/system/controlDict b/tutorials/multiLayerPBF/system/controlDict index 37c566a..3039905 100644 --- a/tutorials/multiLayerPBF/system/controlDict +++ b/tutorials/multiLayerPBF/system/controlDict @@ -79,6 +79,19 @@ functions isoValue 1620; } #endif; + + + #ifeq ${ENABLE_MELTPOOL_DIMENSIONS} true + meltPoolDimensions + { + libs ("libadditiveFoamFunctionObjects.so"); + + type meltPoolDimensions; + + isoValues (1620 1410); + scanPathAngle 0.0; + } + #endif; } // ************************************************************************* //