From ccac1f7f4fe4152bef83ead124bf940af9aa38a1 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Thu, 24 Apr 2025 01:27:44 -0400 Subject: [PATCH 01/22] added wrappers for miniapps/dpg/utils --- mfem/_par/blockstaticcond.i | 41 +++++++++++++++++++++++++++++++++ mfem/_par/complex_densemat.i | 30 ++++++++++++++++++++++++ mfem/_par/complexstaticcond.i | 43 +++++++++++++++++++++++++++++++++++ mfem/_par/complexweakform.i | 40 ++++++++++++++++++++++++++++++++ mfem/_par/pcomplexweakform.i | 42 ++++++++++++++++++++++++++++++++++ mfem/_par/pweakform.i | 42 ++++++++++++++++++++++++++++++++++ mfem/_par/setup.py | 6 +++-- mfem/_par/weakform.i | 43 +++++++++++++++++++++++++++++++++++ mfem/_ser/blockstaticcond.i | 41 +++++++++++++++++++++++++++++++++ mfem/_ser/complex_densemat.i | 1 + mfem/_ser/complexstaticcond.i | 1 + mfem/_ser/setup.py | 5 ++-- mfem/_ser/weakform.i | 43 +++++++++++++++++++++++++++++++++++ mfem/par.py | 11 +++++++++ mfem/ser.py | 10 ++++---- 15 files changed, 390 insertions(+), 9 deletions(-) create mode 100644 mfem/_par/blockstaticcond.i create mode 100644 mfem/_par/complex_densemat.i create mode 100644 mfem/_par/complexstaticcond.i create mode 100644 mfem/_par/complexweakform.i create mode 100644 mfem/_par/pcomplexweakform.i create mode 100644 mfem/_par/pweakform.i create mode 100644 mfem/_par/weakform.i create mode 100644 mfem/_ser/blockstaticcond.i create mode 100644 mfem/_ser/weakform.i diff --git a/mfem/_par/blockstaticcond.i b/mfem/_par/blockstaticcond.i new file mode 100644 index 00000000..cfb2fc5b --- /dev/null +++ b/mfem/_par/blockstaticcond.i @@ -0,0 +1,41 @@ +%module(package="mfem._par") blockstaticcond +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/blockstaticcond.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/blockstaticcond.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "densemat.i" +%import "operators.i" +%import "blockmatrix.i" +%import "blockoperator.i" +%import "fespace.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/blockstaticcond.hpp" diff --git a/mfem/_par/complex_densemat.i b/mfem/_par/complex_densemat.i new file mode 100644 index 00000000..479ca99f --- /dev/null +++ b/mfem/_par/complex_densemat.i @@ -0,0 +1,30 @@ +%module(package="mfem._par") complex_densemat +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "densemat.i" +%import "complex_operator.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +%ignore mfem::ComplexLUFactors::Mult(int m, int n, std::complex *X) const; +%include "linalg/complex_densemat.hpp" diff --git a/mfem/_par/complexstaticcond.i b/mfem/_par/complexstaticcond.i new file mode 100644 index 00000000..82dd9c66 --- /dev/null +++ b/mfem/_par/complexstaticcond.i @@ -0,0 +1,43 @@ +%module(package="mfem._par") complexstaticcond +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/complexstaticcond.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/complexstaticcond.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "gridfunc.i" +%import "mesh.i" +%import "solvers.i" +%import "operators.i" +%import "blockmatrix.i" +%import "blockoperator.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/complexstaticcond.hpp" diff --git a/mfem/_par/complexweakform.i b/mfem/_par/complexweakform.i new file mode 100644 index 00000000..7d990683 --- /dev/null +++ b/mfem/_par/complexweakform.i @@ -0,0 +1,40 @@ +%module(package="mfem._par") complexweakform +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/complexweakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pylininteg.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/complexweakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "coefficient.i" +%import "gridfunc.i" +%import "mesh.i" +%import "solvers.i" +%import "operators.i" +%import "blockmatrix.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + +%include "miniapps/dpg/util/complexweakform.hpp" diff --git a/mfem/_par/pcomplexweakform.i b/mfem/_par/pcomplexweakform.i new file mode 100644 index 00000000..8b68f7f3 --- /dev/null +++ b/mfem/_par/pcomplexweakform.i @@ -0,0 +1,42 @@ +%module(package="mfem._par") pcomplexweakform +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/pcomplexweakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/pcomplexweakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "gridfunc.i" +%import "mesh.i" +%import "solvers.i" +%import "operators.i" +%import "blockmatrix.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/pcomplexweakform.hpp" diff --git a/mfem/_par/pweakform.i b/mfem/_par/pweakform.i new file mode 100644 index 00000000..19245a4d --- /dev/null +++ b/mfem/_par/pweakform.i @@ -0,0 +1,42 @@ +%module(package="mfem._par") pweakform +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/pweakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/pweakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "gridfunc.i" +%import "mesh.i" +%import "solvers.i" +%import "operators.i" +%import "blockmatrix.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/pweakform.hpp" diff --git a/mfem/_par/setup.py b/mfem/_par/setup.py index f879469e..a1f609dd 100644 --- a/mfem/_par/setup.py +++ b/mfem/_par/setup.py @@ -128,8 +128,10 @@ def get_extensions(): "submesh", "transfermap", "staticcond","sidredatacollection", "psubmesh", "ptransfermap", "enzyme", "attribute_sets", "arrays_by_name", - "hyperbolic"] - + "hyperbolic", "complex_densemat", + "blockstaticcond", "complexstaticcond", "complexweakform", + "weakform", "pweakform", "pcomplexweakform", ] + if add_pumi == '1': from setup_local import puminc, pumilib modules.append("pumi") diff --git a/mfem/_par/weakform.i b/mfem/_par/weakform.i new file mode 100644 index 00000000..a4cf2b4b --- /dev/null +++ b/mfem/_par/weakform.i @@ -0,0 +1,43 @@ +%module(package="mfem._par") weakform +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/weakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pylininteg.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/weakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "blockvector.i" +%import "bilininteg.i" +%import "lininteg.i" +%import "fespace.i" +%import "blockmatrix.i" +%import "operators.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/weakform.hpp" diff --git a/mfem/_ser/blockstaticcond.i b/mfem/_ser/blockstaticcond.i new file mode 100644 index 00000000..db39f69f --- /dev/null +++ b/mfem/_ser/blockstaticcond.i @@ -0,0 +1,41 @@ +%module(package="mfem._ser") blockstaticcond +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/blockstaticcond.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/blockstaticcond.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "densemat.i" +%import "operators.i" +%import "blockmatrix.i" +%import "blockoperator.i" +%import "fespace.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/blockstaticcond.hpp" diff --git a/mfem/_ser/complex_densemat.i b/mfem/_ser/complex_densemat.i index 84a1a61a..3187dcf0 100644 --- a/mfem/_ser/complex_densemat.i +++ b/mfem/_ser/complex_densemat.i @@ -26,4 +26,5 @@ import_array(); %import "../common/exception.i" %import "../common/io_stream_typemap.i" +%ignore mfem::ComplexLUFactors::Mult(int m, int n, std::complex *X) const; %include "linalg/complex_densemat.hpp" diff --git a/mfem/_ser/complexstaticcond.i b/mfem/_ser/complexstaticcond.i index bc374d10..ea9a1953 100644 --- a/mfem/_ser/complexstaticcond.i +++ b/mfem/_ser/complexstaticcond.i @@ -32,6 +32,7 @@ import_array(); %import "solvers.i" %import "operators.i" %import "blockmatrix.i" +%import "blockoperator.i" %import "complex_densemat.i" %import "../common/exception.i" %import "../common/io_stream_typemap.i" diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index dbc6f6fd..0fd674f6 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -107,8 +107,9 @@ def get_extensions(): "submesh", "transfermap", "staticcond", "sidredatacollection", "enzyme", "attribute_sets", "arrays_by_name", - "hyperbolic", - "complex_densemat", "complexstaticcond", "complexweakform"] + "hyperbolic", "complex_densemat", + "blockstaticcond", "complexstaticcond", "complexweakform", + "weakform"] if add_cuda == '1': diff --git a/mfem/_ser/weakform.i b/mfem/_ser/weakform.i new file mode 100644 index 00000000..3bea7f9a --- /dev/null +++ b/mfem/_ser/weakform.i @@ -0,0 +1,43 @@ +%module(package="mfem._ser") weakform +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/weakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pylininteg.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/weakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "blockvector.i" +%import "bilininteg.i" +%import "lininteg.i" +%import "fespace.i" +%import "blockmatrix.i" +%import "operators.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + + +%include "miniapps/dpg/util/weakform.hpp" diff --git a/mfem/par.py b/mfem/par.py index 4bc260d1..2db5d04b 100644 --- a/mfem/par.py +++ b/mfem/par.py @@ -34,6 +34,7 @@ from mfem._par.fe_coll import * from mfem._par.vector import * from mfem._par.complex_operator import * +from mfem._par.complex_densemat import * from mfem._par.complex_fem import * from mfem._par.fespace import * from mfem._par.linearform import * @@ -150,3 +151,13 @@ except: pass +try: + import mfem._par.weakform as weakform + import mfem._par.complexweakform as complexweakform + import mfem._par.commlexstaticcond as complexstaticcond + import mfem._par.blockstaticcond as blockstaticcond + import mfem._par.pweakform as pweakform + import mfem._par.pcomplexweakform as pcomplexweakform + +except: + pass diff --git a/mfem/ser.py b/mfem/ser.py index 24eaa32b..cee125ac 100644 --- a/mfem/ser.py +++ b/mfem/ser.py @@ -25,6 +25,7 @@ from mfem._ser.fe_coll import * from mfem._ser.vector import * from mfem._ser.complex_operator import * +from mfem._ser.complex_densemat import * from mfem._ser.complex_fem import * from mfem._ser.fespace import * from mfem._ser.linearform import * @@ -74,11 +75,6 @@ from mfem._ser.doftrans import * from mfem._ser.std_vectors import * -try: - from mfem._ser.complex_densemat import * -except ImportError: - pass - from mfem._ser.submesh import * from mfem._ser.transfermap import * from mfem._ser.hyperbolic import * @@ -112,8 +108,12 @@ # import moduleds built from hpp/cpp under miniapp # try: + import mfem._ser.weakform as weakform import mfem._ser.complexweakform as complexweakform import mfem._ser.commlexstaticcond as complexstaticcond + import mfem._ser.blockstaticcond as blockstaticcond except: pass + + From 3b56b38fcb44505da5d3c7b22fbb833932cc93f0 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Mon, 28 Apr 2025 08:13:05 -0400 Subject: [PATCH 02/22] minor edit to setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 262a5dce..169959d3 100644 --- a/setup.py +++ b/setup.py @@ -1258,6 +1258,7 @@ def print_config(): print(" when needed, the dependency (mfem/hypre/metis) will be installed under " + ext_prefix) print(" build mfem : " + ("Yes" if build_mfem else "No")) + print(" build mfem-miniapps : " + ("Yes" if mfem_build_miniapps else "No")) print(" build metis : " + ("Yes" if build_metis else "No")) print(" build hypre : " + ("Yes" if build_hypre else "No")) print(" build libceed : " + ("Yes" if build_libceed else "No")) From 2201fb90ea1a3e4eda11222ea1950cbd03b4a535 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Sat, 24 May 2025 10:38:19 -0400 Subject: [PATCH 03/22] pmaxwell.py --- mfem/_par/fe_coll.i | 7 + mfem/_par/pfespace.i | 7 + mfem/_ser/fe_coll.i | 9 +- miniapps/dpg/pmaxwell.py | 325 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 345 insertions(+), 3 deletions(-) create mode 100644 miniapps/dpg/pmaxwell.py diff --git a/mfem/_par/fe_coll.i b/mfem/_par/fe_coll.i index 8cdf51b3..f9182415 100644 --- a/mfem/_par/fe_coll.i +++ b/mfem/_par/fe_coll.i @@ -30,6 +30,13 @@ import_array(); %import "eltrans.i" %import "lininteg.i" +/* define FiniteElementCollectionPtrArray */ +%import "../common/array_listtuple_typemap.i" +ARRAY_LISTTUPLE_INPUT_SWIGOBJ(mfem::FiniteElementCollection *, 1) +%import "../common/array_instantiation_macro.i" +IGNORE_ARRAY_METHODS(mfem::FiniteElementCollection *) +INSTANTIATE_ARRAY0(FiniteElementCollection *, FiniteElementCollection, 1) + %include "fem/fe_coll.hpp" %pythoncode %{ DG_FECollection = L2_FECollection diff --git a/mfem/_par/pfespace.i b/mfem/_par/pfespace.i index b3a1331c..c0e11324 100644 --- a/mfem/_par/pfespace.i +++ b/mfem/_par/pfespace.i @@ -75,6 +75,13 @@ def GetFaceNbrElementVDofs(self, i): return vdofs.ToList() %} +/* define FiniteElementSpacePtrArray */ +%import "../common/array_listtuple_typemap.i" +ARRAY_LISTTUPLE_INPUT_SWIGOBJ(mfem::ParFiniteElementSpace *, 1) +%import "../common/array_instantiation_macro.i" +IGNORE_ARRAY_METHODS(mfem::ParFiniteElementSpace *) +INSTANTIATE_ARRAY0(ParFiniteElementSpace *, ParFiniteElementSpace, 1) + %include "fem/pfespace.hpp" %extend mfem::ParFiniteElementSpace{ diff --git a/mfem/_ser/fe_coll.i b/mfem/_ser/fe_coll.i index 6d379fcc..b0f8cddc 100644 --- a/mfem/_ser/fe_coll.i +++ b/mfem/_ser/fe_coll.i @@ -32,9 +32,12 @@ import_array(); %import "lininteg.i" %import "../common/exception.i" - //%inline %{ - // typedef mfem::L2_FECollection mfem::DG_FECollection; - // %} +/* define FiniteElementCollectionPtrArray */ +%import "../common/array_listtuple_typemap.i" +ARRAY_LISTTUPLE_INPUT_SWIGOBJ(mfem::FiniteElementCollection *, 1) +%import "../common/array_instantiation_macro.i" +IGNORE_ARRAY_METHODS(mfem::FiniteElementCollection *) +INSTANTIATE_ARRAY0(FiniteElementCollection *, FiniteElementCollection, 1) %include "fem/fe_coll.hpp" %pythoncode %{ diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py new file mode 100644 index 00000000..7d1cde5a --- /dev/null +++ b/miniapps/dpg/pmaxwell.py @@ -0,0 +1,325 @@ +## +## MFEM Ultraweak DPG Maxwell parallel example +## +## Compile with: make pmaxwell +## +## sample run +## mpirun -np 4 python pmaxwell.py -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0 +## mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0 +## mpirun -np 4 python pmaxwell.py -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0 +## mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2 +## mpirun -np 4 python pmaxwell.py -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3 +## mpirun -np 4 python pmaxwell.py -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4 + +## AMR run. Note that this is a computationally intensive sample run. +## We recommend trying it on a large machine with more mpi ranks +## mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc + +## Description: +## This example code demonstrates the use of MFEM to define and solve +## the "ultraweak" (UW) DPG formulation for the Maxwell problem + +## ∇×(1/μ ∇×E) - ω² ϵ E = Ĵ , in Ω +## E×n = E₀ , on ∂Ω + +## It solves the following kinds of problems +## 1) Known exact solutions with error convergence rates +## a) A manufactured solution problem where E is a plane beam +## 2) Fichera "microwave" problem +## 3) PML problems +## a) Generic PML problem with point source given by the load +## b) Plane wave scattering from a square +## c) PML problem with a point source prescribed on the boundary + +## The DPG UW deals with the First Order System +## i ω μ H + ∇ × E = 0, in Ω +## -i ω ϵ E + ∇ × H = J, in Ω +## E × n = E_0, on ∂Ω +## Note: Ĵ = -iωJ + +## The ultraweak-DPG formulation is obtained by integration by parts of both +## equations and the introduction of trace unknowns on the mesh skeleton + +## in 2D +## E is vector valued and H is scalar. +## (∇ × E, F) = (E, ∇ × F) + < n × E , F> +## or (∇ ⋅ AE , F) = (AE, ∇ F) + < AE ⋅ n, F> +## where A = [0 1; -1 0]; + +## E ∈ (L²(Ω))² , H ∈ L²(Ω) +## Ê ∈ H^-1/2(Γₕ), Ĥ ∈ H^1/2(Γₕ) +## i ω μ (H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹ +## -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +## Ê = E₀ on ∂Ω +## ------------------------------------------------------------------------- +## | | E | H | Ê | Ĥ | RHS | +## ------------------------------------------------------------------------- +## | F | (E,∇ × F) | i ω μ (H,F) | < Ê, F > | | | +## | | | | | | | +## | G | -i ω ϵ (E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) | +## where (F,G) ∈ H¹ × H(curl,Ω) + +## in 3D +## E,H ∈ (L^2(Ω))³ +## Ê ∈ H_0^1/2(Ω)(curl, Γₕ), Ĥ ∈ H^-1/2(curl, Γₕ) +## i ω μ (H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω) +## -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +## Ê × n = E₀ on ∂Ω +## ------------------------------------------------------------------------- +## | | E | H | Ê | Ĥ | RHS | +## ------------------------------------------------------------------------- +## | F | (E,∇ × F) | i ω μ (H,F) | < n × Ê, F > | | | +## | | | | | | | +## | G | -i ω ϵ (E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) | +## where (F,G) ∈ H(curl,Ω) × H(curl,Ω) + +## Here we use the "Adjoint Graph" norm on the test space i.e., +## ||(F,G)||²ᵥ = ||A^*(F,G)||² + ||(F,G)||² where A is the +## maxwell operator defined by (1) + +## The PML formulation is + +## ∇×(1/μ α ∇×E) - ω² ϵ β E = Ĵ , in Ω +## E×n = E₀ , on ∂Ω + +## where α = |J|⁻¹ Jᵀ J (in 2D it's the scalar |J|⁻¹), +## β = |J| J⁻¹ J⁻ᵀ, J is the Jacobian of the stretching map +## and |J| its determinant. + +## The first order system reads +## i ω μ α⁻¹ H + ∇ × E = 0, in Ω +## -i ω ϵ β E + ∇ × H = J, in Ω +## E × n = E₀, on ∂Ω + +## and the ultraweak formulation is + +## in 2D +## E ∈ (L²(Ω))² , H ∈ L²(Ω) +## Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ) +## i ω μ (α⁻¹ H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹ +## -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +## Ê = E₀ on ∂Ω +## --------------------------------------------------------------------------------- +## | | E | H | Ê | Ĥ | RHS | +## --------------------------------------------------------------------------------- +## | F | (E,∇ × F) | i ω μ (α⁻¹ H,F) | < Ê, F > | | | +## | | | | | | | +## | G | -i ω ϵ (β E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) | + +## where (F,G) ∈ H¹ × H(curl,Ω) + +## +## in 3D +## E,H ∈ (L^2(Ω))³ +## Ê ∈ H_0^1/2(Ω)(curl, Γ_h), Ĥ ∈ H^-1/2(curl, Γₕ) +## i ω μ (α⁻¹ H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω) +## -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +## Ê × n = E_0 on ∂Ω +## ------------------------------------------------------------------------------- +## | | E | H | Ê | Ĥ | RHS | +## ------------------------------------------------------------------------------- +## | F | ( E,∇ × F) | i ω μ (α⁻¹ H,F) | < n × Ê, F > | | | +## | | | | | | | +## | G | -iωϵ (β E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) | +## where (F,G) ∈ H(curl,Ω) × H(curl,Ω) + +## For more information see https:##doi.org/10.1016/j.camwa.2021.01.017 +import os +from os.path import expanduser, join + +import numpy as np +from numpy import pi + +import mfem.par as mfem + +from mpi4py import MPI +num_procs = MPI.COMM_WORLD.size +myid = MPI.COMM_WORLD.rank +smyid = '.'+'{:0>6d}'.format(myid) + +prob_type = {"plane_wave", + "fichera_oven", + "pml_general", + "pml_plane_wave_scatter", + "pml_pointsource"} + +def run(meshfile='', + order=1, + delta_order=1, + prob=0, + sr=0, + pr=1, + eps=1.0, + mu=1.0, + rnum=1.0, + theta=0.0, + static_cond=False, + visualization=False): + + omega = 2.*pi*rnum + with_pml = False + + if prob == 0: + exact_known = True; + elif prob == 1: + meshfile = "meshes/fichera-waveguide.mesh"; + omega = 5.0; + rnum = omega/(2.*M_PI); + elif prob == 2: + with_pml = True + else: + with_pml = True + meshfile = "meshes/scatter.mesh" + + mesh_file = expanduser( + join(os.path.dirname(__file__), '..', 'data', meshfile)) + + mesh = mfem.Mesh(mesh_file, 1, 1) + dim = mesh.Dimension() + assert dim > 1, "Dimension = 1 is not supported in this example" + + dimc = 3 if dim == 3 else 1 + for i in range(sr): + mesh.UniformRefinement(); + mesh.EnsureNCMesh(False) + + + if with_pml: + assert False, "PML is not supported" + + pmesh = mfem.ParMesh(MPI.COMM_WORLD, mesh) + del mesh + + attr = mfem.intArray() + attrPML= mfem.intArray() + + # Define spaces + TrialSpace = {"E_space": 0, + "H_space": 1, + "hatE_space": 2, + "hatH_space": 3,} + TestSpace = {"F_space": 0, + "G_space": 1,} + + # Vector L2 L2 space for E + E_fec = mfem.FiniteElementCollection(order-1, dim) + E_fes = mfem.ParFiniteElementSpace(pmesh, E_fec, dim) + + # Vector L2 L2 space for H + H_fec = mfem.FiniteElementCollection(order-1, dim) + H_fes = mfem.ParFiniteElementSpace(pmesh, H_fec, dim) + + # H^-1/2 (curl) space for Ê + test_order = order + delta_order + + if dim == 3: + hatE_fec = mfem.ND_Trace_FECollection(order, dim) + hatH_fec = mfem.ND_Trace_FECollection(order, dim) + F_fec = mfem.ND_FECollection(test_order, dim) + else: + hatE_fec = mfem.RT_Trace_FECollection(order-1, dim) + hatH_fec = mfem.H1_Trace_FECollection(order, dim) + F_fec = mfem.H1_FECollection(test_order, dim) + + hatE_fes = mfem.ParFiniteElementSpace(pmesh, hatE_fec) + hatH_fes = mfem.ParFiniteElementSpace(pmesh, hatH_fec) + G_fec = mfem.ND_FECollection(test_order, dim) + + + + trial_fes = mfem.ParFiniteElementSpacePtrArray() + test_fec = mfem.FiniteElementCollectionPtrArray() + trial_fes.Append(E_fes) + trial_fes.Append(H_fes) + trial_fes.Append(hatE_fes) + trial_fes.Append(hatH_fes) + test_fec.Append(F_fec) + test_fec.Append(G_fec) + + # Bilinear form coefficients + one = mfem.ConstantCoefficient(1.0); + eps2omeg2 = mfem.ConstantCoefficient(epsilon*epsilon*omega*omega) + mu2omeg2 = mfem.ConstantCoefficient(mu*mu*omega*omega) + muomeg = mfem.ConstantCoefficient(mu*omega) + negepsomeg = mfem.ConstantCoefficient(-epsilon*omega) + epsomeg = mfem.ConstantCoefficient(epsilon*omega) + negmuomeg = mfem.ConstantCoefficient(-mu*omega) + + # for the 2D case + rot_mat = mfem.DenseMatrix(np.array([[0, 1.],[-1, 0]]) + rot =mfem.MatrixConstantCoefficient(rot_mat) + epsrot = mfem.ScalarMatrixProductCoefficient(epsomeg,rot) + negepsrot = ScalarMatrixProductCoefficient(negepsomeg,rot) + + + + pass + +if __name__ == "__main__": + from mfem.common.arg_parser import ArgParser + + parser = ArgParser(description='Ex40 (Eikonal queation)') + parser.add_argument('-m', '--mesh', + default='star.mesh', + action='store', type=str, + help='Mesh file to use.') + parser.add_argument('-o', '--order', + action='store', default=1, type=int, + help="Finite element order (polynomial degree).") + + parser.add_argument("-rnum", "--number-of-wavelengths", + action='store', default=1.0, type=float, + help="Number of wavelengths"); + parser.add_argument("-mu", "--permeability", + action='store', default=1.0, type=float, + help="Permeability of free space (or 1/(spring constant)).") + parser.add_argument("-eps", "--permittivity", + action='store', default=1.0, type=float, + help="Permittivity of free space (or mass constant)."); + parser.add_argument("-prob", "--problem", + action='store', default=1, type=int, + help="\n".join(("Problem case" + " 0: plane wave, 1: Fichera 'oven', " + " 2: Generic PML problem with point source given as a load " + " 3: Scattering of a plane wave, " + " 4: Point source given on the boundary"))) + parser.add_argument("-do", "--delta-order", + action='store', default=1, type=int, + help="Order enrichment for DPG test space.") + parser.add_argument("-theta", "--theta", + action='store', default=0.0, type=float, + help="Theta parameter for AMR") + parser.add_argument("-sref", "--serial-ref", + action='store', default=0, type=int, + help="Number of parallel refinements.") + parser.add_argument("-pref", "--parallel-ref", + action='store', default=1, type=int, + help="Number of parallel refinements.") + parser.add_argument("-sc", "--static-condensation", + action='store_true', default=False, + help="Enable static condensation.") + parser.add_argument('-no-vis', '--no-visualization', + action='store_true', + default=False, + help='Disable or disable GLVis visualization') + + args = parser.parse_args() + if myid == 0: + parser.print_options(args) + + visualization = not args.no_visualization + + + run(meshfile=args.mesh, + order=args.order, + prob=args.problem, + sr=args.serial_ref, + pr=args.parallel_ref, + eps=args.permittivity, + mu=args.permeability, + delta_order=args.delta_order, + rnum=args.number_of_wavelengths, + theta=args.theta, + static_cond=args.static_condensation, + visualization=visualization) + From 4d3b446e537f0a9b2ae95eaa497bff947b7f3707 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Sat, 24 May 2025 14:18:40 -0400 Subject: [PATCH 04/22] pmaxwell.py --- miniapps/dpg/pmaxwell.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index 7d1cde5a..597c5eec 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -250,8 +250,26 @@ def run(meshfile='', rot =mfem.MatrixConstantCoefficient(rot_mat) epsrot = mfem.ScalarMatrixProductCoefficient(epsomeg,rot) negepsrot = ScalarMatrixProductCoefficient(negepsomeg,rot) - + if pml: + epsomeg_cf = mfem.RestrictedCoefficient(epsomeg,attr) + negepsomeg_cf = mfem.RestrictedCoefficient(negepsomeg,attr) + eps2omeg2_cf = mfem.RestrictedCoefficient(eps2omeg2,attr) + muomeg_cf = mfem.RestrictedCoefficient(muomeg,attr) + negmuomeg_cf = mfem.RestrictedCoefficient(negmuomeg,attr) + mu2omeg2_cf = mfem.RestrictedCoefficient(mu2omeg2,attr) + epsrot_cf = mfem.MatrixRestrictedCoefficient(epsrot,attr) + negepsrot_cf = mfem.MatrixRestrictedCoefficient(negepsrot,attr) + else: + epsomeg_cf = epsomeg + negepsomeg_cf = negepsomeg + eps2omeg2_cf = eps2omeg2 + muomeg_cf = muomeg + negmuomeg_cf = negmuomeg + mu2omeg2_cf = mu2omeg2 + epsrot_cf = epsrot + negepsrot_cf = negepsrot + pass From 0e11b179773cf775e77503796c815d598aca1510 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Sat, 24 May 2025 17:35:13 -0400 Subject: [PATCH 05/22] (WIP) work in progress --- mfem/_par/blockstaticcond.i | 5 + mfem/_par/complexstaticcond.i | 5 + mfem/_par/complexweakform.i | 5 + mfem/_par/pcomplexweakform.i | 6 +- mfem/_par/pml.i | 44 ++++ mfem/_par/pweakform.i | 5 + mfem/_par/setup.py | 2 +- mfem/_par/weakform.i | 7 +- mfem/_ser/blockstaticcond.i | 5 + mfem/_ser/complexstaticcond.i | 7 +- mfem/_ser/complexweakform.i | 7 +- mfem/_ser/pml.i | 44 ++++ mfem/_ser/setup.py | 2 +- mfem/_ser/weakform.i | 6 + mfem/par.py | 29 +- mfem/ser.py | 12 +- miniapps/dpg/pmaxwell.py | 479 +++++++++++++++++++++++++++++++++- 17 files changed, 646 insertions(+), 24 deletions(-) create mode 100644 mfem/_par/pml.i create mode 100644 mfem/_ser/pml.i diff --git a/mfem/_par/blockstaticcond.i b/mfem/_par/blockstaticcond.i index cfb2fc5b..50dc0e50 100644 --- a/mfem/_par/blockstaticcond.i +++ b/mfem/_par/blockstaticcond.i @@ -12,6 +12,9 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_BLOCKSTATICCOND + %init %{ import_array(); %} @@ -39,3 +42,5 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/blockstaticcond.hpp" + +#endif diff --git a/mfem/_par/complexstaticcond.i b/mfem/_par/complexstaticcond.i index 82dd9c66..34306c1b 100644 --- a/mfem/_par/complexstaticcond.i +++ b/mfem/_par/complexstaticcond.i @@ -12,6 +12,9 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_COMPLEXSTATICCOND + %init %{ import_array(); %} @@ -41,3 +44,5 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/complexstaticcond.hpp" + +#endif diff --git a/mfem/_par/complexweakform.i b/mfem/_par/complexweakform.i index 7d990683..b1ecb5c2 100644 --- a/mfem/_par/complexweakform.i +++ b/mfem/_par/complexweakform.i @@ -13,6 +13,9 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_COMPLEXWEAKFORM + %init %{ import_array(); %} @@ -38,3 +41,5 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/complexweakform.hpp" + +#endif diff --git a/mfem/_par/pcomplexweakform.i b/mfem/_par/pcomplexweakform.i index 8b68f7f3..49952941 100644 --- a/mfem/_par/pcomplexweakform.i +++ b/mfem/_par/pcomplexweakform.i @@ -12,6 +12,9 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_PCOMPLEXWEAKFORM + %init %{ import_array(); %} @@ -38,5 +41,6 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) - %include "miniapps/dpg/util/pcomplexweakform.hpp" + +#endif diff --git a/mfem/_par/pml.i b/mfem/_par/pml.i new file mode 100644 index 00000000..ba004a04 --- /dev/null +++ b/mfem/_par/pml.i @@ -0,0 +1,44 @@ +%module(package="mfem._par") pml +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/pcomplexweakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_PML + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/pml.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "gridfunc.i" +%import "mesh.i" +%import "solvers.i" +%import "operators.i" +%import "blockmatrix.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +%include "miniapps/dpg/util/pml.hpp" + +#endif diff --git a/mfem/_par/pweakform.i b/mfem/_par/pweakform.i index 19245a4d..ae8dd913 100644 --- a/mfem/_par/pweakform.i +++ b/mfem/_par/pweakform.i @@ -12,6 +12,9 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_PWEAKFORM + %init %{ import_array(); %} @@ -40,3 +43,5 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/pweakform.hpp" + +#endif diff --git a/mfem/_par/setup.py b/mfem/_par/setup.py index 9916fe86..16e9fdfe 100644 --- a/mfem/_par/setup.py +++ b/mfem/_par/setup.py @@ -120,7 +120,7 @@ def get_extensions(): "attribute_sets", "arrays_by_name", "hyperbolic", "complex_densemat", "blockstaticcond", "complexstaticcond", "complexweakform", - "weakform", "pweakform", "pcomplexweakform", ] + "weakform", "pweakform", "pcomplexweakform", "pml"] if add_pumi == '1': from setup_local import puminc, pumilib diff --git a/mfem/_par/weakform.i b/mfem/_par/weakform.i index a4cf2b4b..554084a7 100644 --- a/mfem/_par/weakform.i +++ b/mfem/_par/weakform.i @@ -13,6 +13,10 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_WEAKFORM + + %init %{ import_array(); %} @@ -39,5 +43,6 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) - %include "miniapps/dpg/util/weakform.hpp" + +#endif diff --git a/mfem/_ser/blockstaticcond.i b/mfem/_ser/blockstaticcond.i index db39f69f..d39c3733 100644 --- a/mfem/_ser/blockstaticcond.i +++ b/mfem/_ser/blockstaticcond.i @@ -12,6 +12,9 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_BLOCKSTATICCOND + %init %{ import_array(); %} @@ -39,3 +42,5 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/blockstaticcond.hpp" + +#endif diff --git a/mfem/_ser/complexstaticcond.i b/mfem/_ser/complexstaticcond.i index 7ae98853..24c35542 100644 --- a/mfem/_ser/complexstaticcond.i +++ b/mfem/_ser/complexstaticcond.i @@ -12,14 +12,13 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_COMPLEXSTATICCOND + %init %{ import_array(); %} -%include "../common/existing_mfem_headers.i" - -#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_COMPLEXSTATICCOND - %inline %{ #include "miniapps/dpg/util/complexstaticcond.cpp" %} diff --git a/mfem/_ser/complexweakform.i b/mfem/_ser/complexweakform.i index 632c0eab..6d8977d9 100644 --- a/mfem/_ser/complexweakform.i +++ b/mfem/_ser/complexweakform.i @@ -13,14 +13,13 @@ #include "../common/io_stream.hpp" %} +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_COMPLEXWEAKFORM + %init %{ import_array(); %} -%include "../common/existing_mfem_headers.i" - -#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_COMPLEXWEAKFORM - %inline %{ #include "miniapps/dpg/util/complexweakform.cpp" %} diff --git a/mfem/_ser/pml.i b/mfem/_ser/pml.i new file mode 100644 index 00000000..5b794aec --- /dev/null +++ b/mfem/_ser/pml.i @@ -0,0 +1,44 @@ +%module(package="mfem._ser") pml +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "miniapps/dpg/util/pcomplexweakform.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_PML + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/pml.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "gridfunc.i" +%import "mesh.i" +%import "solvers.i" +%import "operators.i" +%import "blockmatrix.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +%include "miniapps/dpg/util/pml.hpp" + +#endif diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index e9f27c03..3690da49 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -107,7 +107,7 @@ def get_extensions(): "attribute_sets", "arrays_by_name", "hyperbolic", "complex_densemat", "blockstaticcond", "complexstaticcond", "complexweakform", - "weakform"] + "weakform", "pml"] if add_cuda == '1': diff --git a/mfem/_ser/weakform.i b/mfem/_ser/weakform.i index 3bea7f9a..14019a2f 100644 --- a/mfem/_ser/weakform.i +++ b/mfem/_ser/weakform.i @@ -13,6 +13,10 @@ #include "../common/io_stream.hpp" %} + +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_WEAKFORM + %init %{ import_array(); %} @@ -41,3 +45,5 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/weakform.hpp" + +#endif diff --git a/mfem/par.py b/mfem/par.py index 2db5d04b..737f2cb4 100644 --- a/mfem/par.py +++ b/mfem/par.py @@ -126,6 +126,17 @@ # # modules not a part of standard build # +import importlib.util +import sys +import types +def load_module(module_name, module_code): + spec = importlib.util.spec_from_loader(module_name, loader=None, origin="dynamic") + module = types.ModuleType(module_name) + spec.loader.exec_module(module) if spec.loader else exec(module_code, module.__dict__) + sys.modules[module_name] = module + return module + + try: import mfem._par.pumi as pumi from mfem._par.pumi import * @@ -151,13 +162,17 @@ except: pass + try: - import mfem._par.weakform as weakform - import mfem._par.complexweakform as complexweakform - import mfem._par.commlexstaticcond as complexstaticcond - import mfem._par.blockstaticcond as blockstaticcond - import mfem._par.pweakform as pweakform - import mfem._par.pcomplexweakform as pcomplexweakform - + module_code = """ + from mfem._par.weakform import * + from mfem._par.complexweakform import * + from mfem._par.commlexstaticcond impoft * + from mfem._par.blockstaticcond import * + from mfem._par.pweakform import * + from mfem._par.pcomplexweakform import * + from mfem._par.pml import * + """ + dpg = load_module("dpg", module_code) except: pass diff --git a/mfem/ser.py b/mfem/ser.py index cee125ac..c523c3d6 100644 --- a/mfem/ser.py +++ b/mfem/ser.py @@ -108,10 +108,14 @@ # import moduleds built from hpp/cpp under miniapp # try: - import mfem._ser.weakform as weakform - import mfem._ser.complexweakform as complexweakform - import mfem._ser.commlexstaticcond as complexstaticcond - import mfem._ser.blockstaticcond as blockstaticcond + module_code = """ + from mfem._par.weakform import * + from mfem._par.complexweakform import * + from mfem._par.commlexstaticcond impoft * + from mfem._par.blockstaticcond import * + from mfem._par.pml import * + """ + dpg = load_module("dpg", module_code) except: pass diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index 597c5eec..bdb3711b 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -270,9 +270,486 @@ def run(meshfile='', epsrot_cf = epsrot negepsrot_cf = negepsrot + detJ_r = mfem.PmlCoefficient(detJ_r_function,pml) + detJ_i = mfem.PmlCoefficient(detJ_i_function,pml) + abs_detJ_2 = mfem.PmlCoefficient(abs_detJ_2_function,pml) + detJ_Jt_J_inv_r = mfem.PmlMatrixCoefficient(dim,detJ_Jt_J_inv_r_function,pml) + detJ_Jt_J_inv_i = mfem.PmlMatrixCoefficient(dim,detJ_Jt_J_inv_i_function,pml) + abs_detJ_Jt_J_inv_2 = mfem.PmlMatrixCoefficient(dim,abs_detJ_Jt_J_inv_2_function,pml) + negmuomeg_detJ_r = mfem.ProductCoefficient(negmuomeg,detJ_r) + negmuomeg_detJ_i = mfem.ProductCoefficient(negmuomeg,detJ_i) + muomeg_detJ_r = mfem.ProductCoefficient(muomeg,detJ_r) + mu2omeg2_detJ_2 = mfem.ProductCoefficient(mu2omeg2,abs_detJ_2) + epsomeg_detJ_Jt_J_inv_i = mfem.ScalarMatrixProductCoefficient(epsomeg, detJ_Jt_J_inv_i) + epsomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(epsomeg, detJ_Jt_J_inv_r) + negepsomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(negepsomeg, detJ_Jt_J_inv_r) + muomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(muomeg,detJ_Jt_J_inv_r) + negmuomeg_detJ_Jt_J_inv_i = mfem.ScalarMatrixProductCoefficient(negmuomeg, detJ_Jt_J_inv_i) + negmuomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(negmuomeg, detJ_Jt_J_inv_r) + mu2omeg2_detJ_Jt_J_inv_2 = mfem.ScalarMatrixProductCoefficient(mu2omeg2, abs_detJ_Jt_J_inv_2) + eps2omeg2_detJ_Jt_J_inv_2 = mfem.ScalarMatrixProductCoefficient(eps2omeg2, abs_detJ_Jt_J_inv_2) + negmuomeg_detJ_r_restr = mfem.RestrictedCoefficient(negmuomeg_detJ_r,attrPML) + negmuomeg_detJ_i_restr = mfem.RestrictedCoefficient(negmuomeg_detJ_i,attrPML) + muomeg_detJ_r_restr = mfem.RestrictedCoefficient(muomeg_detJ_r,attrPML) + mu2omeg2_detJ_2_restr = mfem.RestrictedCoefficient(mu2omeg2_detJ_2,attrPML) + epsomeg_detJ_Jt_J_inv_i_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_i,attrPML) + epsomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_r,attrPML) + negepsomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(negepsomeg_detJ_Jt_J_inv_r,attrPML) + muomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(muomeg_detJ_Jt_J_inv_r, attrPML) + negmuomeg_detJ_Jt_J_inv_i_restr = mfem.MatrixRestrictedCoefficient(negmuomeg_detJ_Jt_J_inv_i,attrPML) + negmuomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(negmuomeg_detJ_Jt_J_inv_r,attrPML) + mu2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient(mu2omeg2_detJ_Jt_J_inv_2,attrPML) + eps2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient(eps2omeg2_detJ_Jt_J_inv_2,attrPML) + + + if pml and dim == 2: + epsomeg_detJ_Jt_J_inv_i_rot = mfem.MatrixProductCoefficient(epsomeg_detJ_Jt_J_inv_i, rot) + epsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient(epsomeg_detJ_Jt_J_inv_r, rot) + negepsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient(negepsomeg_detJ_Jt_J_inv_r, rot) + epsomeg_detJ_Jt_J_inv_i_rot_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_i_rot, + attrPML) + epsomeg_detJ_Jt_J_inv_r_rot_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_r_rot, + attrPML) + negepsomeg_detJ_Jt_J_inv_r_rot_restr = mfem.MatrixRestrictedCoefficient(negepsomeg_detJ_Jt_J_inv_r_rot, + attrPML) + + + a = mfem.dpg.ParComplexDPGWeakForm(trial_fes,test_fec) + a.StoreMatrices() # needed for AMR + + # (E,∇ × F) + a.AddTrialIntegrator(mfem.TransposeIntegrator(mfem.MixedCurlIntegrator(one)), + None, + TrialSpace["E_space"], + TestSpace["F_space"]) + # -i ω ϵ (E , G) = i (- ω ϵ E, G) + a.AddTrialIntegrator(None, + mfem.TransposeIntegrator(mfem.VectorFEMassIntegrator(negepsomeg_cf)), + TrialSpace["E_space"], + TestSpace["G_space"]) + # (H,∇ × G) + a.AddTrialIntegrator(mfem.TransposeIntegrator(mfem.MixedCurlIntegrator(one)), + None, + TrialSpace["H_space"], + TestSpace["G_space"]) + # < n×Ĥ ,G> + a.AddTrialIntegrator(mfem.TangentTraceIntegrator, None, + TrialSpace["hatH_space"], + TestSpace["G_space"]) + # test integrators + # (∇×G ,∇× δG) + a.AddTestIntegrator(mfem.CurlCurlIntegrator(one), None, + TestSpace["G_space"], + TestSpace["G_space"]) + # (G,δG) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator(one), None, + TestSpace["G_space"], + TestSpace["G_space"]) + + if dim == 3: + # i ω μ (H, F) + a.AddTrialIntegrator(None, mfem.TransposeIntegrator( + mfem.VectorFEMassIntegrator(muomeg_cf)), + TrialSpace["H_space"], + TestSpace["F_space"]) + # < n×Ê,F> + a.AddTrialIntegrator(mfem.TangentTraceIntegrator, None, + TrialSpace["hatE_space"], + TestSpace["F_space"]) + + # test integrators + # (∇×F,∇×δF) + a.AddTestIntegrator(mfem.CurlCurlIntegrator(one), None, + TestSpace["F_space"], + TestSpace["F_space"]) + # (F,δF) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator(one), None, + TestSpace["F_space"], + TestSpace["F_space"]) + # μ^2 ω^2 (F,δF) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator(mu2omeg2_cf), None, + TestSpace["F_space"], + TestSpace["F_space"]) + # -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G) + a.AddTestIntegrator(None, mfem.MixedVectorWeakCurlIntegrator(negmuomeg_cf), + TestSpace["F_space"], + TestSpace["G_space"]) + # -i ω ϵ (∇ × F, δG) + a.AddTestIntegrator(None, mfem.MixedVectorCurlIntegrator(negepsomeg_cf), + TestSpace["F_space"], + TestSpace["G_space"]) + # i ω μ (∇ × G,δF) + a.AddTestIntegrator(None, mfem.MixedVectorCurlIntegrator(muomeg_cf), + TestSpace["G_space"], + TestSpace["F_space"]) + # i ω ϵ (G, ∇ × δF ) + a.AddTestIntegrator(None, mfem.MixedVectorWeakCurlIntegrator(epsomeg_cf), + TestSpace["G_space"], + TestSpace["F_space"]) + # ϵ^2 ω^2 (G,δG) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator(eps2omeg2_cf), None, + TestSpace["G_space"], + TestSpace["G_space"]) + else: + # i ω μ (H, F) + a.AddTrialIntegrator(None, mfem.MixedScalarMassIntegrator(muomeg_cf), + TrialSpace["H_space"], + TestSpace["F_space"]) + # < n×Ê,F> + a.AddTrialIntegrator(mfem.TraceIntegrator, None, + TrialSpace["hatE_space"], + TestSpace["F_space"]) + # test integrators + # (∇F,∇δF) + a.AddTestIntegrator(mfem.DiffusionIntegrator(one), None, + TestSpace["F_space"], + TestSpace["F_space"]) + # (F,δF) + a.AddTestIntegrator(mfem.MassIntegrator(one), None, + TestSpace["F_space"], + TestSpace["F_space"]) + # μ^2 ω^2 (F,δF) + a.AddTestIntegrator(mfem.MassIntegrator(mu2omeg2_cf), None, + TestSpace["F_space"], + TestSpace["F_space"]) + # -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G) + a.AddTestIntegrator(None, + mfem.TransposeIntegrator(mfem.MixedCurlIntegrator(negmuomeg_cf)), + TestSpace["F_space"], + TestSpace["G_space"]) + # -i ω ϵ (∇ × F, δG) = i (- ω ϵ A ∇ F,δG), A = [0 1; -1; 0] + a.AddTestIntegrator(None, mfem.MixedVectorGradientIntegrator(negepsrot_cf), + TestSpace["F_space"], + TestSpace["G_space"]) + # i ω μ (∇ × G,δF) = i (ω μ ∇ × G, δF ) + a.AddTestIntegrator(None, mfem.MixedCurlIntegrator(muomeg_cf), + TestSpace["G_space"], + TestSpace["F_space"]) + # i ω ϵ (G, ∇ × δF ) = i (ω ϵ G, A ∇ δF) = i ( G , ω ϵ A ∇ δF) + a.AddTestIntegrator(None, + mfem.TransposeIntegrator(mfem.MixedVectorGradientIntegrator(epsrot_cf)) + TestSpace["G_space"], + TestSpace["F_space"]) + # ϵ^2 ω^2 (G, δG) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator(eps2omeg2_cf), None, + TestSpace["G_space"], + TestSpace["G_space"]) + if pml: + assert False, "PML not supported yet" + + + # RHS + f_rhs_r = mfem.VectorFunctionCoefficient(dim, rhs_func_r) + f_rhs_i = mfem.VectorFunctionCoefficient(dim, rhs_func_i) + f_source = mfem.VectorFunctionCoefficient(dim, source_function) + + if prob == 0: + a.AddDomainLFIntegrator(mfem.VectorFEDomainLFIntegrator(f_rhs_r), + mfem.VectorFEDomainLFIntegrator(f_rhs_i), + TestSpace["G_space"]) + elif prob == 2: + a.AddDomainLFIntegrator(mfem.VectorFEDomainLFIntegrator(f_source), + None, + TestSpace["G_space"]) + + hatEex_r = mfem.VectorFunctionCoefficient(dim, hatE_exact_r) + hatEex_i = mfem.VectorFunctionCoefficient(dim, hatE_exact_i) - pass + if myid == 0: + txt = "\n Ref |" + " Dofs |" + " ω |" + if exact_known: + txt = txt + " L2 Error |" + " Rate |" + + txt = txt + " Residual |" + " Rate |" + " PCG it |" + print(txt) + + if exact_known: + print("-"*82) + else: + print("-"*60) + + res0 = 0. + err0 = 0. + dof0 = 0 + + elements_to_refine = mfem.intArray() + + socketstream E_out_r; + socketstream H_out_r; + + + Array + + ParGridFunction E_r, E_i, H_r, H_i; + + ParaViewDataCollection * paraview_dc = nullptr; + + if static_cond: + a.EnableStaticCondensation() + for (int it = 0; it<=pr; it++) + { + a->Assemble(); + + Array ess_tdof_list; + Array ess_bdr; + if (pmesh.bdr_attributes.Size()) + { + ess_bdr.SetSize(pmesh.bdr_attributes.Max()); + ess_bdr = 1; + hatE_fes->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + if (pml) + { + ess_bdr = 0; + ess_bdr[1] = 1; + } + } + + // shift the ess_tdofs + for (int j = 0; j < ess_tdof_list.Size(); j++) + { + ess_tdof_list[j] += E_fes->GetTrueVSize() + H_fes->GetTrueVSize(); + } + + Array offsets(5); + offsets[0] = 0; + offsets[1] = E_fes->GetVSize(); + offsets[2] = H_fes->GetVSize(); + offsets[3] = hatE_fes->GetVSize(); + offsets[4] = hatH_fes->GetVSize(); + offsets.PartialSum(); + + Vector x(2*offsets.Last()); + x = 0.; + + if (prob != 2) + { + ParGridFunction hatE_gf_r(hatE_fes, x, offsets[2]); + ParGridFunction hatE_gf_i(hatE_fes, x, offsets.Last() + offsets[2]); + if (dim == 3) + { + hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr); + hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr); + } + else + { + hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr); + hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr); + } + } + + OperatorPtr Ah; + Vector X,B; + a->FormLinearSystem(ess_tdof_list,x,Ah, X,B); + + ComplexOperator * Ahc = Ah.As(); + + BlockOperator * BlockA_r = dynamic_cast(&Ahc->real()); + BlockOperator * BlockA_i = dynamic_cast(&Ahc->imag()); + + int num_blocks = BlockA_r->NumRowBlocks(); + Array tdof_offsets(2*num_blocks+1); + + tdof_offsets[0] = 0; + int skip = (static_cond) ? 0 : 2; + int k = (static_cond) ? 2 : 0; + for (int i=0; iGetTrueVSize(); + tdof_offsets[num_blocks+i+1] = trial_fes[i+k]->GetTrueVSize(); + } + tdof_offsets.PartialSum(); + + BlockOperator blockA(tdof_offsets); + for (int i = 0; iGetBlock(i,j)); + blockA.SetBlock(i,j+num_blocks,&BlockA_i->GetBlock(i,j), -1.0); + blockA.SetBlock(i+num_blocks,j+num_blocks,&BlockA_r->GetBlock(i,j)); + blockA.SetBlock(i+num_blocks,j,&BlockA_i->GetBlock(i,j)); + } + } + + X = 0.; + BlockDiagonalPreconditioner M(tdof_offsets); + + if (!static_cond) + { + HypreBoomerAMG * solver_E = new HypreBoomerAMG((HypreParMatrix &) + BlockA_r->GetBlock(0,0)); + solver_E->SetPrintLevel(0); + solver_E->SetSystemsOptions(dim); + HypreBoomerAMG * solver_H = new HypreBoomerAMG((HypreParMatrix &) + BlockA_r->GetBlock(1,1)); + solver_H->SetPrintLevel(0); + solver_H->SetSystemsOptions(dim); + M.SetDiagonalBlock(0,solver_E); + M.SetDiagonalBlock(1,solver_H); + M.SetDiagonalBlock(num_blocks,solver_E); + M.SetDiagonalBlock(num_blocks+1,solver_H); + } + + HypreSolver * solver_hatH = nullptr; + HypreAMS * solver_hatE = new HypreAMS((HypreParMatrix &)BlockA_r->GetBlock(skip, + skip), + hatE_fes); + solver_hatE->SetPrintLevel(0); + if (dim == 2) + { + solver_hatH = new HypreBoomerAMG((HypreParMatrix &)BlockA_r->GetBlock(skip+1, + skip+1)); + dynamic_cast(solver_hatH)->SetPrintLevel(0); + } + else + { + solver_hatH = new HypreAMS((HypreParMatrix &)BlockA_r->GetBlock(skip+1,skip+1), + hatH_fes); + dynamic_cast(solver_hatH)->SetPrintLevel(0); + } + + M.SetDiagonalBlock(skip,solver_hatE); + M.SetDiagonalBlock(skip+1,solver_hatH); + M.SetDiagonalBlock(skip+num_blocks,solver_hatE); + M.SetDiagonalBlock(skip+num_blocks+1,solver_hatH); + + CGSolver cg(MPI_COMM_WORLD); + cg.SetRelTol(1e-6); + cg.SetMaxIter(10000); + cg.SetPrintLevel(0); + cg.SetPreconditioner(M); + cg.SetOperator(blockA); + cg.Mult(B, X); + + for (int i = 0; iRecoverFEMSolution(X,x); + + Vector & residuals = a->ComputeResidual(x); + + real_t residual = residuals.Norml2(); + real_t maxresidual = residuals.Max(); + real_t globalresidual = residual * residual; + MPI_Allreduce(MPI_IN_PLACE, &maxresidual, 1, MPITypeMap::mpi_type, + MPI_MAX, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globalresidual, 1, + MPITypeMap::mpi_type, MPI_SUM, MPI_COMM_WORLD); + + globalresidual = sqrt(globalresidual); + + E_r.MakeRef(E_fes,x, 0); + E_i.MakeRef(E_fes,x, offsets.Last()); + + H_r.MakeRef(H_fes,x, offsets[1]); + H_i.MakeRef(H_fes,x, offsets.Last()+offsets[1]); + + int dofs = 0; + for (int i = 0; iGlobalTrueVSize(); + } + + real_t L2Error = 0.0; + real_t rate_err = 0.0; + + if (exact_known) + { + VectorFunctionCoefficient E_ex_r(dim,E_exact_r); + VectorFunctionCoefficient E_ex_i(dim,E_exact_i); + VectorFunctionCoefficient H_ex_r(dim,H_exact_r); + VectorFunctionCoefficient H_ex_i(dim,H_exact_i); + real_t E_err_r = E_r.ComputeL2Error(E_ex_r); + real_t E_err_i = E_i.ComputeL2Error(E_ex_i); + real_t H_err_r = H_r.ComputeL2Error(H_ex_r); + real_t H_err_i = H_i.ComputeL2Error(H_ex_i); + L2Error = sqrt( E_err_r*E_err_r + E_err_i*E_err_i + + H_err_r*H_err_r + H_err_i*H_err_i ); + rate_err = (it) ? dim*log(err0/L2Error)/log((real_t)dof0/dofs) : 0.0; + err0 = L2Error; + } + + real_t rate_res = (it) ? dim*log(res0/globalresidual)/log(( + real_t)dof0/dofs) : 0.0; + + res0 = globalresidual; + dof0 = dofs; + + if (myid == 0) + { + std::ios oldState(nullptr); + oldState.copyfmt(std::cout); + std::cout << std::right << std::setw(5) << it << " | " + << std::setw(10) << dof0 << " | " + << std::setprecision(1) << std::fixed + << std::setw(4) << 2.0*rnum << " π | " + << std::setprecision(3); + if (exact_known) + { + std::cout << std::setw(10) << std::scientific << err0 << " | " + << std::setprecision(2) + << std::setw(6) << std::fixed << rate_err << " | " ; + } + std::cout << std::setprecision(3) + << std::setw(10) << std::scientific << res0 << " | " + << std::setprecision(2) + << std::setw(6) << std::fixed << rate_res << " | " + << std::setw(6) << std::fixed << num_iter << " | " + << std::endl; + std::cout.copyfmt(oldState); + } + + if (visualization) + { + const char * keys = (it == 0 && dim == 2) ? "jRcml\n" : nullptr; + char vishost[] = "localhost"; + VisualizeField(E_out_r,vishost, visport, E_r, + "Numerical Electric field (real part)", 0, 0, 500, 500, keys); + VisualizeField(H_out_r,vishost, visport, H_r, + "Numerical Magnetic field (real part)", 501, 0, 500, 500, keys); + } + + if (paraview) + { + paraview_dc->SetCycle(it); + paraview_dc->SetTime((real_t)it); + paraview_dc->Save(); + } + + if (it == pr) + { + break; + } + + if (theta > 0.0) + { + elements_to_refine.SetSize(0); + for (int iel = 0; iel theta * maxresidual) + { + elements_to_refine.Append(iel); + } + } + pmesh.GeneralRefinement(elements_to_refine,1,1); + } + else + { + pmesh.UniformRefinement(); + } + if (pml) { pml->SetAttributes(&pmesh); } + for (int i =0; iUpdate(false); + } + a->Update(); + } + if __name__ == "__main__": from mfem.common.arg_parser import ArgParser From bb3f56e24103b52f4bdaf6d9a11306c206843165 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Sun, 25 May 2025 20:52:13 -0400 Subject: [PATCH 06/22] made ser/par.dpg module to load all dpg related routines --- mfem/_par/blockstaticcond.i | 2 +- mfem/_par/complexstaticcond.i | 2 +- mfem/_par/dpg.i | 66 +++ mfem/_par/pfespace.i | 2 +- mfem/_par/setup.py | 3 +- mfem/_ser/blockstaticcond.i | 2 +- mfem/_ser/complexstaticcond.i | 2 +- mfem/_ser/dpg.i | 61 +++ mfem/_ser/setup.py | 5 +- mfem/par.py | 13 +- mfem/ser.py | 10 +- miniapps/dpg/meshes/fichera-waveguide.mesh | 93 ++++ miniapps/dpg/meshes/scatter.mesh | 247 ++++++++++ miniapps/dpg/pmaxwell.py | 541 ++++++++++----------- 14 files changed, 734 insertions(+), 315 deletions(-) create mode 100644 mfem/_par/dpg.i create mode 100644 mfem/_ser/dpg.i create mode 100644 miniapps/dpg/meshes/fichera-waveguide.mesh create mode 100644 miniapps/dpg/meshes/scatter.mesh diff --git a/mfem/_par/blockstaticcond.i b/mfem/_par/blockstaticcond.i index 50dc0e50..07f34c32 100644 --- a/mfem/_par/blockstaticcond.i +++ b/mfem/_par/blockstaticcond.i @@ -40,7 +40,7 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) - +%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; %include "miniapps/dpg/util/blockstaticcond.hpp" #endif diff --git a/mfem/_par/complexstaticcond.i b/mfem/_par/complexstaticcond.i index 34306c1b..641c6f63 100644 --- a/mfem/_par/complexstaticcond.i +++ b/mfem/_par/complexstaticcond.i @@ -42,7 +42,7 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) - +%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; %include "miniapps/dpg/util/complexstaticcond.hpp" #endif diff --git a/mfem/_par/dpg.i b/mfem/_par/dpg.i new file mode 100644 index 00000000..fd496f5b --- /dev/null +++ b/mfem/_par/dpg.i @@ -0,0 +1,66 @@ +%module(package="mfem._par") dpg +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pylininteg.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_WEAKFORM + + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/pml.cpp" +#include "miniapps/dpg/util/blockstaticcond.cpp" +#include "miniapps/dpg/util/complexstaticcond.cpp" +#include "miniapps/dpg/util/weakform.cpp" +#include "miniapps/dpg/util/complexweakform.cpp" +#include "miniapps/dpg/util/pweakform.cpp" +#include "miniapps/dpg/util/pcomplexweakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "blockvector.i" +%import "bilininteg.i" +%import "lininteg.i" +%import "fespace.i" +%import "blockmatrix.i" +%import "operators.i" +%import "blockmatrix.i" +%import "blockoperator.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + +%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; +%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; + +%include "miniapps/dpg/util/pml.hpp" +%include "miniapps/dpg/util/blockstaticcond.hpp" +%include "miniapps/dpg/util/complexstaticcond.hpp" +%include "miniapps/dpg/util/weakform.hpp" +%include "miniapps/dpg/util/complexweakform.hpp" +%include "miniapps/dpg/util/pweakform.hpp" +%include "miniapps/dpg/util/pcomplexweakform.hpp" + + +#endif diff --git a/mfem/_par/pfespace.i b/mfem/_par/pfespace.i index c0e11324..e8094886 100644 --- a/mfem/_par/pfespace.i +++ b/mfem/_par/pfespace.i @@ -75,7 +75,7 @@ def GetFaceNbrElementVDofs(self, i): return vdofs.ToList() %} -/* define FiniteElementSpacePtrArray */ +/* define FiniteElementSpaceArray */ %import "../common/array_listtuple_typemap.i" ARRAY_LISTTUPLE_INPUT_SWIGOBJ(mfem::ParFiniteElementSpace *, 1) %import "../common/array_instantiation_macro.i" diff --git a/mfem/_par/setup.py b/mfem/_par/setup.py index 16e9fdfe..e56455df 100644 --- a/mfem/_par/setup.py +++ b/mfem/_par/setup.py @@ -119,8 +119,7 @@ def get_extensions(): "psubmesh", "ptransfermap", "enzyme", "attribute_sets", "arrays_by_name", "hyperbolic", "complex_densemat", - "blockstaticcond", "complexstaticcond", "complexweakform", - "weakform", "pweakform", "pcomplexweakform", "pml"] + "dpg"] if add_pumi == '1': from setup_local import puminc, pumilib diff --git a/mfem/_ser/blockstaticcond.i b/mfem/_ser/blockstaticcond.i index d39c3733..71655353 100644 --- a/mfem/_ser/blockstaticcond.i +++ b/mfem/_ser/blockstaticcond.i @@ -40,7 +40,7 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) - +%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; %include "miniapps/dpg/util/blockstaticcond.hpp" #endif diff --git a/mfem/_ser/complexstaticcond.i b/mfem/_ser/complexstaticcond.i index 24c35542..5e98a3ae 100644 --- a/mfem/_ser/complexstaticcond.i +++ b/mfem/_ser/complexstaticcond.i @@ -42,7 +42,7 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) - +%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; %include "miniapps/dpg/util/complexstaticcond.hpp" #endif diff --git a/mfem/_ser/dpg.i b/mfem/_ser/dpg.i new file mode 100644 index 00000000..a9328219 --- /dev/null +++ b/mfem/_ser/dpg.i @@ -0,0 +1,61 @@ +%module(package="mfem._ser") dpg +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "../common/pyoperator.hpp" +#include "../common/pysolvers.hpp" +#include "../common/pycoefficient.hpp" +#include "../common/pyintrules.hpp" +#include "../common/pylininteg.hpp" +#include "../common/pybilininteg.hpp" +#include "../common/pynonlininteg.hpp" +#include "../common/io_stream.hpp" +%} + +%include "../common/existing_mfem_headers.i" +#ifdef FILE_EXISTS_MINIAPPS_DPG_UTIL_WEAKFORM + + +%init %{ +import_array(); +%} + +%inline %{ +#include "miniapps/dpg/util/pml.cpp" +#include "miniapps/dpg/util/blockstaticcond.cpp" +#include "miniapps/dpg/util/complexstaticcond.cpp" +#include "miniapps/dpg/util/weakform.cpp" +#include "miniapps/dpg/util/complexweakform.cpp" +%} + + +%include "exception.i" +%import "element.i" +%import "../common/exception.i" + +%import "array.i" +%import "vector.i" +%import "blockvector.i" +%import "bilininteg.i" +%import "lininteg.i" +%import "fespace.i" +%import "blockmatrix.i" +%import "operators.i" +%import "blockmatrix.i" +%import "blockoperator.i" +%import "complex_densemat.i" +%import "../common/exception.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + +%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; +%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; + +%include "miniapps/dpg/util/pml.hpp" +%include "miniapps/dpg/util/blockstaticcond.hpp" +%include "miniapps/dpg/util/complexstaticcond.hpp" +%include "miniapps/dpg/util/weakform.hpp" +%include "miniapps/dpg/util/complexweakform.hpp" + +#endif diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index 3690da49..b9e34841 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -105,9 +105,8 @@ def get_extensions(): "submesh", "transfermap", "staticcond", "sidredatacollection", "enzyme", "attribute_sets", "arrays_by_name", - "hyperbolic", "complex_densemat", - "blockstaticcond", "complexstaticcond", "complexweakform", - "weakform", "pml"] + "hyperbolic", "complex_densemat", + "dpg"] if add_cuda == '1': diff --git a/mfem/par.py b/mfem/par.py index 737f2cb4..3504bb79 100644 --- a/mfem/par.py +++ b/mfem/par.py @@ -162,17 +162,8 @@ def load_module(module_name, module_code): except: pass - try: - module_code = """ - from mfem._par.weakform import * - from mfem._par.complexweakform import * - from mfem._par.commlexstaticcond impoft * - from mfem._par.blockstaticcond import * - from mfem._par.pweakform import * - from mfem._par.pcomplexweakform import * - from mfem._par.pml import * - """ - dpg = load_module("dpg", module_code) + import mfem._par.dpg as dpg except: pass + diff --git a/mfem/ser.py b/mfem/ser.py index c523c3d6..0e66c88b 100644 --- a/mfem/ser.py +++ b/mfem/ser.py @@ -107,15 +107,9 @@ # # import moduleds built from hpp/cpp under miniapp # + try: - module_code = """ - from mfem._par.weakform import * - from mfem._par.complexweakform import * - from mfem._par.commlexstaticcond impoft * - from mfem._par.blockstaticcond import * - from mfem._par.pml import * - """ - dpg = load_module("dpg", module_code) + import mfem._ser.dpg as dpg except: pass diff --git a/miniapps/dpg/meshes/fichera-waveguide.mesh b/miniapps/dpg/meshes/fichera-waveguide.mesh new file mode 100644 index 00000000..4faba20d --- /dev/null +++ b/miniapps/dpg/meshes/fichera-waveguide.mesh @@ -0,0 +1,93 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see fem/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# PRISM = 6 +# PYRAMID = 7 +# + +dimension +3 + +elements +8 +1 5 0 1 4 3 9 10 13 12 +2 5 9 10 13 12 18 19 22 21 +3 5 10 11 14 13 19 20 23 22 +4 5 1 2 5 4 10 11 14 13 +5 5 4 5 8 7 13 14 17 16 +6 5 12 13 16 15 21 22 25 24 +7 5 3 4 7 6 12 13 16 15 +8 5 18 19 22 21 26 27 29 28 + +boundary +28 +1 3 0 3 4 1 +1 3 1 4 5 2 +1 3 3 6 7 4 +1 3 4 7 8 5 +4 3 26 27 29 28 +3 3 0 9 12 3 +3 3 3 12 15 6 +3 3 9 18 21 12 +3 3 12 21 24 15 +3 3 18 26 28 21 +2 3 0 1 10 9 +2 3 9 10 19 18 +2 3 18 19 27 26 +2 3 1 2 11 10 +2 3 10 11 20 19 +5 3 11 14 23 20 +5 3 14 13 22 23 +5 3 19 20 23 22 +5 3 2 5 14 11 +5 3 5 8 17 14 +5 3 8 7 16 17 +5 3 13 14 17 16 +5 3 22 13 16 25 +5 3 16 15 24 25 +5 3 21 22 25 24 +5 3 7 6 15 16 +5 3 29 22 21 28 +5 3 19 22 29 27 + +vertices +30 +3 +0 0 0 +1 0 0 +2 0 0 +0 1 0 +1 1 0 +2 1 0 +0 2 0 +1 2 0 +2 2 0 +0 0 1 +1 0 1 +2 0 1 +0 1 1 +1 1 1 +2 1 1 +0 2 1 +1 2 1 +2 2 1 +0 0 2 +1 0 2 +2 0 2 +0 1 2 +1 1 2 +2 1 2 +0 2 2 +1 2 2 +0 0 3 +1 0 3 +0 1 3 +1 1 3 diff --git a/miniapps/dpg/meshes/scatter.mesh b/miniapps/dpg/meshes/scatter.mesh new file mode 100644 index 00000000..dcc21d89 --- /dev/null +++ b/miniapps/dpg/meshes/scatter.mesh @@ -0,0 +1,247 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see fem/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# PRISM = 6 +# PYRAMID = 7 +# + +dimension +2 + +elements +80 +1 3 0 1 11 10 +1 3 10 11 21 20 +1 3 11 12 22 21 +1 3 1 2 12 11 +1 3 2 3 13 12 +1 3 3 4 14 13 +1 3 13 14 24 23 +1 3 12 13 23 22 +1 3 22 23 33 32 +1 3 23 24 34 33 +1 3 33 34 44 43 +1 3 32 33 43 42 +1 3 31 32 42 41 +1 3 21 22 32 31 +1 3 20 21 31 30 +1 3 30 31 41 40 +1 3 40 41 51 50 +1 3 41 42 52 51 +1 3 51 52 62 61 +1 3 50 51 61 60 +1 3 60 61 71 70 +1 3 61 62 72 71 +1 3 71 72 82 81 +1 3 70 71 81 80 +1 3 80 81 91 90 +1 3 81 82 92 91 +1 3 82 83 93 92 +1 3 83 84 94 93 +1 3 73 74 84 83 +1 3 72 73 83 82 +1 3 62 63 73 72 +1 3 63 64 74 73 +1 3 53 54 64 63 +1 3 52 53 63 62 +1 3 42 43 53 52 +1 3 43 44 54 53 +1 3 45 46 56 55 +1 3 55 56 66 65 +1 3 54 55 65 64 +1 3 64 65 75 74 +1 3 74 75 85 84 +1 3 84 85 95 94 +1 3 85 86 96 95 +1 3 75 76 86 85 +1 3 65 66 76 75 +1 3 66 67 77 76 +1 3 76 77 87 86 +1 3 86 87 97 96 +1 3 87 88 98 97 +1 3 88 89 99 98 +1 3 78 79 89 88 +1 3 77 78 88 87 +1 3 67 68 78 77 +1 3 68 69 79 78 +1 3 58 59 69 68 +1 3 57 58 68 67 +1 3 56 57 67 66 +1 3 46 47 57 56 +1 3 47 48 58 57 +1 3 48 49 59 58 +1 3 38 39 49 48 +1 3 28 29 39 38 +1 3 27 28 38 37 +1 3 37 38 48 47 +1 3 36 37 47 46 +1 3 26 27 37 36 +1 3 25 26 36 35 +1 3 35 36 46 45 +1 3 34 35 45 44 +1 3 24 25 35 34 +1 3 14 15 25 24 +1 3 4 5 15 14 +1 3 5 6 16 15 +1 3 15 16 26 25 +1 3 16 17 27 26 +1 3 6 7 17 16 +1 3 7 8 18 17 +1 3 17 18 28 27 +1 3 18 19 29 28 +1 3 8 9 19 18 + +boundary +40 +1 1 0 1 +1 1 1 2 +1 1 2 3 +1 1 3 4 +1 1 4 5 +1 1 5 6 +1 1 6 7 +1 1 7 8 +1 1 8 9 +1 1 91 90 +1 1 92 91 +1 1 93 92 +1 1 94 93 +1 1 95 94 +1 1 96 95 +1 1 97 96 +1 1 98 97 +1 1 99 98 +1 1 10 0 +1 1 20 10 +1 1 30 20 +1 1 40 30 +1 1 50 40 +1 1 60 50 +1 1 70 60 +1 1 80 70 +1 1 90 80 +1 1 9 19 +1 1 19 29 +1 1 29 39 +1 1 39 49 +1 1 49 59 +1 1 59 69 +1 1 69 79 +1 1 79 89 +1 1 89 99 +2 1 44 54 +2 1 45 44 +2 1 55 45 +2 1 54 55 + +vertices +100 +2 +0 0 +0.11111111 0 +0.22222222 0 +0.33333333 0 +0.44444444 0 +0.55555556 0 +0.66666667 0 +0.77777778 0 +0.88888889 0 +1 0 +0 0.11111111 +0.11111111 0.11111111 +0.22222222 0.11111111 +0.33333333 0.11111111 +0.44444444 0.11111111 +0.55555556 0.11111111 +0.66666667 0.11111111 +0.77777778 0.11111111 +0.88888889 0.11111111 +1 0.11111111 +0 0.22222222 +0.11111111 0.22222222 +0.22222222 0.22222222 +0.33333333 0.22222222 +0.44444444 0.22222222 +0.55555556 0.22222222 +0.66666667 0.22222222 +0.77777778 0.22222222 +0.88888889 0.22222222 +1 0.22222222 +0 0.33333333 +0.11111111 0.33333333 +0.22222222 0.33333333 +0.33333333 0.33333333 +0.44444444 0.33333333 +0.55555556 0.33333333 +0.66666667 0.33333333 +0.77777778 0.33333333 +0.88888889 0.33333333 +1 0.33333333 +0 0.44444444 +0.11111111 0.44444444 +0.22222222 0.44444444 +0.33333333 0.44444444 +0.44444444 0.44444444 +0.55555556 0.44444444 +0.66666667 0.44444444 +0.77777778 0.44444444 +0.88888889 0.44444444 +1 0.44444444 +0 0.55555556 +0.11111111 0.55555556 +0.22222222 0.55555556 +0.33333333 0.55555556 +0.44444444 0.55555556 +0.55555556 0.55555556 +0.66666667 0.55555556 +0.77777778 0.55555556 +0.88888889 0.55555556 +1 0.55555556 +0 0.66666667 +0.11111111 0.66666667 +0.22222222 0.66666667 +0.33333333 0.66666667 +0.44444444 0.66666667 +0.55555556 0.66666667 +0.66666667 0.66666667 +0.77777778 0.66666667 +0.88888889 0.66666667 +1 0.66666667 +0 0.77777778 +0.11111111 0.77777778 +0.22222222 0.77777778 +0.33333333 0.77777778 +0.44444444 0.77777778 +0.55555556 0.77777778 +0.66666667 0.77777778 +0.77777778 0.77777778 +0.88888889 0.77777778 +1 0.77777778 +0 0.88888889 +0.11111111 0.88888889 +0.22222222 0.88888889 +0.33333333 0.88888889 +0.44444444 0.88888889 +0.55555556 0.88888889 +0.66666667 0.88888889 +0.77777778 0.88888889 +0.88888889 0.88888889 +1 0.88888889 +0 1 +0.11111111 1 +0.22222222 1 +0.33333333 1 +0.44444444 1 +0.55555556 1 +0.66666667 1 +0.77777778 1 +0.88888889 1 +1 1 diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index bdb3711b..dc69459f 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -143,13 +143,47 @@ "pml_plane_wave_scatter", "pml_pointsource"} +visport = 19916; + +def VisualizeField(sock, vishost, visport, + gf, title, + x, y, w, h, keys, vec): + + mesh = gf.FESpace().GetMesh() + + sock = None + newly_opened = False + + while True: + if sock is None: + sock = mfem.socketstream("localhost", visport) + sock.precision(8); + newly_opened = True + + sock << "solution\n"; + sock << mesh << gf + + if newly_opend: + sock << "window_title '" << title << "'\n" + sock << "window_geometry " + sock << x << " " << y << " " << w << " " << h << "\n" + + if keys != '': + sock << "keys " << keys << "\n" + if vec: + sock << "vvv" + sock.flush() + + return sock + + def run(meshfile='', order=1, delta_order=1, prob=0, sr=0, pr=1, - eps=1.0, + epsilon=1.0, mu=1.0, rnum=1.0, theta=0.0, @@ -161,18 +195,27 @@ def run(meshfile='', if prob == 0: exact_known = True; + mesh_file = expanduser( + join(os.path.dirname(__file__), '..', 'data', meshfile)) + elif prob == 1: meshfile = "meshes/fichera-waveguide.mesh"; omega = 5.0; - rnum = omega/(2.*M_PI); + rnum = omega/(2.*pi) + mesh_file = expanduser( + join(os.path.dirname(__file__), meshfile)) + elif prob == 2: with_pml = True + mesh_file = expanduser( + join(os.path.dirname(__file__), '..', 'data', meshfile)) + else: with_pml = True - meshfile = "meshes/scatter.mesh" + mesh_file = "meshes/scatter.mesh" + mesh_file = expanduser( + join(os.path.dirname(__file__), meshfile)) - mesh_file = expanduser( - join(os.path.dirname(__file__), '..', 'data', meshfile)) mesh = mfem.Mesh(mesh_file, 1, 1) dim = mesh.Dimension() @@ -202,11 +245,11 @@ def run(meshfile='', "G_space": 1,} # Vector L2 L2 space for E - E_fec = mfem.FiniteElementCollection(order-1, dim) + E_fec = mfem.L2_FECollection(order-1, dim) E_fes = mfem.ParFiniteElementSpace(pmesh, E_fec, dim) # Vector L2 L2 space for H - H_fec = mfem.FiniteElementCollection(order-1, dim) + H_fec = mfem.L2_FECollection(order-1, dim) H_fes = mfem.ParFiniteElementSpace(pmesh, H_fec, dim) # H^-1/2 (curl) space for Ê @@ -227,8 +270,8 @@ def run(meshfile='', - trial_fes = mfem.ParFiniteElementSpacePtrArray() - test_fec = mfem.FiniteElementCollectionPtrArray() + trial_fes = mfem.ParFiniteElementSpaceArray() + test_fec = mfem.FiniteElementCollectionArray() trial_fes.Append(E_fes) trial_fes.Append(H_fes) trial_fes.Append(hatE_fes) @@ -246,12 +289,12 @@ def run(meshfile='', negmuomeg = mfem.ConstantCoefficient(-mu*omega) # for the 2D case - rot_mat = mfem.DenseMatrix(np.array([[0, 1.],[-1, 0]]) + rot_mat = mfem.DenseMatrix(np.array([[0, 1.],[-1, 0]])) rot =mfem.MatrixConstantCoefficient(rot_mat) epsrot = mfem.ScalarMatrixProductCoefficient(epsomeg,rot) - negepsrot = ScalarMatrixProductCoefficient(negepsomeg,rot) + negepsrot = mfem.ScalarMatrixProductCoefficient(negepsomeg,rot) - if pml: + if with_pml: epsomeg_cf = mfem.RestrictedCoefficient(epsomeg,attr) negepsomeg_cf = mfem.RestrictedCoefficient(negepsomeg,attr) eps2omeg2_cf = mfem.RestrictedCoefficient(eps2omeg2,attr) @@ -270,7 +313,7 @@ def run(meshfile='', epsrot_cf = epsrot negepsrot_cf = negepsrot - detJ_r = mfem.PmlCoefficient(detJ_r_function,pml) + detJ_r = mfem.dpg.PmlCoefficient(detJ_r_function,pml) detJ_i = mfem.PmlCoefficient(detJ_i_function,pml) abs_detJ_2 = mfem.PmlCoefficient(abs_detJ_2_function,pml) detJ_Jt_J_inv_r = mfem.PmlMatrixCoefficient(dim,detJ_Jt_J_inv_r_function,pml) @@ -302,7 +345,7 @@ def run(meshfile='', eps2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient(eps2omeg2_detJ_Jt_J_inv_2,attrPML) - if pml and dim == 2: + if with_pml and dim == 2: epsomeg_detJ_Jt_J_inv_i_rot = mfem.MatrixProductCoefficient(epsomeg_detJ_Jt_J_inv_i, rot) epsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient(epsomeg_detJ_Jt_J_inv_r, rot) negepsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient(negepsomeg_detJ_Jt_J_inv_r, rot) @@ -427,14 +470,14 @@ def run(meshfile='', TestSpace["F_space"]) # i ω ϵ (G, ∇ × δF ) = i (ω ϵ G, A ∇ δF) = i ( G , ω ϵ A ∇ δF) a.AddTestIntegrator(None, - mfem.TransposeIntegrator(mfem.MixedVectorGradientIntegrator(epsrot_cf)) + mfem.TransposeIntegrator(mfem.MixedVectorGradientIntegrator(epsrot_cf)), TestSpace["G_space"], TestSpace["F_space"]) # ϵ^2 ω^2 (G, δG) a.AddTestIntegrator(mfem.VectorFEMassIntegrator(eps2omeg2_cf), None, TestSpace["G_space"], TestSpace["G_space"]) - if pml: + if with_pml: assert False, "PML not supported yet" @@ -473,281 +516,207 @@ def run(meshfile='', dof0 = 0 elements_to_refine = mfem.intArray() + + ## visualizaiton socket + E_out_r = None + H_out_r = None + + if static_cond: + a.EnableStaticCondensation() - socketstream E_out_r; - socketstream H_out_r; + for it in range(pr+1): + a.Assemble() + + ess_tdof_list = mfem.intArray() + ess_bdr = mfem.intArray() + + if pmesh.bdr_attributes.Size() != 0: + ess_bdr.SetSize(pmesh.bdr_attributes.Max()) + ess_bdr.Assign(1) + hatE_fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list) + if with_pml: + ess_bdr.Assign(0) + ess_bdr[1] = 1 + + + # shift the ess_tdofs + for j in range(ess_tdof_list.Size()): + ess_tdof_list[j] += E_fes.GetTrueVSize() + H_fes.GetTrueVSize() + + offsets = mfem.intArray(5) + offsets[0] = 0 + offsets[1] = E_fes.GetVSize() + offsets[2] = H_fes.GetVSize() + offsets[3] = hatE_fes.GetVSize() + offsets[4] = hatH_fes.GetVSize() + offsets.PartialSum() + + x = mfem.Vector([0.]*(2*offsets.Last())) + if prob != 2: + hatE_gf_r = mfem.ParGridFunction(hatE_fes, x, offsets[2]) + hatE_gf_i = mfem.ParGridFunction(hatE_fes, x, offsets.Last() + offsets[2]); + if dim == 3: + hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr) + hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr) + else: + hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr) + hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr) + + Ah = mfem.OperatorPtr() + X = mfem.Vector() + B = mfem.Vector() + a.FormLinearSystem(ess_tdof_list,x, Ah, X, B) + + Ahc = Ah.AsComplexOperator() + + assert False, "here (dynamic cast)" + #BlockOperator * BlockA_r = dynamic_cast(&Ahc->real()); + #BlockOperator * BlockA_i = dynamic_cast(&Ahc->imag()); + + num_blocks = BlockA_r.NumRowBlocks() + tdof_offsets = mfem.intArray(2*num_blocks+1) + + tdof_offsets[0] = 0 + skip = 0 if static_cond else 2 + k = 2 if static_cond else 0 + for i in range(num_blocks): + tdof_offsets[i+1] = trial_fes[i+k].GetTrueVSize(); + tdof_offsets[num_blocks+i+1] = trial_fes[i+k].GetTrueVSize() + tdof_offsets.PartialSum(); + + blockA = BlockOperator(tdof_offsets) + for i in range(num_blocks): + for j in range(num_blocks): + blockA.SetBlock(i, j, BlockA_r.GetBlock(i,j)) + blockA.SetBlock(i, j+num_blocks, BlockA_i.GetBlock(i,j), -1.0) + blockA.SetBlock(i+num_blocks, j+num_blocks, BlockA_r.GetBlock(i,j)) + blockA.SetBlock(i+num_blocks, j, BlockA_i.GetBlock(i,j)) + X.Assign(0.0) + M = mfem.BlockDiagonalPreconditioner(tdof_offsets) + + if notstatic_cond: + solver_E = mfem.HypreBoomerAMG(BlockA_r.GetBlock(0,0)); + solver_E.SetPrintLevel(0) + solver_E.SetSystemsOptions(dim) + solver_H = mfem.HypreBoomerAMG(BlockA_r.GetBlock(1,1)) + solver_H.SetPrintLevel(0) + solver_H.SetSystemsOptions(dim) + M.SetDiagonalBlock(0,solver_E) + M.SetDiagonalBlock(1,solver_H) + M.SetDiagonalBlock(num_blocks,solver_E) + M.SetDiagonalBlock(num_blocks+1,solver_H) + + + solver_hatH = None + solver_hatE = mfem.HypreAMS(BlockA_r.GetBlock(skip, skip), hatE_fes) + solver_hatE.SetPrintLevel(0) + if dim == 2: + solver_hatH = mfem.HypreBoomerAMG(BlockA_r.GetBlock(skip+1, skip+1)) + solver_hatH.SetPrintLevel(0) + else: + solver_hatH = mfem.HypreAMS(BlockA_r.GetBlock(skip+1,skip+1), + hatH_fes) + solver_hatH.SetPrintLevel(0) + + M.SetDiagonalBlock(skip,solver_hatE) + M.SetDiagonalBlock(skip+1,solver_hatH) + M.SetDiagonalBlock(skip+num_blocks,solver_hatE) + M.SetDiagonalBlock(skip+num_blocks+1,solver_hatH) + + cg = mfem.CGSolver(MPI.COMM_WORLD) + cg.SetRelTol(1e-6) + cg.SetMaxIter(10000) + cg.SetPrintLevel(0) + cg.SetPreconditioner(M) + cg.SetOperator(blockA) + cg.Mult(B, X) + + #for i in range(num_blocks): + # delete &M.GetDiagonalBlock(i); + + num_iter = cg.GetNumIterations() + a.RecoverFEMSolution(X,x) - Array + residuals = a.ComputeResidual(x) - ParGridFunction E_r, E_i, H_r, H_i; + residual = residuals.Norml2() + maxresidual = residuals.Max() + globalresidual = residual * residual; - ParaViewDataCollection * paraview_dc = nullptr; + maxresidual = MPI.COMM_WORLD.allreduce(maxresidual, op=MPI.MAX) + globalresidual = MPI.COMM_WORLD.allreduce(globalresidual, op=MPI.SUM) + globalresidual = np.sqrt(globalresidual) + + E_r.MakeRef(E_fes,x, 0); + E_i.MakeRef(E_fes,x, offsets.Last()) + + H_r.MakeRef(H_fes,x, offsets[1]) + H_i.MakeRef(H_fes,x, offsets.Last()+offsets[1]) + + dofs = 0; + for i in range(trial_fes.Size()): + dofs += trial_fes[i].GlobalTrueVSize() + + + if exact_known: + E_ex_r = mfem.VectorFunctionCoefficient(dim, E_exact_r) + E_ex_i = mfem.VectorFunctionCoefficient(dim, E_exact_i) + H_ex_r = mfem.VectorFunctionCoefficient(dim, H_exact_r) + H_ex_i = mfem.VectorFunctionCoefficient(dim, H_exact_i) + E_err_r = E_r.ComputeL2Error(E_ex_r) + E_err_i = E_r.ComputeL2Error(E_ex_i) + H_err_r = H_r.ComputeL2Error(E_ex_r) + H_err_i = H_r.ComputeL2Error(E_ex_i) + L2Error = np.sqrt(E_err_r*E_err_r + E_err_i*E_err_i + + H_err_r*H_err_r + H_err_i*H_err_i ) + rate_err = 0 if it == 0 else dim*np.log(err0/L2Error)/np.log(dof0/dofs) + err0 = L2Error + + rate_res = 0.0 if it == 0 else dim*np.log(res0/globalresidual)/np.log(dof0/dofs) + + res0 = globalresidual; + dof0 = dofs; + + if myid == 0: + txt = ("{:5d}".format(it) + "|" + + "{:10d}".format(dof0) + "|" + + "{:4f}".format(2.0*runm) + " π | " ) + if exact_known: + txt = txt + ("{:10e}".format(err0) + "|" + + "{:6f}".format(rate_err) + " | " ) + + txt = txt + ("{:10e}".format(res0) + "|" + + "{:6d}".format(rate_err) + " | " + + "{:6d}".format(num_iter) + " | " ) + print(txt) + + if visualization: + keys = "jRcml\n" if it == 0 and dim == 2 else "" + + E_out_r = VisualizeField(E_out_r, "localhost", visport, E_r, + "Numerical Electric field (real part)", 0, 0, 500, 500, keys) + H_out_r = VisualizeField(H_out_r, "localhost", visport, H_r, + "Numerical Magnetic field (real part)", 0, 0, 500, 500, keys); + + if it == pr: + break + + if theta > 0.0: + elements_to_refine.SetSize(0); + for iel in range(pmesh.GetNE()): + if residuals[iel] > theta * maxresidual: + elements_to_refine.Append(iel) + pmesh.GeneralRefinement(elements_to_refine,1,1) + else: + pmesh.UniformRefinement(); + + if with_pml: + pml.SetAttributes(pmesh) + for i in range(trial_fes.Size()): + trial_fes[i].Update(False) + a.Update() - if static_cond: - a.EnableStaticCondensation() - for (int it = 0; it<=pr; it++) - { - a->Assemble(); - - Array ess_tdof_list; - Array ess_bdr; - if (pmesh.bdr_attributes.Size()) - { - ess_bdr.SetSize(pmesh.bdr_attributes.Max()); - ess_bdr = 1; - hatE_fes->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - if (pml) - { - ess_bdr = 0; - ess_bdr[1] = 1; - } - } - - // shift the ess_tdofs - for (int j = 0; j < ess_tdof_list.Size(); j++) - { - ess_tdof_list[j] += E_fes->GetTrueVSize() + H_fes->GetTrueVSize(); - } - - Array offsets(5); - offsets[0] = 0; - offsets[1] = E_fes->GetVSize(); - offsets[2] = H_fes->GetVSize(); - offsets[3] = hatE_fes->GetVSize(); - offsets[4] = hatH_fes->GetVSize(); - offsets.PartialSum(); - - Vector x(2*offsets.Last()); - x = 0.; - - if (prob != 2) - { - ParGridFunction hatE_gf_r(hatE_fes, x, offsets[2]); - ParGridFunction hatE_gf_i(hatE_fes, x, offsets.Last() + offsets[2]); - if (dim == 3) - { - hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr); - hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr); - } - else - { - hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr); - hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr); - } - } - - OperatorPtr Ah; - Vector X,B; - a->FormLinearSystem(ess_tdof_list,x,Ah, X,B); - - ComplexOperator * Ahc = Ah.As(); - - BlockOperator * BlockA_r = dynamic_cast(&Ahc->real()); - BlockOperator * BlockA_i = dynamic_cast(&Ahc->imag()); - - int num_blocks = BlockA_r->NumRowBlocks(); - Array tdof_offsets(2*num_blocks+1); - - tdof_offsets[0] = 0; - int skip = (static_cond) ? 0 : 2; - int k = (static_cond) ? 2 : 0; - for (int i=0; iGetTrueVSize(); - tdof_offsets[num_blocks+i+1] = trial_fes[i+k]->GetTrueVSize(); - } - tdof_offsets.PartialSum(); - - BlockOperator blockA(tdof_offsets); - for (int i = 0; iGetBlock(i,j)); - blockA.SetBlock(i,j+num_blocks,&BlockA_i->GetBlock(i,j), -1.0); - blockA.SetBlock(i+num_blocks,j+num_blocks,&BlockA_r->GetBlock(i,j)); - blockA.SetBlock(i+num_blocks,j,&BlockA_i->GetBlock(i,j)); - } - } - - X = 0.; - BlockDiagonalPreconditioner M(tdof_offsets); - - if (!static_cond) - { - HypreBoomerAMG * solver_E = new HypreBoomerAMG((HypreParMatrix &) - BlockA_r->GetBlock(0,0)); - solver_E->SetPrintLevel(0); - solver_E->SetSystemsOptions(dim); - HypreBoomerAMG * solver_H = new HypreBoomerAMG((HypreParMatrix &) - BlockA_r->GetBlock(1,1)); - solver_H->SetPrintLevel(0); - solver_H->SetSystemsOptions(dim); - M.SetDiagonalBlock(0,solver_E); - M.SetDiagonalBlock(1,solver_H); - M.SetDiagonalBlock(num_blocks,solver_E); - M.SetDiagonalBlock(num_blocks+1,solver_H); - } - - HypreSolver * solver_hatH = nullptr; - HypreAMS * solver_hatE = new HypreAMS((HypreParMatrix &)BlockA_r->GetBlock(skip, - skip), - hatE_fes); - solver_hatE->SetPrintLevel(0); - if (dim == 2) - { - solver_hatH = new HypreBoomerAMG((HypreParMatrix &)BlockA_r->GetBlock(skip+1, - skip+1)); - dynamic_cast(solver_hatH)->SetPrintLevel(0); - } - else - { - solver_hatH = new HypreAMS((HypreParMatrix &)BlockA_r->GetBlock(skip+1,skip+1), - hatH_fes); - dynamic_cast(solver_hatH)->SetPrintLevel(0); - } - - M.SetDiagonalBlock(skip,solver_hatE); - M.SetDiagonalBlock(skip+1,solver_hatH); - M.SetDiagonalBlock(skip+num_blocks,solver_hatE); - M.SetDiagonalBlock(skip+num_blocks+1,solver_hatH); - - CGSolver cg(MPI_COMM_WORLD); - cg.SetRelTol(1e-6); - cg.SetMaxIter(10000); - cg.SetPrintLevel(0); - cg.SetPreconditioner(M); - cg.SetOperator(blockA); - cg.Mult(B, X); - - for (int i = 0; iRecoverFEMSolution(X,x); - - Vector & residuals = a->ComputeResidual(x); - - real_t residual = residuals.Norml2(); - real_t maxresidual = residuals.Max(); - real_t globalresidual = residual * residual; - MPI_Allreduce(MPI_IN_PLACE, &maxresidual, 1, MPITypeMap::mpi_type, - MPI_MAX, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globalresidual, 1, - MPITypeMap::mpi_type, MPI_SUM, MPI_COMM_WORLD); - - globalresidual = sqrt(globalresidual); - - E_r.MakeRef(E_fes,x, 0); - E_i.MakeRef(E_fes,x, offsets.Last()); - - H_r.MakeRef(H_fes,x, offsets[1]); - H_i.MakeRef(H_fes,x, offsets.Last()+offsets[1]); - - int dofs = 0; - for (int i = 0; iGlobalTrueVSize(); - } - - real_t L2Error = 0.0; - real_t rate_err = 0.0; - - if (exact_known) - { - VectorFunctionCoefficient E_ex_r(dim,E_exact_r); - VectorFunctionCoefficient E_ex_i(dim,E_exact_i); - VectorFunctionCoefficient H_ex_r(dim,H_exact_r); - VectorFunctionCoefficient H_ex_i(dim,H_exact_i); - real_t E_err_r = E_r.ComputeL2Error(E_ex_r); - real_t E_err_i = E_i.ComputeL2Error(E_ex_i); - real_t H_err_r = H_r.ComputeL2Error(H_ex_r); - real_t H_err_i = H_i.ComputeL2Error(H_ex_i); - L2Error = sqrt( E_err_r*E_err_r + E_err_i*E_err_i - + H_err_r*H_err_r + H_err_i*H_err_i ); - rate_err = (it) ? dim*log(err0/L2Error)/log((real_t)dof0/dofs) : 0.0; - err0 = L2Error; - } - - real_t rate_res = (it) ? dim*log(res0/globalresidual)/log(( - real_t)dof0/dofs) : 0.0; - - res0 = globalresidual; - dof0 = dofs; - - if (myid == 0) - { - std::ios oldState(nullptr); - oldState.copyfmt(std::cout); - std::cout << std::right << std::setw(5) << it << " | " - << std::setw(10) << dof0 << " | " - << std::setprecision(1) << std::fixed - << std::setw(4) << 2.0*rnum << " π | " - << std::setprecision(3); - if (exact_known) - { - std::cout << std::setw(10) << std::scientific << err0 << " | " - << std::setprecision(2) - << std::setw(6) << std::fixed << rate_err << " | " ; - } - std::cout << std::setprecision(3) - << std::setw(10) << std::scientific << res0 << " | " - << std::setprecision(2) - << std::setw(6) << std::fixed << rate_res << " | " - << std::setw(6) << std::fixed << num_iter << " | " - << std::endl; - std::cout.copyfmt(oldState); - } - - if (visualization) - { - const char * keys = (it == 0 && dim == 2) ? "jRcml\n" : nullptr; - char vishost[] = "localhost"; - VisualizeField(E_out_r,vishost, visport, E_r, - "Numerical Electric field (real part)", 0, 0, 500, 500, keys); - VisualizeField(H_out_r,vishost, visport, H_r, - "Numerical Magnetic field (real part)", 501, 0, 500, 500, keys); - } - - if (paraview) - { - paraview_dc->SetCycle(it); - paraview_dc->SetTime((real_t)it); - paraview_dc->Save(); - } - - if (it == pr) - { - break; - } - - if (theta > 0.0) - { - elements_to_refine.SetSize(0); - for (int iel = 0; iel theta * maxresidual) - { - elements_to_refine.Append(iel); - } - } - pmesh.GeneralRefinement(elements_to_refine,1,1); - } - else - { - pmesh.UniformRefinement(); - } - if (pml) { pml->SetAttributes(&pmesh); } - for (int i =0; iUpdate(false); - } - a->Update(); - } if __name__ == "__main__": @@ -810,7 +779,7 @@ def run(meshfile='', prob=args.problem, sr=args.serial_ref, pr=args.parallel_ref, - eps=args.permittivity, + epsilon=args.permittivity, mu=args.permeability, delta_order=args.delta_order, rnum=args.number_of_wavelengths, From 26657dcb07a9ee8e35c2138a0dcea9bdfbe804f0 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Mon, 26 May 2025 11:52:54 -0400 Subject: [PATCH 07/22] (WIP)...pmaxwell.py --- mfem/_par/dpg.i | 40 ++----- mfem/_ser/dpg.i | 35 ++---- mfem/common/dpg_common.i | 47 ++++++++ miniapps/dpg/pmaxwell.py | 236 ++++++++++++++++++++++++++++++++++----- 4 files changed, 278 insertions(+), 80 deletions(-) create mode 100644 mfem/common/dpg_common.i diff --git a/mfem/_par/dpg.i b/mfem/_par/dpg.i index fd496f5b..d5ba6209 100644 --- a/mfem/_par/dpg.i +++ b/mfem/_par/dpg.i @@ -1,4 +1,7 @@ %module(package="mfem._par") dpg + +%feature("autodoc", "1"); + %{ #include "mfem.hpp" #include "numpy/arrayobject.h" @@ -6,10 +9,11 @@ #include "../common/pysolvers.hpp" #include "../common/pycoefficient.hpp" #include "../common/pyintrules.hpp" -#include "../common/pylininteg.hpp" +#include "../common/pylininteg.hpp" #include "../common/pybilininteg.hpp" #include "../common/pynonlininteg.hpp" #include "../common/io_stream.hpp" +using namespace mfem; %} %include "../common/existing_mfem_headers.i" @@ -20,39 +24,20 @@ import_array(); %} +%include "exception.i" +%include "../common/exception.i" + %inline %{ #include "miniapps/dpg/util/pml.cpp" #include "miniapps/dpg/util/blockstaticcond.cpp" -#include "miniapps/dpg/util/complexstaticcond.cpp" +#include "miniapps/dpg/util/complexstaticcond.cpp" #include "miniapps/dpg/util/weakform.cpp" -#include "miniapps/dpg/util/complexweakform.cpp" +#include "miniapps/dpg/util/complexweakform.cpp" #include "miniapps/dpg/util/pweakform.cpp" -#include "miniapps/dpg/util/pcomplexweakform.cpp" +#include "miniapps/dpg/util/pcomplexweakform.cpp" %} - -%include "exception.i" -%import "element.i" -%import "../common/exception.i" - -%import "array.i" -%import "vector.i" -%import "blockvector.i" -%import "bilininteg.i" -%import "lininteg.i" -%import "fespace.i" -%import "blockmatrix.i" -%import "operators.i" -%import "blockmatrix.i" -%import "blockoperator.i" -%import "complex_densemat.i" -%import "../common/exception.i" -%import "../common/io_stream_typemap.i" - -OSTREAM_TYPEMAP(std::ostream&) - -%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; -%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; +%include "../common/dpg_common.i" %include "miniapps/dpg/util/pml.hpp" %include "miniapps/dpg/util/blockstaticcond.hpp" @@ -62,5 +47,4 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/pweakform.hpp" %include "miniapps/dpg/util/pcomplexweakform.hpp" - #endif diff --git a/mfem/_ser/dpg.i b/mfem/_ser/dpg.i index a9328219..51c9276d 100644 --- a/mfem/_ser/dpg.i +++ b/mfem/_ser/dpg.i @@ -6,10 +6,11 @@ #include "../common/pysolvers.hpp" #include "../common/pycoefficient.hpp" #include "../common/pyintrules.hpp" -#include "../common/pylininteg.hpp" +#include "../common/pylininteg.hpp" #include "../common/pybilininteg.hpp" #include "../common/pynonlininteg.hpp" #include "../common/io_stream.hpp" +using namespace mfem; %} %include "../common/existing_mfem_headers.i" @@ -20,37 +21,18 @@ import_array(); %} +%include "exception.i" +%include "../common/exception.i" + %inline %{ #include "miniapps/dpg/util/pml.cpp" #include "miniapps/dpg/util/blockstaticcond.cpp" -#include "miniapps/dpg/util/complexstaticcond.cpp" +#include "miniapps/dpg/util/complexstaticcond.cpp" #include "miniapps/dpg/util/weakform.cpp" -#include "miniapps/dpg/util/complexweakform.cpp" +#include "miniapps/dpg/util/complexweakform.cpp" %} - -%include "exception.i" -%import "element.i" -%import "../common/exception.i" - -%import "array.i" -%import "vector.i" -%import "blockvector.i" -%import "bilininteg.i" -%import "lininteg.i" -%import "fespace.i" -%import "blockmatrix.i" -%import "operators.i" -%import "blockmatrix.i" -%import "blockoperator.i" -%import "complex_densemat.i" -%import "../common/exception.i" -%import "../common/io_stream_typemap.i" - -OSTREAM_TYPEMAP(std::ostream&) - -%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; -%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; +%include "../common/dpg_common.i" %include "miniapps/dpg/util/pml.hpp" %include "miniapps/dpg/util/blockstaticcond.hpp" @@ -58,4 +40,5 @@ OSTREAM_TYPEMAP(std::ostream&) %include "miniapps/dpg/util/weakform.hpp" %include "miniapps/dpg/util/complexweakform.hpp" + #endif diff --git a/mfem/common/dpg_common.i b/mfem/common/dpg_common.i new file mode 100644 index 00000000..f79ecfc8 --- /dev/null +++ b/mfem/common/dpg_common.i @@ -0,0 +1,47 @@ +%import "element.i" +%import "array.i" +%import "vector.i" +%import "blockvector.i" +%import "bilininteg.i" +%import "lininteg.i" +%import "fespace.i" +%import "blockmatrix.i" +%import "operators.i" +%import "blockmatrix.i" +%import "blockoperator.i" +%import "complex_densemat.i" +%import "../common/io_stream_typemap.i" + +OSTREAM_TYPEMAP(std::ostream&) + +%ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; +%ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; + +//%constant mfem::real_t detJ_r_function(const mfem::Vector &, mfem::CartesianPML *); + +%constant mfem::real_t detJ_r_function(const mfem::Vector &, mfem::CartesianPML *); +%constant mfem::real_t detJ_i_function(const mfem::Vector &, mfem::CartesianPML *); +%constant mfem::real_t abs_detJ_2_function(const mfem::Vector &, mfem::CartesianPML *); +%constant void Jt_J_detJinv_r_function(const mfem::Vector & , mfem::CartesianPML *, + mfem::DenseMatrix & ); +%constant void Jt_J_detJinv_i_function(const mfem::Vector & , mfem::CartesianPML *, + mfem::DenseMatrix &); +%constant void abs_Jt_J_detJinv_2_function(const mfem::Vector &, mfem::CartesianPML *, + mfem::DenseMatrix &); +%constant void detJ_Jt_J_inv_r_function(const mfem::Vector &, mfem::CartesianPML *, + mfem::DenseMatrix &); +%constant void detJ_Jt_J_inv_i_function(const mfem::Vector &, mfem::CartesianPML *, + mfem::DenseMatrix &); +%constant void abs_detJ_Jt_J_inv_2_function(const mfem::Vector &, mfem::CartesianPML *, + mfem::DenseMatrix &); + + +%rename(detJ_r_f) mfem::detJ_r_function; +%rename(detJ_i_f) mfem::detJ_i_function; +%rename(abs_detJ_2_f) mfem::abs_detJ_2_function; +%rename(Jt_J_detJinv_r_f) mfem::Jt_J_detJinv_r_function; +%rename(Jt_J_detJinv_i_f) mfem::Jt_J_detJinv_i_function; +%rename(abs_Jt_J_detJinv_2_f) mfem::abs_Jt_J_detJinv_2_function; +%rename(detJ_Jt_J_inv_r_f) mfem::detJ_Jt_J_inv_r_function; +%rename(detJ_Jt_J_inv_i_f) mfem::detJ_Jt_J_inv_i_function; +%rename(abs_detJ_Jt_J_inv_2_f) mfem::abs_detJ_Jt_J_inv_2_function; diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index dc69459f..a7921ff2 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -131,18 +131,18 @@ from numpy import pi import mfem.par as mfem +mdpg = mfem.dpg + +from mfem.common.bessel import jv as jn +from mfem.common.bessel import yv as yn + +from numba import njit, void, int32, int64, float64, complex128, types from mpi4py import MPI num_procs = MPI.COMM_WORLD.size myid = MPI.COMM_WORLD.rank smyid = '.'+'{:0>6d}'.format(myid) -prob_type = {"plane_wave", - "fichera_oven", - "pml_general", - "pml_plane_wave_scatter", - "pml_pointsource"} - visport = 19916; def VisualizeField(sock, vishost, visport, @@ -176,6 +176,189 @@ def VisualizeField(sock, vishost, visport, return sock +prob_type = ("plane_wave", + "fichera_oven", + "pml_general", + "pml_plane_wave_scatter", + "pml_pointsource") + +class Functions: + def __init__(self, dim, dimc, omega, epsilon, mu, iprob): + + + prob = prob_type[iprob] + print("params", dim, dimc, omega, epsilon, mu, prob) + + @njit(complex128[:](float64[:])) + def maxwell_solution(x): + E = np.zeros(dim, dtype=np.complex128) + + if prob == "plane_wave": + E[0] = np.exp(1j * omega * np.sum(x)) + + elif prob == "pml_plane_wave_scatter": + E[1] = exp(1j * omega * x[0]) + + elif prob == "fichera_oven": + if abs(x[2] - 3.0) < 1e-10: + E[0] = np.sin(pi*x[1]) + elif prob == "pml_pointsource": + k = omega * np.sqrt(epsilon * mu) + shift = np.array([-0.5]*dim); + + if dim == 2: + x0 = x[0] + shift[0] + x1 = x[1] + shift[1] + r = np.sqrt(x0 * x0 + x1 * x1) + beta = k * r; + + # Bessel functions + Ho = jn(0, beta).real + 1j * yn(0, beta).real + Ho_r = -k * jn(1, beta).real + 1j* yn(1, beta).real + Ho_rr = -k * k * (1. / beta * + (jn(1, beta).real + 1j * yn(1, beta).real) - + (jn(2, beta).real + 1j * yn(2, beta).real)) + + # First derivatives + r_x = x0 / r + r_y = x1 / r + r_xy = -(r_x / r) * r_y + r_xx = (1.0 / r) * (1.0 - r_x * r_x) + + val = 0.25 * 1j * Ho + val_xx = 0.25 * 1j * (r_xx * Ho_r + r_x * r_x * Ho_rr) + val_xy = 0.25 * 1j * (r_xy * Ho_r + r_x * r_y * Ho_rr) + E[0] = 1j / k * (k * k * val + val_xx) + E[1] = 1j / k * val_xy + else: + x0 = x[0] + shift[0] + x1 = x[1] + shift[1] + x2 = x[2] + shift[2] + r = sqrt(x0 * x0 + x1 * x1 + x2 * x2) + + r_x = x0 / r + r_y = x1 / r + r_z = x2 / r + r_xx = (1.0 / r) * (1.0 - r_x * r_x) + r_yx = -(r_y / r) * r_x + r_zx = -(r_z / r) * r_x + + val = np.exp(1j * k * r) / r + val_r = val / r * (1j * k * r - 1.) + val_rr = val / (r * r) * (-k * k * r * r + - 2. * 1j * k * r + 2.) + + val_xx = val_rr * r_x * r_x + val_r * r_xx + val_yx = val_rr * r_x * r_y + val_r * r_yx + val_zx = val_rr * r_x * r_z + val_r * r_zx + alpha = 1j * k / 4. / pi / k / k + E[0] = alpha * (k * k * val + val_xx) + E[1] = alpha * val_yx + E[2] = alpha * val_zx + else: + assert False, "should not come here" + return E + + @njit(complex128[:](float64[:])) + def maxwell_solution_curl(x): + curlE = np.zeros(dimc, dtype=np.complex128) + if prob == "plane_wave": + pw = np.exp(1j * omega * np.sum(x)) + if dim == 3: + curlE[0] = 0.0; + curlE[1] = 1j * omega * pw; + curlE[2] = -1j * omega * pw; + else: + curlE[0] = -1j * omega * pw; + elif prob == "pml_plane_wave_scatter": + pw = np.exp(1j * omega * (x[0])) + curlE[0] = 1j * omega * pw + else: + assert False, "should not come here" + return curlE + + @njit(complex128[:](float64[:])) + def maxwell_solution_curlcurl(x): + curlcurlE = np.zeros(dimc, dtype=np.complex128) + if prob == "plane_wave": + pw = np.exp(1j * omega * np.sum(x)) + if dim == 3: + curlcurlE[0] = 2. * omega * omega * pw + curlcurlE[1] = - omega * omega * pw + curlcurlE[2] = - omega * omega * pw + else: + curlcurlE[0] = omega * omega * pw + curlcurlE[1] = -omega * omega * pw + elif prob == "pml_plane_wave_scatter": + pw = np.exp(1j * omega * x[0]) + curlcurlE[1] = omega * omega * pw + else: + assert False, "should not come here" + return curlcurlE + + self.maxwell_solution = maxwell_solution + self.maxwell_solution_curl = maxwell_solution_curl + self.maxwell_solution_curlcurl = maxwell_solution_curlcurl + + @njit(complex128[:](float64[:])) + def curlH_exact(x): + # ∇ × H = ∇ × ∇ × E / ω μ + curlcurlE = maxwell_solution_curlcurl(x) + return 1j*curlcurlE / (omega * mu) + + @njit(complex128[:](float64[:])) + def hatE_exact(x): + if dim == 3: + E = maxwell_solution(x) + return E + else: + ret = np.zeros(2, dtype=np.complex128) + E = maxwell_solution(x) + ret[0] = E[0] + ret[1] = -E[1] + return ret + + @mfem.jit.vector(vdim=dim) + def E_exact_r(x): + E = maxwell_solution(x) + return E.real + + @mfem.jit.vector(vdim=dim) + def E_exact_i(x): + E = maxwell_solution(x) + return E.imag + + @mfem.jit.vector(vdim=dim) + def hatE_exact_r(x): + ret = hatE_exact(x) + return ret.real + + @mfem.jit.vector(vdim=dim) + def hatE_exact_i(x): + ret = hatE_exact(x) + return ret.imag + + self.hatE_exact_r = hatE_exact_r + self.hatE_exact_i = hatE_exact_i + + # J = -i ω ϵ E + ∇ × H + # J_r + iJ_i = -i ω ϵ (E_r + i E_i) + ∇ × (H_r + i H_i) + @mfem.jit.vector(vdim=dim) + def rhs_func_r(x): + # J_r = ω ϵ E_i + ∇ × H_r + E = maxwell_solution(x) + curlH = curlH_exact(x) + return omega * epsilon * E.imag * curlH.real + @mfem.jit.vector(vdim=dim) + def rhs_func_i(x): + # J_r = ω ϵ E_i + ∇ × H_r + E = maxwell_solution(x) + curlH = curlH_exact(x) + return -omega * epsilon * E.real * curlH.imag + + self.rhs_func_r = rhs_func_r + self.rhs_func_i = rhs_func_i + def run(meshfile='', order=1, @@ -196,7 +379,7 @@ def run(meshfile='', if prob == 0: exact_known = True; mesh_file = expanduser( - join(os.path.dirname(__file__), '..', 'data', meshfile)) + join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) elif prob == 1: meshfile = "meshes/fichera-waveguide.mesh"; @@ -208,7 +391,7 @@ def run(meshfile='', elif prob == 2: with_pml = True mesh_file = expanduser( - join(os.path.dirname(__file__), '..', 'data', meshfile)) + join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) else: with_pml = True @@ -227,6 +410,7 @@ def run(meshfile='', mesh.EnsureNCMesh(False) + pml = None if with_pml: assert False, "PML is not supported" @@ -313,12 +497,12 @@ def run(meshfile='', epsrot_cf = epsrot negepsrot_cf = negepsrot - detJ_r = mfem.dpg.PmlCoefficient(detJ_r_function,pml) - detJ_i = mfem.PmlCoefficient(detJ_i_function,pml) - abs_detJ_2 = mfem.PmlCoefficient(abs_detJ_2_function,pml) - detJ_Jt_J_inv_r = mfem.PmlMatrixCoefficient(dim,detJ_Jt_J_inv_r_function,pml) - detJ_Jt_J_inv_i = mfem.PmlMatrixCoefficient(dim,detJ_Jt_J_inv_i_function,pml) - abs_detJ_Jt_J_inv_2 = mfem.PmlMatrixCoefficient(dim,abs_detJ_Jt_J_inv_2_function,pml) + detJ_r = mdpg.PmlCoefficient(mdpg.detJ_r_function,pml) + detJ_i = mdpg.PmlCoefficient(mdpg.detJ_i_function,pml) + abs_detJ_2 = mdpg.PmlCoefficient(mdpg.abs_detJ_2_function,pml) + detJ_Jt_J_inv_r = mdpg.PmlMatrixCoefficient(dim, mdpg.detJ_Jt_J_inv_r_function,pml) + detJ_Jt_J_inv_i = mdpg.PmlMatrixCoefficient(dim, mdpg.detJ_Jt_J_inv_i_function,pml) + abs_detJ_Jt_J_inv_2 = mdpg.PmlMatrixCoefficient(dim, mdpg.abs_detJ_Jt_J_inv_2_function,pml) negmuomeg_detJ_r = mfem.ProductCoefficient(negmuomeg,detJ_r) negmuomeg_detJ_i = mfem.ProductCoefficient(negmuomeg,detJ_i) muomeg_detJ_r = mfem.ProductCoefficient(muomeg,detJ_r) @@ -357,7 +541,7 @@ def run(meshfile='', attrPML) - a = mfem.dpg.ParComplexDPGWeakForm(trial_fes,test_fec) + a = mdpg.ParComplexDPGWeakForm(trial_fes,test_fec) a.StoreMatrices() # needed for AMR # (E,∇ × F) @@ -376,7 +560,7 @@ def run(meshfile='', TrialSpace["H_space"], TestSpace["G_space"]) # < n×Ĥ ,G> - a.AddTrialIntegrator(mfem.TangentTraceIntegrator, None, + a.AddTrialIntegrator(mfem.TangentTraceIntegrator(), None, TrialSpace["hatH_space"], TestSpace["G_space"]) # test integrators @@ -396,7 +580,7 @@ def run(meshfile='', TrialSpace["H_space"], TestSpace["F_space"]) # < n×Ê,F> - a.AddTrialIntegrator(mfem.TangentTraceIntegrator, None, + a.AddTrialIntegrator(mfem.TangentTraceIntegrator(), None, TrialSpace["hatE_space"], TestSpace["F_space"]) @@ -439,7 +623,7 @@ def run(meshfile='', TrialSpace["H_space"], TestSpace["F_space"]) # < n×Ê,F> - a.AddTrialIntegrator(mfem.TraceIntegrator, None, + a.AddTrialIntegrator(mfem.TraceIntegrator(), None, TrialSpace["hatE_space"], TestSpace["F_space"]) # test integrators @@ -481,22 +665,22 @@ def run(meshfile='', assert False, "PML not supported yet" + fncs = Functions(dim, dimc, omega, epsilon, mu, prob) # RHS - f_rhs_r = mfem.VectorFunctionCoefficient(dim, rhs_func_r) - f_rhs_i = mfem.VectorFunctionCoefficient(dim, rhs_func_i) - f_source = mfem.VectorFunctionCoefficient(dim, source_function) - if prob == 0: + f_rhs_r = fncs.rhs_func_r + f_rhs_i = fncs.rhs_func_i a.AddDomainLFIntegrator(mfem.VectorFEDomainLFIntegrator(f_rhs_r), mfem.VectorFEDomainLFIntegrator(f_rhs_i), TestSpace["G_space"]) elif prob == 2: + f_source =fncs.source_function a.AddDomainLFIntegrator(mfem.VectorFEDomainLFIntegrator(f_source), None, TestSpace["G_space"]) - hatEex_r = mfem.VectorFunctionCoefficient(dim, hatE_exact_r) - hatEex_i = mfem.VectorFunctionCoefficient(dim, hatE_exact_i) + hatEex_r = fncs.hatE_exact_r + hatEex_i = fncs.hatE_exact_i if myid == 0: txt = "\n Ref |" + " Dofs |" + " ω |" @@ -724,7 +908,7 @@ def run(meshfile='', parser = ArgParser(description='Ex40 (Eikonal queation)') parser.add_argument('-m', '--mesh', - default='star.mesh', + default="inline-quad.mesh", action='store', type=str, help='Mesh file to use.') parser.add_argument('-o', '--order', @@ -741,7 +925,7 @@ def run(meshfile='', action='store', default=1.0, type=float, help="Permittivity of free space (or mass constant)."); parser.add_argument("-prob", "--problem", - action='store', default=1, type=int, + action='store', default=0, type=int, help="\n".join(("Problem case" " 0: plane wave, 1: Fichera 'oven', " " 2: Generic PML problem with point source given as a load " From e234fcaefdd2c9c90cab22968255b5d1f6518dbf Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Tue, 27 May 2025 06:56:00 -0400 Subject: [PATCH 08/22] (WIP) pmaxwell --- mfem/_par/blockoperator.i | 6 + mfem/_par/dpg.i | 1 + mfem/_par/handle.i | 17 + mfem/_ser/blockoperator.i | 3 + mfem/_ser/dpg.i | 1 - mfem/_ser/handle.i | 14 + mfem/common/dpg_common.i | 54 ++ miniapps/dpg/pmaxwell.py | 1013 +++++++++++++++++++------------------ 8 files changed, 625 insertions(+), 484 deletions(-) diff --git a/mfem/_par/blockoperator.i b/mfem/_par/blockoperator.i index c7fcae6c..4a41b816 100644 --- a/mfem/_par/blockoperator.i +++ b/mfem/_par/blockoperator.i @@ -73,9 +73,15 @@ if len(args) == 2: mfem::SparseMatrix *Opr2SparseMat(mfem::Operator *op) { return dynamic_cast(op); } + mfem::SparseMatrix *Opr2SparseMatrix(mfem::Operator *op) { + return dynamic_cast(op); + } mfem::HypreParMatrix *Opr2HypreParMat(mfem::Operator *op) { return dynamic_cast(op); } + mfem::HypreParMatrix *Opr2HypreParMatrix(mfem::Operator *op) { + return dynamic_cast(op); + } %} %include "linalg/blockoperator.hpp" diff --git a/mfem/_par/dpg.i b/mfem/_par/dpg.i index d5ba6209..c7d1c9a2 100644 --- a/mfem/_par/dpg.i +++ b/mfem/_par/dpg.i @@ -47,4 +47,5 @@ import_array(); %include "miniapps/dpg/util/pweakform.hpp" %include "miniapps/dpg/util/pcomplexweakform.hpp" + #endif diff --git a/mfem/_par/handle.i b/mfem/_par/handle.i index 2a863553..c6838981 100644 --- a/mfem/_par/handle.i +++ b/mfem/_par/handle.i @@ -29,6 +29,7 @@ import_array(); %import "../common/exception.i" %import "operators.i" +%import "complex_operator.i" #ifdef MFEM_USE_MPI %import "hypre.i" @@ -57,6 +58,13 @@ GET_RENAME(HypreParMatrix) RESET_RENAME(HypreParMatrix) CONVERT_FROM_RENAME(HypreParMatrix) +//CONSTRUCTOR_WRAP(ComplexOperator) +AS_RENAME(ComplexOperator) +IS_RENAME(ComplexOperator) +GET_RENAME(ComplexOperator) +RESET_RENAME(ComplexOperator) +CONVERT_FROM_RENAME(ComplexOperator) + //CONSTRUCTOR_RENAME(ComplexHypreParMatrix) AS_RENAME(ComplexHypreParMatrix) IS_RENAME(ComplexHypreParMatrix) @@ -94,6 +102,13 @@ GET_WRAP(HypreParMatrix) RESET_WRAP(HypreParMatrix) CONVERT_FROM_WRAP(HypreParMatrix) +//CONSTRUCTOR_WRAP(ComplexOperator) +AS_WRAP(ComplexOperator) +IS_WRAP(ComplexOperator) +GET_WRAP(ComplexOperator) +RESET_WRAP(ComplexOperator) +CONVERT_FROM_WRAP(ComplexOperator) + //CONSTRUCTOR_WRAP(ComplexHypreParMatrix) AS_WRAP(ComplexHypreParMatrix) IS_WRAP(ComplexHypreParMatrix) @@ -110,3 +125,5 @@ RESET_WRAP(PetscParMatrix) CONVERT_FROM_WRAP(PetscParMatrix) #endif + + diff --git a/mfem/_ser/blockoperator.i b/mfem/_ser/blockoperator.i index 53ba7c1f..0590eaf5 100644 --- a/mfem/_ser/blockoperator.i +++ b/mfem/_ser/blockoperator.i @@ -74,6 +74,9 @@ if len(args) == 2: mfem::SparseMatrix *Opr2SparseMat(mfem::Operator *op) { return dynamic_cast(op); } + mfem::SparseMatrix *Opr2SparseMatrix(mfem::Operator *op) { + return dynamic_cast(op); + } %} %include "linalg/blockoperator.hpp" diff --git a/mfem/_ser/dpg.i b/mfem/_ser/dpg.i index 51c9276d..fe2dcdde 100644 --- a/mfem/_ser/dpg.i +++ b/mfem/_ser/dpg.i @@ -40,5 +40,4 @@ import_array(); %include "miniapps/dpg/util/weakform.hpp" %include "miniapps/dpg/util/complexweakform.hpp" - #endif diff --git a/mfem/_ser/handle.i b/mfem/_ser/handle.i index 7471aea4..48e9a3a9 100644 --- a/mfem/_ser/handle.i +++ b/mfem/_ser/handle.i @@ -53,6 +53,13 @@ GET_RENAME(SparseMatrix) RESET_RENAME(SparseMatrix) CONVERT_FROM_RENAME(SparseMatrix) +//CONSTRUCTOR_WRAP(ComplexOperator) +AS_RENAME(ComplexOperator) +IS_RENAME(ComplexOperator) +GET_RENAME(ComplexOperator) +RESET_RENAME(ComplexOperator) +CONVERT_FROM_RENAME(ComplexOperator) + %include "linalg/handle.hpp" %pythoncode %{ @@ -67,4 +74,11 @@ GET_WRAP(SparseMatrix) RESET_WRAP(SparseMatrix) CONVERT_FROM_WRAP(SparseMatrix) +//CONSTRUCTOR_WRAP(ComplexOperator) +AS_WRAP(ComplexOperator) +IS_WRAP(ComplexOperator) +GET_WRAP(ComplexOperator) +RESET_WRAP(ComplexOperator) +CONVERT_FROM_WRAP(ComplexOperator) + diff --git a/mfem/common/dpg_common.i b/mfem/common/dpg_common.i index f79ecfc8..6d1bf243 100644 --- a/mfem/common/dpg_common.i +++ b/mfem/common/dpg_common.i @@ -17,6 +17,60 @@ OSTREAM_TYPEMAP(std::ostream&) %ignore mfem::BlockStaticCondensation::ConvertListToReducedTrueDofs; %ignore mfem::ComplexBlockStaticCondensation::ConvertListToReducedTrueDofs; +namespace mfem { +%pythonprepend DPGWeakForm::AddTrialIntegrator %{ + if not hasattr(self, "_integrators"): self._integrators = [] + di = bfi + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + %} +%pythonprepend DPGWeakForm::AddTestIntegrator %{ + if not hasattr(self, "_integrators"): self._integrators = [] + di = bfi + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + %} +%pythonprepend DPGWeakForm::AddDomainLFIntegrator %{ + if not hasattr(self, "_integrators"): self._integrators = [] + di = lfi + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + %} +%pythonprepend ComplexDPGWeakForm::AddTrialIntegrator %{ + if not hasattr(self, "_integrators"): self._integrators = [] + di = bfi_r + if di is not None: + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + di = bfi_i + if di is not None: + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + %} +%pythonprepend ComplexDPGWeakForm::AddTestIntegrator %{ + if not hasattr(self, "_integrators"): self._integrators = [] + di = bfi_r + if di is not None: + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + di = bfi_i + if di is not None: + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + %} +%pythonprepend ComplexDPGWeakForm::AddDomainLFIntegrator %{ + if not hasattr(self, "_integrators"): self._integrators = [] + di = lfi_r + if di is not None: + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + di = lfi_i + if di is not None: + self._integrators.append(di) + di.thisown=0 ## ownership is C++ side + %} +} + //%constant mfem::real_t detJ_r_function(const mfem::Vector &, mfem::CartesianPML *); %constant mfem::real_t detJ_r_function(const mfem::Vector &, mfem::CartesianPML *); diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index a7921ff2..5b5ca5de 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -1,129 +1,133 @@ ## -## MFEM Ultraweak DPG Maxwell parallel example +# MFEM Ultraweak DPG Maxwell parallel example ## -## Compile with: make pmaxwell +# Compile with: make pmaxwell ## -## sample run -## mpirun -np 4 python pmaxwell.py -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0 -## mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0 -## mpirun -np 4 python pmaxwell.py -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0 -## mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2 -## mpirun -np 4 python pmaxwell.py -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3 -## mpirun -np 4 python pmaxwell.py -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4 - -## AMR run. Note that this is a computationally intensive sample run. -## We recommend trying it on a large machine with more mpi ranks -## mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc - -## Description: -## This example code demonstrates the use of MFEM to define and solve -## the "ultraweak" (UW) DPG formulation for the Maxwell problem - -## ∇×(1/μ ∇×E) - ω² ϵ E = Ĵ , in Ω -## E×n = E₀ , on ∂Ω - -## It solves the following kinds of problems -## 1) Known exact solutions with error convergence rates -## a) A manufactured solution problem where E is a plane beam -## 2) Fichera "microwave" problem -## 3) PML problems -## a) Generic PML problem with point source given by the load -## b) Plane wave scattering from a square -## c) PML problem with a point source prescribed on the boundary - -## The DPG UW deals with the First Order System -## i ω μ H + ∇ × E = 0, in Ω -## -i ω ϵ E + ∇ × H = J, in Ω -## E × n = E_0, on ∂Ω -## Note: Ĵ = -iωJ - -## The ultraweak-DPG formulation is obtained by integration by parts of both -## equations and the introduction of trace unknowns on the mesh skeleton - -## in 2D -## E is vector valued and H is scalar. -## (∇ × E, F) = (E, ∇ × F) + < n × E , F> -## or (∇ ⋅ AE , F) = (AE, ∇ F) + < AE ⋅ n, F> -## where A = [0 1; -1 0]; - -## E ∈ (L²(Ω))² , H ∈ L²(Ω) -## Ê ∈ H^-1/2(Γₕ), Ĥ ∈ H^1/2(Γₕ) -## i ω μ (H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹ -## -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) -## Ê = E₀ on ∂Ω -## ------------------------------------------------------------------------- -## | | E | H | Ê | Ĥ | RHS | -## ------------------------------------------------------------------------- -## | F | (E,∇ × F) | i ω μ (H,F) | < Ê, F > | | | -## | | | | | | | -## | G | -i ω ϵ (E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) | -## where (F,G) ∈ H¹ × H(curl,Ω) - -## in 3D -## E,H ∈ (L^2(Ω))³ -## Ê ∈ H_0^1/2(Ω)(curl, Γₕ), Ĥ ∈ H^-1/2(curl, Γₕ) -## i ω μ (H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω) -## -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) -## Ê × n = E₀ on ∂Ω -## ------------------------------------------------------------------------- -## | | E | H | Ê | Ĥ | RHS | -## ------------------------------------------------------------------------- -## | F | (E,∇ × F) | i ω μ (H,F) | < n × Ê, F > | | | -## | | | | | | | -## | G | -i ω ϵ (E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) | -## where (F,G) ∈ H(curl,Ω) × H(curl,Ω) - -## Here we use the "Adjoint Graph" norm on the test space i.e., -## ||(F,G)||²ᵥ = ||A^*(F,G)||² + ||(F,G)||² where A is the -## maxwell operator defined by (1) - -## The PML formulation is - -## ∇×(1/μ α ∇×E) - ω² ϵ β E = Ĵ , in Ω -## E×n = E₀ , on ∂Ω - -## where α = |J|⁻¹ Jᵀ J (in 2D it's the scalar |J|⁻¹), -## β = |J| J⁻¹ J⁻ᵀ, J is the Jacobian of the stretching map -## and |J| its determinant. - -## The first order system reads -## i ω μ α⁻¹ H + ∇ × E = 0, in Ω -## -i ω ϵ β E + ∇ × H = J, in Ω -## E × n = E₀, on ∂Ω - -## and the ultraweak formulation is - -## in 2D -## E ∈ (L²(Ω))² , H ∈ L²(Ω) -## Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ) -## i ω μ (α⁻¹ H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹ -## -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) -## Ê = E₀ on ∂Ω -## --------------------------------------------------------------------------------- -## | | E | H | Ê | Ĥ | RHS | -## --------------------------------------------------------------------------------- -## | F | (E,∇ × F) | i ω μ (α⁻¹ H,F) | < Ê, F > | | | -## | | | | | | | -## | G | -i ω ϵ (β E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) | - -## where (F,G) ∈ H¹ × H(curl,Ω) +# sample run +# mpirun -np 4 python pmaxwell.py -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0 +# mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0 +# mpirun -np 4 python pmaxwell.py -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0 +# mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2 +# mpirun -np 4 python pmaxwell.py -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3 +# mpirun -np 4 python pmaxwell.py -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4 + +# AMR run. Note that this is a computationally intensive sample run. +# We recommend trying it on a large machine with more mpi ranks +# mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc + +# Description: +# This example code demonstrates the use of MFEM to define and solve +# the "ultraweak" (UW) DPG formulation for the Maxwell problem + +# ∇×(1/μ ∇×E) - ω² ϵ E = Ĵ , in Ω +# E×n = E₀ , on ∂Ω + +# It solves the following kinds of problems +# 1) Known exact solutions with error convergence rates +# a) A manufactured solution problem where E is a plane beam +# 2) Fichera "microwave" problem +# 3) PML problems +# a) Generic PML problem with point source given by the load +# b) Plane wave scattering from a square +# c) PML problem with a point source prescribed on the boundary + +# The DPG UW deals with the First Order System +# i ω μ H + ∇ × E = 0, in Ω +# -i ω ϵ E + ∇ × H = J, in Ω +# E × n = E_0, on ∂Ω +# Note: Ĵ = -iωJ + +# The ultraweak-DPG formulation is obtained by integration by parts of both +# equations and the introduction of trace unknowns on the mesh skeleton + +# in 2D +# E is vector valued and H is scalar. +# (∇ × E, F) = (E, ∇ × F) + < n × E , F> +# or (∇ ⋅ AE , F) = (AE, ∇ F) + < AE ⋅ n, F> +# where A = [0 1; -1 0]; + +# E ∈ (L²(Ω))² , H ∈ L²(Ω) +# Ê ∈ H^-1/2(Γₕ), Ĥ ∈ H^1/2(Γₕ) +# i ω μ (H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹ +# -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +# Ê = E₀ on ∂Ω +# ------------------------------------------------------------------------- +# | | E | H | Ê | Ĥ | RHS | +# ------------------------------------------------------------------------- +# | F | (E,∇ × F) | i ω μ (H,F) | < Ê, F > | | | +# | | | | | | | +# | G | -i ω ϵ (E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) | +# where (F,G) ∈ H¹ × H(curl,Ω) + +# in 3D +# E,H ∈ (L^2(Ω))³ +# Ê ∈ H_0^1/2(Ω)(curl, Γₕ), Ĥ ∈ H^-1/2(curl, Γₕ) +# i ω μ (H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω) +# -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +# Ê × n = E₀ on ∂Ω +# ------------------------------------------------------------------------- +# | | E | H | Ê | Ĥ | RHS | +# ------------------------------------------------------------------------- +# | F | (E,∇ × F) | i ω μ (H,F) | < n × Ê, F > | | | +# | | | | | | | +# | G | -i ω ϵ (E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) | +# where (F,G) ∈ H(curl,Ω) × H(curl,Ω) + +# Here we use the "Adjoint Graph" norm on the test space i.e., +# ||(F,G)||²ᵥ = ||A^*(F,G)||² + ||(F,G)||² where A is the +# maxwell operator defined by (1) + +# The PML formulation is + +# ∇×(1/μ α ∇×E) - ω² ϵ β E = Ĵ , in Ω +# E×n = E₀ , on ∂Ω + +# where α = |J|⁻¹ Jᵀ J (in 2D it's the scalar |J|⁻¹), +# β = |J| J⁻¹ J⁻ᵀ, J is the Jacobian of the stretching map +# and |J| its determinant. + +# The first order system reads +# i ω μ α⁻¹ H + ∇ × E = 0, in Ω +# -i ω ϵ β E + ∇ × H = J, in Ω +# E × n = E₀, on ∂Ω + +# and the ultraweak formulation is + +# in 2D +# E ∈ (L²(Ω))² , H ∈ L²(Ω) +# Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ) +# i ω μ (α⁻¹ H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹ +# -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +# Ê = E₀ on ∂Ω +# --------------------------------------------------------------------------------- +# | | E | H | Ê | Ĥ | RHS | +# --------------------------------------------------------------------------------- +# | F | (E,∇ × F) | i ω μ (α⁻¹ H,F) | < Ê, F > | | | +# | | | | | | | +# | G | -i ω ϵ (β E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) | + +# where (F,G) ∈ H¹ × H(curl,Ω) ## -## in 3D -## E,H ∈ (L^2(Ω))³ -## Ê ∈ H_0^1/2(Ω)(curl, Γ_h), Ĥ ∈ H^-1/2(curl, Γₕ) -## i ω μ (α⁻¹ H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω) -## -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) -## Ê × n = E_0 on ∂Ω -## ------------------------------------------------------------------------------- -## | | E | H | Ê | Ĥ | RHS | -## ------------------------------------------------------------------------------- -## | F | ( E,∇ × F) | i ω μ (α⁻¹ H,F) | < n × Ê, F > | | | -## | | | | | | | -## | G | -iωϵ (β E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) | -## where (F,G) ∈ H(curl,Ω) × H(curl,Ω) - -## For more information see https:##doi.org/10.1016/j.camwa.2021.01.017 +# in 3D +# E,H ∈ (L^2(Ω))³ +# Ê ∈ H_0^1/2(Ω)(curl, Γ_h), Ĥ ∈ H^-1/2(curl, Γₕ) +# i ω μ (α⁻¹ H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω) +# -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω) +# Ê × n = E_0 on ∂Ω +# ------------------------------------------------------------------------------- +# | | E | H | Ê | Ĥ | RHS | +# ------------------------------------------------------------------------------- +# | F | ( E,∇ × F) | i ω μ (α⁻¹ H,F) | < n × Ê, F > | | | +# | | | | | | | +# | G | -iωϵ (β E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) | +# where (F,G) ∈ H(curl,Ω) × H(curl,Ω) + +# For more information see https:##doi.org/10.1016/j.camwa.2021.01.017 +from mpi4py import MPI +from numba import njit, void, int32, int64, float64, complex128, types +from mfem.common.bessel import yv as yn +from mfem.common.bessel import jv as jn import os from os.path import expanduser, join @@ -133,62 +137,61 @@ import mfem.par as mfem mdpg = mfem.dpg -from mfem.common.bessel import jv as jn -from mfem.common.bessel import yv as yn - -from numba import njit, void, int32, int64, float64, complex128, types -from mpi4py import MPI num_procs = MPI.COMM_WORLD.size myid = MPI.COMM_WORLD.rank smyid = '.'+'{:0>6d}'.format(myid) -visport = 19916; +visport = 19916 + def VisualizeField(sock, vishost, visport, gf, title, - x, y, w, h, keys, vec): - + x=0, y=0, w=400, h=400, keys='', vec=False): + mesh = gf.FESpace().GetMesh() - sock = None newly_opened = False while True: if sock is None: - sock = mfem.socketstream("localhost", visport) - sock.precision(8); - newly_opened = True + sock = mfem.socketstream("localhost", visport) + sock.precision(8) + newly_opened = True - sock << "solution\n"; + sock << "solution\n" sock << mesh << gf - if newly_opend: + if newly_opened: sock << "window_title '" << title << "'\n" sock << "window_geometry " sock << x << " " << y << " " << w << " " << h << "\n" if keys != '': sock << "keys " << keys << "\n" + else: + sock << "keys maaAc\n" if vec: sock << "vvv" sock.flush() + if sock.is_open(): + break return sock + prob_type = ("plane_wave", "fichera_oven", "pml_general", "pml_plane_wave_scatter", "pml_pointsource") + class Functions: def __init__(self, dim, dimc, omega, epsilon, mu, iprob): - prob = prob_type[iprob] - print("params", dim, dimc, omega, epsilon, mu, prob) - + @njit(complex128[:](float64[:])) def maxwell_solution(x): E = np.zeros(dim, dtype=np.complex128) @@ -201,20 +204,20 @@ def maxwell_solution(x): elif prob == "fichera_oven": if abs(x[2] - 3.0) < 1e-10: - E[0] = np.sin(pi*x[1]) + E[0] = np.sin(pi*x[1]) elif prob == "pml_pointsource": k = omega * np.sqrt(epsilon * mu) - shift = np.array([-0.5]*dim); + shift = np.array([-0.5]*dim) if dim == 2: x0 = x[0] + shift[0] - x1 = x[1] + shift[1] + x1 = x[1] + shift[1] r = np.sqrt(x0 * x0 + x1 * x1) - beta = k * r; + beta = k * r # Bessel functions Ho = jn(0, beta).real + 1j * yn(0, beta).real - Ho_r = -k * jn(1, beta).real + 1j* yn(1, beta).real + Ho_r = -k * jn(1, beta).real + 1j * yn(1, beta).real Ho_rr = -k * k * (1. / beta * (jn(1, beta).real + 1j * yn(1, beta).real) - (jn(2, beta).real + 1j * yn(2, beta).real)) @@ -233,7 +236,7 @@ def maxwell_solution(x): else: x0 = x[0] + shift[0] x1 = x[1] + shift[1] - x2 = x[2] + shift[2] + x2 = x[2] + shift[2] r = sqrt(x0 * x0 + x1 * x1 + x2 * x2) r_x = x0 / r @@ -265,11 +268,11 @@ def maxwell_solution_curl(x): if prob == "plane_wave": pw = np.exp(1j * omega * np.sum(x)) if dim == 3: - curlE[0] = 0.0; - curlE[1] = 1j * omega * pw; - curlE[2] = -1j * omega * pw; + curlE[0] = 0.0 + curlE[1] = 1j * omega * pw + curlE[2] = -1j * omega * pw else: - curlE[0] = -1j * omega * pw; + curlE[0] = -1j * omega * pw elif prob == "pml_plane_wave_scatter": pw = np.exp(1j * omega * (x[0])) curlE[0] = 1j * omega * pw @@ -277,18 +280,18 @@ def maxwell_solution_curl(x): assert False, "should not come here" return curlE - @njit(complex128[:](float64[:])) + @njit(complex128[:](float64[:])) def maxwell_solution_curlcurl(x): curlcurlE = np.zeros(dimc, dtype=np.complex128) if prob == "plane_wave": - pw = np.exp(1j * omega * np.sum(x)) - if dim == 3: - curlcurlE[0] = 2. * omega * omega * pw - curlcurlE[1] = - omega * omega * pw - curlcurlE[2] = - omega * omega * pw - else: - curlcurlE[0] = omega * omega * pw - curlcurlE[1] = -omega * omega * pw + pw = np.exp(1j * omega * np.sum(x)) + if dim == 3: + curlcurlE[0] = 2. * omega * omega * pw + curlcurlE[1] = - omega * omega * pw + curlcurlE[2] = - omega * omega * pw + else: + curlcurlE[0] = omega * omega * pw + curlcurlE[1] = -omega * omega * pw elif prob == "pml_plane_wave_scatter": pw = np.exp(1j * omega * x[0]) curlcurlE[1] = omega * omega * pw @@ -299,48 +302,65 @@ def maxwell_solution_curlcurl(x): self.maxwell_solution = maxwell_solution self.maxwell_solution_curl = maxwell_solution_curl self.maxwell_solution_curlcurl = maxwell_solution_curlcurl - - @njit(complex128[:](float64[:])) + + @njit(complex128[:](float64[:])) def curlH_exact(x): # ∇ × H = ∇ × ∇ × E / ω μ curlcurlE = maxwell_solution_curlcurl(x) return 1j*curlcurlE / (omega * mu) - - @njit(complex128[:](float64[:])) + + @njit(complex128[:](float64[:])) + def H_exact(x): + H = maxwell_solution_curl(x)*1j/omega/mu + return H + + @njit(complex128[:](float64[:])) def hatE_exact(x): if dim == 3: E = maxwell_solution(x) return E else: - ret = np.zeros(2, dtype=np.complex128) + ret = np.zeros(2, dtype=np.complex128) E = maxwell_solution(x) ret[0] = E[0] ret[1] = -E[1] return ret - @mfem.jit.vector(vdim=dim) + @mfem.jit.vector(vdim=dim) def E_exact_r(x): E = maxwell_solution(x) return E.real - @mfem.jit.vector(vdim=dim) + @mfem.jit.vector(vdim=dim) def E_exact_i(x): E = maxwell_solution(x) return E.imag - - @mfem.jit.vector(vdim=dim) + + @mfem.jit.vector(vdim=dim) + def H_exact_r(x): + return H_exact(x).real + + @mfem.jit.vector(vdim=dim) + def H_exact_i(x): + return H_exact(x).imag + + @mfem.jit.vector(vdim=dim) def hatE_exact_r(x): ret = hatE_exact(x) return ret.real - - @mfem.jit.vector(vdim=dim) + + @mfem.jit.vector(vdim=dim) def hatE_exact_i(x): ret = hatE_exact(x) return ret.imag - + + self.E_exact_r = E_exact_r + self.E_exact_i = E_exact_i + self.H_exact_r = H_exact_r + self.H_exact_i = H_exact_i self.hatE_exact_r = hatE_exact_r self.hatE_exact_i = hatE_exact_i - + # J = -i ω ϵ E + ∇ × H # J_r + iJ_i = -i ω ϵ (E_r + i E_i) + ∇ × (H_r + i H_i) @mfem.jit.vector(vdim=dim) @@ -348,24 +368,25 @@ def rhs_func_r(x): # J_r = ω ϵ E_i + ∇ × H_r E = maxwell_solution(x) curlH = curlH_exact(x) - return omega * epsilon * E.imag * curlH.real + return omega * epsilon * E.imag * curlH.real + @mfem.jit.vector(vdim=dim) def rhs_func_i(x): # J_r = ω ϵ E_i + ∇ × H_r E = maxwell_solution(x) curlH = curlH_exact(x) - return -omega * epsilon * E.real * curlH.imag + return -omega * epsilon * E.real * curlH.imag self.rhs_func_r = rhs_func_r - self.rhs_func_i = rhs_func_i + self.rhs_func_i = rhs_func_i def run(meshfile='', order=1, - delta_order=1, + delta_order=1, prob=0, - sr=0, - pr=1, + sr=0, + pr=1, epsilon=1.0, mu=1.0, rnum=1.0, @@ -375,30 +396,29 @@ def run(meshfile='', omega = 2.*pi*rnum with_pml = False - + if prob == 0: - exact_known = True; - mesh_file = expanduser( - join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) - + exact_known = True + mesh_file = expanduser( + join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) + elif prob == 1: - meshfile = "meshes/fichera-waveguide.mesh"; - omega = 5.0; - rnum = omega/(2.*pi) - mesh_file = expanduser( - join(os.path.dirname(__file__), meshfile)) - + meshfile = "meshes/fichera-waveguide.mesh" + omega = 5.0 + rnum = omega/(2.*pi) + mesh_file = expanduser( + join(os.path.dirname(__file__), meshfile)) + elif prob == 2: - with_pml = True - mesh_file = expanduser( - join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) - + with_pml = True + mesh_file = expanduser( + join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) + else: - with_pml = True - mesh_file = "meshes/scatter.mesh" - mesh_file = expanduser( - join(os.path.dirname(__file__), meshfile)) - + with_pml = True + mesh_file = "meshes/scatter.mesh" + mesh_file = expanduser( + join(os.path.dirname(__file__), meshfile)) mesh = mfem.Mesh(mesh_file, 1, 1) dim = mesh.Dimension() @@ -406,35 +426,34 @@ def run(meshfile='', dimc = 3 if dim == 3 else 1 for i in range(sr): - mesh.UniformRefinement(); + mesh.UniformRefinement() mesh.EnsureNCMesh(False) - pml = None if with_pml: assert False, "PML is not supported" - + pmesh = mfem.ParMesh(MPI.COMM_WORLD, mesh) del mesh attr = mfem.intArray() - attrPML= mfem.intArray() + attrPML = mfem.intArray() # Define spaces TrialSpace = {"E_space": 0, "H_space": 1, "hatE_space": 2, - "hatH_space": 3,} + "hatH_space": 3, } TestSpace = {"F_space": 0, - "G_space": 1,} + "G_space": 1, } # Vector L2 L2 space for E E_fec = mfem.L2_FECollection(order-1, dim) E_fes = mfem.ParFiniteElementSpace(pmesh, E_fec, dim) - + # Vector L2 L2 space for H H_fec = mfem.L2_FECollection(order-1, dim) - H_fes = mfem.ParFiniteElementSpace(pmesh, H_fec, dim) + H_fes = mfem.ParFiniteElementSpace(pmesh, H_fec, dimc) # H^-1/2 (curl) space for Ê test_order = order + delta_order @@ -447,12 +466,10 @@ def run(meshfile='', hatE_fec = mfem.RT_Trace_FECollection(order-1, dim) hatH_fec = mfem.H1_Trace_FECollection(order, dim) F_fec = mfem.H1_FECollection(test_order, dim) - + hatE_fes = mfem.ParFiniteElementSpace(pmesh, hatE_fec) hatH_fes = mfem.ParFiniteElementSpace(pmesh, hatH_fec) G_fec = mfem.ND_FECollection(test_order, dim) - - trial_fes = mfem.ParFiniteElementSpaceArray() test_fec = mfem.FiniteElementCollectionArray() @@ -462,9 +479,9 @@ def run(meshfile='', trial_fes.Append(hatH_fes) test_fec.Append(F_fec) test_fec.Append(G_fec) - + # Bilinear form coefficients - one = mfem.ConstantCoefficient(1.0); + one = mfem.ConstantCoefficient(1.0) eps2omeg2 = mfem.ConstantCoefficient(epsilon*epsilon*omega*omega) mu2omeg2 = mfem.ConstantCoefficient(mu*mu*omega*omega) muomeg = mfem.ConstantCoefficient(mu*omega) @@ -473,20 +490,20 @@ def run(meshfile='', negmuomeg = mfem.ConstantCoefficient(-mu*omega) # for the 2D case - rot_mat = mfem.DenseMatrix(np.array([[0, 1.],[-1, 0]])) - rot =mfem.MatrixConstantCoefficient(rot_mat) - epsrot = mfem.ScalarMatrixProductCoefficient(epsomeg,rot) - negepsrot = mfem.ScalarMatrixProductCoefficient(negepsomeg,rot) + rot_mat = mfem.DenseMatrix(np.array([[0, 1.], [-1, 0]])) + rot = mfem.MatrixConstantCoefficient(rot_mat) + epsrot = mfem.ScalarMatrixProductCoefficient(epsomeg, rot) + negepsrot = mfem.ScalarMatrixProductCoefficient(negepsomeg, rot) if with_pml: - epsomeg_cf = mfem.RestrictedCoefficient(epsomeg,attr) - negepsomeg_cf = mfem.RestrictedCoefficient(negepsomeg,attr) - eps2omeg2_cf = mfem.RestrictedCoefficient(eps2omeg2,attr) - muomeg_cf = mfem.RestrictedCoefficient(muomeg,attr) - negmuomeg_cf = mfem.RestrictedCoefficient(negmuomeg,attr) - mu2omeg2_cf = mfem.RestrictedCoefficient(mu2omeg2,attr) - epsrot_cf = mfem.MatrixRestrictedCoefficient(epsrot,attr) - negepsrot_cf = mfem.MatrixRestrictedCoefficient(negepsrot,attr) + epsomeg_cf = mfem.RestrictedCoefficient(epsomeg, attr) + negepsomeg_cf = mfem.RestrictedCoefficient(negepsomeg, attr) + eps2omeg2_cf = mfem.RestrictedCoefficient(eps2omeg2, attr) + muomeg_cf = mfem.RestrictedCoefficient(muomeg, attr) + negmuomeg_cf = mfem.RestrictedCoefficient(negmuomeg, attr) + mu2omeg2_cf = mfem.RestrictedCoefficient(mu2omeg2, attr) + epsrot_cf = mfem.MatrixRestrictedCoefficient(epsrot, attr) + negepsrot_cf = mfem.MatrixRestrictedCoefficient(negepsrot, attr) else: epsomeg_cf = epsomeg negepsomeg_cf = negepsomeg @@ -496,43 +513,67 @@ def run(meshfile='', mu2omeg2_cf = mu2omeg2 epsrot_cf = epsrot negepsrot_cf = negepsrot - - detJ_r = mdpg.PmlCoefficient(mdpg.detJ_r_function,pml) - detJ_i = mdpg.PmlCoefficient(mdpg.detJ_i_function,pml) - abs_detJ_2 = mdpg.PmlCoefficient(mdpg.abs_detJ_2_function,pml) - detJ_Jt_J_inv_r = mdpg.PmlMatrixCoefficient(dim, mdpg.detJ_Jt_J_inv_r_function,pml) - detJ_Jt_J_inv_i = mdpg.PmlMatrixCoefficient(dim, mdpg.detJ_Jt_J_inv_i_function,pml) - abs_detJ_Jt_J_inv_2 = mdpg.PmlMatrixCoefficient(dim, mdpg.abs_detJ_Jt_J_inv_2_function,pml) - negmuomeg_detJ_r = mfem.ProductCoefficient(negmuomeg,detJ_r) - negmuomeg_detJ_i = mfem.ProductCoefficient(negmuomeg,detJ_i) - muomeg_detJ_r = mfem.ProductCoefficient(muomeg,detJ_r) - mu2omeg2_detJ_2 = mfem.ProductCoefficient(mu2omeg2,abs_detJ_2) - epsomeg_detJ_Jt_J_inv_i = mfem.ScalarMatrixProductCoefficient(epsomeg, detJ_Jt_J_inv_i) - epsomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(epsomeg, detJ_Jt_J_inv_r) - negepsomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(negepsomeg, detJ_Jt_J_inv_r) - muomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(muomeg,detJ_Jt_J_inv_r) - negmuomeg_detJ_Jt_J_inv_i = mfem.ScalarMatrixProductCoefficient(negmuomeg, detJ_Jt_J_inv_i) - negmuomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient(negmuomeg, detJ_Jt_J_inv_r) - mu2omeg2_detJ_Jt_J_inv_2 = mfem.ScalarMatrixProductCoefficient(mu2omeg2, abs_detJ_Jt_J_inv_2) - eps2omeg2_detJ_Jt_J_inv_2 = mfem.ScalarMatrixProductCoefficient(eps2omeg2, abs_detJ_Jt_J_inv_2) - negmuomeg_detJ_r_restr = mfem.RestrictedCoefficient(negmuomeg_detJ_r,attrPML) - negmuomeg_detJ_i_restr = mfem.RestrictedCoefficient(negmuomeg_detJ_i,attrPML) - muomeg_detJ_r_restr = mfem.RestrictedCoefficient(muomeg_detJ_r,attrPML) - mu2omeg2_detJ_2_restr = mfem.RestrictedCoefficient(mu2omeg2_detJ_2,attrPML) - epsomeg_detJ_Jt_J_inv_i_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_i,attrPML) - epsomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_r,attrPML) - negepsomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(negepsomeg_detJ_Jt_J_inv_r,attrPML) - muomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(muomeg_detJ_Jt_J_inv_r, attrPML) - negmuomeg_detJ_Jt_J_inv_i_restr = mfem.MatrixRestrictedCoefficient(negmuomeg_detJ_Jt_J_inv_i,attrPML) - negmuomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient(negmuomeg_detJ_Jt_J_inv_r,attrPML) - mu2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient(mu2omeg2_detJ_Jt_J_inv_2,attrPML) - eps2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient(eps2omeg2_detJ_Jt_J_inv_2,attrPML) - + + detJ_r = mdpg.PmlCoefficient(mdpg.detJ_r_function, pml) + detJ_i = mdpg.PmlCoefficient(mdpg.detJ_i_function, pml) + abs_detJ_2 = mdpg.PmlCoefficient(mdpg.abs_detJ_2_function, pml) + detJ_Jt_J_inv_r = mdpg.PmlMatrixCoefficient( + dim, mdpg.detJ_Jt_J_inv_r_function, pml) + detJ_Jt_J_inv_i = mdpg.PmlMatrixCoefficient( + dim, mdpg.detJ_Jt_J_inv_i_function, pml) + abs_detJ_Jt_J_inv_2 = mdpg.PmlMatrixCoefficient( + dim, mdpg.abs_detJ_Jt_J_inv_2_function, pml) + negmuomeg_detJ_r = mfem.ProductCoefficient(negmuomeg, detJ_r) + negmuomeg_detJ_i = mfem.ProductCoefficient(negmuomeg, detJ_i) + muomeg_detJ_r = mfem.ProductCoefficient(muomeg, detJ_r) + mu2omeg2_detJ_2 = mfem.ProductCoefficient(mu2omeg2, abs_detJ_2) + epsomeg_detJ_Jt_J_inv_i = mfem.ScalarMatrixProductCoefficient( + epsomeg, detJ_Jt_J_inv_i) + epsomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient( + epsomeg, detJ_Jt_J_inv_r) + negepsomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient( + negepsomeg, detJ_Jt_J_inv_r) + muomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient( + muomeg, detJ_Jt_J_inv_r) + negmuomeg_detJ_Jt_J_inv_i = mfem.ScalarMatrixProductCoefficient( + negmuomeg, detJ_Jt_J_inv_i) + negmuomeg_detJ_Jt_J_inv_r = mfem.ScalarMatrixProductCoefficient( + negmuomeg, detJ_Jt_J_inv_r) + mu2omeg2_detJ_Jt_J_inv_2 = mfem.ScalarMatrixProductCoefficient( + mu2omeg2, abs_detJ_Jt_J_inv_2) + eps2omeg2_detJ_Jt_J_inv_2 = mfem.ScalarMatrixProductCoefficient( + eps2omeg2, abs_detJ_Jt_J_inv_2) + negmuomeg_detJ_r_restr = mfem.RestrictedCoefficient( + negmuomeg_detJ_r, attrPML) + negmuomeg_detJ_i_restr = mfem.RestrictedCoefficient( + negmuomeg_detJ_i, attrPML) + muomeg_detJ_r_restr = mfem.RestrictedCoefficient(muomeg_detJ_r, attrPML) + mu2omeg2_detJ_2_restr = mfem.RestrictedCoefficient( + mu2omeg2_detJ_2, attrPML) + epsomeg_detJ_Jt_J_inv_i_restr = mfem.MatrixRestrictedCoefficient( + epsomeg_detJ_Jt_J_inv_i, attrPML) + epsomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient( + epsomeg_detJ_Jt_J_inv_r, attrPML) + negepsomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient( + negepsomeg_detJ_Jt_J_inv_r, attrPML) + muomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient( + muomeg_detJ_Jt_J_inv_r, attrPML) + negmuomeg_detJ_Jt_J_inv_i_restr = mfem.MatrixRestrictedCoefficient( + negmuomeg_detJ_Jt_J_inv_i, attrPML) + negmuomeg_detJ_Jt_J_inv_r_restr = mfem.MatrixRestrictedCoefficient( + negmuomeg_detJ_Jt_J_inv_r, attrPML) + mu2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient( + mu2omeg2_detJ_Jt_J_inv_2, attrPML) + eps2omeg2_detJ_Jt_J_inv_2_restr = mfem.MatrixRestrictedCoefficient( + eps2omeg2_detJ_Jt_J_inv_2, attrPML) if with_pml and dim == 2: - epsomeg_detJ_Jt_J_inv_i_rot = mfem.MatrixProductCoefficient(epsomeg_detJ_Jt_J_inv_i, rot) - epsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient(epsomeg_detJ_Jt_J_inv_r, rot) - negepsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient(negepsomeg_detJ_Jt_J_inv_r, rot) + epsomeg_detJ_Jt_J_inv_i_rot = mfem.MatrixProductCoefficient( + epsomeg_detJ_Jt_J_inv_i, rot) + epsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient( + epsomeg_detJ_Jt_J_inv_r, rot) + negepsomeg_detJ_Jt_J_inv_r_rot = mfem.MatrixProductCoefficient( + negepsomeg_detJ_Jt_J_inv_r, rot) epsomeg_detJ_Jt_J_inv_i_rot_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_i_rot, attrPML) epsomeg_detJ_Jt_J_inv_r_rot_restr = mfem.MatrixRestrictedCoefficient(epsomeg_detJ_Jt_J_inv_r_rot, @@ -540,18 +581,18 @@ def run(meshfile='', negepsomeg_detJ_Jt_J_inv_r_rot_restr = mfem.MatrixRestrictedCoefficient(negepsomeg_detJ_Jt_J_inv_r_rot, attrPML) - - a = mdpg.ParComplexDPGWeakForm(trial_fes,test_fec) + a = mdpg.ParComplexDPGWeakForm(trial_fes, test_fec) a.StoreMatrices() # needed for AMR # (E,∇ × F) a.AddTrialIntegrator(mfem.TransposeIntegrator(mfem.MixedCurlIntegrator(one)), - None, + None, TrialSpace["E_space"], TestSpace["F_space"]) # -i ω ϵ (E , G) = i (- ω ϵ E, G) a.AddTrialIntegrator(None, - mfem.TransposeIntegrator(mfem.VectorFEMassIntegrator(negepsomeg_cf)), + mfem.TransposeIntegrator( + mfem.VectorFEMassIntegrator(negepsomeg_cf)), TrialSpace["E_space"], TestSpace["G_space"]) # (H,∇ × G) @@ -576,9 +617,9 @@ def run(meshfile='', if dim == 3: # i ω μ (H, F) a.AddTrialIntegrator(None, mfem.TransposeIntegrator( - mfem.VectorFEMassIntegrator(muomeg_cf)), - TrialSpace["H_space"], - TestSpace["F_space"]) + mfem.VectorFEMassIntegrator(muomeg_cf)), + TrialSpace["H_space"], + TestSpace["F_space"]) # < n×Ê,F> a.AddTrialIntegrator(mfem.TangentTraceIntegrator(), None, TrialSpace["hatE_space"], @@ -641,7 +682,8 @@ def run(meshfile='', TestSpace["F_space"]) # -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G) a.AddTestIntegrator(None, - mfem.TransposeIntegrator(mfem.MixedCurlIntegrator(negmuomeg_cf)), + mfem.TransposeIntegrator( + mfem.MixedCurlIntegrator(negmuomeg_cf)), TestSpace["F_space"], TestSpace["G_space"]) # -i ω ϵ (∇ × F, δG) = i (- ω ϵ A ∇ F,δG), A = [0 1; -1; 0] @@ -654,7 +696,8 @@ def run(meshfile='', TestSpace["F_space"]) # i ω ϵ (G, ∇ × δF ) = i (ω ϵ G, A ∇ δF) = i ( G , ω ϵ A ∇ δF) a.AddTestIntegrator(None, - mfem.TransposeIntegrator(mfem.MixedVectorGradientIntegrator(epsrot_cf)), + mfem.TransposeIntegrator( + mfem.MixedVectorGradientIntegrator(epsrot_cf)), TestSpace["G_space"], TestSpace["F_space"]) # ϵ^2 ω^2 (G, δG) @@ -664,7 +707,6 @@ def run(meshfile='', if with_pml: assert False, "PML not supported yet" - fncs = Functions(dim, dimc, omega, epsilon, mu, prob) # RHS if prob == 0: @@ -674,235 +716,242 @@ def run(meshfile='', mfem.VectorFEDomainLFIntegrator(f_rhs_i), TestSpace["G_space"]) elif prob == 2: - f_source =fncs.source_function + f_source = fncs.source_function a.AddDomainLFIntegrator(mfem.VectorFEDomainLFIntegrator(f_source), None, TestSpace["G_space"]) - + hatEex_r = fncs.hatE_exact_r hatEex_i = fncs.hatE_exact_i if myid == 0: - txt = "\n Ref |" + " Dofs |" + " ω |" - if exact_known: - txt = txt + " L2 Error |" + " Rate |" - - txt = txt + " Residual |" + " Rate |" + " PCG it |" - print(txt) - - if exact_known: - print("-"*82) - else: - print("-"*60) - + txt = "\n Ref |" + " Dofs |" + " ω |" + if exact_known: + txt = txt + " L2 Error |" + " Rate |" + + txt = txt + " Residual |" + " Rate |" + " PCG it |" + print(txt) + + if exact_known: + print("-"*82) + else: + print("-"*60) + res0 = 0. err0 = 0. dof0 = 0 - + elements_to_refine = mfem.intArray() - ## visualizaiton socket + # visualizaiton socket E_out_r = None - H_out_r = None - + H_out_r = None + + E_r = mfem.ParGridFunction() + E_i = mfem.ParGridFunction() + H_r = mfem.ParGridFunction() + H_i = mfem.ParGridFunction() + if static_cond: a.EnableStaticCondensation() - + for it in range(pr+1): - a.Assemble() - - ess_tdof_list = mfem.intArray() - ess_bdr = mfem.intArray() - - if pmesh.bdr_attributes.Size() != 0: - ess_bdr.SetSize(pmesh.bdr_attributes.Max()) - ess_bdr.Assign(1) - hatE_fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list) - if with_pml: - ess_bdr.Assign(0) - ess_bdr[1] = 1 - - - # shift the ess_tdofs - for j in range(ess_tdof_list.Size()): - ess_tdof_list[j] += E_fes.GetTrueVSize() + H_fes.GetTrueVSize() - - offsets = mfem.intArray(5) - offsets[0] = 0 - offsets[1] = E_fes.GetVSize() - offsets[2] = H_fes.GetVSize() - offsets[3] = hatE_fes.GetVSize() - offsets[4] = hatH_fes.GetVSize() - offsets.PartialSum() - - x = mfem.Vector([0.]*(2*offsets.Last())) - if prob != 2: - hatE_gf_r = mfem.ParGridFunction(hatE_fes, x, offsets[2]) - hatE_gf_i = mfem.ParGridFunction(hatE_fes, x, offsets.Last() + offsets[2]); - if dim == 3: - hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr) - hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr) - else: - hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr) - hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr) - - Ah = mfem.OperatorPtr() - X = mfem.Vector() - B = mfem.Vector() - a.FormLinearSystem(ess_tdof_list,x, Ah, X, B) - - Ahc = Ah.AsComplexOperator() - - assert False, "here (dynamic cast)" - #BlockOperator * BlockA_r = dynamic_cast(&Ahc->real()); - #BlockOperator * BlockA_i = dynamic_cast(&Ahc->imag()); - - num_blocks = BlockA_r.NumRowBlocks() - tdof_offsets = mfem.intArray(2*num_blocks+1) - - tdof_offsets[0] = 0 - skip = 0 if static_cond else 2 - k = 2 if static_cond else 0 - for i in range(num_blocks): - tdof_offsets[i+1] = trial_fes[i+k].GetTrueVSize(); - tdof_offsets[num_blocks+i+1] = trial_fes[i+k].GetTrueVSize() - tdof_offsets.PartialSum(); - - blockA = BlockOperator(tdof_offsets) - for i in range(num_blocks): - for j in range(num_blocks): - blockA.SetBlock(i, j, BlockA_r.GetBlock(i,j)) - blockA.SetBlock(i, j+num_blocks, BlockA_i.GetBlock(i,j), -1.0) - blockA.SetBlock(i+num_blocks, j+num_blocks, BlockA_r.GetBlock(i,j)) - blockA.SetBlock(i+num_blocks, j, BlockA_i.GetBlock(i,j)) - X.Assign(0.0) - M = mfem.BlockDiagonalPreconditioner(tdof_offsets) - - if notstatic_cond: - solver_E = mfem.HypreBoomerAMG(BlockA_r.GetBlock(0,0)); - solver_E.SetPrintLevel(0) - solver_E.SetSystemsOptions(dim) - solver_H = mfem.HypreBoomerAMG(BlockA_r.GetBlock(1,1)) - solver_H.SetPrintLevel(0) - solver_H.SetSystemsOptions(dim) - M.SetDiagonalBlock(0,solver_E) - M.SetDiagonalBlock(1,solver_H) - M.SetDiagonalBlock(num_blocks,solver_E) - M.SetDiagonalBlock(num_blocks+1,solver_H) - - - solver_hatH = None - solver_hatE = mfem.HypreAMS(BlockA_r.GetBlock(skip, skip), hatE_fes) - solver_hatE.SetPrintLevel(0) - if dim == 2: - solver_hatH = mfem.HypreBoomerAMG(BlockA_r.GetBlock(skip+1, skip+1)) - solver_hatH.SetPrintLevel(0) - else: - solver_hatH = mfem.HypreAMS(BlockA_r.GetBlock(skip+1,skip+1), - hatH_fes) - solver_hatH.SetPrintLevel(0) - - M.SetDiagonalBlock(skip,solver_hatE) - M.SetDiagonalBlock(skip+1,solver_hatH) - M.SetDiagonalBlock(skip+num_blocks,solver_hatE) - M.SetDiagonalBlock(skip+num_blocks+1,solver_hatH) - - cg = mfem.CGSolver(MPI.COMM_WORLD) - cg.SetRelTol(1e-6) - cg.SetMaxIter(10000) - cg.SetPrintLevel(0) - cg.SetPreconditioner(M) - cg.SetOperator(blockA) - cg.Mult(B, X) - - #for i in range(num_blocks): - # delete &M.GetDiagonalBlock(i); - - num_iter = cg.GetNumIterations() - - a.RecoverFEMSolution(X,x) - - residuals = a.ComputeResidual(x) - - residual = residuals.Norml2() - maxresidual = residuals.Max() - globalresidual = residual * residual; - - maxresidual = MPI.COMM_WORLD.allreduce(maxresidual, op=MPI.MAX) - globalresidual = MPI.COMM_WORLD.allreduce(globalresidual, op=MPI.SUM) - globalresidual = np.sqrt(globalresidual) - - E_r.MakeRef(E_fes,x, 0); - E_i.MakeRef(E_fes,x, offsets.Last()) - - H_r.MakeRef(H_fes,x, offsets[1]) - H_i.MakeRef(H_fes,x, offsets.Last()+offsets[1]) - - dofs = 0; - for i in range(trial_fes.Size()): - dofs += trial_fes[i].GlobalTrueVSize() - - - if exact_known: - E_ex_r = mfem.VectorFunctionCoefficient(dim, E_exact_r) - E_ex_i = mfem.VectorFunctionCoefficient(dim, E_exact_i) - H_ex_r = mfem.VectorFunctionCoefficient(dim, H_exact_r) - H_ex_i = mfem.VectorFunctionCoefficient(dim, H_exact_i) + a.Assemble() + + ess_tdof_list = mfem.intArray() + ess_bdr = mfem.intArray() + + if pmesh.bdr_attributes.Size() != 0: + ess_bdr.SetSize(pmesh.bdr_attributes.Max()) + ess_bdr.Assign(1) + hatE_fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list) + if with_pml: + ess_bdr.Assign(0) + ess_bdr[1] = 1 + + # shift the ess_tdofs + for j in range(ess_tdof_list.Size()): + ess_tdof_list[j] += E_fes.GetTrueVSize() + H_fes.GetTrueVSize() + + offsets = mfem.intArray(5) + offsets[0] = 0 + offsets[1] = E_fes.GetVSize() + offsets[2] = H_fes.GetVSize() + offsets[3] = hatE_fes.GetVSize() + offsets[4] = hatH_fes.GetVSize() + offsets.PartialSum() + offsetsl = offsets.ToList() + + x = mfem.Vector([0.]*(2*offsetsl[-1])) + if prob != 2: + hatE_gf_r = mfem.ParGridFunction(hatE_fes, x, offsetsl[2]) + hatE_gf_i = mfem.ParGridFunction( + hatE_fes, x, offsetsl[-1] + offsetsl[2]) + if dim == 3: + hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr) + hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr) + else: + hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr) + hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr) + + Ah = mfem.OperatorPtr() + X = mfem.Vector() + B = mfem.Vector() + a.FormLinearSystem(ess_tdof_list, x, Ah, X, B) + + Ahc = Ah.AsComplexOperator() + + BlockA_r = mfem.Opr2BlockOpr(Ahc.real()) + BlockA_i = mfem.Opr2BlockOpr(Ahc.imag()) + + num_blocks = BlockA_r.NumRowBlocks() + tdof_offsets = mfem.intArray(2*num_blocks+1) + + tdof_offsets[0] = 0 + skip = 0 if static_cond else 2 + k = 2 if static_cond else 0 + for i in range(num_blocks): + tdof_offsets[i+1] = trial_fes[i+k].GetTrueVSize() + tdof_offsets[num_blocks+i+1] = trial_fes[i+k].GetTrueVSize() + tdof_offsets.PartialSum() + + blockA = mfem.BlockOperator(tdof_offsets) + for i in range(num_blocks): + for j in range(num_blocks): + blockA.SetBlock(i, j, BlockA_r.GetBlock(i, j)) + blockA.SetBlock(i, j+num_blocks, BlockA_i.GetBlock(i, j), -1.0) + blockA.SetBlock(i+num_blocks, j+num_blocks, + BlockA_r.GetBlock(i, j)) + blockA.SetBlock(i+num_blocks, j, BlockA_i.GetBlock(i, j)) + X.Assign(0.0) + M = mfem.BlockDiagonalPreconditioner(tdof_offsets) + + if not static_cond: + E_mat = mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(0, 0)) + H_mat = mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(1, 1)) + solver_E = mfem.HypreBoomerAMG(E_mat) + solver_E.SetPrintLevel(0) + solver_E.SetSystemsOptions(dim) + solver_H = mfem.HypreBoomerAMG(H_mat) + solver_H.SetPrintLevel(0) + solver_H.SetSystemsOptions(dim) + M.SetDiagonalBlock(0, solver_E) + M.SetDiagonalBlock(1, solver_H) + M.SetDiagonalBlock(num_blocks, solver_E) + M.SetDiagonalBlock(num_blocks+1, solver_H) + + hatE_mat = mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(skip, skip)) + solver_hatE = mfem.HypreAMS(hatE_mat, hatE_fes) + solver_hatE.SetPrintLevel(0) + + hatH_mat = mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(skip+1, skip+1)) + if dim == 2: + solver_hatH = mfem.HypreBoomerAMG(hatH_mat) + solver_hatH.SetPrintLevel(0) + else: + solver_hatH = mfem.HypreAMS(hatH_nat, hatH_fes) + solver_hatH.SetPrintLevel(0) + + M.SetDiagonalBlock(skip, solver_hatE) + M.SetDiagonalBlock(skip+1, solver_hatH) + M.SetDiagonalBlock(skip+num_blocks, solver_hatE) + M.SetDiagonalBlock(skip+num_blocks+1, solver_hatH) + + cg = mfem.CGSolver(MPI.COMM_WORLD) + cg.SetRelTol(1e-6) + cg.SetMaxIter(10000) + cg.SetPrintLevel(0) + cg.SetPreconditioner(M) + cg.SetOperator(blockA) + cg.Mult(B, X) + + # for i in range(num_blocks): + # delete &M.GetDiagonalBlock(i); + + num_iter = cg.GetNumIterations() + + a.RecoverFEMSolution(X, x) + + residuals = a.ComputeResidual(x) + + residual = residuals.Norml2() + maxresidual = residuals.Max() + globalresidual = residual * residual + + maxresidual = MPI.COMM_WORLD.allreduce(maxresidual, op=MPI.MAX) + globalresidual = MPI.COMM_WORLD.allreduce(globalresidual, op=MPI.SUM) + globalresidual = np.sqrt(globalresidual) + + E_r.MakeRef(E_fes, x, 0) + E_i.MakeRef(E_fes, x, offsetsl[-1]) + + H_r.MakeRef(H_fes, x, offsetsl[1]) + H_i.MakeRef(H_fes, x, offsetsl[-1]+offsetsl[1]) + + dofs = 0 + for i in range(trial_fes.Size()): + dofs += trial_fes[i].GlobalTrueVSize() + + if exact_known: + E_ex_r = fncs.E_exact_r + E_ex_i = fncs.E_exact_i + H_ex_r = fncs.H_exact_r + H_ex_i = fncs.H_exact_i E_err_r = E_r.ComputeL2Error(E_ex_r) E_err_i = E_r.ComputeL2Error(E_ex_i) H_err_r = H_r.ComputeL2Error(E_ex_r) H_err_i = H_r.ComputeL2Error(E_ex_i) L2Error = np.sqrt(E_err_r*E_err_r + E_err_i*E_err_i - + H_err_r*H_err_r + H_err_i*H_err_i ) - rate_err = 0 if it == 0 else dim*np.log(err0/L2Error)/np.log(dof0/dofs) + + H_err_r*H_err_r + H_err_i*H_err_i) + rate_err = 0 if it == 0 else dim * \ + np.log(err0/L2Error)/np.log(dof0/dofs) err0 = L2Error - rate_res = 0.0 if it == 0 else dim*np.log(res0/globalresidual)/np.log(dof0/dofs) + rate_res = 0.0 if it == 0 else dim * \ + np.log(res0/globalresidual)/np.log(dof0/dofs) - res0 = globalresidual; - dof0 = dofs; + res0 = globalresidual + dof0 = dofs - if myid == 0: - txt = ("{:5d}".format(it) + "|" + - "{:10d}".format(dof0) + "|" + - "{:4f}".format(2.0*runm) + " π | " ) + if myid == 0: + txt = ("{:5d}".format(it) + " | " + + "{:10d}".format(dof0) + " | " + + " {:.1f}".format(2.0*rnum) + " π | ") if exact_known: - txt = txt + ("{:10e}".format(err0) + "|" + - "{:6f}".format(rate_err) + " | " ) + txt = txt + (" {:.3e}".format(err0) + " | " + + " {:.2f} ".format(rate_err) + " | ") - txt = txt + ("{:10e}".format(res0) + "|" + - "{:6d}".format(rate_err) + " | " + - "{:6d}".format(num_iter) + " | " ) + txt = txt + (" {:.3e}".format(res0) + " | " + + " {:.2f} ".format(rate_err) + " | " + + "{:6d}".format(num_iter) + " | ") print(txt) - - if visualization: - keys = "jRcml\n" if it == 0 and dim == 2 else "" - - E_out_r = VisualizeField(E_out_r, "localhost", visport, E_r, - "Numerical Electric field (real part)", 0, 0, 500, 500, keys) - H_out_r = VisualizeField(H_out_r, "localhost", visport, H_r, - "Numerical Magnetic field (real part)", 0, 0, 500, 500, keys); - - if it == pr: - break - - if theta > 0.0: - elements_to_refine.SetSize(0); - for iel in range(pmesh.GetNE()): - if residuals[iel] > theta * maxresidual: - elements_to_refine.Append(iel) - pmesh.GeneralRefinement(elements_to_refine,1,1) - else: - pmesh.UniformRefinement(); - - if with_pml: - pml.SetAttributes(pmesh) - for i in range(trial_fes.Size()): - trial_fes[i].Update(False) - a.Update() - - - + + if visualization: + keys = "jRcml\n" if it == 0 and dim == 2 else "" + E_out_r = VisualizeField(E_out_r, "localhost", visport, E_r, + "Numerical Electric field (real part)", 0, 0, 500, 500, keys) + H_out_r = VisualizeField(H_out_r, "localhost", visport, H_r, + "Numerical Magnetic field (real part)", 0, 0, 500, 500, keys) + + if it == pr: + break + + if theta > 0.0: + elements_to_refine.SetSize(0) + for iel in range(pmesh.GetNE()): + if residuals[iel] > theta * maxresidual: + elements_to_refine.Append(iel) + pmesh.GeneralRefinement(elements_to_refine, 1, 1) + else: + pmesh.UniformRefinement() + + if with_pml: + pml.SetAttributes(pmesh) + for i in range(trial_fes.Size()): + trial_fes[i].Update(False) + a.Update() + + if __name__ == "__main__": from mfem.common.arg_parser import ArgParser @@ -914,25 +963,25 @@ def run(meshfile='', parser.add_argument('-o', '--order', action='store', default=1, type=int, help="Finite element order (polynomial degree).") - + parser.add_argument("-rnum", "--number-of-wavelengths", action='store', default=1.0, type=float, - help="Number of wavelengths"); + help="Number of wavelengths") parser.add_argument("-mu", "--permeability", - action='store', default=1.0, type=float, + action='store', default=1.0, type=float, help="Permeability of free space (or 1/(spring constant)).") parser.add_argument("-eps", "--permittivity", - action='store', default=1.0, type=float, - help="Permittivity of free space (or mass constant)."); + action='store', default=1.0, type=float, + help="Permittivity of free space (or mass constant).") parser.add_argument("-prob", "--problem", - action='store', default=0, type=int, - help="\n".join(("Problem case" - " 0: plane wave, 1: Fichera 'oven', " - " 2: Generic PML problem with point source given as a load " - " 3: Scattering of a plane wave, " - " 4: Point source given on the boundary"))) + action='store', default=0, type=int, + help="\n".join(("Problem case" + " 0: plane wave, 1: Fichera 'oven', " + " 2: Generic PML problem with point source given as a load " + " 3: Scattering of a plane wave, " + " 4: Point source given on the boundary"))) parser.add_argument("-do", "--delta-order", - action='store', default=1, type=int, + action='store', default=1, type=int, help="Order enrichment for DPG test space.") parser.add_argument("-theta", "--theta", action='store', default=0.0, type=float, @@ -944,7 +993,7 @@ def run(meshfile='', action='store', default=1, type=int, help="Number of parallel refinements.") parser.add_argument("-sc", "--static-condensation", - action='store_true', default=False, + action='store_true', default=False, help="Enable static condensation.") parser.add_argument('-no-vis', '--no-visualization', action='store_true', @@ -957,12 +1006,11 @@ def run(meshfile='', visualization = not args.no_visualization - run(meshfile=args.mesh, order=args.order, prob=args.problem, sr=args.serial_ref, - pr=args.parallel_ref, + pr=args.parallel_ref, epsilon=args.permittivity, mu=args.permeability, delta_order=args.delta_order, @@ -970,4 +1018,3 @@ def run(meshfile='', theta=args.theta, static_cond=args.static_condensation, visualization=visualization) - From e1914ba4bf788be3bad98bc44d48cbd393a38934 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Tue, 27 May 2025 18:42:44 -0400 Subject: [PATCH 09/22] (WIP...) --- mfem/common/mfem_config.i | 1 - miniapps/dpg/pmaxwell.py | 5 +++++ setup.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mfem/common/mfem_config.i b/mfem/common/mfem_config.i index 21dd988c..377dfb10 100644 --- a/mfem/common/mfem_config.i +++ b/mfem/common/mfem_config.i @@ -1,5 +1,4 @@ %ignore MFEM_GIT_STRING; -%ignore MFEM_HYPRE_VERSION; %ignore MFEM_SOURCE_DIR; %ignore MFEM_INSTALL_DIR; %ignore MFEM_TIMER_TYPE; diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index 5b5ca5de..7605e642 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -394,6 +394,11 @@ def run(meshfile='', static_cond=False, visualization=False): + device = mfem.Device('cpu') + if myid == 0: + device.Print() + + omega = 2.*pi*rnum with_pml = False diff --git a/setup.py b/setup.py index 2be8b0d0..18aa2959 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ # "metis": "https://github.com/KarypisLab/METIS/archive/refs/tags/v5.1.1-DistDGL-v0.5.tar.gz", # "metis": "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz", "metis": "https://github.com/mfem/tpls/raw/gh-pages/metis-5.1.0.tar.gz", - "hypre": "https://github.com/hypre-space/hypre/archive/v2.28.0.tar.gz", + "hypre": "https://github.com/hypre-space/hypre/archive/refs/tags/v2.33.0.tar.gz", "libceed": "https://github.com/CEED/libCEED/archive/refs/tags/v0.12.0.tar.gz", "gslib": "https://github.com/Nek5000/gslib/archive/refs/tags/v1.0.8.tar.gz"} From 178243553622a4356159204a18b1d9c6736dfa65 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Wed, 28 May 2025 12:45:40 -0400 Subject: [PATCH 10/22] merged --- setup.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/setup.py b/setup.py index a49f5758..b40af1bf 100644 --- a/setup.py +++ b/setup.py @@ -44,11 +44,7 @@ # "metis": "https://github.com/KarypisLab/METIS/archive/refs/tags/v5.1.1-DistDGL-v0.5.tar.gz", # "metis": "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz", "metis": "https://github.com/mfem/tpls/raw/gh-pages/metis-5.1.0.tar.gz", -<<<<<<< HEAD - "hypre": "https://github.com/hypre-space/hypre/archive/refs/tags/v2.33.0.tar.gz", -======= "hypre": "https://github.com/hypre-space/hypre/archive/refs/tags/v2.32.0.tar.gz", ->>>>>>> origin/add_hypre_init "libceed": "https://github.com/CEED/libCEED/archive/refs/tags/v0.12.0.tar.gz", "gslib": "https://github.com/Nek5000/gslib/archive/refs/tags/v1.0.8.tar.gz"} From 96a3d26dede460992853fa922871917887157d26 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Wed, 28 May 2025 18:02:24 -0400 Subject: [PATCH 11/22] (WIP) pmaxwell.py seems okay --- miniapps/dpg/pmaxwell.py | 185 +++++++++++++++++++++++++++++++++------ 1 file changed, 159 insertions(+), 26 deletions(-) diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index 7605e642..2bc0dfc9 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -4,6 +4,11 @@ # Compile with: make pmaxwell ## # sample run + +# mpirun -np 1 python pmaxwell.py -o 2 -pref 2 -prob 0 +# mpirun -np 4 python pmaxwell.py -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0 +# mpirun -np 1 python pmaxwell.py -o 2 -pref 2 -prob 0 -m inline-hex.mesh + # mpirun -np 4 python pmaxwell.py -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0 # mpirun -np 4 python pmaxwell.py -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0 # mpirun -np 4 python pmaxwell.py -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0 @@ -132,7 +137,7 @@ from os.path import expanduser, join import numpy as np -from numpy import pi +from numpy import pi, exp import mfem.par as mfem mdpg = mfem.dpg @@ -149,7 +154,7 @@ def VisualizeField(sock, vishost, visport, gf, title, x=0, y=0, w=400, h=400, keys='', vec=False): - mesh = gf.FESpace().GetMesh() + pmesh = gf.ParFESpace().GetParMesh() newly_opened = False @@ -159,8 +164,9 @@ def VisualizeField(sock, vishost, visport, sock.precision(8) newly_opened = True + sock << "parallel " << str(num_procs) << " " << str(myid) << "\n" sock << "solution\n" - sock << mesh << gf + sock << pmesh << gf if newly_opened: sock << "window_title '" << title << "'\n" @@ -197,7 +203,7 @@ def maxwell_solution(x): E = np.zeros(dim, dtype=np.complex128) if prob == "plane_wave": - E[0] = np.exp(1j * omega * np.sum(x)) + E[0] = exp(1j * omega * np.sum(x)) elif prob == "pml_plane_wave_scatter": E[1] = exp(1j * omega * x[0]) @@ -246,7 +252,7 @@ def maxwell_solution(x): r_yx = -(r_y / r) * r_x r_zx = -(r_z / r) * r_x - val = np.exp(1j * k * r) / r + val = exp(1j * k * r) / r val_r = val / r * (1j * k * r - 1.) val_rr = val / (r * r) * (-k * k * r * r - 2. * 1j * k * r + 2.) @@ -266,7 +272,7 @@ def maxwell_solution(x): def maxwell_solution_curl(x): curlE = np.zeros(dimc, dtype=np.complex128) if prob == "plane_wave": - pw = np.exp(1j * omega * np.sum(x)) + pw = exp(1j * omega * np.sum(x)) if dim == 3: curlE[0] = 0.0 curlE[1] = 1j * omega * pw @@ -274,7 +280,7 @@ def maxwell_solution_curl(x): else: curlE[0] = -1j * omega * pw elif prob == "pml_plane_wave_scatter": - pw = np.exp(1j * omega * (x[0])) + pw = exp(1j * omega * (x[0])) curlE[0] = 1j * omega * pw else: assert False, "should not come here" @@ -282,9 +288,9 @@ def maxwell_solution_curl(x): @njit(complex128[:](float64[:])) def maxwell_solution_curlcurl(x): - curlcurlE = np.zeros(dimc, dtype=np.complex128) + curlcurlE = np.zeros(dim, dtype=np.complex128) if prob == "plane_wave": - pw = np.exp(1j * omega * np.sum(x)) + pw = exp(1j * omega * np.sum(x)) if dim == 3: curlcurlE[0] = 2. * omega * omega * pw curlcurlE[1] = - omega * omega * pw @@ -322,8 +328,8 @@ def hatE_exact(x): else: ret = np.zeros(2, dtype=np.complex128) E = maxwell_solution(x) - ret[0] = E[0] - ret[1] = -E[1] + ret[0] = E[1] + ret[1] = -E[0] return ret @mfem.jit.vector(vdim=dim) @@ -368,18 +374,34 @@ def rhs_func_r(x): # J_r = ω ϵ E_i + ∇ × H_r E = maxwell_solution(x) curlH = curlH_exact(x) - return omega * epsilon * E.imag * curlH.real + return omega * epsilon * E.imag + curlH.real @mfem.jit.vector(vdim=dim) def rhs_func_i(x): # J_r = ω ϵ E_i + ∇ × H_r E = maxwell_solution(x) curlH = curlH_exact(x) - return -omega * epsilon * E.real * curlH.imag + return -omega * epsilon * E.real + curlH.imag self.rhs_func_r = rhs_func_r self.rhs_func_i = rhs_func_i + @mfem.jit.vector(vdim=dim) + def source_function(x): + center = np.zeros(dim)+0.5 + r = 0.0 + for i in range(dim): + r += (x[i] - center[i])**2 + + n = 5.0 * omega * np.sqrt(epsilon * mu) / pi + coeff = pow(n, 2) / pi + alpha = -pow(n, 2) * r + f = np.zeros(dim) + f[0] = -omega * coeff * exp(alpha)/omega + return f + + self.source_function = source_function + def run(meshfile='', order=1, @@ -394,13 +416,9 @@ def run(meshfile='', static_cond=False, visualization=False): - device = mfem.Device('cpu') - if myid == 0: - device.Print() - - omega = 2.*pi*rnum with_pml = False + exact_known = False if prob == 0: exact_known = True @@ -421,7 +439,7 @@ def run(meshfile='', else: with_pml = True - mesh_file = "meshes/scatter.mesh" + meshfile = "meshes/scatter.mesh" mesh_file = expanduser( join(os.path.dirname(__file__), meshfile)) @@ -436,13 +454,19 @@ def run(meshfile='', pml = None if with_pml: - assert False, "PML is not supported" + length = mfem.doubleArray2D(dim, 2) + length.Assign(0.25) + pml = mdpg.CartesianPML(mesh, length) + pml.SetOmega(omega) + pml.SetEpsilonAndMu(epsilon, mu) pmesh = mfem.ParMesh(MPI.COMM_WORLD, mesh) del mesh attr = mfem.intArray() attrPML = mfem.intArray() + if with_pml: + pml.SetAttributes(pmesh, attr, attrPML) # Define spaces TrialSpace = {"E_space": 0, @@ -710,10 +734,111 @@ def run(meshfile='', TestSpace["G_space"], TestSpace["G_space"]) if with_pml: - assert False, "PML not supported yet" + # trial integrators + # -i ω ϵ (β E , G) = -i ω ϵ ((β_re + i β_im) E, G) + # = (ω ϵ β_im E, G) + i (- ω ϵ β_re E, G) + a.AddTrialIntegrator(mfem.TransposeIntegrator(mfem.VectorFEMassIntegrator( + epsomeg_detJ_Jt_J_inv_i_restr)), + mfem.TransposeIntegrator(mfem.VectorFEMassIntegrator( + negepsomeg_detJ_Jt_J_inv_r_restr)), + TrialSpace["E_space"], TestSpace["G_space"]) + if dim == 3: + # trial integrators + # i ω μ (α^-1 H, F) = i ω μ ( (α^-1_re + i α^-1_im) H, F) + # = (- ω μ α^-1_im, H,F) + i *(ω μ α^-1_re H, F) + a.AddTrialIntegrator( + mfem.TransposeIntegrator(mfem.VectorFEMassIntegrator( + negmuomeg_detJ_Jt_J_inv_i_restr)), + mfem.TransposeIntegrator(mfem.VectorFEMassIntegrator( + muomeg_detJ_Jt_J_inv_r_restr)), + TrialSpace["H_space"], TestSpace["F_space"]) + # test integrators + # μ^2 ω^2 (|α|^-2 F,δF) + a.AddTestIntegrator( + mfem.VectorFEMassIntegrator( + mu2omeg2_detJ_Jt_J_inv_2_restr), None, + TestSpace["F_space"], TestSpace["F_space"]) + # -i ω μ (α^-* F,∇ × δG) = i (F, - ω μ α^-1 ∇ × δ G) + # = i (F, - ω μ (α^-1_re + i α^-1_im) ∇ × δ G) + # = (F, - ω μ α^-1_im ∇ × δ G) + i (F, - ω μ α^-1_re ∇×δG) + a.AddTestIntegrator(mfem.MixedVectorWeakCurlIntegrator( + negmuomeg_detJ_Jt_J_inv_i_restr), + mfem.MixedVectorWeakCurlIntegrator( + negmuomeg_detJ_Jt_J_inv_r_restr), + TestSpace["F_space"], TestSpace["G_space"]) + # -i ω ϵ (β ∇ × F, δG) = -i ω ϵ ((β_re + i β_im) ∇ × F, δG) + # = (ω ϵ β_im ∇ × F, δG) + i (- ω ϵ β_re ∇ × F, δG) + a.AddTestIntegrator(mfem.MixedVectorCurlIntegrator( + epsomeg_detJ_Jt_J_inv_i_restr), + mfem.MixedVectorCurlIntegrator( + negepsomeg_detJ_Jt_J_inv_r_restr), + TestSpace["F_space"], TestSpace["G_space"]) + # i ω μ (α^-1 ∇ × G,δF) = i ω μ ((α^-1_re + i α^-1_im) ∇ × G,δF) + # = (- ω μ α^-1_im ∇ × G,δF) + i (ω μ α^-1_re ∇ × G,δF) + a.AddTestIntegrator(mfem.MixedVectorCurlIntegrator( + negmuomeg_detJ_Jt_J_inv_i_restr), + mfem.MixedVectorCurlIntegrator( + muomeg_detJ_Jt_J_inv_r_restr), + TestSpace["G_space"], TestSpace["F_space"]) + # i ω ϵ (β^* G, ∇×δF) = i ω ϵ ( (β_re - i β_im) G, ∇×δF) + # = (ω ϵ β_im G, ∇×δF) + i ( ω ϵ β_re G, ∇×δF) + a.AddTestIntegrator(mfem.MixedVectorWeakCurlIntegrator( + epsomeg_detJ_Jt_J_inv_i_restr), + mfem.MixedVectorWeakCurlIntegrator( + epsomeg_detJ_Jt_J_inv_r_restr), + TestSpace["G_space"], TestSpace["F_space"]) + # ϵ^2 ω^2 (|β|^2 G,δG) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator( + eps2omeg2_detJ_Jt_J_inv_2_restr), None, + TestSpace["G_space"], TestSpace["G_space"]) + + else: + # trial integrators + # i ω μ (α^-1 H, F) = i ω μ ( (α^-1_re + i α^-1_im) H, F) + # = (- ω μ α^-1_im, H,F) + i *(ω μ α^-1_re H, F) + a.AddTrialIntegrator( + mfem.MixedScalarMassIntegrator(negmuomeg_detJ_i_restr), + mfem.MixedScalarMassIntegrator(muomeg_detJ_r_restr), + TrialSpace["H_space"], TestSpace["F_space"]) + # test integrators + # μ^2 ω^2 (|α|^-2 F,δF) + a.AddTestIntegrator(mfem.MassIntegrator(mu2omeg2_detJ_2_restr), None, + TestSpace["F_space"], TestSpace["F_space"]) + # -i ω μ (α^-* F,∇ × δG) = (F, ω μ α^-1 ∇ × δ G) + # =(F, - ω μ α^-1_im ∇ × δ G) + i (F, - ω μ α^-1_re ∇×δG) + a.AddTestIntegrator( + mfem.TransposeIntegrator( + mfem.MixedCurlIntegrator(negmuomeg_detJ_i_restr)), + mfem.TransposeIntegrator( + mfem.MixedCurlIntegrator(negmuomeg_detJ_r_restr)), + TestSpace["F_space"], TestSpace["G_space"]) + # -i ω ϵ (β ∇ × F, δG) = i (- ω ϵ β A ∇ F,δG), A = [0 1; -1; 0] + # = (ω ϵ β_im A ∇ F, δG) + i (- ω ϵ β_re A ∇ F, δG) + a.AddTestIntegrator(mfem.MixedVectorGradientIntegrator( + epsomeg_detJ_Jt_J_inv_i_rot_restr), + mfem.MixedVectorGradientIntegrator( + negepsomeg_detJ_Jt_J_inv_r_rot_restr), + TestSpace["F_space"], TestSpace["G_space"]) + # i ω μ (α^-1 ∇ × G,δF) = i (ω μ α^-1 ∇ × G, δF ) + # = (- ω μ α^-1_im ∇ × G,δF) + i (ω μ α^-1_re ∇ × G,δF) + a.AddTestIntegrator(mfem.MixedCurlIntegrator(negmuomeg_detJ_i_restr), + mfem.MixedCurlIntegrator(muomeg_detJ_r_restr), + TestSpace["G_space"], TestSpace["F_space"]) + # i ω ϵ (β^* G, ∇ × δF ) = i ( G , ω ϵ β A ∇ δF) + # = ( G , ω ϵ β_im A ∇ δF) + i ( G , ω ϵ β_re A ∇ δF) + a.AddTestIntegrator( + mfem.TransposeIntegrator(mfem.MixedVectorGradientIntegrator( + epsomeg_detJ_Jt_J_inv_i_rot_restr)), + mfem.TransposeIntegrator(mfem.MixedVectorGradientIntegrator( + epsomeg_detJ_Jt_J_inv_r_rot_restr)), + TestSpace["G_space"], TestSpace["F_space"]) + # ϵ^2 ω^2 (|β|^2 G,δG) + a.AddTestIntegrator(mfem.VectorFEMassIntegrator( + eps2omeg2_detJ_Jt_J_inv_2_restr), None, + TestSpace["G_space"], TestSpace["G_space"]) - fncs = Functions(dim, dimc, omega, epsilon, mu, prob) # RHS + fncs = Functions(dim, dimc, omega, epsilon, mu, prob) if prob == 0: f_rhs_r = fncs.rhs_func_r f_rhs_i = fncs.rhs_func_i @@ -784,6 +909,7 @@ def run(meshfile='', offsets[2] = H_fes.GetVSize() offsets[3] = hatE_fes.GetVSize() offsets[4] = hatH_fes.GetVSize() + offsets.PartialSum() offsetsl = offsets.ToList() @@ -798,18 +924,24 @@ def run(meshfile='', else: hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr) hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr) - Ah = mfem.OperatorPtr() X = mfem.Vector() B = mfem.Vector() + a.FormLinearSystem(ess_tdof_list, x, Ah, X, B) Ahc = Ah.AsComplexOperator() BlockA_r = mfem.Opr2BlockOpr(Ahc.real()) BlockA_i = mfem.Opr2BlockOpr(Ahc.imag()) - num_blocks = BlockA_r.NumRowBlocks() + + # this is to debug matrix + # for i in range(num_blocks): + # for j in range(num_blocks): + # (mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(i, j))).Print(str(i)+"_"+str(j)+"r") + # (mfem.Opr2HypreParMatrix(BlockA_i.GetBlock(i, j))).Print(str(i)+"_"+str(j)+"i") + tdof_offsets = mfem.intArray(2*num_blocks+1) tdof_offsets[0] = 0 @@ -834,6 +966,7 @@ def run(meshfile='', if not static_cond: E_mat = mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(0, 0)) H_mat = mfem.Opr2HypreParMatrix(BlockA_r.GetBlock(1, 1)) + solver_E = mfem.HypreBoomerAMG(E_mat) solver_E.SetPrintLevel(0) solver_E.SetSystemsOptions(dim) @@ -854,7 +987,7 @@ def run(meshfile='', solver_hatH = mfem.HypreBoomerAMG(hatH_mat) solver_hatH.SetPrintLevel(0) else: - solver_hatH = mfem.HypreAMS(hatH_nat, hatH_fes) + solver_hatH = mfem.HypreAMS(hatH_mat, hatH_fes) solver_hatH.SetPrintLevel(0) M.SetDiagonalBlock(skip, solver_hatE) @@ -927,7 +1060,7 @@ def run(meshfile='', " {:.2f} ".format(rate_err) + " | ") txt = txt + (" {:.3e}".format(res0) + " | " + - " {:.2f} ".format(rate_err) + " | " + + " {:.2f} ".format(rate_res) + " | " + "{:6d}".format(num_iter) + " | ") print(txt) From 68f5506d77f75566b502ba978cd7f5dd045ffbc1 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Tue, 1 Jul 2025 22:24:39 -0400 Subject: [PATCH 12/22] removed rectangular matrix coefficient warnings --- mfem/common/numba_coefficient.i | 10 +++++----- mfem/common/numba_coefficient_utils.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mfem/common/numba_coefficient.i b/mfem/common/numba_coefficient.i index 5687d3a6..e6daf9cb 100644 --- a/mfem/common/numba_coefficient.i +++ b/mfem/common/numba_coefficient.i @@ -1419,12 +1419,12 @@ def _matrix(func, height=None, width=None, shape=None, td=False, params=None, if height is None and width is None and shape is not None: width = shape[0] height = shape[1] - assert height == shape[0], "height and shape[0] are not consistent" - assert width == shape[1], "width and shape[1] are not consistent" + assert height == shape[1], "height and shape[0] are not consistent" + assert width == shape[0], "width and shape[1] are not consistent" - if shape[0] != shape[1]: - import warnings - warning.warn("Rectangular matrix coefficient is experimental", UserWarning) + #if shape[0] != shape[1]: + # import warnings + # warnings.warn("Rectangular matrix coefficient is experimental", UserWarning) if dependency is None: dependency = [] diff --git a/mfem/common/numba_coefficient_utils.py b/mfem/common/numba_coefficient_utils.py index ec9024fe..e4f3867c 100644 --- a/mfem/common/numba_coefficient_utils.py +++ b/mfem/common/numba_coefficient_utils.py @@ -445,7 +445,7 @@ def _process_dependencies(dependencies, setting): if isinstance(xx, MatrixCoefficient): h1, w1 = x[0].GetHeight(), x[0].GetWidth() h2, w2 = x[1].GetHeight(), x[1].GetWidth() - assert h1 == w1, "matrix must be square" + #assert h1 == w1, "matrix must be square" assert h1 == h2, "real and imaginary has to have the same vdim" assert w1 == w2, "real and imaginary has to have the same vdim" else: @@ -461,8 +461,8 @@ def _process_dependencies(dependencies, setting): else: iscomplex.append(0) - if isinstance(xx, MatrixCoefficient): - assert xx.GetHeight() == xx.GetWidth(), "matrix must be square" + #if isinstance(xx, MatrixCoefficient): + # assert xx.GetHeight() == xx.GetWidth(), "matrix must be square" if isinstance(xx, Coefficient): kinds.append(0) From 993774cd11b0b07c6378292b6bf3177a53f305b7 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Wed, 2 Jul 2025 09:36:41 -0400 Subject: [PATCH 13/22] preparig for merge --- _build_system/build_consts.py | 2 ++ miniapps/dpg/pmaxwell.py | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/_build_system/build_consts.py b/_build_system/build_consts.py index 78e2d837..5f017f30 100644 --- a/_build_system/build_consts.py +++ b/_build_system/build_consts.py @@ -89,6 +89,8 @@ releases=[ release( "2.28.0", None, "https://github.com/hypre-space/hypre/archive/v2.28.0.tar.gz"), + release( + "2.32.0", None, "https://github.com/hypre-space/hypre/archive/v2.32.0.tar.gz"), ] ), gslib=dict( diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index 2bc0dfc9..f414b0a6 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -134,7 +134,7 @@ from mfem.common.bessel import yv as yn from mfem.common.bessel import jv as jn import os -from os.path import expanduser, join +from os.path import expanduser, join, dirname import numpy as np from numpy import pi, exp @@ -423,25 +423,25 @@ def run(meshfile='', if prob == 0: exact_known = True mesh_file = expanduser( - join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) + join(dirname(__file__), '..', '..', 'data', meshfile)) elif prob == 1: meshfile = "meshes/fichera-waveguide.mesh" omega = 5.0 rnum = omega/(2.*pi) mesh_file = expanduser( - join(os.path.dirname(__file__), meshfile)) + join(dirname(__file__), meshfile)) elif prob == 2: with_pml = True mesh_file = expanduser( - join(os.path.dirname(__file__), '..', '..', 'data', meshfile)) + join(dirname(__file__), '..', '..', 'data', meshfile)) else: with_pml = True meshfile = "meshes/scatter.mesh" mesh_file = expanduser( - join(os.path.dirname(__file__), meshfile)) + join(dirname(__file__), meshfile)) mesh = mfem.Mesh(mesh_file, 1, 1) dim = mesh.Dimension() From 3cca3b7dc17f509284e129d947b8057912dc5e3b Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Wed, 30 Jul 2025 15:59:59 -0400 Subject: [PATCH 14/22] improved DPGweakform constructor. Instead of passing mfem::Array, we can pass list/tuple --- _build_system/build_utils.py | 2 +- mfem/_par/complexweakform.i | 20 +++++++++++ mfem/_par/pcomplexweakform.i | 20 +++++++++++ mfem/_par/pweakform.i | 19 +++++++++++ mfem/_par/weakform.i | 19 +++++++++++ mfem/_ser/complexweakform.i | 20 +++++++++++ mfem/_ser/setup.py | 8 +++-- mfem/_ser/weakform.i | 19 +++++++++++ mfem/common/dpg_common.i | 65 ++++++++++++++++++++++++++++++++++++ miniapps/dpg/pmaxwell.py | 23 +++++++------ 10 files changed, 201 insertions(+), 14 deletions(-) diff --git a/_build_system/build_utils.py b/_build_system/build_utils.py index 6197eb80..0cff67ef 100644 --- a/_build_system/build_utils.py +++ b/_build_system/build_utils.py @@ -81,7 +81,7 @@ def external_install_prefix(prefix, verbose=True): # when prefix is given...let's borrow pip._internal to find the location ;D import pip._internal.locations path = pip._internal.locations.get_scheme( - "mfem", prefix=prefix).purelib + "mfem", prefix=prefix).platlib if not os.path.exists(path): os.makedirs(path) path = os.path.join(path, 'mfem', 'external') diff --git a/mfem/_par/complexweakform.i b/mfem/_par/complexweakform.i index b1ecb5c2..abe48d21 100644 --- a/mfem/_par/complexweakform.i +++ b/mfem/_par/complexweakform.i @@ -40,6 +40,26 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) +%import "../common/object_array_typemap.i" +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + FiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + FiniteElementCollection*) + + +%pythonprepend mfem::ComplexDPGWeakForm::ComplexDPGWeakForm %{ + if len(args) > 0: + fes_, fecol_ = args + self._fes = fes_ + self._fecol = fecol_ +%} + +%pythonprepend mfem::ComplexDPGWeakForm::SetSpaces %{ + self._fes = fes_ + self._fecol = fecol_ +%} + + %include "miniapps/dpg/util/complexweakform.hpp" #endif diff --git a/mfem/_par/pcomplexweakform.i b/mfem/_par/pcomplexweakform.i index 49952941..c64b0b4e 100644 --- a/mfem/_par/pcomplexweakform.i +++ b/mfem/_par/pcomplexweakform.i @@ -41,6 +41,26 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) +%import "../common/object_array_typemap.i" +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + ParFiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + FiniteElementCollection*) + + +%pythonprepend mfem::ParComplexDPGWeakForm::ParComplexDPGWeakForm %{ + if len(args) > 0: + trial_pfes_, fecol_ = args + self._fes = trial_pfes_ + self._fecol = fecol_ + +%} + +%pythonprepend mfem::ParComplexDPGWeakForm::SetParSpaces %{ + self._fes = trial_pfes_ + self._fecol = fecol_ +%} + %include "miniapps/dpg/util/pcomplexweakform.hpp" #endif diff --git a/mfem/_par/pweakform.i b/mfem/_par/pweakform.i index ae8dd913..d7c0b5c9 100644 --- a/mfem/_par/pweakform.i +++ b/mfem/_par/pweakform.i @@ -41,6 +41,25 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) +%import "../common/object_array_typemap.i" +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + ParFiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + FiniteElementCollection*) + + +%pythonprepend mfem::ParDPGWeakForm::ParDPGWeakForm %{ + if len(args) > 0: + trial_fes_, fecol_ = args + self._fes = trial_pfes_ + self._fecol = fecol_ + +%} + +%pythonprepend mfem::ParDPGWeakForm::SetParSpaces %{ + self._fes = trial_pfes_ + self._fecol = fecol_ +%} %include "miniapps/dpg/util/pweakform.hpp" diff --git a/mfem/_par/weakform.i b/mfem/_par/weakform.i index 554084a7..7e6e8c7c 100644 --- a/mfem/_par/weakform.i +++ b/mfem/_par/weakform.i @@ -43,6 +43,25 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) +%import "../common/object_array_typemap.i" +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + FiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, + FiniteElementCollection*) + + +%pythonprepend mfem::DPGWeakForm::DPGWeakForm %{ + if len(args) > 0: + fes_, fecol_ = args + self._fes = fes_ + self._fecol = fecol_ +%} + +%pythonprepend mfem::DPGWeakForm::SetSpaces %{ + self._fes = fes_ + self._fecol = fecol_ +%} + %include "miniapps/dpg/util/weakform.hpp" #endif diff --git a/mfem/_ser/complexweakform.i b/mfem/_ser/complexweakform.i index 6d8977d9..1eda056d 100644 --- a/mfem/_ser/complexweakform.i +++ b/mfem/_ser/complexweakform.i @@ -40,6 +40,26 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) +%include "../common/typemap_macros.i" +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + FiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + FiniteElementCollection*) + + +%pythonprepend mfem::ComplexDPGWeakForm::ComplexDPGWeakForm %{ + if len(args) > 0: + fes_, fecol_ = args + self._fes = fes_ + self._fecol = fecol_ +%} + +%pythonprepend mfem::ComplexDPGWeakForm::SetSpaces %{ + self._fes = fes_ + self._fecol = fecol_ +%} + + %include "miniapps/dpg/util/complexweakform.hpp" #endif diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index 8ecff6b0..33d8ab88 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -36,7 +36,7 @@ def get_extensions(): from setup_local import (mfemserbuilddir, mfemserincdir, mfemsrcdir, mfemserlnkdir, mfemstpl, build_mfem, numpyinc, cc_ser, cxx_ser, - cxx11flag, + cxx11flag, mfem_outside, add_cuda, add_libceed, add_suitesparse, add_gslibs, bdist_wheel_dir) @@ -58,6 +58,8 @@ def get_extensions(): add_gslibs = '' cxx11flag = '' build_mfem = '0' + mfem_outside = '0' + mpiinc = '' libraries = ['mfem'] @@ -140,9 +142,9 @@ def get_extensions(): runtime_library_dirs = [ x for x in library_dirs if x.find(bdist_wheel_dir) == -1] - if build_mfem == "1" and sys.platform in ("linux", "linux2"): + if mfem_outside == "0" and sys.platform in ("linux", "linux2"): runtime_library_dirs.append("$ORIGIN/../external/ser/lib") - elif build_mfem == "1" and sys.platform == "darwin": + elif mfem_outside == "0" and sys.platform == "darwin": runtime_library_dirs.append("@loader_path/../external/ser/lib") else: runtime_library_dirs = library_dirs diff --git a/mfem/_ser/weakform.i b/mfem/_ser/weakform.i index 14019a2f..7cf1bff3 100644 --- a/mfem/_ser/weakform.i +++ b/mfem/_ser/weakform.i @@ -43,6 +43,25 @@ import_array(); OSTREAM_TYPEMAP(std::ostream&) +%import "../common/object_array_typemap.i" +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + FiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + FiniteElementCollection*) + + +%pythonprepend mfem::DPGWeakForm::DPGWeakForm %{ + if len(args) > 0: + fes_, fecol_ = args + self._fes = fes_ + self._fecol = fecol_ +%} + +%pythonprepend mfem::DPGWeakForm::SetSpaces %{ + self._fes = fes_ + self._fecol = fecol_ +%} + %include "miniapps/dpg/util/weakform.hpp" diff --git a/mfem/common/dpg_common.i b/mfem/common/dpg_common.i index 6d1bf243..bbdbab7f 100644 --- a/mfem/common/dpg_common.i +++ b/mfem/common/dpg_common.i @@ -99,3 +99,68 @@ namespace mfem { %rename(detJ_Jt_J_inv_r_f) mfem::detJ_Jt_J_inv_r_function; %rename(detJ_Jt_J_inv_i_f) mfem::detJ_Jt_J_inv_i_function; %rename(abs_detJ_Jt_J_inv_2_f) mfem::abs_detJ_Jt_J_inv_2_function; + + +// % handle Array input +%include "../common/typemap_macros.i" +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + mfem::FiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + mfem::ParFiniteElementSpace*) +LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, + mfem::FiniteElementCollection*) + + +//DPGWeakForm +%pythonprepend mfem::DPGWeakForm::DPGWeakForm %{ + if len(args) > 0: + fes_, fecol_ = args + self._fes = fes_ + self._fecol = fecol_ +%} + +%pythonprepend mfem::DPGWeakForm::SetSpaces %{ + self._fes = fes_ + self._fecol = fecol_ +%} + +//ComplexDPGWeakForm +%pythonprepend mfem::ComplexDPGWeakForm::ComplexDPGWeakForm %{ + if len(args) > 0: + fes_, fecol_ = args + self._fes = fes_ + self._fecol = fecol_ +%} + +%pythonprepend mfem::ComplexDPGWeakForm::SetSpaces %{ + self._fes = fes_ + self._fecol = fecol_ +%} + +//ParDPGWeakForm +%pythonprepend mfem::ParDPGWeakForm::ParDPGWeakForm %{ + if len(args) > 0: + trial_pfes_, fecol_ = args + self._fes = trial_pfes_ + self._fecol = fecol_ + +%} + +%pythonprepend mfem::ParDPGWeakForm::SetParSpaces %{ + self._pfes = trial_pfes_ + self._fecol = fecol_ +%} + +//ParComplexDPGWeakForm +%pythonprepend mfem::ParComplexDPGWeakForm::ParComplexDPGWeakForm %{ + if len(args) > 0: + trial_pfes_, fecol_ = args + self._fes = trial_pfes_ + self._fecol = fecol_ + +%} + +%pythonprepend mfem::ParComplexDPGWeakForm::SetParSpaces %{ + self._pfes = trial_pfes_ + self._fecol = fecol_ +%} diff --git a/miniapps/dpg/pmaxwell.py b/miniapps/dpg/pmaxwell.py index f414b0a6..124d553d 100644 --- a/miniapps/dpg/pmaxwell.py +++ b/miniapps/dpg/pmaxwell.py @@ -500,14 +500,17 @@ def run(meshfile='', hatH_fes = mfem.ParFiniteElementSpace(pmesh, hatH_fec) G_fec = mfem.ND_FECollection(test_order, dim) - trial_fes = mfem.ParFiniteElementSpaceArray() - test_fec = mfem.FiniteElementCollectionArray() - trial_fes.Append(E_fes) - trial_fes.Append(H_fes) - trial_fes.Append(hatE_fes) - trial_fes.Append(hatH_fes) - test_fec.Append(F_fec) - test_fec.Append(G_fec) + # trial_fes = mfem.ParFiniteElementSpaceArray() + # test_fec = mfem.FiniteElementCollectionArray() + trial_fes = [] + test_fec = [] + + trial_fes.append(E_fes) + trial_fes.append(H_fes) + trial_fes.append(hatE_fes) + trial_fes.append(hatH_fes) + test_fec.append(F_fec) + test_fec.append(G_fec) # Bilinear form coefficients one = mfem.ConstantCoefficient(1.0) @@ -1027,7 +1030,7 @@ def run(meshfile='', H_i.MakeRef(H_fes, x, offsetsl[-1]+offsetsl[1]) dofs = 0 - for i in range(trial_fes.Size()): + for i in range(len(trial_fes)): dofs += trial_fes[i].GlobalTrueVSize() if exact_known: @@ -1085,7 +1088,7 @@ def run(meshfile='', if with_pml: pml.SetAttributes(pmesh) - for i in range(trial_fes.Size()): + for i in range(len(trial_fes)): trial_fes[i].Update(False) a.Update() From 8e69e620d78498a43fcf8e6651ce547d442e75eb Mon Sep 17 00:00:00 2001 From: "S. Shiraiwa" Date: Mon, 15 Dec 2025 07:02:34 -0500 Subject: [PATCH 15/22] (WIP) --- _build_system/build_config.py | 7 ++++--- _build_system/build_mfem.py | 6 +++--- _build_system/build_pymfem.py | 1 + docs/changelog.txt | 2 ++ mfem/_par/setup.py | 5 ++++- mfem/_ser/setup.py | 11 +++++++---- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/_build_system/build_config.py b/_build_system/build_config.py index a82bf1f8..5d83050f 100644 --- a/_build_system/build_config.py +++ b/_build_system/build_config.py @@ -36,6 +36,7 @@ def print_config(): print(" when needed, the dependency (mfem/hypre/metis) will be installed under " + bglb.ext_prefix) print(" build mfem : " + ("Yes" if bglb.build_mfem else "No")) + print(" build miniapps: " + ("Yes" if bglb.mfem_miniapps else "No")) print(" build metis : " + ("Yes" if bglb.build_metis else "No")) print(" build hypre : " + ("Yes" if bglb.build_hypre else "No")) print(" build libceed : " + ("Yes" if bglb.build_libceed else "No")) @@ -89,7 +90,7 @@ def initialize_cmd_options(command_obj): command_obj.mfem_source = bglb.mfem_source command_obj.mfem_branch = '' command_obj.mfem_debug = False - command_obj.mfem_build_miniapps = False + command_obj.mfem_miniapps = True command_obj.metis_prefix = '' command_obj.hypre_prefix = '' @@ -146,7 +147,7 @@ def initialize_cmd_options(command_obj): ('mfem-source=', None, 'Specify mfem source location' + 'MFEM source directory. Required to run-swig '), ('mfem-debug', None, 'Build MFME with MFEM_DEBUG enabled'), - ('mfem-build-miniapps', None, 'build MFME Miniapps'), + ('mfem-miniapps', None, 'build MFME Miniapps'), ('hypre-prefix=', None, 'Specify locaiton of hypre' + 'libHYPRE.so must exits under /lib'), ('metis-prefix=', None, 'Specify locaiton of metis' + @@ -298,7 +299,7 @@ def configure_install(self): bglb.run_swig_parallel = bool(self.with_parallel) bglb.mfem_debug = bool(self.mfem_debug) - bglb.mfem_build_miniapps = bool(self.mfem_build_miniapps) + bglb.mfem_miniapps = bool(self.mfem_miniapps) if bglb.build_serial: bglb.build_serial = (not bglb.swig_only and not bglb.ext_only) diff --git a/_build_system/build_mfem.py b/_build_system/build_mfem.py index 2e55853e..67781d1c 100644 --- a/_build_system/build_mfem.py +++ b/_build_system/build_mfem.py @@ -43,7 +43,7 @@ def add_rpath(p, dest): cmake_opts = {'DBUILD_SHARED_LIBS': '1', 'DMFEM_ENABLE_EXAMPLES': '1', - 'DMFEM_ENABLE_MINIAPPS': '0', + 'DMFEM_ENABLE_MINIAPPS': '1', 'DCMAKE_SHARED_LINKER_FLAGS': ldflags, 'DMFEM_USE_ZLIB': '1', 'DCMAKE_CXX_FLAGS': bglb.cxxstd_flag, @@ -56,8 +56,8 @@ def add_rpath(p, dest): if bglb.mfem_debug: cmake_opts['DMFEM_DEBUG'] = 'YES' - if bglb.mfem_build_miniapps: - cmake_opts['DMFEM_ENABLE_MINIAPPS'] = '1' + if not bglb.mfem_miniapps: + cmake_opts['DMFEM_ENABLE_MINIAPPS'] = '0' if bglb.verbose: cmake_opts['DCMAKE_VERBOSE_MAKEFILE'] = '1' diff --git a/_build_system/build_pymfem.py b/_build_system/build_pymfem.py index fb572e86..585ca41b 100644 --- a/_build_system/build_pymfem.py +++ b/_build_system/build_pymfem.py @@ -71,6 +71,7 @@ def write_setup_local(): 'gslibpinc': os.path.join(bglb.gslibp_prefix, 'include'), 'cxxstdflag': bglb.cxxstd_flag, 'build_mfem': '1' if bglb.build_mfem else '0', + 'build_miniapps': '1' if bglb.mfem_miniapps else '0', 'bdist_wheel_dir': bglb.bdist_wheel_dir, } diff --git a/docs/changelog.txt b/docs/changelog.txt index ba4501b8..a4edf05a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -2,6 +2,8 @@ 2025 12 * PyMFEM4.9 - ordering.i is added and made correponding adjustment in *.i files. + - update ex22, ex22p to save ComplexGridFunction as is + - fixed ParComplexGridFunction::Save wrapping 2025 09 * PyMFEM 4.8 diff --git a/mfem/_par/setup.py b/mfem/_par/setup.py index d373cc61..74af30aa 100644 --- a/mfem/_par/setup.py +++ b/mfem/_par/setup.py @@ -40,7 +40,7 @@ def get_extensions(): mfemptpl, numpyinc, mpi4pyinc, mpiinc, hypreinc, metisinc, hyprelib, metis5lib, cc_par, cxx_par, cc_ser, cxx_ser, - cxxstdflag, mfem_outside, + cxxstdflag, mfem_outside, build_miniapps, add_pumi, add_cuda, add_libceed, add_strumpack, add_suitesparse, add_gslibp, bdist_wheel_dir) @@ -67,9 +67,12 @@ def get_extensions(): add_gslibp = '' cxxstdflag = '-std=c++17' mfem_outside = '0' + build_miniapps = '0' mpiinc = '' libraries = ['mfem',] + if build_miniapps == '0': + libraries.append("mfem-common") # remove current directory from path print("__file__", os.path.abspath(__file__)) diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index 65d55150..06b6ccde 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -35,10 +35,10 @@ def get_extensions(): # first load variables from PyMFEM_ROOT/setup_local.py sys.path.insert(0, root) try: - from setup_local import (mfemserbuilddir, mfemserincdir, mfemsrcdir, mfemserlnkdir, - mfemstpl, numpyinc, + from setup_local import (mfemserbuilddir, mfemserincdir, mfemsrcdir, + mfemserlnkdir, mfemstpl, numpyinc, cc_ser, cxx_ser, - cxxstdflag, mfem_outside, + cxxstdflag, mfem_outside, build_miniapps, add_cuda, add_libceed, add_suitesparse, add_gslibs, bdist_wheel_dir) @@ -58,11 +58,14 @@ def get_extensions(): add_libceed = '' add_suitesparse = '' add_gslibs = '' - cxxstdflag = '-std=c++17' + cxxstdflag = '-std=c++17' mfem_outside = '0' + build_miniapps = '0' libraries = ['mfem'] + if build_miniapps == '0': + libraries.append("mfem-common") # remove current directory from path # print("__file__", os.path.abspath(__file__)) From d75793c306011df135e60f79ff07f89a4d0d2942 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Mon, 15 Dec 2025 17:50:42 -0500 Subject: [PATCH 16/22] added partcileset/particlevector wrapping --- _build_system/build_config.py | 6 +++++- mfem/_par/ordering.i | 4 +++- mfem/_par/particleset.i | 30 ++++++++++++++++++++++++++++++ mfem/_par/particlevector.i | 28 ++++++++++++++++++++++++++++ mfem/_par/setup.py | 3 ++- mfem/_ser/ordering.i | 3 ++- mfem/_ser/particleset.i | 31 +++++++++++++++++++++++++++++++ mfem/_ser/particlevector.i | 28 ++++++++++++++++++++++++++++ mfem/_ser/setup.py | 3 ++- mfem/par.py | 2 ++ mfem/ser.py | 2 ++ 11 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 mfem/_par/particleset.i create mode 100644 mfem/_par/particlevector.i create mode 100644 mfem/_ser/particleset.i create mode 100644 mfem/_ser/particlevector.i diff --git a/_build_system/build_config.py b/_build_system/build_config.py index 5d83050f..131b5567 100644 --- a/_build_system/build_config.py +++ b/_build_system/build_config.py @@ -222,10 +222,14 @@ def process_cmd_options(command_obj, cfs): assert False, str(command_obj) + " does not have " + attr setattr(command_obj, attr, value) else: - value = cfs.pop(param, "No") if not hasattr(command_obj, attr): assert False, str(command_obj) + " does not have " + attr + if getattr(command_obj, attr): + value = cfs.pop(param, "Yes") + else: + value = cfs.pop(param, "No") + if value.upper() in ("YES", "TRUE", "1"): setattr(command_obj, attr, True) else: diff --git a/mfem/_par/ordering.i b/mfem/_par/ordering.i index cd86978f..0267785b 100644 --- a/mfem/_par/ordering.i +++ b/mfem/_par/ordering.i @@ -13,10 +13,12 @@ import_array1(-1); %} %include "exception.i" -%import "element.i" + %include "../common/typemap_macros.i" %include "../common/exception.i" +%import "array.i" +%import "vector.i" %include "linalg/ordering.hpp" diff --git a/mfem/_par/particleset.i b/mfem/_par/particleset.i new file mode 100644 index 00000000..57fc0a46 --- /dev/null +++ b/mfem/_par/particleset.i @@ -0,0 +1,30 @@ +// +// Copyright (c) 2020-2025, Princeton Plasma Physics Laboratory, All rights reserved. +// +%module(package="mfem._par") particleset + +%feature("autodoc", "1"); + +%{ +#include "mfem.hpp" +#include "../common/io_stream.hpp" +#include "numpy/arrayobject.h" +#include "../common/pyoperator.hpp" +#include "../common/pyintrules.hpp" +%} + +%init %{ +import_array1(-1); +%} + +%include "exception.i" +%include "../common/typemap_macros.i" +%include "../common/exception.i" +%include "../common/kernel_dispatch.i" + +%import "array.i" +%import "ordering.i" +%import "particlevector.i" + +%include "fem/particleset.hpp" + diff --git a/mfem/_par/particlevector.i b/mfem/_par/particlevector.i new file mode 100644 index 00000000..4d47770a --- /dev/null +++ b/mfem/_par/particlevector.i @@ -0,0 +1,28 @@ +// +// Copyright (c) 2020-2025, Princeton Plasma Physics Laboratory, All rights reserved. +// +%module(package="mfem._par") particlevector + +%feature("autodoc", "1"); + +%{ +#include "mfem.hpp" +#include "../common/io_stream.hpp" +#include "numpy/arrayobject.h" +#include "../common/pyoperator.hpp" +#include "../common/pyintrules.hpp" +%} + +%init %{ +import_array1(-1); +%} + +%include "exception.i" +%include "../common/typemap_macros.i" +%include "../common/exception.i" + +%import "vector.i" +%import "ordering.i" + +%include "linalg/particlevector.hpp" + diff --git a/mfem/_par/setup.py b/mfem/_par/setup.py index 74af30aa..2c6b25e3 100644 --- a/mfem/_par/setup.py +++ b/mfem/_par/setup.py @@ -129,7 +129,8 @@ def get_extensions(): "submesh", "transfermap", "staticcond", "sidredatacollection", "psubmesh", "ptransfermap", "enzyme", "attribute_sets", "arrays_by_name", - "hyperbolic", "bounds", "integrator", "ordering"] + "hyperbolic", "bounds", "integrator", "ordering", + "particleset", "particlevector"] if mpiinc != '': include_dirs.append(mpiinc) diff --git a/mfem/_ser/ordering.i b/mfem/_ser/ordering.i index 2f1c8363..0b793361 100644 --- a/mfem/_ser/ordering.i +++ b/mfem/_ser/ordering.i @@ -13,9 +13,10 @@ import_array1(-1); %} %include "exception.i" -%import "element.i" %include "../common/typemap_macros.i" %include "../common/exception.i" +%import "array.i" +%import "vector.i" %include "linalg/ordering.hpp" diff --git a/mfem/_ser/particleset.i b/mfem/_ser/particleset.i new file mode 100644 index 00000000..16dfa59f --- /dev/null +++ b/mfem/_ser/particleset.i @@ -0,0 +1,31 @@ +// +// Copyright (c) 2020-2025, Princeton Plasma Physics Laboratory, All rights reserved. +// +%module(package="mfem._ser") particleset + +%feature("autodoc", "1"); + +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "../common/io_stream.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pyintrules.hpp" +%} + +%init %{ +import_array1(-1); +%} + +%include "exception.i" +%include "../common/typemap_macros.i" +%include "../common/exception.i" + +%import "array.i" +%import "ordering.i" +%import "particlevector.i" + +%include "fem/particleset.hpp" + + + diff --git a/mfem/_ser/particlevector.i b/mfem/_ser/particlevector.i new file mode 100644 index 00000000..4216306e --- /dev/null +++ b/mfem/_ser/particlevector.i @@ -0,0 +1,28 @@ +// +// Copyright (c) 2020-2025, Princeton Plasma Physics Laboratory, All rights reserved. +// +%module(package="mfem._ser") particlevector + +%feature("autodoc", "1"); + +%{ +#include "mfem.hpp" +#include "numpy/arrayobject.h" +#include "../common/io_stream.hpp" +#include "../common/pyoperator.hpp" +#include "../common/pyintrules.hpp" +%} + +%init %{ +import_array1(-1); +%} + +%include "exception.i" +%include "../common/typemap_macros.i" +%include "../common/exception.i" + +%import "vector.i" +%import "ordering.i" + +%include "linalg/particlevector.hpp" + diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index 06b6ccde..02de6070 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -113,7 +113,8 @@ def get_extensions(): "attribute_sets", "arrays_by_name", "hyperbolic", "complex_densemat", "complexstaticcond", "complexweakform", - "bounds", "integrator", "ordering"] + "bounds", "integrator", "ordering", + "particleset", "particlevector"] if add_cuda == '1': from setup_local import cudainc diff --git a/mfem/par.py b/mfem/par.py index 95523511..d662bb3d 100644 --- a/mfem/par.py +++ b/mfem/par.py @@ -79,6 +79,8 @@ from mfem._par.quadinterpolator_face import * from mfem._par.attribute_sets import * from mfem._par.ordering import * +from mfem._par.particleset import * +from mfem._par.particlevector import * from mfem._par.fe_base import * from mfem._par.fe_h1 import * diff --git a/mfem/ser.py b/mfem/ser.py index 4c5a7895..af67c1ac 100644 --- a/mfem/ser.py +++ b/mfem/ser.py @@ -62,6 +62,8 @@ from mfem._ser.quadinterpolator_face import * from mfem._ser.attribute_sets import * from mfem._ser.ordering import * +from mfem._ser.particleset import * +from mfem._ser.particlevector import * from mfem._ser.fe_base import * from mfem._ser.fe_h1 import * From 2f29cfd700a3de984d6f6b34574418399e1aa3db Mon Sep 17 00:00:00 2001 From: "S. Shiraiwa" Date: Thu, 25 Dec 2025 15:01:53 -0500 Subject: [PATCH 17/22] addressed change in hypre.hpp to fix const correctness (https://github.com/mfem/mfem/commit/613d5dd8263f24d428e5bad13b4091528487ac09) --- mfem/_par/hypre.i | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/mfem/_par/hypre.i b/mfem/_par/hypre.i index f4841540..8915b484 100644 --- a/mfem/_par/hypre.i +++ b/mfem/_par/hypre.i @@ -104,11 +104,11 @@ bool is_HYPRE_USING_CUDA(){ is 4, cols is set to be rows. */ -%typemap(in) (int *I, - HYPRE_BigInt *J, - mfem::real_t *data, - HYPRE_BigInt *rows, - HYPRE_BigInt *cols) +%typemap(in) (const int *I, + const HYPRE_BigInt *J, + const mfem::real_t *data, + const HYPRE_BigInt *rows, + const HYPRE_BigInt *cols) (PyArrayObject *tmp_arr1_ = NULL, PyArrayObject *tmp_arr2_ = NULL, PyArrayObject *tmp_arr3_ = NULL, @@ -133,8 +133,11 @@ bool is_HYPRE_USING_CUDA(){ $5 = (HYPRE_BigInt *) PyArray_DATA(tmp_arr5_); } } -%typemap(freearg) (int *I, HYPRE_BigInt *J, - mfem::real_t *data, HYPRE_BigInt *rows, HYPRE_BigInt *cols){ +%typemap(freearg) (const int *I, + const HYPRE_BigInt *J, + const mfem::real_t *data, + const HYPRE_BigInt *rows, + const HYPRE_BigInt *cols){ Py_XDECREF(tmp_arr1_$argnum); Py_XDECREF(tmp_arr2_$argnum); Py_XDECREF(tmp_arr3_$argnum); @@ -144,9 +147,11 @@ bool is_HYPRE_USING_CUDA(){ } } -%typemap(typecheck ) (int *I, HYPRE_BigInt *J, - mfem::real_t *data, HYPRE_BigInt *rows, - HYPRE_BigInt *cols){ +%typemap(typecheck ) (const int *I, + const HYPRE_BigInt *J, + const mfem::real_t *data, + const HYPRE_BigInt *rows, + const HYPRE_BigInt *cols){ /* check if list of 5 numpy array or not */ if (!PyList_Check($input)) $1 = 0; else { From 4e9df3a621660bd22da77ec2898b9ee237411d39 Mon Sep 17 00:00:00 2001 From: "S. Shiraiwa" Date: Thu, 1 Jan 2026 17:09:45 -0500 Subject: [PATCH 18/22] picked-up dpg-dev branch, added link to the orignal object when Vector/SparseMatrix/DenseMatrix/DenseTensor returns numpy array via GetDataArray --- mfem/_par/complexweakform.i | 4 ++-- mfem/_par/densemat.i | 15 +++++++++++++++ mfem/_par/pcomplexweakform.i | 4 ++-- mfem/_par/pweakform.i | 4 ++-- mfem/_par/sparsemat.i | 22 ++++++++++++++++++++++ mfem/_par/vector.i | 8 ++++++++ mfem/_par/weakform.i | 4 ++-- mfem/_ser/complexweakform.i | 6 ++++-- mfem/_ser/densemat.i | 15 +++++++++++++++ mfem/_ser/sparsemat.i | 22 ++++++++++++++++++++++ mfem/_ser/vector.i | 8 ++++++++ mfem/_ser/weakform.i | 6 +++--- 12 files changed, 105 insertions(+), 13 deletions(-) diff --git a/mfem/_par/complexweakform.i b/mfem/_par/complexweakform.i index abe48d21..d133b7b3 100644 --- a/mfem/_par/complexweakform.i +++ b/mfem/_par/complexweakform.i @@ -42,9 +42,9 @@ OSTREAM_TYPEMAP(std::ostream&) %import "../common/object_array_typemap.i" LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - FiniteElementSpace*) + mfem::FiniteElementSpace*) LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - FiniteElementCollection*) + mfem::FiniteElementCollection*) %pythonprepend mfem::ComplexDPGWeakForm::ComplexDPGWeakForm %{ diff --git a/mfem/_par/densemat.i b/mfem/_par/densemat.i index 6042d228..24ad035e 100644 --- a/mfem/_par/densemat.i +++ b/mfem/_par/densemat.i @@ -124,6 +124,21 @@ def __getitem__(self, *args): return _densemat.DenseTensor___getitem__(self, check) %} +%typemap(out) PyObject* mfem::DenseMatrix::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} +%typemap(out) PyObject* mfem::DenseTensor::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} + %include "linalg/densemat.hpp" %extend mfem::DenseMatrix { diff --git a/mfem/_par/pcomplexweakform.i b/mfem/_par/pcomplexweakform.i index c64b0b4e..d6ef0a88 100644 --- a/mfem/_par/pcomplexweakform.i +++ b/mfem/_par/pcomplexweakform.i @@ -43,9 +43,9 @@ OSTREAM_TYPEMAP(std::ostream&) %import "../common/object_array_typemap.i" LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - ParFiniteElementSpace*) + mfem::ParFiniteElementSpace*) LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - FiniteElementCollection*) + mfem::FiniteElementCollection*) %pythonprepend mfem::ParComplexDPGWeakForm::ParComplexDPGWeakForm %{ diff --git a/mfem/_par/pweakform.i b/mfem/_par/pweakform.i index d7c0b5c9..124af89d 100644 --- a/mfem/_par/pweakform.i +++ b/mfem/_par/pweakform.i @@ -43,9 +43,9 @@ OSTREAM_TYPEMAP(std::ostream&) %import "../common/object_array_typemap.i" LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - ParFiniteElementSpace*) + mfem::ParFiniteElementSpace*) LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - FiniteElementCollection*) + mfem::FiniteElementCollection*) %pythonprepend mfem::ParDPGWeakForm::ParDPGWeakForm %{ diff --git a/mfem/_par/sparsemat.i b/mfem/_par/sparsemat.i index 3e80ad17..893fea03 100644 --- a/mfem/_par/sparsemat.i +++ b/mfem/_par/sparsemat.i @@ -147,6 +147,28 @@ if len(args) == 1 and isinstance(args[0], csr_matrix): } } +%typemap(out) PyObject* mfem::SparseMatrix::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} +%typemap(out) PyObject* mfem::SparseMatrix::GetJArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} +%typemap(out) PyObject* mfem::SparseMatrix::GetIArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} + //%rename(add_sparse) mfem::Add; %include "linalg/sparsemat.hpp" diff --git a/mfem/_par/vector.i b/mfem/_par/vector.i index 8e2d409d..2bff502c 100644 --- a/mfem/_par/vector.i +++ b/mfem/_par/vector.i @@ -168,6 +168,14 @@ XXXPTR_SIZE_IN(mfem::Vector **data_, int asize, mfem::Vector *) IGNORE_ARRAY_METHODS(mfem::Vector *) INSTANTIATE_ARRAY0(Vector *, Vector, 1) +%typemap(out) PyObject* mfem::Vector::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} + %include "linalg/vector.hpp" %extend mfem::Vector { diff --git a/mfem/_par/weakform.i b/mfem/_par/weakform.i index 7e6e8c7c..251ff80c 100644 --- a/mfem/_par/weakform.i +++ b/mfem/_par/weakform.i @@ -45,9 +45,9 @@ OSTREAM_TYPEMAP(std::ostream&) %import "../common/object_array_typemap.i" LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - FiniteElementSpace*) + mfem::FiniteElementSpace*) LIST_TO_MFEMOBJ_ARRAY_IN(const mfem::Array&, - FiniteElementCollection*) + mfem::FiniteElementCollection*) %pythonprepend mfem::DPGWeakForm::DPGWeakForm %{ diff --git a/mfem/_ser/complexweakform.i b/mfem/_ser/complexweakform.i index 3327bf08..4da4e4fd 100644 --- a/mfem/_ser/complexweakform.i +++ b/mfem/_ser/complexweakform.i @@ -33,10 +33,12 @@ import_array1(-1); %import "../common/exception.i" %import "coefficient.i" +%import "fe_coll.i" %import "gridfunc.i" %import "mesh.i" %import "solvers.i" %import "operators.i" +%import "fespace.i" %import "blockmatrix.i" %import "../common/exception.i" %import "../common/io_stream_typemap.i" @@ -45,9 +47,9 @@ OSTREAM_TYPEMAP(std::ostream&) %include "../common/typemap_macros.i" LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, - FiniteElementSpace*) + mfem::FiniteElementSpace*) LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, - FiniteElementCollection*) + mfem::FiniteElementCollection*) %pythonprepend mfem::ComplexDPGWeakForm::ComplexDPGWeakForm %{ diff --git a/mfem/_ser/densemat.i b/mfem/_ser/densemat.i index e176caec..a5b0e7ef 100644 --- a/mfem/_ser/densemat.i +++ b/mfem/_ser/densemat.i @@ -124,6 +124,21 @@ def __getitem__(self, *args): return _densemat.DenseTensor___getitem__(self, check) %} +%typemap(out) PyObject* mfem::DenseMatrix::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} +%typemap(out) PyObject* mfem::DenseTensor::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} + %include "linalg/densemat.hpp" %extend mfem::DenseMatrix { diff --git a/mfem/_ser/sparsemat.i b/mfem/_ser/sparsemat.i index d3d0de35..6363767b 100644 --- a/mfem/_ser/sparsemat.i +++ b/mfem/_ser/sparsemat.i @@ -144,6 +144,28 @@ if len(args) == 1 and isinstance(args[0], csr_matrix): } } +%typemap(out) PyObject* mfem::SparseMatrix::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} +%typemap(out) PyObject* mfem::SparseMatrix::GetJArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} +%typemap(out) PyObject* mfem::SparseMatrix::GetIArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} + %include "linalg/sparsemat.hpp" diff --git a/mfem/_ser/vector.i b/mfem/_ser/vector.i index d72e8a05..4d9822dd 100644 --- a/mfem/_ser/vector.i +++ b/mfem/_ser/vector.i @@ -174,6 +174,14 @@ XXXPTR_SIZE_IN(mfem::Vector **data_, int asize, mfem::Vector *) IGNORE_ARRAY_METHODS(mfem::Vector *) INSTANTIATE_ARRAY0(Vector *, Vector, 1) +%typemap(out) PyObject* mfem::Vector::GetDataArray() { + // assign self to base object + Py_INCREF($self); + PyArray_SetBaseObject((PyArrayObject *) $1, $self); + + $result = $1; +} + %include "linalg/vector.hpp" %extend mfem::Vector { diff --git a/mfem/_ser/weakform.i b/mfem/_ser/weakform.i index 7cf1bff3..dddd70c6 100644 --- a/mfem/_ser/weakform.i +++ b/mfem/_ser/weakform.i @@ -35,7 +35,7 @@ import_array(); %import "blockvector.i" %import "bilininteg.i" %import "lininteg.i" -%import "fespace.i" +%import "fe_coll.i" %import "blockmatrix.i" %import "operators.i" %import "../common/exception.i" @@ -45,9 +45,9 @@ OSTREAM_TYPEMAP(std::ostream&) %import "../common/object_array_typemap.i" LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, - FiniteElementSpace*) + mfem::FiniteElementSpace*) LIST_TO_MFEMOBJ_ARRAY_IN(mfem::Array&, - FiniteElementCollection*) + mfem::FiniteElementCollection*) %pythonprepend mfem::DPGWeakForm::DPGWeakForm %{ From 96c2d21bd89ce0b894d044f0bba47df09859c6bd Mon Sep 17 00:00:00 2001 From: "S. Shiraiwa" Date: Thu, 1 Jan 2026 17:27:50 -0500 Subject: [PATCH 19/22] update change log --- docs/changelog.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index a4edf05a..4374a5f2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -4,6 +4,12 @@ - ordering.i is added and made correponding adjustment in *.i files. - update ex22, ex22p to save ComplexGridFunction as is - fixed ParComplexGridFunction::Save wrapping + - fixed GetDataArray of Vector/DenseMatrix/DenseTensor/SparseMatrix so that + destructore is not pre-maturely called when return value is not stored to + a variable. + - particleset.hpp, particlevector.hpp wrapper + - miniapp/dpg/utils/*.hpp is wrapped. + - Python version of pmaxwell.py in miniapp/dpg directory 2025 09 * PyMFEM 4.8 From 7ba94652bad81f641983c62b568c25d99fac1f1d Mon Sep 17 00:00:00 2001 From: "S. Shiraiwa" Date: Fri, 2 Jan 2026 13:36:48 -0500 Subject: [PATCH 20/22] fixed DenseMatrix::GetDataArray() --- mfem/_par/densemat.i | 14 ++++++++------ mfem/_ser/densemat.i | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/mfem/_par/densemat.i b/mfem/_par/densemat.i index 24ad035e..aacf9f84 100644 --- a/mfem/_par/densemat.i +++ b/mfem/_par/densemat.i @@ -125,16 +125,18 @@ def __getitem__(self, *args): %} %typemap(out) PyObject* mfem::DenseMatrix::GetDataArray() { - // assign self to base object - Py_INCREF($self); - PyArray_SetBaseObject((PyArrayObject *) $1, $self); + // assign self to base object + Py_INCREF($self); + PyObject * base = PyArray_BASE((PyArrayObject *) $1); + PyArray_SetBaseObject((PyArrayObject *) base , $self); $result = $1; } %typemap(out) PyObject* mfem::DenseTensor::GetDataArray() { - // assign self to base object - Py_INCREF($self); - PyArray_SetBaseObject((PyArrayObject *) $1, $self); + // assign self to base object + Py_INCREF($self); + PyObject * base = PyArray_BASE((PyArrayObject *) $1); + PyArray_SetBaseObject((PyArrayObject *) base, $self); $result = $1; } diff --git a/mfem/_ser/densemat.i b/mfem/_ser/densemat.i index a5b0e7ef..dc80969c 100644 --- a/mfem/_ser/densemat.i +++ b/mfem/_ser/densemat.i @@ -125,16 +125,18 @@ def __getitem__(self, *args): %} %typemap(out) PyObject* mfem::DenseMatrix::GetDataArray() { - // assign self to base object - Py_INCREF($self); - PyArray_SetBaseObject((PyArrayObject *) $1, $self); + // assign self to base object + Py_INCREF($self); + PyObject * base = PyArray_BASE((PyArrayObject *) $1); + PyArray_SetBaseObject((PyArrayObject *) base, $self); $result = $1; } %typemap(out) PyObject* mfem::DenseTensor::GetDataArray() { - // assign self to base object - Py_INCREF($self); - PyArray_SetBaseObject((PyArrayObject *) $1, $self); + // assign self to base object + Py_INCREF($self); + PyObject * base = PyArray_BASE((PyArrayObject *) $1); + PyArray_SetBaseObject((PyArrayObject *) base, $self); $result = $1; } From 49d611232d48a873c13bb56fa55581866e762079 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Tue, 6 Jan 2026 11:34:58 -0500 Subject: [PATCH 21/22] minor fix...response to copilot... --- INSTALL.md | 1 + _build_system/build_config.py | 7 ++++--- mfem/_par/setup.py | 2 +- mfem/_ser/setup.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 6e8a65e0..3871e7c2 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -56,6 +56,7 @@ pip install . -C"with-parallel=Yes" -C"with-gslib=Yes" |------|-------------| | `--with-parallel` | Install both serial and parallel versions of `MFEM` and the wrapper
(note: this option turns on building `metis` and `hypre`) | | `--mfem-branch=` | Download/install MFEM using a specific reference (`git` `branch`, `hash`, or `tag`) | +| `--mfem-miniapps` | Install MFEM with MFEM C++ miniapps | | `--user` | Install in user's site-package | ## Advanced options diff --git a/_build_system/build_config.py b/_build_system/build_config.py index 131b5567..71d07c10 100644 --- a/_build_system/build_config.py +++ b/_build_system/build_config.py @@ -235,6 +235,9 @@ def process_cmd_options(command_obj, cfs): else: setattr(command_obj, attr, False) + if len(cfs) != 0: + assert False, "unknonw input is given " + str(cfs) + def process_setup_options(command_obj, args): for item in args: @@ -444,7 +447,6 @@ def configure_install(self): bglb.build_parallel = False bglb.keep_temp = True - if bglb.libceed_only: bglb.clean_swig = False bglb.run_swig = False @@ -458,7 +460,6 @@ def configure_install(self): bglb.build_libceed = True bglb.keep_temp = True - if bglb.gslib_only: bglb.clean_swig = False bglb.run_swig = False @@ -471,7 +472,7 @@ def configure_install(self): bglb.build_gslib = True bglb.keep_temp = True - bglb.is_configured = True + configure_build = configure_install diff --git a/mfem/_par/setup.py b/mfem/_par/setup.py index 0d9e5c80..5e47104f 100644 --- a/mfem/_par/setup.py +++ b/mfem/_par/setup.py @@ -71,7 +71,7 @@ def get_extensions(): mpiinc = '' libraries = ['mfem',] - if build_miniapps == '0': + if build_miniapps != '0': libraries.append("mfem-common") # remove current directory from path diff --git a/mfem/_ser/setup.py b/mfem/_ser/setup.py index a87a0ccb..fd51bba3 100644 --- a/mfem/_ser/setup.py +++ b/mfem/_ser/setup.py @@ -64,7 +64,7 @@ def get_extensions(): libraries = ['mfem'] - if build_miniapps == '0': + if build_miniapps != '0': libraries.append("mfem-common") # remove current directory from path From 99ac29059f7ac4b4c29e47742464f3d1ec418278 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Thu, 15 Jan 2026 16:06:41 -0500 Subject: [PATCH 22/22] update shadowed method in fespace.i and pfespace.i --- docs/changelog.txt | 34 ++++---- docs/manual.txt | 48 ++++++++++ mfem/_par/fespace.i | 202 +++++++++++++++++++++++++++--------------- mfem/_par/pfespace.i | 60 +++++++------ mfem/_ser/fespace.i | 203 ++++++++++++++++++++++++++++--------------- 5 files changed, 361 insertions(+), 186 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4374a5f2..18f46355 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -10,6 +10,8 @@ - particleset.hpp, particlevector.hpp wrapper - miniapp/dpg/utils/*.hpp is wrapped. - Python version of pmaxwell.py in miniapp/dpg directory + - Shadowed method in fespace.i and pfespace.i are improved to return intArray and DofTransformation + as a pre-allocated object. 2025 09 * PyMFEM 4.8 @@ -29,26 +31,26 @@ - wrappers for the following MFEM objects are added -- Array2D -- IterativeSolverController - -- CoefficientPtrArray - -- VectorCoefficientPtrArray - -- MatrixCoefficientPtrArray - - bounds.i is added to support bounds.hpp - - c++ standared is moved to c++17 + -- CoefficientPtrArray + -- VectorCoefficientPtrArray + -- MatrixCoefficientPtrArray + - bounds.i is added to support bounds.hpp + - c++ standared is moved to c++17 2024 08 * MFEM 4.7 support - AttributeSets are supported. ex39 and ex39p are added to demonstrate how to use it from Python - - Hyperbolic conservation element/face form integrators (hyperbolic.hpp) are supported. ex18.py and - ex18.py are updated to conform with the updated C++ examples. - - Update SWIG requirement to >= 4.2.1 (required to wrap MFEM routines which use recent C++ features) - - Buiding --with-libceed will download libceed=0.12.0, as required by MFEM 4.7 - - Fixed eltrans::transformback - - Improved testing using Github actions - - New caller and dispatch yml configulations allows for running a test manually - - Test runs automatically for PR and PR update - - Test using Python 3.11 is added + - Hyperbolic conservation element/face form integrators (hyperbolic.hpp) are supported. ex18.py and + ex18.py are updated to conform with the updated C++ examples. + - Update SWIG requirement to >= 4.2.1 (required to wrap MFEM routines which use recent C++ features) + - Buiding --with-libceed will download libceed=0.12.0, as required by MFEM 4.7 + - Fixed eltrans::transformback + - Improved testing using Github actions + - New caller and dispatch yml configulations allows for running a test manually + - Test runs automatically for PR and PR update + - Test using Python 3.11 is added - Refresh install instruction (Install.md) - - Python 3.7 has reached EOL and is no longer supported. This version will support Python 3.8 and above, and + - Python 3.7 has reached EOL and is no longer supported. This version will support Python 3.8 and above, and will likely be the last version to support Python 3.8. @@ -331,5 +333,3 @@ 2017 10.10 chypre.py * CHypreMat::__add__ and CHypreMat::__sub__ was calling CHypreMat without specifing col_parts. - - diff --git a/docs/manual.txt b/docs/manual.txt index 01ef2d26..f4ddf601 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -681,6 +681,54 @@ to find more details of the MFEM library. M = mfem.GSSmoother(AA) mfem.PCG(A, M, B, X, 1, 200, 1e-12, 0.0) + 4-19) fespace/pfespace + Following routines are wrapped using Shadow feature + FiniteElementSpace::GetBdrElementVDofs + FiniteElementSpace::GetElementVDofs + FiniteElementSpace::GetPatchVDofs + FiniteElementSpace::GetFaceVDofs + FiniteElementSpace::GetEdgeVDofs + FiniteElementSpace::GetVertexVDofs + FiniteElementSpace::GetElementInteriorVDofs + FiniteElementSpace::GetEdgeInteriorVDofs + + FiniteElementSpace::GetBdrElementDofs + FiniteElementSpace::GetElementDofs + FiniteElementSpace::GetPatchDofs + FiniteElementSpace::GetFaceDofs + FiniteElementSpace::GetEdgeDofs + FiniteElementSpace::GetVertexDofs + FiniteElementSpace::GetElementInteriorDofs + FiniteElementSpace::GetEdgeInterioVDofs + + ParFiniteElementSpace::GetSharedEdgeDofs + ParFiniteElementSpace::GetSharedTriangleDofs + ParFiniteElementSpace::GetSharedQuadrilateralDofs + ParFiniteElementSpace::GetFaceNbrElementVDofs + + For example, GetPatchDofs are wrapped with + + %feature("shadow") mfem::FiniteElementSpace::GetPatchDofs %{ + def GetPatchDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) + %} + + Therefore, + # this returns a newly created Python list, + GetPatchDofs(i) + + # this stores data to intArray (more closed to C++ syntax) + arr = mfem.ntArray() + GetPatchDofs(i, arr) + + + -- Known issues -- PyMFEM is an on-going effort. Not all MFEM functionality is properly diff --git a/mfem/_par/fespace.i b/mfem/_par/fespace.i index c56acab0..4262fb38 100644 --- a/mfem/_par/fespace.i +++ b/mfem/_par/fespace.i @@ -55,104 +55,166 @@ INT_DEFAULT_NEGATIVE_ONE(int component = -1) //VDoF accesser %feature("shadow") mfem::FiniteElementSpace::GetBdrElementVDofs %{ -def GetBdrElementVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetBdrElementVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementVDofs %{ -def GetElementVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) +%} +%feature("shadow") mfem::FiniteElementSpace::GetPatchVDofs %{ +def GetPatchVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetFaceVDofs %{ -def GetFaceVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetFaceVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeVDofs %{ -def GetEdgeVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetVertexVDofs %{ -def GetVertexVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetVertexVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementInteriorVDofs %{ -def GetElementInteriorVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementInteriorVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeInteriorVDofs %{ -def GetEdgeInteriorVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeInteriorVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} //DoF accesser %feature("shadow") mfem::FiniteElementSpace::GetBdrElementDofs %{ -def GetBdrElementDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetBdrElementDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementDofs %{ -def GetElementDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetFaceDofs %{ -def GetFaceDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetFaceDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeDofs %{ -def GetEdgeDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetVertexDofs %{ -def GetVertexDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetVertexDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementInteriorDofs %{ -def GetElementInteriorDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementInteriorDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeInteriorDofs %{ -def GetEdgeInteriorDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeInteriorDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) +%} +%feature("shadow") mfem::FiniteElementSpace::GetPatchDofs %{ +def GetPatchDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %pythonappend mfem::FiniteElementSpace::FiniteElementSpace%{ diff --git a/mfem/_par/pfespace.i b/mfem/_par/pfespace.i index fc6dd3dd..8e20f201 100644 --- a/mfem/_par/pfespace.i +++ b/mfem/_par/pfespace.i @@ -44,39 +44,44 @@ import_array1(-1); } %feature("shadow") mfem::ParFiniteElementSpace::GetSharedEdgeDofs %{ -def GetSharedEdgeDofs(self, group, ei): - from .array import intArray - dofs = intArray() - $action(self, group, ei, dofs) - return dofs.ToList() -%} -%feature("shadow") mfem::ParFiniteElementSpace::GetSharedFaceDofs %{ -def GetSharedFaceDofs(self, group, fi): - from .array import intArray - dofs = intArray() - $action(self, group, fi, dofs) - return dofs.ToList() +def GetSharedEdgeDofs(self, *args): + if len(args) == 2: + from .array import intArray + dofs = intArray() + $action(self, args[0], args[1], dofs) + return dofs.ToList() + else: + $action(self, *args) %} %feature("shadow") mfem::ParFiniteElementSpace::GetSharedTriangleDofs %{ -def GetSharedTriangleDofs(self, group, fi): - from .array import intArray - dofs = intArray() - $action(self, group, fi, dofs) - return dofs.ToList() +def GetSharedTriangleDofs(self, *args): + if len(args) == 2: + from .array import intArray + dofs = intArray() + $action(self, args[0], args[1], dofs) + return dofs.ToList() + else: + $action(self, *args) %} %feature("shadow") mfem::ParFiniteElementSpace::GetSharedQuadrilateralDofs %{ -def GetSharedQuadrilateralDofs(self, group, fi): - from .array import intArray - dofs = intArray() - $action(self, group, fi, dofs) - return dofs.ToList() +def GetSharedQuadrilateralDofs(self, *args): + if len(args) == 2: + from .array import intArray + dofs = intArray() + $action(self, args[0], args[1], dofs) + return dofs.ToList() + else: + $action(self, *args) %} %feature("shadow") mfem::ParFiniteElementSpace::GetFaceNbrElementVDofs %{ -def GetFaceNbrElementVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetFaceNbrElementVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, i, vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} /* define FiniteElementSpaceArray */ @@ -102,4 +107,3 @@ INSTANTIATE_ARRAY0(ParFiniteElementSpace *, ParFiniteElementSpace, 1) return self->GetFaceNbrElementVDofs(elem, dofs); } }; - diff --git a/mfem/_ser/fespace.i b/mfem/_ser/fespace.i index a150c2c8..12caa38b 100644 --- a/mfem/_ser/fespace.i +++ b/mfem/_ser/fespace.i @@ -57,104 +57,166 @@ ISTREAM_TYPEMAP(std::istream&) //VDoF accesser %feature("shadow") mfem::FiniteElementSpace::GetBdrElementVDofs %{ -def GetBdrElementVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetBdrElementVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementVDofs %{ -def GetElementVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) +%} +%feature("shadow") mfem::FiniteElementSpace::GetPatchVDofs %{ +def GetPatchVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetFaceVDofs %{ -def GetFaceVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetFaceVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeVDofs %{ -def GetEdgeVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetVertexVDofs %{ -def GetVertexVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetVertexVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementInteriorVDofs %{ -def GetElementInteriorVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementInteriorVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeInteriorVDofs %{ -def GetEdgeInteriorVDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeInteriorVDofs(self, *args): + if len(args) == 1: + from .array import intArray + vdofs = intArray() + $action(self, args[0], vdofs) + return vdofs.ToList() + else: + return $action(self, *args) %} //DoF accesser %feature("shadow") mfem::FiniteElementSpace::GetBdrElementDofs %{ -def GetBdrElementDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetBdrElementDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementDofs %{ -def GetElementDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetFaceDofs %{ -def GetFaceDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetFaceDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeDofs %{ -def GetEdgeDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetVertexDofs %{ -def GetVertexDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetVertexDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetElementInteriorDofs %{ -def GetElementInteriorDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetElementInteriorDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %feature("shadow") mfem::FiniteElementSpace::GetEdgeInteriorDofs %{ -def GetEdgeInteriorDofs(self, i): - from .array import intArray - vdofs = intArray() - $action(self, i, vdofs) - return vdofs.ToList() +def GetEdgeInteriorDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) +%} +%feature("shadow") mfem::FiniteElementSpace::GetPatchDofs %{ +def GetPatchDofs(self, *args): + if len(args) == 1: + from .array import intArray + dofs = intArray() + $action(self, args[0], dofs) + return vdofs.ToList() + else: + return $action(self, *args) %} %pythonappend mfem::FiniteElementSpace::FiniteElementSpace%{ @@ -210,4 +272,3 @@ OSTREAM_ADD_DEFAULT_STDOUT_FILE(QuadratureSpace, Save) return self->GetBdrElementVDofs(bel, dofs); } }; -