circle_as_generalised_element.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 #ifndef CIRCLE_AS_GEN_ELEMENT_HEADER
27 #define CIRCLE_AS_GEN_ELEMENT_HEADER
28 
29 #include "circle.h"
30 
31 
32 namespace oomph
33 {
34 
35 /// ///////////////////////////////////////////////////////////////////////
36 /// ///////////////////////////////////////////////////////////////////////
37 /// ///////////////////////////////////////////////////////////////////////
38 
39 
40 //===========start_of_general_circle=========================================
41 /// GeneralCircle "upgraded" to a GeneralisedElement: Circular
42 /// ring whose position is given by
43 /// \f[ x = X_c + R \cos(\zeta) \f]
44 /// \f[ y = Y_c + R \sin(\zeta) \f]
45 /// The ring's vertical position \f$ Y_c \f$ is
46 /// determined by "pseudo elasticity":
47 /// \f[
48 /// 0 = f_{load} - Y_c \ k_{stiff}
49 /// \f]
50 /// This simulates the case where the centre of the ring is mounted on
51 /// an elastic spring of stiffness \f$ k_{stiff} \f$ and loaded by
52 /// the force \f$ f_{load}. \f$ The "load" is specified by the
53 /// Data object \c load_pt().
54 //=========================================================================
55 class ElasticallySupportedRingElement : public GeneralisedElement,
56  public GeneralCircle
57 {
58 
59 public:
60 
61  /// Constructor: Build ring from doubles that describe
62  /// the geometry: x and y positions of centre and the radius.
63  /// Initialise stiffness to 1.0. By default, no load is set.
64  ElasticallySupportedRingElement(const double& x_c, const double& y_c,
65  const double& r) :
66  GeneralCircle(x_c,y_c,r), K_stiff(1.0), Load_data_has_been_set(false)
67  {
68  // The geometric data is internal to the element -- we copy the pointers
69  // to the GeomObject's geometric data to the element's internal
70  // data to ensure that any unknown values of geometric data are
71  // given global equation numbers. The add_internal_data(...)
72  // function returns the index by which the added Data item
73  // is accessible from internal_data_pt(...).
74  Internal_geometric_data_index=add_internal_data(Geom_data_pt[0]);
75 
76  // Geometric Data for the GeomObject has been set up (and pinned) in
77  // constructor for geometric object. Now free the y-position
78  // of the centre because we want to determine it as an unknown
79  internal_data_pt(Internal_geometric_data_index)->unpin(1);
80 
81  // Change cleanup responsibilities: The GeomData will now be killed
82  // by the GeneralisedElement when it wipes its internal Data
83  Must_clean_up=false;
84  }
85 
86 
87  /// Destructor:
88  virtual ~ElasticallySupportedRingElement()
89  {
90  // The GeomObject's GeomData is mirrored in the element's
91  // Internal Data and therefore gets wiped in the
92  // destructor of GeneralisedElement --> No need to kill it here
93  }
94 
95 
96  /// Set pointer to Data object that specifies the "load"
97  /// on the ElasticallySupportedRingElement
98  void set_load_pt(Data* load_pt)
99  {
100 #ifdef PARANOID
101  if (load_pt->nvalue()!=1)
102  {
103  std::ostringstream error_stream;
104  error_stream << "The data object that stores the load on the "
105  << "ElasticallySupportedRingElement\n"
106  << "should only contain a single data value\n"
107  << "This one contains " << load_pt->nvalue() << std::endl;
108 
109  throw OomphLibError(error_stream.str(),
110  OOMPH_CURRENT_FUNCTION,
111  OOMPH_EXCEPTION_LOCATION);
112  }
113 #endif
114 
115  // Add load to the element's external data and store
116  // its index within that storage scheme: Following this assignment,
117  // the load Data is accessible from
118  // GeneralisedElement::external_data_pt(External_load_index)
119  External_load_index = add_external_data(load_pt);
120 
121  // Load has now been set
122  Load_data_has_been_set=true;
123 
124  } // end of set_load_pt(...)
125 
126 
127  /// "Load" acting on the ring
128  double load()
129  {
130  // Return the load if it has been set
131  if (Load_data_has_been_set)
132  {
133  return external_data_pt(External_load_index)->value(0);
134  }
135  // ...otherwise return zero load
136  else
137  {
138  return 0.0;
139  }
140  } // end of load()
141 
142 
143  /// Access function for the spring stiffness
144  double& k_stiff() {return K_stiff;}
145 
146 
147  /// Pin the vertical displacement
148  void pin_yc()
149  {
150  // Vertical position of centre is stored as value 1 in the
151  // element's one and only internal Data object.
152  internal_data_pt(Internal_geometric_data_index)->pin(1);
153  }
154 
155 
156  /// Unpin the vertical displacement
157  void unpin_yc()
158  {
159  // Vertical position of centre is stored as value 1 in the
160  // element's one and only internal Data object.
161  internal_data_pt(Internal_geometric_data_index)->unpin(1);
162 
163  } // end of unpin_yc()
164 
165 
166  /// Compute element residual vector (wrapper)
167  void get_residuals(Vector<double> &residuals)
168  {
169  //Initialise residuals to zero
170  residuals.initialise(0.0);
171  //Create a dummy matrix
172  DenseMatrix<double> dummy(1);
173  //Call the generic residuals function with flag set to 0
174  fill_in_generic_residual_contribution(residuals,dummy,0);
175  }
176 
177 
178  /// Compute element residual Vector and element Jacobian matrix (wrapper)
179  void get_jacobian(Vector<double> &residuals,
180  DenseMatrix<double> &jacobian)
181  {
182  //Initialise residuals to zero
183  residuals.initialise(0.0);
184  //Initialise the jacobian matrix to zero
185  jacobian.initialise(0.0);
186  //Call the generic routine with the flag set to 1
187  fill_in_generic_residual_contribution(residuals,jacobian,1);
188 
189  } // end of get_jacobian(...)
190 
191 
192  protected:
193 
194 
195  /// Compute element residual Vector (only if flag=0) and also
196  /// the element Jacobian matrix (if flag=1)
197  void fill_in_generic_residual_contribution(Vector<double> &residuals,
198  DenseMatrix<double> &jacobian,
199  unsigned flag)
200  {
201  //Find out how may dofs there are in the element
202  unsigned n_dof = ndof();
203  //If everything is pinned return straight away
204  if (n_dof==0) return;
205 
206  // Pseudo-elastic force balance to determine the position of the
207  // ring's centre for a given load.
208 
209  // What's the local equation number of the force balance equation
210  // [It's the equation that "determines" the value of the internal
211  // dof, y_c, which is stored as the second value of the one-and-only
212  // internal data object in this element]
213  int local_eqn_number_for_yc =
214  internal_local_eqn(Internal_geometric_data_index,1);
215 
216  // Add residual to appropriate entry in the element's residual
217  // vector:
218  residuals[local_eqn_number_for_yc]=load()-K_stiff*y_c();
219 
220  // Work out Jacobian:
221  if (flag)
222  {
223  // Derivative of residual w.r.t. the internal dof, i.e. the vertical
224  // position of the ring's centre: d residual[0]/d y_c
225  jacobian(local_eqn_number_for_yc,local_eqn_number_for_yc) = -K_stiff;
226 
227 
228  // Derivative with respect to external dof, i.e. the applied
229  // load: d residual[0]/d load -- but only if the load is an unknown
230  if (n_dof==2)
231  {
232  // What's the local equation number of the load parameter?
233  // It's stored as the 0th value in the the element's
234  // one-and-only external data item:
235  int local_eqn_number_for_load =
236  external_local_eqn(External_load_index,0);
237 
238 #ifdef PARANOID
239  if (local_eqn_number_for_load<0)
240  {
241  throw OomphLibError(
242  "Load is pinned and yet n_dof=2?\n This is very fishy!\n",
243  OOMPH_CURRENT_FUNCTION,
244  OOMPH_EXCEPTION_LOCATION);
245  }
246 #endif
247 
248  // Add entry into element Jacobian
249  jacobian(local_eqn_number_for_yc,local_eqn_number_for_load) = 1.0;
250  }
251  }
252  } // end of get_residuals_generic(...)
253 
254 
255 private:
256 
257  /// Stiffness of the ring's "elastic" support
258  double K_stiff;
259 
260  /// Index of the location of the load Data in the element's
261  /// array of external data
262  unsigned External_load_index;
263 
264  /// Index of the location of the geometric Data in the element's
265  /// array of internal data
266  unsigned Internal_geometric_data_index;
267 
268  /// Flag to indicate that load data has been set
269  bool Load_data_has_been_set;
270 
271 };
272 
273 }
274 
275 #endif
Definition: circle.h:34