Skip to content

Commit cb209d5

Browse files
colemanjsgknapp1
andauthored
Melt pool dimensions (#77)
add function object for tracking melt pool dimensions provided a list of isotherms and a scan path angle --------- Co-authored-by: Gerry Knapp <knappgl@ornl.gov>
1 parent a7f2a78 commit cb209d5

9 files changed

Lines changed: 481 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
ExaCA/ExaCA.C
22
solidificationData/solidificationData.C
3+
meltPoolDimensions/meltPoolDimensions.C
34

45
LIB = $(FOAM_USER_LIBBIN)/libadditiveFoamFunctionObjects
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
/*---------------------------------------------------------------------------*\
2+
========= |
3+
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4+
\\ / O peration | Website: https://openfoam.org
5+
\\ / A nd | Copyright (C) 2024 OpenFOAM Foundation
6+
\\/ M anipulation |
7+
-------------------------------------------------------------------------------
8+
Copyright (C) 2023 Oak Ridge National Laboratory
9+
-------------------------------------------------------------------------------
10+
License
11+
This file is part of OpenFOAM.
12+
13+
OpenFOAM is free software: you can redistribute it and/or modify it
14+
under the terms of the GNU General Public License as published by
15+
the Free Software Foundation, either version 3 of the License, or
16+
(at your option) any later version.
17+
18+
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21+
for more details.
22+
23+
You should have received a copy of the GNU General Public License
24+
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25+
26+
\*---------------------------------------------------------------------------*/
27+
28+
#include "meltPoolDimensions.H"
29+
#include "Time.H"
30+
#include "fvMesh.H"
31+
#include "addToRunTimeSelectionTable.H"
32+
#include "volFields.H"
33+
#include "fvc.H"
34+
#include "OSspecific.H"
35+
#include "labelVector.H"
36+
37+
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38+
39+
namespace Foam
40+
{
41+
namespace functionObjects
42+
{
43+
defineTypeNameAndDebug(meltPoolDimensions, 0);
44+
45+
addToRunTimeSelectionTable
46+
(
47+
functionObject,
48+
meltPoolDimensions,
49+
dictionary
50+
);
51+
}
52+
}
53+
54+
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
55+
56+
Foam::functionObjects::meltPoolDimensions::meltPoolDimensions
57+
(
58+
const word& name,
59+
const Time& runTime,
60+
const dictionary& dict
61+
)
62+
:
63+
fvMeshFunctionObject(name, runTime, dict),
64+
T_(mesh_.lookupObject<VolField<scalar>>("T"))
65+
{
66+
read(dict);
67+
68+
if (Pstream::master())
69+
{
70+
const fileName probeDir
71+
(
72+
mesh_.time().rootPath()/mesh_.time().globalCaseName()
73+
/"postProcessing"/"meltPoolDimensions"
74+
);
75+
76+
mkDir(probeDir);
77+
78+
logFilePtrs_.setSize(isoValues_.size());
79+
80+
forAll(isoValues_, i)
81+
{
82+
const fileName logFileName
83+
(
84+
probeDir/Foam::name(isoValues_[i]) + ".csv"
85+
);
86+
87+
Info<< "melt pool dimensions log file name: "
88+
<< logFileName << endl;
89+
90+
logFilePtrs_.set
91+
(
92+
i,
93+
new OFstream(logFileName)
94+
);
95+
96+
logFilePtrs_[i] << "time(s),length(m),width(m),depth(m)" << endl;
97+
}
98+
}
99+
}
100+
101+
102+
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
103+
104+
Foam::functionObjects::meltPoolDimensions::~meltPoolDimensions()
105+
{}
106+
107+
108+
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
109+
110+
bool Foam::functionObjects::meltPoolDimensions::read(const dictionary& dict)
111+
{
112+
isoValues_ = dict.lookup<scalarList>("isoValues");
113+
scanPathAngle_ = dict.lookupOrDefault<scalar>("scanPathAngle", 0.0);
114+
115+
return true;
116+
}
117+
118+
Foam::wordList Foam::functionObjects::meltPoolDimensions::fields() const
119+
{
120+
return wordList::null();
121+
}
122+
123+
bool Foam::functionObjects::meltPoolDimensions::execute()
124+
{
125+
const labelUList& owner = mesh_.owner();
126+
const labelUList& neighbour = mesh_.neighbour();
127+
128+
const volVectorField& cc = mesh_.C();
129+
130+
const scalar radians =
131+
scanPathAngle_ * ( Foam::constant::mathematical::pi / 180.0 );
132+
133+
const scalar s = sin(radians);
134+
const scalar c = cos(radians);
135+
136+
List<treeBoundBox> boundBoxes
137+
(
138+
isoValues_.size(),
139+
treeBoundBox(point::max, point::min)
140+
);
141+
142+
// check internal faces
143+
for(label facei=0; facei < mesh_.nInternalFaces(); facei++)
144+
{
145+
const label own = owner[facei];
146+
const label nei = neighbour[facei];
147+
148+
scalar minFace = min(T_[own], T_[nei]);
149+
scalar maxFace = max(T_[own], T_[nei]);
150+
151+
forAll(isoValues_, i)
152+
{
153+
const scalar iso_ = isoValues_[i];
154+
155+
// update the bounding box
156+
if ((minFace < iso_) && (maxFace >= iso_))
157+
{
158+
vector d = cc[nei] - cc[own];
159+
160+
vector p =
161+
cc[own] + d*(iso_ - T_[own])/(T_[nei] - T_[own]);
162+
163+
vector p_rotated
164+
(
165+
p.x() * c + p.y() * s,
166+
p.y() * c - p.x() * s,
167+
p.z()
168+
);
169+
170+
boundBoxes[i].min() =
171+
min(p_rotated, boundBoxes[i].min());
172+
173+
boundBoxes[i].max() =
174+
max(p_rotated, boundBoxes[i].max());
175+
}
176+
}
177+
}
178+
179+
// check boundary faces
180+
const volScalarField::Boundary& TBf = T_.boundaryField();
181+
182+
forAll(TBf, patchi)
183+
{
184+
const fvPatchScalarField& TPf = TBf[patchi];
185+
186+
const labelUList& faceCells = TPf.patch().faceCells();
187+
188+
if (TPf.coupled())
189+
{
190+
// processor boundary : interpolate across face
191+
const vectorField ccn
192+
(
193+
cc.boundaryField()[patchi].patchNeighbourField()
194+
);
195+
196+
const scalarField fn(TPf.patchNeighbourField());
197+
198+
forAll(faceCells, facei)
199+
{
200+
label own = faceCells[facei];
201+
202+
scalar minFace = min(T_[own], fn[facei]);
203+
scalar maxFace = max(T_[own], fn[facei]);
204+
205+
206+
forAll(isoValues_, i)
207+
{
208+
const scalar iso_ = isoValues_[i];
209+
210+
// update the bounding box
211+
if ((minFace < iso_) && (maxFace >= iso_))
212+
{
213+
vector d = ccn[facei] - cc[own];
214+
215+
vector p =
216+
cc[own] + d*(iso_ - T_[own])/(fn[facei] - T_[own]);
217+
218+
vector p_rotated
219+
(
220+
p.x() * c + p.y() * s,
221+
p.y() * c - p.x() * s,
222+
p.z()
223+
);
224+
225+
boundBoxes[i].min() =
226+
min(p_rotated, boundBoxes[i].min());
227+
228+
boundBoxes[i].max() =
229+
max(p_rotated, boundBoxes[i].max());
230+
}
231+
}
232+
}
233+
}
234+
else
235+
{
236+
// physical boundary : take face point if above iso value
237+
const vectorField& Cf = mesh_.Cf().boundaryField()[patchi];
238+
239+
const scalarField& pif(TPf.patchInternalField());
240+
241+
forAll(faceCells, facei)
242+
{
243+
scalar maxFace = max(pif[facei], TPf[facei]);
244+
245+
forAll(isoValues_, i)
246+
{
247+
const scalar iso_ = isoValues_[i];
248+
249+
if (maxFace >= iso_)
250+
{
251+
const vector& p = Cf[facei];
252+
253+
vector p_rotated
254+
(
255+
p.x() * c + p.y() * s,
256+
p.y() * c - p.x() * s,
257+
p.z()
258+
);
259+
260+
boundBoxes[i].min() =
261+
min(p_rotated, boundBoxes[i].min());
262+
263+
boundBoxes[i].max() =
264+
max(p_rotated, boundBoxes[i].max());
265+
}
266+
}
267+
}
268+
}
269+
}
270+
271+
forAll(isoValues_, i)
272+
{
273+
reduce(boundBoxes[i].min(), minOp<point>());
274+
reduce(boundBoxes[i].max(), maxOp<point>());
275+
}
276+
277+
// update the melt pool dimensions log files
278+
if (Pstream::master())
279+
{
280+
forAll(isoValues_, i)
281+
{
282+
vector dimensions = max(boundBoxes[i].span(), vector::zero);
283+
284+
OFstream& logFile = logFilePtrs_[i];
285+
286+
logFile<< mesh_.time().value() << ","
287+
<< dimensions.x() << ","
288+
<< dimensions.y() << ","
289+
<< dimensions.z() << endl;
290+
}
291+
}
292+
293+
return true;
294+
}
295+
296+
bool Foam::functionObjects::meltPoolDimensions::end()
297+
{
298+
return true;
299+
}
300+
301+
302+
bool Foam::functionObjects::meltPoolDimensions::write()
303+
{
304+
return true;
305+
}
306+
307+
308+
// ************************************************************************* //

0 commit comments

Comments
 (0)