278 * <a name=
"Includefiles"></a>
279 * <h3>Include files</h3>
283 * All the include files have already been discussed in previous tutorials.
286 * #include <deal.II/dofs/dof_handler.h>
287 * #include <deal.II/dofs/dof_renumbering.h>
288 * #include <deal.II/grid/grid_generator.h>
289 * #include <deal.II/grid/tria_accessor.h>
290 * #include <deal.II/grid/tria_iterator.h>
291 * #include <deal.II/dofs/dof_accessor.h>
292 * #include <deal.II/fe/fe_q.h>
293 * #include <deal.II/dofs/dof_tools.h>
294 * #include <deal.II/fe/fe_values.h>
295 * #include <deal.II/base/quadrature_lib.h>
296 * #include <deal.II/base/function.h>
297 * #include <deal.II/numerics/vector_tools.h>
298 * #include <deal.II/numerics/matrix_tools.h>
299 * #include <deal.II/lac/vector.h>
300 * #include <deal.II/lac/full_matrix.h>
301 * #include <deal.II/lac/dynamic_sparsity_pattern.h>
303 * #include <deal.II/grid/grid_in.h>
304 * #include <deal.II/grid/grid_tools.h>
305 * #include <deal.II/lac/trilinos_vector.h>
306 * #include <deal.II/lac/trilinos_sparse_matrix.h>
307 * #include <deal.II/lac/trilinos_solver.h>
308 * #include <deal.II/lac/trilinos_precondition.h>
310 * #include <deal.II/lac/sparsity_tools.h>
311 * #include <deal.II/lac/generic_linear_algebra.h>
313 * #include <deal.II/base/conditional_ostream.h>
314 * #include <deal.II/base/utilities.h>
315 * #include <deal.II/base/index_set.h>
316 * #include <deal.II/distributed/
tria.h>
318 * #include <deal.II/numerics/data_out.h>
320 * #include <iostream>
323 * #include <deal.II/base/logstream.h>
324 * #include <deal.II/lac/affine_constraints.h>
325 * #include <deal.II/base/timer.h>
332 * #include <deal.II/numerics/error_estimator.h>
333 * #include <deal.II/distributed/grid_refinement.h>
334 * #include <deal.II/distributed/solution_transfer.h>
338 * remember to use the
namespace dealii before
339 * defining a
class that is inheritaged from
Function<dim>
346 * In
general, it is more clear to separate boundary and
initial condictions,
347 * as well as the right hand side function from a file holding all the things.
348 * To
do so, in
this work, the globalPara.h file defines physical constants,
349 * laser parameters, and heat characteristics of materials involved. Boundary
350 * and
initial conditions are defined in boundaryInit.h. The rightHandSide.h
351 * defines the heat source, which in
this work is a moving Gaussian beam.
357 * #ifndef GLOBAL_PARA
358 * #define GLOBAL_PARA
359 * #include
"./globalPara.h"
360 * #include
"./boundaryInit.h"
361 * #include
"./rightHandSide.h"
366 * Now the main
class is defined as following
379 *
void setup_system();
381 *
void assemble_system_matrix_init (
double time_step);
382 *
void dynamic_assemble_rhs_T (
double time,
double time_step);
386 *
void refine_mesh();
387 *
void output_results (
int output_num)
const;
414 *
for storing right
matrix
421 * System_rhs, only locally owned cells
429 * Old Solutions with ghost cells,
for output
436 * Old Solutions only with locally owned cells
443 * New Solutions only with locally owned cells
450 * Dynamic assembling of the righthandside terms
474 * LaserHeating<dim>::LaserHeating ()
476 * mpi_communicator (MPI_COMM_WORLD),
491 * LaserHeating<dim>::~LaserHeating ()
493 * dof_handler.clear();
499 * <a name=
"LaserHeatingmake_grid"></a>
500 * <h4>LaserHeating::make_grid</h4>
501 * make grid by importing msh file, and rescale
505 *
void LaserHeating<dim>::make_grid ()
511 * std::ifstream input_file (
"geometry.msh");
512 * grid_in.read_msh (input_file);
515 * pcout <<
" Number of active cells: "
518 * <<
" Total number of cells: "
526 * <a name=
"LaserHeatingsetup_system"></a>
527 * <h4>LaserHeating::setup_system</h4>
532 *
void LaserHeating<dim>::setup_system ()
537 * dof_handler.distribute_dofs (fe);
539 * pcout <<
" Number of degrees of freedom: "
540 * << dof_handler.n_dofs()
543 * locally_owned_dofs = dof_handler.locally_owned_dofs();
548 * we want to output solution, so here should have ghost cells
551 * old_solution_T.reinit (locally_owned_dofs,locally_relevant_dofs,mpi_communicator);
555 * locally owned cells
558 * old_solution_T_cal.reinit (locally_owned_dofs,mpi_communicator);
559 * new_solution_T.reinit (locally_owned_dofs,mpi_communicator);
560 * dynamic_rhs_T.reinit (locally_owned_dofs,mpi_communicator);
561 * system_rhs_T.reinit (locally_owned_dofs,mpi_communicator);
563 * constraints_T.clear();
564 * constraints_T.reinit (locally_relevant_dofs);
566 * constraints_T.close();
573 * locally_owned_dofs,
575 * locally_relevant_dofs);
577 * left_system_matrix_T.reinit (locally_owned_dofs,locally_owned_dofs,dsp_T,mpi_communicator);
578 * right_system_matrix_T.reinit (locally_owned_dofs,locally_owned_dofs,dsp_T,mpi_communicator);
579 * system_matrix_T.reinit (locally_owned_dofs,locally_owned_dofs,dsp_T,mpi_communicator);
587 * <a name=
"LaserHeatingassemble_system_matrix"></a>
588 * <h4>LaserHeating::assemble_system_matrix</h4>
595 *
void LaserHeating<dim>::assemble_system_matrix_init (
double time_step)
603 *
const InitialValues<dim> initial_value_func_T;
606 *
const RhoC<dim> rho_C_fun_T;
607 *
const K_T<dim> k_fun_T;
614 *
const unsigned int dofs_per_cell = fe.dofs_per_cell;
615 *
const unsigned int n_q_points = quadrature_formula.size();
625 * std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
627 * system_matrix_T = 0;
628 * left_system_matrix_T = 0;
629 * right_system_matrix_T = 0;
633 *
for (
const auto &cell : dof_handler.active_cell_iterators())
634 * if(cell->is_locally_owned())
637 * fe_values.
reinit (cell);
638 * local_init_matrix = 0;
640 * local_rho_c_T_matrix = 0;
641 * local_k_T_matrix = 0;
643 * local_init_T_rhs = 0;
645 *
for (
unsigned int q=0; q<n_q_points; ++q)
646 *
for (
unsigned int i=0; i<dofs_per_cell; ++i)
648 *
const Tensor<1,dim> div_phi_i_u = fe_values.shape_grad (i,q);
649 *
const double phi_i_u = fe_values.shape_value (i,q);
651 *
for (
unsigned int j=0; j<dofs_per_cell; ++j)
654 *
const Tensor<1,dim> div_phi_j_u = fe_values.shape_grad(j,q);
655 *
const double phi_j_u = fe_values.shape_value (j,q);
657 * local_init_matrix(i,j) += (phi_i_u *
659 * fe_values.JxW (q));
661 * local_rho_c_T_matrix(i,j) += (rho_C_fun_T.value(fe_values.quadrature_point(q)) *
666 * time_step * (theta) *
667 * (k_fun_T.value(fe_values.quadrature_point(q)) *
670 * fe_values.JxW (q));
672 * local_k_T_matrix(i,j) += (rho_C_fun_T.value(fe_values.quadrature_point(q)) *
677 * time_step * (1.0-theta) *
678 * (k_fun_T.value(fe_values.quadrature_point(q)) *
681 * fe_values.JxW (q));
685 * local_init_T_rhs(i) += (phi_i_u *
686 * initial_value_func_T.value (fe_values.quadrature_point (q)) *
687 * fe_values.JxW (q));
691 * cell->get_dof_indices (local_dof_indices);
698 * constraints_T.distribute_local_to_global(local_init_matrix,
707 * store M + dt*theta*A as the left_system_matrix
713 * constraints_T.distribute_local_to_global(local_rho_c_T_matrix,
715 * left_system_matrix_T);
719 * store M - dt*(1-theta)*A as the right_system_matrix
722 * constraints_T.distribute_local_to_global(local_k_T_matrix,
724 * right_system_matrix_T);
740 * <a name=
"LaserHeatingdynamic_assemble_rhs_T"></a>
741 * <h4>LaserHeating::dynamic_assemble_rhs_T</h4>
742 * The right hand side is assembled each time during running, which is necessary as
743 * the laser source is moving. To separate the heat source and the right hand
744 * side assembling, the right hand side function is defined as RightHandside<dim>.
748 *
void LaserHeating<dim>::dynamic_assemble_rhs_T (
double time,
double time_step)
755 * RightHandside<dim> rhs_func_T_1;
756 * rhs_func_T_1.set_time(time);
758 * RightHandside<dim> rhs_func_T_2;
759 * rhs_func_T_2.set_time(time-time_step);
766 *
const unsigned int dofs_per_cell = fe.dofs_per_cell;
767 *
const unsigned int n_q_points = quadrature_formula.size();
771 * std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
773 * std::vector<double> Rnp_cal_assemble (n_q_points);
776 * dynamic_rhs_T = 0 ;
779 * cell = dof_handler.begin_active(),
780 * endc = dof_handler.end();
782 *
for (; cell!=endc; ++cell)
783 *
if(cell->is_locally_owned())
785 * fe_values.reinit (cell);
786 * local_rhs_vector_T = 0;
788 *
for (
unsigned int q=0; q<n_q_points; ++q)
789 *
for (
unsigned int i=0; i<dofs_per_cell; ++i)
791 *
const double phi_i_u = fe_values.shape_value (i,q);
794 * local_rhs_vector_T(i) += time_step * theta *
796 * rhs_func_T_1.value_v2 (fe_values.quadrature_point (q)) *
799 * time_step * (1.0 - theta) *
801 * rhs_func_T_2.value_v2 (fe_values.quadrature_point (q)) *
802 * fe_values.JxW (q));
805 * cell->get_dof_indices (local_dof_indices);
808 * constraints_T.distribute_local_to_global(local_rhs_vector_T,
823 * <a name=
"LaserHeatingsolve"></a>
824 * <h4>LaserHeating::solve</h4>
825 * Solving the equation is direct. Recall that we have defined several matrices and vectors,
826 * to avoid ambiguous, here, we only use system_matrix_T as the system
matrix, system_rhs_T
827 * as the system right hand side. The vector completely_distributed_solution is used to store
828 * the obtained solution.
832 *
void LaserHeating<dim>::solve_T ()
837 *
SolverControl solver_control (1*system_rhs_T.size(),1e-12*system_rhs_T.l2_norm(),
true);
844 * preconditioner.initialize(system_matrix_T,data);
846 * solver.solve (system_matrix_T,completely_distributed_solution,system_rhs_T,preconditioner);
851 * Print the number of iterations by hand.
857 * pcout <<
" " << solver_control.last_step()
858 * <<
" CG iterations needed to obtain convergence." << std::endl
859 * <<
"\t initial convergence value = " << solver_control.initial_value() << std::endl
860 * <<
"\t final convergence value = " << solver_control.last_value() << std::endl
863 * constraints_T.distribute (completely_distributed_solution);
864 * new_solution_T = completely_distributed_solution;
872 * <a name=
"LaserHeatingrefine_mesh"></a>
873 * <h4>LaserHeating::refine_mesh</h4>
880 *
void LaserHeating<dim>::refine_mesh()
893 * only
refine mesh 5um above the TiO2 and glass
interface
902 *
if(cell->is_locally_owned())
904 * fe_values.reinit(cell);
905 *
if(
std::abs(fe_values.quadrature_point(0)[1]) <= global_film_thickness+5
e-6)
907 * cell->set_refine_flag();
911 * cell->clear_refine_flag();
922 * <a name=
"LaserHeatinghoutput_results"></a>
923 * <h4>LaserHeatingh::output_results</h4>
930 *
void LaserHeating<dim>::output_results (
int output_num)
const
936 * data_out.add_data_vector (old_solution_T,
"T");
940 * the length of output numbering
948 * data_out.build_patches ();
950 *
const std::string filename = (
"solution-" +
955 * std::ofstream output (filename.c_str());
956 * data_out.write_vtu (output);
961 * output the overall solution
969 * std::vector<std::string> filenames;
971 * filenames.push_back (
"solution-" +
976 * std::ofstream master_output ((
"solution-" +
979 * data_out.write_pvtu_record (master_output,filenames);
991 * <a name=
"LaserHeatingrun"></a>
992 * <h4>LaserHeating::run</h4>
996 * This is the function which has the top-
level control over everything. Apart
997 * from one line of additional output, it is the same as
for the previous
1001 *
template <
int dim>
1002 *
void LaserHeating<dim>::run ()
1004 * pcout <<
"Solving problem in " << dim <<
" space dimensions." << std::endl;
1010 * assemble_system_matrix_init (global_simulation_time_step);
1014 * projection of
initial conditions by solving.
1015 * solution stored in new_solution_T;
1023 * old_solution_T = new_solution_T;
1024 * old_solution_T_cal = new_solution_T;
1034 * system_matrix_T = 0;
1038 *
double time_step = global_simulation_time_step;
1040 *
int timestep_number = 0;
1047 * output_results (0);
1050 *
while(time < global_simulation_end_time)
1053 * time += time_step;
1054 * timestep_number ++;
1056 * pcout <<
"Time step " << timestep_number
1057 * <<
" at t=" << time
1058 * <<
" time_step = " << time_step
1068 * right_system_matrix_T.vmult(system_rhs_T,old_solution_T_cal);
1070 * dynamic_assemble_rhs_T (time,time_step);
1071 * system_rhs_T.add(1,dynamic_rhs_T);
1073 * system_matrix_T.copy_from (left_system_matrix_T);
1076 * BoundaryValues<dim> boundary_values_function;
1077 * std::map<types::global_dof_index,double> boundary_values;
1081 * boundary_values_function,
1096 * old_solution_T is used
for output, holding ghost cells
1097 * old_solution_T_cal is used
for calculation, holding only
1098 * locally owned cells.
1101 * old_solution_T = new_solution_T;
1102 * old_solution_T_cal = new_solution_T;
1107 * output_results (timestep_number);
1110 * computing_timer.print_summary ();
1111 * computing_timer.reset();
1113 * pcout << std::endl;
1124 * <a name=
"Thecodemaincodefunction"></a>
1125 * <h3>The <code>main</code> function</h3>
1131 *
int main (
int argc,
char *argv[])
1137 * LaserHeating<2> laserHeating_2d;
1138 * laserHeating_2d.run ();
1142 *
catch (std::exception &exc)
1144 * std::cerr << std::endl
1146 * <<
"----------------------------------------------------"
1148 * std::cerr <<
"Exception on processing: " << std::endl
1149 * << exc.what() << std::endl
1150 * <<
"Aborting!" << std::endl
1151 * <<
"----------------------------------------------------"
1158 * std::cerr << std::endl
1160 * <<
"----------------------------------------------------"
1162 * std::cerr <<
"Unknown exception!" << std::endl
1163 * <<
"Aborting!" << std::endl
1164 * <<
"----------------------------------------------------"
1175<a name=
"ann-boundaryInit.h"></a>
1176<h1>Annotated version of boundaryInit.h</h1>
1183 * #----------------------------------------------------------
1185 * # This file defines the boundary and
initial conditions
1187 * #----------------------------------------------------------
1193 * #ifndef GLOBAL_PARA
1194 * #define GLOBAL_PARA
1195 * #include
"./globalPara.h"
1200 * #----------------------------------------------------------
1207 *
template <
int dim>
1208 *
class BoundaryValues :
public Function<dim>
1211 * BoundaryValues () :
Function<dim>() {}
1214 *
const unsigned int component = 0)
const override;
1217 *
template <
int dim>
1218 *
class InitialValues :
public Function<dim>
1221 * InitialValues () :
Function<dim>() {}
1224 *
const unsigned int component = 0)
const override;
1230 * #----------------------------------------------------------
1237 *
template <
int dim>
1238 *
double BoundaryValues<dim>::value (
const Point<dim> &,
1239 *
const unsigned int )
const
1245 *
template <
int dim>
1246 *
double InitialValues<dim>::value (
const Point<dim> &,
1247 *
const unsigned int )
const
1258 * #----------------------------------------------------------
1259 * # Declaration and Implementation
1260 * # mass density and heat capacity
1266 *
template <
int dim>
1267 *
class RhoC :
public Function<dim>
1273 *
const unsigned int component = 0)
const override;
1276 *
template <
int dim>
1277 *
double RhoC<dim>::value (
const Point<dim> &p,
1278 *
const unsigned int )
const
1282 * # p stores the xyz coordinates at each vertex
1283 * #
for 2D problems in xy, we assume the non-uniform is in y-axis.
1286 *
if ( p[1] >= -global_film_thickness )
1288 *
return global_rho_Tio2 * global_C_Tio2;
1291 *
return global_rho_glass * global_C_glass;
1299 * #----------------------------------------------------------
1300 * # Declaration and Implementation
1301 * # thermal conductivity
1307 *
template <
int dim>
1314 *
const unsigned int component = 0)
const override;
1317 *
template <
int dim>
1318 *
double K_T<dim>::value (
const Point<dim> &p,
1319 *
const unsigned int )
const
1323 * # p stores the xyz coordinates at each vertex
1324 * #
for 2D problems in xy, we assume the non-uniform is in y-axis.
1327 *
if ( p[1] >= -global_film_thickness)
1329 *
return global_k_Tio2;
1332 *
return global_k_glass;
1338<a name=
"ann-globalPara.h"></a>
1339<h1>Annotated version of globalPara.h</h1>
1346 * # physics constants
1349 *
double global_PI = 3.1415927;
1356 *
double global_Pow_laser = 0.4;
1357 *
double global_spotsize_at_e_2 = 20
e-6;
1358 *
double global_c_laser = global_spotsize_at_e_2 / 4.0;
1359 *
double global_c_hwhm = global_c_laser * 2.35482 / 2;
1360 *
double global_V_scan_x = 10
e-3;
1362 *
double global_init_position_x0 = -50
e-6;
1370 *
double global_rho_Tio2 = 4200;
1371 *
double global_C_Tio2 = 690;
1372 *
double global_k_Tio2 = 4.8;
1378 *
double global_rho_glass = 2200;
1379 *
double global_C_glass = 700;
1380 *
double global_k_glass = 1.8;
1382 *
double global_film_thickness = 400
e-9;
1389 *
double global_simulation_time_step = 1
e-5;
1390 *
double global_simulation_end_time = 100
e-6 / global_V_scan_x;
1397 * #define BOUNDARY_NUM 11
1401<a name=
"ann-rightHandSide.h"></a>
1402<h1>Annotated version of rightHandSide.h</h1>
1406 * #----------------------------------------------------------
1408 * # This file defines the boundary and
initial conditions
1410 * #----------------------------------------------------------
1416 * #ifndef GLOBAL_PARA
1417 * #define GLOBAL_PARA
1418 * #include
"./globalPara.h"
1423 * #----------------------------------------------------------
1430 *
template <
int dim>
1431 *
class RightHandside :
public Function<dim>
1434 * RightHandside () :
Function<dim>() {}
1441 * #----------------------------------------------------------
1448 *
template <
int dim>
1449 *
double RightHandside<dim>::value_v2 (
const Point<dim> &p)
1452 *
double alpha_abs = 1e4;
1455 *
if(p[1] >= -global_film_thickness)
1458 *
double P00 = global_Pow_laser / global_PI / global_c_laser / global_c_laser / 2.0;
1462 * (p[0] - global_V_scan_x * this->
get_time()-global_init_position_x0) *
1463 * (p[0] - global_V_scan_x * this->
get_time()-global_init_position_x0)
1465 * (2.0 * global_c_laser * global_c_laser) );
1468 *
return alpha_abs * I00 *
std::exp(-alpha_abs*(0 - p[1]));
void attach_dof_handler(const DoFHandler< dim, spacedim > &)
virtual RangeNumberType value(const Point< dim > &p, const unsigned int component=0) const
void attach_triangulation(Triangulation< dim, spacedim > &tria)
typename ActiveSelector::active_cell_iterator active_cell_iterator
void make_hanging_node_constraints(const DoFHandler< dim, spacedim > &dof_handler, AffineConstraints< number > &constraints)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints=AffineConstraints< number >(), const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
void refine(Triangulation< dim, spacedim > &tria, const Vector< Number > &criteria, const double threshold, const unsigned int max_to_mark=numbers::invalid_unsigned_int)
@ matrix
Contents is actually a matrix.
@ general
No special properties.
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
void copy(const T *begin, const T *end, U *dest)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
::VectorizedArray< Number, width > exp(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
const ::Triangulation< dim, spacedim > & tria