15#ifdef MFEM_USE_MOONOLITH
23#include "moonolith_bounding_volume_with_span.hpp"
24#include "moonolith_n_tree_mutator_factory.hpp"
25#include "moonolith_n_tree_with_span_mutator_factory.hpp"
26#include "moonolith_n_tree_with_tags_mutator_factory.hpp"
27#include "moonolith_profiler.hpp"
28#include "moonolith_redistribute.hpp"
29#include "moonolith_sparse_matrix.hpp"
30#include "moonolith_tree.hpp"
31#include "par_moonolith.hpp"
35using namespace mfem::internal;
37static const bool dof_transformation =
false;
42struct ParMortarAssembler::Impl
46 std::shared_ptr<ParFiniteElementSpace> source;
47 std::shared_ptr<ParFiniteElementSpace> destination;
48 std::vector<std::shared_ptr<MortarIntegrator>> integrators;
50 std::shared_ptr<HypreParMatrix> coupling_matrix;
51 std::shared_ptr<HypreParMatrix> mass_matrix;
53 std::shared_ptr<IterativeSolver> solver;
57 bool assemble_mass_and_coupling_together{
true};
63 solver = std::make_shared<BiCGSTABSolver>(comm);
64 solver->SetMaxIter(20000);
65 solver->SetRelTol(1e-6);
71 assert(!integrators.empty());
72 return integrators[0]->newBFormIntegrator();
79 const std::shared_ptr<IterativeSolver> &solver)
81 impl_->solver = solver;
86 impl_->assemble_mass_and_coupling_together = value;
90 const int max_solver_iterations)
92 impl_->ensure_solver();
94 impl_->solver->SetMaxIter(max_solver_iterations);
98 const std::shared_ptr<MortarIntegrator> &integrator)
100 impl_->integrators.push_back(integrator);
105 impl_->verbose = verbose;
108template <
int Dimension>
class ElementAdapter :
public moonolith::Serializable
111 using Bound = moonolith::AABBWithKDOPSpan<Dimension, double>;
112 using Point = moonolith::Vector<double, Dimension>;
114 inline int tag()
const {
return tag_; }
116 const Bound &bound()
const {
return bound_; }
118 Bound &bound() {
return bound_; }
120 void applyRW(moonolith::Stream &stream)
124 stream &element_handle_;
128 const long element_handle,
const int tag)
129 : fe_(&fe), element_(element), element_handle_(element_handle), tag_(tag),
132 assert(element < fe.
GetNE());
138 for (
int j = 0; j <
pts.Width(); ++j)
140 for (
int i = 0; i <
pts.Height(); ++i)
142 p[i] =
pts.Elem(i, j);
145 bound_.static_bound() +=
p;
146 bound_.dynamic_bound() +=
p;
151 : fe_(nullptr), element_(-1), element_handle_(-1), tag_(-1),
154 inline long handle()
const {
return element_handle_; }
156 inline long element()
const {
return element_; }
161 assert(element_ < fe_->GetNE());
162 return *fe_->
GetFE(element_);
171 void set_dof_map(std::vector<long> *ptr) { dof_map_ = ptr; }
173 void get_elements_vdofs(
Array<int> &vdofs)
const
179 assert(dof_map_->size() == vdofs.
Size());
181 for (
int i = 0; i < vdofs.
Size(); ++i)
183 vdofs[i] = dof_map_->at(i);
196 long element_handle_;
199 std::vector<long> *dof_map_;
202template <
int _Dimension>
class TreeTraits
205 enum { Dimension = _Dimension };
207 using Bound = moonolith::AABBWithKDOPSpan<Dimension, double>;
208 using DataType = mfem::ElementAdapter<Dimension>;
211template <
int Dimension>
212class MFEMTree :
public moonolith::Tree<TreeTraits<Dimension>>
215 using Traits = mfem::TreeTraits<Dimension>;
219 static std::shared_ptr<MFEMTree>
220 New(
const int maxElementsXNode = moonolith::DEFAULT_REFINE_MAX_ELEMENTS,
221 const int maxDepth = moonolith::DEFAULT_REFINE_DEPTH)
223 using namespace moonolith;
225 std::shared_ptr<MFEMTree> tree = std::make_shared<MFEMTree>();
226 std::shared_ptr<NTreeWithSpanMutatorFactory<MFEMTree>> factory =
227 std::make_shared<NTreeWithSpanMutatorFactory<MFEMTree>>();
228 factory->set_refine_params(maxElementsXNode, maxDepth);
229 tree->set_mutator_factory(factory);
233 static std::shared_ptr<MFEMTree>
234 New(
const std::shared_ptr<moonolith::Predicate> &predicate,
235 const int maxElementsXNode = moonolith::DEFAULT_REFINE_MAX_ELEMENTS,
236 const int maxDepth = moonolith::DEFAULT_REFINE_DEPTH)
238 using namespace moonolith;
242 return New(maxElementsXNode, maxDepth);
245 std::shared_ptr<MFEMTree> tree = std::make_shared<MFEMTree>();
246 std::shared_ptr<NTreeWithTagsMutatorFactory<MFEMTree>> factory =
247 std::make_shared<NTreeWithTagsMutatorFactory<MFEMTree>>(predicate);
248 factory->set_refine_params(maxElementsXNode, maxDepth);
249 tree->set_mutator_factory(factory);
254class ElementDofMap :
public moonolith::Serializable
257 void read(moonolith::InputStream &is)
override
262 is.read(&global[0], n);
265 void write(moonolith::OutputStream &os)
const override
267 int n = global.size();
269 os.write(&global[0], n);
272 std::vector<long> global;
278 explicit Spaces(
const moonolith::Communicator &comm) : comm(comm)
280 must_destroy_attached[0] =
false;
281 must_destroy_attached[1] =
false;
284 Spaces(
const std::shared_ptr<ParFiniteElementSpace> &
source,
285 const std::shared_ptr<ParFiniteElementSpace> &destination)
288 spaces_.push_back(
source);
289 spaces_.push_back(destination);
291 must_destroy_attached[0] =
false;
292 must_destroy_attached[1] =
false;
294 copy_global_dofs(*
source, dof_maps_[0]);
295 copy_global_dofs(*destination, dof_maps_[1]);
303 for (
int i = 0; i < spaces_.size(); ++i)
305 if (spaces_[i] && must_destroy_attached[0])
307 m = spaces_[i]->GetMesh();
311 spaces_[i] = std::shared_ptr<FiniteElementSpace>();
319 inline long n_elements()
const
322 for (
auto s : spaces_)
333 inline std::vector<std::shared_ptr<FiniteElementSpace>> &spaces()
338 inline const std::vector<std::shared_ptr<FiniteElementSpace>> &
344 inline std::vector<ElementDofMap> &dof_map(
const int i)
351 inline const std::vector<ElementDofMap> &dof_map(
const int i)
const
358 inline void set_must_destroy_attached(
const int index,
const bool value)
362 must_destroy_attached[
index] = value;
366 std::vector<std::shared_ptr<FiniteElementSpace>> spaces_;
367 moonolith::Communicator comm;
368 std::vector<ElementDofMap> dof_maps_[2];
369 bool must_destroy_attached[2];
372 std::vector<ElementDofMap> &dof_map)
375 dof_map.resize(fe.
GetNE());
377 for (
int i = 0; i < fe.
GetNE(); ++i)
381 for (
int k = 0; k < vdofs.
Size(); ++k)
393 dof_map[i].global.push_back(g_dof);
399template <
class Iterator>
400static void write_space(
const Iterator &begin,
const Iterator &end,
402 const std::vector<ElementDofMap> &dof_map,
403 const int role, moonolith::OutputStream &os)
405 const int dim =
space.GetMesh()->Dimension();
406 const long n_elements = std::distance(begin, end);
408 std::set<long> nodeIds;
409 std::map<long, long> mapping;
412 for (Iterator it = begin; it != end; ++it)
415 space.GetElementVertices(i, verts);
417 for (
int j = 0; j < verts.
Size(); ++j)
419 nodeIds.insert(verts[j]);
423 long n_nodes = nodeIds.size();
426 os.request_space((n_elements * 8 + n_nodes *
dim) *
427 (
sizeof(
double) +
sizeof(
long)));
429 auto fe_coll =
space.FEColl();
430 const char *name = fe_coll->Name();
431 const int name_lenght = strlen(name);
435 os.write(name, name_lenght);
438 for (
auto nodeId : nodeIds)
440 mapping[nodeId] =
index++;
449 for (
auto node_id : nodeIds)
451 double *v =
space.GetMesh()->GetVertex(node_id);
452 for (
int i = 0; i <
dim; ++i)
459 for (Iterator it = begin; it != end; ++it)
462 space.GetElementVertices(k, verts);
464 const int attribute =
space.GetAttribute(k);
465 const int e_n_nodes = verts.
Size();
466 const int type =
space.GetElementType(k);
467 const int order =
space.GetOrder(k);
470 os <<
type << attribute << order << e_n_nodes;
472 for (
int i = 0; i < e_n_nodes; ++i)
474 auto it = mapping.find(verts[i]);
475 assert(it != mapping.end());
477 int index = it->second;
488template <
class Iterator>
489static void write_element_selection(
const Iterator &begin,
const Iterator &end,
490 const Spaces &spaces,
491 moonolith::OutputStream &os)
493 if (spaces.spaces().empty())
499 auto m = spaces.spaces()[0];
500 std::shared_ptr<FiniteElementSpace> s =
nullptr;
502 if (spaces.spaces().size() > 1)
504 s = spaces.spaces()[1];
507 std::vector<long> source_selection;
508 std::vector<long> destination_selection;
510 bool met_destination_selection =
false;
512 for (Iterator it = begin; it != end; ++it)
519 destination_selection.push_back(
index);
523 met_destination_selection =
true;
524 destination_selection.push_back(
index);
528 assert(!met_destination_selection);
530 source_selection.push_back(
index);
534 const bool has_source = !source_selection.empty();
535 const bool has_destination = !destination_selection.empty();
537 os << has_source << has_destination;
541 write_space(source_selection.begin(), source_selection.end(), *m,
542 spaces.dof_map(0), 0, os);
547 write_space(destination_selection.begin(), destination_selection.end(), *s,
548 spaces.dof_map(1), 1, os);
557static void read_space(moonolith::InputStream &is,
559 std::shared_ptr<FiniteElementSpace> &
space,
560 std::vector<ElementDofMap> &dof_map)
565 int dim, role, name_lenght;
569 std::string name(name_lenght, 0);
570 is.read(&name[0], name_lenght);
580 auto fe_coll = FECollFromName(name);
581 auto mesh_ptr =
new Mesh(
dim, n_nodes, n_elements);
583 for (
long i = 0; i < n_nodes; ++i)
586 for (
int i = 0; i <
dim; ++i)
592 mesh_ptr->AddVertex(v);
595 dof_map.resize(n_elements);
596 std::vector<int> e2v;
597 for (
long i = 0; i < n_elements; ++i)
600 int type, attribute, order, e_n_nodes;
601 is >>
type >> attribute >> order >> e_n_nodes;
602 e2v.resize(e_n_nodes);
604 for (
int i = 0; i < e_n_nodes; ++i)
611 mesh_ptr->AddElement(NewElem(type, &e2v[0], attribute));
617 Finalize(*mesh_ptr,
true);
620 space = make_shared<FiniteElementSpace>(mesh_ptr, fe_coll, vdim);
623static void read_spaces(moonolith::InputStream &is,
const int vdim,
626 bool has_source, has_destination;
627 is >> has_source >> has_destination;
629 spaces.spaces().resize(2);
633 read_space(is, vdim, spaces.spaces()[0], spaces.dof_map(0));
634 spaces.set_must_destroy_attached(0,
true);
638 spaces.spaces()[0] =
nullptr;
643 read_space(is, vdim, spaces.spaces()[1], spaces.dof_map(1));
644 spaces.set_must_destroy_attached(1,
true);
648 spaces.spaces()[1] =
nullptr;
652template <
int Dimensions,
class Fun>
653static bool Assemble(moonolith::Communicator &comm,
654 std::shared_ptr<ParFiniteElementSpace> &
source,
655 std::shared_ptr<ParFiniteElementSpace> &destination,
656 Fun process_fun,
const moonolith::SearchSettings &settings,
659 using namespace moonolith;
661 typedef mfem::MFEMTree<Dimensions> NTreeT;
662 typedef typename NTreeT::DataContainer DataContainer;
663 typedef typename NTreeT::DataType Adapter;
665 long maxNElements = settings.max_elements;
666 long maxDepth = settings.max_depth;
668 const int n_elements_source =
source->GetNE();
669 const int n_elements_destination = destination->GetNE();
670 const int n_elements = n_elements_source + n_elements_destination;
672 auto predicate = std::make_shared<MasterAndSlave>();
673 predicate->add(0, 1);
675 MOONOLITH_EVENT_BEGIN(
"create_adapters");
677 std::shared_ptr<NTreeT> tree = NTreeT::New(predicate, maxNElements, maxDepth);
678 tree->reserve(n_elements);
680 std::shared_ptr<Spaces> local_spaces =
681 std::make_shared<Spaces>(
source, destination);
686 for (
auto s : local_spaces->spaces())
690 for (
int i = 0; i < s->GetNE(); ++i)
692 Adapter
a(*s, i, offset + i, space_num);
693 a.set_dof_map(&local_spaces->dof_map(space_num)[i].global);
697 offset += s->GetNE();
703 tree->root()->bound().static_bound().enlarge(1e-6);
705 MOONOLITH_EVENT_END(
"create_adapters");
708 std::map<long, std::shared_ptr<Spaces>> spaces;
709 std::map<long, std::vector<std::shared_ptr<Spaces>>> migrated_spaces;
711 auto read = [&spaces, &migrated_spaces, &
source,
712 comm](
const long ownerrank,
const long ,
713 bool is_forwarding, DataContainer &data, InputStream &in)
715 CHECK_STREAM_READ_BEGIN(
"vol_proj", in);
717 std::shared_ptr<Spaces> proc_space = std::make_shared<Spaces>(comm);
719 read_spaces(in,
source->GetVDim(), *proc_space);
723 assert(!spaces[ownerrank]);
724 spaces[ownerrank] = proc_space;
728 migrated_spaces[ownerrank].push_back(proc_space);
731 data.reserve(data.size() + proc_space->n_elements());
735 for (
auto s : proc_space->spaces())
739 for (
int i = 0; i < s->GetNE(); ++i)
741 data.push_back(Adapter(*s, i, offset + i, space_num));
742 data.back().set_dof_map(&proc_space->dof_map(space_num)[i].global);
745 offset += s->GetNE();
751 CHECK_STREAM_READ_END(
"vol_proj", in);
754 auto write = [&local_spaces, &spaces,
755 &comm](
const long ownerrank,
const long ,
756 const std::vector<long>::const_iterator &begin,
757 const std::vector<long>::const_iterator &end,
758 const DataContainer & , OutputStream &
out)
760 CHECK_STREAM_WRITE_BEGIN(
"vol_proj",
out);
762 if (ownerrank == comm.rank())
764 write_element_selection(begin, end, *local_spaces,
out);
768 auto it = spaces.find(ownerrank);
769 assert(it != spaces.end());
770 std::shared_ptr<Spaces> spaceptr = it->second;
771 assert(std::distance(begin, end) > 0);
772 write_element_selection(begin, end, *spaceptr,
out);
775 CHECK_STREAM_WRITE_END(
"vol_proj",
out);
778 long n_false_positives = 0, n_intersections = 0;
779 auto fun = [&n_false_positives, &n_intersections,
780 &process_fun](Adapter &
source, Adapter &destination) ->
bool
782 bool ok = process_fun(
source, destination);
798 moonolith::search_and_compute(comm, tree, predicate,
read,
write, fun,
803 long n_total_candidates = n_intersections + n_false_positives;
805 long n_collection[3] = {n_intersections, n_total_candidates,
808 comm.all_reduce(n_collection, 3, moonolith::MPISum());
812 mfem::out <<
"n_intersections: " << n_collection[0]
813 <<
", n_total_candidates: " << n_collection[1]
814 <<
", n_false_positives: " << n_collection[2] << std::endl;
821static void add_matrix(
const Array<int> &destination_vdofs,
824 moonolith::SparseMatrix<double> &mat_buffer)
827 for (
int i = 0; i < destination_vdofs.
Size(); ++i)
829 long dof_I = destination_vdofs[i];
839 for (
int j = 0; j < source_vdofs.
Size(); ++j)
841 long dof_J = source_vdofs[j];
843 double sign_J = sign_I;
851 mat_buffer.add(dof_I, dof_J, sign_J * elem_mat.
Elem(i, j));
857 const std::vector<moonolith::Integer> &destination_ranges,
860 moonolith::SparseMatrix<double> &mat_buffer)
863 auto &&comm = mat_buffer.comm();
865 moonolith::Redistribute<moonolith::SparseMatrix<double>> redist(comm.get());
866 redist.apply(destination_ranges, mat_buffer, moonolith::AddAssign<double>());
868 std::vector<int> I(s_offsets[1] - s_offsets[0] + 1);
871 std::vector<HYPRE_Int> J;
872 std::vector<double> data;
873 J.reserve(mat_buffer.n_local_entries());
874 data.reserve(J.capacity());
876 for (
auto it = mat_buffer.iter(); it; ++it)
878 I[it.row() - s_offsets[0] + 1]++;
879 J.push_back(it.col());
883 for (
int i = 1; i < I.size(); ++i)
888 auto ret = std::make_shared<HypreParMatrix>(
889 comm.get(), s_offsets[1] - s_offsets[0], mat_buffer.rows(),
890 mat_buffer.cols(), &I[0], &J[0], &data[0], s_offsets, m_offsets);
901template <
int Dimensions>
903Assemble(moonolith::Communicator &comm, ParMortarAssembler::Impl &impl,
904 const moonolith::SearchSettings &settings,
const bool verbose)
906 auto &
source = impl.source;
907 auto &destination = impl.destination;
909 auto &integrators = impl.integrators;
910 auto &pmat = impl.coupling_matrix;
912 bool lump_mass =
false;
915 for (
auto i_ptr : integrators)
917 max_q_order = std::max(i_ptr->GetQuadratureOrder(), max_q_order);
920 const int dim =
source->GetMesh()->Dimension();
924 assert(
false &&
"NOT Supported!");
937 const HYPRE_BigInt s_global_n_dofs = destination->GlobalTrueVSize();
938 HYPRE_BigInt *s_offsets = destination->GetTrueDofOffsets();
940 double local_element_matrices_sum = 0.0;
942 moonolith::SparseMatrix<double> mat_buffer(comm);
943 mat_buffer.set_size(s_global_n_dofs, m_global_n_dofs);
945 moonolith::SparseMatrix<double> mass_mat_buffer(comm);
946 mass_mat_buffer.set_size(s_global_n_dofs, s_global_n_dofs);
948 std::unique_ptr<BilinearFormIntegrator> mass_integr(
949 impl.newBFormIntegrator());
951 auto fun = [&](
const ElementAdapter<Dimensions> &
source,
952 const ElementAdapter<Dimensions> &destination) ->
bool
954 const auto &src =
source.space();
955 const auto &dest = destination.space();
957 const int src_index =
source.element();
958 const int dest_index = destination.element();
960 auto &src_fe = *src.GetFE(src_index);
961 auto &dest_fe = *dest.GetFE(dest_index);
964 *dest.GetElementTransformation(dest_index);
971 const int src_order = src_order_mult * src_fe.GetOrder();
972 const int dest_order = dest_order_mult * dest_fe.GetOrder();
974 int contraction_order = src_order + dest_order;
975 if (impl.assemble_mass_and_coupling_together)
977 contraction_order = std::max(contraction_order, 2 * dest_order);
981 contraction_order + dest_order_mult * dest_Trans.
OrderW() + max_q_order;
983 cut->SetIntegrationOrder(order);
985 if (cut->BuildQuadrature(src, src_index, dest, dest_index, src_ir,
990 *src.GetElementTransformation(src_index);
992 source.get_elements_vdofs(source_vdofs);
993 destination.get_elements_vdofs(destination_vdofs);
996 for (
auto i_ptr : integrators)
1000 i_ptr->AssembleElementMatrix(src_fe, src_ir, src_Trans, dest_fe,
1001 dest_ir, dest_Trans, cumulative_elemmat);
1006 i_ptr->AssembleElementMatrix(src_fe, src_ir, src_Trans, dest_fe,
1007 dest_ir, dest_Trans, elemmat);
1008 cumulative_elemmat += elemmat;
1012 local_element_matrices_sum += Sum(cumulative_elemmat);
1013 add_matrix(destination_vdofs, source_vdofs, cumulative_elemmat,
1016 if (impl.assemble_mass_and_coupling_together)
1018 mass_integr->SetIntRule(&dest_ir);
1019 mass_integr->AssembleElementMatrix(dest_fe, dest_Trans, elemmat);
1023 int n = destination_vdofs.
Size();
1025 for (
int i = 0; i < n; ++i)
1027 double row_sum = 0.;
1028 for (
int j = 0; j < n; ++j)
1030 row_sum += elemmat(i, j);
1034 elemmat(i, i) = row_sum;
1038 add_matrix(destination_vdofs, destination_vdofs, elemmat,
1050 if (!Assemble<Dimensions>(comm,
source, destination, fun, settings,
1058 double volumes[2] = {local_element_matrices_sum};
1059 comm.all_reduce(volumes, 2, moonolith::MPISum());
1065 mfem::out <<
"sum(B): " << volumes[0] << std::endl;
1069 std::vector<moonolith::Integer> destination_ranges(comm.size() + 1, 0);
1071 std::copy(s_offsets, s_offsets + 2, destination_ranges.begin() + comm.rank());
1072 comm.all_reduce(&destination_ranges[0], destination_ranges.size(),
1073 moonolith::MPIMax());
1078 if (impl.assemble_mass_and_coupling_together)
1081 s_offsets, mass_mat_buffer);
1088 const std::shared_ptr<ParFiniteElementSpace> &
source,
1089 const std::shared_ptr<ParFiniteElementSpace> &destination)
1092 impl_->comm =
source->GetComm();
1094 impl_->destination = destination;
1099 assert(!impl_->integrators.empty() &&
1100 "it must have at least on integrator see class MortarIntegrator");
1102 moonolith::SearchSettings settings;
1108 moonolith::Communicator comm(impl_->comm);
1109 if (impl_->source->GetMesh()->Dimension() == 2)
1111 ok = mfem::Assemble<2>(comm, *impl_, settings, impl_->verbose);
1114 if (impl_->source->GetMesh()->Dimension() == 3)
1116 ok = mfem::Assemble<3>(comm, *impl_, settings, impl_->verbose);
1119 pmat = impl_->coupling_matrix;
1133 const bool verbose = impl_->verbose;
1135 if (!impl_->coupling_matrix)
1143 auto &B = *impl_->coupling_matrix;
1144 auto &D = *impl_->mass_matrix;
1145 auto &P_destination = *impl_->destination->GetProlongationMatrix();
1147 impl_->ensure_solver();
1152 impl_->solver->SetOperator(D);
1156 impl_->solver->SetPrintLevel(3);
1159 if (dof_transformation)
1163 Vector P_x_src_fun(B.Width());
1164 auto &P_source = *impl_->source->GetProlongationMatrix();
1165 P_source.MultTranspose(src_fun, P_x_src_fun);
1167 Vector B_x_src_fun(B.Height());
1170 B.Mult(P_x_src_fun, B_x_src_fun);
1172 Vector R_x_dest_fun(D.Height());
1175 impl_->solver->Mult(B_x_src_fun, R_x_dest_fun);
1177 P_destination.Mult(R_x_dest_fun, dest_fun);
1184 std::unique_ptr<HypreParVector> td_src_fun =
1187 Vector B_x_src_fun(B.Height());
1189 B.Mult(*td_src_fun, B_x_src_fun);
1192 Vector R_x_dest_fun(D.Height());
1194 impl_->solver->Mult(B_x_src_fun, R_x_dest_fun);
1196 P_destination.Mult(R_x_dest_fun, dest_fun);
1201 int converged = impl_->solver->GetFinalNorm() < 1e-5;
1202 MPI_Allreduce(MPI_IN_PLACE, &converged, 1, MPI_INT, MPI_MIN, impl_->comm);
1208 using namespace std;
1209 const bool verbose = impl_->verbose;
1211 moonolith::Communicator comm(impl_->comm);
1216 moonolith::root_describe(
1217 "--------------------------------------------------------"
1218 "\nAssembly begin: ",
1222 if (!
Assemble(impl_->coupling_matrix))
1229 moonolith::root_describe(
1231 "--------------------------------------------------------",
1235 if (dof_transformation)
1237 impl_->coupling_matrix.reset(
RAP(impl_->destination->Dof_TrueDof_Matrix(),
1238 impl_->coupling_matrix.get(),
1239 impl_->source->Dof_TrueDof_Matrix()));
1242 auto &B = *impl_->coupling_matrix;
1244 if (!impl_->assemble_mass_and_coupling_together)
1250 impl_->mass_matrix = shared_ptr<HypreParMatrix>(b_form.
ParallelAssemble());
1255 if (verbose && comm.is_root())
1257 mfem::out <<
"P in R^(" << impl_->source->Dof_TrueDof_Matrix()->Height();
1258 mfem::out <<
" x " << impl_->source->Dof_TrueDof_Matrix()->Width() <<
")\n";
1260 << impl_->destination->Dof_TrueDof_Matrix()->Height();
1261 mfem::out <<
" x " << impl_->destination->Dof_TrueDof_Matrix()->Width()
1265 if (dof_transformation && impl_->assemble_mass_and_coupling_together)
1267 impl_->mass_matrix.reset(
RAP(impl_->destination->Dof_TrueDof_Matrix(),
1268 impl_->mass_matrix.get(),
1269 impl_->destination->Dof_TrueDof_Matrix()));
1272 auto &D = *impl_->mass_matrix;
1276 if (verbose && comm.is_root())
1278 mfem::out <<
"--------------------------------------------------------"
1280 mfem::out <<
"B in R^(" << B.GetGlobalNumRows() <<
" x "
1281 << B.GetGlobalNumCols() <<
")" << std::endl;
1282 mfem::out <<
"D in R^(" << D.GetGlobalNumRows() <<
" x "
1283 << D.GetGlobalNumCols() <<
")" << std::endl;
1284 mfem::out <<
"--------------------------------------------------------"
1298 double sum_Dv = Dv.
Sum();
1299 comm.all_reduce(&sum_Dv, 1, MPI_SUM);
1303 mfem::out <<
"sum(D): " << sum_Dv << std::endl;
int Size() const
Return the logical size of the array.
Data type dense matrix using column-major storage.
real_t & Elem(int i, int j) override
Returns reference to a_{ij}.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
int GetNE() const
Returns number of elements in the mesh.
Mesh * GetMesh() const
Returns the mesh.
Abstract class for all finite elements.
Class for an integration rule - an Array of IntegrationPoint.
int GetNE() const
Returns number of elements.
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Abstract parallel finite element space.
HYPRE_BigInt GetGlobalTDofNumber(int ldof) const
Returns the global tdof number of the given local degree of freedom.
Class for parallel grid function.
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
bool Apply(const ParGridFunction &src_fun, ParGridFunction &dest_fun)
transfer a function from source to destination. It requires that the Update function is called before
void SetSolver(const std::shared_ptr< IterativeSolver > &solver)
Changes the solver to be used for solving the mass-matrix linear system.
void SetMaxSolverIterations(const int max_solver_iterations)
Control the maximum numbers of conjugate gradients steps for mass matrix inversion.
bool Assemble(std::shared_ptr< HypreParMatrix > &B)
assembles the coupling matrix B. B : source -> destination If u is a coefficient associated with sour...
ParMortarAssembler(const std::shared_ptr< ParFiniteElementSpace > &source, const std::shared_ptr< ParFiniteElementSpace > &destination)
constructs the object with source and destination spaces
void SetAssembleMassAndCouplingTogether(const bool value)
Control if the Mass matrix is computed together with the coupling operator every time.
bool Transfer(const ParGridFunction &src_fun, ParGridFunction &dest_fun)
transfer a function from source to destination. if the transfer is to be performed multiple times use...
void SetVerbose(const bool verbose)
Expose process details with verbose output.
void AddMortarIntegrator(const std::shared_ptr< MortarIntegrator > &integrator)
This method must be called before Assemble or Transfer. It will assemble the operator in all intersec...
bool Update()
assembles the various components necessary for the transfer. To be called before calling the Apply fu...
real_t Sum() const
Return the sum of the vector entries.
void source(const Vector &x, Vector &f)
int index(int i, int j, int nx, int ny)
void write(std::ostream &os, T value)
Write 'value' to stream.
T read(std::istream &is)
Read a value from the stream and return it.
MFEM_HOST_DEVICE constexpr auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
std::shared_ptr< Cut > NewCut(const int dim)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
int order_multiplier(const Geometry::Type type, const int dim)
std::shared_ptr< HypreParMatrix > convert_to_hypre_matrix(const std::vector< moonolith::Integer > &destination_ranges, HYPRE_BigInt *s_offsets, HYPRE_BigInt *m_offsets, moonolith::SparseMatrix< double > &mat_buffer)
real_t p(const Vector &x, real_t t)
void pts(int iphi, int t, real_t x[])