653 *
double return_value = 0.0;
654 *
for (
unsigned int i = 0; i < dim; ++i)
655 * return_value += 4.0 *
std::pow(p(i), 4.0);
657 *
return return_value;
663 * BoundaryValues<dim>::value(
const Point<dim> &p,
664 *
const unsigned int )
const
672 * CoupledLaplaceProblem<dim>::CoupledLaplaceProblem()
675 * , interface_boundary_id(1)
676 * , adapter(parameters, interface_boundary_id)
682 * CoupledLaplaceProblem<dim>::make_grid()
687 *
for (
const auto &cell :
triangulation.active_cell_iterators())
688 *
for (
const auto face : cell->face_iterators())
692 * We choose the boundary in
positive x direction
for the
693 *
interface coupling.
696 *
if (face->at_boundary() && (face->center()[0] == 1))
697 * face->set_boundary_id(interface_boundary_id);
700 * std::cout <<
" Number of active cells: " <<
triangulation.n_active_cells()
709 * CoupledLaplaceProblem<dim>::setup_system()
711 * dof_handler.distribute_dofs(fe);
713 * std::cout <<
" Number of degrees of freedom: " << dof_handler.n_dofs()
718 * sparsity_pattern.copy_from(dsp);
720 * system_matrix.reinit(sparsity_pattern);
722 * solution.reinit(dof_handler.n_dofs());
723 * old_solution.reinit(dof_handler.n_dofs());
724 * system_rhs.reinit(dof_handler.n_dofs());
731 * CoupledLaplaceProblem<dim>::assemble_system()
735 * Reset global structures
742 * Update old solution
values
745 * old_solution = solution;
749 * RightHandSide<dim> right_hand_side;
752 * quadrature_formula,
756 *
const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
760 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
763 * The solution
values from previous time steps are stored
for each quadrature
767 * std::vector<double> local_values_old_solution(fe_values.n_quadrature_points);
769 *
for (
const auto &cell : dof_handler.active_cell_iterators())
771 * fe_values.reinit(cell);
776 * Get the local
values from the `fe_values
' object
779 * fe_values.get_function_values(old_solution, local_values_old_solution);
783 * The system matrix contains additionally a mass matrix due to the time
784 * discretization. The RHS has contributions from the old solution values.
787 * for (const unsigned int q_index : fe_values.quadrature_point_indices())
788 * for (const unsigned int i : fe_values.dof_indices())
790 * for (const unsigned int j : fe_values.dof_indices())
791 * cell_matrix(i, j) +=
792 * ((fe_values.shape_value(i, q_index) * // phi_i(x_q)
793 * fe_values.shape_value(j, q_index)) + // phi_j(x_q)
794 * (delta_t * // delta t
795 * fe_values.shape_grad(i, q_index) * // grad phi_i(x_q)
796 * fe_values.shape_grad(j, q_index))) * // grad phi_j(x_q)
797 * fe_values.JxW(q_index); // dx
799 * const auto x_q = fe_values.quadrature_point(q_index);
800 * const auto &local_value = local_values_old_solution[q_index];
801 * cell_rhs(i) += ((delta_t * // delta t
802 * fe_values.shape_value(i, q_index) * // phi_i(x_q)
803 * right_hand_side.value(x_q)) + // f(x_q)
804 * fe_values.shape_value(i, q_index) *
805 * local_value) * // phi_i(x_q)*val
806 * fe_values.JxW(q_index); // dx
811 * Copy local to global
814 * cell->get_dof_indices(local_dof_indices);
815 * for (const unsigned int i : fe_values.dof_indices())
817 * for (const unsigned int j : fe_values.dof_indices())
818 * system_matrix.add(local_dof_indices[i],
819 * local_dof_indices[j],
820 * cell_matrix(i, j));
822 * system_rhs(local_dof_indices[i]) += cell_rhs(i);
828 * At first, we apply the Dirichlet boundary condition from @ref step_4 "step-4", as
832 * std::map<types::global_dof_index, double> boundary_values;
833 * VectorTools::interpolate_boundary_values(dof_handler,
835 * BoundaryValues<dim>(),
837 * MatrixTools::apply_boundary_values(boundary_values,
845 * Afterwards, we apply the coupling boundary condition. The `boundary_data`
846 * has already been filled by preCICE.
849 * MatrixTools::apply_boundary_values(boundary_data,
860 * CoupledLaplaceProblem<dim>::solve()
862 * SolverControl solver_control(1000, 1e-12);
863 * SolverCG<Vector<double>> solver(solver_control);
864 * solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity());
866 * std::cout << " " << solver_control.last_step()
867 * << " CG iterations needed to obtain convergence." << std::endl;
874 * CoupledLaplaceProblem<dim>::output_results() const
876 * DataOut<dim> data_out;
878 * data_out.attach_dof_handler(dof_handler);
879 * data_out.add_data_vector(solution, "solution");
881 * data_out.build_patches(mapping);
883 * std::ofstream output("solution-" + std::to_string(time_step) + ".vtk");
884 * data_out.write_vtk(output);
891 * CoupledLaplaceProblem<dim>::run()
893 * std::cout << "Solving problem in " << dim << " space dimensions."
901 * After we set up the system, we initialize preCICE using the functionalities
902 * of the Adapter. preCICE returns the maximum admissible time-step size,
903 * which needs to be compared to our desired solver time-step size.
906 * precice_delta_t = adapter.initialize(dof_handler, boundary_data, mapping);
907 * delta_t = std::min(precice_delta_t, solver_delta_t);
911 * preCICE steers the coupled simulation: `isCouplingOngoing` is
912 * used to synchronize the end of the simulation with the coupling partner
915 * while (adapter.precice.isCouplingOngoing())
919 * The time step number is solely used to generate unique output files
925 * In the time loop, we assemble the coupled system and solve it as
934 * After we solved the system, we advance the coupling to the next time
935 * level. In a bi-directional coupled simulation, we would pass our
936 * calculated data to and obtain new data from preCICE. Here, we simply
937 * obtain new data from preCICE, so from the other participant. As before,
938 * we obtain a maximum time-step size and compare it against the desired
939 * solver time-step size.
942 * precice_delta_t = adapter.advance(boundary_data, delta_t);
943 * delta_t = std::min(precice_delta_t, solver_delta_t);
947 * Write an output file if the time step is completed. In case of an
948 * implicit coupling, where individual time steps are computed more than
949 * once, the function `isTimeWindowCompleted` prevents unnecessary result
950 * writing. For this simple tutorial configuration (explicit coupling),
951 * the function returns always `true`.
954 * if (adapter.precice.isTimeWindowComplete())
964 * CoupledLaplaceProblem<2> laplace_problem;
965 * laplace_problem.run();
972<a name="ann-fancy_boundary_condition.cc"></a>
973<h1>Annotated version of fancy_boundary_condition.cc</h1>
977 * This program does not use any deal.II functionality and depends only on
978 * preCICE and the standard libraries.
981 * #include <precice/SolverInterface.hpp>
983 * #include <iostream>
988 * The program computes a time-varying parabolic boundary condition, which is
989 * passed to preCICE and serves as Dirichlet boundary condition for the other
990 * coupling participant.
994 * Function to generate boundary values in each time step
998 * define_boundary_values(std::vector<double> &boundary_data,
1000 * const double end_time)
1004 * Scale the current time value
1007 * const double relative_time = time / end_time;
1010 * Define the amplitude. Values run from -0.5 to 0.5
1013 * const double amplitude = (relative_time - 0.5);
1016 * Specify the actual data we want to pass to the other participant. Here, we
1017 * choose a parabola with boundary values 2 in order to enforce continuity
1018 * to adjacent boundaries.
1021 * const double n_elements = boundary_data.size();
1022 * const double right_zero = boundary_data.size() - 1;
1023 * const double left_zero = 0;
1024 * const double offset = 2;
1025 * for (uint i = 0; i < n_elements; ++i)
1026 * boundary_data[i] =
1027 * -amplitude * ((i - left_zero) * (i - right_zero)) + offset;
1034 * std::cout << "Boundary participant: starting... \n";
1041 * const std::string configFileName("precice-config.xml");
1042 * const std::string solverName("boundary-participant");
1043 * const std::string meshName("boundary-mesh");
1044 * const std::string dataWriteName("boundary-data");
1048 * Adjust to MPI rank and size for parallel computation
1051 * const int commRank = 0;
1052 * const int commSize = 1;
1054 * precice::SolverInterface precice(solverName,
1059 * const int meshID = precice.getMeshID(meshName);
1060 * const int dimensions = precice.getDimensions();
1061 * const int numberOfVertices = 6;
1063 * const int dataID = precice.getDataID(dataWriteName, meshID);
1067 * Set up data structures
1070 * std::vector<double> writeData(numberOfVertices);
1071 * std::vector<int> vertexIDs(numberOfVertices);
1072 * std::vector<double> vertices(numberOfVertices * dimensions);
1076 * Define a boundary mesh
1079 * std::cout << "Boundary participant: defining boundary mesh \n";
1080 * const double length = 2;
1081 * const double xCoord = 1;
1082 * const double deltaY = length / (numberOfVertices - 1);
1083 * for (int i = 0; i < numberOfVertices; ++i)
1084 * for (int j = 0; j < dimensions; ++j)
1086 * const unsigned int index = dimensions * i + j;
1089 * The x-coordinate is always 1, i.e., the boundary is parallel to the
1090 * y-axis. The y-coordinate is descending from 1 to -1.
1094 * vertices[index] = xCoord;
1096 * vertices[index] = 1 - deltaY * i;
1101 * Pass the vertices to preCICE
1104 * precice.setMeshVertices(meshID,
1107 * vertexIDs.data());
1111 * initialize the Solverinterface
1114 * double dt = precice.initialize();
1121 * const double end_time = 1;
1123 * while (precice.isCouplingOngoing())
1127 * Generate new boundary data
1130 * define_boundary_values(writeData, time, end_time);
1133 * std::cout << "Boundary participant: writing coupling data \n";
1134 * precice.writeBlockScalarData(dataID,
1137 * writeData.data());
1140 * dt = precice.advance(dt);
1141 * std::cout << "Boundary participant: advancing in time\n";
1146 * std::cout << "Boundary participant: closing...\n";
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternType &sparsity_pattern, const AffineConstraints< number > &constraints=AffineConstraints< number >(), const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation