lumpedPointMovement.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2016-2021 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
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
26Application
27 lumpedPointMovement
28
29Description
30 This utility can be used to produce VTK files to visualize the response
31 points/rotations and the corresponding movement of the building surfaces.
32
33 Uses the tabulated responses from the specified file.
34 Optionally, it can also be used to a dummy responder for the
35 externalFileCoupler logic, which makes it useful as a debugging facility
36 as well demonstrating how an external application could communicate
37 with the lumpedPointMovement point-patch boundary condition.
38
39\*---------------------------------------------------------------------------*/
40
41#include "argList.H"
42#include "Time.H"
43#include "OFstream.H"
44#include "foamVtkSeriesWriter.H"
45#include "lumpedPointTools.H"
47
48using namespace Foam;
49
50
51inline List<lumpedPointStateTuple> getResponseTable
52(
53 const fileName& file,
54 const lumpedPointState& state0
55)
56{
57 return lumpedPointTools::lumpedPointStates
58 (
59 file,
60 state0.rotationOrder(),
61 state0.degrees()
62 );
63}
64
65
66void echoTableLimits
67(
69 const label span,
70 const label maxOut
71)
72{
73 Info<< "Using response table with " << tbl.size() << " entries" << nl;
74
75 if (span)
76 {
77 Info<< "Increment input by " << span << nl;
78 }
79
80 if (maxOut)
81 {
82 Info<< "Stopping after " << maxOut << " outputs" << nl;
83 }
84}
85
86
87// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
88
89int main(int argc, char *argv[])
90{
91 argList::addNote
92 (
93 "Visualize lumpedPoint movements or provide a slave responder"
94 " for diagnostic purposes."
95 );
96
97 argList::noFunctionObjects(); // Never use function objects
98 argList::addOption
99 (
100 "max",
101 "N",
102 "Maximum number of outputs"
103 );
104 argList::addOption
105 (
106 "span",
107 "N",
108 "Increment each input by N (default: 1)"
109 );
110 argList::addOption
111 (
112 "scale",
113 "factor",
114 "Relaxation/scaling factor for movement (default: 1)"
115 );
116 argList::addOption
117 (
118 "visual-length",
119 "len",
120 "Visualization length for planes (visualized as triangles)"
121 );
122 argList::addDryRunOption
123 (
124 "Test movement without a mesh"
125 );
126 argList::addBoolOption
127 (
128 "removeLock",
129 "Remove lock-file on termination of slave"
130 );
131 argList::addBoolOption
132 (
133 "slave",
134 "Invoke as a slave responder for testing"
135 );
136 argList::addArgument("responseFile");
137
138 #include "setRootCase.H"
139
140 const label maxOut = Foam::max(0, args.getOrDefault<label>("max", 0));
141 const label span = Foam::max(1, args.getOrDefault<label>("span", 1));
142
143 // Control parameters
144 const bool dryrun = args.dryRun();
145 const bool slave = args.found("slave");
146 const bool removeLock = args.found("removeLock");
147
148 const scalar relax = args.getOrDefault<scalar>("scale", 1);
149
150 args.readIfPresent("visual-length", lumpedPointState::visLength);
151
152 const auto responseFile = args.get<fileName>(1);
153
154 // ----------------------------------------------------------------------
155 // Slave mode
156 // ----------------------------------------------------------------------
157
158 if (slave)
159 {
160 Info<< "Running as slave responder" << endl;
161
162 if (Pstream::parRun())
163 {
165 << "Running as slave responder is not permitted in parallel"
166 << nl
167 << exit(FatalError);
168 }
169
170 #include "createTime.H"
171
172 // Create movement without a mesh
174 lumpedPointIOMovement::New(runTime);
175
176 if (!movementPtr)
177 {
178 Info<< "No valid movement found" << endl;
179 return 1;
180 }
181 auto& movement = *movementPtr;
182
183 // Reference state0
184 const lumpedPointState& state0 = movement.state0();
185
186 List<lumpedPointStateTuple> responseTable =
187 getResponseTable(responseFile, state0);
188
189 echoTableLimits(responseTable, span, maxOut);
190
191 if (dryrun)
192 {
193 Info<< "dry-run: response table with " << responseTable.size()
194 << " entries" << nl
195 << "\nEnd\n" << endl;
196 return 0;
197 }
198
199 externalFileCoupler& coupler = movement.coupler();
200
201 for
202 (
203 label timei = 0, outputCount = 0;
204 timei < responseTable.size();
205 timei += span
206 )
207 {
208 Info<< args.executable() << ": waiting for master" << endl;
209
210 // Wait for master, but stop if status=done was seen
211 if (!coupler.waitForMaster())
212 {
214 << ": stopping status=done was detected" << endl;
215 break;
216 }
217
218 lumpedPointState state = responseTable[timei].second();
219 state.relax(relax, state0);
220
221 // Generate input for OpenFOAM
222 OFstream os(coupler.resolveFile(movement.inputName()));
223 if
224 (
225 movement.inputFormat()
226 == lumpedPointState::inputFormatType::PLAIN
227 )
228 {
229 state.writePlain(os);
230 }
231 else
232 {
233 os.writeEntry("time", responseTable[timei].first());
234 state.writeDict(os);
235 }
236
238 << ": updated to state " << timei
239 << " - switch to master"
240 << endl;
241
242 // Let OpenFOAM know that it can continue
243 coupler.useMaster();
244
245 ++outputCount;
246
247 if (maxOut && outputCount >= maxOut)
248 {
250 << ": stopping after " << maxOut << " outputs" << endl;
251 break;
252 }
253 }
254
255 if (removeLock)
256 {
257 Info<< args.executable() << ": removing lock file" << endl;
258 coupler.useSlave(); // This removes the lock-file
259 }
260
261 Info<< args.executable() << ": finishing" << nl;
262
263 Info<< "\nEnd\n" << endl;
264 return 0;
265 }
266
267
268 // ----------------------------------------------------------------------
269 // dry-run
270 // ----------------------------------------------------------------------
271
272 if (dryrun)
273 {
274 Info<< "dry-run: creating states only" << nl;
275
276 #include "createTime.H"
277
278 // Create movement without a mesh
280 lumpedPointIOMovement::New(runTime);
281
282 if (!movementPtr)
283 {
284 Info<< "No valid movement found" << endl;
285 return 1;
286 }
287 auto& movement = *movementPtr;
288
289 // Reference state0
290 const lumpedPointState& state0 = movement.state0();
291
292 List<lumpedPointStateTuple> responseTable =
293 getResponseTable(responseFile, state0);
294
295 echoTableLimits(responseTable, span, maxOut);
296
297
298 vtk::seriesWriter stateSeries;
299
300 for
301 (
302 label timei = 0, outputCount = 0;
303 timei < responseTable.size();
304 timei += span
305 )
306 {
307 lumpedPointState state = responseTable[timei].second();
308
309 state += movement.origin();
310 movement.scalePoints(state);
311 state.relax(relax, state0);
312
313 Info<< "output [" << timei << '/' << responseTable.size() << ']';
314
315 // State/response = what comes back from FEM
316 {
317 const word outputName =
318 word::printf("state_%06d.vtp", outputCount);
319
320 Info<< " " << outputName;
321
322 movement.writeStateVTP(state, outputName);
323 stateSeries.append(outputCount, outputName);
324 }
325
326 Info<< endl;
327
328 ++outputCount;
329
330 if (maxOut && outputCount >= maxOut)
331 {
332 Info<< "Max output " << maxOut << " ... stopping" << endl;
333 break;
334 }
335 }
336
337 // Write file series
338
339 if (stateSeries.size())
340 {
341 Info<< nl << "write state.vtp.series" << nl;
342 stateSeries.write("state.vtp");
343 }
344
345 Info<< "\nEnd\n" << endl;
346 return 0;
347 }
348
349
350 // ----------------------------------------------------------------------
351 // test patch movement
352 // ----------------------------------------------------------------------
353
354 #include "createTime.H"
355
356 runTime.setTime(instant(runTime.constant()), 0);
357
358 #include "createNamedMesh.H"
359
360 // Create movement with mesh
362 lumpedPointIOMovement::New(mesh);
363
364 if (!movementPtr)
365 {
366 Info<< "No valid movement found" << endl;
367 return 1;
368 }
369 auto& movement = *movementPtr;
370
371 // Reference state0
372 const lumpedPointState& state0 = movement.state0();
373
374 List<lumpedPointStateTuple> responseTable =
375 getResponseTable(responseFile, state0);
376
377 echoTableLimits(responseTable, span, maxOut);
378
379 pointIOField points0(lumpedPointTools::points0Field(mesh));
380
381 const label nPatches = lumpedPointTools::setPatchControls(mesh, points0);
382 if (!nPatches)
383 {
384 Info<< "No point patches with lumped movement found" << endl;
385 return 2;
386 }
387
388 Info<< "Lumped point patch controls set on "
389 << nPatches << " patches" << nl;
390
391 lumpedPointTools::setInterpolators(mesh, points0);
392
393
394 // Output vtk file series
395 vtk::seriesWriter stateSeries;
396 vtk::seriesWriter geomSeries;
397
398 // Initial geometry
399 movement.writeVTP("geom_init.vtp", state0, mesh, points0);
400
401 lumpedPointTools::setInterpolators(mesh);
402
403 for
404 (
405 label timei = 0, outputCount = 0;
406 timei < responseTable.size();
407 timei += span
408 )
409 {
410 lumpedPointState state = responseTable[timei].second();
411
412 state += movement.origin();
413 movement.scalePoints(state);
414 state.relax(relax, state0);
415
416 Info<< "output [" << timei << '/' << responseTable.size() << ']';
417
418 // State/response = what comes back from FEM
419 {
420 const word outputName =
421 word::printf("state_%06d.vtp", outputCount);
422
423 Info<< " " << outputName;
424
425 movement.writeStateVTP(state, outputName);
426 stateSeries.append(outputCount, outputName);
427 }
428
429 {
430 const word outputName =
431 word::printf("geom_%06d.vtp", outputCount);
432
433 Info<< " " << outputName;
434
435 movement.writeVTP(outputName, state, mesh, points0);
436 geomSeries.append(outputCount, outputName);
437 }
438
439 Info<< endl;
440
441 ++outputCount;
442
443 if (maxOut && outputCount >= maxOut)
444 {
445 Info<< "Max output " << maxOut << " ... stopping" << endl;
446 break;
447 }
448 }
449
450
451 // Write file series
452
453 if (geomSeries.size())
454 {
455 Info<< nl << "write geom.vtp.series" << nl;
456 geomSeries.write("geom.vtp");
457 }
458 if (stateSeries.size())
459 {
460 Info<< nl << "write state.vtp.series" << nl;
461 stateSeries.write("state.vtp");
462 }
463
464 Info<< "\nEnd\n" << endl;
465
466 return 0;
467}
468
469
470// ************************************************************************* //
A primitive field of type <T> with automated input and output.
Definition: IOField.H:58
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
Output to file stream, using an OSstream.
Definition: OFstream.H:57
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:278
int dryRun() const noexcept
Return the dry-run flag.
Definition: argListI.H:116
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:178
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:323
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:307
const word & executable() const noexcept
Name of executable without the path.
Definition: argListI.H:51
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
Encapsulates the logic for coordinating between OpenFOAM and an external application.
enum Time::stopAtControls useSlave(const bool wait=false) const
Remove lock file to indicate that the external program is in charge.
enum Time::stopAtControls useMaster(const bool wait=false) const
Create lock file to indicate that OpenFOAM is in charge.
fileName resolveFile(const word &file) const
Return the file path in the communications directory.
enum Time::stopAtControls waitForMaster() const
Wait for master to complete.
A class for handling file names.
Definition: fileName.H:76
An instant of time. Contains the time value and name. Uses Foam::Time when formatting the name.
Definition: instant.H:56
The state of lumped points corresponds to positions and rotations.
void writePlain(Ostream &os) const
Output as plain content.
bool degrees() const
Rotation angles in degrees.
void relax(const scalar alpha, const lumpedPointState &prev)
Relax the state.
quaternion::eulerOrder rotationOrder() const
The Euler-angle rotation order.
void writeDict(Ostream &os) const
Output as dictionary content.
void scalePoints(const scalar scaleFactor)
Scale points by given factor.
Provides a means of accumulating and generating VTK file series.
bool append(const fileNameInstant &inst)
Append the specified file instant.
label size() const noexcept
The number of data sets.
static void write(const fileName &base, const UList< instant > &series, const char sep='_')
Write file series (JSON format) to disk, for specified instances.
A class for handling words, derived from Foam::string.
Definition: word.H:68
UEqn relax()
dynamicFvMesh & mesh
engineTime & runTime
Required Variables.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
word outputName("finiteArea-edges.obj")
OBJstream os(runTime.globalPath()/outputName)
const label nPatches
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
Foam::argList args(argc, argv)
pointField points0(pointIOField(IOobject("points", mesh.time().constant(), polyMesh::meshSubDir, mesh, IOobject::MUST_READ, IOobject::NO_WRITE, false)))