periodic_orbit_handler.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 #include "periodic_orbit_handler.h"
31 
32 namespace oomph
33 {
34 
36  std::ostream &outfile,
37  const unsigned &n_plot)
38  {
39  //Find out how many nodes there are
40  const unsigned n_node = nnode();
41 
42  //Set up memory for the shape and test functions
43  Shape psi(n_node);
44  DShape dpsidt(n_node,1);
45 
46  Vector<double> s(1);
47 
48  //Cast the element
49  PeriodicOrbitBaseElement* const base_el_pt =
50  dynamic_cast<PeriodicOrbitBaseElement*>(elem_pt);
51 
52  const double inverse_timescale = this->omega();
53 
54  //Loop over the plot point
55  for(unsigned i=0;i<n_plot;i++)
56  {
57  //Get the coordinate
58  s[0] = -1.0 + 2.0*i/((double)(n_plot-1));
59 
60  (void)dshape_eulerian(s,psi,dpsidt);
61 
62  //Sort out the timestepper weights and the time in here
63  //Calculate the time
64  double interpolated_time = 0.0;
65  for(unsigned l=0;l<n_node;l++)
66  {
67  interpolated_time += raw_nodal_position(l,0)*psi(l);
68  }
69 
70 
71  //Need to multiply by period and the set global time
72  this->time_pt()->time() = interpolated_time;
73 
74  //Set the weights of the timestepper
75  this->set_timestepper_weights(psi,dpsidt);
76 
77  base_el_pt->spacetime_output(outfile,n_plot,
78  interpolated_time/inverse_timescale);
79  }
80  }
81 
83  PeriodicOrbitAssemblyHandlerBase* const &assembly_handler_pt,
84  GeneralisedElement* const &elem_pt,
85  Vector<double> &residuals, DenseMatrix<double> &jacobian,
86  const unsigned& flag)
87  {
88  //A simple integration loop
89  //Find out how many nodes there are
90  const unsigned n_node = nnode();
91 
92  //Set up memory for the shape and test functions
93  Shape psi(n_node), test(n_node);
94  DShape dpsidt(n_node,1), dtestdt(n_node,1);
95 
96  //Set the value of n_intpt
97  const unsigned n_intpt = integral_pt()->nweight();
98 
99  //Integers to store the local equation and unknown numbers
100  int local_eqn=0, local_unknown=0;
101 
102  //Storage for the underlying element's residuals
103  const unsigned n_elem_dof = elem_pt->ndof();
104  Vector<double> el_residuals(n_elem_dof);
105  DenseMatrix<double> el_mass;
106  DenseMatrix<double> el_jacobian;
107 
108  if(flag)
109  {
110  el_mass.resize(n_elem_dof,n_elem_dof);
111  el_jacobian.resize(n_elem_dof,n_elem_dof);
112  }
113 
114  //Storage for the current value of the unkowns
115  Vector<double> u(n_elem_dof);
116  //and the derivatives
117  Vector<double> du_dt(n_elem_dof);
118  //And the previous derivative
119  Vector<double> du_dt_old(n_elem_dof);
120  //Storage for the inner product matrix
121  DenseMatrix<double> inner_product(n_elem_dof);
122  //Cast the element
123  PeriodicOrbitBaseElement* const base_el_pt =
124  dynamic_cast<PeriodicOrbitBaseElement*>(elem_pt);
125  //Get the inner product matrix
126  base_el_pt->get_inner_product_matrix(inner_product);
127 
128  //Storage for "all" unknowns
129  Vector<double> all_current_unknowns;
130  Vector<double> all_previous_unknowns;
131 
132  //Get the value of omega
133  const double inverse_timescale = this->omega();
134 
135  //Loop over the integration points
136  for(unsigned ipt=0;ipt<n_intpt;ipt++)
137  {
138  //Get the integral weight
139  double w = integral_pt()->weight(ipt);
140 
141  //Call the derivatives of the shape and test functions
142  double J = dshape_and_dtest_eulerian_at_knot_orbit(ipt,psi,dpsidt,
143  test,dtestdt);
144 
145  //Premultiply the weights and the Jacobian
146  double W = w*J;
147 
148  //Sort out the timestepper weights and the time in here
149  //Calculate the time
150  double interpolated_time = 0.0;
151  for(unsigned l=0;l<n_node;l++)
152  {
153  interpolated_time += raw_nodal_position(l,0)*psi(l);
154  }
155 
156 
157  //Need to multiply by period and the set global time
158  this->time_pt()->time() = interpolated_time/inverse_timescale;
159  //Set the weights of the timestepper
160  this->set_timestepper_weights(psi,dpsidt);
161 
162  //Get the residuals of the element or residuals and jacobian
163  if(flag)
164  {
165  elem_pt->get_jacobian_and_mass_matrix(el_residuals,el_jacobian,
166  el_mass);
167  }
168  else
169  {
170  elem_pt->get_residuals(el_residuals);
171  }
172 
173  //Get the current value of the unknown time derivatives
174  base_el_pt->get_non_external_ddofs_dt(du_dt);
175 
176  //Multiply the elemental residuals by the appropriate test functions
177  for(unsigned l=0;l<n_node;l++)
178  {
179  //Get the local equation number
180  local_eqn = nodal_local_eqn(l,0);
181  //If it's not a boundary condition (it will never be)
182  if(local_eqn >= 0)
183  {
184  //Work out the offset which is the GLOBAL time unknown
185  //multiplied by the number of elemental unknowns
186  unsigned offset = this->eqn_number(local_eqn)*n_elem_dof;
187  //Add to the appropriate residuals
188  for(unsigned i=0;i<n_elem_dof;i++)
189  {
190  residuals[i + offset] += el_residuals[i]*psi(l)*W;
191  }
192 
193 
194  //Add the jacobian contributions
195  if(flag)
196  {
197  //The form of the equations is -M du/dt + R = 0
198 
199  //Now add the contribution to the jacobian
200  for(unsigned l2=0;l2<n_node;l2++)
201  {
202  local_unknown = nodal_local_eqn(l2,0);
203  if(local_unknown >= 0)
204  {
205  //Work out the second offset
206  unsigned offset2 = this->eqn_number(local_unknown)*n_elem_dof;
207  //Add to the appropriate jacobian terms
208  for(unsigned i=0;i<n_elem_dof;i++)
209  {
210  for(unsigned j=0;j<n_elem_dof;j++)
211  {
212  //Add in the Jacobian terms
213  jacobian(i + offset, j+ offset2) +=
214  el_jacobian(i,j)*psi(l2)*psi(l)*W;
215 
216  //Add the time derivative terms,
217  jacobian(i + offset, j + offset2) -= el_mass(i,j)*
218  dpsidt(l2,0)*inverse_timescale*psi(l)*W;
219  }
220  }
221  }
222  }
223 
224 
225  //Add the variation of the period
226  for(unsigned i=0;i<n_elem_dof;i++)
227  {
228  for(unsigned j=0;j<n_elem_dof;j++)
229  {
230  jacobian(i + offset, Ntstorage*n_elem_dof)
231  -= el_mass(i,j)*(du_dt[j]/inverse_timescale)*psi(l)*W;
232  }
233  }
234  } //End of Jacobian flag
235  }
236  }
237 
238  //Sort out the phase condition
239 
240  //Get the current value of the unknowns
241  base_el_pt->get_non_external_dofs(u);
242 
243  //Now get the unknowns required by the assembly handler
244  //i.e. including all values throughout the period for backup
245  assembly_handler_pt->get_dofs_for_element(elem_pt,
246  all_current_unknowns);
247  //Get the previous values as stored by the assembly handler
248  assembly_handler_pt->get_previous_dofs_for_element(elem_pt,
249  all_previous_unknowns);
250 
251  //Now set the elemental values to the previous values
252  assembly_handler_pt->set_dofs_for_element(elem_pt,all_previous_unknowns);
253  //Get the previous time derivatives
254  base_el_pt->get_non_external_ddofs_dt(du_dt_old);
255  //Reset the element's values to the current
256  assembly_handler_pt->set_dofs_for_element(elem_pt,all_current_unknowns);
257 
258 
259  //Assemble the inner product
260  double sum = 0.0;
261  for(unsigned i=0;i<n_elem_dof;i++)
262  {
263  for(unsigned j=0;j<n_elem_dof;j++)
264  {
265  sum += u[i]*inner_product(i,j)*du_dt_old[j];
266  }
267  }
268 
269  //Add to the residuals
270  residuals[Ntstorage*n_elem_dof] += sum*W;
271 
272  //Sort out the jacobian
273  if(flag)
274  {
275  //Loop over the unknown time points
276  for(unsigned l2=0;l2<n_node;l2++)
277  {
278  //Get the local unknown
279  local_unknown = nodal_local_eqn(l2,0);
280  if(local_unknown >= 0)
281  {
282  //Work out the offset
283  unsigned offset2 = this->eqn_number(local_unknown)*n_elem_dof;
284  //Now add in the appropriate jacobian terms
285  for(unsigned i2=0;i2<n_elem_dof;i2++)
286  {
287  double sum2 = 0.0;
288  for(unsigned j=0;j<n_elem_dof;j++)
289  {
290  sum2 += inner_product(i2,j)*du_dt_old[j];
291  }
292  jacobian(Ntstorage*n_elem_dof,i2 + offset2) += psi(l2)*sum2*W;
293  }
294  }
295  }
296  } //End of jacobian calculation
297 
298  } //End of loop over time period integration points
299  }
300 
301 
302 
303 }
virtual void get_inner_product_matrix(DenseMatrix< double > &inner_product)
Get the inner product matrix.
A Generalised Element class.
Definition: elements.h:76
virtual void get_residuals(Vector< double > &residuals)
Calculate the vector of residuals of the equations in the element. By default initialise the vector t...
Definition: elements.h:975
double omega()
Return the frequency.
cstr elem_len * i
Definition: cfortran.h:607
virtual void get_non_external_dofs(Vector< double > &u)
Interface to get the current value of all (internal and shared) unknowns.
virtual double dshape_and_dtest_eulerian_at_knot_orbit(const unsigned &ipt, Shape &psi, DShape &dpsidt, Shape &test, DShape &dtestdt) const =0
Shape/test functions and derivs w.r.t. to global coords at integration point ipt; return Jacobian of ...
virtual double weight(const unsigned &i) const =0
Return weight of i-th integration point.
Time *& time_pt()
Retun the pointer to the global time.
void orbit_output(GeneralisedElement *const &elem_pt, std::ostream &outfile, const unsigned &n_plot)
virtual void get_non_external_ddofs_dt(Vector< double > &du_dt)
unsigned ndof() const
Return the number of equations/dofs in the element.
Definition: elements.h:834
double dshape_eulerian(const Vector< double > &s, Shape &psi, DShape &dpsidx) const
Compute the geometric shape functions and also first derivatives w.r.t. global coordinates at local c...
Definition: elements.cc:3227
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1908
static char t char * s
Definition: cfortran.h:572
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number...
Definition: elements.h:709
virtual void get_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > &dofs)=0
virtual void get_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Calculate the residuals and jacobian and elemental "mass" matrix, the matrix that multiplies the time...
Definition: elements.h:1010
double & time()
Return the current value of the continuous time.
Definition: timesteppers.h:130
virtual void set_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > const &dofs)=0
virtual void spacetime_output(std::ostream &outilfe, const unsigned &Nplot, const double &time=0.0)
double raw_nodal_position(const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n. Do not use the hanging node representation. NOTE: Moved to cc file because of a possible compiler bug in gcc (yes, really!). The move to the cc file avoids inlining which appears to cause problems (only) when compiled with gcc and -O3; offensive "illegal read" is in optimised-out section of code and data that is allegedly illegal is readily readable (by other means) just before this function is called so I can&#39;t really see how we could possibly be responsible for this...
Definition: elements.cc:1659
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
void set_timestepper_weights(const Shape &psi, const DShape &dpsidt)
Set the timestepper weights.
void fill_in_generic_residual_contribution_orbit(PeriodicOrbitAssemblyHandlerBase *const &assembly_handler_pt, GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
The routine that actually does all the work!
virtual void get_previous_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > &dofs)=0
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
int nodal_local_eqn(const unsigned &n, const unsigned &i) const
Return the local equation number corresponding to the i-th value at the n-th local node...
Definition: elements.h:1386
void resize(const unsigned long &n)
Definition: matrices.h:511