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-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//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
37using namespace std;
38
39using namespace oomph;
40
41using 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//=========================================================================
49class MyEllipse : public GeomObject
50{
51
52public:
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
96protected:
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*
173MathematicalConstants::Pi*time)))-Y))*(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-
174Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*
175Alpha*TanPhi*TanPhi-2.0*tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
176MathematicalConstants::Pi*time)))-Y))*(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-
177Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*
178Alpha+0.2E1*(1.0-pow(tanh(0.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*
179MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*TanPhi*Beta*(1.0-pow(tanh(
180Gamma*cos(0.2E1*MathematicalConstants::Pi*time)),2.0))*Gamma*sin(0.2E1*
181MathematicalConstants::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*
198MathematicalConstants::Pi*time)))-Y)),2.0))*Alpha*TanPhi*NX+(1.0-pow(tanh(
1990.1E1-Alpha*(TanPhi*(X-Beta*tanh(Gamma*cos(0.2E1*MathematicalConstants::Pi*
200time)))-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//====================================================================
214template<class ELEMENT>
215class RefineableUnsteadyHeatProblem : public Problem
216{
217
218public:
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.
239
240 /// Actions before adapt: Wipe the mesh of prescribed flux elements
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.
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
278private:
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
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//========================================================================
307template<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 snprintf(filename, sizeof(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//========================================================================
475template<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//========================================================================
488template<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//========================================================================
524template<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//========================================================================
540template<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//========================================================================
570template<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//========================================================================
712template<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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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//=======================================================================
852template<class ELEMENT>
854create_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//=======================================================================
885template<class ELEMENT>
887delete_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//========================================================================
908template<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//========================================================================
923template<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//========================================================================
952int 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.
Unsteady heat problem in deformable ellipse domain.
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.
Namespace for exact solution of unsteady heat equation with sharp step.
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.
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[])
Demonstrate how to solve an unsteady heat problem in deformable domain with mesh adaptation....