refineable_linear_wave_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-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//====================================================================
27 
28 
29 namespace oomph
30 {
31  //========================================================================
32  /// Add element's contribution to the elemental
33  /// residual vector and/or Jacobian matrix.
34  /// flag=1: compute both
35  /// flag=0: compute only residual vector
36  //========================================================================
37  template<unsigned DIM>
40  Vector<double>& residuals, DenseMatrix<double>& jacobian, unsigned flag)
41  {
42  // Find out how many nodes there are in the element
43  unsigned n_node = nnode();
44 
45  // Get continuous time from timestepper of first node
46  double time = node_pt(0)->time_stepper_pt()->time_pt()->time();
47 
48  // Find the index at which the unknown is stored
49  unsigned u_nodal_index = this->u_index_lin_wave();
50 
51  // Set up memory for the shape and test functions
52  Shape psi(n_node), test(n_node);
53  DShape dpsidx(n_node, DIM), dtestdx(n_node, DIM);
54 
55  // Set the value of n_intpt
56  unsigned n_intpt = integral_pt()->nweight();
57 
58  // Set the Vector to hold local coordinates
59  Vector<double> s(DIM);
60 
61  // Integers used to store the local equation number and local unknown
62  // indices for the residuals and jacobians
63  int local_eqn = 0, local_unknown = 0;
64 
65  // Local storage for pointers to hang_info objects
66  HangInfo *hang_info_pt = 0, *hang_info2_pt = 0;
67 
68  // Loop over the integration points
69  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
70  {
71  // Assign values of s
72  for (unsigned i = 0; i < DIM; i++) s[i] = integral_pt()->knot(ipt, i);
73 
74  // Get the integral weight
75  double w = integral_pt()->weight(ipt);
76 
77  // Call the derivatives of the shape and test functions
78  double J = this->dshape_and_dtest_eulerian_at_knot_lin_wave(
79  ipt, psi, dpsidx, test, dtestdx);
80 
81  // Premultiply the weights and the Jacobian
82  double W = w * J;
83 
84  // Calculate local values of the function
85  double ddudt = 0.0;
86  double interpolated_u = 0.0;
87 
88  // This needs to be a Vector to be ANSI C++, initialise to zero
89  Vector<double> interpolated_x(DIM, 0.0);
90  Vector<double> interpolated_dudx(DIM, 0.0);
91 
92  // Calculate function value and derivatives:
93  //-----------------------------------------
94 
95  // Loop over nodes
96  for (unsigned l = 0; l < n_node; l++)
97  {
98  // Get the value at the node
99  double u_value = this->nodal_value(l, u_nodal_index);
100  interpolated_u += u_value * psi(l);
101  ddudt += this->d2u_dt2_lin_wave(l) * psi(l);
102  // Loop over directions
103  for (unsigned j = 0; j < DIM; j++)
104  {
105  interpolated_x[j] += nodal_position(l, j) * psi(l);
106  interpolated_dudx[j] += u_value * dpsidx(l, j);
107  }
108  }
109 
110  // Get body force
111  double source;
112  this->get_source_lin_wave(time, ipt, interpolated_x, source);
113 
114 
115  // Assemble residuals and Jacobian
116  //================================
117 
118  // Loop over the nodes for the test functions
119  //-------------------------------------------
120  for (unsigned l = 0; l < n_node; l++)
121  {
122  // Local variables to store the number of master nodes and
123  // the weight associated with the shape function if the node is hanging
124  unsigned n_master = 1;
125  double hang_weight = 1.0;
126  // Local bool (is the node hanging)
127  bool is_node_hanging = this->node_pt(l)->is_hanging();
128 
129 
130  // If the node is hanging, get the number of master nodes
131  if (is_node_hanging)
132  {
133  hang_info_pt = this->node_pt(l)->hanging_pt();
134  n_master = hang_info_pt->nmaster();
135  }
136  // Otherwise there is just one master node, the node itself
137  else
138  {
139  n_master = 1;
140  }
141 
142  // Loop over the number of master nodes
143  for (unsigned m = 0; m < n_master; m++)
144  {
145  // Get the local equation number and hang_weight
146  // If the node is hanging
147  if (is_node_hanging)
148  {
149  // Read out the local equation from the master node
150  local_eqn = this->local_hang_eqn(hang_info_pt->master_node_pt(m),
151  u_nodal_index);
152  // Read out the weight from the master node
153  hang_weight = hang_info_pt->master_weight(m);
154  }
155  // If the node is not hanging
156  else
157  {
158  // The local equation number comes from the node itself
159  local_eqn = this->nodal_local_eqn(l, u_nodal_index);
160  // The hang weight is one
161  hang_weight = 1.0;
162  }
163 
164  // If the nodal equation is not a boundary condition
165  if (local_eqn >= 0)
166  {
167  // Add body force/source term and time derivative
168  residuals[local_eqn] +=
169  (ddudt + source) * test(l) * W * hang_weight;
170 
171  // Laplace operator itself
172  for (unsigned k = 0; k < DIM; k++)
173  {
174  residuals[local_eqn] +=
175  interpolated_dudx[k] * dtestdx(l, k) * W * hang_weight;
176  }
177 
178  // Calculate the Jacobian
179  if (flag)
180  {
181  // Local variables to store the number of master nodes
182  // and the weights associated with each hanging node
183  unsigned n_master2 = 1;
184  double hang_weight2 = 1.0;
185  // Loop over the nodes for the variables
186  for (unsigned l2 = 0; l2 < n_node; l2++)
187  {
188  // Local bool (is the node hanging)
189  bool is_node2_hanging = this->node_pt(l2)->is_hanging();
190  // If the node is hanging, get the number of master nodes
191  if (is_node2_hanging)
192  {
193  hang_info2_pt = this->node_pt(l2)->hanging_pt();
194  n_master2 = hang_info2_pt->nmaster();
195  }
196  // Otherwise there is one master node, the node itself
197  else
198  {
199  n_master2 = 1;
200  }
201 
202  // Loop over the master nodes
203  for (unsigned m2 = 0; m2 < n_master2; m2++)
204  {
205  // Get the local unknown and weight
206  // If the node is hanging
207  if (is_node2_hanging)
208  {
209  // Read out the local unknown from the master node
210  local_unknown = this->local_hang_eqn(
211  hang_info2_pt->master_node_pt(m2), u_nodal_index);
212  // Read out the hanging weight from the master node
213  hang_weight2 = hang_info2_pt->master_weight(m2);
214  }
215  // If the node is not hanging
216  else
217  {
218  // The local unknown number comes from the node
219  local_unknown = this->nodal_local_eqn(l2, u_nodal_index);
220  // The hang weight is one
221  hang_weight2 = 1.0;
222  }
223 
224  // If the unknown is not pinned
225  if (local_unknown >= 0)
226  {
227  // Add contribution to Elemental Matrix
228  // Mass matrix
229  jacobian(local_eqn, local_unknown) +=
230  test(l) * psi(l2) *
231  this->node_pt(l2)->time_stepper_pt()->weight(2, 0) * W *
232  hang_weight * hang_weight2;
233 
234  // Laplace operator
235  for (unsigned k = 0; k < DIM; k++)
236  {
237  jacobian(local_eqn, local_unknown) +=
238  dpsidx(l2, k) * dtestdx(l, k) * W * hang_weight *
239  hang_weight2;
240  }
241  }
242  } // End of loop over master nodes
243  }
244  } // End of Jacobian calculation
245  }
246  } // End of loop over master nodes for residuals
247  } // End of loop over nodes
248 
249  } // End of loop over integration points
250  }
251 
252  //====================================================================
253  // Force build of templates
254  //====================================================================
255  template class RefineableQLinearWaveElement<2, 2>;
256  template class RefineableQLinearWaveElement<2, 3>;
257  template class RefineableQLinearWaveElement<2, 4>;
258 
259  template class RefineableQLinearWaveElement<3, 2>;
260  template class RefineableQLinearWaveElement<3, 3>;
261  template class RefineableQLinearWaveElement<3, 4>;
262 
263 } // namespace oomph
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition: shape.h:278
Class that contains data for hanging nodes.
Definition: nodes.h:742
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Definition: nodes.h:808
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
Definition: nodes.h:791
unsigned nmaster() const
Return the number of master nodes.
Definition: nodes.h:785
void fill_in_generic_residual_contribution_lin_wave(Vector< double > &residuals, DenseMatrix< double > &jacobian, unsigned flag)
Add element's contribution to elemental residual vector and/or Jacobian matrix flag=1: compute both f...
Refineable version of 2D QLinearWaveElement elements.
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
//////////////////////////////////////////////////////////////////// ////////////////////////////////...