periodic_orbit_handler.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_PERIODIC_ORBIT_HANDLER_CLASS_HEADER
27#define OOMPH_PERIODIC_ORBIT_HANDLER_CLASS_HEADER
28
29// Config header
30#ifdef HAVE_CONFIG_H
31#include <oomph-lib-config.h>
32#endif
33
34// OOMPH-LIB headers
35#include "matrices.h"
36#include "linear_solver.h"
38#include "problem.h"
39#include "assembly_handler.h"
41#include "../meshes/one_d_mesh.h"
42
43namespace oomph
44{
45 class PeriodicOrbitEquations;
46
47 class PeriodicOrbitAssemblyHandlerBase;
48
49 //====================================================================
50 /// Timestepper used to calculate periodic orbits directly. It's
51 /// not really a "timestepper" per se, but represents the time storage
52 /// and means of calculating time-derivatives given the underlying
53 /// discretisation.
54 //====================================================================
56 {
58
59 public:
60 /// Constructor for the case when we allow adaptive timestepping
63 {
64 Type = "PeriodicOrbitTimeDiscretisation";
65 }
66
67
68 /// Broken copy constructor
70 delete;
71
72 /// Broken assignment operator
74
75 /// Return the actual order of the scheme
76 unsigned order() const
77 {
78 return 1;
79 }
80
81 /// Broken initialisation the time-history for the Data values
82 /// corresponding to an impulsive start.
84 {
85 throw OomphLibError(
86 "Cannot perform impulsive start for PeriodicOrbitTimeDiscretisation",
89 }
90
91 /// Broken initialisation of
92 /// the positions for the node corresponding to an impulsive start
94 {
95 throw OomphLibError(
96 "Cannot perform impulsive start for PeriodicOrbitTimeDiscretisation",
99 }
100
101
102 /// Typedef for function that returns the (scalar) initial
103 /// value at a given value of the continuous time t.
104 typedef double (*InitialConditionFctPt)(const double& t);
105
106 /// Initialise the time-history for the Data values,
107 /// corresponding to given time history, specified by
108 /// Vector of function pointers.
111 {
112 // The time history stores the previous function values
113 unsigned n_time_value = ntstorage();
114
115 // Find number of values stored
116 unsigned n_value = data_pt->nvalue();
117
118 // Loop over current and stored timesteps
119 for (unsigned t = 0; t < n_time_value; t++)
120 {
121 // Get corresponding continous time
122 double time = Time_pt->time(t);
123
124 // Loop over values
125 for (unsigned j = 0; j < n_value; j++)
126 {
127 data_pt->set_value(t, j, initial_value_fct[j](time));
128 }
129 }
130 }
131
132 /// Broken shifting of time values
134 {
135 throw OomphLibError(
136 "Cannot shift time values for PeriodicOrbitTimeDiscretisation",
139 }
140
141 /// Broken shifting of time positions
142 void shift_time_positions(Node* const& node_pt)
143 {
144 throw OomphLibError(
145 "Cannot shift time positions for PeriodicOrbitTimeDiscretisation",
148 }
149
150 /// Set the weights
151 void set_weights() {}
152
153 /// Number of previous values available.
154 unsigned nprev_values() const
155 {
156 return ntstorage();
157 }
158
159 /// Number of timestep increments that need to be stored by the scheme
160 unsigned ndt() const
161 {
162 return ntstorage();
163 }
164 };
165
166
167 // Special element for integrating the residuals over one period
169 {
170 // Storage for the total number of time variables
171 unsigned Ntstorage;
172
173 // Pointer to the global variable that represents the frequency
174 double* Omega_pt;
175
176 /// Pointer to global time.
178
179 public:
180 // Constructor, do nothing
182
183 /// Broken copy constructor
185
186 /// Broken assignment operator
187 // Commented out broken assignment operator because this can lead to a
188 // conflict warning when used in the virtual inheritence hierarchy.
189 // Essentially the compiler doesn't realise that two separate
190 // implementations of the broken function are the same and so, quite
191 // rightly, it shouts.
192 /*void operator=(const PeriodicOrbitEquations&) = delete;*/
193
194 /// Set the pointer to the frequency
195 double*& omega_pt()
196 {
197 return Omega_pt;
198 }
199
200 /// Return the frequency
201 double omega()
202 {
203 return *Omega_pt;
204 }
205
206 /// Set the total number of time storage values
207 void set_ntstorage(const unsigned& n_tstorage)
208 {
210 }
211
212 /// Retun the pointer to the global time
214 {
215 return Time_pt;
216 }
217
218 /// Return the pointer to the global time (const version)
219 Time* const& time_pt() const
220 {
221 return Time_pt;
222 }
223
224 /// Return the global time, accessed via the time pointer
225 double time() const
226 {
227 // If no Time_pt, return 0.0
228 if (Time_pt == 0)
229 {
230 return 0.0;
231 }
232 else
233 {
234 return Time_pt->time();
235 }
236 }
237
238 /// Add the element's contribution to its residual vector (wrapper)
240 PeriodicOrbitAssemblyHandlerBase* const& assembly_handler_pt,
243 {
244 // Call the generic residuals function with flag set to 0
245 // using a dummy matrix argument
247 assembly_handler_pt,
248 elem_pt,
249 residuals,
251 0);
252 }
253
254 /// Add the element's contribution to its residual vector and
255 /// element Jacobian matrix (wrapper)
257 PeriodicOrbitAssemblyHandlerBase* const& assembly_handler_pt,
260 DenseMatrix<double>& jacobian)
261 {
262 // Call the generic routine with the flag set to 1
264 assembly_handler_pt, elem_pt, residuals, jacobian, 1);
265 }
266
267
269 std::ostream& outfile,
270 const unsigned& n_plot);
271
272
273 protected:
274 /// The routine that actually does all the work!
276 PeriodicOrbitAssemblyHandlerBase* const& assembly_handler_pt,
279 DenseMatrix<double>& jacobian,
280 const unsigned& flag);
281
282 /// Set the timestepper weights
284 {
287
288
289 // Zero the timestepper weights
290 unsigned n_time_dof = cast_time_stepper_pt->ntstorage();
291 for (unsigned i = 0; i < n_time_dof; i++)
292 {
293 cast_time_stepper_pt->Weight(0, i) = 0.0;
294 cast_time_stepper_pt->Weight(1, i) = 0.0;
295 }
296
297 // Cache the frequency (timescale)
298 const double inverse_timescale = this->omega();
299 // Now set the weights
300 const unsigned n_node = this->nnode();
301
302 // Global equation for the total number of time unknowns
303 // in the problem
304 int global_eqn;
305 for (unsigned l = 0; l < n_node; l++)
306 {
307 global_eqn = this->eqn_number(this->nodal_local_eqn(l, 0));
308 cast_time_stepper_pt->Weight(0, global_eqn) = psi(l);
309 cast_time_stepper_pt->Weight(1, global_eqn) =
311 }
312 }
313
314 /// Shape/test functions and derivs w.r.t. to global coords at
315 /// local coord. s; return Jacobian of mapping
317 Shape& psi,
318 DShape& dpsidt,
319 Shape& test,
320 DShape& dtestdt) const = 0;
321
322
323 /// Shape/test functions and derivs w.r.t. to global coords at
324 /// integration point ipt; return Jacobian of mapping
326 const unsigned& ipt,
327 Shape& psi,
328 DShape& dpsidt,
329 Shape& test,
330 DShape& dtestdt) const = 0;
331
332 /// Compute element residual Vector only (if flag=and/or element
333 /// Jacobian matrix
334
335 // Output function
336
337 /// Output function:
338 /// x,y,u or x,y,z,u at n_plot^DIM plot points
339 };
340
341
342 //======================================================================
343 /// QPoissonElement elements are linear/quadrilateral/brick-shaped
344 /// Poisson elements with isoparametric interpolation for the function.
345 //======================================================================
346 template<unsigned NNODE_1D>
348 : public virtual QSpectralElement<1, NNODE_1D>,
349 public virtual RefineableQSpectralElement<1>,
350 public virtual PeriodicOrbitEquations,
351 public virtual ElementWithZ2ErrorEstimator
352 {
353 public:
354 /// Constructor: Call constructors for QElement and
355 /// Poisson equations
362
363 /// Broken copy constructor
366
367 /// Broken assignment operator
368 /*void operator=(const SpectralPeriodicOrbitElement<NNODE_1D>&) = delete;*/
369
370
371 /// Required # of `values' (pinned or dofs)
372 /// at node n (only ever one dummy value, used for equation numbering)
373 /// This is also used to represent all *spatial* variables during a
374 /// temporal refinement, which is a bit naughty but it quick and dirty.
375 inline unsigned required_nvalue(const unsigned& n) const
376 {
377 return 1;
378 }
379
380 /// Number of continuously interpolated values (1)
381 inline unsigned ncont_interpolated_values() const
382 {
383 return 1;
384 }
385
386 /// Return the dummy values
388 {
389 this->get_interpolated_values(0, s, value);
390 }
391
392 /// Return the temporal dummy values
393 void get_interpolated_values(const unsigned& t,
394 const Vector<double>& s,
395 Vector<double>& value)
396 {
397 value.resize(1);
398 value[0] = 0.0;
399
400 const unsigned n_node = this->nnode();
402 this->shape(s, psi);
403
404 for (unsigned n = 0; n < n_node; n++)
405 {
406 value[0] += this->nodal_value(t, n, 0) * psi(n);
407 }
408 }
409
410 // Order of recovery shape functions for Z2 error estimation:
412 {
413 return NNODE_1D - 1;
414 }
415
416 /// Number of flux terms for Z2 error estimation
417 /// This will be used to represent all spatial values,
419 {
420 return this->node_pt(0)->ntstorage();
421 }
422
423 /// Get the fluxes for the recovert
425 {
426 // Find out the number of nodes in the element
427 const unsigned n_node = this->nnode();
428
429 // Get the shape functions
431 DShape dpsidx(n_node, 1);
432
433 // Get the derivatives
434 (void)this->dshape_eulerian(s, psi, dpsidx);
435
436 // Now assemble all the derivatives
437 const unsigned n_tstorage = this->node_pt(0)->ntstorage();
438
439 // Zero the flux vector
440 for (unsigned t = 0; t < n_tstorage; t++)
441 {
442 flux[t] = 0.0;
443 }
444
445 // Loop over the nodes
446 for (unsigned n = 0; n < n_node; n++)
447 {
448 const double dpsidx_ = dpsidx(n, 0);
449 for (unsigned t = 0; t < n_tstorage; t++)
450 {
451 flux[t] += this->nodal_value(t, n, 0) * dpsidx_;
452 }
453 }
454 }
455
456 // Number of vertex nodes in the element (always 2)
457 unsigned nvertex_node() const
458 {
459 return 2;
460 }
461
462 /// Pointer to the j-th vertex node in the element
463 Node* vertex_node_pt(const unsigned& j) const
464 {
466 }
467
468
469 //
470 /// Function to return the number of values
471
472 /// Output function:
473 /// x,y,u or x,y,z,u
474 void output(std::ostream& outfile)
475 {
477 }
478
479
480 /// Output function:
481 /// x,y,u or x,y,z,u at n_plot^DIM plot points
482 void output(std::ostream& outfile, const unsigned& n_plot)
483 {
485 }
486
487
488 /// C-style output function:
489 /// x,y,u or x,y,z,u
494
495
496 /// C-style output function:
497 /// x,y,u or x,y,z,u at n_plot^DIM plot points
498 void output(FILE* file_pt, const unsigned& n_plot)
499 {
501 }
502
503
504 protected:
505 /// Shape, test functions & derivs. w.r.t. to global coords. Return
506 /// Jacobian.
508 Shape& psi,
509 DShape& dpsidt,
510 Shape& test,
511 DShape& dtestdt) const;
512
513
514 /// Shape, test functions & derivs. w.r.t. to global coords. at
515 /// integration point ipt. Return Jacobian.
517 const unsigned& ipt,
518 Shape& psi,
519 DShape& dpsidt,
520 Shape& test,
521 DShape& dtestdt) const;
522 };
523
524
525 // Inline functions:
526
527
528 //======================================================================
529 /// Define the shape functions and test functions and derivatives
530 /// w.r.t. global coordinates and return Jacobian of mapping.
531 ///
532 /// Galerkin: Test functions = shape functions
533 //======================================================================
534 template<unsigned NNODE_1D>
535 double SpectralPeriodicOrbitElement<
536 NNODE_1D>::dshape_and_dtest_eulerian_orbit(const Vector<double>& s,
537 Shape& psi,
538 DShape& dpsidt,
539 Shape& test,
540 DShape& dtestdt) const
541 {
542 // Call the geometrical shape functions and derivatives
543 const double J = this->dshape_eulerian(s, psi, dpsidt);
544
545 // Set the test functions equal to the shape functions
546 test = psi;
547 dtestdt = dpsidt;
548
549 // Return the jacobian
550 return J;
551 }
552
553
554 //======================================================================
555 /// Define the shape functions and test functions and derivatives
556 /// w.r.t. global coordinates and return Jacobian of mapping.
557 ///
558 /// Galerkin: Test functions = shape functions
559 //======================================================================
560 template<unsigned NNODE_1D>
562 NNODE_1D>::dshape_and_dtest_eulerian_at_knot_orbit(const unsigned& ipt,
563 Shape& psi,
564 DShape& dpsidt,
565 Shape& test,
566 DShape& dtestdt) const
567 {
568 // Call the geometrical shape functions and derivatives
569 const double J = this->dshape_eulerian_at_knot(ipt, psi, dpsidt);
570
571 // Set the pointers of the test functions
572 test = psi;
573 dtestdt = dpsidt;
574
575 // Return the jacobian
576 return J;
577 }
578
579
580 template<unsigned NNODE_1D>
582
583
584 //======================================================================
585 /// A special temporal mesh class
586 //=====================================================================
587 template<class ELEMENT>
589 {
590 // Let's have the periodic handler as a friend
591 template<unsigned NNODE_1D>
593
594 public:
595 /// Constructor, create a 1D mesh from 0 to 1 that is periodic
597 : OneDMesh<ELEMENT>(n_element, 1.0),
598 RefineableOneDMesh<ELEMENT>(n_element, 1.0)
599 {
600 // Make the mesh periodic by setting the LAST node to have the same data
601 // as the FIRST node
602 // Not necessarily a smart move for when doing Floquet analysis
603 this->boundary_node_pt(1, 0)->make_periodic(this->boundary_node_pt(0, 0));
604 }
605
606
607 // Output the orbit for all elements in the mesh
609 std::ostream& outfile,
610 const unsigned& n_plot)
611 {
612 // Loop over all elements in the mesh
613 const unsigned n_element = this->nelement();
614 for (unsigned e = 0; e < n_element; e++)
615 {
616 dynamic_cast<ELEMENT*>(this->element_pt(e))
617 ->orbit_output(elem_pt, outfile, n_plot);
618 }
619 }
620
621 // Loop over all temporal elements and assemble their contributions
623 PeriodicOrbitAssemblyHandlerBase* const& assembly_handler_pt,
626 {
627 // Initialise the residuals to zero
628 residuals.initialise(0.0);
629 // Loop over all elements in the mesh
630 const unsigned n_element = this->nelement();
631 for (unsigned e = 0; e < n_element; e++)
632 {
633 dynamic_cast<ELEMENT*>(this->element_pt(e))
634 ->fill_in_contribution_to_integrated_residuals(
635 assembly_handler_pt, elem_pt, residuals);
636 }
637 }
638
639
640 // Loop over all temporal elements and assemble their contributions
641 // and the jaobian
643 PeriodicOrbitAssemblyHandlerBase* const& assembly_handler_pt,
646 DenseMatrix<double>& jacobian)
647 {
648 // Initialise the residuals to zero
649 residuals.initialise(0.0);
650 jacobian.initialise(0.0);
651 // Loop over all elements in the mesh
652 const unsigned n_element = this->nelement();
653 for (unsigned e = 0; e < n_element; e++)
654 {
655 dynamic_cast<ELEMENT*>(this->element_pt(e))
656 ->fill_in_contribution_to_integrated_jacobian(
657 assembly_handler_pt, elem_pt, residuals, jacobian);
658 }
659 }
660 };
661
662 /// ===============================================================
663 /// Base class to avoid template complications
664 //===============================================================
666 {
667 public:
668 // Do nothing in constructor
670
671 // Provide interface
673 Vector<double>& dofs) = 0;
674
675
678
679
681 Vector<double> const& dofs) = 0;
682 };
683
684 //======================================================================
685 /// A class that is used to assemble and solve the augmented system
686 /// of equations associated with calculating periodic orbits directly
687 //========================================================================
688 template<unsigned NNODE_1D>
690 {
691 private:
692 /// Pointer to the timestepper
694
695 /// Pointer to the problem
697
698 /// Storage for mesh of temporal elements
701
702 /// Storage for the mesh of temporal elements with a simple mesh pointer
704
705 /// Storage for the previous solution
707
708 /// Store number of degrees of freedom in the original problem
709 unsigned Ndof;
710
711 /// Storage for number of elements in the period
713
714 /// Storage for the number of unknown time values
715 unsigned N_tstorage;
716
717 /// Storage for the frequency of the orbit (scaled by 2pi)
718 double Omega;
719
720 public:
721 /// Constructor, initialises values and constructs mesh of elements
723 Problem* const& problem_pt,
724 const unsigned& n_element_in_period,
726 const double& omega)
727 : Problem_pt(problem_pt),
729 Omega(omega / (2.0 * MathematicalConstants::Pi))
730 {
731 // Store the current number of degrees of freedom
732 Ndof = problem_pt->ndof();
733
734 // Create the appropriate mesh of "1D" time elements depending on
735 // the specified spectral order
736 // The time domain runs from zero to one
740
742
743 // Set the error estimator
744 Time_mesh_pt->spatial_error_estimator_pt() = new Z2ErrorEstimator;
745 Time_mesh_pt->max_permitted_error() = 1.0e-2;
746 Time_mesh_pt->min_permitted_error() = 1.0e-5;
747 Time_mesh_pt->max_refinement_level() = 10;
748
749 // Now we need to number the mesh
750 // Dummy dof pointer
752 Time_mesh_pt->assign_global_eqn_numbers(dummy_dof_pt);
753 // Assign the local equation numbers
755
756 // Find the number of temporal degrees of freedom
758
759 // Now we need to do something clever to setup the time storage schemes
760 // and the initial values (don't quite know what that is yet)
761
762 // Create the "fake" timestepper
764 // Loop over the temporal elements and set the pointers
765 for (unsigned e = 0; e < n_element_in_period; e++)
766 {
769 Time_mesh_pt->element_pt(e));
770
771 // Set the time and the timestepper
772 el_pt->time_pt() = problem_pt->time_pt();
774
775 // Set the number of temporal degrees of freedom
776 el_pt->set_ntstorage(N_tstorage);
777 // Set the frequency
778 el_pt->omega_pt() = &Omega;
779 }
780
781 // We now need to do something much more drastic which is to loop over all
782 // our the data in the problem and change the timestepper, which is going
783 // to be a real pain when I start to worry about halo nodes, etc.
784
785 // Will need to use the appropriate mesh-level functions that have
786 // not been written yet ..
787
788 // Let's just break if there are submeshes
789 if (problem_pt->nsub_mesh() > 0)
790 {
791 throw OomphLibError(
792 "PeriodicOrbitHandler can't cope with submeshes yet",
795 }
796
797 // OK now we have only one mesh
798 unsigned n_node = problem_pt->mesh_pt()->nnode();
799 for (unsigned n = 0; n < n_node; n++)
800 {
801 Node* const nod_pt = problem_pt->mesh_pt()->node_pt(n);
802 nod_pt->set_time_stepper(Time_stepper_pt, false);
803 // If the unknowns are pinned then copy the value to all values
804 unsigned n_value = nod_pt->nvalue();
805 for (unsigned i = 0; i < n_value; i++)
806 {
807 if (nod_pt->is_pinned(i))
808 {
809 const unsigned n_tstorage = nod_pt->ntstorage();
810 const double value = nod_pt->value(i);
811 for (unsigned t = 1; t < n_tstorage; t++)
812 {
813 nod_pt->set_value(t, i, value);
814 }
815 }
816 }
817 }
818
819 unsigned n_element = problem_pt->mesh_pt()->nelement();
820 for (unsigned e = 0; e < n_element; e++)
821 {
822 unsigned n_internal =
823 problem_pt->mesh_pt()->element_pt(e)->ninternal_data();
824 for (unsigned i = 0; i < n_internal; i++)
825 {
826 // Cache the internal data
827 Data* const data_pt =
828 problem_pt->mesh_pt()->element_pt(e)->internal_data_pt(i);
829 // and set the timestepper
830 data_pt->set_time_stepper(Time_stepper_pt, false);
831
832 // If the unknowns are pinned then copy the value to all values
833 unsigned n_value = data_pt->nvalue();
834 for (unsigned j = 0; j < n_value; j++)
835 {
836 if (data_pt->is_pinned(j))
837 {
838 const unsigned n_tstorage = data_pt->ntstorage();
839 const double value = data_pt->value(j);
840 for (unsigned t = 1; t < n_tstorage; t++)
841 {
842 data_pt->set_value(t, j, value);
843 }
844 }
845 }
846 }
847 }
848
849 // Need to reassign equation numbers so that the DOF pointer, points to
850 // the newly allocated storage
851 oomph_info << "Re-allocated " << problem_pt->assign_eqn_numbers()
852 << " equation numbers\n";
853
854 // Now's let's add all the unknowns to the problem
855 problem_pt->Dof_pt.resize(Ndof * N_tstorage + 1);
856 // This is reasonably straight forward using pointer arithmetic
857 // but this does rely on knowing how the data is stored in the
858 // Nodes which is a little nasty
859 for (unsigned i = 0; i < N_tstorage; i++)
860 {
861 unsigned offset = Ndof * i;
862 for (unsigned n = 0; n < Ndof; n++)
863 {
864 problem_pt->Dof_pt[offset + n] = problem_pt->Dof_pt[n] + i;
865 }
866 }
867
868 // Add the frequency of the orbit to the unknowns
869 problem_pt->Dof_pt[Ndof * N_tstorage] = &Omega;
870
871 // Rebuild everything
872 problem_pt->Dof_distribution_pt->build(
873 problem_pt->communicator_pt(), Ndof * N_tstorage + 1, true);
874
875
876 // Set initial condition of constant-ness plus wobble
877 for (unsigned i = 0; i < N_tstorage; i++)
878 {
879 unsigned offset = Ndof * i;
880 for (unsigned n = 0; n < Ndof; n++)
881 {
882 problem_pt->dof(offset + n) =
883 initial_guess(i, n); // problem_pt->dof(n);
884 }
885 }
886
887 // Set the initial unkowns to be the original problem
888 Previous_dofs.resize(Ndof * N_tstorage + 1, 0.0);
890
891 // Now check everything is OK ... it seems to be
892 // std::cout << problem_pt->ndof() << "\n";
893 // Let's check it
894 // for(unsigned i=0;i<problem_pt->ndof();i++)
895 // {
896 // std::cout << i << " " << problem_pt->dof(i) << "\n";
897 //}
898 }
899
900 /// Update the previous dofs
902 {
903 for (unsigned n = 0; n < Ndof * N_tstorage + 1; n++)
904 {
906 }
907 }
908
909 /// Return the number of degrees of freedom in the element elem_pt
911 {
912 return ((elem_pt->ndof()) * N_tstorage + 1);
913 }
914
915 /// Return the global equation number of the local unknown ieqn_local
916 /// in elem_pt.
917 unsigned long eqn_number(GeneralisedElement* const& elem_pt,
918 const unsigned& ieqn_local)
919 {
920 // Get unaugmented number of (spatial) dofs in element
921 unsigned raw_ndof = elem_pt->ndof();
922 // The final variable (the period) is stored at the end
924 {
925 return N_tstorage * Ndof;
926 }
927 // Otherwise we need to do a little more work
928 else
929 {
930 // Now find out the time level
931 unsigned t = ieqn_local / raw_ndof;
932 // and the remainder (original eqn number)
933 unsigned raw_ieqn = ieqn_local % raw_ndof;
934 // hence calculate the global value
935 return t * Ndof + elem_pt->eqn_number(raw_ieqn);
936 }
937 }
938
939 /// Return the contribution to the residuals of the element elem_pt
942 {
943 Time_mesh_pt->assemble_residuals(this, elem_pt, residuals);
944 }
945
946
947 // Provide interface
950 {
951 // Find the number of dofs in the element
952 const unsigned n_elem_dof = this->ndof(elem_pt);
953 dofs.resize(n_elem_dof);
954 // Now just get the dofs corresponding to the element's unknowns from the
955 // problem dof
956 for (unsigned i = 0; i < n_elem_dof; i++)
957 {
958 dofs[i] = Problem_pt->dof(this->eqn_number(elem_pt, i));
959 }
960 }
961
964 {
965 // Find the number of dofs in the element
966 const unsigned n_elem_dof = this->ndof(elem_pt);
967 dofs.resize(n_elem_dof);
968 // Now just get the dofs corresponding to the element's unknowns from the
969 // problem dof
970 for (unsigned i = 0; i < n_elem_dof; i++)
971 {
972 dofs[i] = Previous_dofs[this->eqn_number(elem_pt, i)];
973 }
974 }
975
976
978 Vector<double> const& dofs)
979 {
980 // Find the number of dofs in the element
981 const unsigned n_elem_dof = this->ndof(elem_pt);
982 // Now just get the dofs corresponding to the element's unknowns from the
983 // problem dof
984 for (unsigned i = 0; i < n_elem_dof; i++)
985 {
986 Problem_pt->dof(this->eqn_number(elem_pt, i)) = dofs[i];
987 }
988 }
989
990
991 /// Calculate the elemental Jacobian matrix "d equation
992 /// / d variable" for elem_pt.
995 DenseMatrix<double>& jacobian)
996 {
997 Time_mesh_pt->assemble_residuals_and_jacobian(
998 this, elem_pt, residuals, jacobian);
999 }
1000
1001 /// Calculate all desired vectors and matrices
1002 /// provided by the element elem_pt.
1003 // void get_all_vectors_and_matrices(
1004 // GeneralisedElement* const &elem_pt,
1005 // Vector<Vector<double> >&vec, Vector<DenseMatrix<double> > &matrix) {}
1006
1007 /// Return an unsigned integer to indicate whether the
1008 /// handler is a bifurcation tracking handler. The default
1009 /// is zero (not)
1010 // virtual int bifurcation_type() const {return 0;}
1011
1012 /// Return a pointer to the
1013 /// bifurcation parameter in bifurcation tracking problems
1014 // virtual double* bifurcation_parameter_pt() const;
1015
1016 /// Return the eigenfunction(s) associated with the bifurcation that
1017 /// has been detected in bifurcation tracking problems
1018 // virtual void get_eigenfunction(Vector<DoubleVector> &eigenfunction);
1019
1020 /// Return the contribution to the residuals of the element elem_pt
1021 void orbit_output(std::ostream& outfile, const unsigned& n_plot)
1022 {
1023 const unsigned n_element = Problem_pt->mesh_pt()->nelement();
1024 for (unsigned e = 0; e < n_element; e++)
1025 {
1026 Time_mesh_pt->orbit_output(
1028 }
1029 }
1030
1031
1032 /// Tell me the times at which you want the solution
1034 {
1035 const unsigned n_node = Time_mesh_pt->nnode();
1036 t.resize(n_node);
1037 for (unsigned n = 0; n < n_node; n++)
1038 {
1039 t[n] = Time_mesh_pt->node_pt(n)->x(0);
1040 }
1041 }
1042
1043 /// Adapt the time mesh
1045 {
1046 // First job is to compute some sort of error measure
1047 // Then we can decide how to refine this is probably best handled
1048 // separately for now
1049
1050 // The current plan is to copy all (locally held in the case of
1051 // distributed problem) spatial degrees of freedom into the dummy
1052 // storage of the time mesh
1053
1054 // Probably should kick this down to the mesh level...
1055
1056 // OK, let's do it, count up all values
1057 unsigned total_n_value = 0;
1058
1059 // Firstly the global data in the mesh
1061 for (unsigned i = 0; i < n_global_data; i++)
1062 {
1064 }
1065
1066 // Now the nodal data
1067 unsigned n_node = Problem_pt->mesh_pt()->nnode();
1068 for (unsigned n = 0; n < n_node; n++)
1069 {
1072 dynamic_cast<SolidNode*>(Problem_pt->mesh_pt()->node_pt(n));
1073 if (solid_nod_pt != 0)
1074 {
1075 total_n_value += solid_nod_pt->variable_position_pt()->nvalue();
1076 }
1077 }
1078
1079 // Now just do the internal data
1080 unsigned n_space_element = Problem_pt->mesh_pt()->nelement();
1081 for (unsigned e = 0; e < n_space_element; e++)
1082 {
1083 const unsigned n_internal_data =
1085 for (unsigned i = 0; i < n_internal_data; i++)
1086 {
1087 total_n_value +=
1089 }
1090 }
1091
1092 // Now in theory I know the total number of values in the problem
1093 // So I can create another Fake timestepper
1096
1097 // Now apply this time stepper to all time nodes
1098 unsigned n_time_node = Time_mesh_pt->nnode();
1099 for (unsigned t = 0; t < n_time_node; t++) // Do include the periodic one
1100 {
1102 false);
1103 }
1104
1105 // Now I "just" copy the values into the new storage
1106 unsigned count = 0;
1107 for (unsigned i = 0; i < n_global_data; i++)
1108 {
1110 const unsigned n_value = glob_data_pt->nvalue();
1111 for (unsigned j = 0; j < n_value; j++)
1112 {
1113 for (unsigned t = 0; t < N_tstorage; t++)
1114 {
1115 // Some heavy assumptions here about the time mesh, but that's OK
1116 // because I know exactly how it's laid out
1118 count, 0, glob_data_pt->value(t, j));
1119 }
1120 ++count;
1121 }
1122 }
1123
1124 // Now the nodal data
1125 for (unsigned n = 0; n < n_node; n++)
1126 {
1127 Node* const nod_pt = Problem_pt->mesh_pt()->node_pt(n);
1128 const unsigned n_value = nod_pt->nvalue();
1129 for (unsigned i = 0; i < n_value; i++)
1130 {
1131 for (unsigned t = 0; t < N_tstorage; t++)
1132 {
1133 Time_mesh_pt->node_pt(t)->set_value(count, 0, nod_pt->value(t, i));
1134 }
1135 ++count;
1136 }
1137
1138 // Now deal with the solid node data
1139 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
1140 if (solid_nod_pt != 0)
1141 {
1142 const unsigned n_solid_value =
1143 solid_nod_pt->variable_position_pt()->nvalue();
1144 for (unsigned i = 0; i < n_solid_value; i++)
1145 {
1146 for (unsigned t = 0; t < N_tstorage; t++)
1147 {
1149 count, 0, solid_nod_pt->variable_position_pt()->value(t, i));
1150 }
1151 ++count;
1152 }
1153 }
1154 }
1155
1156 // Now just do the internal data
1157 for (unsigned e = 0; e < n_space_element; e++)
1158 {
1159 const unsigned n_internal =
1161 for (unsigned i = 0; i < n_internal; i++)
1162 {
1163 Data* const internal_dat_pt =
1165
1166 const unsigned n_value = internal_dat_pt->nvalue();
1167 for (unsigned j = 0; j < n_value; j++)
1168 {
1169 for (unsigned t = 0; t < N_tstorage; t++)
1170 {
1172 count, 0, internal_dat_pt->value(t, j));
1173 }
1174 ++count;
1175 }
1176 }
1177 }
1178
1179
1180 // Think it's done but let's check
1181 /*{
1182 std::ofstream munge("data_remunge.dat");
1183 const unsigned n_time_element = Time_mesh_pt->nelement();
1184 for(unsigned e=0;e<n_time_element;e++)
1185 {
1186 const unsigned n_node = Time_mesh_pt->nnode();
1187 for(unsigned n=0;n<n_node;n++)
1188 {
1189 Node* const nod_pt = Time_mesh_pt->node_pt(n);
1190 munge << nod_pt->x(0) << " ";
1191 const unsigned n_space_storage = nod_pt->ntstorage();
1192 for(unsigned t=0;t<n_space_storage;t++)
1193 {
1194 munge << nod_pt->value(t,0) << " ";
1195 }
1196 munge << std::endl;
1197 }
1198 }
1199 munge.close();
1200 }*/
1201
1202 // Ok get the elemental errors
1203 const unsigned n_time_element = Time_mesh_pt->nelement();
1205 Time_mesh_pt->spatial_error_estimator_pt()->get_element_errors(
1207
1208 // Let's dump it
1209 for (unsigned e = 0; e < n_time_element; e++)
1210 {
1211 oomph_info << e << " " << elemental_error[e] << "\n";
1212 }
1213
1214 // Now adapt the mesh
1216
1217 // I seem to have remunged the data,
1218 // Now let's pretend that we have done the the error adaptation
1219 // Time_mesh_pt->refine_uniformly();
1220
1221 // Let's just refine the central elements twice
1222 // Vector<unsigned> refine_elements;
1223 // refine_elements.push_back(0);
1224 // refine_elements.push_back(9);
1225 // Time_mesh_pt->refine_selected_elements(refine_elements);
1226 // refine_elements.clear();
1227 // refine_elements.push_back(0);
1228 // refine_elements.push_back(1);
1229 // refine_elements.push_back(10);
1230 // refine_elements.push_back(11);
1231 // Time_mesh_pt->refine_selected_elements(refine_elements);
1232
1233 /* std::ofstream munge("data_refine.dat");
1234 const unsigned n_time_element = Time_mesh_pt->nelement();
1235 for(unsigned e=0;e<n_time_element;e++)
1236 {
1237 const unsigned n_node = Time_mesh_pt->nnode();
1238 for(unsigned n=0;n<n_node;n++)
1239 {
1240 Node* const nod_pt = Time_mesh_pt->node_pt(n);
1241 munge << nod_pt->x(0) << " ";
1242 const unsigned n_space_storage = nod_pt->ntstorage();
1243 for(unsigned t=0;t<n_space_storage;t++)
1244 {
1245 munge << nod_pt->value(t,0) << " ";
1246 }
1247 munge << std::endl;
1248 }
1249 }
1250 munge.close();*/
1251
1252 // Now we need to put the refined data back into the problem
1253
1254 // Now we need to number the mesh
1255 // Dummy dof pointer
1257 Time_mesh_pt->assign_global_eqn_numbers(dummy_dof_pt);
1258 // Assign the local equation numbers
1260
1261 // Find the number of temporal degrees of freedom
1263 // and new number of elements
1264 N_element_in_period = Time_mesh_pt->nelement();
1265
1266 // Create the new "fake" timestepper
1269
1270 // Loop over the temporal elements and set the pointers
1271 for (unsigned e = 0; e < N_element_in_period; e++)
1272 {
1275 Time_mesh_pt->element_pt(e));
1276
1277 // Set the time and the timestepper
1278 el_pt->time_pt() = Problem_pt->time_pt();
1280
1281 // Set the number of temporal degrees of freedom
1282 el_pt->set_ntstorage(N_tstorage);
1283 // Set the frequency
1284 el_pt->omega_pt() = &Omega;
1285 }
1286
1287 // We now need to do something much more drastic which is to loop over all
1288 // our the data in the problem and change the timestepper, which is going
1289 // to be a real pain when I start to worry about halo nodes, etc.
1290
1291 // Will need to use the appropriate mesh-level functions that have
1292 // not been written yet ..
1293
1294 // Let's just break if there are submeshes
1295 if (Problem_pt->nsub_mesh() > 0)
1296 {
1297 throw OomphLibError(
1298 "PeriodicOrbitHandler can't cope with submeshes yet",
1301 }
1302
1303 // OK now we have only one mesh
1304 for (unsigned n = 0; n < n_node; n++)
1305 {
1306 Node* const nod_pt = Problem_pt->mesh_pt()->node_pt(n);
1307 nod_pt->set_time_stepper(periodic_time_stepper_pt, false);
1308 }
1309
1310 for (unsigned e = 0; e < n_space_element; e++)
1311 {
1312 unsigned n_internal =
1314 for (unsigned i = 0; i < n_internal; i++)
1315 {
1316 // Cache the internal data
1317 Data* const data_pt =
1319 // and set the timestepper
1320 data_pt->set_time_stepper(periodic_time_stepper_pt, false);
1321 }
1322 }
1323
1324 // Now I can delete the old timestepper and switch
1325 delete Time_stepper_pt;
1327
1328 // Need to reassign equation numbers so that the DOF pointer, points to
1329 // the newly allocated storage
1330 oomph_info << "Re-allocated " << Problem_pt->assign_eqn_numbers()
1331 << " equation numbers\n";
1332
1333 // Now's let's add all the unknowns to the problem
1334 Problem_pt->Dof_pt.resize(Ndof * N_tstorage + 1);
1335 // This is reasonably straight forward using pointer arithmetic
1336 // but this does rely on knowing how the data is stored in the
1337 // Nodes which is a little nasty
1338 for (unsigned i = 0; i < N_tstorage; i++)
1339 {
1340 unsigned offset = Ndof * i;
1341 for (unsigned n = 0; n < Ndof; n++)
1342 {
1343 Problem_pt->Dof_pt[offset + n] = Problem_pt->Dof_pt[n] + i;
1344 }
1345 }
1346
1347 // Add the frequency of the orbit to the unknowns
1349
1350 // Rebuild everything
1352 Problem_pt->communicator_pt(), Ndof * N_tstorage + 1, true);
1353
1354
1355 // Now finally transfer the solution accross
1356
1357 // Now I "just" copy the values into the new storage
1358 count = 0;
1359 for (unsigned i = 0; i < n_global_data; i++)
1360 {
1362 const unsigned n_value = glob_data_pt->nvalue();
1363 for (unsigned j = 0; j < n_value; j++)
1364 {
1365 for (unsigned t = 0; t < N_tstorage; t++)
1366 {
1367 // Some heavy assumptions here about the time mesh, but that's OK
1368 // because I know exactly how it's laid out
1369 glob_data_pt->set_value(
1370 t, j, Time_mesh_pt->node_pt(t)->value(count, 0));
1371 }
1372 ++count;
1373 }
1374 }
1375
1376 // Now the nodal data
1377 for (unsigned n = 0; n < n_node; n++)
1378 {
1379 Node* const nod_pt = Problem_pt->mesh_pt()->node_pt(n);
1380 const unsigned n_value = nod_pt->nvalue();
1381 for (unsigned i = 0; i < n_value; i++)
1382 {
1383 for (unsigned t = 0; t < N_tstorage; t++)
1384 {
1385 nod_pt->set_value(t, i, Time_mesh_pt->node_pt(t)->value(count, 0));
1386 }
1387 ++count;
1388 }
1389
1390 // Now deal with the solid node data
1391 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
1392 if (solid_nod_pt != 0)
1393 {
1394 const unsigned n_solid_value =
1395 solid_nod_pt->variable_position_pt()->nvalue();
1396 for (unsigned i = 0; i < n_solid_value; i++)
1397 {
1398 for (unsigned t = 0; t < N_tstorage; t++)
1399 {
1400 solid_nod_pt->variable_position_pt()->set_value(
1401 t, i, Time_mesh_pt->node_pt(t)->value(count, 0));
1402 }
1403 ++count;
1404 }
1405 }
1406 }
1407
1408 // Now just do the internal data
1409 for (unsigned e = 0; e < n_space_element; e++)
1410 {
1411 const unsigned n_internal =
1413 for (unsigned i = 0; i < n_internal; i++)
1414 {
1415 Data* const internal_dat_pt =
1417
1418 const unsigned n_value = internal_dat_pt->nvalue();
1419 for (unsigned j = 0; j < n_value; j++)
1420 {
1421 for (unsigned t = 0; t < N_tstorage; t++)
1422 {
1423 internal_dat_pt->set_value(
1424 t, j, Time_mesh_pt->node_pt(t)->value(count, 0));
1425 }
1426 ++count;
1427 }
1428 }
1429 }
1430
1431
1432 // Now I should be able to delete the fake time timestepper
1434 for (unsigned t = 0; t < n_time_node; t++)
1435 {
1437 false);
1438 }
1439 // Delete the fake timestepper
1441
1442 // Set the initial unkowns to be the original problem
1443 Previous_dofs.resize(Ndof * N_tstorage + 1, 0.0);
1445 }
1446
1447
1448 /// Destructor, destroy the time mesh
1450 {
1451 delete Time_mesh_pt;
1452 }
1453 };
1454
1455
1457 {
1458 public:
1460
1461
1462 /// Interface to get the current value of all (internal and shared) unknowns
1464
1465 /// Interface to get the current value of the time derivative of
1466 /// all (internal and shared) unknowns
1468
1469
1470 /// Get the inner product matrix
1472 {
1473 const unsigned n_dof = this->ndof();
1474 inner_product.initialise(0.0);
1475 for (unsigned i = 0; i < n_dof; i++)
1476 {
1477 inner_product(i, i) = 1.0;
1478 }
1479 }
1480
1481 virtual void spacetime_output(std::ostream& outilfe,
1482 const unsigned& Nplot,
1483 const double& time = 0.0)
1484 {
1485 }
1486 };
1487
1488
1489} // namespace oomph
1490
1491#endif
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
char t
Definition cfortran.h:568
A class that is used to define the functions used to assemble the elemental contributions to the resi...
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition shape.h:278
A class that represents a collection of data; each Data object may contain many different individual ...
Definition nodes.h:86
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition nodes.h:271
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition nodes.h:483
unsigned ntstorage() const
Return total number of doubles stored per value to record time history of each value (one for steady ...
Definition nodes.cc:879
void set_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set a new timestepper by resizing the appropriate storage. If already assigned the equation numbering...
Definition nodes.cc:406
Base class for finite elements that can compute the quantities that are required for the Z2 error est...
A general Finite Element class.
Definition elements.h:1317
double nodal_value(const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n. Produces suitably interpolated values for hanging nodes...
Definition elements.h:2597
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing.
Definition elements.h:3054
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
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:1436
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
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:3328
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
A Generalised Element class.
Definition elements.h:73
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
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition elements.h:605
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
Definition elements.h:227
unsigned ninternal_data() const
Return the number of internal data objects.
Definition elements.h:810
virtual void assign_local_eqn_numbers(const bool &store_local_dof_pt)
Setup the arrays of local equation numbers for the element. If the optional boolean argument is true,...
Definition elements.cc:696
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
void build(const OomphCommunicator *const comm_pt, const unsigned &first_row, const unsigned &nrow_local, const unsigned &nrow=0)
Sets the distribution. Takes first_row, nrow_local and nrow as arguments. If nrow is not provided or ...
A general mesh class.
Definition mesh.h:67
static Steady< 0 > Default_TimeStepper
Default Steady Timestepper, to be used in default arguments to Mesh constructors.
Definition mesh.h:75
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition mesh.h:440
unsigned long nnode() const
Return number of nodes in the mesh.
Definition mesh.h:604
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition mesh.h:452
const Vector< GeneralisedElement * > & element_pt() const
Return reference to the Vector of elements.
Definition mesh.h:464
unsigned long nelement() const
Return number of elements in the mesh.
Definition mesh.h:598
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition mesh.h:497
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition nodes.h:1060
virtual void make_periodic(Node *const &node_pt)
Make the node periodic by copying the values from node_pt. Note that the coordinates will always rema...
Definition nodes.cc:2257
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation....
Definition nodes.cc:2408
1D mesh consisting of N one-dimensional elements from the QElement family.
Definition one_d_mesh.h:52
An OomphLibError object which should be thrown when an run-time error is encountered....
=============================================================== Base class to avoid template complica...
virtual void set_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > const &dofs)=0
virtual void get_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > &dofs)=0
virtual void get_previous_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > &dofs)=0
A class that is used to assemble and solve the augmented system of equations associated with calculat...
void adapt_temporal_mesh()
Adapt the time mesh.
void set_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > const &dofs)
void orbit_output(std::ostream &outfile, const unsigned &n_plot)
Calculate all desired vectors and matrices provided by the element elem_pt.
unsigned N_element_in_period
Storage for number of elements in the period.
void discrete_times(Vector< double > &t)
Tell me the times at which you want the solution.
void get_previous_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > &dofs)
void get_jacobian(GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
Calculate the elemental Jacobian matrix "d equation / d variable" for elem_pt.
~PeriodicOrbitAssemblyHandler()
Destructor, destroy the time mesh.
void get_dofs_for_element(GeneralisedElement *const elem_pt, Vector< double > &dofs)
unsigned Ndof
Store number of degrees of freedom in the original problem.
PeriodicOrbitTemporalMesh< SpectralPeriodicOrbitElement< NNODE_1D > > * Time_mesh_pt
Storage for mesh of temporal elements.
Vector< double > Previous_dofs
Storage for the previous solution.
unsigned ndof(GeneralisedElement *const &elem_pt)
Return the number of degrees of freedom in the element elem_pt.
void set_previous_dofs_to_current_dofs()
Update the previous dofs.
Problem * Problem_pt
Pointer to the problem.
unsigned long eqn_number(GeneralisedElement *const &elem_pt, const unsigned &ieqn_local)
Return the global equation number of the local unknown ieqn_local in elem_pt.
unsigned N_tstorage
Storage for the number of unknown time values.
PeriodicOrbitTimeDiscretisation * Time_stepper_pt
Pointer to the timestepper.
Mesh * Basic_time_mesh_pt
Storage for the mesh of temporal elements with a simple mesh pointer.
double Omega
Storage for the frequency of the orbit (scaled by 2pi)
void get_residuals(GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Return the contribution to the residuals of the element elem_pt.
virtual void get_non_external_ddofs_dt(Vector< double > &du_dt)
Interface to get the current value of the time derivative of all (internal and shared) unknowns.
virtual void spacetime_output(std::ostream &outilfe, const unsigned &Nplot, const double &time=0.0)
virtual void get_non_external_dofs(Vector< double > &u)
Interface to get the current value of all (internal and shared) unknowns.
virtual void get_inner_product_matrix(DenseMatrix< double > &inner_product)
Get the inner product matrix.
Time * Time_pt
Pointer to global time.
void orbit_output(GeneralisedElement *const &elem_pt, std::ostream &outfile, const unsigned &n_plot)
Time *const & time_pt() const
Return the pointer to the global time (const version)
Time *& time_pt()
Retun the pointer to the global time.
double *& omega_pt()
Broken assignment operator.
void fill_in_contribution_to_integrated_jacobian(PeriodicOrbitAssemblyHandlerBase *const &assembly_handler_pt, GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the element's contribution to its residual vector and element Jacobian matrix (wrapper)
void set_timestepper_weights(const Shape &psi, const DShape &dpsidt)
Set the timestepper weights.
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 ...
void fill_in_contribution_to_integrated_residuals(PeriodicOrbitAssemblyHandlerBase *const &assembly_handler_pt, GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Add the element's contribution to its residual vector (wrapper)
virtual double dshape_and_dtest_eulerian_orbit(const Vector< double > &s, Shape &psi, DShape &dpsidt, Shape &test, DShape &dtestdt) const =0
Shape/test functions and derivs w.r.t. to global coords at local coord. s; return Jacobian of mapping...
double time() const
Return the global time, accessed via the time pointer.
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!
void set_ntstorage(const unsigned &n_tstorage)
Set the total number of time storage values.
double omega()
Return the frequency.
PeriodicOrbitEquations(const PeriodicOrbitEquations &dummy)=delete
Broken copy constructor.
A special temporal mesh class.
PeriodicOrbitTemporalMesh(const unsigned &n_element)
Constructor, create a 1D mesh from 0 to 1 that is periodic.
void assemble_residuals_and_jacobian(PeriodicOrbitAssemblyHandlerBase *const &assembly_handler_pt, GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
void orbit_output(GeneralisedElement *const &elem_pt, std::ostream &outfile, const unsigned &n_plot)
void assemble_residuals(PeriodicOrbitAssemblyHandlerBase *const &assembly_handler_pt, GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Timestepper used to calculate periodic orbits directly. It's not really a "timestepper" per se,...
double(* InitialConditionFctPt)(const double &t)
Typedef for function that returns the (scalar) initial value at a given value of the continuous time ...
void shift_time_positions(Node *const &node_pt)
Broken shifting of time positions.
unsigned order() const
Return the actual order of the scheme.
void assign_initial_values_impulsive(Data *const &data_pt)
Broken initialisation the time-history for the Data values corresponding to an impulsive start.
void shift_time_values(Data *const &data_pt)
Broken shifting of time values.
PeriodicOrbitTimeDiscretisation(const unsigned &n_tstorage)
Constructor for the case when we allow adaptive timestepping.
void assign_initial_positions_impulsive(Node *const &node_pt)
Broken initialisation of the positions for the node corresponding to an impulsive start.
void assign_initial_data_values(Data *const &data_pt, Vector< InitialConditionFctPt > initial_value_fct)
Initialise the time-history for the Data values, corresponding to given time history,...
unsigned ndt() const
Number of timestep increments that need to be stored by the scheme.
PeriodicOrbitTimeDiscretisation(const PeriodicOrbitTimeDiscretisation &)=delete
Broken copy constructor.
void operator=(const PeriodicOrbitTimeDiscretisation &)=delete
Broken assignment operator.
unsigned nprev_values() const
Number of previous values available.
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition problem.h:154
unsigned long assign_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Assign all equation numbers for problem: Deals with global data (= data that isn't attached to any el...
Definition problem.cc:2085
unsigned long ndof() const
Return the number of dofs.
Definition problem.h:1704
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition problem.h:1266
double & dof(const unsigned &i)
i-th dof in the problem
Definition problem.h:1843
unsigned nglobal_data() const
Return the number of global data values.
Definition problem.h:1716
Data *& global_data_pt(const unsigned &i)
Return a pointer to the the i-th global data object.
Definition problem.h:1673
Vector< double * > Dof_pt
Vector of pointers to dofs.
Definition problem.h:557
unsigned nsub_mesh() const
Return number of submeshes.
Definition problem.h:1343
LinearAlgebraDistribution * Dof_distribution_pt
The distribution of the DOFs in this problem. This object is created in the Problem constructor and s...
Definition problem.h:463
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition problem.h:1300
Time *& time_pt()
Return a pointer to the global time object.
Definition problem.h:1524
void shape(const Vector< double > &s, Shape &psi) const
Calculate the geometric shape functions at local coordinate s.
General QLegendreElement class.
Refineable version of the OneDMesh.
Definition one_d_mesh.h:122
A class that is used to template the refineable Q spectral elements by dimension. It's really nothing...
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition shape.h:76
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition nodes.h:1686
QPoissonElement elements are linear/quadrilateral/brick-shaped Poisson elements with isoparametric in...
double dshape_and_dtest_eulerian_at_knot_orbit(const unsigned &ipt, Shape &psi, DShape &dpsidt, Shape &test, DShape &dtestdt) const
Shape, test functions & derivs. w.r.t. to global coords. at integration point ipt....
double dshape_and_dtest_eulerian_orbit(const Vector< double > &s, Shape &psi, DShape &dpsidt, Shape &test, DShape &dtestdt) const
Shape, test functions & derivs. w.r.t. to global coords. Return Jacobian.
void get_interpolated_values(const Vector< double > &s, Vector< double > &value)
Return the dummy values.
void output(FILE *file_pt)
C-style output function: x,y,u or x,y,z,u.
unsigned nrecovery_order()
Order of recovery shape functions.
unsigned nvertex_node() const
Number of vertex nodes in the element.
void get_interpolated_values(const unsigned &t, const Vector< double > &s, Vector< double > &value)
Return the temporal dummy values.
unsigned num_Z2_flux_terms()
Number of flux terms for Z2 error estimation This will be used to represent all spatial values,...
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
unsigned ncont_interpolated_values() const
Number of continuously interpolated values (1)
unsigned required_nvalue(const unsigned &n) const
Broken assignment operator.
void output(std::ostream &outfile, const unsigned &n_plot)
Output function: x,y,u or x,y,z,u at n_plot^DIM plot points.
void output(std::ostream &outfile)
Function to return the number of values.
SpectralPeriodicOrbitElement(const SpectralPeriodicOrbitElement< NNODE_1D > &dummy)=delete
Broken copy constructor.
SpectralPeriodicOrbitElement()
Constructor: Call constructors for QElement and Poisson equations.
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function: x,y,u or x,y,z,u at n_plot^DIM plot points.
void get_Z2_flux(const Vector< double > &s, Vector< double > &flux)
Get the fluxes for the recovert.
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...
Time * Time_pt
Pointer to discrete time storage scheme.
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
double & time()
Return current value of continous time.
Class to keep track of discrete/continous time. It is essential to have a single Time object when usi...
double & time()
Return the current value of the continuous time.
Z2-error-estimator: Elements that can be used with Z2 error estimation should be derived from the bas...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...