Reference documentation for deal.II version 9.4.1
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
coupled_laplace_problem.h
Go to the documentation of this file.
1) const
652 * {
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);
656 *
657 * return return_value;
658 * }
659 *
660 *
661 * template <int dim>
662 * double
663 * BoundaryValues<dim>::value(const Point<dim> &p,
664 * const unsigned int /*component*/) const
665 * {
666 * return p.square();
667 * }
668 *
669 *
670 *
671 * template <int dim>
672 * CoupledLaplaceProblem<dim>::CoupledLaplaceProblem()
673 * : fe(1)
674 * , dof_handler(triangulation)
675 * , interface_boundary_id(1)
676 * , adapter(parameters, interface_boundary_id)
677 * {}
678 *
679 *
680 * template <int dim>
681 * void
682 * CoupledLaplaceProblem<dim>::make_grid()
683 * {
685 * triangulation.refine_global(4);
686 *
687 * for (const auto &cell : triangulation.active_cell_iterators())
688 * for (const auto face : cell->face_iterators())
689 * {
690 * @endcode
691 *
692 * We choose the boundary in positive x direction for the
693 * interface coupling.
694 *
695 * @code
696 * if (face->at_boundary() && (face->center()[0] == 1))
697 * face->set_boundary_id(interface_boundary_id);
698 * }
699 *
700 * std::cout << " Number of active cells: " << triangulation.n_active_cells()
701 * << std::endl
702 * << " Total number of cells: " << triangulation.n_cells()
703 * << std::endl;
704 * }
705 *
706 *
707 * template <int dim>
708 * void
709 * CoupledLaplaceProblem<dim>::setup_system()
710 * {
711 * dof_handler.distribute_dofs(fe);
712 *
713 * std::cout << " Number of degrees of freedom: " << dof_handler.n_dofs()
714 * << std::endl;
715 *
716 * DynamicSparsityPattern dsp(dof_handler.n_dofs());
717 * DoFTools::make_sparsity_pattern(dof_handler, dsp);
718 * sparsity_pattern.copy_from(dsp);
719 *
720 * system_matrix.reinit(sparsity_pattern);
721 *
722 * solution.reinit(dof_handler.n_dofs());
723 * old_solution.reinit(dof_handler.n_dofs());
724 * system_rhs.reinit(dof_handler.n_dofs());
725 * }
726 *
727 *
728 *
729 * template <int dim>
730 * void
731 * CoupledLaplaceProblem<dim>::assemble_system()
732 * {
733 * @endcode
734 *
735 * Reset global structures
736 *
737 * @code
738 * system_rhs = 0;
739 * system_matrix = 0;
740 * @endcode
741 *
742 * Update old solution values
743 *
744 * @code
745 * old_solution = solution;
746 *
747 * QGauss<dim> quadrature_formula(fe.degree + 1);
748 *
749 * RightHandSide<dim> right_hand_side;
750 *
751 * FEValues<dim> fe_values(fe,
752 * quadrature_formula,
755 *
756 * const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
757 *
758 * FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
759 * Vector<double> cell_rhs(dofs_per_cell);
760 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
761 * @endcode
762 *
763 * The solution values from previous time steps are stored for each quadrature
764 * point
765 *
766 * @code
767 * std::vector<double> local_values_old_solution(fe_values.n_quadrature_points);
768 *
769 * for (const auto &cell : dof_handler.active_cell_iterators())
770 * {
771 * fe_values.reinit(cell);
772 * cell_matrix = 0;
773 * cell_rhs = 0;
774 * @endcode
775 *
776 * Get the local values from the `fe_values' object
777 *
778 * @code
779 * fe_values.get_function_values(old_solution, local_values_old_solution);
780 *
781 * @endcode
782 *
783 * The system matrix contains additionally a mass matrix due to the time
784 * discretization. The RHS has contributions from the old solution values.
785 *
786 * @code
787 * for (const unsigned int q_index : fe_values.quadrature_point_indices())
788 * for (const unsigned int i : fe_values.dof_indices())
789 * {
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
798 *
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
807 * }
808 *
809 * @endcode
810 *
811 * Copy local to global
812 *
813 * @code
814 * cell->get_dof_indices(local_dof_indices);
815 * for (const unsigned int i : fe_values.dof_indices())
816 * {
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));
821 *
822 * system_rhs(local_dof_indices[i]) += cell_rhs(i);
823 * }
824 * }
825 * {
826 * @endcode
827 *
828 * At first, we apply the Dirichlet boundary condition from @ref step_4 "step-4", as
829 * usual.
830 *
831 * @code
832 * std::map<types::global_dof_index, double> boundary_values;
833 * VectorTools::interpolate_boundary_values(dof_handler,
834 * 0,
835 * BoundaryValues<dim>(),
836 * boundary_values);
837 * MatrixTools::apply_boundary_values(boundary_values,
838 * system_matrix,
839 * solution,
840 * system_rhs);
841 * }
842 * {
843 * @endcode
844 *
845 * Afterwards, we apply the coupling boundary condition. The `boundary_data`
846 * has already been filled by preCICE.
847 *
848 * @code
849 * MatrixTools::apply_boundary_values(boundary_data,
850 * system_matrix,
851 * solution,
852 * system_rhs);
853 * }
854 * }
855 *
856 *
857 *
858 * template <int dim>
859 * void
860 * CoupledLaplaceProblem<dim>::solve()
861 * {
862 * SolverControl solver_control(1000, 1e-12);
863 * SolverCG<Vector<double>> solver(solver_control);
864 * solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity());
865 *
866 * std::cout << " " << solver_control.last_step()
867 * << " CG iterations needed to obtain convergence." << std::endl;
868 * }
869 *
870 *
871 *
872 * template <int dim>
873 * void
874 * CoupledLaplaceProblem<dim>::output_results() const
875 * {
876 * DataOut<dim> data_out;
877 *
878 * data_out.attach_dof_handler(dof_handler);
879 * data_out.add_data_vector(solution, "solution");
880 *
881 * data_out.build_patches(mapping);
882 *
883 * std::ofstream output("solution-" + std::to_string(time_step) + ".vtk");
884 * data_out.write_vtk(output);
885 * }
886 *
887 *
888 *
889 * template <int dim>
890 * void
891 * CoupledLaplaceProblem<dim>::run()
892 * {
893 * std::cout << "Solving problem in " << dim << " space dimensions."
894 * << std::endl;
895 *
896 * make_grid();
897 * setup_system();
898 *
899 * @endcode
900 *
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.
904 *
905 * @code
906 * precice_delta_t = adapter.initialize(dof_handler, boundary_data, mapping);
907 * delta_t = std::min(precice_delta_t, solver_delta_t);
908 *
909 * @endcode
910 *
911 * preCICE steers the coupled simulation: `isCouplingOngoing` is
912 * used to synchronize the end of the simulation with the coupling partner
913 *
914 * @code
915 * while (adapter.precice.isCouplingOngoing())
916 * {
917 * @endcode
918 *
919 * The time step number is solely used to generate unique output files
920 *
921 * @code
922 * ++time_step;
923 * @endcode
924 *
925 * In the time loop, we assemble the coupled system and solve it as
926 * usual.
927 *
928 * @code
929 * assemble_system();
930 * solve();
931 *
932 * @endcode
933 *
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.
940 *
941 * @code
942 * precice_delta_t = adapter.advance(boundary_data, delta_t);
943 * delta_t = std::min(precice_delta_t, solver_delta_t);
944 *
945 * @endcode
946 *
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`.
952 *
953 * @code
954 * if (adapter.precice.isTimeWindowComplete())
955 * output_results();
956 * }
957 * }
958 *
959 *
960 *
961 * int
962 * main()
963 * {
964 * CoupledLaplaceProblem<2> laplace_problem;
965 * laplace_problem.run();
966 *
967 * return 0;
968 * }
969 * @endcode
970
971
972<a name="ann-fancy_boundary_condition.cc"></a>
973<h1>Annotated version of fancy_boundary_condition.cc</h1>
974 *
975 *
976 *
977 * This program does not use any deal.II functionality and depends only on
978 * preCICE and the standard libraries.
979 *
980 * @code
981 * #include <precice/SolverInterface.hpp>
982 *
983 * #include <iostream>
984 * #include <sstream>
985 *
986 * @endcode
987 *
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.
991 *
992
993 *
994 * Function to generate boundary values in each time step
995 *
996 * @code
997 * void
998 * define_boundary_values(std::vector<double> &boundary_data,
999 * const double time,
1000 * const double end_time)
1001 * {
1002 * @endcode
1003 *
1004 * Scale the current time value
1005 *
1006 * @code
1007 * const double relative_time = time / end_time;
1008 * @endcode
1009 *
1010 * Define the amplitude. Values run from -0.5 to 0.5
1011 *
1012 * @code
1013 * const double amplitude = (relative_time - 0.5);
1014 * @endcode
1015 *
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.
1019 *
1020 * @code
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;
1028 * }
1029 *
1030 *
1031 * int
1032 * main()
1033 * {
1034 * std::cout << "Boundary participant: starting... \n";
1035 *
1036 * @endcode
1037 *
1038 * Configuration
1039 *
1040 * @code
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");
1045 *
1046 * @endcode
1047 *
1048 * Adjust to MPI rank and size for parallel computation
1049 *
1050 * @code
1051 * const int commRank = 0;
1052 * const int commSize = 1;
1053 *
1054 * precice::SolverInterface precice(solverName,
1055 * configFileName,
1056 * commRank,
1057 * commSize);
1058 *
1059 * const int meshID = precice.getMeshID(meshName);
1060 * const int dimensions = precice.getDimensions();
1061 * const int numberOfVertices = 6;
1062 *
1063 * const int dataID = precice.getDataID(dataWriteName, meshID);
1064 *
1065 * @endcode
1066 *
1067 * Set up data structures
1068 *
1069 * @code
1070 * std::vector<double> writeData(numberOfVertices);
1071 * std::vector<int> vertexIDs(numberOfVertices);
1072 * std::vector<double> vertices(numberOfVertices * dimensions);
1073 *
1074 * @endcode
1075 *
1076 * Define a boundary mesh
1077 *
1078 * @code
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)
1085 * {
1086 * const unsigned int index = dimensions * i + j;
1087 * @endcode
1088 *
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.
1091 *
1092 * @code
1093 * if (j == 0)
1094 * vertices[index] = xCoord;
1095 * else
1096 * vertices[index] = 1 - deltaY * i;
1097 * }
1098 *
1099 * @endcode
1100 *
1101 * Pass the vertices to preCICE
1102 *
1103 * @code
1104 * precice.setMeshVertices(meshID,
1105 * numberOfVertices,
1106 * vertices.data(),
1107 * vertexIDs.data());
1108 *
1109 * @endcode
1110 *
1111 * initialize the Solverinterface
1112 *
1113 * @code
1114 * double dt = precice.initialize();
1115 *
1116 * @endcode
1117 *
1118 * Start time loop
1119 *
1120 * @code
1121 * const double end_time = 1;
1122 * double time = 0;
1123 * while (precice.isCouplingOngoing())
1124 * {
1125 * @endcode
1126 *
1127 * Generate new boundary data
1128 *
1129 * @code
1130 * define_boundary_values(writeData, time, end_time);
1131 *
1132 * {
1133 * std::cout << "Boundary participant: writing coupling data \n";
1134 * precice.writeBlockScalarData(dataID,
1135 * numberOfVertices,
1136 * vertexIDs.data(),
1137 * writeData.data());
1138 * }
1139 *
1140 * dt = precice.advance(dt);
1141 * std::cout << "Boundary participant: advancing in time\n";
1142 *
1143 * time += dt;
1144 * }
1145 *
1146 * std::cout << "Boundary participant: closing...\n";
1147 *
1148 * return 0;
1149 * }
1150 * @endcode
1151
1152
1153*/
Definition: point.h:111
Definition: vector.h:109
@ 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.)
Definition: advection.h:75
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition: utilities.cc:190
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation