two_d_unsteady_heat_ALE.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 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
221  RefineableUnsteadyHeatProblem(UnsteadyHeatEquations<2>::
222  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  /// Set initial condition (incl previous timesteps) according
247  /// to specified function. Note that his overloads the virtual
248  /// function in the Problem base class and is therefore executed
249  /// automatically to re-assign the initial conditions during the
250  /// spatially adaptive solution at the first timestep.
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 
278 private:
279 
280  /// Pointer to GeomObject that specifies the domain bondary
281  GeomObject* Boundary_pt;
282 
283  /// Pointer to source function
284  UnsteadyHeatEquations<2>::UnsteadyHeatSourceFctPt Source_fct_pt;
285 
286  /// Pointer to the "bulk" mesh
287  RefineableQuarterCircleSectorMesh<ELEMENT>* Bulk_mesh_pt;
288 
289  /// Pointer to the "surface" mesh
291 
292  /// Pointer to central node (exists at all refinement levels) for doc
293  Node* Doc_node_pt;
294 
295  /// Doc info object
296  DocInfo Doc_info;
297 
298  /// Trace file
299  ofstream Trace_file;
300 
301 }; // end of problem_class
302 
303 //========start_of_constructor============================================
304 /// Constructor for UnsteadyHeat problem on deformable ellipse domain.
305 /// Pass pointer to source function.
306 //========================================================================
307 template<class ELEMENT>
309  UnsteadyHeatEquations<2>::UnsteadyHeatSourceFctPt source_fct_pt) :
310  Source_fct_pt(source_fct_pt)
311 {
312 
313 
314  // Setup labels for output
315  //------------------------
316 
317  // Output directory
318  Doc_info.set_directory("RESLT");
319 
320  // Output number
321  Doc_info.number()=0;
322 
323  // Open trace file
324  char filename[100];
325  sprintf(filename,"%s/trace.dat",Doc_info.directory().c_str());
326  Trace_file.open(filename);
327 
328  Trace_file << "VARIABLES=\"time t\",\"u<SUB>FE</SUB>\",\"u<SUB>exact</SUB>\","
329  << "\"A\","
330  << "\"X<SUB>step</SUB>\","
331  << "\"N<SUB>element</SUB>\","
332  << "\"N<SUB>refined</SUB>\","
333  << "\"N<SUB>unrefined</SUB>\","
334  << "\"norm of error\","
335  << "\"norm of solution\""
336  << std::endl;
337 
338 
339  // Setup parameters for tanh solution
340  // ----------------------------------
341 
342  // Steepness of step
344 
345  // Orientation of step
347 
348  // Amplitude for movement of step
350 
351  // Parameter for time-dependence of step movement
353 
354 
355 
356  //Allocate the timestepper -- This constructs the time object as well
357  add_time_stepper_pt(new BDF<2>());
358 
359 
360  // Setup mesh
361  //-----------
362 
363  // Build geometric object that forms the curvilinear domain boundary:
364  // an oscillating ellipse
365 
366  // Half axes
367  double a=1.0;
368  double b=1.0;
369 
370  // Variations of half axes
371  double a_hat= 0.1;
372  double b_hat=-0.1;
373 
374  // Period of the oscillation
375  double period=1.0;
376 
377  // Create GeomObject
378  Boundary_pt=new MyEllipse(a,b,a_hat,b_hat,period,Problem::time_pt());
379 
380  // Start and end coordinates of curvilinear domain boundary on ellipse
381  double xi_lo=0.0;
382  double xi_hi=MathematicalConstants::Pi/2.0;
383 
384  // Now create the bulk mesh. Separating line between the two
385  // elements next to the curvilinear boundary is located half-way
386  // along the boundary.
387  double fract_mid=0.5;
388  Bulk_mesh_pt = new RefineableQuarterCircleSectorMesh<ELEMENT>(
389  Boundary_pt,xi_lo,fract_mid,xi_hi,time_stepper_pt());
390 
391  // Create the surface mesh as an empty mesh
392  Surface_mesh_pt=new Mesh;
393 
394  // Create prescribed-flux elements from all elements that are
395  // adjacent to boundary 0 (the horizontal lower boundary), and add them
396  // to the (so far empty) surface mesh.
398 
399  // Add the two sub meshes to the problem
400  add_sub_mesh(Bulk_mesh_pt);
401  add_sub_mesh(Surface_mesh_pt);
402 
403  // Combine all submeshes into a single global Mesh
404  build_global_mesh();
405 
406  // Set error estimator for bulk mesh
407  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
408  Bulk_mesh_pt->spatial_error_estimator_pt()=error_estimator_pt;
409 
410  // Set the boundary conditions for this problem: All nodes are
411  // free by default -- just pin the ones that have Dirichlet conditions
412  // here.
413  unsigned n_bound = Bulk_mesh_pt->nboundary();
414  for(unsigned b=0;b<n_bound;b++)
415  {
416  // Leave nodes on boundary 0 free -- this is where we apply the flux
417  // boundary condition
418  if (b!=0)
419  {
420  unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
421  for (unsigned n=0;n<n_node;n++)
422  {
423  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
424  }
425  }
426  }
427 
428  // Extract pointer to the central node (this exists at all refinement levels)
429  // for doc of solution
430  FiniteElement* el0_pt=Bulk_mesh_pt->finite_element_pt(0);
431  unsigned nnod=el0_pt->nnode();
432  Doc_node_pt=el0_pt->node_pt(nnod-1);
433 
434 
435  // Complete the build of all elements so they are fully functional
436  //----------------------------------------------------------------
437 
438  // Find number of elements in mesh
439  unsigned n_element = Bulk_mesh_pt->nelement();
440 
441  // Loop over the elements to set up element-specific
442  // things that cannot be handled by constructor
443  for(unsigned i=0;i<n_element;i++)
444  {
445  // Upcast from FiniteElement to the present element
446  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(i));
447 
448  //Set the source function pointer
449  el_pt->source_fct_pt() = Source_fct_pt;
450  }
451 
452  // Loop over the flux elements to pass pointer to prescribed flux function
453  n_element=Surface_mesh_pt->nelement();
454  for(unsigned e=0;e<n_element;e++)
455  {
456  // Upcast from GeneralisedElement to UnsteadyHeat flux element
457  UnsteadyHeatFluxElement<ELEMENT> *el_pt =
458  dynamic_cast<UnsteadyHeatFluxElement<ELEMENT>*>(
459  Surface_mesh_pt->element_pt(e));
460 
461  // Set the pointer to the prescribed flux function
462  el_pt->flux_fct_pt() =
464  }
465 
466  // Do equation numbering
467  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
468 
469 } // end of constructor
470 
471 
472 //======start_of_destructor===============================================
473 /// Destructor: Close trace file
474 //========================================================================
475 template<class ELEMENT>
477 {
478  // Close trace file
479  Trace_file.close();
480 
481 } // end of destructor
482 
483 
484 //=========start of actions_before_implicit_timestep===============================
485 /// Actions before timestep: Update the domain shape, then set the
486 /// boundary conditions for the current time.
487 //========================================================================
488 template<class ELEMENT>
490 {
491  // Update the domain shape
492  Bulk_mesh_pt->node_update();
493 
494  // Get current time
495  double time=time_pt()->time();
496 
497  //Loop over all boundaries
498  unsigned num_bound = Bulk_mesh_pt->nboundary();
499  for(unsigned b=0;b<num_bound;b++)
500  {
501  // Exclude flux boundary
502  if (b!=0)
503  {
504  // Loop over the nodes on boundary
505  unsigned num_nod=Bulk_mesh_pt->nboundary_node(b);
506  for (unsigned j=0;j<num_nod;j++)
507  {
508  Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(b,j);
509  double u;
510  Vector<double> x(2);
511  x[0]=nod_pt->x(0);
512  x[1]=nod_pt->x(1);
514  nod_pt->set_value(0,u);
515  }
516  }
517  }
518 } // end of actions_before_implicit_timestep
519 
520 
521 //=========start_of_actions_before_adapt==================================
522 /// Actions before adapt: Wipe the mesh of prescribed flux elements
523 //========================================================================
524 template<class ELEMENT>
526 {
527 
528  // Kill the flux elements and wipe surface mesh
529  delete_flux_elements(Surface_mesh_pt);
530 
531  // Rebuild the global mesh.
532  rebuild_global_mesh();
533 
534 } // end of actions_before_adapt
535 
536 
537 //==========start_of_actions_after_adapt==================================
538 /// Actions after adapt: Rebuild the mesh of prescribed flux elements
539 //========================================================================
540 template<class ELEMENT>
542 {
543  // Create prescribed-flux elements from all elements that are
544  // adjacent to boundary 0 and add them to surface mesh
545  create_flux_elements(0,Bulk_mesh_pt,Surface_mesh_pt);
546 
547  // Rebuild the global mesh
548  rebuild_global_mesh();
549 
550  // Loop over the flux elements to pass pointer to prescribed flux function
551  unsigned n_element=Surface_mesh_pt->nelement();
552  for(unsigned e=0;e<n_element;e++)
553  {
554  // Upcast from GeneralisedElement to UnsteadyHeat flux element
555  UnsteadyHeatFluxElement<ELEMENT> *el_pt =
556  dynamic_cast<UnsteadyHeatFluxElement<ELEMENT>*>(
557  Surface_mesh_pt->element_pt(e));
558 
559  // Set the pointer to the prescribed flux function
560  el_pt->flux_fct_pt() =
562  }
563 } // end of actions_after_adapt
564 
565 
566 //======================start_of_set_initial_condition====================
567 /// Set initial condition: Assign previous and current values
568 /// from exact solution.
569 //========================================================================
570 template<class ELEMENT>
572 {
573 
574  // Pointer to restart file
575  ifstream* restart_file_pt=0;
576 
577  // Restart?
578  //---------
579  // Restart file specified via command line [all programs have at least
580  // a single command line argument: their name. Ignore this here.]
581  if (CommandLineArgs::Argc==1)
582  {
583  cout << "No restart -- setting IC from exact solution" << std::endl;
584  }
585  else if (CommandLineArgs::Argc==2)
586  {
587  // Open restart file
588  restart_file_pt= new ifstream(CommandLineArgs::Argv[1],ios_base::in);
589  if (restart_file_pt!=0)
590  {
591  cout << "Have opened " << CommandLineArgs::Argv[1] <<
592  " for restart. " << std::endl;
593  }
594  else
595  {
596  std::ostringstream error_stream;
597  error_stream
598  << "ERROR while trying to open " << CommandLineArgs::Argv[1] <<
599  " for restart." << std::endl;
600 
601  throw OomphLibError(
602  error_stream.str(),
603  OOMPH_CURRENT_FUNCTION,
604  OOMPH_EXCEPTION_LOCATION);
605  }
606  }
607  // More than one command line argument?
608  else
609  {
610  std::ostringstream error_stream;
611  error_stream << "Can only specify one input file\n"
612  << "You specified the following command line arguments:\n";
613  //Fix this
614  CommandLineArgs::output();
615 
616  throw OomphLibError(
617  error_stream.str(),
618  OOMPH_CURRENT_FUNCTION,
619  OOMPH_EXCEPTION_LOCATION);
620  }
621 
622 
623  // Read restart data:
624  //-------------------
625  if (restart_file_pt!=0)
626  {
627  // Read the data from restart file and find out if the restart file
628  // was from an unsteady run
629  restart(*restart_file_pt);
630  }
631  // Assign initial condition from exact solution
632  //---------------------------------------------
633  else
634  {
635  // Choose initial timestep
636  double dt0=0.01;
637 
638  // Initialise timestep -- also sets the weights for all timesteppers
639  // in the problem.
640  initialise_dt(dt0);
641 
642  // Backup time in global timestepper
643  double backed_up_time=time_pt()->time();
644 
645  // Past history for velocities must be established for t=time0-deltat, ...
646  // Then provide current values (at t=time0) which will also form
647  // the initial guess for first solve at t=time0+deltat
648 
649  // Vector of exact solution value
650  Vector<double> soln(1);
651  Vector<double> x(2);
652 
653  //Find number of nodes in mesh
654  unsigned num_nod = Bulk_mesh_pt->nnode();
655 
656  // Get continuous times at previous timesteps
657  int nprev_steps=time_stepper_pt()->nprev_values();
658  Vector<double> prev_time(nprev_steps+1);
659  for (int itime=nprev_steps;itime>=0;itime--)
660  {
661  prev_time[itime]=time_pt()->time(unsigned(itime));
662  }
663 
664  // Loop over current & previous timesteps (in outer loop because
665  // the mesh also moves!)
666  for (int itime=nprev_steps;itime>=0;itime--)
667  {
668  double time=prev_time[itime];
669 
670  // Set global time (because this is how the geometric object refers
671  // to continous time
672  time_pt()->time()=time;
673 
674  cout << "setting IC at time =" << time << std::endl;
675 
676  // Update the mesh for this value of the continuous time
677  // (The wall object reads the continous time from the same
678  // global time object)
679  Bulk_mesh_pt->node_update();
680 
681  // Loop over the nodes to set initial guess everywhere
682  for (unsigned jnod=0;jnod<num_nod;jnod++)
683  {
684  // Get nodal coordinates
685  x[0]=Bulk_mesh_pt->node_pt(jnod)->x(0);
686  x[1]=Bulk_mesh_pt->node_pt(jnod)->x(1);
687 
688  // Get intial solution
690 
691  // Assign solution
692  Bulk_mesh_pt->node_pt(jnod)->set_value(itime,0,soln[0]);
693 
694  // Loop over coordinate directions
695  for (unsigned i=0;i<2;i++)
696  {
697  Bulk_mesh_pt->node_pt(jnod)->x(itime,i)=x[i];
698  }
699  }
700  } // end of loop over previous timesteps
701 
702  // Reset backed up time for global timestepper
703  time_pt()->time()=backed_up_time;
704  }
705 
706 } // end of set_initial_condition
707 
708 
709 //=======start_of_doc_solution============================================
710 /// Doc the solution
711 //========================================================================
712 template<class ELEMENT>
714 {
715  ofstream some_file;
716  char filename[100];
717 
718  // Number of plot points
719  unsigned npts;
720  npts=5;
721 
722  cout << std::endl;
723  cout << "=================================================" << std::endl;
724  cout << "Docing solution for t=" << time_pt()->time() << std::endl;
725  cout << "=================================================" << std::endl;
726 
727  // Output solution
728  //-----------------
729  sprintf(filename,"%s/soln%i.dat",Doc_info.directory().c_str(),
730  Doc_info.number());
731  some_file.open(filename);
732  Bulk_mesh_pt->output(some_file,npts);
733  some_file << "TEXT X=2.5,Y=93.6,F=HELV,HU=POINT,C=BLUE,H=26,T=\"time = "
734  << time_pt()->time() << "\"";
735  some_file << "GEOMETRY X=2.5,Y=98,T=LINE,C=BLUE,LT=0.4" << std::endl;
736  some_file << "1" << std::endl;
737  some_file << "2" << std::endl;
738  some_file << " 0 0" << std::endl;
739  some_file << time_pt()->time()*20.0 << " 0" << std::endl;
740 
741  // Write dummy zones
742  some_file << "ZONE I=2,J=2" << std::endl;
743  some_file << "0.0 0.0 -1.2" << std::endl;
744  some_file << "1.3 0.0 -1.2" << std::endl;
745  some_file << "0.0 1.3 -1.2" << std::endl;
746  some_file << "1.3 1.3 -1.2" << std::endl;
747  some_file << "ZONE I=2,J=2" << std::endl;
748  some_file << "0.0 0.0 1.2" << std::endl;
749  some_file << "1.3 0.0 1.2" << std::endl;
750  some_file << "0.0 1.3 1.2" << std::endl;
751  some_file << "1.3 1.3 1.2" << std::endl;
752 
753  some_file.close();
754 
755 
756  // Output exact solution
757  //----------------------
758  sprintf(filename,"%s/exact_soln%i.dat",Doc_info.directory().c_str(),
759  Doc_info.number());
760  some_file.open(filename);
761  Bulk_mesh_pt->output_fct(some_file,npts,time_pt()->time(),
763 
764  // Write dummy zones
765  some_file << "ZONE I=2,J=2" << std::endl;
766  some_file << "0.0 0.0 -1.2" << std::endl;
767  some_file << "1.3 0.0 -1.2" << std::endl;
768  some_file << "0.0 1.3 -1.2" << std::endl;
769  some_file << "1.3 1.3 -1.2" << std::endl;
770  some_file << "ZONE I=2,J=2" << std::endl;
771  some_file << "0.0 0.0 1.2" << std::endl;
772  some_file << "1.3 0.0 1.2" << std::endl;
773  some_file << "0.0 1.3 1.2" << std::endl;
774  some_file << "1.3 1.3 1.2" << std::endl;
775 
776  some_file.close();
777 
778 
779  // Doc error
780  //----------
781  double error,norm;
782  sprintf(filename,"%s/error%i.dat",Doc_info.directory().c_str(),
783  Doc_info.number());
784  some_file.open(filename);
785  Bulk_mesh_pt->compute_error(some_file,
787  time_pt()->time(),
788  error,norm);
789  some_file.close();
790 
791 
792 
793  // Doc error and write trace file
794  //--------------------------------
795  cout << "error: " << error << std::endl;
796  cout << "norm : " << norm << std::endl << std::endl;
797 
798  Vector<double> x(2);
799  x[0]=Doc_node_pt->x(0);
800  x[1]=Doc_node_pt->x(1);
801  double u_exact;
802  TanhSolnForUnsteadyHeat::get_exact_u(time_pt()->time(),x,u_exact);
803  Vector<double > xi_wall(1);
804  Vector<double > r_wall(2);
805  xi_wall[0]=0.0;
806  Boundary_pt->position(xi_wall,r_wall);
807  Trace_file << time_pt()->time()
808  << " " << Doc_node_pt->value(0)
809  << " " << u_exact
810  << " " << r_wall[0]
811  << " " << TanhSolnForUnsteadyHeat::step_position(time_pt()->time())
812  << " " << Bulk_mesh_pt->nelement()
813  << " " << Bulk_mesh_pt->nrefined()
814  << " " << Bulk_mesh_pt->nunrefined()
815  << " " << error
816  << " " << norm << std::endl;
817 
818  // Plot wall posn
819  //---------------
820  sprintf(filename,"%s/Wall%i.dat",Doc_info.directory().c_str(),
821  Doc_info.number());
822  some_file.open(filename);
823 
824  unsigned nplot=100;
825  for (unsigned iplot=0;iplot<nplot;iplot++)
826  {
827  xi_wall[0]=0.5*Pi*double(iplot)/double(nplot-1);
828  Boundary_pt->position(xi_wall,r_wall);
829  some_file << r_wall[0] << " " << r_wall[1] << std::endl;
830  }
831  some_file.close();
832 
833  // Write restart file
834  sprintf(filename,"%s/restart%i.dat",Doc_info.directory().c_str(),
835  Doc_info.number());
836  some_file.open(filename);
837  dump_it(some_file);
838  some_file.close();
839 
840  // Increment number of doc
841  Doc_info.number()++;
842 
843 
844 } // end of doc_solution
845 
846 
847 //============start_of_create_flux_elements==============================
848 /// Create UnsteadyHeat Flux Elements on the b-th boundary of the Mesh object
849 /// pointed to by bulk_mesh_pt and add the elements to the Mesh object
850 /// pointed to by surface_mesh_pt.
851 //=======================================================================
852 template<class ELEMENT>
854 create_flux_elements(const unsigned& b, Mesh* const &bulk_mesh_pt,
855  Mesh* const &surface_mesh_pt)
856 {
857  // How many bulk elements are adjacent to boundary b?
858  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
859 
860  // Loop over the bulk elements adjacent to boundary b?
861  for(unsigned e=0;e<n_element;e++)
862  {
863  // Get pointer to the bulk element that is adjacent to boundary b
864  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
865  bulk_mesh_pt->boundary_element_pt(b,e));
866 
867  //What is the face index of element e along boundary b
868  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
869 
870  // Build the corresponding prescribed-flux element
871  UnsteadyHeatFluxElement<ELEMENT>* flux_element_pt = new
872  UnsteadyHeatFluxElement<ELEMENT>(bulk_elem_pt,face_index);
873 
874  //Add the prescribed-flux element to the surface mesh
875  surface_mesh_pt->add_element_pt(flux_element_pt);
876 
877  } //end of loop over bulk elements adjacent to boundary b
878 
879 } // end of create_flux_elements
880 
881 
882 //============start_of_delete_flux_elements==============================
883 /// Delete UnsteadyHeat Flux Elements and wipe the surface mesh
884 //=======================================================================
885 template<class ELEMENT>
887 delete_flux_elements(Mesh* const &surface_mesh_pt)
888 {
889  // How many surface elements are in the surface mesh
890  unsigned n_element = surface_mesh_pt->nelement();
891 
892  // Loop over the surface elements
893  for(unsigned e=0;e<n_element;e++)
894  {
895  // Kill surface element
896  delete surface_mesh_pt->element_pt(e);
897  }
898 
899  // Wipe the mesh
900  surface_mesh_pt->flush_element_and_node_storage();
901 
902 } // end of delete_flux_elements
903 
904 
905 //=======start_of_dump_it=================================================
906 /// Dump the solution to disk
907 //========================================================================
908 template<class ELEMENT>
910 {
911 
912  // Write step number
913  dump_file << Doc_info.number() << " # step number" << std::endl;
914 
915  // Dump the refinement pattern and the generic problem data
916  Problem::dump(dump_file);
917 
918 } // end of dump_it
919 
920 //=========start_of_restart===============================================
921 /// Read solution from disk
922 //========================================================================
923 template<class ELEMENT>
925 {
926  // Read line up to termination sign
927  string input_string;
928  getline(restart_file,input_string,'#');
929 
930  // Ignore rest of line
931  restart_file.ignore(80,'\n');
932 
933  // Read in step number
934  Doc_info.number()=unsigned(atof(input_string.c_str()));
935 
936  // Refine the mesh and read in the generic problem data
937  Problem::read(restart_file);
938 
939 } // end of restart
940 
941 
942 
943 /// /////////////////////////////////////////////////////////////////////
944 /// /////////////////////////////////////////////////////////////////////
945 /// /////////////////////////////////////////////////////////////////////
946 
947 //======start_of_main=====================================================
948 /// Demonstrate how to solve an unsteady heat problem in deformable domain
949 /// with mesh adaptation. Command line arguments specify
950 /// the name of the restart file.
951 //========================================================================
952 int main(int argc, char* argv[])
953 {
954 
955  // Store command line arguments
956  CommandLineArgs::setup(argc,argv);
957 
958  // Build problem
961 
962  // Specify duration of the simulation
963 // double t_max=3.0;
964 
965  // Set targets for spatial adaptivity
966  problem.bulk_mesh_pt()->max_permitted_error()=0.001;
967  problem.bulk_mesh_pt()->min_permitted_error()=0.0001;
968 
969  // First timestep?
970  bool first=true;
971 
972  // Max. number of spatial adaptations per timestep. Allow plenty
973  // of adaptations at first timestep as the initial conditions
974  // can be reset "exactly" from without any interpolation error.
975  unsigned max_adapt=10;
976 
977  // Set IC
978  problem.set_initial_condition();
979 
980  // Initial timestep: Use the one used when setting up the initial
981  // condition
982  double dt=problem.time_pt()->dt();
983 
984  // If restart: The first step isn't really the first step,
985  // i.e. initial condition should not be re-set when
986  // adaptive refinement has been performed. Also, limit
987  // the max. number of refinements per timestep to the
988  // normal value straightaway.
989  if (CommandLineArgs::Argc==2)
990  {
991  first=false;
992  max_adapt=1;
993  }
994  // If no restart, refine mesh uniformly before we get started
995  else
996  {
997  problem.refine_uniformly();
998  problem.refine_uniformly();
999  }
1000 
1001  //Output solution
1002  problem.doc_solution();
1003 
1004  // find number of steps
1005  unsigned nstep = 6; //unsigned(t_max/dt);
1006 
1007  // Timestepping loop
1008  for (unsigned istep=0;istep<nstep;istep++)
1009  {
1010  // Take timestep
1011  problem.unsteady_newton_solve(dt,max_adapt,first);
1012 
1013  // Now we've done the first timestep -- don't re-set the IC
1014  // in subsequent steps
1015  first=false;
1016 
1017  // Reduce the number of spatial adaptations to one per
1018  // timestep
1019  max_adapt=1;
1020 
1021  //Output solution
1022  problem.doc_solution();
1023 
1024  }
1025 
1026 
1027 }; // 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.
void set_initial_condition()
Set initial condition (incl previous timesteps) according to specified function. Note that his overlo...
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...
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.
~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)
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[])
///////////////////////////////////////////////////////////////////// ///////////////////////////////...