62 .def_property_readonly(
"height", &Operator::Height,
"Get the height (number of rows) of the Operator.")
63 .def_property_readonly(
"width", &Operator::Width,
"Get the width (number of columns) of the Operator.")
70 .def(
"Mult", py::overload_cast<const Vector&, Vector&>(&Operator::Mult, py::const_),
71 py::arg(
"x"), py::arg(
"y"),
"Calculates y = A(x). y must be pre-allocated.")
74 .def(
"Mult", [](
const Operator &op,
const Vector &x) {
75 Vector y(op.Height());
78 }, py::arg(
"x"),
"Calculates and returns a new vector y = A(x).")
81 .def(
"MultTranspose", py::overload_cast<const Vector&, Vector&>(&Operator::MultTranspose, py::const_),
82 py::arg(
"x"), py::arg(
"y"),
"Calculates y = A^T(x). y must be pre-allocated.")
84 .def(
"MultTranspose", [](
const Operator &op,
const Vector &x) {
86 op.MultTranspose(x, y);
88 }, py::arg(
"x"),
"Calculates and returns a new vector y = A^T(x).")
91 .def(
"AddMult", &Operator::AddMult, py::arg(
"x"), py::arg(
"y"), py::arg(
"a") = 1.0,
"Performs y += a * A(x).")
92 .def(
"AddMultTranspose", &Operator::AddMultTranspose, py::arg(
"x"), py::arg(
"y"), py::arg(
"a") = 1.0,
"Performs y += a * A^T(x).")
95 .def(
"AssembleDiagonal", &Operator::AssembleDiagonal, py::arg(
"diag"),
"Assembles the operator diagonal into the given Vector.")
96 .def(
"RecoverFEMSolution", &Operator::RecoverFEMSolution, py::arg(
"X"), py::arg(
"b"), py::arg(
"x"),
"Recovers the full FE solution.")
97 .def(
"GetGradient", &Operator::GetGradient, py::return_value_policy::reference,
"Returns the Gradient of a non-linear operator.")
100 .def(
"GetProlongation", &Operator::GetProlongation, py::return_value_policy::reference,
"Returns the prolongation operator.")
101 .def(
"GetRestriction", &Operator::GetRestriction, py::return_value_policy::reference,
"Returns the restriction operator.")
104 .def(
"__matmul__", [](
const Operator &op,
const Vector &x) {
105 Vector y(op.Height());
108 }, py::is_operator());
112 using namespace mfem;
113 py::class_<Matrix, Operator, serif::pybind::PyMatrix>(mfem_submodule,
"Matrix")
115 .def_property_readonly(
"is_square", &Matrix::IsSquare,
116 "Returns true if the matrix is square.")
118 .def(
"finalize", &Matrix::Finalize, py::arg(
"skip_zeros") = 1,
119 "Finalizes the matrix initialization.")
121 .def(
"inverse", &Matrix::Inverse,
122 "Returns a pointer to (an approximation) of the matrix inverse.",
123 py::return_value_policy::take_ownership)
126 .def(
"__getitem__", [](
const Matrix &m, py::tuple t) {
128 throw py::index_error(
"Matrix index must be a 2-tuple (i, j)");
130 return m.Elem(t[0].cast<int>(), t[1].cast<int>());
134 .def(
"__setitem__", [](Matrix &m, py::tuple t, real_t value) {
136 throw py::index_error(
"Matrix index must be a 2-tuple (i, j)");
138 m.Elem(t[0].cast<int>(), t[1].cast<int>()) = value;
141 .def(
"__repr__", [](
const Matrix &m) {
142 return "<mfem.Matrix (Abstract) " +
143 std::to_string(m.Height()) +
"x" +
144 std::to_string(m.Width()) +
">";
149 using namespace mfem;
151 py::class_<mfem::Vector>(mfem_submodule,
"Vector")
152 .def(py::init<int>(), py::arg(
"size"))
153 .def(py::init<const mfem::Vector &>(), py::arg(
"other"))
154 .def(py::init([](py::array_t<double> arr) {
155 py::buffer_info info = arr.request();
156 if (info.ndim != 1) {
157 throw std::runtime_error(
"Vector(): expected a 1-D numpy array");
159 mfem::Vector v(info.size);
160 std::memcpy(v.GetData(), info.ptr, info.size *
sizeof(
double));
162 }), py::arg(
"array"))
163 .def(
"GetData", &mfem::Vector::GetData, py::return_value_policy::reference_internal)
164 .def(
"Size", &mfem::Vector::Size)
165 .def(
"__getitem__", [](
const mfem::Vector &v,
int i) {
return v[i]; })
166 .def(
"__len__", &mfem::Vector::Size)
167 .def(
"__setitem__", [](mfem::Vector &v,
int i,
double value) { v[i] = value; })
168 .def(
"__repr__", [](
const mfem::Vector &v) {
169 return "<mfem.Vector(size=" + std::to_string(v.Size()) +
")>";
171 .def(
"as_numpy", [](mfem::Vector &self) {
172 return py::array_t<double>(self.Size(), self.GetData());
177 using namespace mfem;
178 py::class_<Array<int>>(mfem_submodule,
"IntArray")
180 .def(py::init<>(),
"Default constructor.")
181 .def(py::init<int>(), py::arg(
"size"),
"Constructor with size.")
182 .def(py::init([](
const std::vector<int> &v) {
183 auto *arr =
new Array<int>(v.size());
184 for (
size_t i = 0; i < v.size(); ++i) {
188 }), py::arg(
"list"),
"Constructor from a Python list.")
191 .def(
"__len__", &Array<int>::Size)
192 .def(
"__getitem__", [](
const Array<int> &self,
int i) {
193 if (i < 0) i += self.Size();
194 if (i < 0 || i >= self.Size())
throw py::index_error();
197 .def(
"__setitem__", [](Array<int> &self,
int i,
int value) {
198 if (i < 0) i += self.Size();
199 if (i < 0 || i >= self.Size())
throw py::index_error();
202 .def(
"__iter__", [](Array<int> &self) {
203 return py::make_iterator(self.begin(), self.end());
204 }, py::keep_alive<0, 1>())
205 .def(
"__repr__", [](
const Array<int> &self) {
206 std::stringstream ss;
208 for (
int i = 0; i < self.Size(); ++i) {
209 ss << self[i] << (i == self.Size() - 1 ?
"" :
", ");
216 .def(
"Size", &Array<int>::Size)
217 .def(
"SetSize", py::overload_cast<int>(&Array<int>::SetSize), py::arg(
"size"))
218 .def(
"Append", py::overload_cast<const int &>(&Array<int>::Append), py::arg(
"el"))
219 .def(
"Last", py::overload_cast<>(&Array<int>::Last, py::const_))
220 .def(
"DeleteLast", &Array<int>::DeleteLast)
221 .def(
"DeleteAll", &Array<int>::DeleteAll)
222 .def(
"Sort", [](Array<int> &self) { self.Sort(); })
223 .def(
"Unique", &Array<int>::Unique)
224 .def(
"Assign", [](Array<int> &self,
const Array<int> &other) {
225 self.Assign(other.GetData());
227 .def(
"as_numpy", [](Array<int> &self) {
229 return py::array_t<int>(self.Size(), self.GetData());
235 using namespace mfem;
242 py::class_<BilinearForm, Matrix>(mfem_submodule,
"BilinearForm")
245 .def(py::init<FiniteElementSpace *>(), py::arg(
"fespace"),
249 py::keep_alive<1, 2>(),
250 "Constructs a bilinear form on the given FiniteElementSpace.")
253 .def(
"SetAssemblyLevel", &BilinearForm::SetAssemblyLevel, py::arg(
"assembly_level"),
254 "Set the assembly level (e.g., LEGACY, FULL, PARTIAL, NONE).")
255 .def(
"EnableStaticCondensation", &BilinearForm::EnableStaticCondensation,
256 "Enable static condensation to reduce system size.")
257 .def(
"EnableHybridization", &BilinearForm::EnableHybridization,
258 "Enable hybridization.")
259 .def(
"UsePrecomputedSparsity", &BilinearForm::UsePrecomputedSparsity, py::arg(
"ps") = 1,
260 "Enable use of precomputed sparsity pattern.")
261 .def(
"SetDiagonalPolicy", &BilinearForm::SetDiagonalPolicy, py::arg(
"policy"),
262 "Set the policy for handling diagonal entries of essential DOFs.")
265 .def(
"AddDomainIntegrator", py::overload_cast<BilinearFormIntegrator *>(&BilinearForm::AddDomainIntegrator),
266 py::arg(
"bfi"), py::keep_alive<1, 2>(),
267 "Adds a domain integrator to the form.")
268 .def(
"AddBoundaryIntegrator", py::overload_cast<BilinearFormIntegrator *>(&BilinearForm::AddBoundaryIntegrator),
269 py::arg(
"bfi"), py::keep_alive<1, 2>(),
270 "Adds a boundary integrator to the form.")
271 .def(
"AddInteriorFaceIntegrator", &BilinearForm::AddInteriorFaceIntegrator,
272 py::arg(
"bfi"), py::keep_alive<1, 2>(),
273 "Adds an interior face integrator (e.g., for DG methods).")
274 .def(
"AddBdrFaceIntegrator", py::overload_cast<BilinearFormIntegrator *>(&BilinearForm::AddBdrFaceIntegrator),
275 py::arg(
"bfi"), py::keep_alive<1, 2>(),
276 "Adds a boundary face integrator.")
279 .def(
"Assemble", &BilinearForm::Assemble, py::arg(
"skip_zeros") = 1,
280 "Assembles the bilinear form into a sparse matrix.")
281 .def(
"AssembleDiagonal", &BilinearForm::AssembleDiagonal, py::arg(
"diag"),
282 "Assembles the diagonal of the operator into a Vector.")
283 .def(
"FormLinearSystem",
284 [](BilinearForm &self,
const Array<int> &ess_tdof_list, Vector &x,
285 Vector &b, OperatorHandle &A, Vector &X, Vector &B,
int copy_interior) {
286 self.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
288 py::arg(
"ess_tdof_list"), py::arg(
"x"), py::arg(
"b"), py::arg(
"A"),
289 py::arg(
"X"), py::arg(
"B"), py::arg(
"copy_interior") = 0,
290 "Forms the linear system AX=B, applying boundary conditions and other transformations.")
291 .def(
"FormSystemMatrix",
292 [](BilinearForm &self,
const Array<int> &ess_tdof_list, OperatorHandle &A) {
293 self.FormSystemMatrix(ess_tdof_list, A);
295 py::arg(
"ess_tdof_list"), py::arg(
"A"),
296 "Forms the system matrix A, applying necessary transformations.")
297 .def(
"RecoverFEMSolution", py::overload_cast<const Vector&, const Vector&, Vector&>(&BilinearForm::RecoverFEMSolution),
298 py::arg(
"X"), py::arg(
"b"), py::arg(
"x"),
299 "Recovers the full FE solution vector after solving a linear system.")
302 .def(
"FESpace", py::overload_cast<>(&BilinearForm::FESpace, py::const_), py::return_value_policy::reference_internal,
303 "Returns a pointer to the associated FiniteElementSpace.")
304 .def(
"SpMat", py::overload_cast<>(&BilinearForm::SpMat), py::return_value_policy::reference_internal,
305 "Returns a reference to the internal sparse matrix.")
306 .def(
"Update", &BilinearForm::Update, py::arg(
"nfes") =
nullptr,
307 "Update the BilinearForm after the FE space has changed.");
311 py::enum_<mfem::Matrix::DiagonalPolicy>(mfem_submodule,
"DiagonalPolicy")
312 .value(
"DIAG_ZERO", mfem::Matrix::DiagonalPolicy::DIAG_ZERO)
313 .value(
"DIAG_ONE", mfem::Matrix::DiagonalPolicy::DIAG_ONE)
314 .value(
"DIAG_KEEP", mfem::Matrix::DiagonalPolicy::DIAG_KEEP)
332 using namespace mfem;
336 py::class_<MixedBilinearForm, Matrix>(mfem_submodule,
"MixedBilinearForm")
339 .def(py::init<FiniteElementSpace *, FiniteElementSpace *>(),
340 py::arg(
"trial_fespace"), py::arg(
"test_fespace"),
343 py::keep_alive<1, 2>(), py::keep_alive<1, 3>(),
344 "Constructs a mixed bilinear form on the given trial and test FE spaces.")
347 .def(
"SetAssemblyLevel", &MixedBilinearForm::SetAssemblyLevel, py::arg(
"assembly_level"),
348 "Set the assembly level (e.g., LEGACY, FULL, PARTIAL, NONE).")
351 .def(
"AddDomainIntegrator", py::overload_cast<BilinearFormIntegrator *>(&MixedBilinearForm::AddDomainIntegrator),
352 py::arg(
"bfi"), py::keep_alive<1, 2>(),
353 "Adds a domain integrator to the form.")
354 .def(
"AddBoundaryIntegrator", py::overload_cast<BilinearFormIntegrator *>(&MixedBilinearForm::AddBoundaryIntegrator),
355 py::arg(
"bfi"), py::keep_alive<1, 2>(),
356 "Adds a boundary integrator to the form.")
357 .def(
"AddInteriorFaceIntegrator", &MixedBilinearForm::AddInteriorFaceIntegrator,
358 py::arg(
"bfi"), py::keep_alive<1, 2>(),
359 "Adds an interior face integrator.")
360 .def(
"AddBdrFaceIntegrator", py::overload_cast<BilinearFormIntegrator *>(&MixedBilinearForm::AddBdrFaceIntegrator),
361 py::arg(
"bfi"), py::keep_alive<1, 2>(),
362 "Adds a boundary face integrator.")
363 .def(
"AddTraceFaceIntegrator", &MixedBilinearForm::AddTraceFaceIntegrator,
364 py::arg(
"bfi"), py::keep_alive<1, 2>(),
365 "Adds a trace face integrator.")
369 .def(
"Assemble", &MixedBilinearForm::Assemble, py::arg(
"skip_zeros") = 1,
370 "Assembles the mixed bilinear form into a sparse matrix.")
371 .def(
"FormRectangularSystemMatrix",
372 [](MixedBilinearForm &self,
const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list, OperatorHandle &A) {
373 self.FormRectangularSystemMatrix(trial_tdof_list, test_tdof_list, A);
375 py::arg(
"trial_tdof_list"), py::arg(
"test_tdof_list"), py::arg(
"A"),
376 "Forms the rectangular system matrix A, applying necessary transformations.")
377 .def(
"FormRectangularLinearSystem",
378 [](MixedBilinearForm &self,
const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list,
379 Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B) {
380 self.FormRectangularLinearSystem(trial_tdof_list, test_tdof_list, x, b, A, X, B);
382 py::arg(
"trial_tdof_list"), py::arg(
"test_tdof_list"), py::arg(
"x"), py::arg(
"b"),
383 py::arg(
"A"), py::arg(
"X"), py::arg(
"B"),
384 "Forms the rectangular linear system AX=B.")
387 .def(
"TrialFESpace", py::overload_cast<>(&MixedBilinearForm::TrialFESpace, py::const_),
388 py::return_value_policy::reference_internal,
389 "Returns a pointer to the associated trial FiniteElementSpace.")
390 .def(
"TestFESpace", py::overload_cast<>(&MixedBilinearForm::TestFESpace, py::const_),
391 py::return_value_policy::reference_internal,
392 "Returns a pointer to the associated test FiniteElementSpace.")
393 .def(
"SpMat", py::overload_cast<>(&MixedBilinearForm::SpMat),
394 py::return_value_policy::reference_internal,
395 "Returns a reference to the internal sparse matrix.")
396 .def(
"Update", &MixedBilinearForm::Update,
397 "Update the MixedBilinearForm after the FE spaces have changed.");
402 using namespace mfem;
404 py::class_<Mesh>(mfem_submodule,
"Mesh")
410 .def(py::init<const std::string &, int, int, bool>(),
411 py::arg(
"filename"), py::arg(
"generate_edges") = 0,
412 py::arg(
"refine") = 1, py::arg(
"fix_orientation") =
true)
414 .def_static(
"LoadFromFile", &Mesh::LoadFromFile,
415 py::arg(
"filename"), py::arg(
"generate_edges") = 0,
416 py::arg(
"refine") = 1, py::arg(
"fix_orientation") =
true,
417 "Creates a mesh by reading a file.")
420 .def_property_readonly(
"dim", &Mesh::Dimension)
421 .def_property_readonly(
"space_dim", &Mesh::SpaceDimension)
422 .def_property_readonly(
"nv", &Mesh::GetNV,
"Number of Vertices")
423 .def_property_readonly(
"ne", &Mesh::GetNE,
"Number of Elements")
424 .def_property_readonly(
"nbe", &Mesh::GetNBE,
"Number of Boundary Elements")
425 .def_property_readonly(
"n_edges", &Mesh::GetNEdges)
426 .def_property_readonly(
"n_faces", &Mesh::GetNFaces)
427 .def_readonly(
"attributes", &Mesh::attributes)
428 .def_readonly(
"bdr_attributes", &Mesh::bdr_attributes)
429 .def(
"GetBoundingBox",
430 [](Mesh &self,
int ref) {
432 self.GetBoundingBox(min, max, ref);
434 return py::make_tuple(min, max);
435 }, py::arg(
"ref") = 2,
436 "Returns the min and max corners of the mesh bounding box.")
439 .def(
"GetElementVertices",
440 [](
const Mesh &self,
int i) {
442 self.GetElementVertices(i, v);
444 }, py::arg(
"i"),
"Returns a list of vertex indices for element i.")
445 .def(
"GetBdrElementVertices",
446 [](
const Mesh &self,
int i) {
448 self.GetBdrElementVertices(i, v);
450 }, py::arg(
"i"),
"Returns a list of vertex indices for boundary element i.")
451 .def(
"GetFaceElements",
452 [](
const Mesh &self,
int i) {
454 self.GetFaceElements(i, &e1, &e2);
455 return py::make_tuple(e1, e2);
456 }, py::arg(
"face_idx"),
"Returns a tuple of the two elements sharing a face.")
457 .def(
"GetBdrElementFace",
458 [](
const Mesh &self,
int i) {
460 self.GetBdrElementFace(i, &f, &o);
461 return py::make_tuple(f, o);
462 }, py::arg(
"bdr_elem_idx"),
"Returns the face index and orientation for a boundary element.")
463 .def(
"ElementToEdgeTable", &Mesh::ElementToEdgeTable, py::return_value_policy::reference_internal)
464 .def(
"ElementToFaceTable", &Mesh::ElementToFaceTable, py::return_value_policy::reference_internal)
467 .def(
"GetNodes", py::overload_cast<>(&Mesh::GetNodes, py::const_), py::return_value_policy::reference_internal,
468 "Returns the GridFunction for the mesh nodes (if any).")
469 .def(
"SetCurvature", &Mesh::SetCurvature, py::arg(
"order"), py::arg(
"discontinuous") =
false,
470 py::arg(
"space_dim") = -1, py::arg(
"ordering") = 1,
471 "Set the curvature of the mesh, creating a high-order nodal GridFunction.")
473 .def(
"GetElementTransformation", py::overload_cast<int>(&Mesh::GetElementTransformation), py::arg(
"i"),
474 py::return_value_policy::reference_internal)
475 .def(
"GetFaceElementTransformations", py::overload_cast<int, int>(&Mesh::GetFaceElementTransformations), py::arg(
"i"),
476 py::arg(
"mask")=31, py::return_value_policy::reference_internal)
479 .def(
"Save", &Mesh::Save, py::arg(
"filename"), py::arg(
"precision") = 16);
482 py::enum_<VTKFormat>(mfem_submodule,
"VTKFormat")
483 .value(
"ASCII", VTKFormat::ASCII)
484 .value(
"BINARY", VTKFormat::BINARY)
485 .value(
"BINARY32", VTKFormat::BINARY32)
490 using namespace mfem;
492 py::class_<Table>(mfem_submodule,
"Table")
493 .def(
"GetRow", [](
const Table &self,
int row) {
495 self.GetRow(row, row_data);
498 }, py::arg(
"row"),
"Get a row of the table as a list.")
499 .def(
"RowSize", &Table::RowSize, py::arg(
"row"),
"Get the number of entries in a specific row.")
500 .def_property_readonly(
"height", &Table::Size,
"Number of rows in the table.")
501 .def_property_readonly(
"width", &Table::Width,
"Number of columns in the table.")
502 .def(
"__len__", &Table::Size)
503 .def(
"__getitem__", [](
const Table &self,
int row) {
504 if (row < 0 || row >= self.Size()) {
505 throw py::index_error(
"Row index out of bounds");
508 self.GetRow(row, row_data);
511 .def(
"__repr__", [](
const Table &self) {
512 return "<mfem.Table (" + std::to_string(self.Size()) +
"x" +
513 std::to_string(self.Width()) +
")>";
529 using namespace mfem;
530 py::class_<BasisType> basis_type(m,
"BasisType",
"Possible basis types.");
532 basis_type.def_property_readonly_static(
"Invalid", [](py::object) {
return BasisType::Invalid; });
533 basis_type.def_property_readonly_static(
"GaussLegendre", [](py::object) {
return BasisType::GaussLegendre; });
534 basis_type.def_property_readonly_static(
"GaussLobatto", [](py::object) {
return BasisType::GaussLobatto; });
535 basis_type.def_property_readonly_static(
"Positive", [](py::object) {
return BasisType::Positive; });
536 basis_type.def_property_readonly_static(
"OpenUniform", [](py::object) {
return BasisType::OpenUniform; });
537 basis_type.def_property_readonly_static(
"ClosedUniform", [](py::object) {
return BasisType::ClosedUniform; });
538 basis_type.def_property_readonly_static(
"OpenHalfUniform", [](py::object) {
return BasisType::OpenHalfUniform; });
539 basis_type.def_property_readonly_static(
"Serendipity", [](py::object) {
return BasisType::Serendipity; });
540 basis_type.def_property_readonly_static(
"ClosedGL", [](py::object) {
return BasisType::ClosedGL; });
541 basis_type.def_property_readonly_static(
"IntegratedGLL", [](py::object) {
return BasisType::IntegratedGLL; });
583 using namespace mfem;
588 py::class_<FiniteElementSpace>(mfem_submodule,
"FiniteElementSpace")
590 .def(py::init<Mesh *, const FiniteElementCollection *, int, int>(),
591 py::arg(
"mesh"), py::arg(
"fec"), py::arg(
"vdim") = 1, py::arg(
"ordering") = Ordering::byNODES,
594 py::keep_alive<1, 2>(), py::keep_alive<1, 3>())
597 .def_property_readonly(
"ndofs", &FiniteElementSpace::GetNDofs,
"Number of local scalar degrees of freedom.")
598 .def_property_readonly(
"vdim", &FiniteElementSpace::GetVDim,
"Vector dimension of the space.")
599 .def_property_readonly(
"vsize", &FiniteElementSpace::GetVSize,
"Total number of local vector degrees of freedom.")
600 .def_property_readonly(
"true_vsize", &FiniteElementSpace::GetTrueVSize,
"Number of true (conforming) vector degrees of freedom.")
601 .def(
"GetMesh", &FiniteElementSpace::GetMesh, py::return_value_policy::reference_internal,
"Get the associated Mesh.")
602 .def(
"FEColl", &FiniteElementSpace::FEColl, py::return_value_policy::reference_internal,
"Get the associated FiniteElementCollection.")
605 .def(
"GetElementDofs",
606 [](
const FiniteElementSpace &self,
int i) {
608 self.GetElementDofs(i, dofs);
610 }, py::arg(
"elem_idx"),
"Get the local scalar DOFs for a given element.")
611 .def(
"GetElementVDofs",
612 [](
const FiniteElementSpace &self,
int i) {
614 self.GetElementVDofs(i, vdofs);
616 }, py::arg(
"elem_idx"),
"Get the local vector DOFs for a given element.")
617 .def(
"GetBdrElementDofs",
618 [](
const FiniteElementSpace &self,
int i) {
620 self.GetBdrElementDofs(i, dofs);
622 }, py::arg(
"bdr_elem_idx"),
"Get the local scalar DOFs for a given boundary element.")
623 .def(
"GetEssentialVDofs",
624 [](
const FiniteElementSpace &self,
const Array<int> &bdr_attr_is_ess,
int component) {
625 Array<int> ess_vdofs;
626 self.GetEssentialVDofs(bdr_attr_is_ess, ess_vdofs, component);
628 }, py::arg(
"bdr_attr_is_ess"), py::arg(
"component") = -1,
629 "Get a list of essential (Dirichlet) vector DOFs based on boundary attributes.")
630 .def(
"GetEssentialTrueDofs",
631 [](
const FiniteElementSpace &self,
const Array<int> &bdr_attr_is_ess,
int component) {
632 Array<int> ess_tdof_list;
633 self.GetEssentialTrueDofs(bdr_attr_is_ess, ess_tdof_list, component);
634 return ess_tdof_list;
635 }, py::arg(
"bdr_attr_is_ess"), py::arg(
"component") = -1,
636 "Get a list of essential true (conforming) DOFs for use in linear systems.")
639 .def(
"Update", &FiniteElementSpace::Update, py::arg(
"want_transform") =
true,
640 "Update the FE space after the mesh has been modified (e.g., refined).")
641 .def(
"GetUpdateOperator", py::overload_cast<>(&FiniteElementSpace::GetUpdateOperator),
642 py::return_value_policy::reference_internal,
643 "Get the operator that maps GridFunctions from the old space to the new space after an Update.")
644 .def(
"GetProlongationMatrix", &FiniteElementSpace::GetProlongationMatrix,
645 py::return_value_policy::reference_internal,
"Get the P operator (true DOFs to local DOFs).")
646 .def(
"GetRestrictionOperator", &FiniteElementSpace::GetRestrictionOperator,
647 py::return_value_policy::reference_internal,
"Get the R operator (local DOFs to true DOFs).")
649 .def(
"__repr__", [](
const FiniteElementSpace &fes) {
650 std::stringstream ss;
651 ss <<
"<mfem.FiniteElementSpace with " << fes.GetNDofs() <<
" DOFs, vdim=" << fes.GetVDim() <<
">";
666 using namespace mfem;
670 py::class_<GridFunction, Vector>(m,
"GridFunction")
671 .def(py::init<FiniteElementSpace *>(), py::arg(
"fespace"),
672 py::keep_alive<1, 2>(),
673 "Construct a GridFunction on a given FiniteElementSpace.")
675 .def(py::init<FiniteElementSpace *, real_t *>(),
676 py::arg(
"fespace"), py::arg(
"data"),
677 py::keep_alive<1, 2>(),
678 "Construct a GridFunction using previously allocated data.")
680 .def(
"FESpace", py::overload_cast<>(&GridFunction::FESpace, py::const_),
681 py::return_value_policy::reference_internal,
682 "Returns the associated FiniteElementSpace.")
683 .def(
"Update", &GridFunction::Update,
684 "Update the GridFunction after its FE space has been modified.")
685 .def(
"SetSpace", &GridFunction::SetSpace, py::arg(
"fespace"),
686 py::keep_alive<1, 2>(),
"Associate a new FE space with the GridFunction.")
689 .def(
"ProjectCoefficient",
690 py::overload_cast<Coefficient &>(&GridFunction::ProjectCoefficient),
692 "Project a scalar Coefficient onto the GridFunction.")
693 .def(
"ProjectCoefficient",
694 py::overload_cast<VectorCoefficient &>(&GridFunction::ProjectCoefficient),
696 "Project a vector Coefficient onto the GridFunction.")
697 .def(
"ProjectBdrCoefficient",
698 py::overload_cast<Coefficient &,
const Array<int> &>(&GridFunction::ProjectBdrCoefficient),
699 py::arg(
"coeff"), py::arg(
"attr"),
700 "Project a scalar Coefficient onto the boundary degrees of freedom.")
701 .def(
"ProjectBdrCoefficient",
702 py::overload_cast<VectorCoefficient &,
const Array<int> &>(&GridFunction::ProjectBdrCoefficient),
703 py::arg(
"vcoeff"), py::arg(
"attr"),
704 "Project a vector Coefficient onto the boundary degrees of freedom.")
707 .def(
"GetValue", py::overload_cast<ElementTransformation &, const IntegrationPoint &, int, Vector *>(&GridFunction::GetValue, py::const_),
708 py::arg(
"T"), py::arg(
"ip"), py::arg(
"comp") = 0, py::arg(
"tr") =
nullptr,
709 "Get the scalar value at a point described by an ElementTransformation.")
710 .def(
"GetVectorValue",
711 [](
const GridFunction &self, ElementTransformation &T,
const IntegrationPoint &ip) {
713 self.GetVectorValue(T, ip, val);
716 py::arg(
"T"), py::arg(
"ip"),
717 "Get the vector value at a point described by an ElementTransformation.")
719 [](
const GridFunction &self, ElementTransformation &T,
const IntegrationRule &ir,
int comp) {
721 self.GetValues(T, ir, vals, comp);
724 py::arg(
"T"), py::arg(
"ir"), py::arg(
"comp") = 0,
725 "Get scalar values at all points of an IntegrationRule.")
726 .def(
"GetVectorValues",
727 [](
const GridFunction &self, ElementTransformation &T,
const IntegrationRule &ir) {
729 self.GetVectorValues(T, ir, vals);
732 py::arg(
"T"), py::arg(
"ir"),
733 "Get vector values at all points of an IntegrationRule.")
736 .def(
"GetTrueDofs", &GridFunction::GetTrueDofs, py::arg(
"tv"),
737 "Extract the true-dofs from the GridFunction.")
738 .def(
"SetFromTrueDofs", &GridFunction::SetFromTrueDofs, py::arg(
"tv"),
739 "Set the GridFunction from a true-dof vector.")
742 .def(
"Save", py::overload_cast<const char *, int>(&GridFunction::Save, py::const_),
743 py::arg(
"fname"), py::arg(
"precision") = 16)
744 .def(
"__repr__", [](
const GridFunction &gf) {
745 std::stringstream ss;
746 ss <<
"<mfem.GridFunction with " << gf.Size() <<
" DOFs>";
749 .def(
"as_numpy", [](
const GridFunction &self) {
751 return py::array_t<real_t>(self.Size(), self.GetData());
752 },
"Convert the GridFunction to a numpy array.");
757 using namespace mfem;
760 py::class_<Coefficient, serif::pybind::PyCoefficient> coefficient(m,
"Coefficient");
763 .def(
"SetTime", &Coefficient::SetTime, py::arg(
"t"))
764 .def(
"GetTime", &Coefficient::GetTime)
765 .def(
"Eval", py::overload_cast<ElementTransformation &, const IntegrationPoint&>(&Coefficient::Eval),
766 "Evaluate the coefficient at a point in an element.",
767 py::arg(
"T"), py::arg(
"ip"));
769 py::class_<VectorCoefficient, serif::pybind::PyVectorCoefficient> vector_coefficient(m,
"VectorCoefficient");
771 .def(py::init<int>(), py::arg(
"vdim"))
772 .def(
"SetTime", &VectorCoefficient::SetTime, py::arg(
"t"))
773 .def(
"GetTime", &VectorCoefficient::GetTime)
774 .def(
"GetVDim", &VectorCoefficient::GetVDim)
775 .def(
"Eval", py::overload_cast<Vector &, ElementTransformation &, const IntegrationPoint &>(&VectorCoefficient::Eval),
776 "Evaluate the vector coefficient at a point in an element.",
777 py::arg(
"V"), py::arg(
"T"), py::arg(
"ip"));
782 py::class_<ConstantCoefficient, Coefficient>(m,
"ConstantCoefficient")
783 .def(py::init<real_t>(), py::arg(
"c") = 1.0)
784 .def_readwrite(
"constant", &ConstantCoefficient::constant);
787 py::class_<FunctionCoefficient, Coefficient>(m,
"FunctionCoefficient")
788 .def(py::init<std::function<real_t(
const Vector &)>>(),
789 py::arg(
"F"),
"Create a coefficient from a Python function of space.")
790 .def(py::init<std::function<real_t(
const Vector &, real_t)>>(),
791 py::arg(
"TDF"),
"Create a coefficient from a Python function of space and time.");
794 py::class_<VectorConstantCoefficient, VectorCoefficient>(m,
"VectorConstantCoefficient")
795 .def(py::init<const Vector &>(), py::arg(
"v"));
798 py::class_<VectorFunctionCoefficient, VectorCoefficient>(m,
"VectorFunctionCoefficient")
799 .def(py::init<
int, std::function<
void(
const Vector &, Vector &)>>(),
800 py::arg(
"dim"), py::arg(
"F"),
"Create a vector coefficient from a Python function of space.")
801 .def(py::init<
int, std::function<
void(
const Vector &, real_t, Vector &)>>(),
802 py::arg(
"dim"), py::arg(
"TDF"),
"Create a vector coefficient from a Python function of space and time.");
805 py::class_<GridFunctionCoefficient, Coefficient>(m,
"GridFunctionCoefficient")
807 .def(py::init<const GridFunction *>(), py::arg(
"gf"))
808 .def(
"SetGridFunction", &GridFunctionCoefficient::SetGridFunction, py::arg(
"gf"))
809 .def(
"GetGridFunction", &GridFunctionCoefficient::GetGridFunction, py::return_value_policy::reference);
814 using namespace mfem;
815 py::class_<IntegrationPoint>(m,
"IntegrationPoint")
817 .def_readwrite(
"x", &IntegrationPoint::x)
818 .def_readwrite(
"y", &IntegrationPoint::y)
819 .def_readwrite(
"z", &IntegrationPoint::z)
820 .def_readwrite(
"weight", &IntegrationPoint::weight)
821 .def(
"__repr__", [](
const IntegrationPoint &ip) {
822 std::stringstream ss;
823 ss <<
"IP(x=" << ip.x <<
", y=" << ip.y <<
", z=" << ip.z <<
", w=" << ip.weight <<
")";
827 py::class_<IntegrationRule>(m,
"IntegrationRule")
829 .def(py::init<int>(), py::arg(
"NumPoints"))
830 .def(
"GetNPoints", &IntegrationRule::GetNPoints)
831 .def(
"GetOrder", &IntegrationRule::GetOrder)
832 .def(
"__len__", &IntegrationRule::GetNPoints)
833 .def(
"__getitem__", [](
const IntegrationRule &self,
int i) {
834 if (i < 0 || i >= self.GetNPoints())
throw py::index_error();
835 return self.IntPoint(i);
837 .def(
"__iter__", [](
const IntegrationRule &self) {
838 return py::make_iterator(self.begin(), self.end());
839 }, py::keep_alive<0, 1>());
844 using namespace mfem;
847 py::class_<ElementTransformation> eltrans(m,
"ElementTransformation");
849 .def_readonly(
"Attribute", &ElementTransformation::Attribute)
850 .def_readonly(
"ElementNo", &ElementTransformation::ElementNo)
851 .def(
"SetIntPoint", &ElementTransformation::SetIntPoint, py::arg(
"ip"))
852 .def(
"Transform", py::overload_cast<const IntegrationPoint &, Vector &>(&ElementTransformation::Transform),
853 py::arg(
"ip"), py::arg(
"transip"))
854 .def(
"Weight", &ElementTransformation::Weight)
856 .def_property_readonly(
"Jacobian", &ElementTransformation::Jacobian, py::return_value_policy::reference_internal)
857 .def_property_readonly(
"InverseJacobian", &ElementTransformation::InverseJacobian, py::return_value_policy::reference_internal)
858 .def_property_readonly(
"AdjugateJacobian", &ElementTransformation::AdjugateJacobian, py::return_value_policy::reference_internal);
861 py::class_<IsoparametricTransformation, ElementTransformation>(m,
"IsoparametricTransformation")
865 py::class_<FaceElementTransformations, ElementTransformation>(m,
"FaceElementTransformations")
867 .def_readonly(
"Elem1No", &FaceElementTransformations::Elem1No)
868 .def_readonly(
"Elem2No", &FaceElementTransformations::Elem2No)
869 .def_property_readonly(
"Elem1", [](FaceElementTransformations &self) {
return self.Elem1; }, py::return_value_policy::reference)
870 .def_property_readonly(
"Elem2", [](FaceElementTransformations &self) {
return self.Elem2; }, py::return_value_policy::reference)
871 .def(
"GetElement1IntPoint", &FaceElementTransformations::GetElement1IntPoint)
872 .def(
"GetElement2IntPoint", &FaceElementTransformations::GetElement2IntPoint);
875 py::enum_<FaceElementTransformations::ConfigMasks>(eltrans,
"ConfigMasks")
876 .value(
"HAVE_ELEM1", FaceElementTransformations::HAVE_ELEM1)
877 .value(
"HAVE_ELEM2", FaceElementTransformations::HAVE_ELEM2)
878 .value(
"HAVE_LOC1", FaceElementTransformations::HAVE_LOC1)
879 .value(
"HAVE_LOC2", FaceElementTransformations::HAVE_LOC2)
880 .value(
"HAVE_FACE", FaceElementTransformations::HAVE_FACE)