two_d_unsteady_heat_2adapt.cc
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Copyright (C) 2006-2023 Matthias Heil and Andrew Hazel
7 //LIC//
8 //LIC// This library is free software; you can redistribute it and/or
9 //LIC// modify it under the terms of the GNU Lesser General Public
10 //LIC// License as published by the Free Software Foundation; either
11 //LIC// version 2.1 of the License, or (at your option) any later version.
12 //LIC//
13 //LIC// This library is distributed in the hope that it will be useful,
14 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 //LIC// Lesser General Public License for more details.
17 //LIC//
18 //LIC// You should have received a copy of the GNU Lesser General Public
19 //LIC// License along with this library; if not, write to the Free Software
20 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //LIC// 02110-1301 USA.
22 //LIC//
23 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 //LIC//
25 //LIC//====================================================================
26 //Driver for doubly adaptive 2D unsteady heat problem in moving domain
27 
28 //Generic routines
29 #include "generic.h"
30 
31 // The unsteady heat equations
32 #include "unsteady_heat.h"
33 
34 // Mesh
35 #include "meshes/quarter_circle_sector_mesh.h"
36 
37 using namespace std;
38 
39 using namespace oomph;
40 
41 using namespace MathematicalConstants;
42 
43 
44 //============start_of_MyEllipse===========================================
45 /// Oscillating ellipse
46 /// \f[ x = (a + \widehat{a} \sin(2\Pi t/T)) \cos(\xi) \f]
47 /// \f[ y = (b + \widehat{b} \sin(2\Pi t/T)) \sin(\xi) \f]
48 //=========================================================================
49 class MyEllipse : public GeomObject
50 {
51 
52 public:
53 
54  /// Constructor: Pass half axes, amplitudes of their variation, period
55  /// of oscillation and pointer to time object.
56  MyEllipse(const double& a, const double& b,
57  const double& a_hat, const double& b_hat,
58  const double& period, Time* time_pt) :
59  GeomObject(1,2), A(a), B(b), A_hat(a_hat), B_hat(b_hat),
60  T(period), Time_pt(time_pt) {}
61 
62  /// Destructor: Empty
63  virtual ~MyEllipse() {}
64 
65  /// Current position vector to material point at
66  /// Lagrangian coordinate xi
67  void position(const Vector<double>& xi, Vector<double>& r) const
68  {
69  // Get current time:
70  double time=Time_pt->time();
71 
72  // Position vector
73  r[0] = (A+A_hat*sin(2.0*MathematicalConstants::Pi*time/T))*cos(xi[0]);
74  r[1] = (B+B_hat*sin(2.0*MathematicalConstants::Pi*time/T))*sin(xi[0]);
75 
76  } // end of position(...)
77 
78 
79 
80  /// Parametrised position on object: r(xi). Evaluated at
81  /// previous time level. t=0: current time; t>0: previous
82  /// time level.
83  void position(const unsigned& t, const Vector<double>& xi,
84  Vector<double>& r) const
85  {
86  // Get current time:
87  double time=Time_pt->time(t);
88 
89  // Position vector
90  r[0] = (A+A_hat*sin(2.0*MathematicalConstants::Pi*time/T))*cos(xi[0]);
91  r[1] = (B+B_hat*sin(2.0*MathematicalConstants::Pi*time/T))*sin(xi[0]);
92 
93  } // end of position(...)
94 
95 
96 protected:
97 
98  /// x-half axis
99  double A;
100 
101  /// y-half axis
102  double B;
103 
104  /// Amplitude of variation in x-half axis
105  double A_hat;
106 
107  /// Amplitude of variation in y-half axis
108  double B_hat;
109 
110  /// Period of oscillation
111  double T;
112 
113  /// Pointer to time object
114  Time* Time_pt;
115 
116 }; // end of MyEllipse
117 
118 /// ////////////////////////////////////////////////////////////////////
119 /// ////////////////////////////////////////////////////////////////////
120 /// /////////////////////////////////////////////////////////////////////
121 
122 
123 //======start_of_TanhSolnForUnsteadyHeat==============================
124 /// Namespace for exact solution of unsteady heat equation
125 /// with sharp step
126 //====================================================================
128 {
129 
130  /// Parameter for steepness of step
131  double Alpha;
132 
133  /// Parameter for amplitude of step translation
134  double Beta;
135 
136  /// Parameter for timescale of step translation
137  double Gamma;
138 
139  /// Parameter for angle of step
140  double TanPhi;
141 
142  /// Position of step (x-axis intercept)
143  double step_position(const double& time)
144  {
145  return Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*time));
146  }
147 
148  /// Exact solution as a Vector
149  void get_exact_u(const double& time, const Vector<double>& x,
150  Vector<double>& u)
151  {
152  double X=x[0];
153  double Y=x[1];
154  u[0]=tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
155  MathematicalConstants::Pi*time)))-Y));
156  }
157 
158  /// Exact solution as a scalar
159  void get_exact_u(const double& time, const Vector<double>& x, double& u)
160  {
161  double X=x[0];
162  double Y=x[1];
163  u=tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
164  MathematicalConstants::Pi*time)))-Y));
165  }
166 
167  /// Source function to make it an exact solution
168  void get_source(const double& time, const Vector<double>& x, double& source)
169  {
170  double X=x[0];
171  double Y=x[1];
172  source = -2.0*tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
173 MathematicalConstants::Pi*time)))-Y))*(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-
174 Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*
175 Alpha*TanPhi*TanPhi-2.0*tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
176 MathematicalConstants::Pi*time)))-Y))*(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-
177 Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*
178 Alpha+0.2E1*(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
179 MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*TanPhi*Beta*(1.0-pow(tanh(
180 Gamma*cos(0.2E1*MathematicalConstants::Pi*time)),2.0))*Gamma*sin(0.2E1*
181 MathematicalConstants::Pi*time)*MathematicalConstants::Pi;
182  }
183 
184  /// Flux required by the exact solution on a boundary on which y is fixed
185  void prescribed_flux_on_fixed_y_boundary(const double& time,
186  const Vector<double>& x,
187  double& flux)
188  {
189  double X=x[0];
190  double Y=x[1];
191 
192  //The outer unit normal to the boundary is (0,-1)
193  double NX = 0.0;
194  double NY = -1.0;
195 
196  //The flux in terms of the normal is
197  flux = -(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
198 MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*TanPhi*NX+(1.0-pow(tanh(
199 0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*
200 time)))-Y)),2.0))*Alpha*NY;
201  }
202 
203 } // end of TanhSolnForUnsteadyHeat
204 
205 
206 /// /////////////////////////////////////////////////////////////////////
207 /// /////////////////////////////////////////////////////////////////////
208 /// /////////////////////////////////////////////////////////////////////
209 
210 
211 //=====start_of_problem_class=========================================
212 /// Unsteady heat problem in deformable ellipse domain.
213 //====================================================================
214 template<class ELEMENT>
215 class RefineableUnsteadyHeatProblem : public Problem
216 {
217 
218 public:
219 
220  /// Constructor: Pass pointer to source function and timestep
222  UnsteadyHeatEquations<2>::UnsteadyHeatSourceFctPt source_fct_pt);
223 
224  /// Destructor: Close trace file
226 
227  /// Update the problem specs after solve (empty)
229 
230  /// Update the problem specs before solve (empty)
232 
233  /// Update the problem specs after timestep (empty)
235 
236  /// Update the problem specs before next timestep:
237  /// Set Dirchlet boundary conditions from exact solution.
238  void actions_before_implicit_timestep();
239 
240  /// Actions before adapt: Wipe the mesh of prescribed flux elements
241  void actions_before_adapt();
242 
243  /// Actions after adapt: Rebuild the mesh of prescribed flux elements
244  void actions_after_adapt();
245 
246  /// Global error norm for adaptive time-stepping
247  double global_temporal_error_norm();
248 
249  /// Set initial condition (incl previous timesteps) according
250  /// to specified function.
251  void set_initial_condition();
252 
253  /// Create UnsteadyHeat flux elements on boundary b of the Mesh pointed
254  /// to by bulk_mesh_pt and add them to the Mesh object pointed to by
255  /// surface_mesh_pt
256  void create_flux_elements(const unsigned &b, Mesh* const &bulk_mesh_pt,
257  Mesh* const &surface_mesh_pt);
258 
259  /// Delete UnsteadyHeat flux elements and wipe the surface mesh
260  void delete_flux_elements(Mesh* const &surface_mesh_pt);
261 
262  /// Doc the solution
263  void doc_solution();
264 
265  /// Dump problem data to allow for later restart
266  void dump_it(ofstream& dump_file);
267 
268  /// Read problem data for restart
269  void restart(ifstream& restart_file);
270 
271  /// Pointer to bulk mesh
272  RefineableQuarterCircleSectorMesh<ELEMENT>* bulk_mesh_pt()
273  {
274  return Bulk_mesh_pt;
275  }
276 
277  /// Target error for adaptive timestepping
278  double& epsilon_t() {return Epsilon_t;}
279 
280  /// Write header for trace file
281  void write_trace_file_header();
282 
283  /// Suggestion for next timestep (stored to allow it to be written
284  /// to (or read from) restart file)
285  double& next_dt(){return Next_dt;}
286 
287 private:
288 
289  /// Doc info object
290  DocInfo Doc_info;
291 
292  /// Suggestion for next timestep (stored to allow it to be written
293  /// to (or read from) restart file)
294  double Next_dt;
295 
296  /// Pointer to GeomObject that specifies the domain bondary
297  GeomObject* Boundary_pt;
298 
299  /// Pointer to source function
300  UnsteadyHeatEquations<2>::UnsteadyHeatSourceFctPt Source_fct_pt;
301 
302  /// Pointer to the "bulk" mesh
303  RefineableQuarterCircleSectorMesh<ELEMENT>* Bulk_mesh_pt;
304 
305  /// Pointer to the "surface" mesh
307 
308  /// Pointer to central node (exists at all refinement levels) for doc
309  Node* Doc_node_pt;
310 
311  /// Trace file
312  ofstream Trace_file;
313 
314  /// Target error for adaptive timestepping
315  double Epsilon_t;
316 
317 }; // end of problem_class
318 
319 //========start_of_constructor============================================
320 /// Constructor for UnsteadyHeat problem on deformable ellipse domain.
321 /// Pass pointer to source function.
322 //========================================================================
323 template<class ELEMENT>
325  UnsteadyHeatEquations<2>::UnsteadyHeatSourceFctPt source_fct_pt)
326  : Source_fct_pt(source_fct_pt)
327 {
328 
329  // Setup labels for output
330  //------------------------
331 
332  // Output directory
333  Doc_info.set_directory("RESLT");
334 
335  // Output number
336  Doc_info.number()=0;
337 
338 
339  // Setup timestepping
340  //-------------------
341 
342  // Allocate the timestepper -- this constructs the time object as well.
343  // The boolean flag to the constructor enables adaptivity.
344  add_time_stepper_pt(new BDF<2>(true));
345 
346  // Set target error for adaptive timestepping
347  Epsilon_t=1.0e-2;
348 
349  // Setup parameters for tanh solution
350  // ----------------------------------
351 
352  // Steepness of step
354 
355  // Orientation of step
357 
358  // Amplitude for movement of step
360 
361  // Parameter for time-dependence of step movement
363 
364  // Setup mesh
365  //-----------
366 
367  // Build geometric object that forms the curvilinear domain boundary:
368  // an oscillating ellipse
369 
370  // Half axes
371  double a=1.0;
372  double b=1.0;
373 
374  // Variations of half axes
375  double a_hat= 0.1;
376  double b_hat=-0.1;
377 
378  // Period of the oscillation
379  double period=1.0;
380 
381  // Create GeomObject
382  Boundary_pt=new MyEllipse(a,b,a_hat,b_hat,period,Problem::time_pt());
383 
384  // Start and end coordinates of curvilinear domain boundary on ellipse
385  double xi_lo=0.0;
386  double xi_hi=MathematicalConstants::Pi/2.0;
387 
388  // Now create the bulk mesh. Separating line between the two
389  // elements next to the curvilinear boundary is located half-way
390  // along the boundary.
391  double fract_mid=0.5;
392  Bulk_mesh_pt = new RefineableQuarterCircleSectorMesh<ELEMENT>(
393  Boundary_pt,xi_lo,fract_mid,xi_hi,time_stepper_pt());
394 
395  // Create the surface mesh as an empty mesh
396  Surface_mesh_pt=new Mesh;
397 
398  // Create prescribed-flux elements from all elements that are
399  // adjacent to boundary 0 (the horizontal lower boundary), and add them
400  // to the (so far empty) surface mesh.
402 
403  // Add the two sub meshes to the problem
404  add_sub_mesh(Bulk_mesh_pt);
405  add_sub_mesh(Surface_mesh_pt);
406 
407  // Combine all submeshes into a single global Mesh
408  build_global_mesh();
409 
410  // Set error estimator for bulk mesh
411  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
412  Bulk_mesh_pt->spatial_error_estimator_pt()=error_estimator_pt;
413 
414  // Set the boundary conditions for this problem: All nodes are
415  // free by default -- just pin the ones that have Dirichlet conditions
416  // here.
417  unsigned n_bound = Bulk_mesh_pt->nboundary();
418  for(unsigned b=0;b<n_bound;b++)
419  {
420  // Leave nodes on boundary 0 free -- this is where we apply the flux
421  // boundary condition
422  if (b!=0)
423  {
424  unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
425  for (unsigned n=0;n<n_node;n++)
426  {
427  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
428  }
429  }
430  }
431 
432  // Extract pointer to the central node (this exists at all refinement levels)
433  // for doc of solution
434  FiniteElement* el0_pt=Bulk_mesh_pt->finite_element_pt(0);
435  unsigned nnod=el0_pt->nnode();
436  Doc_node_pt=el0_pt->node_pt(nnod-1);
437 
438 
439  // Complete the build of all elements so they are fully functional
440  //----------------------------------------------------------------
441 
442  // Find number of elements in mesh
443  unsigned n_element = Bulk_mesh_pt->nelement();
444 
445  // Loop over the elements to set up element-specific
446  // things that cannot be handled by constructor
447  for(unsigned i=0;i<n_element;i++)
448  {
449  // Upcast from FiniteElement to the present element
450  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(i));
451 
452  //Set the source function pointer
453  el_pt->source_fct_pt() = Source_fct_pt;
454  }
455 
456  // Loop over the flux elements to pass pointer to prescribed flux function
457  n_element=Surface_mesh_pt->nelement();
458  for(unsigned e=0;e<n_element;e++)
459  {
460  // Upcast from GeneralisedElement to UnsteadyHeat flux element
461  UnsteadyHeatFluxElement<ELEMENT> *el_pt =
462  dynamic_cast<UnsteadyHeatFluxElement<ELEMENT>*>(
463  Surface_mesh_pt->element_pt(e));
464 
465  // Set the pointer to the prescribed flux function
466  el_pt->flux_fct_pt() =
468  }
469 
470  // Do equation numbering
471  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
472 
473 } // end of constructor
474 
475 
476 //======start_of_destructor===============================================
477 /// Destructor: Close trace file
478 //========================================================================
479 template<class ELEMENT>
481 {
482  // Close trace file
483  Trace_file.close();
484 } // end of destructor
485 
486 
487 //=========start of actions_before_implicit_timestep===============================
488 /// Actions before timestep: Update the domain shape, then set the
489 /// boundary conditions for the current time.
490 //========================================================================
491 template<class ELEMENT>
493 {
494  // Update the domain shape
495  Bulk_mesh_pt->node_update();
496 
497  // Get current time
498  double time=time_pt()->time();
499 
500  //Loop over all boundaries
501  unsigned num_bound = Bulk_mesh_pt->nboundary();
502  for(unsigned b=0;b<num_bound;b++)
503  {
504  // Exclude flux boundary
505  if (b!=0)
506  {
507  // Loop over the nodes on boundary
508  unsigned num_nod=Bulk_mesh_pt->nboundary_node(b);
509  for (unsigned j=0;j<num_nod;j++)
510  {
511  Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(b,j);
512  double u;
513  Vector<double> x(2);
514  x[0]=nod_pt->x(0);
515  x[1]=nod_pt->x(1);
517  nod_pt->set_value(0,u);
518  }
519  }
520  }
521 } // end of actions_before_implicit_timestep
522 
523 
524 //=========start_of_actions_before_adapt==================================
525 /// Actions before adapt: Wipe the mesh of prescribed flux elements
526 //========================================================================
527 template<class ELEMENT>
529 {
530 
531  // Kill the flux elements and wipe surface mesh
532  delete_flux_elements(Surface_mesh_pt);
533 
534  // Rebuild the global mesh.
535  rebuild_global_mesh();
536 
537 } // end of actions_before_adapt
538 
539 
540 //==========start_of_actions_after_adapt==================================
541 /// Actions after adapt: Rebuild the mesh of prescribed flux elements
542 //========================================================================
543 template<class ELEMENT>
545 {
546  // Create prescribed-flux elements from all elements that are
547  // adjacent to boundary 0 and add them to surface mesh
548  create_flux_elements(0,Bulk_mesh_pt,Surface_mesh_pt);
549 
550  // Rebuild the global mesh
551  rebuild_global_mesh();
552 
553  // Loop over the flux elements to pass pointer to prescribed flux function
554  unsigned n_element=Surface_mesh_pt->nelement();
555  for(unsigned e=0;e<n_element;e++)
556  {
557  // Upcast from GeneralisedElement to UnsteadyHeat flux element
558  UnsteadyHeatFluxElement<ELEMENT> *el_pt =
559  dynamic_cast<UnsteadyHeatFluxElement<ELEMENT>*>(
560  Surface_mesh_pt->element_pt(e));
561 
562  // Set the pointer to the prescribed flux function
563  el_pt->flux_fct_pt() =
565  }
566 } // end of actions_after_adapt
567 
568 
569 //======================start_of_set_initial_condition====================
570 /// Set initial condition: Assign previous and current values
571 /// from exact solution.
572 //========================================================================
573 template<class ELEMENT>
575 {
576 
577  // Pointer to restart file
578  ifstream* restart_file_pt=0;
579 
580  // Restart?
581  //---------
582  // Restart file specified via command line [all programs have at least
583  // a single command line argument: their name. Ignore this here.]
584  if (CommandLineArgs::Argc==1)
585  {
586  cout << "No restart -- setting IC from exact solution" << std::endl;
587  }
588  else if (CommandLineArgs::Argc==2)
589  {
590  // Open restart file
591  restart_file_pt= new ifstream(CommandLineArgs::Argv[1],ios_base::in);
592  if (restart_file_pt!=0)
593  {
594  cout << "Have opened " << CommandLineArgs::Argv[1] <<
595  " for restart. " << std::endl;
596  }
597  else
598  {
599  std::ostringstream error_stream;
600  error_stream
601  << "ERROR while trying to open " << CommandLineArgs::Argv[1]
602  << " for restart." << std::endl;
603 
604  throw OomphLibError(
605  error_stream.str(),
606  OOMPH_CURRENT_FUNCTION,
607  OOMPH_EXCEPTION_LOCATION);
608  }
609  }
610  // More than one command line argument?
611  else
612  {
613  std::ostringstream error_stream;
614  error_stream << "Can only specify one input file\n"
615  << "You specified the following command line arguments:\n";
616 
617  throw OomphLibError(
618  error_stream.str(),
619  OOMPH_CURRENT_FUNCTION,
620  OOMPH_EXCEPTION_LOCATION);
621 
622 
623  //REWRITE THIS
624  CommandLineArgs::output();
625  }
626 
627 
628  // Read restart data:
629  //-------------------
630  if (restart_file_pt!=0)
631  {
632  // Read the data from restart file and find out if the restart file
633  // was from an unsteady run
634  restart(*restart_file_pt);
635  }
636  // Assign initial condition from exact solution
637  //---------------------------------------------
638  else
639  {
640  // Choose initial timestep
641  double dt0=0.005;
642 
643  // Initialise timestep -- also sets the weights for all timesteppers
644  // in the problem.
645  initialise_dt(dt0);
646 
647  // Use this as the first "suggested" timestep
648  Next_dt=dt0;
649 
650  // Backup time in global timestepper
651  double backed_up_time=time_pt()->time();
652 
653  // Past history for velocities must be established for t=time0-deltat, ...
654  // Then provide current values (at t=time0) which will also form
655  // the initial guess for first solve at t=time0+deltat
656 
657  // Vector of exact solution value
658  Vector<double> soln(1);
659  Vector<double> x(2);
660 
661  //Find number of nodes in mesh
662  unsigned num_nod = Bulk_mesh_pt->nnode();
663 
664  // Get continuous times at previous timesteps
665  int nprev_steps=time_stepper_pt()->nprev_values();
666  Vector<double> prev_time(nprev_steps+1);
667  for (int itime=nprev_steps;itime>=0;itime--)
668  {
669  prev_time[itime]=time_pt()->time(unsigned(itime));
670  }
671 
672  // Loop over current & previous timesteps (in outer loop because
673  // the mesh also moves!)
674  for (int itime=nprev_steps;itime>=0;itime--)
675  {
676  double time=prev_time[itime];
677 
678  // Set global time (because this is how the geometric object refers
679  // to continous time
680  time_pt()->time()=time;
681 
682  cout << "setting IC at time =" << time << std::endl;
683 
684  // Update the mesh for this value of the continuous time
685  // (The wall object reads the continous time from the same
686  // global time object)
687  Bulk_mesh_pt->node_update();
688 
689  // Loop over the nodes to set initial guess everywhere
690  for (unsigned jnod=0;jnod<num_nod;jnod++)
691  {
692  // Get nodal coordinates
693  x[0]=Bulk_mesh_pt->node_pt(jnod)->x(0);
694  x[1]=Bulk_mesh_pt->node_pt(jnod)->x(1);
695 
696  // Get intial solution
698 
699  // Assign solution
700  Bulk_mesh_pt->node_pt(jnod)->set_value(itime,0,soln[0]);
701 
702  // Loop over coordinate directions
703  for (unsigned i=0;i<2;i++)
704  {
705  Bulk_mesh_pt->node_pt(jnod)->x(itime,i)=x[i];
706  }
707  }
708  }
709 
710  // Reset backed up time for global timestepper
711  time_pt()->time()=backed_up_time;
712  }
713 
714 } // end of set_initial_condition
715 
716 
717 
718 
719 //=======start_of_write_trace_file_header=================================
720 /// Write the tecplot header for the trace file
721 //========================================================================
722 template<class ELEMENT>
724 {
725  // Open trace file
726  char filename[100];
727  sprintf(filename,"%s/trace.dat",Doc_info.directory().c_str());
728  Trace_file.open(filename);
729 
730  Trace_file << "VARIABLES=\"time t\","
731  << "\"u<SUB>FE</SUB>\","
732  << "\"u<SUB>exact</SUB>\","
733  << "\"A\","
734  << "\"dt\","
735  << "\"global temporal error norm\","
736  << "\"X<SUB>step</SUB>\","
737  << "\"N<SUB>element</SUB>\","
738  << "\"N<SUB>refined</SUB>\","
739  << "\"N<SUB>unrefined</SUB>\","
740  << "\"norm of error\","
741  << "\"norm of solution\""
742  << std::endl;
743  Trace_file << "ZONE T=\"" << time_stepper_pt()->type()
744  << time_stepper_pt()->nprev_values()
745  << "; initial dt="
746  << time_pt()->dt() << "; ";
747  if (time_stepper_pt()->adaptive_flag())
748  {
749  Trace_file << "adaptive; target error " << Epsilon_t << " \"" << std::endl;
750  }
751  else
752  {
753  Trace_file << "(fixed timestep)\"" << std::endl;
754  }
755 
756 } // end of write_trace_file_header
757 
758 
759 
760 //=======start_of_doc_solution============================================
761 /// Doc the solution
762 //========================================================================
763 template<class ELEMENT>
765 {
766  ofstream some_file;
767  char filename[100];
768 
769  // Number of plot points
770  unsigned npts;
771  npts=5;
772 
773  cout << std::endl;
774  cout << "=================================================" << std::endl;
775  cout << "Docing solution for t=" << time_pt()->time() << std::endl;
776  cout << "=================================================" << std::endl;
777 
778  // Output solution
779  //-----------------
780  sprintf(filename,"%s/soln%i.dat",Doc_info.directory().c_str(),
781  Doc_info.number());
782  some_file.open(filename);
783  Bulk_mesh_pt->output(some_file,npts);
784  some_file << "TEXT X=2.5,Y=93.6,F=HELV,HU=POINT,C=BLUE,H=26,T=\"time = "
785  << time_pt()->time() << "\"";
786  some_file << "GEOMETRY X=2.5,Y=98,T=LINE,C=BLUE,LT=0.4" << std::endl;
787  some_file << "1" << std::endl;
788  some_file << "2" << std::endl;
789  some_file << " 0 0" << std::endl;
790  some_file << time_pt()->time()*20.0 << " 0" << std::endl;
791 
792  // Write dummy zones
793  some_file << "ZONE I=2,J=2" << std::endl;
794  some_file << "0.0 0.0 -1.2" << std::endl;
795  some_file << "1.3 0.0 -1.2" << std::endl;
796  some_file << "0.0 1.3 -1.2" << std::endl;
797  some_file << "1.3 1.3 -1.2" << std::endl;
798  some_file << "ZONE I=2,J=2" << std::endl;
799  some_file << "0.0 0.0 1.2" << std::endl;
800  some_file << "1.3 0.0 1.2" << std::endl;
801  some_file << "0.0 1.3 1.2" << std::endl;
802  some_file << "1.3 1.3 1.2" << std::endl;
803 
804  some_file.close();
805 
806 
807  // Output exact solution
808  //----------------------
809  sprintf(filename,"%s/exact_soln%i.dat",Doc_info.directory().c_str(),
810  Doc_info.number());
811  some_file.open(filename);
812  Bulk_mesh_pt->output_fct(some_file,npts,time_pt()->time(),
814 
815  // Write dummy zones
816  some_file << "ZONE I=2,J=2" << std::endl;
817  some_file << "0.0 0.0 -1.2" << std::endl;
818  some_file << "1.3 0.0 -1.2" << std::endl;
819  some_file << "0.0 1.3 -1.2" << std::endl;
820  some_file << "1.3 1.3 -1.2" << std::endl;
821  some_file << "ZONE I=2,J=2" << std::endl;
822  some_file << "0.0 0.0 1.2" << std::endl;
823  some_file << "1.3 0.0 1.2" << std::endl;
824  some_file << "0.0 1.3 1.2" << std::endl;
825  some_file << "1.3 1.3 1.2" << std::endl;
826 
827  some_file.close();
828 
829 
830  // Doc error
831  //----------
832  double error,norm;
833  sprintf(filename,"%s/error%i.dat",Doc_info.directory().c_str(),
834  Doc_info.number());
835  some_file.open(filename);
836  Bulk_mesh_pt->compute_error(some_file,
838  time_pt()->time(),
839  error,norm);
840  some_file.close();
841 
842 
843 
844  // Doc error and write trace file
845  //--------------------------------
846  cout << "error: " << error << std::endl;
847  cout << "norm : " << norm << std::endl << std::endl;
848 
849  Vector<double> x(2);
850  x[0]=Doc_node_pt->x(0);
851  x[1]=Doc_node_pt->x(1);
852  double u_exact;
853  TanhSolnForUnsteadyHeat::get_exact_u(time_pt()->time(),x,u_exact);
854  Vector<double > xi_wall(1);
855  Vector<double > r_wall(2);
856  xi_wall[0]=0.0;
857  Boundary_pt->position(xi_wall,r_wall);
858  Trace_file << time_pt()->time()
859  << " " << Doc_node_pt->value(0)
860  << " " << u_exact
861  << " " << r_wall[0]
862  << " " << time_pt()->dt()
863  << " " << global_temporal_error_norm()
864  << " " << TanhSolnForUnsteadyHeat::step_position(time_pt()->time())
865  << " " << Bulk_mesh_pt->nelement()
866  << " " << Bulk_mesh_pt->nrefined()
867  << " " << Bulk_mesh_pt->nunrefined()
868  << " " << error
869  << " " << norm << std::endl;
870 
871  // Plot wall posn
872  //---------------
873  sprintf(filename,"%s/Wall%i.dat",Doc_info.directory().c_str(),
874  Doc_info.number());
875  some_file.open(filename);
876 
877  unsigned nplot=100;
878  for (unsigned iplot=0;iplot<nplot;iplot++)
879  {
880  xi_wall[0]=0.5*Pi*double(iplot)/double(nplot-1);
881  Boundary_pt->position(xi_wall,r_wall);
882  some_file << r_wall[0] << " " << r_wall[1] << std::endl;
883  }
884  some_file.close();
885 
886  // Write restart file
887  sprintf(filename,"%s/restart%i.dat",Doc_info.directory().c_str(),
888  Doc_info.number());
889  some_file.open(filename);
890  dump_it(some_file);
891  some_file.close();
892 
893  // Increment number of doc
894  Doc_info.number()++;
895 
896 
897 } // end of doc_solution
898 
899 
900 //============start_of_create_flux_elements==============================
901 /// Create UnsteadyHeat Flux Elements on the b-th boundary of the Mesh object
902 /// pointed to by bulk_mesh_pt and add the elements to the Mesh object
903 /// pointed to by surface_mesh_pt.
904 //=======================================================================
905 template<class ELEMENT>
907 create_flux_elements(const unsigned& b, Mesh* const &bulk_mesh_pt,
908  Mesh* const &surface_mesh_pt)
909 {
910  // How many bulk elements are adjacent to boundary b?
911  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
912 
913  // Loop over the bulk elements adjacent to boundary b?
914  for(unsigned e=0;e<n_element;e++)
915  {
916  // Get pointer to the bulk element that is adjacent to boundary b
917  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
918  bulk_mesh_pt->boundary_element_pt(b,e));
919 
920  //What is the face index of element e on boundary b
921  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
922 
923  // Build the corresponding prescribed-flux element
924  UnsteadyHeatFluxElement<ELEMENT>* flux_element_pt = new
925  UnsteadyHeatFluxElement<ELEMENT>(bulk_elem_pt,face_index);
926 
927  //Add the prescribed-flux element to the surface mesh
928  surface_mesh_pt->add_element_pt(flux_element_pt);
929 
930  } //end of loop over bulk elements adjacent to boundary b
931 
932 } // end of create_flux_elements
933 
934 
935 //============start_of_delete_flux_elements==============================
936 /// Delete UnsteadyHeat Flux Elements and wipe the surface mesh
937 //=======================================================================
938 template<class ELEMENT>
940 delete_flux_elements(Mesh* const &surface_mesh_pt)
941 {
942  // How many surface elements are in the surface mesh
943  unsigned n_element = surface_mesh_pt->nelement();
944 
945  // Loop over the surface elements
946  for(unsigned e=0;e<n_element;e++)
947  {
948  // Kill surface element
949  delete surface_mesh_pt->element_pt(e);
950  }
951 
952  // Wipe the mesh
953  surface_mesh_pt->flush_element_and_node_storage();
954 
955 } // end of delete_flux_elements
956 
957 
958 //========start_of_global_temporal_error_norm==============================
959 /// Global error norm for adaptive timestepping: RMS error, based on
960 /// difference between predicted and actual value at all nodes.
961 //=========================================================================
962 template<class ELEMENT>
964 {
965  double global_error = 0.0;
966 
967  //Find out how many nodes there are in the problem
968  unsigned n_node = Bulk_mesh_pt->nnode();
969 
970  //Loop over the nodes and calculate the errors in the values
971  for(unsigned i=0;i<n_node;i++)
972  {
973  // Get error in solution: Difference between predicted and actual
974  // value for nodal value 0
975  double error =
976  Bulk_mesh_pt->node_pt(i)->time_stepper_pt()->
977  temporal_error_in_value(Bulk_mesh_pt->node_pt(i),0);
978 
979  //Add the square of the individual error to the global error
980  global_error += error*error;
981  }
982 
983  //Now the global error must be divided by the number of nodes
984  global_error /= double(n_node);
985 
986  //Return the square root of the error
987  return sqrt(global_error);
988 
989 } // end of global_temporal_error_norm
990 
991 
992 //=======start_of_dump_it=================================================
993 /// Dump the solution to disk
994 //========================================================================
995 template<class ELEMENT>
997 {
998 
999  // Write step number
1000  dump_file << Doc_info.number() << " # step number" << std::endl;
1001 
1002  // Write suggested next timestep
1003  dump_file << Next_dt << " # suggested next timestep" << std::endl;
1004 
1005  // Dump the refinement pattern and the generic problem data
1006  Problem::dump(dump_file);
1007 
1008 } // end of dump_it
1009 
1010 //=========start_of_restart===============================================
1011 /// Read solution from disk
1012 //========================================================================
1013 template<class ELEMENT>
1015 {
1016  // Read line up to termination sign
1017  string input_string;
1018  getline(restart_file,input_string,'#');
1019 
1020  // Ignore rest of line
1021  restart_file.ignore(80,'\n');
1022 
1023  // Read in step number
1024  Doc_info.number()=unsigned(atof(input_string.c_str()));
1025 
1026  // Increment number for next solution
1027  Doc_info.number()++;
1028 
1029  // Read line up to termination sign
1030  getline(restart_file,input_string,'#');
1031 
1032  // Ignore rest of line
1033  restart_file.ignore(80,'\n');
1034 
1035  // Read suggested next timestep
1036  Next_dt=double(atof(input_string.c_str()));
1037 
1038  // Refine the mesh and read in the generic problem data
1039  Problem::read(restart_file);
1040 
1041 } // end of restart
1042 
1043 
1044 
1045 /// /////////////////////////////////////////////////////////////////////
1046 /// /////////////////////////////////////////////////////////////////////
1047 /// /////////////////////////////////////////////////////////////////////
1048 
1049 //======start_of_main=====================================================
1050 /// Demonstrate how to solve an unsteady heat problem in deformable domain
1051 /// with mesh adaptation. Command line arguments specify
1052 /// the name of the restart file.
1053 //========================================================================
1054 int main(int argc, char* argv[])
1055 {
1056 
1057  // Store command line arguments
1058  CommandLineArgs::setup(argc,argv);
1059 
1060 
1061  // Specify duration of the simulation
1062  double t_max=0.04; // 2.0;
1063 
1064  // Build problem: Pass pointer to source function and initial timestep
1067 
1068  // Set targets for spatial adaptivity
1069  problem.bulk_mesh_pt()->max_permitted_error()=0.001;
1070  problem.bulk_mesh_pt()->min_permitted_error()=0.0001;
1071 
1072  // First timestep?
1073  bool first=true;
1074 
1075  // Max. number of spatial adaptations per timestep. Allow plenty
1076  // of adaptations at first timestep as the initial conditions
1077  // can be reset "exactly" from without any interpolation error.
1078  unsigned max_adapt=10;
1079 
1080  // Set IC
1081  problem.set_initial_condition();
1082 
1083  // Initial timestep: Use the one used when setting up the initial
1084  // condition or the "suggested next dt" from the restarted run
1085  double dt=problem.next_dt();
1086 
1087  cout << "Doing first timestep with dt: " << dt << std::endl;
1088 
1089  // If restart: The first step isn't really the first step,
1090  // i.e. initial condition should not be re-set when
1091  // adaptive refinement has been performed. Also, limit
1092  // the max. number of refinements per timestep to the
1093  // normal value straightaway.
1094  if (CommandLineArgs::Argc==2)
1095  {
1096  first=false;
1097  max_adapt=1;
1098  }
1099  // If no restart, refine mesh uniformly before we get started
1100  else
1101  {
1102  problem.refine_uniformly();
1103  problem.refine_uniformly();
1104  }
1105 
1106  // Write header for trace file
1107  problem.write_trace_file_header();
1108 
1109 
1110  // Timestepping loop
1111  while (problem.time_pt()->time()<t_max)
1112  {
1113  // Take timestep with temporal and spatial adaptivity
1114  double dt_new=
1115  problem.doubly_adaptive_unsteady_newton_solve(dt,problem.epsilon_t(),
1116  max_adapt,first);
1117  cout << "Suggested new dt: " << dt_new << std::endl;
1118  dt=dt_new;
1119 
1120  // Store for restart
1121  problem.next_dt()=dt_new;
1122 
1123  // Now we've done the first timestep -- don't re-set the IC
1124  // in subsequent steps
1125  first=false;
1126 
1127  // Reduce the number of spatial adaptations to one per
1128  // timestep -- too scared that the interpolation error will
1129  // wipe out any further gains...
1130  max_adapt=1;
1131 
1132  //Output solution
1133  problem.doc_solution();
1134 
1135  }
1136 
1137 
1138 }; // end of main
Oscillating ellipse.
double B_hat
Amplitude of variation in y-half axis.
double A_hat
Amplitude of variation in x-half axis.
void position(const Vector< double > &xi, Vector< double > &r) const
Current position vector to material point at Lagrangian coordinate xi.
double B
y-half axis
void position(const unsigned &t, const Vector< double > &xi, Vector< double > &r) const
Parametrised position on object: r(xi). Evaluated at previous time level. t=0: current time; t>0: pre...
double A
x-half axis
MyEllipse(const double &a, const double &b, const double &a_hat, const double &b_hat, const double &period, Time *time_pt)
Constructor: Pass half axes, amplitudes of their variation, period of oscillation and pointer to time...
double T
Period of oscillation.
Time * Time_pt
Pointer to time object.
virtual ~MyEllipse()
Destructor: Empty.
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of prescribed flux elements.
void dump_it(ofstream &dump_file)
Dump problem data to allow for later restart.
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
double Next_dt
Suggestion for next timestep (stored to allow it to be written to (or read from) restart file)
void set_initial_condition()
Set initial condition (incl previous timesteps) according to specified function.
double Epsilon_t
Target error for adaptive timestepping.
GeomObject * Boundary_pt
Pointer to GeomObject that specifies the domain bondary.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of prescribed flux elements.
RefineableQuarterCircleSectorMesh< ELEMENT > * bulk_mesh_pt()
Pointer to bulk mesh.
void create_flux_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &surface_mesh_pt)
Create UnsteadyHeat flux elements on boundary b of the Mesh pointed to by bulk_mesh_pt and add them t...
double & epsilon_t()
Target error for adaptive timestepping.
Node * Doc_node_pt
Pointer to central node (exists at all refinement levels) for doc.
RefineableUnsteadyHeatProblem(UnsteadyHeatEquations< 2 >::UnsteadyHeatSourceFctPt source_fct_pt)
Constructor: Pass pointer to source function and timestep.
double global_temporal_error_norm()
Global error norm for adaptive time-stepping.
void write_trace_file_header()
Write header for trace file.
~RefineableUnsteadyHeatProblem()
Destructor: Close trace file.
UnsteadyHeatEquations< 2 >::UnsteadyHeatSourceFctPt Source_fct_pt
Pointer to source function.
void actions_after_implicit_timestep()
Update the problem specs after timestep (empty)
void actions_before_newton_solve()
Update the problem specs before solve (empty)
void actions_before_implicit_timestep()
Update the problem specs before next timestep: Set Dirchlet boundary conditions from exact solution.
void delete_flux_elements(Mesh *const &surface_mesh_pt)
Delete UnsteadyHeat flux elements and wipe the surface mesh.
void actions_after_newton_solve()
Update the problem specs after solve (empty)
double & next_dt()
Suggestion for next timestep (stored to allow it to be written to (or read from) restart file)
void restart(ifstream &restart_file)
Read problem data for restart.
RefineableQuarterCircleSectorMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
void get_exact_u(const double &time, const Vector< double > &x, Vector< double > &u)
Exact solution as a Vector.
double Alpha
Parameter for steepness of step.
double Gamma
Parameter for timescale of step translation.
void get_exact_u(const double &time, const Vector< double > &x, double &u)
Exact solution as a scalar.
double Beta
Parameter for amplitude of step translation.
double step_position(const double &time)
Position of step (x-axis intercept)
void get_source(const double &time, const Vector< double > &x, double &source)
Source function to make it an exact solution.
void prescribed_flux_on_fixed_y_boundary(const double &time, const Vector< double > &x, double &flux)
Flux required by the exact solution on a boundary on which y is fixed.
double TanPhi
Parameter for angle of step.
int main(int argc, char *argv[])
///////////////////////////////////////////////////////////////////// ///////////////////////////////...