element_with_moving_nodes.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// Functions for the ElementWithMovingNode class
28#include "geom_objects.h"
29#include "algebraic_elements.h"
30
31namespace oomph
32{
33 /////////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////
35 // Functions for the ElementWithMovingNodes class
36 ///////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////
38
39 //====================================================================
40 /// Return a set of all geometric data associated with the element's node
41 /// update function
42 //======================================================================
44 std::set<Data*>& unique_geom_data_pt)
45 {
46 // First clear the set (just in case)
47 unique_geom_data_pt.clear();
48
49 // Get number of nodes
50 const unsigned n_node = this->nnode();
51
52 // Loop over all nodes
53 for (unsigned n = 0; n < n_node; n++)
54 {
55 // Cache pointer to the Node
56 Node* const nod_pt = this->node_pt(n);
57
58 // Is the node hanging
59 const bool node_is_hanging = nod_pt->is_hanging();
60
61 // Default number of master nodes
62 unsigned nmaster = 1;
63
64 // Default: Node isn't hanging so it's its own master node
65 Node* master_node_pt = nod_pt;
66
67 // Cache the hanging point
69
70 // Find the number of master nodes if the node is hanging
72 {
73 hang_info_pt = nod_pt->hanging_pt();
74 nmaster = hang_info_pt->nmaster();
75 }
76
77 // Loop over all master nodes
78 for (unsigned imaster = 0; imaster < nmaster; imaster++)
79 {
80 // Get the master node
82 {
83 master_node_pt = hang_info_pt->master_node_pt(imaster);
84 }
85
86
87 // Find the number of data
88 const unsigned n_geom_data = master_node_pt->ngeom_data();
89 // If there are geometric data add them to the set
90 if (n_geom_data > 0)
91 {
92 // Get vector of geometric data involved in the geometric
93 // change of this node
94 Data** node_geom_data_pt = master_node_pt->all_geom_data_pt();
95
96 for (unsigned i = 0; i < n_geom_data; i++)
97 {
99 }
100 }
101
102 // Find the number of geometric objects
103 unsigned n_geom_obj = master_node_pt->ngeom_object();
104
105 // If there are geometric objects, add them to the set
106 if (n_geom_obj > 0)
107 {
108 // Get vector of geometric objects involved in the default
109 // update function for this (master) node.
110 // Vector is constructed by copy operation.
111 GeomObject** geom_object_pt = master_node_pt->all_geom_object_pt();
112
113 // Loop over the geometric objects
114 for (unsigned i = 0; i < n_geom_obj; i++)
115 {
116 // Get the next geometric object
117 GeomObject* geom_obj_pt = geom_object_pt[i];
118
119 // Number of items of geometric data that the geometric
120 // object depends on
121 unsigned n_geom_data = geom_obj_pt->ngeom_data();
122
123 // Loop over geometric data and add to set (use set to ensure
124 // that each one is only counted once)
125 for (unsigned idata = 0; idata < n_geom_data; idata++)
126 {
128 }
129 }
130 } // End of add geom object loop
131 }
132 }
133 }
134
135 //=================================================================
136 /// Construct the vector of (unique) geometric data
137 //=================================================================
139 {
140 // This set will hold the pointers to all the unique (geometric) Data that
141 // affects the shape of this element
142 std::set<Data*> unique_geom_data_pt;
143 // Assemble that data
144 this->assemble_set_of_all_geometric_data(unique_geom_data_pt);
145
146 // Resize storage for the pointers to the Data items that are
147 // involved in the element's node update operation.
148 Geom_data_pt.clear();
149
150 // Loop over all the unique remaining Data items involved in the
151 // node update operations
152 typedef std::set<Data*>::iterator IT;
153 for (IT it = unique_geom_data_pt.begin(); it != unique_geom_data_pt.end();
154 it++)
155 {
156 Geom_data_pt.push_back(*it);
157 }
158 }
159
160 //==================================================================
161 /// Function to describe the local dofs of the element[s]. The ostream
162 /// specifies the output stream to which the description
163 /// is written; the string stores the currently
164 /// assembled output that is ultimately written to the
165 /// output stream by Data::describe_dofs(...); it is typically
166 /// built up incrementally as we descend through the
167 /// call hierarchy of this function when called from
168 /// Problem::describe_dofs(...)
169 //==================================================================
171 std::ostream& out, const std::string& current_string) const
172 {
173 // Call the standard finite element classification.
175
176 // Set the number of data
177 const unsigned n_geom_data = ngeom_data();
178
179 // Loop over the node update data
180 for (unsigned i = 0; i < n_geom_data; i++)
181 {
182 // Pointer to geometric Data
184
185 std::stringstream conversion;
186 conversion << " of Geometric Data " << i << current_string;
187 std::string in(conversion.str());
189 }
190 }
191
192
193 //==================================================================
194 /// Assign local equation numbers for the geometric data associated
195 /// with the element.
196 //==================================================================
198 const bool& store_local_dof_pt)
199 {
200 // Get local number of dofs so far
201 unsigned local_eqn_number = this->ndof();
202
203 // Set the number of data
204 const unsigned n_geom_data = ngeom_data();
205
206 // Reset number of geometric dofs
207 Ngeom_dof = 0;
208
209 // If we have any geometric data
210 if (n_geom_data > 0)
211 {
212 // Work out total number of values involved
213 // Initialise from the first object
214 unsigned n_total_values = Geom_data_pt[0]->nvalue();
215
216 // Add the values from the other data
217 for (unsigned i = 1; i < n_geom_data; i++)
218 {
219 n_total_values += Geom_data_pt[i]->nvalue();
220 }
221
222 // If allocated delete the old storage
224 {
225 delete[] Geometric_data_local_eqn[0];
227 }
228
229 // If there are no values, we are done, null out the storage and
230 // return
231 if (n_total_values == 0)
232 {
234 return;
235 }
236
237 // Resize the storage for the geometric data local equation numbers
238 // Firstly allocate the row pointers
240
241 // Now allocate storage for all the equation numbers
243
244 // Initially all local equations are unclassified
245 for (unsigned i = 0; i < n_total_values; i++)
246 {
248 }
249
250 // Loop over the remaining rows and set their pointers
251 for (unsigned i = 1; i < n_geom_data; ++i)
252 {
253 // Initially set the pointer to the i-th row to the pointer
254 // to the i-1th row
256
257 // Now increase the row pointer by the number of values
258 // stored at the i-1th geometric data
259 Geometric_data_local_eqn[i] += Geom_data_pt[i - 1]->nvalue();
260 }
261
262 // A local queue to store the global equation numbers
263 std::deque<unsigned long> global_eqn_number_queue;
264
265 // Loop over the node update data
266 for (unsigned i = 0; i < n_geom_data; i++)
267 {
268 // Pointer to geometric Data
270
271 // Loop over values at this Data item
272 unsigned n_value = data_pt->nvalue();
273 for (unsigned j = 0; j < n_value; j++)
274 {
275 // Get global equation number
277
278 // If equation number positive
279 if (eqn_number >= 0)
280 {
281 // Add the global equation number to our queue
283 // Add pointer to the dof to the queue if required
285 {
286 GeneralisedElement::Dof_pt_deque.push_back(data_pt->value_pt(j));
287 }
288
289 // Add to local value
292
293 // Bump up number of geometric dofs
294 Ngeom_dof++;
295 }
296 else
297 {
298 // Set the local scheme to be pinned
300 }
301 }
302 }
303
304 // Now add our global equations numbers to the internal element storage
305 this->add_global_eqn_numbers(global_eqn_number_queue,
307 // Clear the memory used in the deque
309 {
310 std::deque<double*>().swap(GeneralisedElement::Dof_pt_deque);
311 }
312 }
313 }
314
315
316 //==================================================================
317 /// Calculate the node-update--related entries in the
318 /// Jacobian. The vector passed
319 /// in residuals has to contain the nonlinear residuals,
320 /// evaluated for the current values of the unknowns, in
321 /// case FDing is used to computed the derivatives.
322 //==================================================================
325 {
327 {
328 // Get number of Data items involved in node update operations
329 const unsigned n_geometric_data = ngeom_data();
330
331 // If there is nothing to be done, then leave
332 if (n_geometric_data == 0) return;
333
334 // Number of dofs
335 const unsigned n_dof = this->ndof();
336
337 // Number of nodes
338 unsigned n_nod = this->nnode();
339
340 // If there are no dofs, return
341 if (n_nod == 0) return;
342
343 // Get nodal dimension from first node
344 const unsigned dim_nod = node_pt(0)->ndim();
345
346 // Number of shape controlling nodes for nonrefineable elements
347 unsigned n_shape_controlling_node = nnode();
348
349 // Are we dealing with a refineable element?
350 RefineableElement* ref_el_pt = dynamic_cast<RefineableElement*>(this);
351 if (ref_el_pt != 0)
352 {
353 // Adjust number of shape controlling nodes
354 n_shape_controlling_node = ref_el_pt->nshape_controlling_nodes();
355 }
356
357 // How are we going to evaluate the shape derivs?
358 unsigned method = 0;
360 {
361 method = 0;
362 }
364 {
365 method = 1;
366 }
368 {
369 // Direct FD-ing of residuals w.r.t. geometric dofs is likely to be
370 // faster if there are fewer geometric dofs than total nodal coordinates
371 // (nodes x dim) in element:
373 {
374 method = 0;
375 }
376 else
377 {
378 method = 1;
379 }
380 }
381
382 // Choose method
383 //===============
384 switch (method)
385 {
386 // Direct FD:
387 //-----------
388 case 0:
389
390 {
391 // Create newres vector
393
394 // Use the default finite difference step
396
397 // Integer storage for the local unknown
398 int local_unknown = 0;
399
400 // Loop over the Data items that affect the node update operations
401 for (unsigned i = 0; i < n_geometric_data; i++)
402 {
403 // Loop over values
404 unsigned n_value = Geom_data_pt[i]->nvalue();
405 for (unsigned j = 0; j < n_value; j++)
406 {
408
409 // If the value is free
410 if (local_unknown >= 0)
411 {
412 // Get a pointer to the geometric data value
413 double* value_pt = Geom_data_pt[i]->value_pt(j);
414
415 // Save the old value
416 double old_var = *value_pt;
417
418 // Increment the variable
419 *value_pt += fd_step;
420
421 // Update the whole element (Bit inefficient)
422 this->node_update();
423
424 // Calculate the new residuals
425 this->get_residuals(newres);
426
427 // Now do finite differences
428 for (unsigned m = 0; m < n_dof; m++)
429 {
430 // Stick the entry into the Jacobian matrix
431 jacobian(m, local_unknown) =
432 (newres[m] - residuals[m]) / fd_step;
433 }
434
435 // Reset the variable
436 *value_pt = old_var;
437
438 // We're relying on the total node update in the next loop
439 }
440 }
441 }
442
443 // Node update the element one final time to get things back to
444 // the original state
445 this->node_update();
446 }
447
448 break;
449
450 // Chain rule
451 //-----------
452 case 1:
453
454 {
455 // Get derivatives of residuals w.r.t. all nodal coordinates
458
459 // Use FD-version in base class?
461 {
462 if (ref_el_pt != 0)
463 {
464 ref_el_pt->RefineableElement::get_dresidual_dnodal_coordinates(
466 }
467 else
468 {
471 }
472 }
473 // Otherwise use the overloaded analytical version in derived
474 // class (if it exists -- if it doesn't this just drops through
475 // to the default implementation in FiniteElement).
476 else
477 {
479 dresidual_dnodal_coordinates);
480 }
481
482 // Get derivatives of nodal coordinates w.r.t. geometric dofs
485
487
488 // Assemble Jacobian via chain rule
489 for (unsigned l = 0; l < n_dof; l++)
490 {
491 // Loop over the Data items that affect the node update operations
492 for (unsigned i_data = 0; i_data < n_geometric_data; i_data++)
493 {
494 // Loop over values
495 unsigned n_value = Geom_data_pt[i_data]->nvalue();
496 for (unsigned j_val = 0; j_val < n_value; j_val++)
497 {
499
500 // If the value is free
501 if (k >= 0)
502 {
503 jacobian(l, k) = 0.0;
504 for (unsigned i = 0; i < dim_nod; i++)
505 {
506 for (unsigned j = 0; j < n_shape_controlling_node; j++)
507 {
508 jacobian(l, k) += dresidual_dnodal_coordinates(l, i, j) *
510 }
511 }
512 }
513 }
514 }
515 }
516 }
517
518 break;
519
520 default:
521
522 std::ostringstream error_message;
523 error_message << "Never get here: method " << method;
524 throw OomphLibError(error_message.str(),
527 }
528 }
529 }
530
531
532 //======================================================================
533 /// Compute derivatives of the nodal coordinates w.r.t.
534 /// to the geometric dofs. Default implementation by FD can be overwritten
535 /// for specific elements.
536 /// dnodal_coordinates_dgeom_dofs(l,i,j) = dX_{ij} / d s_l
537 //======================================================================
540 {
541 // Get number of Data items involved in node update operations
542 const unsigned n_geometric_data = ngeom_data();
543
544 // If there is nothing to be done, then leave
545 if (n_geometric_data == 0)
546 {
547 return;
548 }
549
550 // Number of nodes
551 const unsigned n_nod = nnode();
552
553 // If the element has no nodes (why??!!) return straightaway
554 if (n_nod == 0) return;
555
556 // Get dimension from first node
557 unsigned dim_nod = node_pt(0)->ndim();
558
559 // Number of shape controlling nodes for nonrefineable elements
561
562 // Are we dealing with a refineable element?
563 RefineableElement* ref_el_pt = dynamic_cast<RefineableElement*>(this);
564 if (ref_el_pt != 0)
565 {
566 // Adjust number of shape controlling nodes
567 n_shape_controlling_node = ref_el_pt->nshape_controlling_nodes();
568 }
569
570 // Current and advanced nodal positions
572
573 // Shape controlling nodes
574 std::map<Node*, unsigned> local_shape_controlling_node_lookup;
575
576 // Refineable element:
577 if (ref_el_pt != 0)
578 {
580 ref_el_pt->shape_controlling_node_lookup();
581 }
582 // Non-refineable element: the nodes themselves
583 else
584 {
585 unsigned count = 0;
586 for (unsigned j = 0; j < n_nod; j++)
587 {
589 count++;
590 }
591 }
592
593 // Loop over all shape-controlling nodes to backup their original position
594 for (std::map<Node*, unsigned>::iterator it =
597 it++)
598 {
599 // Get node
600 Node* nod_pt = it->first;
601
602 // Get its number
603 unsigned node_number = it->second;
604
605 // Backup
606 for (unsigned i = 0; i < dim_nod; i++)
607 {
609 }
610 }
611
612
613 // Integer storage for the local unknown
614 int local_unknown = 0;
615
616 // Use the default finite difference step
618
619 // Loop over the Data items that affect the node update operations
620 for (unsigned i = 0; i < n_geometric_data; i++)
621 {
622 // Loop over values
623 unsigned n_value = Geom_data_pt[i]->nvalue();
624 for (unsigned j = 0; j < n_value; j++)
625 {
627
628 // If the value is free
629 if (local_unknown >= 0)
630 {
631 // Get a pointer to the geometric data value
632 double* value_pt = Geom_data_pt[i]->value_pt(j);
633
634 // Save the old value
635 double old_var = *value_pt;
636
637 // Increment the variable
638 *value_pt += fd_step;
639
640 // Update the whole element
641 this->node_update();
642
643 // Loop over all shape-controlling nodes
644 for (std::map<Node*, unsigned>::iterator it =
647 it++)
648 {
649 // Get node
650 Node* nod_pt = it->first;
651
652 // Get its number
653 unsigned node_number = it->second;
654
655 // Get advanced position and FD
656 for (unsigned ii = 0; ii < dim_nod; ii++)
657 {
660 }
661 }
662
663 // Reset the variable
664 *value_pt = old_var;
665
666 // We're relying on the total node update in the next loop
667 }
668 }
669 }
670 // Node update the element one final time to get things back to
671 // the original state
672 this->node_update();
673 }
674
675} // namespace oomph
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
static long Is_pinned
Static "Magic number" used in place of the equation number to indicate that the value is pinned.
Definition nodes.h:183
static long Is_unclassified
Static "Magic number" used in place of the equation number to denote a value that hasn't been classif...
Definition nodes.h:192
Vector< Data * > Geom_data_pt
Vector that stores pointers to all Data that affect the node update operations, i....
int geometric_data_local_eqn(const unsigned &n, const unsigned &i)
Return the local equation number corresponding to the i-th value at the n-th geometric data object.
unsigned Ngeom_dof
Number of geometric dofs (computed on the fly when equation numbers are set up)
bool Evaluate_dresidual_dnodal_coordinates_by_fd
Boolean to decide if shape derivatives are to be evaluated by fd (using FiniteElement::get_dresidual_...
virtual void assign_all_generic_local_eqn_numbers(const bool &store_local_dof_pt)
Assign local equation numbers for the geometric Data in the element If the boolean argument is true t...
virtual void get_dnodal_coordinates_dgeom_dofs(RankThreeTensor< double > &dnodal_coordinates_dgeom_dofs)
Compute derivatives of the nodal coordinates w.r.t. to the geometric dofs. Default implementation by ...
bool Bypass_fill_in_jacobian_from_geometric_data
Set flag to true to bypass calculation of Jacobain entries resulting from geometric data.
void complete_setup_of_dependencies()
Construct the vector of (unique) geometric data.
int Method_for_shape_derivs
Choose method for evaluation of shape derivatives (this takes one of the values in the enumeration)
void describe_local_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the local dofs of the element. The ostream specifies the output stream to which ...
unsigned ngeom_data() const
Return the number of geometric data upon which the shape of the element depends.
void assemble_set_of_all_geometric_data(std::set< Data * > &unique_geom_data_pt)
Return a set of all geometric data associated with the element.
void fill_in_jacobian_from_geometric_data(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Calculate the contributions to the Jacobian matrix from the geometric data. This version assumes that...
int ** Geometric_data_local_eqn
Array to hold local eqn number information for the geometric Data variables.
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the parametrised position of the FiniteElement in its incarnation as a GeomObject,...
Definition elements.h:2680
Data * geom_data_pt(const unsigned &j)
A standard FiniteElement is fixed, so there are no geometric data when viewed in its GeomObject incar...
Definition elements.h:2671
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
virtual void describe_local_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the local dofs of the element[s]. The ostream specifies the output stream to whi...
Definition elements.cc:1737
virtual void node_update()
Update the positions of all nodes in the element using each node update function. The default impleme...
Definition elements.cc:5102
unsigned ngeom_data() const
A standard FiniteElement is fixed, so there are no geometric data when viewed in its GeomObject incar...
Definition elements.h:2664
virtual void get_dresidual_dnodal_coordinates(RankThreeTensor< double > &dresidual_dnodal_coordinates)
Compute derivatives of elemental residual vector with respect to nodal coordinates....
Definition elements.cc:3774
static double Default_fd_jacobian_step
Double used for the default finite difference step in elemental jacobian calculations.
Definition elements.h:1185
unsigned ndof() const
Return the number of equations/dofs in the element.
Definition elements.h:822
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:691
int local_eqn_number(const unsigned long &ieqn_global) const
Return the local equation number corresponding to the ieqn_global-th global equation number....
Definition elements.h:713
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:967
void add_global_eqn_numbers(std::deque< unsigned long > const &global_eqn_numbers, std::deque< double * > const &global_dof_pt)
Add the contents of the queue global_eqn_numbers to the local storage for the local-to-global transla...
Definition elements.cc:161
static std::deque< double * > Dof_pt_deque
Static storage for deque used to add_global_equation_numbers when pointers to the dofs in each elemen...
Definition elements.h:231
void describe_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the dofs of the element. The ostream specifies the output stream to which the de...
Definition elements.cc:556
A geometric object is an object that provides a parametrised description of its shape via the functio...
Class that contains data for hanging nodes.
Definition nodes.h:742
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
virtual unsigned ngeom_object() const
Return the number of geometric objects that affect the nodal position. The default value is zero (nod...
Definition nodes.h:1639
virtual GeomObject ** all_geom_object_pt()
Return a pointer to an array of all (geometric) objects that affect the nodal position....
Definition nodes.h:1647
virtual Data ** all_geom_data_pt()
Return a pointer to an array of all (geometric) data that affect the nodal position....
Definition nodes.h:1632
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition nodes.h:1054
virtual unsigned ngeom_data() const
Return the number of geometric data that affect the nodal position. The default value is zero (node i...
Definition nodes.h:1625
An OomphLibError object which should be thrown when an run-time error is encountered....
RefineableElements are FiniteElements that may be subdivided into children to provide a better local ...
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).