geom_objects.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-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#ifndef OOMPH_GEOM_OBJECTS_HEADER
27#define OOMPH_GEOM_OBJECTS_HEADER
28
29
30// Config header
31#ifdef HAVE_CONFIG_H
32#include <oomph-lib-config.h>
33#endif
34
35// oomph-lib headers
36#include "nodes.h"
37#include "timesteppers.h"
38
39
40namespace oomph
41{
42 ////////////////////////////////////////////////////////////////////////
43 ////////////////////////////////////////////////////////////////////////
44 // Geometric object
45 ////////////////////////////////////////////////////////////////////////
46 ////////////////////////////////////////////////////////////////////////
47
48
49 //========================================================================
50 /// A geometric object is an object that provides a parametrised
51 /// description of its shape via the function GeomObject::position(...).
52 ///
53 /// The minimum functionality is: The geometric object has
54 /// a number of Lagrangian (intrinsic) coordinates that parametrise
55 /// the (Eulerian) position vector, whose dimension might
56 /// differ from the number of Lagrangian (intrinsic) coordinates (e.g.
57 /// for shell-like objects).
58 ///
59 /// We might also need the derivatives of the position
60 /// Vector w.r.t. to the Lagrangian (intrinsic) coordinates and interfaces
61 /// for this functionality are provided.
62 /// [Note: For some geometric objects it might be too tedious to work out
63 /// the derivatives and they might not be needed anyway. In other
64 /// cases we might always need the position vector and all
65 /// derivatives at the same time. We provide suitable interfaces
66 /// for these cases in virtual but broken (rather than pure virtual) form
67 /// so the user can (but doesn't have to) provide the required versions
68 /// by overloading.]
69 ///
70 /// The shape of a geometric object is usually determined by a number
71 /// of parameters whose value might have to be determined as part
72 /// of the overall solution (e.g. for geometric objects that represent
73 /// elastic walls). The geometric object
74 /// therefore has a vector of (pointers to) geometric Data,
75 /// which can be free/pinned and have a time history, etc. This makes
76 /// it possible to `upgrade' GeomObjects to GeneralisedElements -- in this
77 /// case the geometric Data plays the role of internal Data in the
78 /// GeneralisedElement. Conversely, FiniteElements, in which a geometry
79 /// (spatial coordinate) has been defined, inherit from GeomObjects,
80 /// which is particularly useful in FSI computations:
81 /// Meshing of moving domains is typically performed by representing the
82 /// domain as an object of type Domain and, by default, Domain boundaries are
83 /// represented by GeomObjects. In FSI computations, the boundary
84 /// of the fluid domain is represented by a number of solid mechanics
85 /// elements. These elements are, in fact, GeomObjects via inheritance so
86 /// that the we can use the standard interfaces of the GeomObject class for
87 /// mesh generation. An example is the class \c FSIHermiteBeamElement which is
88 /// derived from the class \c HermiteBeamElement (a `normal' beam element) and
89 /// the \c GeomObject class.
90 ///
91 /// The shape of a geometric object can have an explicit time-dependence, for
92 /// instance in cases where a domain boundary is performing
93 /// prescribed motions. We provide access to the `global'
94 /// time by giving the object a pointer to a timestepping scheme.
95 /// [Note that, within the overall FE code, time is only ever evaluated at
96 /// discrete instants (which are accessible via the timestepper),
97 /// never in continuous form]. The timestepper is also needed to evaluate
98 /// time-derivatives if the geometric Data carries a time history.
99 //========================================================================
101 {
102 public:
103 /// Default constructor.
105
106 /// Constructor: Pass dimension of geometric object (# of Eulerian
107 /// coords = # of Lagrangian coords; no time history available/needed)
108 GeomObject(const unsigned& ndim)
110 {
111 }
112
113
114 /// Constructor: pass # of Eulerian and Lagrangian coordinates.
115 /// No time history available/needed
116 GeomObject(const unsigned& nlagrangian, const unsigned& ndim)
118 {
119#ifdef PARANOID
120 if (nlagrangian > ndim)
121 {
122 std::ostringstream error_message;
123 error_message << "# of Lagrangian coordinates " << nlagrangian
124 << " cannot be bigger than # of Eulerian ones " << ndim
125 << std::endl;
126
127 throw OomphLibError(error_message.str(),
130 }
131#endif
132 }
133
134 /// Constructor: pass # of Eulerian and Lagrangian coordinates
135 /// and pointer to time-stepper which is used to handle the
136 /// position at previous timesteps and allows the evaluation
137 /// of veloc/acceleration etc. in cases where the GeomData
138 /// varies with time.
139 GeomObject(const unsigned& nlagrangian,
140 const unsigned& ndim,
143 Ndim(ndim),
145 {
146#ifdef PARANOID
147 if (nlagrangian > ndim)
148 {
149 std::ostringstream error_message;
150 error_message << "# of Lagrangian coordinates " << nlagrangian
151 << " cannot be bigger than # of Eulerian ones " << ndim
152 << std::endl;
153
154 throw OomphLibError(error_message.str(),
157 }
158#endif
159 }
160
161 /// Broken copy constructor
162 GeomObject(const GeomObject& dummy) = delete;
163
164 /// Broken assignment operator
165 void operator=(const GeomObject&) = delete;
166
167 /// (Empty) destructor
168 virtual ~GeomObject() {}
169
170 /// Access function to # of Lagrangian coordinates
171 unsigned nlagrangian() const
172 {
173 return NLagrangian;
174 }
175
176 /// Access function to # of Eulerian coordinates
177 unsigned ndim() const
178 {
179 return Ndim;
180 }
181
182 /// Set # of Lagrangian and Eulerian coordinates
184 const unsigned& n_dim)
185 {
187 Ndim = n_dim;
188 }
189
190 /// Access function for pointer to time stepper: Null if object is
191 /// not time-dependent
196
197 /// Access function for pointer to time stepper: Null if object is
198 /// not time-dependent. Const version
203
204 /// How many items of Data does the shape of the object depend on?
205 /// This is implemented as a broken virtual function. You must overload
206 /// this for GeomObjects that contain geometric Data, i.e. GeomObjects
207 /// whose shape depends on Data that may contain unknowns in the
208 /// overall Problem.
209 virtual unsigned ngeom_data() const
210 {
211 std::ostringstream error_message;
212 error_message
213 << "GeomObject::ngeom_data() is a broken virtual function.\n"
214 << "Please implement it (and its companion "
215 "GeomObject::geom_data_pt())\n"
216 << "for any GeomObject whose shape depends on Data whose values may \n"
217 << "be unknowns in the global Problem. \n"
218 << "If you have arrived here in a parallel job then it may be the case "
219 "\n"
220 << "that you have not set the keep_all_elements_as_halos() flag to "
221 "true \n"
222 << "for the MeshAsGeomObject representing the lower-dimensional mesh \n"
223 << "in a problem with multiple meshes. \n";
224 throw OomphLibError(
226 }
227
228 /// Return pointer to the j-th Data item that the object's
229 /// shape depends on. This is implemented as a broken virtual function.
230 /// You must overload this for GeomObjects that contain geometric Data,
231 /// i.e. GeomObjects whose shape depends on Data that may contain
232 /// unknowns in the overall Problem.
233 virtual Data* geom_data_pt(const unsigned& j)
234 {
235 std::ostringstream error_message;
236 error_message
237 << "GeomObject::geom_data_pt() is a broken virtual function.\n"
238 << "Please implement it (and its companion GeomObject::ngeom_data())\n"
239 << "for any GeomObject whose shape depends on Data whose values may \n"
240 << "be unknowns in the global Problem. \n"
241 << "If you have arrived here in a parallel job then it may be the case "
242 "\n"
243 << "that you have not set the keep_all_elements_as_halos() flag to "
244 "true \n"
245 << "for the MeshAsGeomObject representing the lower-dimensional mesh \n"
246 << "in a problem with multiple meshes. \n";
247 throw OomphLibError(
249 }
250
251 /// Parametrised position on object at current time: r(zeta).
252 virtual void position(const Vector<double>& zeta,
253 Vector<double>& r) const = 0;
254
255 /// Parametrised position on object: r(zeta). Evaluated at
256 /// previous timestep. t=0: current time; t>0: previous
257 /// timestep. Works for t=0 but needs to be overloaded
258 /// if genuine time-dependence is required.
259 virtual void position(const unsigned& t,
260 const Vector<double>& zeta,
261 Vector<double>& r) const
262 {
263 if (t != 0)
264 {
265 throw OomphLibError(
266 "Calling steady position() from discrete unsteady position()",
269 }
270 position(zeta, r);
271 }
272
273
274 /// Parametrised position on object: r(zeta). Evaluated at
275 /// the continuous time value, t.
276 virtual void position(const double& t,
277 const Vector<double>& zeta,
278 Vector<double>& r) const
279 {
280 std::ostringstream error_message;
281 error_message << "GeomObject::position() is a broken virtual function.\n"
282 << "Please implement it for any GeomObject whose shape\n"
283 << "is time-dependent and will be used in the extrusion\n"
284 << "of a mesh (in the time direction).\n";
285 throw OomphLibError(
287 }
288
289
290 /// j-th time-derivative on object at current time:
291 /// \f$ \frac{d^{j} r(\zeta)}{dt^j} \f$.
292 virtual void dposition_dt(const Vector<double>& zeta,
293 const unsigned& j,
295 {
296 // If the index is zero the return the position
297 if (j == 0)
298 {
300 }
301 // Otherwise assume that the geometric object is static
302 // and return zero after throwing a warning
303 else
304 {
305 std::ostringstream warning_stream;
307 << "Using default (static) assignment " << j
308 << "-th time derivative in GeomObject::dposition_dt(...) is zero\n"
309 << "Overload for your specific geometric object if this is not \n"
310 << "appropriate. \n";
312 "GeomObject::dposition_dt()",
314
315 unsigned n = drdt.size();
316 for (unsigned i = 0; i < n; i++)
317 {
318 drdt[i] = 0.0;
319 }
320 }
321 }
322
323
324 /// Derivative of position Vector w.r.t. to coordinates:
325 /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
326 /// Evaluated at current time.
327 virtual void dposition(const Vector<double>& zeta,
329 {
330 throw OomphLibError(
331 "You must specify dposition() for your own object! \n",
334 }
335
336
337 /// 2nd derivative of position Vector w.r.t. to coordinates:
338 /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
339 /// ddrdzeta(alpha,beta,i).
340 /// Evaluated at current time.
341 virtual void d2position(const Vector<double>& zeta,
343 {
344 throw OomphLibError(
345 "You must specify d2position() for your own object! \n",
348 }
349
350
351 /// Posn Vector and its 1st & 2nd derivatives
352 /// w.r.t. to coordinates:
353 /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
354 /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
355 /// ddrdzeta(alpha,beta,i).
356 /// Evaluated at current time.
357 virtual void d2position(const Vector<double>& zeta,
361 {
362 throw OomphLibError(
363 "You must specify d2position() for your own object! \n",
366 }
367
368 /// A geometric object may be composed of may sub-objects (e.g.
369 /// a finite-element representation of a boundary). In order to implement
370 /// sparse update functions, it is necessary to know the sub-object
371 /// and local coordinate within
372 /// that sub-object at a given intrinsic coordinate, zeta. Note that only
373 /// one sub-object can "cover" any given intrinsic position. If the position
374 /// is at an "interface" between sub-objects, either one can be returned.
375 /// The default implementation merely returns, the pointer to the "entire"
376 /// GeomObject and the coordinate, zeta
377 /// The optional boolean flag only applies if a Newton method is used to
378 /// find the value of zeta, and if true the value of the coordinate
379 /// s is used as the initial guess for the method. If the flag is false
380 /// (the default) a value of s=0 is used as the initial guess.
381 virtual void locate_zeta(
382 const Vector<double>& zeta,
385 const bool& use_coordinate_as_initial_guess = false)
386 {
387 // By default, the local coordinate is intrinsic coordinate
388 s = zeta;
389 // The sub_object is the entire object
390 sub_geom_object_pt = this;
391 }
392
393 /// A geometric object may be composed of many sub-objects
394 /// each with their own local coordinate. This function returns the
395 /// "global" intrinsic coordinate zeta (within the compound object), at
396 /// a given local coordinate s (i.e. the intrinsic coordinate of the
397 /// sub-GeomObject. In simple (non-compound) GeomObjects, the local
398 /// intrinsic coordinate is the global intrinsic coordinate
399 /// and so the function merely returns s. To make it less likely
400 /// that the default implementation is called in error (because
401 /// it is not overloaded in a derived GeomObject where the default
402 /// is not appropriate, we do at least check that s and zeta
403 /// have the same size if called in PARANOID mode.
404 virtual void interpolated_zeta(const Vector<double>& s,
405 Vector<double>& zeta) const
406 {
407#ifdef PARANOID
408 if (zeta.size() != s.size())
409 {
410 std::ostringstream error_message;
411 error_message << "You've called the default implementation of "
412 << "GeomObject::interpolated_zeta() \n"
413 << "but zeta.size()=" << zeta.size()
414 << "and s.size()=" << s.size() << std::endl
415 << "This doesn't make sense! You probably have to \n"
416 << "overload this function in your specific GeomObject\n";
417 throw OomphLibError(error_message.str(),
420 }
421#endif
422 // By default the global intrinsic coordinate is equal to the local one
423 zeta = s;
424 }
425
426 protected:
427 /// Number of Lagrangian (intrinsic) coordinates
428 unsigned NLagrangian;
429
430 /// Number of Eulerian coordinates
431 unsigned Ndim;
432
433 /// Timestepper (used to handle access to geometry
434 /// at previous timesteps)
436 };
437
438
439 ///////////////////////////////////////////////////////////////////////
440 ///////////////////////////////////////////////////////////////////////
441 // Straight line as geometric object
442 ///////////////////////////////////////////////////////////////////////
443 ///////////////////////////////////////////////////////////////////////
444
445
446 //=========================================================================
447 /// Steady, straight 1D line in 2D space
448 /// \f[ x = \zeta \f]
449 /// \f[ y = H \f]
450 //=========================================================================
452 {
453 public:
454 /// Constructor: One item of geometric data:
455 /// \code
456 /// Geom_data_pt[0]->value(0) = height
457 /// \endcode
459 {
460#ifdef PARANOID
461 if (geom_data_pt.size() != 1)
462 {
463 std::ostringstream error_message;
464 error_message << "geom_data_pt should have size 1, not "
465 << geom_data_pt.size() << std::endl;
466
467 if (geom_data_pt[0]->nvalue() != 1)
468 {
469 error_message << "geom_data_pt[0] should have 1 value, not "
470 << geom_data_pt[0]->nvalue() << std::endl;
471 }
472
473 throw OomphLibError(error_message.str(),
476 }
477#endif
478 Geom_data_pt.resize(1);
480
481 // Data has been created externally: Must not clean up
482 Must_clean_up = false;
483 }
484
485 /// Constructor: Pass height (pinned by default)
486 StraightLine(const double& height) : GeomObject(1, 2)
487 {
488 // Create Data for straight-line object: The only geometric data is the
489 // height which is pinned
490 Geom_data_pt.resize(1);
491
492 // Create data: One value, no timedependence, free by default
493 Geom_data_pt[0] = new Data(1);
494
495 // I've created the data, I need to clean up
496 Must_clean_up = true;
497
498 // Pin the data
499 Geom_data_pt[0]->pin(0);
500
501 // Give it a value: Initial height
502 Geom_data_pt[0]->set_value(0, height);
503 }
504
505
506 /// Broken copy constructor
508
509 /// Broken assignment operator
510 void operator=(const StraightLine&) = delete;
511
512 /// Destructor: Clean up if necessary
514 {
515 // Do I need to clean up?
516 if (Must_clean_up)
517 {
518 delete Geom_data_pt[0];
519 Geom_data_pt[0] = 0;
520 }
521 }
522
523
524 /// Position Vector at Lagrangian coordinate zeta
526 {
527 // Position Vector
528 r[0] = zeta[0];
529 r[1] = Geom_data_pt[0]->value(0);
530 }
531
532
533 /// Parametrised position on object: r(zeta). Evaluated at
534 /// previous timestep. t=0: current time; t>0: previous
535 /// timestep.
536 void position(const unsigned& t,
537 const Vector<double>& zeta,
538 Vector<double>& r) const
539 {
540#ifdef PARANOID
541 if (t > Geom_data_pt[0]->time_stepper_pt()->nprev_values())
542 {
543 std::ostringstream error_message;
544 error_message << "t > nprev_values() " << t << " "
546 << std::endl;
547
548 throw OomphLibError(error_message.str(),
551 }
552#endif
553
554 // Position Vector at time level t
555 r[0] = zeta[0];
556 r[1] = Geom_data_pt[0]->value(t, 0);
557 }
558
559
560 /// Derivative of position Vector w.r.t. to coordinates:
561 /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
562 /// Evaluated at current time.
563 virtual void dposition(const Vector<double>& zeta,
565 {
566 // Tangent vector
567 drdzeta(0, 0) = 1.0;
568 drdzeta(0, 1) = 0.0;
569 }
570
571
572 /// 2nd derivative of position Vector w.r.t. to coordinates:
573 /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
574 /// ddrdzeta(alpha,beta,i). Evaluated at current time.
575 virtual void d2position(const Vector<double>& zeta,
577 {
578 // Derivative of tangent vector
579 ddrdzeta(0, 0, 0) = 0.0;
580 ddrdzeta(0, 0, 1) = 0.0;
581 }
582
583
584 /// Posn Vector and its 1st & 2nd derivatives
585 /// w.r.t. to coordinates:
586 /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
587 /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
588 /// ddrdzeta(alpha,beta,i).
589 /// Evaluated at current time.
590 virtual void d2position(const Vector<double>& zeta,
594 {
595 // Position Vector
596 r[0] = zeta[0];
597 r[1] = Geom_data_pt[0]->value(0);
598
599 // Tangent vector
600 drdzeta(0, 0) = 1.0;
601 drdzeta(0, 1) = 0.0;
602
603 // Derivative of tangent vector
604 ddrdzeta(0, 0, 0) = 0.0;
605 ddrdzeta(0, 0, 1) = 0.0;
606 }
607
608
609 /// How many items of Data does the shape of the object depend on?
610 unsigned ngeom_data() const
611 {
612 return Geom_data_pt.size();
613 }
614
615 /// Return pointer to the j-th Data item that the object's
616 /// shape depends on
617 Data* geom_data_pt(const unsigned& j)
618 {
619 return Geom_data_pt[j];
620 }
621
622 private:
623 /// Vector of pointers to Data items that affects the object's shape
625
626 /// Do I need to clean up?
628 };
629
630
631 ///////////////////////////////////////////////////////////////////////
632 ///////////////////////////////////////////////////////////////////////
633 // Ellipse as geometric object
634 ///////////////////////////////////////////////////////////////////////
635 ///////////////////////////////////////////////////////////////////////
636
637
638 //=========================================================================
639 /// Steady ellipse with half axes A and B as geometric object:
640 /// \f[ x = A \cos(\zeta) \f]
641 /// \f[ y = B \sin(\zeta) \f]
642 //=========================================================================
643 class Ellipse : public GeomObject
644 {
645 public:
646 /// Constructor: 1 Lagrangian coordinate, 2 Eulerian coords. Pass
647 /// half axes as Data:
648 /// \code
649 /// Geom_data_pt[0]->value(0) = A
650 /// Geom_data_pt[0]->value(1) = B
651 /// \endcode
653 {
654#ifdef PARANOID
655 if (geom_data_pt.size() != 1)
656 {
657 std::ostringstream error_message;
658 error_message << "geom_data_pt should have size 1, not "
659 << geom_data_pt.size() << std::endl;
660
661 if (geom_data_pt[0]->nvalue() != 2)
662 {
663 error_message << "geom_data_pt[0] should have 2 values, not "
664 << geom_data_pt[0]->nvalue() << std::endl;
665 }
666
667 throw OomphLibError(error_message.str(),
670 }
671#endif
672 Geom_data_pt.resize(1);
674
675 // Data has been created externally: Must not clean up
676 Must_clean_up = false;
677 }
678
679
680 /// Constructor: 1 Lagrangian coordinate, 2 Eulerian coords. Pass
681 /// half axes A and B; both pinned.
682 Ellipse(const double& A, const double& B) : GeomObject(1, 2)
683 {
684 // Resize Data for ellipse object:
685 Geom_data_pt.resize(1);
686
687 // Create data: Two values, no timedependence, free by default
688 Geom_data_pt[0] = new Data(2);
689
690 // I've created the data, I need to clean up
691 Must_clean_up = true;
692
693 // Pin the data
694 Geom_data_pt[0]->pin(0);
695 Geom_data_pt[0]->pin(1);
696
697 // Set half axes
698 Geom_data_pt[0]->set_value(0, A);
699 Geom_data_pt[0]->set_value(1, B);
700 }
701
702 /// Broken copy constructor
703 Ellipse(const Ellipse& dummy) = delete;
704
705 /// Broken assignment operator
706 void operator=(const Ellipse&) = delete;
707
708 /// Destructor: Clean up if necessary
710 {
711 // Do I need to clean up?
712 if (Must_clean_up)
713 {
714 delete Geom_data_pt[0];
715 Geom_data_pt[0] = 0;
716 }
717 }
718
719 /// Set horizontal half axis
720 void set_A_ellips(const double& a)
721 {
722 Geom_data_pt[0]->set_value(0, a);
723 }
724
725 /// Set vertical half axis
726 void set_B_ellips(const double& b)
727 {
728 Geom_data_pt[0]->set_value(1, b);
729 }
730
731 /// Access function for horizontal half axis
732 double a_ellips()
733 {
734 return Geom_data_pt[0]->value(0);
735 }
736
737 /// Access function for vertical half axis
738 double b_ellips()
739 {
740 return Geom_data_pt[0]->value(1);
741 }
742
743
744 /// Position Vector at Lagrangian coordinate zeta
746 {
747 // Position Vector
748 r[0] = Geom_data_pt[0]->value(0) * cos(zeta[0]);
749 r[1] = Geom_data_pt[0]->value(1) * sin(zeta[0]);
750 }
751
752
753 /// Parametrised position on object: r(zeta). Evaluated at
754 /// previous timestep. t=0: current time; t>0: previous
755 /// timestep.
756 void position(const unsigned& t,
757 const Vector<double>& zeta,
758 Vector<double>& r) const
759 {
760 // If we have done the construction, it's a Steady Ellipse,
761 // so all time-history values of the position are equal to the position
762 if (Must_clean_up)
763 {
764 position(zeta, r);
765 return;
766 }
767
768 // Otherwise check that the value of t is within range
769#ifdef PARANOID
770 if (t > Geom_data_pt[0]->time_stepper_pt()->nprev_values())
771 {
772 std::ostringstream error_message;
773 error_message << "t > nprev_values() " << t << " "
775 << std::endl;
776
777 throw OomphLibError(error_message.str(),
780 }
781#endif
782
783 // Position Vector
784 r[0] = Geom_data_pt[0]->value(t, 0) * cos(zeta[0]);
785 r[1] = Geom_data_pt[0]->value(t, 1) * sin(zeta[0]);
786 }
787
788
789 /// Derivative of position Vector w.r.t. to coordinates:
790 /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
793 {
794 // Components of the single tangent Vector
795 drdzeta(0, 0) = -Geom_data_pt[0]->value(0) * sin(zeta[0]);
796 drdzeta(0, 1) = Geom_data_pt[0]->value(1) * cos(zeta[0]);
797 }
798
799
800 /// 2nd derivative of position Vector w.r.t. to coordinates:
801 /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
802 /// ddrdzeta(alpha,beta,i).
803 /// Evaluated at current time.
806 {
807 // Components of the derivative of the tangent Vector
808 ddrdzeta(0, 0, 0) = -Geom_data_pt[0]->value(0) * cos(zeta[0]);
809 ddrdzeta(0, 0, 1) = -Geom_data_pt[0]->value(1) * sin(zeta[0]);
810 }
811
812 /// Position Vector and 1st and 2nd derivs to coordinates:
813 /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
814 /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
815 /// ddrdzeta(alpha,beta,i).
816 /// Evaluated at current time.
821 {
822 double a = Geom_data_pt[0]->value(0);
823 double b = Geom_data_pt[0]->value(1);
824 // Position Vector
825 r[0] = a * cos(zeta[0]);
826 r[1] = b * sin(zeta[0]);
827
828 // Components of the single tangent Vector
829 drdzeta(0, 0) = -a * sin(zeta[0]);
830 drdzeta(0, 1) = b * cos(zeta[0]);
831
832 // Components of the derivative of the tangent Vector
833 ddrdzeta(0, 0, 0) = -a * cos(zeta[0]);
834 ddrdzeta(0, 0, 1) = -b * sin(zeta[0]);
835 }
836
837
838 /// How many items of Data does the shape of the object depend on?
839 unsigned ngeom_data() const
840 {
841 return Geom_data_pt.size();
842 }
843
844 /// Return pointer to the j-th Data item that the object's
845 /// shape depends on
846 Data* geom_data_pt(const unsigned& j)
847 {
848 return Geom_data_pt[j];
849 }
850
851 private:
852 /// Vector of pointers to Data items that affects the object's shape
854
855 /// Do I need to clean up?
857 };
858
859
860 ///////////////////////////////////////////////////////////////////////
861 ///////////////////////////////////////////////////////////////////////
862 // Circle as geometric object
863 ///////////////////////////////////////////////////////////////////////
864 ///////////////////////////////////////////////////////////////////////
865
866
867 //=========================================================================
868 /// Circle in 2D space.
869 /// \f[ x = X_c + R \cos(\zeta) \f]
870 /// \f[ y = Y_c + R \sin(\zeta) \f]
871 //=========================================================================
872 class Circle : public GeomObject
873 {
874 public:
875 /// Constructor: Pass x and y-coords of centre and radius (all pinned)
876 Circle(const double& x_c, const double& y_c, const double& r)
877 : GeomObject(1, 2)
878 {
879 // Create Data:
880 Geom_data_pt.resize(1);
881 Geom_data_pt[0] = new Data(3);
882
883 // No time-dependence
884 Is_time_dependent = false;
885
886 // Assign data: X_c; no timedependence, free by default
887
888 // Pin the data
889 Geom_data_pt[0]->pin(0);
890 // Give it a value:
891 Geom_data_pt[0]->set_value(0, x_c);
892
893 // Assign data: Y_c; no timedependence, free by default
894
895 // Pin the data
896 Geom_data_pt[0]->pin(1);
897 // Give it a value:
898 Geom_data_pt[0]->set_value(1, y_c);
899
900 // Assign data: R; no timedependence, free by default
901
902 // Pin the data
903 Geom_data_pt[0]->pin(2);
904 // Give it a value:
905 Geom_data_pt[0]->set_value(2, r);
906
907 // I've created the data, I need to clean up
908 Must_clean_up = true;
909 }
910
911
912 /// Constructor: Pass x and y-coords of centre and radius (all
913 /// pinned) Circle is static but can be used in time-dependent runs with
914 /// specified timestepper.
915 Circle(const double& x_c,
916 const double& y_c,
917 const double& r,
920 {
921 // Create Data:
922 Geom_data_pt.resize(1);
923 Geom_data_pt[0] = new Data(time_stepper_pt, 3);
924
925 // We have time-dependence
926 Is_time_dependent = true;
927
928 // Assign data: X_c; no timedependence, free by default
929
930 // Pin the data
931 Geom_data_pt[0]->pin(0);
932 // Give it a value:
933 Geom_data_pt[0]->set_value(0, x_c);
934
935 // Assign data: Y_c; no timedependence, free by default
936
937 // Pin the data
938 Geom_data_pt[0]->pin(1);
939 // Give it a value:
940 Geom_data_pt[0]->set_value(1, y_c);
941
942 // Assign data: R; no timedependence, free by default
943
944 // Pin the data
945 Geom_data_pt[0]->pin(2);
946 // Give it a value:
947 Geom_data_pt[0]->set_value(2, r);
948
949 // "Impulsive" start because there isn't any time-dependence
951
952 // I've created the data, I need to clean up
953 Must_clean_up = true;
954 }
955
956
957 /// Constructor: Pass x and y-coords of centre and radius
958 /// (all as Data)
959 /// \code
960 /// Geom_data_pt[0]->value(0) = X_c;
961 /// Geom_data_pt[0]->value(1) = Y_c;
962 /// Geom_data_pt[0]->value(2) = R;
963 /// \endcode
965 {
966#ifdef PARANOID
967 if (geom_data_pt.size() != 1)
968 {
969 std::ostringstream error_message;
970 error_message << "geom_data_pt should have size 1, not "
971 << geom_data_pt.size() << std::endl;
972
973 if (geom_data_pt[0]->nvalue() != 3)
974 {
975 error_message << "geom_data_pt[0] should have 3 values, not "
976 << geom_data_pt[0]->nvalue() << std::endl;
977 }
978
979 throw OomphLibError(error_message.str(),
982 }
983#endif
984
985 // We have time-dependence
986 if (geom_data_pt[0]->time_stepper_pt()->nprev_values() > 0)
987 {
988 Is_time_dependent = true;
989 }
990 else
991 {
992 Is_time_dependent = false;
993 }
994
995 Geom_data_pt.resize(1);
997
998 // Data has been created externally: Must not clean up
999 Must_clean_up = false;
1000 }
1001
1002 /// Broken copy constructor
1003 Circle(const Circle& dummy) = delete;
1004
1005 /// Broken assignment operator
1006 void operator=(const Circle&) = delete;
1007
1008 /// Destructor: Clean up if necessary
1009 virtual ~Circle()
1010 {
1011 // Do I need to clean up?
1012 if (Must_clean_up)
1013 {
1014 unsigned ngeom_data = Geom_data_pt.size();
1015 for (unsigned i = 0; i < ngeom_data; i++)
1016 {
1017 delete Geom_data_pt[i];
1018 Geom_data_pt[i] = 0;
1019 }
1020 }
1021 }
1022
1023 /// Position Vector at Lagrangian coordinate zeta
1025 {
1026 // Extract data
1027 double X_c = Geom_data_pt[0]->value(0);
1028 double Y_c = Geom_data_pt[0]->value(1);
1029 double R = Geom_data_pt[0]->value(2);
1030
1031 // Position Vector
1032 r[0] = X_c + R * cos(zeta[0]);
1033 r[1] = Y_c + R * sin(zeta[0]);
1034 }
1035
1036
1037 /// Parametrised position on object: r(zeta). Evaluated at
1038 /// previous timestep. t=0: current time; t>0: previous
1039 /// timestep.
1040 void position(const unsigned& t,
1041 const Vector<double>& zeta,
1042 Vector<double>& r) const
1043 {
1044 // Genuine time-dependence?
1045 if (!Is_time_dependent)
1046 {
1047 position(zeta, r);
1048 }
1049 else
1050 {
1051#ifdef PARANOID
1052 if (t > Geom_data_pt[0]->time_stepper_pt()->nprev_values())
1053 {
1054 std::ostringstream error_message;
1055 error_message << "t > nprev_values() " << t << " "
1057 << std::endl;
1058
1059 throw OomphLibError(error_message.str(),
1062 }
1063#endif
1064
1065 // Extract data
1066 double X_c = Geom_data_pt[0]->value(t, 0);
1067 double Y_c = Geom_data_pt[0]->value(t, 1);
1068 double R = Geom_data_pt[0]->value(t, 2);
1069
1070 // Position Vector
1071 r[0] = X_c + R * cos(zeta[0]);
1072 r[1] = Y_c + R * sin(zeta[0]);
1073 }
1074 }
1075
1076 /// Access function to x-coordinate of centre of circle
1077 double& x_c()
1078 {
1079 return *Geom_data_pt[0]->value_pt(0);
1080 }
1081
1082 /// Access function to y-coordinate of centre of circle
1083 double& y_c()
1084 {
1085 return *Geom_data_pt[0]->value_pt(1);
1086 }
1087
1088 /// Access function to radius of circle
1089 double& R()
1090 {
1091 return *Geom_data_pt[0]->value_pt(2);
1092 }
1093
1094 /// How many items of Data does the shape of the object depend on?
1095 unsigned ngeom_data() const
1096 {
1097 return Geom_data_pt.size();
1098 }
1099
1100 /// Return pointer to the j-th Data item that the object's
1101 /// shape depends on
1102 Data* geom_data_pt(const unsigned& j)
1103 {
1104 return Geom_data_pt[j];
1105 }
1106
1107 protected:
1108 /// Vector of pointers to Data items that affects the object's shape
1110
1111 /// Do I need to clean up?
1113
1114 /// Genuine time-dependence?
1116 };
1117
1118
1119 ///////////////////////////////////////////////////////////////////////
1120 ///////////////////////////////////////////////////////////////////////
1121 ///////////////////////////////////////////////////////////////////////
1122
1123
1124 //===========================================================
1125 /// Elliptical tube with half axes a and b.
1126 ///
1127 /// \f[ {\bf r} = ( a \cos(\zeta_1), b \sin(zeta_1), \zeta_0)^T \f]
1128 ///
1129 //===========================================================
1131 {
1132 public:
1133 /// Constructor: Specify radius
1134 EllipticalTube(const double& a, const double& b)
1135 : GeomObject(2, 3), A(a), B(b)
1136 {
1137 }
1138
1139 /// Broken copy constructor
1141
1142 /// Broken assignment operator
1143 void operator=(const EllipticalTube&) = delete;
1144
1145 /// Access function to x-half axis
1146 double& a()
1147 {
1148 return A;
1149 }
1150
1151 /// Access function to y-half axis
1152 double& b()
1153 {
1154 return B;
1155 }
1156
1157 /// Position vector
1159 {
1160 r[0] = A * cos(zeta[1]);
1161 r[1] = B * sin(zeta[1]);
1162 r[2] = zeta[0];
1163 }
1164
1165
1166 /// Position vector (dummy unsteady version returns steady version)
1167 void position(const unsigned& t,
1168 const Vector<double>& zeta,
1169 Vector<double>& r) const
1170 {
1171 position(zeta, r);
1172 }
1173
1174 /// How many items of Data does the shape of the object depend on?
1175 virtual unsigned ngeom_data() const
1176 {
1177 return 0;
1178 }
1179
1180 /// Position Vector and 1st and 2nd derivs w.r.t. zeta.
1183 {
1184 ddrdzeta(0, 0, 0) = 0.0;
1185 ddrdzeta(0, 0, 1) = 0.0;
1186 ddrdzeta(0, 0, 2) = 0.0;
1187
1188 ddrdzeta(1, 1, 0) = -A * cos(zeta[1]);
1189 ddrdzeta(1, 1, 1) = -B * sin(zeta[1]);
1190 ddrdzeta(1, 1, 2) = 0.0;
1191
1192 ddrdzeta(0, 1, 0) = ddrdzeta(1, 0, 0) = 0.0;
1193 ddrdzeta(0, 1, 1) = ddrdzeta(1, 0, 1) = 0.0;
1194 ddrdzeta(0, 1, 2) = ddrdzeta(1, 0, 2) = 0.0;
1195 }
1196
1197 /// Position Vector and 1st and 2nd derivs w.r.t. zeta.
1202 {
1203 // Let's just do a simple tube
1204 r[0] = A * cos(zeta[1]);
1205 r[1] = B * sin(zeta[1]);
1206 r[2] = zeta[0];
1207
1208 // Do the azetaal derivatives
1209 drdzeta(0, 0) = 0.0;
1210 drdzeta(0, 1) = 0.0;
1211 drdzeta(0, 2) = 1.0;
1212
1213 // Do the azimuthal derivatives
1214 drdzeta(1, 0) = -A * sin(zeta[1]);
1215 drdzeta(1, 1) = B * cos(zeta[1]);
1216 drdzeta(1, 2) = 0.0;
1217
1218 // Now let's do the second derivatives
1219 ddrdzeta(0, 0, 0) = 0.0;
1220 ddrdzeta(0, 0, 1) = 0.0;
1221 ddrdzeta(0, 0, 2) = 0.0;
1222
1223 ddrdzeta(1, 1, 0) = -A * cos(zeta[1]);
1224 ddrdzeta(1, 1, 1) = -B * sin(zeta[1]);
1225 ddrdzeta(1, 1, 2) = 0.0;
1226
1227 // Mixed derivatives
1228 ddrdzeta(0, 1, 0) = ddrdzeta(1, 0, 0) = 0.0;
1229 ddrdzeta(0, 1, 1) = ddrdzeta(1, 0, 1) = 0.0;
1230 ddrdzeta(0, 1, 2) = ddrdzeta(1, 0, 2) = 0.0;
1231 }
1232
1233 private:
1234 /// x-half axis
1235 double A;
1236
1237 /// x-half axis
1238 double B;
1239 };
1240
1241} // namespace oomph
1242
1243#endif
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
char t
Definition cfortran.h:568
Circle in 2D space.
double & x_c()
Access function to x-coordinate of centre of circle.
double & y_c()
Access function to y-coordinate of centre of circle.
void operator=(const Circle &)=delete
Broken assignment operator.
Circle(const Circle &dummy)=delete
Broken copy constructor.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
Circle(const double &x_c, const double &y_c, const double &r, TimeStepper *time_stepper_pt)
Constructor: Pass x and y-coords of centre and radius (all pinned) Circle is static but can be used i...
virtual ~Circle()
Destructor: Clean up if necessary.
Vector< Data * > Geom_data_pt
Vector of pointers to Data items that affects the object's shape.
unsigned ngeom_data() const
How many items of Data does the shape of the object depend on?
bool Must_clean_up
Do I need to clean up?
bool Is_time_dependent
Genuine time-dependence?
void position(const Vector< double > &zeta, Vector< double > &r) const
Position Vector at Lagrangian coordinate zeta.
Circle(const Vector< Data * > &geom_data_pt)
Constructor: Pass x and y-coords of centre and radius (all as Data)
Circle(const double &x_c, const double &y_c, const double &r)
Constructor: Pass x and y-coords of centre and radius (all pinned)
Data * geom_data_pt(const unsigned &j)
Return pointer to the j-th Data item that the object's shape depends on.
double & R()
Access function to radius of circle.
A class that represents a collection of data; each Data object may contain many different individual ...
Definition nodes.h:86
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition nodes.h:483
Steady ellipse with half axes A and B as geometric object:
void d2position(const Vector< double > &zeta, RankThreeTensor< double > &ddrdzeta) const
2nd derivative of position Vector w.r.t. to coordinates: = ddrdzeta(alpha,beta,i)....
Ellipse(const double &A, const double &B)
Constructor: 1 Lagrangian coordinate, 2 Eulerian coords. Pass half axes A and B; both pinned.
Ellipse(const Vector< Data * > &geom_data_pt)
Constructor: 1 Lagrangian coordinate, 2 Eulerian coords. Pass half axes as Data:
void d2position(const Vector< double > &zeta, Vector< double > &r, DenseMatrix< double > &drdzeta, RankThreeTensor< double > &ddrdzeta) const
Position Vector and 1st and 2nd derivs to coordinates: = drdzeta(alpha,i). = ddrdzeta(alpha,...
void operator=(const Ellipse &)=delete
Broken assignment operator.
void set_A_ellips(const double &a)
Set horizontal half axis.
Ellipse(const Ellipse &dummy)=delete
Broken copy constructor.
unsigned ngeom_data() const
How many items of Data does the shape of the object depend on?
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
void set_B_ellips(const double &b)
Set vertical half axis.
double b_ellips()
Access function for vertical half axis.
void position(const Vector< double > &zeta, Vector< double > &r) const
Position Vector at Lagrangian coordinate zeta.
Data * geom_data_pt(const unsigned &j)
Return pointer to the j-th Data item that the object's shape depends on.
~Ellipse()
Destructor: Clean up if necessary.
bool Must_clean_up
Do I need to clean up?
double a_ellips()
Access function for horizontal half axis.
Vector< Data * > Geom_data_pt
Vector of pointers to Data items that affects the object's shape.
void dposition(const Vector< double > &zeta, DenseMatrix< double > &drdzeta) const
Derivative of position Vector w.r.t. to coordinates: = drdzeta(alpha,i).
Elliptical tube with half axes a and b.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Position vector (dummy unsteady version returns steady version)
double B
x-half axis
EllipticalTube(const EllipticalTube &node)=delete
Broken copy constructor.
void operator=(const EllipticalTube &)=delete
Broken assignment operator.
void d2position(const Vector< double > &zeta, Vector< double > &r, DenseMatrix< double > &drdzeta, RankThreeTensor< double > &ddrdzeta) const
Position Vector and 1st and 2nd derivs w.r.t. zeta.
EllipticalTube(const double &a, const double &b)
Constructor: Specify radius.
double A
x-half axis
void d2position(const Vector< double > &zeta, RankThreeTensor< double > &ddrdzeta) const
Position Vector and 1st and 2nd derivs w.r.t. zeta.
double & a()
Access function to x-half axis.
virtual unsigned ngeom_data() const
How many items of Data does the shape of the object depend on?
double & b()
Access function to y-half axis.
void position(const Vector< double > &zeta, Vector< double > &r) const
Position vector.
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
A geometric object is an object that provides a parametrised description of its shape via the functio...
unsigned ndim() const
Access function to # of Eulerian coordinates.
virtual void d2position(const Vector< double > &zeta, RankThreeTensor< double > &ddrdzeta) const
2nd derivative of position Vector w.r.t. to coordinates: = ddrdzeta(alpha,beta,i)....
virtual void position(const Vector< double > &zeta, Vector< double > &r) const =0
Parametrised position on object at current time: r(zeta).
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
unsigned NLagrangian
Number of Lagrangian (intrinsic) coordinates.
TimeStepper * Geom_object_time_stepper_pt
Timestepper (used to handle access to geometry at previous timesteps)
virtual unsigned ngeom_data() const
How many items of Data does the shape of the object depend on? This is implemented as a broken virtua...
virtual void interpolated_zeta(const Vector< double > &s, Vector< double > &zeta) const
A geometric object may be composed of many sub-objects each with their own local coordinate....
void set_nlagrangian_and_ndim(const unsigned &n_lagrangian, const unsigned &n_dim)
Set # of Lagrangian and Eulerian coordinates.
virtual void d2position(const Vector< double > &zeta, Vector< double > &r, DenseMatrix< double > &drdzeta, RankThreeTensor< double > &ddrdzeta) const
Posn Vector and its 1st & 2nd derivatives w.r.t. to coordinates: = drdzeta(alpha,...
virtual Data * geom_data_pt(const unsigned &j)
Return pointer to the j-th Data item that the object's shape depends on. This is implemented as a bro...
void operator=(const GeomObject &)=delete
Broken assignment operator.
GeomObject(const unsigned &ndim)
Constructor: Pass dimension of geometric object (# of Eulerian coords = # of Lagrangian coords; no ti...
unsigned Ndim
Number of Eulerian coordinates.
GeomObject(const unsigned &nlagrangian, const unsigned &ndim, TimeStepper *time_stepper_pt)
Constructor: pass # of Eulerian and Lagrangian coordinates and pointer to time-stepper which is used ...
virtual void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s, const bool &use_coordinate_as_initial_guess=false)
A geometric object may be composed of may sub-objects (e.g. a finite-element representation of a boun...
TimeStepper * time_stepper_pt() const
Access function for pointer to time stepper: Null if object is not time-dependent....
virtual void dposition(const Vector< double > &zeta, DenseMatrix< double > &drdzeta) const
Derivative of position Vector w.r.t. to coordinates: = drdzeta(alpha,i). Evaluated at current time.
virtual void dposition_dt(const Vector< double > &zeta, const unsigned &j, Vector< double > &drdt)
j-th time-derivative on object at current time: .
virtual ~GeomObject()
(Empty) destructor
virtual void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
GeomObject(const unsigned &nlagrangian, const unsigned &ndim)
Constructor: pass # of Eulerian and Lagrangian coordinates. No time history available/needed.
unsigned nlagrangian() const
Access function to # of Lagrangian coordinates.
virtual void position(const double &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at the continuous time value, t.
GeomObject(const GeomObject &dummy)=delete
Broken copy constructor.
GeomObject()
Default constructor.
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
Steady, straight 1D line in 2D space.
Data * geom_data_pt(const unsigned &j)
Return pointer to the j-th Data item that the object's shape depends on.
virtual void dposition(const Vector< double > &zeta, DenseMatrix< double > &drdzeta) const
Derivative of position Vector w.r.t. to coordinates: = drdzeta(alpha,i). Evaluated at current time.
StraightLine(const StraightLine &dummy)=delete
Broken copy constructor.
StraightLine(const Vector< Data * > &geom_data_pt)
Constructor: One item of geometric data:
~StraightLine()
Destructor: Clean up if necessary.
Vector< Data * > Geom_data_pt
Vector of pointers to Data items that affects the object's shape.
StraightLine(const double &height)
Constructor: Pass height (pinned by default)
bool Must_clean_up
Do I need to clean up?
void position(const Vector< double > &zeta, Vector< double > &r) const
Position Vector at Lagrangian coordinate zeta.
virtual void d2position(const Vector< double > &zeta, Vector< double > &r, DenseMatrix< double > &drdzeta, RankThreeTensor< double > &ddrdzeta) const
Posn Vector and its 1st & 2nd derivatives w.r.t. to coordinates: = drdzeta(alpha,...
unsigned ngeom_data() const
How many items of Data does the shape of the object depend on?
virtual void d2position(const Vector< double > &zeta, RankThreeTensor< double > &ddrdzeta) const
2nd derivative of position Vector w.r.t. to coordinates: = ddrdzeta(alpha,beta,i)....
void operator=(const StraightLine &)=delete
Broken assignment operator.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
virtual void assign_initial_values_impulsive(Data *const &data_pt)=0
Initialise the time-history for the Data values corresponding to an impulsive start.
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).