immersed_rigid_body_elements.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26// Non-inline functions for Rigid Body Elements
28
29namespace oomph
30{
31 /// Static default value for physical constants
32 /// Zero gives instantaneous force and torque balances --- no solid intertia
34
35 /// Static default value for physical ratio
37
38 /// Static default gravity direction vector
40
41 //=======================================================================
42 /// Work out the position derivative taking into account the movement
43 /// relative to the original centre of mass
44 //======================================================================
46 const unsigned& j,
48 {
49 // Switch on time level
50 switch (j)
51 {
52 // Current time, just return the position
53 case 0:
54 return position(zeta, drdt);
55 break;
56
57 // Time derivative
58 case 1:
59 {
60 // Get the initial position of the underlying geometric object
63 // Scale relative to the centre of mass
64 double X = initial_x[0] - Initial_centre_of_mass[0];
65 double Y = initial_x[1] - Initial_centre_of_mass[1];
66
67 // Now calculate the original angle and radius
68 double phi_orig = atan2(Y, X);
69 double r_orig = sqrt(X * X + Y * Y);
70
71 // Get first time derivatives of all displacement data
72 Vector<double> veloc(3);
73 // Get the velocity of the data
75 1, this->Centre_displacement_data_pt, veloc);
76
77 // Now use the chain rule to specify the boundary velocities
78 drdt[0] = veloc[0];
79 drdt[1] = veloc[1];
80
82 {
83 drdt[0] +=
84 -r_orig *
86 veloc[2];
87 drdt[1] +=
88 r_orig *
90 veloc[2];
91 }
92 }
93 // Done
94 return;
95 break;
96
97 default:
98 std::ostringstream warning_stream;
100 << "Using default (static) assignment " << j
101 << "-th time derivative in GeomObject::dposition_dt(...) is zero\n"
102 << "Overload for your specific geometric object if this is not \n"
103 << "appropriate. \n";
105 "GeomObject::dposition_dt()",
107
108 unsigned n = drdt.size();
109 for (unsigned i = 0; i < n; i++)
110 {
111 drdt[i] = 0.0;
112 }
113 break;
114 }
115 }
116
117 //=======================================================================
118 /// Output the position of the centre of gravity including velocities
119 /// and accelerations
120 //======================================================================
122 {
123 // Get timestepper
126
127 // Get first time derivatives of all displacement data
128 Vector<double> veloc(3);
130 1, this->Centre_displacement_data_pt, veloc);
131
132 // Get second time derivatives of all displacement data
133 Vector<double> accel(3);
135 2, this->Centre_displacement_data_pt, accel);
136
137 outfile << time_stepper_pt->time() << " "
140 << " "
143 << " " << Initial_Phi + this->Centre_displacement_data_pt->value(2)
144 << " " << veloc[0] << " " << veloc[1] << " " << veloc[2] << " "
145 << accel[0] << " " << accel[1] << " " << accel[2] << std::endl;
146 }
147
148
149 //======================================================================
150 /// Obtain the external force and torque on the body from specified
151 /// function pointers and also from a drag mesh, if there is one
152 //=====================================================================
155 double& torque)
156 {
157 // Get external force
158 if (External_force_fct_pt == 0)
159 {
160 force[0] = 0.0;
161 force[1] = 0.0;
162 }
163 else
164 {
166 }
167
168 // Get external torque
169 if (External_torque_fct_pt == 0)
170 {
171 torque = 0.0;
172 }
173 else
174 {
176 }
177
178 // Add drag from any (fluid) mesh attached to surface of body
181 if (Drag_mesh_pt == 0)
182 {
183 return;
184 }
185 else
186 {
187 unsigned nel = Drag_mesh_pt->nelement();
188
189 for (unsigned e = 0; e < nel; e++)
190 {
192 ->get_drag_and_torque(element_drag_force, element_drag_torque);
193 force[0] += element_drag_force[0];
194 force[1] += element_drag_force[1];
196 }
197 }
198 }
199
200 //=======================================================================
201 /// Set the external drag mesh, which should consist of
202 /// NavierStokesSurfaceDragTorqueElements and then read out the
203 /// appropriate load and geometric data from those elements and set
204 /// as external data for this element.
205 //=======================================================================
207 {
208 // Delete the external hijacked data
210 // Flush any existing external data
211 this->flush_external_data();
212 // Set the pointer
214
215 // Allocate storage for all geometric data in the mesh
216 std::set<Data*> bulk_geometric_data_pt;
217 // Allocate storage for all load data in the mesh
218 std::set<std::pair<Data*, unsigned>> bulk_load_data_pt;
219
220 // Loop over all elements in the drag mesh
221 const unsigned n_element = drag_mesh_pt->nelement();
222 for (unsigned e = 0; e < n_element; ++e)
223 {
224 // Cast the bulk element associated with each FaceElement to
225 // an FSIFluidElement
227 dynamic_cast<FaceElement*>(drag_mesh_pt->element_pt(e))
228 ->bulk_element_pt());
229 // Check that the cast worked
230 if (bulk_elem_pt == 0)
231 {
232 throw OomphLibError("Drag mesh must consist of FSIFluidElements\n",
235 }
236
237 // Add the geometric and load data from the bulk element to the
238 // set allocated above
240 bulk_elem_pt->identify_load_data(bulk_load_data_pt);
241 }
242
243 // Need to add all these data as external data to this (Rigid Body) object
244 for (std::set<Data*>::iterator it = bulk_geometric_data_pt.begin();
245 it != bulk_geometric_data_pt.end();
246 ++it)
247 {
248 this->add_external_data(*it);
249 }
250
251 // Now do the same but make custom data for the load data
252 for (std::set<std::pair<Data*, unsigned>>::iterator it =
253 bulk_load_data_pt.begin();
254 it != bulk_load_data_pt.end();
255 ++it)
256 {
257 Data* temp_data_pt = new HijackedData(it->second, it->first);
259 this->add_external_data(temp_data_pt));
260 }
261 }
262
263 //======================================================================
264 /// Initialise the internal data
265 //=====================================================================
267 {
268 // This could be calculated by an integral around the boundary
269 Initial_centre_of_mass.resize(2, 0.0);
270
271 // Temporary hack
272 if (time_stepper_pt == 0)
273 {
274 return;
275 }
276
277 // Provide Data for centre-of-mass displacement internally
279 {
281
282 // I've created it so I have to tidy up too!
284
285 // Centre displacement is internal Data for this element
288 }
289 // Data created externally, so somebody else will clean up
290 else
291 {
293
294 // Centre displacement is external Data for this element
297 }
298 }
299
300
301 //=======================================================================
302 /// Calculate the contributions to the residuals and the jacobian
303 //======================================================================
305 Vector<double>& residuals, DenseMatrix<double>& jacobian, const bool& flag)
306 {
307 // Get timestepper and time
310 double time = timestepper_pt->time();
311
312 // Get second time derivatives of all displacement data
313 Vector<double> accel(3);
314 timestepper_pt->time_derivative(
315 2, this->Centre_displacement_data_pt, accel);
316
317 // Get force and torque
319 double external_torque;
321
322 // Get the timescale ratio product of Reynolds number
323 // and Strouhal number squared
324 const double Lambda_sq =
325 this->re() * this->st() * this->st() * this->density_ratio();
326
327 // Get the effective ReInvFr which must be multiplied by the
328 // density ratio to compute the gravitational load on the rigid body
329 const double scaled_re_inv_fr = this->re_invfr() * this->density_ratio();
330 // Get the gravitational load
331 Vector<double> G = g();
332
333 // Newton's law
334 int local_eqn = 0;
336 if (local_eqn >= 0)
337 {
338 residuals[local_eqn] = Lambda_sq * Mass * accel[0] - external_force[0] -
339 Mass * scaled_re_inv_fr * G[0];
340
341 // Get Jacobian too?
342 if (flag)
343 {
344 jacobian(local_eqn, local_eqn) =
345 Lambda_sq * Mass * timestepper_pt->weight(2, 0);
346 }
347 }
348
350 if (local_eqn >= 0)
351 {
352 residuals[local_eqn] = Lambda_sq * Mass * accel[1] - external_force[1] -
353 Mass * scaled_re_inv_fr * G[1];
354 // Get Jacobian too?
355 if (flag)
356 {
357 jacobian(local_eqn, local_eqn) =
358 Lambda_sq * Mass * timestepper_pt->weight(2, 0);
359 }
360 }
361
363 if (local_eqn >= 0)
364 {
367 // Get Jacobian too?
368 if (flag)
369 {
370 jacobian(local_eqn, local_eqn) =
372 }
373 }
374 }
375
376
377 //=======================================================================
378 /// Constructor: Specify coordinates of a point inside the hole
379 /// and a vector of pointers to TriangleMeshPolyLines
380 /// that define the boundary segments of the polygon.
381 /// Each TriangleMeshPolyLine has its own boundary ID and can contain
382 /// multiple (straight-line) segments. The optional final argument
383 /// is a pointer to a Data object whose three values represent
384 /// the two displacements of and the rotation angle about the polygon's
385 /// centre of mass.
386 //=======================================================================
389 const Vector<TriangleMeshCurveSection*>& boundary_polyline_pt,
390 TimeStepper* const& time_stepper_pt,
391 Data* const& centre_displacement_data_pt)
392 : TriangleMeshCurve(boundary_polyline_pt),
393 TriangleMeshClosedCurve(boundary_polyline_pt, hole_center),
394 TriangleMeshPolygon(boundary_polyline_pt, hole_center),
395 ImmersedRigidBodyElement(time_stepper_pt, centre_displacement_data_pt)
396 {
397 // The underlying geometric object can be used to update the configuration
398 // internally before a remesh
399 this->Can_update_configuration = true;
400
401 // Original rotation angle is zero
402 Initial_Phi = 0.0;
403
404 // Compute coordinates of centre of gravity etc
407 Mass = 0.0;
408 Initial_centre_of_mass[0] = 0.0;
409 Initial_centre_of_mass[1] = 0.0;
410 double inertia_x = 0.0;
411 double inertia_y = 0.0;
412
413 // Loop over polylines
414 unsigned nboundary = boundary_polyline_pt.size();
415 for (unsigned i = 0; i < nboundary; i++)
416 {
417 // Loop over the segments to get the vertex coordinates
418 unsigned nseg = boundary_polyline_pt[i]->nsegment();
419 for (unsigned j = 0; j < nseg; j++)
420 {
421 // Get the vertex coordinates
423 r_right = this->polyline_pt(i)->vertex_coordinate(j + 1);
424
425 // Mass (area)
426 Mass += 0.5 * (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
427
428 // Centroid
430 (r_left[0] + r_right[0]) *
431 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
433 (r_left[1] + r_right[1]) *
434 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
435 }
436 if (nboundary == 1)
437 {
438 // Get the vertex coordinates
439 r_left = this->polyline_pt(0)->vertex_coordinate(nseg);
441
442 // Mass (area)
443 Mass += 0.5 * (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
444
445 // Centroid
447 (r_left[0] + r_right[0]) *
448 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
450 (r_left[1] + r_right[1]) *
451 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
452 }
453 }
454
455 // Normalise
456 Initial_centre_of_mass[0] /= (6.0 * Mass);
457 Initial_centre_of_mass[1] /= (6.0 * Mass);
458
459 // Another loop over polylines for moment of inertia
460 for (unsigned i = 0; i < nboundary; i++)
461 {
462 // Loop over the segments to get the vertex coordinates
463 unsigned nseg = boundary_polyline_pt[i]->nsegment();
464 for (unsigned j = 0; j < nseg; j++)
465 {
466 // Get the vertex coordinates
468 r_right = this->polyline_pt(i)->vertex_coordinate(j + 1);
469
470 // Get moment about centroid
475
476 // Moment of inertia
477 inertia_x += 1.0 / 12.0 *
478 (r_left[1] * r_left[1] + r_left[1] * r_right[1] +
479 r_right[1] * r_right[1]) *
480 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
481
482 inertia_y += 1.0 / 12.0 *
483 (r_left[0] * r_left[0] + r_left[0] * r_right[0] +
484 r_right[0] * r_right[0]) *
485 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
486 }
487
488 if (nboundary == 1)
489 {
490 // Get the vertex coordinates
491 r_left = this->polyline_pt(0)->vertex_coordinate(nseg);
493
494 // Get moment about centroid
495 r_left[0] -= Initial_centre_of_mass[0];
499
500 // Moment of inertia
501 inertia_x += 1.0 / 12.0 *
502 (r_left[1] * r_left[1] + r_left[1] * r_right[1] +
503 r_right[1] * r_right[1]) *
504 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
505
506 inertia_y += 1.0 / 12.0 *
507 (r_left[0] * r_left[0] + r_left[0] * r_right[0] +
508 r_right[0] * r_right[0]) *
509 (r_left[0] * r_right[1] - r_right[0] * r_left[1]);
510 }
511 }
512
513 // Polar moment of inertia is sum of two orthogonal planar moments
515
516 // // Tested for circular and elliptical cross section
517 // cout << "Mass : " << Mass << std::endl;
518 // cout << "Moment of inertia: " << Moment_of_inertia << std::endl;
519 // cout << "X_c : " << Initial_centre_of_mass[0] <<
520 // std::endl; cout << "Y_c : " << Initial_centre_of_mass[1]
521 // << std::endl; pause("done");
522
523
524 // Assign the intrinsic coordinate
525 this->assign_zeta();
526
527 // {
528 // unsigned n_poly = this->npolyline();
529 // for(unsigned p=0;p<n_poly;++p)
530 // {
531 // std::cout << "Polyline " << p << "\n";
532 // std::cout << "-----------------------\n";
533 // unsigned n_vertex = Zeta_vertex[p].size();
534 // for(unsigned v=0;v<n_vertex;v++)
535 // {
536 // std::cout << v << " " << Zeta_vertex[p][v] << "\n";
537 // }
538 // }
539 // }
540 }
541
542
543 //===============================================================
544 /// Update the reference configuration by re-setting the original
545 /// position of the vertices to their current ones, re-set the
546 /// original position of the centre of mass, and the displacements
547 /// and rotations relative to it
548 //===============================================================
550 {
552 Vector<double> r(2);
553
554 // Loop over the polylines and update their vertex positions
555 unsigned npoly = this->ncurve_section();
556 for (unsigned i = 0; i < npoly; i++)
557 {
559 unsigned nvertex = poly_line_pt->nvertex();
560 for (unsigned j = 0; j < nvertex; j++)
561 {
562 x_orig = poly_line_pt->vertex_coordinate(j);
563 this->apply_rigid_body_motion(0, x_orig, r);
564 poly_line_pt->vertex_coordinate(j) = r;
565 }
566 }
567
568 // Update coordinates of hole
570 this->apply_rigid_body_motion(0, orig_hole_coord, this->internal_point());
571
572 // Update centre of gravity
579
580 // Reset displacement and rotation ("non-previous-value"
581 // history values stay)
584 unsigned nprev = timestepper_pt->nprev_values();
585 for (unsigned t = 0; t < nprev; t++)
586 {
589
592
595 }
596 }
597
598} // namespace oomph
e
Definition cfortran.h:571
cstr elem_len * i
Definition cfortran.h:603
char t
Definition cfortran.h:568
A class that represents a collection of data; each Data object may contain many different individual ...
Definition nodes.h:86
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition nodes.h:238
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition nodes.h:271
double value(const unsigned &i) const
Return i-th stored value. This function is not virtual so that it can be inlined. This means that if ...
Definition nodes.h:293
Base class for elements that can specify a drag and torque (about the origin) – typically used for im...
Definition elements.h:5092
The FSIFluidElement class is a base class for all fluid finite elements that apply a load (traction) ...
Definition fsi.h:63
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
Definition elements.h:4342
virtual void identify_geometric_data(std::set< Data * > &geometric_data_pt)
The purpose of this function is to identify all Data objects that affect the elements' geometry....
Definition elements.h:2793
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
unsigned add_internal_data(Data *const &data_pt, const bool &fd=true)
Add a (pointer to an) internal data object to the element and return the index required to obtain it ...
Definition elements.cc:67
void flush_external_data()
Flush all external data.
Definition elements.cc:392
unsigned add_external_data(Data *const &data_pt, const bool &fd=true)
Add a (pointer to an) external data object to the element and return its index (i....
Definition elements.cc:312
virtual void position(const Vector< double > &zeta, Vector< double > &r) const =0
Parametrised position on object at current time: r(zeta).
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
Custom Data class that is used when HijackingData. The class always contains a single value that is c...
Definition nodes.h:575
Class that solves the equations of motion for a general two-dimensional rigid body subject to a parti...
bool Include_geometric_rotation
Boolean to indicate that the rotation variable does not affect the boundary shape.
void position(const Vector< double > &xi, Vector< double > &r) const
Overload the position to apply the rotation and translation.
const double & density_ratio() const
Access function for the the density ratio.
Mesh *const & drag_mesh_pt()
Access fct to mesh containing face elements that allow the computation of the drag on the body.
const double & st() const
Access function for the fluid Strouhal number.
static double Default_Physical_Constant_Value
Static default value for physical constants.
void initialise(TimeStepper *const &time_stepper_pt)
Initialisation function.
void dposition_dt(const Vector< double > &zeta, const unsigned &j, Vector< double > &drdt)
Work out the position derivative, including rigid body motion.
ExternalTorqueFctPt External_torque_fct_pt
Function pointer to function that specifies external torque.
const Vector< double > & g() const
Access function for gravity.
void delete_external_hijacked_data()
Delete the storage for the external data formed from hijacked data.
double Initial_Phi
Original rotation angle.
bool Displacement_data_is_internal
Boolean flag to indicate whether data is internal.
void get_residuals_rigid_body_generic(Vector< double > &residuals, DenseMatrix< double > &jacobian, const bool &flag)
Get residuals and/or Jacobian.
void output_centre_of_gravity(std::ostream &outfile)
Output position velocity and acceleration of centre of gravity.
Data * Centre_displacement_data_pt
Data for centre of gravity displacement. Values: 0: x-displ; 1: y-displ; 2: rotation angle.
unsigned Index_for_centre_displacement
Index for the data (internal or external) that contains the centre-of-gravity displacement.
static Vector< double > Default_Gravity_vector
Static default value for gravity.
const double & re_invfr()
Access to the fluid inverse Froude number.
GeomObject * Geom_object_pt
Underlying geometric object.
ExternalForceFctPt External_force_fct_pt
Function pointer to function that specifies external force.
int centre_displacement_local_eqn(const unsigned &i)
Return the equation number associated with the i-th centre of gravity displacment 0: x-displ; 1: y-di...
double Moment_of_inertia
Polar moment of inertia of body.
void set_drag_mesh(Mesh *const &drag_mesh_pt)
Function to set the drag mesh and add the appropriate load and geometric data as external data to the...
Mesh * Drag_mesh_pt
Mesh containing face elements that allow the computation of the drag on the body.
void get_force_and_torque(const double &time, Vector< double > &force, double &torque)
Get force and torque from specified fct pointers and drag mesh.
const double & re() const
Access function for the fluid Reynolds number.
void apply_rigid_body_motion(const unsigned &t, const Vector< double > &initial_x, Vector< double > &r) const
Helper function to adjust the position in response to changes in position and angle of the solid abou...
static double Default_Physical_Ratio_Value
Static default value for physical ratios.
Vector< double > Initial_centre_of_mass
X-coordinate of initial centre of gravity.
std::list< unsigned > List_of_external_hijacked_data
Storage for the external data that is formed from hijacked data that must be deleted by this element.
void assign_zeta()
Helper function to assign the values of the (scaled) arc-length to each node of each polyline....
ImmersedRigidBodyTriangleMeshPolygon(const Vector< double > &hole_center, const Vector< TriangleMeshCurveSection * > &boundary_polyline_pt, TimeStepper *const &time_stepper_pt, Data *const &centre_displacement_data_pt=0)
Constructor: Specify coordinates of a point inside the hole and a vector of pointers to TriangleMeshP...
void reset_reference_configuration()
Update the reference configuration by re-setting the original position of the vertices to their curre...
A general mesh class.
Definition mesh.h:67
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition mesh.h:452
unsigned long nelement() const
Return number of elements in the mesh.
Definition mesh.h:598
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
double & time()
Return current value of continous time.
void time_derivative(const unsigned &i, Data *const &data_pt, Vector< double > &deriv)
Evaluate i-th derivative of all values in Data and return in Vector deriv[].
Base class defining a closed curve for the Triangle mesh generation.
Vector< double > internal_point() const
Coordinates of the internal point.
closed curves and open curves. All TriangleMeshCurves are composed of a Vector of TriangleMeshCurveSe...
Class defining a polyline for use in Triangle Mesh generation.
Vector< double > vertex_coordinate(const unsigned &i) const
Coordinate vector of i-th vertex (const version)
Class defining a closed polygon for the Triangle mesh generation.
TriangleMeshPolyLine * polyline_pt(const unsigned &i) const
Pointer to i-th constituent polyline.
unsigned ncurve_section() const
Number of constituent curves.
bool Can_update_configuration
Boolean flag to indicate whether the polygon can update its own reference configuration after it has ...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).