navier_stokes_surface_drag_torque_elements.h
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-2023 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 // Header file for specific surface elements
27 
28 #ifndef OOMPH_NAVIER_STOKES_SURFACE_DRAG_TORQUE_ELEMENTS_HEADER
29 #define OOMPH_NAVIER_STOKES_SURFACE_DRAG_TORQUE_ELEMENTS_HEADER
30 
31 // Config header generated by autoconfig
32 #ifdef HAVE_CONFIG_H
33 #include <oomph-lib-config.h>
34 #endif
35 
36 namespace oomph
37 {
38  //======================================================================
39  /// A class of elements that allow the determination of the
40  /// drag and toque, relative to a given centre of rotation, along
41  /// a domain boundary.
42  /// The element operates as a FaceElement and attaches itself
43  /// to a bulk element of the type specified by the template
44  /// argument.
45  //======================================================================
46  template<class ELEMENT>
48  : public virtual FaceGeometry<ELEMENT>,
49  public virtual FaceElement,
50  public virtual ElementWithDragFunction
51  {
52  public:
53  /// Constructor, which takes a "bulk" element and the value of an
54  /// index describing to which face the element should be attached.
56  const int& face_index)
57  : FaceGeometry<ELEMENT>(), FaceElement()
58  {
59  // Attach the geometrical information to the element. N.B. This function
60  // also assigns nbulk_value from the required_nvalue of the bulk element
61  element_pt->build_face_element(face_index, this);
62 
63  // Set the dimension from the dimension of the first node
64  this->Dim = node_pt(0)->ndim();
65 
66  // Default centre of rotation is the origin
67  this->Centre_of_rotation.resize(this->Dim, 0.0);
68  }
69 
70  /// Set the translation and rotation of the rigid object
71  /// as external data
72  void set_translation_and_rotation(Data* const& object_data_pt)
73  {
74  this->Translation_index = this->add_external_data(object_data_pt);
75  }
76 
77 
78  /// Access function for the centre of rotation
79  double& centre_of_rotation(const unsigned& i)
80  {
81  return this->Centre_of_rotation[i];
82  }
83 
84 
85  /// Function that specifies the drag force and the torque about
86  /// the origin
87  virtual void get_drag_and_torque(Vector<double>& drag_force,
88  Vector<double>& drag_torque)
89  {
90  // Spatial dimension of element
91  unsigned ndim = dim();
92 
93  // Initialise force
94  for (unsigned i = 0; i < ndim + 1; i++)
95  {
96  drag_force[i] = 0.0;
97  }
98 
99  // Now there will be one torque component in 2D (1D surface element)
100  // and three in 3D (2D surface element)
101  for (unsigned i = 0; i < 2 * ndim - 1; i++)
102  {
103  drag_torque[i] = 0.0;
104  }
105 
106  // Vector of local coordinates in face element
108 
109  // Vector for global Eulerian coordinates
110  Vector<double> x(ndim + 1);
111 
112  // Vector for local coordinates in bulk element
113  Vector<double> s_bulk(ndim + 1);
114 
115  // Set the value of n_intpt
116  unsigned n_intpt = integral_pt()->nweight();
117 
118  // Get pointer to assocated bulk element
119  ELEMENT* bulk_el_pt = dynamic_cast<ELEMENT*>(bulk_element_pt());
120 
121  // Loop over the integration points
122  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
123  {
124  // Assign values of s in FaceElement and local coordinates in bulk
125  // element
126  for (unsigned i = 0; i < ndim; i++)
127  {
128  s[i] = integral_pt()->knot(ipt, i);
129  }
130 
131  // Get the bulk coordinates
132  this->get_local_coordinate_in_bulk(s, s_bulk);
133 
134  // Get the integral weight
135  double w = integral_pt()->weight(ipt);
136 
137  // Get jacobian of mapping
138  double J = J_eulerian(s);
139 
140  // Premultiply the weights and the Jacobian
141  double W = w * J;
142 
143  // Get x position as Vector
144  interpolated_x(s, x);
145 
146 #ifdef PARANOID
147 
148  // Get x position as Vector from bulk element
149  Vector<double> x_bulk(ndim + 1);
150  bulk_el_pt->interpolated_x(s_bulk, x_bulk);
151 
152  double max_legal_error = 1.0e-5;
153  double error = 0.0;
154  for (unsigned i = 0; i < ndim + 1; i++)
155  {
156  error += fabs(x[i] - x_bulk[i]);
157  }
158  if (error > max_legal_error)
159  {
160  std::ostringstream error_stream;
161  error_stream << "difference in Eulerian posn from bulk and face: "
162  << error << " exceeds threshold " << max_legal_error
163  << std::endl;
164  throw OomphLibError(error_stream.str(),
165  OOMPH_CURRENT_FUNCTION,
166  OOMPH_EXCEPTION_LOCATION);
167  }
168 #endif
169 
170  // Outer unit normal of the fluid
171  Vector<double> normal(ndim + 1);
172  outer_unit_normal(s, normal);
173 
174  // Get velocity from bulk element
175  Vector<double> veloc(ndim + 1);
176  bulk_el_pt->interpolated_u_nst(s_bulk, veloc);
177 
178  // Get traction from bulk element this is directed into the fluid
179  // so we need to reverse the sign
180  Vector<double> traction(ndim + 1);
181  bulk_el_pt->get_traction(s_bulk, normal, traction);
182 
183  // Integrate (note the minus sign)
184  for (unsigned i = 0; i < ndim + 1; i++)
185  {
186  drag_force[i] -= traction[i] * W;
187  }
188 
189  // Now Calculate the torque which is r x F
190  // Scale X relative to the centre of rotation
191  Vector<double> X(ndim + 1);
192  for (unsigned i = 0; i < ndim + 1; i++)
193  {
194  X[i] = x[i] - Centre_of_rotation[i] -
196  }
197 
198  // In 2D it's just a single scalar
199  // again note the minus sign
200  if (ndim == 1)
201  {
202  drag_torque[0] -= (X[0] * traction[1] - X[1] * traction[0]) * W;
203  }
204  else if (ndim == 2)
205  {
206  drag_torque[0] -= (X[1] * traction[2] - X[2] * traction[1]) * W;
207  drag_torque[1] -= (X[2] * traction[0] - X[0] * traction[2]) * W;
208  drag_torque[2] -= (X[0] * traction[1] - X[1] * traction[0]) * W;
209  }
210  else
211  {
212  throw OomphLibError("Dimension of a surface element must be 1 or 2\n",
213  OOMPH_CURRENT_FUNCTION,
214  OOMPH_EXCEPTION_LOCATION);
215  }
216  }
217 
218  // std::cout << "Forces " << drag_force[0] << " " << drag_force[1] << " "
219  // << drag_torque[0] << "\n";
220  }
221 
222 
223  /// Specify the value of nodal zeta from the face geometry
224  /// The "global" intrinsic coordinate of the element when
225  /// viewed as part of a geometric object should be given by
226  /// the FaceElement representation, by default (needed to break
227  /// indeterminacy if bulk element is SolidElement)
228  double zeta_nodal(const unsigned& n,
229  const unsigned& k,
230  const unsigned& i) const
231  {
232  return FaceElement::zeta_nodal(n, k, i);
233  }
234 
235 
236  /// Output function
237  void output(std::ostream& outfile, const unsigned& n_plot)
238  {
239  // Get pointer to assocated bulk element
240  ELEMENT* bulk_el_pt = dynamic_cast<ELEMENT*>(bulk_element_pt());
241 
242  // Elemental dimension
243  unsigned dim_el = dim();
244 
245  // Local coordinates
246  Vector<double> s(dim_el);
247 
248  Vector<double> s_bulk(dim_el + 1);
249 
250  // Calculate the Eulerian coordinates and Lagrange multiplier
251  Vector<double> x(dim_el + 1, 0.0);
252 
253  // Outer unit normal of the fluid
254  Vector<double> normal(dim_el + 1);
255 
256  // Velocity from bulk element
257  Vector<double> veloc(dim_el + 1);
258 
259  // Tractions (from bulk element)
260  Vector<double> traction(dim_el + 1);
261 
262  // Tecplot header info
263  outfile << this->tecplot_zone_string(n_plot);
264 
265  // Loop over plot points
266  unsigned num_plot_points = this->nplot_points(n_plot);
267  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
268  {
269  // Get local coordinates of plot point
270  this->get_s_plot(iplot, n_plot, s);
271 
272  this->get_local_coordinate_in_bulk(s, s_bulk);
273 
274  // Get x position from bulk
275  bulk_el_pt->interpolated_x(s_bulk, x);
276  // Get outer unit normal
277  outer_unit_normal(s, normal);
278  bulk_el_pt->interpolated_u_nst(s_bulk, veloc);
279  // Get traction from bulk element this is directed into the fluid
280  // so we need to reverse the sign
281  bulk_el_pt->get_traction(s_bulk, normal, traction);
282 
283  // Now Calculate the torque which is r x F
284  // Scale X relative to the centre of rotation
285  Vector<double> X(dim_el + 1);
286  for (unsigned i = 0; i < dim_el + 1; i++)
287  {
288  X[i] = x[i] - Centre_of_rotation[i] -
290  }
291 
292  for (unsigned i = 0; i < dim_el + 1; i++)
293  {
294  outfile << x[i] << " ";
295  }
296 
297  for (unsigned i = 0; i < dim_el + 1; i++)
298  {
299  outfile << normal[i] << " ";
300  }
301 
302  for (unsigned i = 0; i < dim_el + 1; i++)
303  {
304  outfile << veloc[i] << " ";
305  }
306 
307  for (unsigned i = 0; i < dim_el + 1; i++)
308  {
309  outfile << -1.0 * traction[i] << " ";
310  }
311  outfile << -(X[0] * traction[1] - X[1] * traction[0]);
312 
313  outfile << std::endl;
314  }
315 
316  this->write_tecplot_zone_footer(outfile, n_plot);
317  }
318 
319 
320  private:
321  /// The highest dimension of the problem
322  unsigned Dim;
323 
324  /// The centre of rotation for the torque calculation
326 
327  /// The index of where the translation and rotation data is stored
329  };
330 
331 
332 } // namespace oomph
333 
334 #endif
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:86
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
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: elements.h:5088
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
Definition: elements.h:4338
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
Definition: elements.h:4626
void outer_unit_normal(const Vector< double > &s, Vector< double > &unit_normal) const
Compute outer unit normal at the specified local coordinate.
Definition: elements.cc:6006
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
In a FaceElement, the "global" intrinsic coordinate of the element along the boundary,...
Definition: elements.h:4497
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Definition: elements.h:4735
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s. Overloaded to get information from bulk...
Definition: elements.h:4528
double J_eulerian(const Vector< double > &s) const
Return the Jacobian of mapping from local to global coordinates at local position s....
Definition: elements.cc:5242
void get_local_coordinate_in_bulk(const Vector< double > &s, Vector< double > &s_bulk) const
Calculate the vector of local coordinate in the bulk element given the local coordinates in this Face...
Definition: elements.cc:6384
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: elements.h:4998
A general Finite Element class.
Definition: elements.h:1313
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction")
Definition: elements.h:3161
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2611
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1963
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: elements.h:3148
virtual unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction")
Definition: elements.h:3186
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Function for building a lower dimensional FaceElement on the specified face of the FiniteElement....
Definition: elements.cc:5132
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Add tecplot zone "footer" to output stream (when plotting nplot points in each "coordinate direction"...
Definition: elements.h:3174
Data *& external_data_pt(const unsigned &i)
Return a pointer to i-th external data object.
Definition: elements.h:659
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:307
unsigned ndim() const
Access function to # of Eulerian coordinates.
Definition: geom_objects.h:177
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
virtual double weight(const unsigned &i) const =0
Return weight of i-th integration point.
A class of elements that allow the determination of the drag and toque, relative to a given centre of...
void set_translation_and_rotation(Data *const &object_data_pt)
Set the translation and rotation of the rigid object as external data.
unsigned Translation_index
The index of where the translation and rotation data is stored.
Vector< double > Centre_of_rotation
The centre of rotation for the torque calculation.
void output(std::ostream &outfile, const unsigned &n_plot)
Output function.
virtual void get_drag_and_torque(Vector< double > &drag_force, Vector< double > &drag_torque)
Function that specifies the drag force and the torque about the origin.
NavierStokesSurfaceDragTorqueElement(FiniteElement *const &element_pt, const int &face_index)
Constructor, which takes a "bulk" element and the value of an index describing to which face the elem...
double & centre_of_rotation(const unsigned &i)
Access function for the centre of rotation.
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Specify the value of nodal zeta from the face geometry The "global" intrinsic coordinate of the eleme...
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
An OomphLibError object which should be thrown when an run-time error is encountered....
//////////////////////////////////////////////////////////////////// ////////////////////////////////...