780 * <a name=
"PerfectlyMatchedLayerClass"></a>
808 *
static_assert(dim == 2,
809 *
"The perfectly matched layer is only implemented in 2d.");
825 *
std::complex<double>
d_2,
846 *
add_parameter(
"inner radius",
848 *
"inner radius of the PML shell");
850 *
add_parameter(
"outer radius",
852 *
"outer radius of the PML shell");
854 *
add_parameter(
"strength",
strength,
"strength of the PML");
859 *
typename std::complex<double>
878 *
typename std::complex<double>
884 *
const double s_bar =
890 *
return {1.0,
s_bar};
902 *
std::complex<double>
d_2,
918 *
const auto d = this->d(point);
919 *
const auto d_bar = this->d_bar(point);
929 *
const auto d = this->d(point);
930 *
const auto d_bar = this->d_bar(point);
939 *
const auto d = this->d(point);
940 *
const auto d_bar = this->d_bar(point);
949 * <a name=
"MaxwellClass"></a>
973 *
unsigned int refinements;
991 *
std::unique_ptr<FiniteElement<dim>> fe;
1003 * <a name=
"ClassTemplateDefinitionsandImplementation"></a>
1009 * <a name=
"TheConstructor"></a>
1020 * these are also known as perfectly conducting boundary conditions.
1026 * template <int dim>
1027 * Maxwell<dim>::Maxwell()
1028 * : ParameterAcceptor("Maxwell")
1029 * , dof_handler(triangulation)
1031 * ParameterAcceptor::parse_parameters_call_back.connect(
1032 * [&]() { parse_parameters_callback(); });
1035 * add_parameter("scaling", scaling, "scale of the hypercube geometry");
1038 * add_parameter("refinements",
1040 * "number of refinements of the geometry");
1043 * add_parameter("fe order", fe_order, "order of the finite element space");
1045 * quadrature_order = 1;
1046 * add_parameter("quadrature order",
1048 * "order of the quadrature");
1050 * absorbing_boundary = true;
1051 * add_parameter("absorbing boundary condition",
1052 * absorbing_boundary,
1053 * "use absorbing boundary conditions?");
1057 * template <int dim>
1058 * void Maxwell<dim>::parse_parameters_callback()
1060 * fe = std::make_unique<FESystem<dim>>(FE_NedelecSZ<dim>(fe_order), 2);
1065 * The Maxwell::make_grid() routine creates the mesh for the
1066 * computational domain which in our case is a scaled square domain.
1067 * Additionally, a material interface is introduced by setting the
1068 * material id of the upper half (@f$y>0@f$) to 1 and of the lower half
1069 * (@f$y<0@f$) of the computational domain to 2.
1070 * We are using a block decomposition into real and imaginary matrices
1071 * for the solution matrices. More details on this are available
1072 * under the Results section.
1078 * template <int dim>
1079 * void Maxwell<dim>::make_grid()
1081 * GridGenerator::hyper_cube(triangulation, -scaling, scaling);
1082 * triangulation.refine_global(refinements);
1084 * if (!absorbing_boundary)
1086 * for (auto &face : triangulation.active_face_iterators())
1087 * if (face->at_boundary())
1088 * face->set_boundary_id(1);
1091 * for (auto &cell : triangulation.active_cell_iterators())
1092 * if (cell->center()[1] > 0.)
1093 * cell->set_material_id(1);
1095 * cell->set_material_id(2);
1098 * std::cout << "Number of active cells: " << triangulation.n_active_cells()
1104 * The Maxwell::setup_system() routine follows the usual routine of
1105 * enumerating all the degrees of freedom and setting up the matrix and
1106 * vector objects to hold the system data. Enumerating is done by using
1107 * DoFHandler::distribute_dofs().
1113 * template <int dim>
1114 * void Maxwell<dim>::setup_system()
1116 * dof_handler.distribute_dofs(*fe);
1117 * std::cout << "Number of degrees of freedom: " << dof_handler.n_dofs()
1120 * solution.reinit(dof_handler.n_dofs());
1121 * system_rhs.reinit(dof_handler.n_dofs());
1123 * constraints.clear();
1125 * DoFTools::make_hanging_node_constraints(dof_handler, constraints);
1127 * VectorTools::project_boundary_values_curl_conforming_l2(
1129 * 0, /* real part */
1130 * Functions::ZeroFunction<dim>(2 * dim),
1131 * 0, /* boundary id */
1133 * VectorTools::project_boundary_values_curl_conforming_l2(
1135 * dim, /* imaginary part */
1136 * Functions::ZeroFunction<dim>(2 * dim),
1137 * 0, /* boundary id */
1140 * constraints.close();
1142 * DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs());
1143 * DoFTools::make_sparsity_pattern(dof_handler,
1146 * /* keep_constrained_dofs = */ true);
1147 * sparsity_pattern.copy_from(dsp);
1148 * system_matrix.reinit(sparsity_pattern);
1153 * This is a helper function that takes the tangential component of a tensor.
1156 * template <int dim>
1157 * DEAL_II_ALWAYS_INLINE inline Tensor<1, dim, std::complex<double>>
1158 * tangential_part(const Tensor<1, dim, std::complex<double>> &tensor,
1159 * const Tensor<1, dim> & normal)
1161 * auto result = tensor;
1162 * result[0] = normal[1] * (tensor[0] * normal[1] - tensor[1] * normal[0]);
1163 * result[1] = -normal[0] * (tensor[0] * normal[1] - tensor[1] * normal[0]);
1170 * Assemble the stiffness matrix and the right-hand side:
1172 * A_{ij} = \int_\Omega (\mu_r^{-1}\nabla \times \varphi_j) \cdot
1173 * (\nabla\times\bar{\varphi}_i)\text{d}x
1174 * - \int_\Omega \varepsilon_r\varphi_j \cdot \bar{\varphi}_i\text{d}x
1175 * - i\int_\Sigma (\sigma_r^{\Sigma}(\varphi_j)_T) \cdot
1176 * (\bar{\varphi}_i)_T\text{do}x
1177 * - i\int_{\partial\Omega} (\sqrt{\mu_r^{-1}\varepsilon}(\varphi_j)_T) \cdot
1178 * (\nabla\times(\bar{\varphi}_i)_T)\text{d}x, \f} \f{align}{
1179 * F_i = i\int_\Omega J_a \cdot \bar{\varphi_i}\text{d}x - \int_\Omega
1180 * \mu_r^{-1} \cdot (\nabla \times \bar{\varphi_i}) \text{d}x.
1182 * In addition, we will be modifying the coefficients if the position of the
1183 * cell is within the PML region.
1189 * template <int dim>
1190 * void Maxwell<dim>::assemble_system()
1192 * QGauss<dim> quadrature_formula(quadrature_order);
1193 * QGauss<dim - 1> face_quadrature_formula(quadrature_order);
1195 * FEValues<dim, dim> fe_values(*fe,
1196 * quadrature_formula,
1197 * update_values | update_gradients |
1198 * update_quadrature_points |
1199 * update_JxW_values);
1200 * FEFaceValues<dim, dim> fe_face_values(*fe,
1201 * face_quadrature_formula,
1202 * update_values | update_gradients |
1203 * update_quadrature_points |
1204 * update_normal_vectors |
1205 * update_JxW_values);
1207 * const unsigned int dofs_per_cell = fe->dofs_per_cell;
1209 * const unsigned int n_q_points = quadrature_formula.size();
1210 * const unsigned int n_face_q_points = face_quadrature_formula.size();
1212 * FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
1213 * Vector<double> cell_rhs(dofs_per_cell);
1214 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1218 * This is assembling the interior of the domain on the left hand side.
1219 * So we are assembling
1221 * \int_\Omega (\mu_r^{-1}\nabla \times \varphi_i) \cdot
1222 * (\nabla\times\bar{\varphi}_j)\text{d}x
1223 * - \int_\Omega \varepsilon_r\varphi_i \cdot \bar{\varphi}_j\text{d}x
1227 * i\int_\Omega J_a \cdot \bar{\varphi_i}\text{d}x
1228 * - \int_\Omega \mu_r^{-1} \cdot (\nabla \times \bar{\varphi_i}) \text{d}x.
1230 * In doing so, we need test functions @f$\varphi_i@f$ and @f$\varphi_j@f$, and the
1231 * curl of these test variables. We must be careful with the signs of the
1232 * imaginary parts of these complex test variables. Moreover, we have a
1233 * conditional that changes the parameters if the cell is in the PML region.
1236 * for (const auto &cell : dof_handler.active_cell_iterators())
1238 * fe_values.reinit(cell);
1239 * FEValuesViews::Vector<dim> real_part(fe_values, 0);
1240 * FEValuesViews::Vector<dim> imag_part(fe_values, dim);
1245 * cell->get_dof_indices(local_dof_indices);
1246 * const auto id = cell->material_id();
1248 * const auto &quadrature_points = fe_values.get_quadrature_points();
1250 * for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
1252 * const Point<dim> &position = quadrature_points[q_point];
1254 * auto mu_inv = parameters.mu_inv(position, id);
1255 * auto epsilon = parameters.epsilon(position, id);
1256 * const auto J_a = parameters.J_a(position, id);
1258 * const auto A = perfectly_matched_layer.a_matrix(position);
1259 * const auto B = perfectly_matched_layer.b_matrix(position);
1260 * const auto d = perfectly_matched_layer.d(position);
1262 * mu_inv = mu_inv / d;
1263 * epsilon = invert(A) * epsilon * invert(B);
1265 * for (const auto i : fe_values.dof_indices())
1267 * constexpr std::complex<double> imag{0., 1.};
1269 * const auto phi_i = real_part.value(i, q_point) -
1270 * imag * imag_part.value(i, q_point);
1271 * const auto curl_phi_i = real_part.curl(i, q_point) -
1272 * imag * imag_part.curl(i, q_point);
1274 * const auto rhs_value =
1275 * (imag * scalar_product(J_a, phi_i)) * fe_values.JxW(q_point);
1276 * cell_rhs(i) += rhs_value.real();
1278 * for (const auto j : fe_values.dof_indices())
1280 * const auto phi_j = real_part.value(j, q_point) +
1281 * imag * imag_part.value(j, q_point);
1282 * const auto curl_phi_j = real_part.curl(j, q_point) +
1283 * imag * imag_part.curl(j, q_point);
1286 * (scalar_product(mu_inv * curl_phi_j, curl_phi_i) -
1287 * scalar_product(epsilon * phi_j, phi_i)) *
1288 * fe_values.JxW(q_point);
1289 * cell_matrix(i, j) += temp.real();
1296 * Now we assemble the face and the boundary. The following loops will
1299 * - i\int_\Sigma (\sigma_r^{\Sigma}(\varphi_i)_T) \cdot
1300 * (\bar{\varphi}_j)_T\text{do}x \f} and \f{align}{
1301 * - i\int_{\partial\Omega} (\sqrt{\mu_r^{-1}\varepsilon}(\varphi_i)_T)
1302 * \cdot (\nabla\times(\bar{\varphi}_j)_T)\text{d}x,
1304 * respectively. The test variables and the PML are implemented
1305 * similarly as the domain.
1308 * for (const auto &face : cell->face_iterators())
1310 * if (face->at_boundary())
1312 * const auto id = face->boundary_id();
1315 * fe_face_values.reinit(cell, face);
1316 * FEValuesViews::Vector<dim> real_part(fe_face_values, 0);
1317 * FEValuesViews::Vector<dim> imag_part(fe_face_values, dim);
1319 * for (unsigned int q_point = 0; q_point < n_face_q_points;
1322 * const auto &position = quadrature_points[q_point];
1324 * auto mu_inv = parameters.mu_inv(position, id);
1325 * auto epsilon = parameters.epsilon(position, id);
1328 * perfectly_matched_layer.a_matrix(position);
1330 * perfectly_matched_layer.b_matrix(position);
1331 * const auto d = perfectly_matched_layer.d(position);
1333 * mu_inv = mu_inv / d;
1334 * epsilon = invert(A) * epsilon * invert(B);
1336 * const auto normal =
1337 * fe_face_values.normal_vector(q_point);
1339 * for (const auto i : fe_face_values.dof_indices())
1341 * constexpr std::complex<double> imag{0., 1.};
1343 * const auto phi_i =
1344 * real_part.value(i, q_point) -
1345 * imag * imag_part.value(i, q_point);
1346 * const auto phi_i_T = tangential_part(phi_i, normal);
1348 * for (const auto j : fe_face_values.dof_indices())
1350 * const auto phi_j =
1351 * real_part.value(j, q_point) +
1352 * imag * imag_part.value(j, q_point);
1353 * const auto phi_j_T =
1354 * tangential_part(phi_j, normal) *
1355 * fe_face_values.JxW(q_point);
1357 * const auto prod = mu_inv * epsilon;
1358 * const auto sqrt_prod = prod;
1361 * -imag * scalar_product((sqrt_prod * phi_j_T),
1363 * cell_matrix(i, j) += temp.real();
1373 * We are on an interior face:
1376 * const auto face_index = cell->face_iterator_to_index(face);
1378 * const auto id1 = cell->material_id();
1379 * const auto id2 = cell->neighbor(face_index)->material_id();
1382 * continue; /* skip this face */
1384 * fe_face_values.reinit(cell, face);
1385 * FEValuesViews::Vector<dim> real_part(fe_face_values, 0);
1386 * FEValuesViews::Vector<dim> imag_part(fe_face_values, dim);
1388 * for (unsigned int q_point = 0; q_point < n_face_q_points;
1391 * const auto &position = quadrature_points[q_point];
1393 * auto sigma = parameters.sigma(position, id1, id2);
1395 * const auto B = perfectly_matched_layer.b_matrix(position);
1396 * const auto C = perfectly_matched_layer.c_matrix(position);
1397 * sigma = invert(C) * sigma * invert(B);
1399 * const auto normal = fe_face_values.normal_vector(q_point);
1401 * for (const auto i : fe_face_values.dof_indices())
1403 * constexpr std::complex<double> imag{0., 1.};
1405 * const auto phi_i = real_part.value(i, q_point) -
1406 * imag * imag_part.value(i, q_point);
1407 * const auto phi_i_T = tangential_part(phi_i, normal);
1409 * for (const auto j : fe_face_values.dof_indices())
1411 * const auto phi_j =
1412 * real_part.value(j, q_point) +
1413 * imag * imag_part.value(j, q_point);
1414 * const auto phi_j_T = tangential_part(phi_j, normal);
1418 * scalar_product((sigma * phi_j_T), phi_i_T) *
1419 * fe_face_values.JxW(q_point);
1420 * cell_matrix(i, j) += temp.real();
1427 * constraints.distribute_local_to_global(
1428 * cell_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs);
1434 * We use a direct solver from the SparseDirectUMFPACK to solve the system
1437 * template <int dim>
1438 * void Maxwell<dim>::solve()
1440 * SparseDirectUMFPACK A_direct;
1441 * A_direct.initialize(system_matrix);
1442 * A_direct.vmult(solution, system_rhs);
1447 * The output is written into a vtk file with 4 components
1450 * template <int dim>
1451 * void Maxwell<dim>::output_results()
1453 * DataOut<2> data_out;
1454 * data_out.attach_dof_handler(dof_handler);
1455 * data_out.add_data_vector(solution,
1456 * {"real_Ex", "real_Ey", "imag_Ex", "imag_Ey"});
1457 * data_out.build_patches();
1458 * std::ofstream output("solution.vtk");
1459 * data_out.write_vtk(output);
1463 * template <int dim>
1464 * void Maxwell<dim>::run()
1468 * assemble_system();
1473 * } // namespace Step81
1477 * The following main function calls the class @ref step_81 "step-81"(), initializes the
1478 * ParameterAcceptor, and calls the run() function.
1488 * using namespace dealii;
1490 * Step81::Maxwell<2> maxwell_2d;
1491 * ParameterAcceptor::initialize("parameters.prm");
1494 * catch (std::exception &exc)
1496 * std::cerr << std::endl
1498 * << "----------------------------------------------------"
1500 * std::cerr << "Exception on processing: " << std::endl
1501 * << exc.what() << std::endl
1502 * << "Aborting!" << std::endl
1503 * << "----------------------------------------------------"
1509 * std::cerr << std::endl
1511 * << "----------------------------------------------------"
1513 * std::cerr << "Unknown exception!" << std::endl
1514 * << "Aborting!" << std::endl
1515 * << "----------------------------------------------------"
1522<a name="Results"></a><h1>Results</h1>
1525The solution is written to a .vtk file with four components. These are the
1526real and imaginary parts of the @f$E_x@f$ and @f$E_y@f$ solution waves. With the
1527current setup, the output should read
1530Number of active cells: 4096
1531Number of degrees of freedom: 16640
1532Program ended with exit code: 0
1535<a name="AbsorbingboundaryconditionsandthePML"></a><h3> Absorbing boundary conditions and the PML </h3>
1538The following images are the outputs for the imaginary @f$E_x@f$ without the
1539interface and with the dipole centered at @f$(0,0)@f$. In order to remove the
1540interface, the surface conductivity is set to 0. First, we turn off the
1541absorbing boundary conditions and the PML. Second, we want to see the
1542effect of the PML when absorbing boundary conditions apply. So we set
1543absorbing boundary conditions to true and leave the PML strength to 0.
1544Lastly, we increase the strength of the PML to 4. Change the following in
1548# use absorbing boundary conditions?
1549 set absorbing boundary condition = false
1551# position of the dipole
1552 set dipole position = 0, 0
1554# strength of the PML
1557# surface conductivity between material 1 and material 2
1558 set sigma = 0, 0; 0, 0| 0, 0; 0, 0
1561Following are the output images:
1563<table width="80%" align="center">
1566 <img src="https://www.dealii.org/images/steps/developer/step-81-nointerface_noabs_PML0.png" alt="Visualization of the solution of step-81 with no interface, Dirichlet boundary conditions and PML strength 0" height="210"/>
1567 <p> Solution with no interface, Dirichlet boundary conditions and PML strength 0.</p>
1571 <img src="https://www.dealii.org/images/steps/developer/step-81-nointerface_abs_PML0.png" alt="Visualization of the solution of step-81 with no interface, absorbing boundary conditions and PML strength 0" height="210">
1572 <p> Solution with no interface, absorbing boundary conditions and PML strength 0.</p>
1576 <img src="https://www.dealii.org/images/steps/developer/step-81-nointerface_abs_PML4.png" alt="Visualization of the solution of step-81 with no interface, absorbing boundary conditions and PML strength 4" height="210">
1577 <p> Solution with no interface, absorbing boundary conditions and PML strength 4.</p>
1582We observe that with absorbing boundary conditions and in absence of the
1583PML, there is a lot of distortion and resonance (the real parts will not be
1584generated without a PML). This is, as we stipulated, due to reflection from
1585infinity. As we see, a much more coherent image is generated with an
1588<a name="SurfacePlasmonPolariton"></a><h3> Surface Plasmon Polariton </h3>
1595# position of the dipole
1598# surface conductivity between material 1 and material 2
1599 set sigma = 0.001, 0.2; 0, 0| 0, 0; 0.001, 0.2
1607<table width=
"80%" align=
"center">
1610 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-imagEx_noabs_PML0.png" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1615 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-imagEx_abs_PML0.png" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1620 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-imagEx_abs_PML4.png" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 4" height=
"210">
1627<table width=
"80%" align=
"center">
1630 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-realEx_noabs_PML0.png" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1635 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-realEx_abs_PML0.png" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1640 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-realEx_abs_PML4.png" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 4" height=
"210">
1655<table width=
"80%" align=
"center">
1658 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-dirichlet_Ex.gif" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1663 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-absorbing_Ex.gif" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1668 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-perfectly_matched_layer_Ex.gif" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 4" height=
"210">
1675<table width=
"80%" align=
"center">
1678 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-dirichlet_Ey.gif" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1683 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-absorbing_Ey.gif" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 0" height=
"210">
1688 <
img src=
"https://www.dealii.org/images/steps/developer/step-81-perfectly_matched_layer_Ey.gif" alt=
"Visualization of the solution of step-81 with an interface, absorbing boundary conditions and PML strength 4" height=
"210">
1709<a name=
"RotationsandScaling"></a><
h4> Rotations
and Scaling </
h4>
1719any arbitrary scaling constants @f$a@f$ and @f$b@f$. If we choose this scaling, the
1720@f$\phi_j@f$ must also be modified with the same scaling, as follows:
1723const auto phi_i = a*real_part.value(i, q_point) -
1724 bi * imag_part.value(i, q_point);
1726const auto phi_j = a*real_part.value(i, q_point) +
1727 bi * imag_part.value(i, q_point);
1730Moreover, the cell_rhs need not be the real part of the rhs_value. Say if
1731we modify to take the imaginary part of the computed rhs_value, we must
1732also modify the cell_matrix accordingly to take the imaginary part of temp.
1733However, making these changes to both sides of the equation will not affect
1734our solution, and we will still be able to generate the surface plasmon
1738cell_rhs(i) += rhs_value.imag();
1740cell_matrix(i) += temp.imag();
1743<a name="Postprocessing"></a><h4> Postprocessing </h4>
1745We will create a video demonstrating the wave in motion, which is
1746essentially an implementation of @f$e^{-i\omega t}(Re(E) + i*Im(E))@f$ as we
1747increment time. This is done by slightly changing the output function to
1748generate a series of .vtk files, which will represent out solution wave as
1749we increment time. Introduce an input variable @f$t@f$ in the output_results()
1750class as output_results(unsigned int t). Then change the class itself to
1755void Maxwell<dim>::output_results(unsigned int t)
1757 std::cout << "Running step:" << t << std::endl;
1758 DataOut<2> data_out;
1759 data_out.attach_dof_handler(dof_handler);
1760 Vector<double> postprocessed;
1761 postprocessed.reinit(solution);
1762 for (unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
1766 postprocessed[i] = std::cos(2 * M_PI * 0.04 * t) * solution[i] -
1767 std::sin(2 * M_PI * 0.04 * t) * solution[i + 1];
1769 else if (i % 4 == 2)
1771 postprocessed[i] = std::cos(2 * M_PI * 0.04 * t) * solution[i] -
1772 std::sin(2 * M_PI * 0.04 * t) * solution[i + 1];
1775 data_out.add_data_vector(postprocessed, {"E_x", "E_y", "null0", "null1"});
1776 data_out.build_patches();
1777 const std::string filename =
1778 "solution-" + Utilities::int_to_string(t) + ".vtk";
1779 std::ofstream output(filename);
1780 data_out.write_vtk(output);
1781 std::cout << "Done running step:" << t << std::endl;
1785Finally, in the run() function, replace output_results() with
1787for (int t = 0; t <= 100; t++)
1793This would generate 100 solution .vtk files, which can be opened in a group
1794on Paraview and then can be saved as an animation. We used FFMPEG to
1797<a name="PossibilitiesforExtension"></a><h3> Possibilities for Extension </h3>
1800The example step could be extended in a number of different directions.
1803 The current program uses a direct solver to solve the linear system.
1804 This is efficient for two spatial dimensions where scattering problems
1805 up to a few millions degrees of freedom can be solved. In 3D, however,
1806 the increased stencil size of the Nedelec element pose a severe
1807 limiting factor on the problem size that can be computed. As an
1808 alternative, the idea to use iterative solvers can be entertained.
1809 This, however requires specialized preconditioners. For example, just
1810 using an iterative Krylov space solver (such as SolverGMRES) on above
1811 problem will requires many thousands of iterations to converge.
1830<a name=
"PlainProg"></a>
void add_parameter(const std::string &entry, ParameterType ¶meter, const std::string &documentation="", ParameterHandler &prm_=prm, const Patterns::PatternBase &pattern= *Patterns::Tools::Convert< ParameterType >::to_pattern())
numbers::NumberTraits< Number >::real_type norm() const
__global__ void set(Number *val, const Number s, const size_type N)
void loop(ITERATOR begin, std_cxx20::type_identity_t< ITERATOR > end, DOFINFO &dinfo, INFOBOX &info, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(DOFINFO &, DOFINFO &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, ASSEMBLER &assembler, const LoopControl &lctrl=LoopControl())
double norm(const FEValuesBase< dim > &fe, const ArrayView< const std::vector< Tensor< 1, dim > > > &Du)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
SymmetricTensor< 2, dim, Number > C(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
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)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)