From 1fed67455abf7a3a535987b77f6ac407cdc02c94 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 19 Sep 2017 15:39:46 -0700 Subject: [PATCH 001/535] x86 intrinsic for the high-performance templated operator --- INSTALL | 3 + config/config.hpp.in | 3 + config/config.mk.in | 1 + config/defaults.mk | 1 + config/tconfig.hpp | 4 + fem/bilinearform.cpp | 14 ++- fem/bilinearform.hpp | 9 +- fem/fespace.cpp | 20 +++- fem/fespace.hpp | 4 +- fem/tbilinearform.hpp | 22 +++-- fem/teltrans.hpp | 34 +++---- fem/tevaluator.hpp | 52 +++++------ fem/tfe.hpp | 4 +- fem/tfespace.hpp | 39 +++++--- fem/tintrules.hpp | 2 +- general/x86intrin.hpp | 173 +++++++++++++++++++++++++++++++++++ linalg/sparsemat.cpp | 13 ++- linalg/sparsemat.hpp | 54 ++++++++++- linalg/tdensemat.hpp | 113 +++++++++++++++++++++++ linalg/ttensor.hpp | 5 +- makefile | 3 +- miniapps/performance/ex1.cpp | 63 ++++++++----- 22 files changed, 531 insertions(+), 105 deletions(-) create mode 100644 general/x86intrin.hpp create mode 100644 linalg/tdensemat.hpp diff --git a/INSTALL b/INSTALL index 36cc45b451..89b3fbea4e 100644 --- a/INSTALL +++ b/INSTALL @@ -317,6 +317,9 @@ MFEM_USE_SIDRE = YES/NO specification. When enabled, this option requires installation of HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project. +MFEM_USE_X86INTRIN = YES/NO + X86 intrinsics will be used. + MFEM_USE_GZSTREAM = YES/NO Enables use of on-the-fly gzip compressed streams. With this feature enabled (YES), MFEM can compress its output files on-the-fly. In addition, it can diff --git a/config/config.hpp.in b/config/config.hpp.in index 2d1d28e140..16862864f0 100644 --- a/config/config.hpp.in +++ b/config/config.hpp.in @@ -88,6 +88,9 @@ // Enable Sidre support // #define MFEM_USE_SIDRE +// Enable x86intrin support +// #define MFEM_USE_X86INTRIN + // Enable functionality based on the NetCDF library (reading CUBIT files) // #define MFEM_USE_NETCDF diff --git a/config/config.mk.in b/config/config.mk.in index 6c969e4bfc..1eb7bc1804 100644 --- a/config/config.mk.in +++ b/config/config.mk.in @@ -33,6 +33,7 @@ MFEM_USE_NETCDF = @MFEM_USE_NETCDF@ MFEM_USE_PETSC = @MFEM_USE_PETSC@ MFEM_USE_MPFR = @MFEM_USE_MPFR@ MFEM_USE_SIDRE = @MFEM_USE_SIDRE@ +MFEM_USE_X86INTRIN = @MFEM_USE_X86INTRIN@ # Compiler, compile options, and link options MFEM_CXX = @MFEM_CXX@ diff --git a/config/defaults.mk b/config/defaults.mk index 8ed1bd5550..588ef68739 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -83,6 +83,7 @@ MFEM_USE_NETCDF = NO MFEM_USE_PETSC = NO MFEM_USE_MPFR = NO MFEM_USE_SIDRE = NO +MFEM_USE_X86INTRIN = NO LIBUNWIND_OPT = -g LIBUNWIND_LIB = $(if $(NOTMAC),-lunwind -ldl,) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index de57f68be2..c3434dfbe9 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -15,6 +15,10 @@ // the main MFEM config header #include "config.hpp" +#ifdef MFEM_USE_X86INTRIN +#include "general/x86intrin.hpp" +#endif + // --- MFEM_STATIC_ASSERT #if (__cplusplus >= 201103L) #define MFEM_STATIC_ASSERT(cond, msg) static_assert((cond), msg) diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index c3cb18ad6c..89fea6a1a1 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -54,7 +54,8 @@ void BilinearForm::AllocMat() int *I = dof_dof.GetI(); int *J = dof_dof.GetJ(); - double *data = new double[I[height]]; + //double *data = new double[I[height]]; + __attribute__ ((aligned(32))) double *data = (double*) aligned_alloc(32,I[height]*sizeof(double)); mat = new SparseMatrix(I, J, data, height, height, true, true, true); *mat = 0.0; @@ -253,6 +254,17 @@ void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) } } +void BilinearForm::AssembleElementMatrix(int i, + const TDenseMatrix &M, + Array &vdofs){ + fes->GetElementVDofs(i, vdofs); + if (mat == NULL) { + std::cout<<"[AssembleElementMatrix] AllocMat"<AddSubMatrix(vdofs, M); +} + void BilinearForm::AssembleElementMatrix( int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros) { diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index b012670f83..c758825160 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -66,8 +66,6 @@ protected: Hybridization *hybridization; int precompute_sparsity; - // Allocate appropriate SparseMatrix and assign it to mat - void AllocMat(); void ConformingAssemble(); @@ -81,7 +79,10 @@ protected: } public: - /// Creates bilinear form associated with FE space *f. + // Allocate appropriate SparseMatrix and assign it to mat + void AllocMat(); + + /// Creates bilinear form associated with FE space *f. BilinearForm(FiniteElementSpace *f); BilinearForm(FiniteElementSpace *f, BilinearForm *bf, int ps = 0); @@ -281,6 +282,8 @@ public: { delete element_matrices; element_matrices = NULL; } void ComputeElementMatrix(int i, DenseMatrix &elmat); + void AssembleElementMatrix(int, const TDenseMatrix&, + Array&); void AssembleElementMatrix(int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros = 1); void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 99dc649404..aadfb0e4e4 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -129,7 +129,11 @@ void FiniteElementSpace::AdjustVDofs (Array &vdofs) } } } - + +void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const +{ + GetElementDofs(i, vdofs); +} void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const { GetElementDofs(i, vdofs); @@ -1066,6 +1070,20 @@ void FiniteElementSpace::Construct() // later. } +void FiniteElementSpace::GetElementDofs(int i, Array &dofs) const{ + Array dof[x86::width]; + for(int k=0; kGetRow(i+k, dof[k]); + const int size = dof[0].Size(); + dofs.SetSize(size); + x86::vint_t gather=0; + for(int j=0;j &dofs) const { if (elem_dof) diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 6347c7e530..e9bd5ab978 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -220,6 +220,7 @@ public: /// Returns indexes of degrees of freedom in array dofs for i'th element. virtual void GetElementDofs(int i, Array &dofs) const; + virtual void GetElementDofs(int i, Array &dofs) const; /// Returns indexes of degrees of freedom for i'th boundary element. virtual void GetBdrElementDofs(int i, Array &dofs) const; @@ -256,7 +257,8 @@ public: /// Returns indexes of degrees of freedom in array dofs for i'th element. void GetElementVDofs(int i, Array &vdofs) const; - + void GetElementVDofs(int i, Array &vdofs) const; + /// Returns indexes of degrees of freedom for i'th boundary element. void GetBdrElementVDofs(int i, Array &vdofs) const; diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 6589871e82..06b8d71b73 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -19,6 +19,7 @@ #include "teltrans.hpp" #include "tcoefficient.hpp" #include "fespace.hpp" +#include "../linalg/tdensemat.hpp" namespace mfem { @@ -170,7 +171,7 @@ public: kernel_t::Action(0, F, wQ, res, R); - solFEval.template Assemble(R); + solFEval.template Assemble(el,R); } } @@ -216,7 +217,7 @@ public: kernel_t::MultAssembled(k, assembled_data[el+k], R); } - solFEval.template Assemble(R); + solFEval.template Assemble(el,R); } // complex_t = double @@ -443,12 +444,18 @@ public: coeff_eval_t wQ(int_rule, coeff); Array vdofs; + Array vdofs128; const Array *dof_map = sol_fe.GetDofMap(); const int *dof_map_ = dof_map->GetData(); DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros + TDenseMatrix tM_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros + const int NE = mesh.GetNE(); - for (int el = 0; el < NE; el++) + MFEM_VERIFY((NE%x86::width)==0,"x86::width should be modulo NE"); + std::cout<<"NE="< 1, assume block-diagonal matrix with the same // diagonal block for all components. TMatrix M_loc; + TMatrix tM_loc; S_spec::ElementMatrix::Compute( - asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval); + asm_qpt_data.layout, asm_qpt_data, tM_loc.layout, tM_loc, solEval); if (dof_map) // switch from tensor-product ordering { @@ -473,15 +481,15 @@ public: { for (int j = 0; j < dofs; j++) { - M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j); + tM_loc_perm(dof_map_[i],dof_map_[j]) = tM_loc(i,j); } } for (int bi = 1; bi < vdim; bi++) { - M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0, + tM_loc_perm.CopyMN(tM_loc_perm, dofs, dofs, 0, 0, bi*dofs, bi*dofs); } - a.AssembleElementMatrix(el, M_loc_perm, vdofs); + a.AssembleElementMatrix(el, tM_loc_perm, vdofs128); } else { diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp index d5a5a530c7..a0cb9be522 100644 --- a/fem/teltrans.hpp +++ b/fem/teltrans.hpp @@ -75,13 +75,13 @@ public: protected: #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - TTensor3 nodes_dof; + TTensor3 nodes_dof; #endif ShapeEval evaluator; FESpace_type fes; nodeLayout_type node_layout; - const real_t *nodes; + const double *nodes; const Element* const *elements; @@ -150,7 +150,7 @@ public: #endif x_type x; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -160,12 +160,12 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); - T.fes.VectorExtract(T.node_layout, T.nodes, + T.fes.VectorExtract(el,T.node_layout, T.nodes, nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, x.layout.merge_23(), x); @@ -191,7 +191,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -201,12 +201,12 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); - T.fes.VectorExtract(T.node_layout, T.nodes, + T.fes.VectorExtract(el,T.node_layout, T.nodes, nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -234,7 +234,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -244,12 +244,12 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); - T.fes.VectorExtract(T.node_layout, T.nodes, + T.fes.VectorExtract(el,T.node_layout, T.nodes, nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, x.layout.merge_23(), x); @@ -280,7 +280,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -291,12 +291,12 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); - T.fes.VectorExtract(T.node_layout, T.nodes, + T.fes.VectorExtract(el,T.node_layout, T.nodes, nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -324,7 +324,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -335,12 +335,12 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); - T.fes.VectorExtract(T.node_layout, T.nodes, + T.fes.VectorExtract(el,T.node_layout, T.nodes, nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 5d1abccf92..78cc841d87 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -41,7 +41,7 @@ protected: TMatrix B; TMatrix Bt; TTensor3 G; - TTensor3 Gt; + TTensor3 Gt; public: ShapeEvaluator_base(const FE &fe) @@ -354,7 +354,7 @@ public: { const int NC = dof_layout_t::dim_2; // DOF x DOF x NC --> NIP x DOF x NC --> NIP x NIP x NC - TTensor3 A; + TTensor3 A; // (1) A_{i,j,k} = \sum_s B_1d_{i,s} dof_data_{s,j,k} Mult_2_1(B_1d.layout, Dx ? G_1d : B_1d, @@ -386,7 +386,7 @@ public: { const int NC = dof_layout_t::dim_2; // NIP x NIP X NC --> NIP x DOF x NC --> DOF x DOF x NC - TTensor3 A; + TTensor3 A; // (1) A_{i,j,k} = \sum_s B_1d_{s,j} qpt_data_{i,s,k} Mult_1_2(B_1d.layout, Dy ? G_1d : B_1d, @@ -469,7 +469,7 @@ public: TTensor3::layout, A, M_layout.merge_23().template split_12(), M_data); #elif 1 - TTensor4 A; + TTensor4 A; // qpt_data --> A TensorAssemble( Bt_1d.layout, Bt_1d, B_1d.layout, B_1d, @@ -517,7 +517,7 @@ public: D_data_t &D_data) const { const int NC = qpt_layout_t::dim_2; - TTensor4 A; + TTensor4 A; // Using TensorAssemble: --> @@ -629,8 +629,8 @@ public: const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { const int NC = dof_layout_t::dim_2; - TVector QDD; - TVector QQD; + TVector QDD; + TVector QQD; // QDD_{i,jj,k} = \sum_s B_1d_{i,s} dof_data_{s,jj,k} Mult_2_1(B_1d.layout, Dx ? G_1d : B_1d, @@ -665,8 +665,8 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { const int NC = dof_layout_t::dim_2; - TVector QDD; - TVector QQD; + TVector QDD; + TVector QQD; // QQD_{ii,j,k} = \sum_s B_1d_{s,j} qpt_data_{ii,s,k} Mult_1_2(B_1d.layout, Dz ? G_1d : B_1d, @@ -795,8 +795,8 @@ public: D_data_t &D_data) const { const int NC = qpt_layout_t::dim_2; - TTensor4 A1; - TTensor4 A2; + TTensor4 A1; + TTensor4 A2; // Using TensorAssemble: --> @@ -1005,15 +1005,15 @@ protected: using base_class::fespace; using base_class::shapeEval; using base_class::vec_layout; - const complex_t *data_in; - complex_t *data_out; + const double *data_in; + double *data_out; public: // With this constructor, fespace is a shallow copy of tfes. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FESpace_t &tfes, const ShapeEval_type &shape_eval, const VecLayout_type &vec_layout, - const complex_t *global_data_in, complex_t *global_data_out) + const double *global_data_in, double *global_data_out) : base_class(tfes, shape_eval, vec_layout), data_in(global_data_in), data_out(global_data_out) @@ -1022,7 +1022,7 @@ public: // With this constructor, fespace is a shallow copy of f.fespace. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FieldEvaluator &f, - const complex_t *global_data_in, complex_t *global_data_out) + const double *global_data_in, double *global_data_out) : base_class(f.fespace, f.shapeEval, f.vec_layout), data_in(global_data_in), data_out(global_data_out) @@ -1031,7 +1031,7 @@ public: // This constructor creates a new fespace, not a shallow copy. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FiniteElementSpace &fes, - const complex_t *global_data_in, complex_t *global_data_out) + const double *global_data_in, double *global_data_out) : base_class(FE_type(*fes.FEColl()), fes), data_in(global_data_in), data_out(global_data_out) @@ -1057,7 +1057,7 @@ public: const int ne = val_layout_t::dim_3; TTensor3 val_dofs; SetElement(el); - fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs); + fespace.VectorExtract(el,vec_layout, data_in, val_dofs.layout, val_dofs); shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, l.merge_23(), vals); } @@ -1069,7 +1069,7 @@ public: const int ne = grad_layout_t::dim_4; TTensor3 val_dofs; SetElement(el); - fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs); + fespace.VectorExtract(el,vec_layout, data_in, val_dofs.layout, val_dofs); shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, l.merge_34(), grad); } @@ -1094,11 +1094,11 @@ public: template inline MFEM_ALWAYS_INLINE - void Assemble(DataType &F) + void AssembleOp(int el, DataType &F) { // T.SetElement() must be called outside Action:: - template Assemble(vec_layout, *this, F); + template Assemble(el,vec_layout, *this, F); } template @@ -1106,7 +1106,7 @@ public: void Assemble(int el, DataType &F) { SetElement(el); - Assemble(F); + AssembleOp(el,F); } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE @@ -1213,7 +1213,7 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif - T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); + T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); T.shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); } @@ -1266,14 +1266,14 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif - T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); + T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); T.shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, D.grad_qpts.layout.merge_34(), D.grad_qpts); } template static inline MFEM_ALWAYS_INLINE - void Assemble(const vec_layout_t &l, T_type &T, AData_t &D) + void Assemble(int el, const vec_layout_t &l, T_type &T, AData_t &D) { const AssignOp::Type Op = Add ? AssignOp::Add : AssignOp::Set; #ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS @@ -1284,7 +1284,7 @@ public: T.shapeEval.template CalcGradT( D.grad_qpts.layout.merge_34(), D.grad_qpts, val_dofs.layout.merge_23(), val_dofs); - T.fespace.template VectorAssemble( + T.fespace.template VectorAssemble(el, val_dofs.layout, val_dofs, l, T.data_out); } @@ -1319,7 +1319,7 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif - T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); + T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); T.shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); T.shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, diff --git a/fem/tfe.hpp b/fem/tfe.hpp index 08e1ccb2bf..78cf5ddc72 100644 --- a/fem/tfe.hpp +++ b/fem/tfe.hpp @@ -36,7 +36,7 @@ void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir, for (int id = 0; id < dof; id++) { int orig_id = dof_map ? (*dof_map)[id] : id; - B[ip+nip*id] = shape(orig_id); + B[ip+nip*id] = x86::set(shape(orig_id)); } } } @@ -60,7 +60,7 @@ void CalcGradTensor(const FiniteElement &fe, const IntegrationRule &ir, int orig_id = dof_map ? (*dof_map)[id] : id; for (int d = 0; d < dim; d++) { - G[ip+nip*(d+dim*id)] = dshape(orig_id, d); + G[ip+nip*(d+dim*id)] = x86::set(dshape(orig_id, d)); } } } diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index 1e7bc5e4ae..d5fc477e8f 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -197,24 +197,30 @@ public: typename vec_layout_t, typename glob_vdof_data_t, typename vdof_layout_t, typename vdof_data_t> inline MFEM_ALWAYS_INLINE - void VectorExtract(const vec_layout_t &vl, + void VectorExtract(const int el, + const vec_layout_t &vl, const glob_vdof_data_t &glob_vdof_data, const vdof_layout_t &vdof_layout, - vdof_data_t &vdof_data) const + vdof_data_t &vdof_data) /*const*/ { const int NC = vdof_layout_t::dim_2; const int NE = vdof_layout_t::dim_3; MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, "invalid number of dofs"); MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); + x86::vreal_t gather; for (int k = 0; k < NC; k++) { for (int j = 0; j < NE; j++) { for (int i = 0; i < FE::dofs; i++) { - Assign(vdof_data[vdof_layout.ind(i,k,j)], - glob_vdof_data[vl.ind(ind.map(i,j), k)]); + for(int n=0; n(vdof_data[vdof_layout.ind(i,k,j)],gather); } } } @@ -223,12 +229,13 @@ public: template inline MFEM_ALWAYS_INLINE - void VectorExtract(const vec_layout_t &vl, + void VectorExtract(const int el, + const vec_layout_t &vl, const glob_vdof_data_t &glob_vdof_data, const vdof_layout_t &vdof_layout, - vdof_data_t &vdof_data) const + vdof_data_t &vdof_data) /*const*/ { - VectorExtract(vl, glob_vdof_data, vdof_layout, vdof_data); + VectorExtract(el,vl, glob_vdof_data, vdof_layout, vdof_data); } // Multi-element VectorAssemble: vdof_layout is (DOFS x NumComp x NumElems). @@ -236,10 +243,11 @@ public: typename vdof_layout_t, typename vdof_data_t, typename vec_layout_t, typename glob_vdof_data_t> inline MFEM_ALWAYS_INLINE - void VectorAssemble(const vdof_layout_t &vdof_layout, + void VectorAssemble(const int el, + const vdof_layout_t &vdof_layout, const vdof_data_t &vdof_data, const vec_layout_t &vl, - glob_vdof_data_t &glob_vdof_data) const + glob_vdof_data_t &glob_vdof_data) //const { const int NC = vdof_layout_t::dim_2; const int NE = vdof_layout_t::dim_3; @@ -252,8 +260,12 @@ public: { for (int i = 0; i < FE::dofs; i++) { - Assign(glob_vdof_data[vl.ind(ind.map(i,j), k)], - vdof_data[vdof_layout.ind(i,k,j)]); + for(int n=0; n(glob_vdof_data[vl.ind(ind.map(i,j), k)], + vdof_data[vdof_layout.ind(i,k,j)][n]); + } } } } @@ -262,12 +274,13 @@ public: template inline MFEM_ALWAYS_INLINE - void VectorAssemble(const vdof_layout_t &vdof_layout, + void VectorAssemble(const int el, + const vdof_layout_t &vdof_layout, const vdof_data_t &vdof_data, const vec_layout_t &vl, glob_vdof_data_t &glob_vdof_data) const { - VectorAssemble(vdof_layout, vdof_data, vl, glob_vdof_data); + VectorAssemble(el,vdof_layout, vdof_data, vl, glob_vdof_data); } // Extract a static number of consecutive components; vdof_layout is diff --git a/fem/tintrules.hpp b/fem/tintrules.hpp index 0f9464f983..c4e6f45a51 100644 --- a/fem/tintrules.hpp +++ b/fem/tintrules.hpp @@ -220,7 +220,7 @@ public: MFEM_ASSERT(ir_1d.GetNPoints() == qpts_1d, "quadrature rule mismatch"); for (int j = 0; j < qpts_1d; j++) { - weights_1d.data[j] = ir_1d.IntPoint(j).weight; + weights_1d.data[j] = x86::set(ir_1d.IntPoint(j).weight); } } diff --git a/general/x86intrin.hpp b/general/x86intrin.hpp new file mode 100644 index 0000000000..46b7bd1682 --- /dev/null +++ b/general/x86intrin.hpp @@ -0,0 +1,173 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. +#ifndef MFEM_X86INTRIN_HPP +#define MFEM_X86INTRIN_HPP + +#include "x86intrin.h" +//#pragma warning MFEM_X86INTRIN_HPP + +// x86intrin class forward description +template struct x86intrin; + +// Switch between SCALAR, SSE, AVX, AVX2, AVX512F +#ifndef __SSE__ +#define __SSE__ 0 +#endif +#ifndef __AVX__ +#define __AVX__ 0 +#endif +#ifndef __AVX2__ +#define __AVX2__ 0 +#endif +#ifndef __AVX512F__ +#define __AVX512F__ 0 +#endif +#define VA_ADD_CXX_FLAGS(drop,a,b,c,d,...) a+b+c+d +#define ADD_CXX_FLAGS(...) VA_ADD_CXX_FLAGS(,##__VA_ARGS__,) +//#define __SIMD__ ADD_CXX_FLAGS(__SSE__,__AVX__,__AVX2__,__AVX512F__) + +//#define STRNG(s) #s +//#define PRAGMA_MESSAGE(m) STRNG(m) +//#pragma message PRAGMA_MESSAGE(__SIMD__) + +#define __SIMD__ 3 + +// **************************************************************************** +// * AVX2 +// **************************************************************************** +#if __SIMD__==3 +//#warning __AVX2__ +// INTEGER type class +struct __attribute__ ((aligned(16))) integer { +protected: + __m128i vec; +public: + // Constructors + inline integer(){} + inline integer(__m128i mm):vec(mm){} + inline integer(int i):vec(_mm_set_epi32(i,i,i,i)){} + // Convertors + inline operator __m128i() const { return vec; } + // Logical Operations + inline integer& operator&=(const integer &a) { return *this = (integer)_mm_and_si128(vec,a); } + inline integer& operator|=(const integer &a) { return *this = (integer)_mm_or_si128(vec,a); } + inline integer& operator^=(const integer &a) { return *this = (integer)_mm_xor_si128(vec,a); } + inline integer& operator+=(const integer &a) { return *this = (integer)_mm_add_epi32(vec,a); } + inline integer& operator-=(const integer &a) { return *this = (integer)_mm_sub_epi32(vec,a); } + // Friends operators + friend inline __m256d operator==(const integer &a, const int i); + // [] operators + inline const int& operator[](int i) const { + const int *a=(int*)&vec; + return a[i]; + } + inline int& operator[](int i) { + int *a=(int*)&vec; + return a[i]; + } +}; +// REAL type class +struct __attribute__ ((aligned(32))) real { + protected: + __attribute__ ((aligned(32))) __m256d vec; + public: + // Constructors + inline real(){} + inline real(int i):vec(_mm256_set1_pd((double)i)){} + inline real(integer i):vec(_mm256_set_pd(i[3],i[2],i[1],i[0])){} + inline real(long i):vec(_mm256_set1_pd((double)i)){} + inline real(double d):vec(_mm256_set1_pd(d)){} + inline real(__m256d x):vec(x){} + inline real(double *x):vec(_mm256_load_pd(x)){} + // Convertors + inline operator __m256d() const { return vec; } + // Arithmetics + friend inline real operator +(const real &a, const real &b) { return _mm256_add_pd(a,b); } + friend inline real operator -(const real &a, const real &b) { return _mm256_sub_pd(a,b); } + friend inline real operator *(const real &a, const real &b) { return _mm256_mul_pd(a,b); } + friend inline real operator /(const real &a, const real &b) { return _mm256_div_pd(a,b); } + // Unary + inline real operator -() const { return _mm256_xor_pd (_mm256_set1_pd(-0.0), *this); } + inline real operator +() const { return vec; } + // Assignment operations + inline real& operator +=(const real &a) { return *this = _mm256_add_pd(vec,a); } + inline real& operator -=(const real &a) { return *this = _mm256_sub_pd(vec,a); } + inline real& operator *=(const real &a) { return *this = _mm256_mul_pd(vec,a); } + inline real& operator /=(const real &a) { return *this = _mm256_div_pd(vec,a); } + // Mixed vector-scalar assignment operations + inline real& operator *=(const double &f) { return *this = _mm256_mul_pd(vec,_mm256_set1_pd(f)); } + inline real& operator /=(const double &f) { return *this = _mm256_div_pd(vec,_mm256_set1_pd(f)); } + inline real& operator +=(const double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } + inline real& operator +=(double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } + inline real& operator -=(const double &f) { return *this = _mm256_sub_pd(vec,_mm256_set1_pd(f)); } + // Friends operator + friend inline real operator +(const real &a, const double &f) { return _mm256_add_pd(a, _mm256_set1_pd(f)); } + friend inline real operator -(const real &a, const double &f) { return _mm256_sub_pd(a, _mm256_set1_pd(f)); } + friend inline real operator *(const real &a, const double &f) { return _mm256_mul_pd(a, _mm256_set1_pd(f)); } + friend inline real operator /(const real &a, const double &f) { return _mm256_div_pd(a, _mm256_set1_pd(f)); } + friend inline real operator +(const double &f, const real &a) { return _mm256_add_pd(_mm256_set1_pd(f),a); } + friend inline real operator -(const double &f, const real &a) { return _mm256_sub_pd(_mm256_set1_pd(f),a); } + friend inline real operator *(const double &f, const real &a) { return _mm256_mul_pd(_mm256_set1_pd(f),a); } + friend inline real operator /(const double &f, const real &a) { return _mm256_div_pd(_mm256_set1_pd(f),a); } + friend inline real sqrt(const real &a) { return _mm256_sqrt_pd(a); } + friend inline real ceil(const real &a) { return _mm256_round_pd((a), _MM_FROUND_CEIL); } + friend inline real floor(const real &a) { return _mm256_round_pd((a), _MM_FROUND_FLOOR); } + friend inline real trunc(const real &a) { return _mm256_round_pd((a), _MM_FROUND_TO_ZERO); } + friend inline real min(const real &r, const real &s){ return _mm256_min_pd(r,s);} + friend inline real max(const real &r, const real &s){ return _mm256_max_pd(r,s);} + //friend inline real round(const real &a) { return _mm256_svml_round_pd(a); } + // Comparison operator + friend inline real cmp_eq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OS); } + friend inline real cmp_lt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } + friend inline real cmp_le(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); } + friend inline real cmp_gt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GT_OS); } + friend inline real cmp_ge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GE_OS); } + friend inline real cmp_neq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_US); } + friend inline real cmp_nlt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); } + friend inline real cmp_nle(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); } + friend inline real cmp_ngt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGT_US); } + friend inline real cmp_nge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGE_US); } + friend inline real operator<(const real &a, const real& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } + friend inline real operator<(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LT_OS); } + friend inline real operator>(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } + friend inline real operator>(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } + friend inline real operator>(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GT_OS); } + friend inline real operator>=(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GE_OS); } + friend inline real operator>=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GE_OS); } + friend inline real operator<=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_LE_OS); } + friend inline real operator<=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LE_OS); } + friend inline real operator==(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_EQ_OQ); } + friend inline real operator==(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_EQ_OQ); } + friend inline real operator!=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_NEQ_UQ); } + friend inline real operator!=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_NEQ_UQ); } + // [] operators + inline const double& operator[](int i) const { + const double *d = (double*)&vec; + return *(d+i); + } + inline double& operator[](int i) { + double *d = (double*)&vec; + return *(d+i); + } +}; +template <> struct x86intrin<3>{ +public: + static const int align = 32; + static const int width = 4; + typedef real vreal_t; + typedef integer vint_t; + static inline vreal_t set(double a){return _mm256_set1_pd(a);} +}; +#endif // __AVX2__ + +class x86: public x86intrin<__SIMD__>{}; + +#endif // MFEM_X86_HPP diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index 8c6921e697..19026a7c6f 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -1846,6 +1846,16 @@ void SparseMatrix::Jacobi3(const Vector &b, const Vector &x0, Vector &x1, } } } + +void SparseMatrix::AddSubMatrix(const Array &idx, + const TDenseMatrix &subm){ + for (int i = 0; i < idx.Size(); i++){ + SetColPtr(idx[i]); + for (int j = 0; j < idx.Size(); j++){ + _Add_(idx[j],subm(i,j)); + } + } +} void SparseMatrix::AddSubMatrix(const Array &rows, const Array &cols, const DenseMatrix &subm, int skip_zeros) @@ -2529,7 +2539,8 @@ void SparseMatrix::Destroy() } if (A != NULL && ownData) { - delete [] A; + #warning delete A + //delete [] A; } if (Rows != NULL) diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index d391abdb69..5385b35120 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -18,6 +18,8 @@ #include "../general/table.hpp" #include "densemat.hpp" #include +#include "../general/x86intrin.hpp" +#include "../linalg/tdensemat.hpp" namespace mfem { @@ -47,13 +49,13 @@ protected: this array is always zero, I[0] = 0, and the last entry, I[height], gives the total number of entries stored (at a minimum, all nonzeros must be represented) in the sparse matrix. */ - int *I; + __attribute__ ((aligned(32))) int *I; /** @brief %Array with size #I[#height], containing the column indices for all matrix entries, as indexed by the #I array. */ - int *J; + __attribute__ ((aligned(32))) int *J; /** @brief %Array with size #I[#height], containing the actual entries of the sparse matrix, as indexed by the #I array. */ - double *A; + __attribute__ ((aligned(32))) double *A; ///@} /** @brief %Array of linked lists, one for every row. This array represents @@ -299,7 +301,11 @@ public: inline void _Set_(const int col, const double a) { SearchRow(col) = a; } inline double _Get_(const int col) const; - + + inline void SetColPtr(const x86::vint_t row) const; + inline void SearchRow(const x86::vint_t col, const x86::vreal_t a); + inline void _Add_(const x86::vint_t col, const x86::vreal_t a){ SearchRow(col,a);} + inline double &SearchRow(const int row, const int col); inline void _Add_(const int row, const int col, const double a) { SearchRow(row, col) += a; } @@ -317,6 +323,8 @@ public: void AddSubMatrix(const Array &rows, const Array &cols, const DenseMatrix &subm, int skip_zeros = 1); + void AddSubMatrix(const Array &idx, + const TDenseMatrix &subm); bool RowIsEmpty(const int row) const; @@ -461,9 +469,45 @@ SparseMatrix * Add(Array & Ai); // Inline methods - +// **************************************************************************** +// * SetColPtr - gather +// **************************************************************************** +inline void SparseMatrix::SetColPtr(const x86::vint_t row) const{ + /*for(int k=0;k +#include +#include +#include +#include + +namespace mfem{ + +/// Data type dense matrix using column-major storage +template +class TDenseMatrix : public Matrix{ +private: + __attribute__ ((aligned(32))) data_t *data; + int capacity; // zero or negative capacity means we do not own the data. +public: + + /// Creates rectangular matrix of size m x n. + TDenseMatrix(int m, int n) : Matrix(m, n){ + MFEM_ASSERT(m >= 0 && n >= 0, + "invalid TDenseMatrix size: " << m << " x " << n); + capacity = m*n; + MFEM_ASSERT(capacity>0,"invalid TDenseMatrix capacity"); + //data = new data_t[capacity](); + data = (data_t*)aligned_alloc(32,capacity*sizeof(data_t)); + } + + /// Returns reference to a_{ij}. + inline data_t &operator()(int i, int j){ + MFEM_ASSERT(data && i >= 0 && i < height && j >= 0 && j < width, ""); + return data[i+j*height]; + } + /// Returns constant reference to a_{ij}. + inline const data_t &operator()(int i, int j) const{ + MFEM_ASSERT(data && i >= 0 && i < height && j >= 0 && j < width, ""); + return data[i+j*height]; + } + + inline DenseMatrix &simd(DenseMatrix &D, int k) const{ + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + D(i,j)=(*this)(i,j)[k]; + return D; + } + + double &Elem(int i, int j){ + MFEM_ASSERT(false,"Elem SIMD HACK"); + return (*this)(i,j)[0]; // SIMD HACK + } + + /// Returns reference to a_{ij}. + const double &Elem(int i, int j) const { + MFEM_ASSERT(false,"Elem not implemented"); + return (*this)(i,j)[0]; + } + + void Mult(const Vector &x, Vector &y) const { + MFEM_ASSERT(false,"Mult not implemented"); + } + + virtual MatrixInverse *Inverse() const { + MFEM_ASSERT(false,"Inverse not implemented"); + return NULL; + } + + /** Copy the m x n submatrix of A at row/col offsets Aro/Aco to *this at + row_offset, col_offset */ + void CopyMN(const TDenseMatrix &A, + int m, int n, int Aro, int Aco, + int row_offset, int col_offset){} + + /// Destroys dense matrix. + ~TDenseMatrix(){} + + void Print(int k,std::ostream &out = std::cout, int width_ = 4) const{ + std::ios::fmtflags old_flags = out.flags(); + // output flags = scientific + show sign + out << setiosflags(std::ios::scientific | std::ios::showpos); + for (int i = 0; i < height; i++){ + out << "[row " << i << "]\n"; + for (int j = 0; j < width; j++){ + out << (*this)(i,j)[k]; + if (j+1 == width || (j+1) % width_ == 0){ + out << '\n'; + }else{ + out << ' '; + } + } + } + // reset output flags to original values + out.flags(old_flags); + } + +}; + +} // namespace mfem + +#endif diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index cfab39cd63..c1416ea2bf 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -246,7 +246,7 @@ public: static const int size = S; static const int aligned_size = align ? MFEM_ALIGN_SIZE(S,data_t) : size; typedef data_t data_type; - data_t data[aligned_size>0?aligned_size:1]; + __attribute__ ((aligned(32))) data_t data[aligned_size>0?aligned_size:1]; typedef StridedLayout1D layout_type; static const layout_type layout; @@ -550,7 +550,8 @@ void TensorAssemble(const A_layout_t &A_layout, const A_data_t &A_data, MFEM_FLOPS_ADD(A1*B1*C1*C3); // computation of H(l) for (int l = 0; l < C3; l++) { - TTensor3 H; + //TTensor3 H; + TTensor3 H; // H(l)_{i,k,s} = A_{i,s} C_{k,s,l} for (int s = 0; s < B1; s++) { diff --git a/makefile b/makefile index 5164bbf78b..e549ef9539 100644 --- a/makefile +++ b/makefile @@ -212,7 +212,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_USE_MPI MFEM_USE_METIS MFEM_USE_METIS_5\ MFEM_THREAD_SAFE MFEM_USE_OPENMP MFEM_USE_MEMALLOC MFEM_TIMER_TYPE\ MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE MFEM_USE_GECKO\ MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS MFEM_USE_NETCDF\ - MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE + MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_X86INTRIN # List of makefile variables that will be written to config.mk: MFEM_CONFIG_VARS = MFEM_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS MFEM_INC_DIR\ @@ -435,6 +435,7 @@ status info: $(info MFEM_USE_PETSC = $(MFEM_USE_PETSC)) $(info MFEM_USE_MPFR = $(MFEM_USE_MPFR)) $(info MFEM_USE_SIDRE = $(MFEM_USE_SIDRE)) + $(info MFEM_USE_X86INTRIN = $(MFEM_USE_X86INTRIN)) $(info MFEM_CXX = $(value MFEM_CXX)) $(info MFEM_CPPFLAGS = $(value MFEM_CPPFLAGS)) $(info MFEM_CXXFLAGS = $(value MFEM_CXXFLAGS)) diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index df63aa5076..780dc185be 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -53,12 +53,15 @@ typedef H1_FiniteElement sol_fe_t; typedef H1_FiniteElementSpace sol_fes_t; // Static quadrature, coefficient and integrator types -typedef TIntegrationRule int_rule_t; -typedef TConstantCoefficient<> coeff_t; +typedef TIntegrationRule int_rule_t; +typedef TConstantCoefficient coeff_t; typedef TIntegrator integ_t; // Static bilinear form type, combining the above types -typedef TBilinearForm HPCBilinearForm; +typedef TBilinearForm HPCBilinearForm; int main(int argc, char *argv[]) { @@ -69,7 +72,7 @@ int main(int argc, char *argv[]) bool static_cond = false; const char *pc = "none"; bool perf = true; - bool matrix_free = true; + bool matrix_free = false; bool visualization = 1; OptionsParser args(argc, argv); @@ -155,8 +158,8 @@ int main(int argc, char *argv[]) // largest number that gives a final mesh with no more than 50,000 // elements. { - int ref_levels = - (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); + int ref_levels = 2; + //(int)floor(log(50000./mesh->GetNE())/log(2.)/dim); for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); @@ -259,7 +262,7 @@ int main(int argc, char *argv[]) "cannot use LOR preconditioner with static condensation"); } - cout << "Assembling the bilinear form ..." << flush; + cout << "Assembling the bilinear form ..." << endl<AddDomainIntegrator(new DiffusionIntegrator(one)); a->Assemble(); } else { - // High-performance assembly/evaluation using the templated operator type - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - if (matrix_free) - { - a_hpc->Assemble(); // partial assembly - } + cout << "High-performance assembly/evaluation using the templated operator type" << flush<< endl; + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (matrix_free) + { + cout<<"partial assembly"<Assemble(); // partial assembly + } else { + cout<<"full matrix assembly"<AssembleBilinearForm(*a); // full matrix assembly } } tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; + cout << " done, " << tic_toc.RealTime() << "s." <FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "Size of linear system: " << a_hpc->Height() << endl; + cout << "[perf && matrix_free] a_hpc FormLinearSystem" << endl<FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "[perf && !matrix_free] Size of linear system: " << a_hpc->Height() << endl; } else { - a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cout << "Size of linear system: " << A.Height() << endl; - a_oper = &A; + cout << "[std] a FormLinearSystem" << endl<FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + cout << "[std] Size of linear system: " << A.Height() << endl; + a_oper = &A; } // Setup the matrix used for preconditioning - cout << "Assembling the preconditioning matrix ..." << flush; + //cout << "Assembling the preconditioning matrix ..." << endl << flush; tic_toc.Clear(); tic_toc.Start(); SparseMatrix A_pc; if (pc_choice == LOR) { - // TODO: assemble the LOR matrix using the performance code + cout << "pc_choice == LOR" << flush << endl; + // TODO: assemble the LOR matrix using the performance code a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); a_pc->UsePrecomputedSparsity(); a_pc->Assemble(); @@ -326,10 +335,12 @@ int main(int argc, char *argv[]) { if (!matrix_free) { + cout << "!matrix_free" << flush << endl; A_pc.MakeRef(A); // matrix already assembled, reuse it } else { + cout << "else" << flush << endl; a_pc->UsePrecomputedSparsity(); a_hpc->AssembleBilinearForm(*a_pc); a_pc->FormSystemMatrix(ess_tdof_list, A_pc); @@ -342,21 +353,25 @@ int main(int argc, char *argv[]) // Solve with CG or PCG, depending if the matrix A_pc is available if (pc_choice != NONE) { - GSSmoother M(A_pc); - PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); + cout << "PCG" << endl; + GSSmoother M(A_pc); + PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); } else { + cout << "CG" << endl; CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); } // 13. Recover the solution as a finite element grid function. if (perf && matrix_free) { - a_hpc->RecoverFEMSolution(X, *b, x); + cout << "a_hpc->RecoverFEMSolution" << endl; + a_hpc->RecoverFEMSolution(X, *b, x); } else { + cout << "a->RecoverFEMSolution" << endl; a->RecoverFEMSolution(X, *b, x); } From 8c1041979f0b28bd2fb6f29de557f744ae508e5c Mon Sep 17 00:00:00 2001 From: camierjs Date: Thu, 21 Sep 2017 17:47:22 -0700 Subject: [PATCH 002/535] x86 scalar/sse/avx/avx2/avx512 header files --- config/tconfig.hpp | 2 + general/x86_m128.hpp | 151 ++++++++++++++++++++++++++++++ general/x86_m256.hpp | 133 ++++++++++++++++++++++++++ general/x86_m512.hpp | 133 ++++++++++++++++++++++++++ general/x86_m64.hpp | 54 +++++++++++ general/x86intrin.hpp | 211 ++++++++++++++++-------------------------- linalg/sparsemat.hpp | 26 ++---- 7 files changed, 564 insertions(+), 146 deletions(-) create mode 100644 general/x86_m128.hpp create mode 100644 general/x86_m256.hpp create mode 100644 general/x86_m512.hpp create mode 100644 general/x86_m64.hpp diff --git a/config/tconfig.hpp b/config/tconfig.hpp index c3434dfbe9..5ec182dcbb 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -34,7 +34,9 @@ #endif #define MFEM_TEMPLATE_BLOCK_SIZE 4 +#ifndef MFEM_SIMD_SIZE #define MFEM_SIMD_SIZE 32 +#endif #define MFEM_TEMPLATE_ENABLE_SERIALIZE // #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS diff --git a/general/x86_m128.hpp b/general/x86_m128.hpp new file mode 100644 index 0000000000..8a70d2403b --- /dev/null +++ b/general/x86_m128.hpp @@ -0,0 +1,151 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. +#ifndef MFEM_X86_M128_HPP +#define MFEM_X86_M128_HPP + +// **************************************************************************** +// * SSE integer +// **************************************************************************** +struct __attribute__ ((aligned(8))) integer { +protected: + __m128i vec; +public: + // Constructors + inline integer():vec(_mm_set_epi32(0,0,0,0)){} + inline integer(__m128i mm):vec(mm){} + inline integer(int i):vec(_mm_set_epi32(0,0,i,i)){} + inline integer(int i0, int i1){vec=_mm_set_epi32(0, 0, i1, i0);} + // Convertors + inline operator __m128i() const { return vec; } + // Logical Operations + inline integer& operator&=(const integer &a) { return *this = (integer) _mm_and_si128(vec,a); } + inline integer& operator|=(const integer &a) { return *this = (integer) _mm_or_si128(vec,a); } + inline integer& operator^=(const integer &a) { return *this = (integer) _mm_xor_si128(vec,a); } + friend inline integer operator<(const integer &a, const integer &b) { return _mm_cmpeq_epi32(a, b); } + // Arithmetics + friend inline integer operator +(const integer &a, const integer &b) { return _mm_add_epi32(a,b); } + friend inline integer operator -(const integer &a, const integer &b) { return _mm_sub_epi32(a,b); } + friend inline integer operator *(const integer &a, const integer &b) { return _mm_mul_epi32(a,b); } + friend inline integer operator /(const integer &a, const integer &b) { + return _mm_set_epi32(a[0]/b[0],a[1]/b[1],0,0); + } + friend inline integer operator %(const integer &a, const integer &b) { + return _mm_set_epi32(a[0]%b[0],a[1]%b[1],0,0); + } + inline integer& operator +=(const integer &a) { return *this = (integer)_mm_add_epi32(vec,a); } + inline integer& operator -=(const integer &a) { return *this = (integer)_mm_sub_epi32(vec,a); } + //friend inline __m128d operator==(const integer &a, const int i); + inline const int& operator[](int i) const { + int *a=(int*)&vec; + return a[i]; + } + inline int& operator[](int i) { + int *a=(int*)&vec; + return a[i]; + } +}; +// Logicals +//inline integer operator&(const integer &a, const integer &b) { return _mm_and_si128(a,b); } +//inline integer operator|(const integer &a, const integer &b) { return _mm_or_si128(a,b); } +//inline integer operator^(const integer &a, const integer &b) { return _mm_xor_si128(a,b); } + +// **************************************************************************** +// * SSE real type class +// **************************************************************************** +struct __attribute__ ((aligned(16))) real { + protected: + __m128d vec; + public: + // Constructors + inline real(): vec(_mm_setzero_pd()){} + inline real(int i):vec(_mm_set1_pd((double)i)){} + inline real(integer i):vec(_mm_set_pd(i[1],i[0])){} + inline real(long i):vec(_mm_set1_pd((double)i)){} + inline real(double d):vec(_mm_set1_pd(d)){} + inline real(__m128d x):vec(x){} + inline real(double *x):vec(_mm_load_pd(x)){} + inline real(double d0, double d1):vec(_mm_set_pd(d1,d0)){} + // Convertors + inline operator __m128d() const { return vec; } + // Arithmetics + friend inline real operator +(const real &a, const real &b) { return _mm_add_pd(a,b); } + friend inline real operator -(const real &a, const real &b) { return _mm_sub_pd(a,b); } + friend inline real operator *(const real &a, const real &b) { return _mm_mul_pd(a,b); } + //CLANG has a built-in candidate +#ifndef __clang_major__ + friend inline real operator /(const real &a, const real &b) { return _mm_div_pd(a,b); } +#endif + inline real& operator +=(const real &a) { return *this = _mm_add_pd(vec,a); } + inline real& operator -=(const real &a) { return *this = _mm_sub_pd(vec,a); } + inline real& operator *=(const real &a) { return *this = _mm_mul_pd(vec,a); } + inline real& operator /=(const real &a) { return *this = _mm_div_pd(vec,a); } + // Unary +/- operators + inline real operator -() const { return _mm_xor_pd (_mm_set1_pd(-0.0), *this); } + inline real operator +() const { return vec; } + // Mixed vector-scalar operations + inline real& operator *=(const double &f) { return *this = _mm_mul_pd(vec,_mm_set1_pd(f)); } + inline real& operator /=(const double &f) { return *this = _mm_div_pd(vec,_mm_set1_pd(f)); } + inline real& operator +=(const double &f) { return *this = _mm_add_pd(vec,_mm_set1_pd(f)); } + inline real& operator +=(double &f) { return *this = _mm_add_pd(vec,_mm_set1_pd(f)); } + inline real& operator -=(const double &f) { return *this = _mm_sub_pd(vec,_mm_set1_pd(f)); } + // Friends operators + friend inline real operator+(const real &a, const double &f) { return _mm_add_pd(a, _mm_set1_pd(f)); } + friend inline real operator-(const real &a, const double &f) { return _mm_sub_pd(a, _mm_set1_pd(f)); } + friend inline real operator*(const real &a, const double &f) { return _mm_mul_pd(a, _mm_set1_pd(f)); } + friend inline real operator/(const real &a, const double &f) { return _mm_div_pd(a, _mm_set1_pd(f)); } + friend inline real operator+(const double &f, const real &a) { return _mm_add_pd(_mm_set1_pd(f),a); } + friend inline real operator-(const double &f, const real &a) { return _mm_sub_pd(_mm_set1_pd(f),a); } + friend inline real operator*(const double &f, const real &a) { return _mm_mul_pd(_mm_set1_pd(f),a); } + friend inline real operator/(const double &f, const real &a) { return _mm_div_pd(_mm_set1_pd(f),a); } + + friend inline real sqrt(const real &a) { return _mm_sqrt_pd(a); } + friend inline real min(const real &r, const real &s){ return _mm_min_pd(r,s);} + friend inline real max(const real &r, const real &s){ return _mm_max_pd(r,s);} + friend inline real cube_root(const real &a){return real(::cbrt(a[0]),::cbrt(a[1]));} + friend inline real norm(const real &u){ return real(::fabs(u[0]),::fabs(u[1]));} + // Compares: Mask is returned + friend inline real cmp_eq(const real &a, const real &b) { return _mm_cmpeq_pd(a, b); } + friend inline real cmp_lt(const real &a, const real &b) { return _mm_cmplt_pd(a, b); } + friend inline real cmp_le(const real &a, const real &b) { return _mm_cmple_pd(a, b); } + friend inline real cmp_gt(const real &a, const real &b) { return _mm_cmpgt_pd(a, b); } + friend inline real cmp_ge(const real &a, const real &b) { return _mm_cmpge_pd(a, b); } + friend inline real cmp_neq(const real &a, const real &b) { return _mm_cmpneq_pd(a, b); } + friend inline real cmp_nlt(const real &a, const real &b) { return _mm_cmpnlt_pd(a, b); } + friend inline real cmp_nle(const real &a, const real &b) { return _mm_cmpnle_pd(a, b); } + friend inline real cmp_ngt(const real &a, const real &b) { return _mm_cmpngt_pd(a, b); } + friend inline real cmp_nge(const real &a, const real &b) { return _mm_cmpnge_pd(a, b); } + // Comparison operators + friend inline real operator<(const real &a, const real& b) { return _mm_cmplt_pd(a, b); } + friend inline real operator<(const real &a, double d) { return _mm_cmplt_pd(a, _mm_set1_pd(d)); } + friend inline real operator>(const real &a, real& r) { return _mm_cmpgt_pd(a, r); } + friend inline real operator>(const real &a, const real& r) { return _mm_cmpgt_pd(a, r); } + friend inline real operator>(const real &a, double d) { return _mm_cmpgt_pd(a, _mm_set1_pd(d)); } + friend inline real operator>=(const real &a, real& r) { return _mm_cmpge_pd(a, r); } + friend inline real operator>=(const real &a, double d) { return _mm_cmpge_pd(a, _mm_set1_pd(d)); } + friend inline real operator<=(const real &a, const real& r) { return _mm_cmple_pd(a, r); } + friend inline real operator<=(const real &a, double d) { return _mm_cmple_pd(a, _mm_set1_pd(d)); } + friend inline real operator==(const real &a, const real& r) { return _mm_cmpeq_pd(a, r); } + friend inline real operator==(const real &a, double d) { return _mm_cmpeq_pd(a, _mm_set1_pd(d)); } + friend inline real operator!=(const real &a, const real& r) { return _mm_cmpneq_pd(a, r); } + friend inline real operator!=(const real &a, double d) { return _mm_cmpneq_pd(a, _mm_set1_pd(d)); } + // [] operators + inline const double& operator[](int i) const { + double *d= (double*)&vec; + return d[i]; + } + + inline double& operator[](int i) { + double *d = (double*)&vec; + return d[i]; + } +}; + +#endif // MFEM_X86_M128_HPP diff --git a/general/x86_m256.hpp b/general/x86_m256.hpp new file mode 100644 index 0000000000..91c48428d9 --- /dev/null +++ b/general/x86_m256.hpp @@ -0,0 +1,133 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. +#ifndef MFEM_X86_M256_HPP +#define MFEM_X86_M256_HPP + +// **************************************************************************** +// * AVX integer type class +// **************************************************************************** +struct __attribute__ ((aligned(16))) integer { +protected: + __m128i vec; +public: + // Constructors + inline integer(){} + inline integer(__m128i mm):vec(mm){} + inline integer(int i):vec(_mm_set_epi32(i,i,i,i)){} + // Convertors + inline operator __m128i() const { return vec; } + // Logical Operations + inline integer& operator&=(const integer &a) { return *this = (integer)_mm_and_si128(vec,a); } + inline integer& operator|=(const integer &a) { return *this = (integer)_mm_or_si128(vec,a); } + inline integer& operator^=(const integer &a) { return *this = (integer)_mm_xor_si128(vec,a); } + inline integer& operator+=(const integer &a) { return *this = (integer)_mm_add_epi32(vec,a); } + inline integer& operator-=(const integer &a) { return *this = (integer)_mm_sub_epi32(vec,a); } + // Friends operators + //friend inline __m256d operator==(const integer &a, const int i); + // [] operators + inline const int& operator[](int i) const { + const int *a=(int*)&vec; + return a[i]; + } + inline int& operator[](int i) { + int *a=(int*)&vec; + return a[i]; + } +}; + +// **************************************************************************** +// * AVX real type class +// **************************************************************************** +struct __attribute__ ((aligned(32))) real { + protected: + __m256d vec; + public: + // Constructors + inline real(){} + inline real(int i):vec(_mm256_set1_pd((double)i)){} + inline real(integer i):vec(_mm256_set_pd(i[3],i[2],i[1],i[0])){} + inline real(long i):vec(_mm256_set1_pd((double)i)){} + inline real(double d):vec(_mm256_set1_pd(d)){} + inline real(__m256d x):vec(x){} + inline real(double *x):vec(_mm256_load_pd(x)){} + // Convertors + inline operator __m256d() const { return vec; } + // Arithmetics + friend inline real operator +(const real &a, const real &b) { return _mm256_add_pd(a,b); } + friend inline real operator -(const real &a, const real &b) { return _mm256_sub_pd(a,b); } + friend inline real operator *(const real &a, const real &b) { return _mm256_mul_pd(a,b); } + friend inline real operator /(const real &a, const real &b) { return _mm256_div_pd(a,b); } + // Unary + inline real operator -() const { return _mm256_xor_pd (_mm256_set1_pd(-0.0), *this); } + inline real operator +() const { return vec; } + // Assignment operations + inline real& operator +=(const real &a) { return *this = _mm256_add_pd(vec,a); } + inline real& operator -=(const real &a) { return *this = _mm256_sub_pd(vec,a); } + inline real& operator *=(const real &a) { return *this = _mm256_mul_pd(vec,a); } + inline real& operator /=(const real &a) { return *this = _mm256_div_pd(vec,a); } + // Mixed vector-scalar assignment operations + inline real& operator *=(const double &f) { return *this = _mm256_mul_pd(vec,_mm256_set1_pd(f)); } + inline real& operator /=(const double &f) { return *this = _mm256_div_pd(vec,_mm256_set1_pd(f)); } + inline real& operator +=(const double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } + inline real& operator +=(double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } + inline real& operator -=(const double &f) { return *this = _mm256_sub_pd(vec,_mm256_set1_pd(f)); } + // Friends operator + friend inline real operator +(const real &a, const double &f) { return _mm256_add_pd(a, _mm256_set1_pd(f)); } + friend inline real operator -(const real &a, const double &f) { return _mm256_sub_pd(a, _mm256_set1_pd(f)); } + friend inline real operator *(const real &a, const double &f) { return _mm256_mul_pd(a, _mm256_set1_pd(f)); } + friend inline real operator /(const real &a, const double &f) { return _mm256_div_pd(a, _mm256_set1_pd(f)); } + friend inline real operator +(const double &f, const real &a) { return _mm256_add_pd(_mm256_set1_pd(f),a); } + friend inline real operator -(const double &f, const real &a) { return _mm256_sub_pd(_mm256_set1_pd(f),a); } + friend inline real operator *(const double &f, const real &a) { return _mm256_mul_pd(_mm256_set1_pd(f),a); } + friend inline real operator /(const double &f, const real &a) { return _mm256_div_pd(_mm256_set1_pd(f),a); } + friend inline real sqrt(const real &a) { return _mm256_sqrt_pd(a); } + friend inline real ceil(const real &a) { return _mm256_round_pd((a), _MM_FROUND_CEIL); } + friend inline real floor(const real &a) { return _mm256_round_pd((a), _MM_FROUND_FLOOR); } + friend inline real trunc(const real &a) { return _mm256_round_pd((a), _MM_FROUND_TO_ZERO); } + friend inline real min(const real &r, const real &s){ return _mm256_min_pd(r,s);} + friend inline real max(const real &r, const real &s){ return _mm256_max_pd(r,s);} + //friend inline real round(const real &a) { return _mm256_svml_round_pd(a); } + // Comparison operator + friend inline real cmp_eq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OS); } + friend inline real cmp_lt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } + friend inline real cmp_le(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); } + friend inline real cmp_gt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GT_OS); } + friend inline real cmp_ge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GE_OS); } + friend inline real cmp_neq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_US); } + friend inline real cmp_nlt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); } + friend inline real cmp_nle(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); } + friend inline real cmp_ngt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGT_US); } + friend inline real cmp_nge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGE_US); } + friend inline real operator<(const real &a, const real& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } + friend inline real operator<(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LT_OS); } + friend inline real operator>(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } + friend inline real operator>(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } + friend inline real operator>(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GT_OS); } + friend inline real operator>=(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GE_OS); } + friend inline real operator>=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GE_OS); } + friend inline real operator<=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_LE_OS); } + friend inline real operator<=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LE_OS); } + friend inline real operator==(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_EQ_OQ); } + friend inline real operator==(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_EQ_OQ); } + friend inline real operator!=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_NEQ_UQ); } + friend inline real operator!=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_NEQ_UQ); } + // [] operators + inline const double& operator[](int i) const { + const double *d = (double*)&vec; + return *(d+i); + } + inline double& operator[](int i) { + double *d = (double*)&vec; + return *(d+i); + } +}; + +#endif // MFEM_X86_M256_HPP diff --git a/general/x86_m512.hpp b/general/x86_m512.hpp new file mode 100644 index 0000000000..11d360eb2c --- /dev/null +++ b/general/x86_m512.hpp @@ -0,0 +1,133 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. +#ifndef MFEM_X86_M512_HPP +#define MFEM_X86_M512_HPP + +// **************************************************************************** +// * AVX512 integer type class +// **************************************************************************** +struct __attribute__ ((aligned(64))) integer { +protected: + __m512i vec; +public: + // Constructors + inline integer(){} + inline integer(__m512i mm):vec(mm){} + inline integer(int i):vec(_mm512_set_epi64(i,i,i,i,i,i,i,i)){} + inline integer(int i7, int i6, int i5, int i4, + int i3, int i2, int i1, int i0){vec=_mm512_set_epi64(i7,i6,i5,i4,i3,i2,i1,i0);} + // Convertors + inline operator __m512i() const { return vec; } + // Logical Operations + inline integer& operator&=(const integer &a) { return *this = (integer) _mm512_and_epi64(vec,a); } + inline integer& operator|=(const integer &a) { return *this = (integer) _mm512_or_epi64(vec,a); } + inline integer& operator^=(const integer &a) { return *this = (integer) _mm512_xor_epi64(vec,a); } + inline integer& operator+=(const integer &a) { return *this = (integer)_mm512_add_epi64(vec,a); } + inline integer& operator-=(const integer &a) { return *this = (integer)_mm512_sub_epi64(vec,a); } + // Friends operators + //friend inline __mmask8 operator==(const integer &a, const int i); + // [] operators + inline const int& operator[](const int i) const { + int *dp = (int*)&vec; + return *(dp+i); + } + inline int& operator[](const int i) { + int *dp = (int*)&vec; + return *(dp+i); + } +}; +// Logicals +//inline integer operator&(const integer &a, const integer &b) { return _mm512_and_epi64(a,b); } +//inline integer operator|(const integer &a, const integer &b) { return _mm512_or_epi64(a,b); } +//inline integer operator^(const integer &a, const integer &b) { return _mm512_xor_epi64(a,b); } +//inline __mmask8 operator==(const integer &a, const int i){ +// return _mm512_cmp_epi64_mask(a.vec,_mm512_set_epi64(i,i,i,i,i,i,i,i),_MM_CMPINT_EQ); +//} + + +// **************************************************************************** +// * AVX512 real type class +// **************************************************************************** +struct __attribute__ ((aligned(64))) real { + protected: + __m512d vec; + public: + // Constructors + inline real(){} + inline real(__m512i d):vec(_mm512_set_pd(d[0],d[1],d[2],d[3], + d[4],d[5],d[6],d[7])){} + inline real(integer d):vec(_mm512_set_pd(d[0],d[1],d[2],d[3], + d[4],d[5],d[6],d[7])){} + inline real(int d):vec(_mm512_set1_pd(d)){} + inline real(double d):vec(_mm512_set1_pd(d)){} + inline real(__m512d x):vec(x){} + inline real(double *x):vec(_mm512_load_pd(x)){} + inline real(double d7, double d6, double d5, double d4, + double d3, double d2, double d1, double d0): + vec(_mm512_set_pd(d7,d6,d5,d4,d3,d2,d1,d0)){} + // Conversion operator + inline operator __m512d() const { return vec; } + // Arithmetics + friend inline real operator +(const real &a, const real &b){ return _mm512_add_pd(a,b); } + friend inline real operator -(const real &a, const real &b){ return _mm512_sub_pd(a,b); } + friend inline real operator *(const real &a, const real &b){ return _mm512_mul_pd(a,b); } +#ifndef __clang_major__ + friend inline real operator /(const real &a, const real &b){ return _mm512_div_pd(a,b); } +#endif + inline real& operator +=(const real &a){ return *this = _mm512_add_pd(vec,a); } + inline real& operator -=(const real &a){ return *this = _mm512_sub_pd(vec,a); } + inline real& operator *=(const real &a){ return *this = _mm512_mul_pd(vec,a); } + inline real& operator /=(const real &a){ return *this = _mm512_div_pd(vec,a); } + // Unary + or - + inline real operator -() const { return real(0.0) - vec; } + inline real operator -() { return real(0.0) - vec; } + inline real operator +() { return vec; } + // Mixed vector-scalar operations + inline real& operator *=(const double &f){ return *this = _mm512_mul_pd(vec,_mm512_set1_pd(f)); } + inline real& operator /=(const double &f){ return *this = _mm512_div_pd(vec,_mm512_set1_pd(f)); } + inline real& operator +=(const double &f){ return *this = _mm512_add_pd(vec,_mm512_set1_pd(f)); } + inline real& operator +=(double &f){ return *this = _mm512_add_pd(vec,_mm512_set1_pd(f)); } + inline real& operator -=(const double &f){ return *this = _mm512_sub_pd(vec,_mm512_set1_pd(f)); } + // Friends operators + friend inline real operator +(const real &a, const double &f){ return _mm512_add_pd(a, _mm512_set1_pd(f)); } + friend inline real operator -(const real &a, const double &f){ return _mm512_sub_pd(a, _mm512_set1_pd(f)); } + friend inline real operator *(const real &a, const double &f){ return _mm512_mul_pd(a, _mm512_set1_pd(f)); } + friend inline real operator /(const real &a, const double &f){ return _mm512_div_pd(a, _mm512_set1_pd(f)); } + friend inline real operator +(const double &f, const real &a){ return _mm512_add_pd(_mm512_set1_pd(f),a); } + friend inline real operator -(const double &f, const real &a){ return _mm512_sub_pd(_mm512_set1_pd(f),a); } + friend inline real operator *(const double &f, const real &a){ return _mm512_mul_pd(_mm512_set1_pd(f),a); } + friend inline real operator /(const double &f, const real &a){ return _mm512_div_pd(_mm512_set1_pd(f),a); } + // Comparison operators + friend inline __mmask8 operator==(const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_EQ_OQ); } + friend inline __mmask8 operator==(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_EQ_OQ); } + friend inline __mmask8 operator< (const real &a, const real& b){ return _mm512_cmp_pd_mask(a,b,_CMP_LT_OS); } + friend inline __mmask8 operator< (const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_LT_OS); } + friend inline __mmask8 operator<=(const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_LE_OS); } + friend inline __mmask8 operator<=(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_LE_OS); } + friend inline __mmask8 operator> (const real &a, real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NLE_US); } + friend inline __mmask8 operator> (const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NLE_US); } + friend inline __mmask8 operator> (const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_NLE_US); } + friend inline __mmask8 operator>=(const real &a, real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NLT_US); } + friend inline __mmask8 operator>=(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_NLT_US); } + friend inline __mmask8 operator!=(const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NEQ_UQ); } + friend inline __mmask8 operator!=(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_NEQ_UQ); } + // [] operators + inline const double& operator[](const int i) const { + double *dp = (double*)&vec; + return *(dp+i); + } + inline double& operator[](const int i){ + double *dp = (double*)&vec; + return *(dp+i); + } +}; + +#endif // MFEM_X86_M512_HPP diff --git a/general/x86_m64.hpp b/general/x86_m64.hpp new file mode 100644 index 0000000000..cd5b03b491 --- /dev/null +++ b/general/x86_m64.hpp @@ -0,0 +1,54 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. +#ifndef MFEM_X86_M64_HPP +#define MFEM_X86_M64_HPP + +// **************************************************************************** +// * STD integer +// **************************************************************************** +struct integer { +protected: + int vec; +public: + // Constructors + inline integer():vec(){} + inline integer(int i):vec(i){} + // Convertors + inline operator int() const { return vec; } + // Arithmetics + friend inline integer operator *(const integer &a, const integer &b) { return a*b; } + // [] operator + inline int& operator[](int k) { return vec; } + inline const int& operator[](int k) const { return vec; } +}; + +// **************************************************************************** +// * STD real type class +// **************************************************************************** +struct real { + protected: + double vec; + public: + // Constructors + inline real(): vec(){} + inline real(double a): vec(a){} + // Convertors + inline operator double() const { return vec; } + // Arithmetics + inline real& operator+=(const real &a) { return *this = vec+a; } + // Mixed vector-scalar operations + inline real& operator*=(const double &f) { return *this = vec*f; } + // [] operators + inline const double& operator[](int k) const { return vec; } + inline double& operator[](int k) { return vec; } +}; + +#endif // MFEM_X86_M64_HPP diff --git a/general/x86intrin.hpp b/general/x86intrin.hpp index 46b7bd1682..495323c3a1 100644 --- a/general/x86intrin.hpp +++ b/general/x86intrin.hpp @@ -12,14 +12,16 @@ #define MFEM_X86INTRIN_HPP #include "x86intrin.h" -//#pragma warning MFEM_X86INTRIN_HPP -// x86intrin class forward description +// x86 intrinsic class forward description template struct x86intrin; -// Switch between SCALAR, SSE, AVX, AVX2, AVX512F -#ifndef __SSE__ -#define __SSE__ 0 +// **************************************************************************** +// * ifdef switch between SCALAR, SSE, AVX, AVX2, AVX512F +// gcc --machine-avx512f -ffreestanding -C -E general/x86intrin.hpp|more +// **************************************************************************** +#ifndef __SSE2__ +#define __SSE2__ 0 #endif #ifndef __AVX__ #define __AVX__ 0 @@ -30,134 +32,32 @@ template struct x86intrin; #ifndef __AVX512F__ #define __AVX512F__ 0 #endif -#define VA_ADD_CXX_FLAGS(drop,a,b,c,d,...) a+b+c+d -#define ADD_CXX_FLAGS(...) VA_ADD_CXX_FLAGS(,##__VA_ARGS__,) -//#define __SIMD__ ADD_CXX_FLAGS(__SSE__,__AVX__,__AVX2__,__AVX512F__) - -//#define STRNG(s) #s -//#define PRAGMA_MESSAGE(m) STRNG(m) -//#pragma message PRAGMA_MESSAGE(__SIMD__) - -#define __SIMD__ 3 +#define __SIMD__ __SSE2__+__AVX__+__AVX2__+__AVX512F__ +//__SIMD__ // **************************************************************************** -// * AVX2 +// * AVX512 (-mavx512f) +// **************************************************************************** +#if __SIMD__==4 +#include "x86_m512.hpp" +#define MFEM_SIMD_SIZE 64 +#pragma message "X86intrin::AVX512" +template <> struct x86intrin<4>{ +public: + const static int align = 64; + const static int width = 8; + typedef real vreal_t; + typedef integer vint_t; + static inline vreal_t set(double a){return _mm512_set1_pd(a);} +}; +#endif // __AVX512__ + +// **************************************************************************** +// * AVX2 (-mavx2) // **************************************************************************** #if __SIMD__==3 -//#warning __AVX2__ -// INTEGER type class -struct __attribute__ ((aligned(16))) integer { -protected: - __m128i vec; -public: - // Constructors - inline integer(){} - inline integer(__m128i mm):vec(mm){} - inline integer(int i):vec(_mm_set_epi32(i,i,i,i)){} - // Convertors - inline operator __m128i() const { return vec; } - // Logical Operations - inline integer& operator&=(const integer &a) { return *this = (integer)_mm_and_si128(vec,a); } - inline integer& operator|=(const integer &a) { return *this = (integer)_mm_or_si128(vec,a); } - inline integer& operator^=(const integer &a) { return *this = (integer)_mm_xor_si128(vec,a); } - inline integer& operator+=(const integer &a) { return *this = (integer)_mm_add_epi32(vec,a); } - inline integer& operator-=(const integer &a) { return *this = (integer)_mm_sub_epi32(vec,a); } - // Friends operators - friend inline __m256d operator==(const integer &a, const int i); - // [] operators - inline const int& operator[](int i) const { - const int *a=(int*)&vec; - return a[i]; - } - inline int& operator[](int i) { - int *a=(int*)&vec; - return a[i]; - } -}; -// REAL type class -struct __attribute__ ((aligned(32))) real { - protected: - __attribute__ ((aligned(32))) __m256d vec; - public: - // Constructors - inline real(){} - inline real(int i):vec(_mm256_set1_pd((double)i)){} - inline real(integer i):vec(_mm256_set_pd(i[3],i[2],i[1],i[0])){} - inline real(long i):vec(_mm256_set1_pd((double)i)){} - inline real(double d):vec(_mm256_set1_pd(d)){} - inline real(__m256d x):vec(x){} - inline real(double *x):vec(_mm256_load_pd(x)){} - // Convertors - inline operator __m256d() const { return vec; } - // Arithmetics - friend inline real operator +(const real &a, const real &b) { return _mm256_add_pd(a,b); } - friend inline real operator -(const real &a, const real &b) { return _mm256_sub_pd(a,b); } - friend inline real operator *(const real &a, const real &b) { return _mm256_mul_pd(a,b); } - friend inline real operator /(const real &a, const real &b) { return _mm256_div_pd(a,b); } - // Unary - inline real operator -() const { return _mm256_xor_pd (_mm256_set1_pd(-0.0), *this); } - inline real operator +() const { return vec; } - // Assignment operations - inline real& operator +=(const real &a) { return *this = _mm256_add_pd(vec,a); } - inline real& operator -=(const real &a) { return *this = _mm256_sub_pd(vec,a); } - inline real& operator *=(const real &a) { return *this = _mm256_mul_pd(vec,a); } - inline real& operator /=(const real &a) { return *this = _mm256_div_pd(vec,a); } - // Mixed vector-scalar assignment operations - inline real& operator *=(const double &f) { return *this = _mm256_mul_pd(vec,_mm256_set1_pd(f)); } - inline real& operator /=(const double &f) { return *this = _mm256_div_pd(vec,_mm256_set1_pd(f)); } - inline real& operator +=(const double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } - inline real& operator +=(double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } - inline real& operator -=(const double &f) { return *this = _mm256_sub_pd(vec,_mm256_set1_pd(f)); } - // Friends operator - friend inline real operator +(const real &a, const double &f) { return _mm256_add_pd(a, _mm256_set1_pd(f)); } - friend inline real operator -(const real &a, const double &f) { return _mm256_sub_pd(a, _mm256_set1_pd(f)); } - friend inline real operator *(const real &a, const double &f) { return _mm256_mul_pd(a, _mm256_set1_pd(f)); } - friend inline real operator /(const real &a, const double &f) { return _mm256_div_pd(a, _mm256_set1_pd(f)); } - friend inline real operator +(const double &f, const real &a) { return _mm256_add_pd(_mm256_set1_pd(f),a); } - friend inline real operator -(const double &f, const real &a) { return _mm256_sub_pd(_mm256_set1_pd(f),a); } - friend inline real operator *(const double &f, const real &a) { return _mm256_mul_pd(_mm256_set1_pd(f),a); } - friend inline real operator /(const double &f, const real &a) { return _mm256_div_pd(_mm256_set1_pd(f),a); } - friend inline real sqrt(const real &a) { return _mm256_sqrt_pd(a); } - friend inline real ceil(const real &a) { return _mm256_round_pd((a), _MM_FROUND_CEIL); } - friend inline real floor(const real &a) { return _mm256_round_pd((a), _MM_FROUND_FLOOR); } - friend inline real trunc(const real &a) { return _mm256_round_pd((a), _MM_FROUND_TO_ZERO); } - friend inline real min(const real &r, const real &s){ return _mm256_min_pd(r,s);} - friend inline real max(const real &r, const real &s){ return _mm256_max_pd(r,s);} - //friend inline real round(const real &a) { return _mm256_svml_round_pd(a); } - // Comparison operator - friend inline real cmp_eq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OS); } - friend inline real cmp_lt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } - friend inline real cmp_le(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); } - friend inline real cmp_gt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GT_OS); } - friend inline real cmp_ge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GE_OS); } - friend inline real cmp_neq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_US); } - friend inline real cmp_nlt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); } - friend inline real cmp_nle(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); } - friend inline real cmp_ngt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGT_US); } - friend inline real cmp_nge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGE_US); } - friend inline real operator<(const real &a, const real& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } - friend inline real operator<(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LT_OS); } - friend inline real operator>(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } - friend inline real operator>(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } - friend inline real operator>(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GT_OS); } - friend inline real operator>=(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GE_OS); } - friend inline real operator>=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GE_OS); } - friend inline real operator<=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_LE_OS); } - friend inline real operator<=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LE_OS); } - friend inline real operator==(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_EQ_OQ); } - friend inline real operator==(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_EQ_OQ); } - friend inline real operator!=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_NEQ_UQ); } - friend inline real operator!=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_NEQ_UQ); } - // [] operators - inline const double& operator[](int i) const { - const double *d = (double*)&vec; - return *(d+i); - } - inline double& operator[](int i) { - double *d = (double*)&vec; - return *(d+i); - } -}; +#include "x86_m256.hpp" +#pragma message "X86intrin::AVX2" template <> struct x86intrin<3>{ public: static const int align = 32; @@ -168,6 +68,57 @@ public: }; #endif // __AVX2__ +// **************************************************************************** +// * AVX (-mavx -mno-avx2) +// **************************************************************************** +#if __SIMD__==2 +#pragma message "X86intrin::AVX" +#include "x86_m256.hpp" +template <> struct x86intrin<2>{ +public: + static const int align = 32; + static const int width = 4; + typedef real vreal_t; + typedef integer vint_t; + static inline vreal_t set(double a){return _mm256_set1_pd(a);} +}; +#endif // __AVX__ + +// **************************************************************************** +// * SSE (-mno-avx) +// **************************************************************************** +#if __SIMD__==1 +#include "x86_m128.hpp" +#pragma message "X86intrin::SSE" +template <> struct x86intrin<1>{ +public: + static const int align = 16; + static const int width = 2; + typedef real vreal_t; + typedef integer vint_t; + static inline vreal_t set(double a){return _mm_set1_pd(a);} +}; +#endif // __SSE__ + +// **************************************************************************** +// * 'SCALAR' (-mno-sse2) +// **************************************************************************** +#if __SIMD__==0 +#include "x86_m64.hpp" +#pragma message "X86intrin::STD" +template <> struct x86intrin<0>{ +public: + static const int align = 8; + static const int width = 1; + typedef real vreal_t; + typedef integer vint_t; + static inline vreal_t set(double a){return a;} +}; +#endif // __STD__ + +// **************************************************************************** +// * X86 intrinsic base class +// **************************************************************************** class x86: public x86intrin<__SIMD__>{}; -#endif // MFEM_X86_HPP +#endif // MFEM_X86INTRIN_HPP diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index 5385b35120..643781960b 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -49,14 +49,14 @@ protected: this array is always zero, I[0] = 0, and the last entry, I[height], gives the total number of entries stored (at a minimum, all nonzeros must be represented) in the sparse matrix. */ - __attribute__ ((aligned(32))) int *I; - /** @brief %Array with size #I[#height], containing the column indices for - all matrix entries, as indexed by the #I array. */ - __attribute__ ((aligned(32))) int *J; - /** @brief %Array with size #I[#height], containing the actual entries of the - sparse matrix, as indexed by the #I array. */ - __attribute__ ((aligned(32))) double *A; - ///@} + int *I; + /** @brief %Array with size #I[#height], containing the column indices for + all matrix entries, as indexed by the #I array. */ + int *J; + /** @brief %Array with size #I[#height], containing the actual entries of the + sparse matrix, as indexed by the #I array. */ + double *A; + ///@} /** @brief %Array of linked lists, one for every row. This array represents the linked list (LIL) storage format. */ @@ -472,12 +472,7 @@ SparseMatrix * Add(Array & Ai); // **************************************************************************** // * SetColPtr - gather // **************************************************************************** -inline void SparseMatrix::SetColPtr(const x86::vint_t row) const{ - /*for(int k=0;k Date: Thu, 28 Sep 2017 11:21:43 -0700 Subject: [PATCH 003/535] GCC, ICC & Clang alignment sanitization for TBilinearForm root class --- config/tconfig.hpp | 8 +- fem/bilinearform.cpp | 4 +- fem/coefficient.hpp | 2 +- fem/tbilinearform.hpp | 25 ++-- fem/tevaluator.hpp | 32 ++++- fem/tfe.hpp | 9 +- general/array.cpp | 7 +- general/table.cpp | 48 +++++--- general/x86_m128.hpp | 12 +- general/x86_m256.hpp | 6 +- general/x86intrin.hpp | 6 +- linalg/blockmatrix.cpp | 1 + linalg/densemat.cpp | 12 +- linalg/matrix.hpp | 2 +- linalg/operator.hpp | 2 +- linalg/sparsemat.cpp | 24 ++-- linalg/sparsemat.hpp | 2 +- linalg/tdensemat.hpp | 8 +- linalg/ttensor.hpp | 13 ++- makefile | 2 + miniapps/performance/ex1.cpp | 214 ++++++++++++++++++---------------- miniapps/performance/makefile | 2 +- 22 files changed, 269 insertions(+), 172 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 5ec182dcbb..026684d4a9 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -15,10 +15,6 @@ // the main MFEM config header #include "config.hpp" -#ifdef MFEM_USE_X86INTRIN -#include "general/x86intrin.hpp" -#endif - // --- MFEM_STATIC_ASSERT #if (__cplusplus >= 201103L) #define MFEM_STATIC_ASSERT(cond, msg) static_assert((cond), msg) @@ -33,6 +29,10 @@ #define MFEM_ALWAYS_INLINE #endif +#ifdef MFEM_USE_X86INTRIN +#include "general/x86intrin.hpp" +#endif + #define MFEM_TEMPLATE_BLOCK_SIZE 4 #ifndef MFEM_SIMD_SIZE #define MFEM_SIMD_SIZE 32 diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index 89fea6a1a1..bd9631215f 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -54,8 +54,8 @@ void BilinearForm::AllocMat() int *I = dof_dof.GetI(); int *J = dof_dof.GetJ(); - //double *data = new double[I[height]]; - __attribute__ ((aligned(32))) double *data = (double*) aligned_alloc(32,I[height]*sizeof(double)); + double *data = new double[I[height]]; + //double *data = (double*) aligned_alloc(x86::align,I[height]*sizeof(double)); mat = new SparseMatrix(I, J, data, height, height, true, true, true); *mat = 0.0; diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 9d6460bc0d..74b8799543 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -28,7 +28,7 @@ class ParMesh; /// Base class Coefficient that may optionally depend on time. -class Coefficient + class Coefficient { protected: double time; diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 06b8d71b73..8b3cca3215 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -34,7 +34,16 @@ template class TBilinearForm : public Operator { -protected: + public: + static void* operator new(size_t count) { return Allocate(count); } +private: + static void* Allocate(size_t count) { + void* result = nullptr; + const auto alloc_failed = posix_memalign(&result, 32, count); + if (alloc_failed) throw ::std::bad_alloc(); + return result; + } + protected: typedef complex_t complex_type; typedef real_t real_type; @@ -450,15 +459,19 @@ public: DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros TDenseMatrix tM_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros - + TMatrix M_loc; + TMatrix tM_loc; + f_assembled_t asm_qpt_data; + const int NE = mesh.GetNE(); + MFEM_VERIFY((NE%x86::width)==0,"x86::width should be modulo NE"); std::cout<<"NE="<::Type F; T.Eval(el, F); @@ -470,9 +483,7 @@ public: // For now, when vdim > 1, assume block-diagonal matrix with the same // diagonal block for all components. - TMatrix M_loc; - TMatrix tM_loc; - S_spec::ElementMatrix::Compute( + S_spec::ElementMatrix::Compute( asm_qpt_data.layout, asm_qpt_data, tM_loc.layout, tM_loc, solEval); if (dof_map) // switch from tensor-product ordering diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 78cc841d87..35dff18bda 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -46,10 +46,14 @@ protected: public: ShapeEvaluator_base(const FE &fe) { + std::cout<<"[ShapeEvaluator_base]"<(Bt.layout, Bt, B.layout.transpose_12(), B); + std::cout<<"[ShapeEvaluator_base] CalcTransposed"<(Gt.layout.merge_23(), Gt, G.layout.merge_12().transpose_12(), G); + std::cout<<"[ShapeEvaluator_base] CalcMerged"< --> #if 0 @@ -184,6 +193,7 @@ public: const D_layout_t &D_layout, D_data_t &D_data) const { + std::cout<<"[ShapeEvaluator_base::AssembleGradGrad]"< F; for (int k = 0; k < NC; k++) @@ -218,7 +228,7 @@ protected: TMatrix Bt_1d, Gt_1d; public: - TProductShapeEvaluator() { } + TProductShapeEvaluator() { std::cout<<"[TProductShapeEvaluator<1D>]"<] NIP="<::Calc]"< NIP x DOF x NC --> NIP x NIP x NC TTensor3 A; @@ -374,6 +385,7 @@ public: void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::Calc] bis"<(dof_layout, dof_data, qpt_layout, qpt_data); } @@ -384,6 +396,7 @@ public: void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::CalcT]"< NIP x DOF x NC --> DOF x DOF x NC TTensor3 A; @@ -407,6 +420,7 @@ public: void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::Calc] bis"<(qpt_layout, qpt_data, dof_layout, dof_data); } @@ -420,6 +434,7 @@ public: const grad_layout_t &grad_layout, grad_data_t &grad_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::CalcGrad]"<(dof_layout, dof_data, grad_layout.ind2(0), grad_data); Calc(dof_layout, dof_data, @@ -438,6 +453,7 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::CalcGradT]"<(grad_layout.ind2(0), grad_data, dof_layout, dof_data); CalcT(grad_layout.ind2(1), grad_data, @@ -452,6 +468,7 @@ public: void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const M_layout_t &M_layout, M_data_t &M_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::Assemble]"< --> @@ -516,6 +533,7 @@ public: const D_layout_t &D_layout, D_data_t &D_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::Assemble] bis"< A; @@ -546,6 +564,7 @@ public: const D_layout_t &D_layout, D_data_t &D_data) const { + //std::cout<<"[TProductShapeEvaluator<2D>::AssembleGradGrad]"<(qpt_layout.ind23(0,0), qpt_data, D_layout, D_data); Assemble<1,0,true >(qpt_layout.ind23(1,0), qpt_data, D_layout, D_data); @@ -619,7 +638,7 @@ public: static const int TDOF = DOF*DOF*DOF; // total dofs static const int TNIP = NIP*NIP*NIP; // total qpts - TProductShapeEvaluator() { } + TProductShapeEvaluator() { std::cout<<"[TProductShapeEvaluator] 3D"<(Bt_1d.layout, Bt_1d, B_1d.layout.transpose_12(), B_1d); + std::cout<<"[ShapeEvaluator_base] G Transpose:"<(Gt_1d.layout, Gt_1d, G_1d.layout.transpose_12(), G_1d); } @@ -1089,7 +1111,7 @@ public: void Eval(int el, DataType &F) { SetElement(el); - Eval(F); + Eval(F);//Eval(el,F); } template diff --git a/fem/tfe.hpp b/fem/tfe.hpp index 78cf5ddc72..75d726c4b6 100644 --- a/fem/tfe.hpp +++ b/fem/tfe.hpp @@ -70,6 +70,7 @@ template void CalcShapes(const FiniteElement &fe, const IntegrationRule &ir, real_t *B, real_t *G, const Array *dof_map) { + std::cout<<"[CalcShapes]"< void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { + std::cout<<"[CalcShapes] H1"< @@ -191,6 +193,7 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { + std::cout<<"[CalcShapes] H1 bis"< *GetDofMap() const { return NULL; } @@ -252,11 +255,13 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { - mfem::CalcShapes(*my_fe, ir, B, G, my_dof_map); + std::cout<<"[H1_FiniteElement::CalcShapes]"< void Calc1DShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { + std::cout<<"[H1_FiniteElement::Calc1DShapes]"< *GetDofMap() const { return my_dof_map; } @@ -310,6 +315,7 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { + std::cout<<"[CalcShapes] H1 TETRAHEDRON"< *GetDofMap() const { return NULL; } @@ -440,6 +446,7 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *Grad) const { + std::cout<<"[CalcShapes] L2"< diff --git a/general/array.cpp b/general/array.cpp index b7384bfd98..976b7c067b 100644 --- a/general/array.cpp +++ b/general/array.cpp @@ -13,6 +13,7 @@ // Abstract array data type #include "array.hpp" +#include "x86intrin.hpp" namespace mfem { @@ -21,7 +22,8 @@ BaseArray::BaseArray(int asize, int ainc, int elementsize) { if (asize > 0) { - data = new char[asize * elementsize]; + //data = new char[asize * elementsize]; + data = (void*)aligned_alloc(x86::align,sizeof(char)*asize*elementsize); size = allocsize = asize; } else @@ -46,7 +48,8 @@ void BaseArray::GrowSize(int minsize, int elementsize) int nsize = (inc > 0) ? abs(allocsize) + inc : 2 * abs(allocsize); if (nsize < minsize) { nsize = minsize; } - p = new char[nsize * elementsize]; + //p = new char[nsize * elementsize]; + p = (void*)aligned_alloc(x86::align,sizeof(char)*nsize*elementsize); if (size > 0) { memcpy(p, data, size * elementsize); diff --git a/general/table.cpp b/general/table.cpp index a15a237459..efa6149431 100644 --- a/general/table.cpp +++ b/general/table.cpp @@ -17,6 +17,8 @@ #include "array.hpp" #include "table.hpp" #include "error.hpp" +#include "error.hpp" +#include "x86intrin.hpp" namespace mfem { @@ -29,8 +31,10 @@ Table::Table(const Table &table) if (size >= 0) { const int nnz = table.I[size]; - I = new int[size+1]; - J = new int[nnz]; + //I = new int[size+1]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1)); + //J = new int[nnz]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(nnz)); memcpy(I, table.I, sizeof(int)*(size+1)); memcpy(J, table.J, sizeof(int)*nnz); } @@ -45,8 +49,10 @@ Table::Table (int dim, int connections_per_row) int i, j, sum = dim * connections_per_row; size = dim; - I = new int[size+1]; - J = new int[sum]; + //I = new int[size+1]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1)); + //J = new int[sum]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(sum)); I[0] = 0; for (i = 1; i <= size; i++) @@ -60,8 +66,10 @@ Table::Table (int nrows, int *partitioning) { size = nrows; - I = new int[size+1]; - J = new int[size]; + //I = new int[size+1]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1)); + //J = new int[size]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(size)); for (int i = 0; i < size; i++) { @@ -90,7 +98,8 @@ void Table::MakeJ() j = I[i], I[i] = k, k += j; } - J = new int[I[size]=k]; + //J = new int[I[size]=k]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(I[size]=k)); } void Table::AddConnections (int r, const int *c, int nc) @@ -137,14 +146,16 @@ void Table::SetDims(int rows, int nnz) if (size != rows) { size = rows; - if (I) { delete [] I; } - I = (rows >= 0) ? (new int[rows+1]) : (NULL); + //if (I) { delete [] I; } + //I = (rows >= 0) ? (new int[rows+1]) : (NULL); + I = (rows >= 0) ? (int*)aligned_alloc(x86::align,sizeof(int)*(rows+1)) : (NULL); } if (j != nnz) { - if (J) { delete [] J; } - J = (nnz > 0) ? (new int[nnz]) : (NULL); + //if (J) { delete [] J; } + //J = (nnz > 0) ? (new int[nnz]) : (NULL); + J = (nnz >= 0) ? (int*)aligned_alloc(x86::align,sizeof(int)*(nnz)) : (NULL); } if (size >= 0) @@ -238,7 +249,8 @@ void Table::Finalize() if (sum != I[size]) { - int *NewJ = new int[sum]; + //int *NewJ = new int[sum]; + int *NewJ = (int*)aligned_alloc(x86::align,sizeof(int)*(sum)); for (i=0; i &list) size = nrows; int nnz = list.Size(); - I = new int[size+1]; - J = new int[nnz]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1));//new int[size+1]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(nnz));//new int[nnz]; for (int i = 0, k = 0; i <= size; i++) { @@ -347,13 +359,13 @@ void Table::Load(istream &in) delete [] J; in >> size; - I = new int[size+1]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1));//new int[size+1]; for (int i = 0; i <= size; i++) { in >> I[i]; } int nnz = I[size]; - J = new int[nnz]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(nnz));//new int[nnz]; for (int j = 0; j < nnz; j++) { in >> J[j]; @@ -401,8 +413,8 @@ long Table::MemoryUsage() const Table::~Table () { - if (I) { delete [] I; } - if (J) { delete [] J; } + //if (I) { delete [] I; } + //if (J) { delete [] J; } } void Transpose (const Table &A, Table &At, int _ncols_A) diff --git a/general/x86_m128.hpp b/general/x86_m128.hpp index 8a70d2403b..9e1511765f 100644 --- a/general/x86_m128.hpp +++ b/general/x86_m128.hpp @@ -31,10 +31,10 @@ public: inline integer& operator^=(const integer &a) { return *this = (integer) _mm_xor_si128(vec,a); } friend inline integer operator<(const integer &a, const integer &b) { return _mm_cmpeq_epi32(a, b); } // Arithmetics - friend inline integer operator +(const integer &a, const integer &b) { return _mm_add_epi32(a,b); } - friend inline integer operator -(const integer &a, const integer &b) { return _mm_sub_epi32(a,b); } - friend inline integer operator *(const integer &a, const integer &b) { return _mm_mul_epi32(a,b); } - friend inline integer operator /(const integer &a, const integer &b) { + friend inline integer operator+(const integer &a, const integer &b) { return _mm_add_epi32(a,b); } + friend inline integer operator-(const integer &a, const integer &b) { return _mm_sub_epi32(a,b); } + //friend inline integer operator*(const integer &a, const integer &b) { return _mm_mul_epi32(a,b); } + friend inline integer operator/(const integer &a, const integer &b) { return _mm_set_epi32(a[0]/b[0],a[1]/b[1],0,0); } friend inline integer operator %(const integer &a, const integer &b) { @@ -109,8 +109,8 @@ struct __attribute__ ((aligned(16))) real { friend inline real sqrt(const real &a) { return _mm_sqrt_pd(a); } friend inline real min(const real &r, const real &s){ return _mm_min_pd(r,s);} friend inline real max(const real &r, const real &s){ return _mm_max_pd(r,s);} - friend inline real cube_root(const real &a){return real(::cbrt(a[0]),::cbrt(a[1]));} - friend inline real norm(const real &u){ return real(::fabs(u[0]),::fabs(u[1]));} + //friend inline real cube_root(const real &a){return real(::cbrt(a[0]),::cbrt(a[1]));} + //friend inline real norm(const real &u){ return real(::fabs(u[0]),::fabs(u[1]));} // Compares: Mask is returned friend inline real cmp_eq(const real &a, const real &b) { return _mm_cmpeq_pd(a, b); } friend inline real cmp_lt(const real &a, const real &b) { return _mm_cmplt_pd(a, b); } diff --git a/general/x86_m256.hpp b/general/x86_m256.hpp index 91c48428d9..6b8d193068 100644 --- a/general/x86_m256.hpp +++ b/general/x86_m256.hpp @@ -16,7 +16,7 @@ // **************************************************************************** struct __attribute__ ((aligned(16))) integer { protected: - __m128i vec; + __attribute__ ((aligned(16))) __m128i vec; public: // Constructors inline integer(){} @@ -45,8 +45,10 @@ public: // **************************************************************************** // * AVX real type class +// * error 0x81e350 +// * ok with: 0x81e020 // **************************************************************************** -struct __attribute__ ((aligned(32))) real { +struct real { protected: __m256d vec; public: diff --git a/general/x86intrin.hpp b/general/x86intrin.hpp index 495323c3a1..72d77f24b5 100644 --- a/general/x86intrin.hpp +++ b/general/x86intrin.hpp @@ -16,9 +16,13 @@ // x86 intrinsic class forward description template struct x86intrin; + // **************************************************************************** // * ifdef switch between SCALAR, SSE, AVX, AVX2, AVX512F -// gcc --machine-avx512f -ffreestanding -C -E general/x86intrin.hpp|more +// * gcc --machine-avx512f -ffreestanding -C -E general/x86intrin.hpp|more +// * strings /usr/local/cuda/bin/nvcc | grep [-]D +// * gcc -dM -E -m64 - < /dev/null|sort|grep -i x86 +// * __CUDA_ARCH__ vs __x86_64__ // **************************************************************************** #ifndef __SSE2__ #define __SSE2__ 0 diff --git a/linalg/blockmatrix.cpp b/linalg/blockmatrix.cpp index f5ac83b550..cdd03e940f 100644 --- a/linalg/blockmatrix.cpp +++ b/linalg/blockmatrix.cpp @@ -10,6 +10,7 @@ // Software Foundation) version 2.1 dated February 1999. #include "../general/array.hpp" +#include "../general/x86intrin.hpp" #include "matrix.hpp" #include "sparsemat.hpp" #include "blockvector.hpp" diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 6d93dbb41d..f44931bc18 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -13,6 +13,7 @@ // Implementation of data types dense matrix, inverse dense matrix +#include "../general/x86intrin.hpp" #include "vector.hpp" #include "matrix.hpp" #include "densemat.hpp" @@ -44,7 +45,7 @@ DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.height, m.width) int hw = height * width; if (hw > 0) { - data = new double[hw]; + data = (double*) aligned_alloc(x86::align,sizeof(double)*(hw));//new double[hw]; capacity = hw; for (int i = 0; i < hw; i++) { @@ -64,7 +65,7 @@ DenseMatrix::DenseMatrix(int s) : Matrix(s) capacity = s*s; if (capacity > 0) { - data = new double[capacity](); // init with zeroes + data = (double*) aligned_alloc(x86::align,sizeof(double)*(capacity));//new double[capacity](); // init with zeroes } else { @@ -79,7 +80,7 @@ DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n) capacity = m*n; if (capacity > 0) { - data = new double[capacity](); // init with zeroes + data = (double*) aligned_alloc(x86::align,sizeof(double)*(capacity));//new double[capacity](); // init with zeroes } else { @@ -93,7 +94,7 @@ DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch) capacity = height*width; if (capacity > 0) { - data = new double[capacity]; + data = (double*) aligned_alloc(x86::align,sizeof(double)*(capacity));//new double[capacity]; for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) @@ -125,7 +126,8 @@ void DenseMatrix::SetSize(int h, int w) delete [] data; } capacity = hw; - data = new double[hw](); // init with zeroes + //data = new double[hw](); // init with zeroes + data = (double*) aligned_alloc(x86::align,sizeof(double)*(hw)); // init with zeroes } } diff --git a/linalg/matrix.hpp b/linalg/matrix.hpp index 9be099ba8c..f79c5776be 100644 --- a/linalg/matrix.hpp +++ b/linalg/matrix.hpp @@ -24,7 +24,7 @@ namespace mfem class MatrixInverse; /// Abstract data type matrix -class Matrix : public Operator + class Matrix : public Operator { friend class MatrixInverse; public: diff --git a/linalg/operator.hpp b/linalg/operator.hpp index 86be45997a..bec9051c72 100644 --- a/linalg/operator.hpp +++ b/linalg/operator.hpp @@ -18,7 +18,7 @@ namespace mfem { /// Abstract operator -class Operator + class Operator { protected: int height; ///< Dimension of the output / number of rows in the matrix. diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index 19026a7c6f..bdde013bff 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -108,9 +108,12 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize) #ifdef MFEM_USE_MEMALLOC NodesMem = NULL; #endif - I = new int[nrows + 1]; - J = new int[nrows * rowsize]; - A = new double[nrows * rowsize]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(nrows+1)); + //I = new int[nrows + 1]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*(nrows*rowsize)); + //J = new int[nrows * rowsize]; + A = (double*)aligned_alloc(x86::align,sizeof(double)*nrows*rowsize); + //A = new double[nrows * rowsize]; for (int i = 0; i <= nrows; i++) { @@ -754,7 +757,8 @@ void SparseMatrix::Finalize(int skip_zeros, bool fix_empty_rows) delete [] ColPtrNode; ColPtrNode = NULL; - I = new int[height+1]; + //I = new int[height+1]; + I = (int*)aligned_alloc(x86::align,sizeof(int)*(height+1)); I[0] = 0; for (i = 1; i <= height; i++) { @@ -769,8 +773,10 @@ void SparseMatrix::Finalize(int skip_zeros, bool fix_empty_rows) } nz = I[height]; - J = new int[nz]; - A = new double[nz]; + //J = new int[nz]; + J = (int*)aligned_alloc(x86::align,sizeof(int)*nz); + //A = new double[nz]; + A = (double*)aligned_alloc(x86::align,sizeof(double)*nz); // Assume we're sorted until we find out otherwise isSorted = true; for (j = i = 0; i < height; i++) @@ -2531,15 +2537,15 @@ void SparseMatrix::Destroy() { if (I != NULL && ownGraph) { - delete [] I; + //delete [] I; } if (J != NULL && ownGraph) { - delete [] J; + //delete [] J; } if (A != NULL && ownData) { - #warning delete A +#warning delete A //delete [] A; } diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index 643781960b..8047c4b235 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -480,7 +480,7 @@ inline void SparseMatrix::SetColPtr(const x86::vint_t row) const{ ColPtrJ[k*width+i] = -1; } for(int k=0;k class TDenseMatrix : public Matrix{ private: - __attribute__ ((aligned(32))) data_t *data; + data_t *data; int capacity; // zero or negative capacity means we do not own the data. public: /// Creates rectangular matrix of size m x n. TDenseMatrix(int m, int n) : Matrix(m, n){ - MFEM_ASSERT(m >= 0 && n >= 0, + std::cout<<"[TDenseMatrix]"<= 0 && n >= 0, "invalid TDenseMatrix size: " << m << " x " << n); capacity = m*n; MFEM_ASSERT(capacity>0,"invalid TDenseMatrix capacity"); //data = new data_t[capacity](); - data = (data_t*)aligned_alloc(32,capacity*sizeof(data_t)); + data = (data_t*)aligned_alloc(x86::align,capacity*sizeof(data_t)); } /// Returns reference to a_{ij}. diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index c1416ea2bf..17ad2a06ee 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -246,7 +246,13 @@ public: static const int size = S; static const int aligned_size = align ? MFEM_ALIGN_SIZE(S,data_t) : size; typedef data_t data_type; - __attribute__ ((aligned(32))) data_t data[aligned_size>0?aligned_size:1]; + + //__attribute__ ((aligned(32))) data_t data[aligned_size>0?aligned_size:1]; + data_t *data = (data_t*)aligned_alloc(x86::align, sizeof(data_t)*(aligned_size>0?aligned_size:1)); + /*TVector(){ + std::cout<<"[TVector] size="< layout_type; static const layout_type layout; @@ -309,6 +315,11 @@ struct TMatrix : public TVector typedef ColumnMajorLayout2D layout_type; static const layout_type layout; + + /*TMatrix(){ + std::cout<<"[TMatrix]"<GetNE())/log(2.)/dim); - for (int l = 0; l < ref_levels; l++) - { + if (ref_levels==-1) + ref_levels = + (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); + for (int l = 0; l < ref_levels; l++) + { mesh->UniformRefinement(); - } + } } if (mesh->MeshGenerator() & 1) // simplex mesh { MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" " the LOR preconditioner yet"); } - + std::cout<<"NE="<GetNE()<<""<GetTrueVSize() << endl; + cout << "Number of finite element unknowns: " + << fespace->GetTrueVSize() <<""<< endl; // Create the LOR mesh and finite element space. In the settings of this // example, we can transfer between HO and LOR with the identity operator. @@ -274,27 +284,27 @@ int main(int argc, char *argv[]) if (!perf) { // Standard assembly using a diffusion domain integrator - cout << "Standard assembly using a diffusion domain integrator ..." << flush<< endl; + cout << "[std] Standard assembly using a diffusion domain integrator ..." << flush<< endl; a->AddDomainIntegrator(new DiffusionIntegrator(one)); a->Assemble(); } else { - cout << "High-performance assembly/evaluation using the templated operator type" << flush<< endl; - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + cout << "[perf] High-performance assembly/evaluation using the templated operator type" << flush<< endl; + a_hpc = new HPCBilinearForm(integ_t(coeff_t(x86::set(1.0))), *fespace); if (matrix_free) { - cout<<"partial assembly"<Assemble(); // partial assembly } else { - cout<<"full matrix assembly"<AssembleBilinearForm(*a); // full matrix assembly } } tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." <FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "[perf && !matrix_free] Size of linear system: " << a_hpc->Height() << endl; - } - else - { - cout << "[std] a FormLinearSystem" << endl<FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cout << "[std] Size of linear system: " << A.Height() << endl; - a_oper = &A; - } + if (solve_also){ + if (perf && matrix_free) + { + cout << "[perf && free] a_hpc FormLinearSystem" << endl<FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "[perf && free] Size of linear system: " << a_hpc->Height() << endl; + } + else + { + cout << "[std] a FormLinearSystem" << endl<FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + cout << "[std] Size of linear system: " << A.Height() << endl; + a_oper = &A; + } - // Setup the matrix used for preconditioning - //cout << "Assembling the preconditioning matrix ..." << endl << flush; - tic_toc.Clear(); - tic_toc.Start(); + // Setup the matrix used for preconditioning + //cout << "Assembling the preconditioning matrix ..." << endl << flush; + tic_toc.Clear(); + tic_toc.Start(); - SparseMatrix A_pc; - if (pc_choice == LOR) - { - cout << "pc_choice == LOR" << flush << endl; - // TODO: assemble the LOR matrix using the performance code - a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); - a_pc->UsePrecomputedSparsity(); - a_pc->Assemble(); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - else if (pc_choice == HO) - { - if (!matrix_free) - { - cout << "!matrix_free" << flush << endl; - A_pc.MakeRef(A); // matrix already assembled, reuse it - } - else - { - cout << "else" << flush << endl; + SparseMatrix A_pc; + if (pc_choice == LOR) + { + cout << "pc_choice == LOR" << flush << endl; + // TODO: assemble the LOR matrix using the performance code + a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); + a_pc->Assemble(); a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - } + } + else if (pc_choice == HO) + { + if (!matrix_free) + { + cout << "[std] matrix already assembled, reuse it" << flush << endl; + A_pc.MakeRef(A); // matrix already assembled, reuse it + } + else + { + cout << "[hpc && free] else" << flush << endl; + a_pc->UsePrecomputedSparsity(); + a_hpc->AssembleBilinearForm(*a_pc); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + } - tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; + tic_toc.Stop(); + cout << " done, " << tic_toc.RealTime() << "s." << endl; - // Solve with CG or PCG, depending if the matrix A_pc is available - if (pc_choice != NONE) - { - cout << "PCG" << endl; - GSSmoother M(A_pc); - PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); - } - else - { - cout << "CG" << endl; - CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); - } + // Solve with CG or PCG, depending if the matrix A_pc is available + if (pc_choice != NONE) + { + cout << "PCG" << endl; + GSSmoother M(A_pc); + PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); + } + else + { + cout << "CG" << endl; + CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + } - // 13. Recover the solution as a finite element grid function. - if (perf && matrix_free) - { - cout << "a_hpc->RecoverFEMSolution" << endl; - a_hpc->RecoverFEMSolution(X, *b, x); - } - else - { - cout << "a->RecoverFEMSolution" << endl; - a->RecoverFEMSolution(X, *b, x); - } + // 13. Recover the solution as a finite element grid function. + if (perf && matrix_free) + { + cout << "[hpc && free] a_hpc->RecoverFEMSolution" << endl; + a_hpc->RecoverFEMSolution(X, *b, x); + } + else + { + cout << "[std] a->RecoverFEMSolution" << endl; + a->RecoverFEMSolution(X, *b, x); + } - // 14. Save the refined mesh and the solution. This output can be viewed later - // using GLVis: "glvis -m refined.mesh -g sol.gf". - ofstream mesh_ofs("refined.mesh"); - mesh_ofs.precision(8); - mesh->Print(mesh_ofs); - ofstream sol_ofs("sol.gf"); - sol_ofs.precision(8); - x.Save(sol_ofs); + // 14. Save the refined mesh and the solution. This output can be viewed later + // using GLVis: "glvis -m refined.mesh -g sol.gf". + ofstream mesh_ofs("refined.mesh"); + mesh_ofs.precision(8); + mesh->Print(mesh_ofs); + ofstream sol_ofs("sol.gf"); + sol_ofs.precision(8); + x.Save(sol_ofs); - // 15. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock.precision(8); - sol_sock << "solution\n" << *mesh << x << flush; + // 15. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock.precision(8); + sol_sock << "solution\n" << *mesh << x << flush; + } } - + // 16. Free the used memory. delete a; delete a_hpc; diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 4ea84574f4..8f709a4da8 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -26,7 +26,7 @@ MFEM_MACHINE ?= $(shell uname -m) # Compiler specific optimizations. # For best performance, GCC 5 (or newer) is recommended. -ifneq (,$(findstring $(MFEM_CXX),g++ mpicxx)) +ifneq (,$(findstring $(MFEM_CXX),g++ mpicxx /usr/bin/g++)) ifeq ($(MFEM_MACHINE),x86_64) MFEM_CXXFLAGS += -march=native else ifneq (,$(findstring ppc64,$(MFEM_MACHINE))) From af53d47cb72ff829907ff078ecea7ff74f1c8804 Mon Sep 17 00:00:00 2001 From: camierjs Date: Thu, 28 Sep 2017 17:36:24 -0700 Subject: [PATCH 004/535] Cleanup & MFEM_USE_X86INTRIN ifdefs --- fem/bilinearform.cpp | 6 +-- fem/bilinearform.hpp | 7 ++- fem/coefficient.hpp | 2 +- fem/fespace.cpp | 3 +- fem/tbilinearform.hpp | 67 ++++++++++++++---------- fem/teltrans.hpp | 46 +++++++++++++---- fem/tevaluator.hpp | 97 ++++++++++++++++++++++++----------- fem/tfe.hpp | 13 ++--- fem/tfespace.hpp | 83 +++++++++++++++++++++++++++++- fem/tintrules.hpp | 2 +- general/array.cpp | 7 +-- general/table.cpp | 48 +++++++---------- general/x86intrin.hpp | 6 +++ linalg/blockmatrix.cpp | 1 - linalg/densemat.cpp | 12 ++--- linalg/matrix.hpp | 2 +- linalg/operator.hpp | 2 +- linalg/sparsemat.cpp | 25 ++++----- linalg/sparsemat.hpp | 21 ++++---- linalg/tdensemat.hpp | 5 +- linalg/ttensor.hpp | 15 +----- miniapps/performance/ex1.cpp | 12 ++++- miniapps/performance/makefile | 2 +- 23 files changed, 305 insertions(+), 179 deletions(-) diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index bd9631215f..904c9b7136 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -55,7 +55,6 @@ void BilinearForm::AllocMat() int *I = dof_dof.GetI(); int *J = dof_dof.GetJ(); double *data = new double[I[height]]; - //double *data = (double*) aligned_alloc(x86::align,I[height]*sizeof(double)); mat = new SparseMatrix(I, J, data, height, height, true, true, true); *mat = 0.0; @@ -259,12 +258,11 @@ void BilinearForm::AssembleElementMatrix(int i, Array &vdofs){ fes->GetElementVDofs(i, vdofs); if (mat == NULL) { - std::cout<<"[AssembleElementMatrix] AllocMat"<AddSubMatrix(vdofs, M); } - + void BilinearForm::AssembleElementMatrix( int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros) { diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index c758825160..ab423b3800 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -66,6 +66,8 @@ protected: Hybridization *hybridization; int precompute_sparsity; + // Allocate appropriate SparseMatrix and assign it to mat + void AllocMat(); void ConformingAssemble(); @@ -79,10 +81,7 @@ protected: } public: - // Allocate appropriate SparseMatrix and assign it to mat - void AllocMat(); - - /// Creates bilinear form associated with FE space *f. + /// Creates bilinear form associated with FE space *f. BilinearForm(FiniteElementSpace *f); BilinearForm(FiniteElementSpace *f, BilinearForm *bf, int ps = 0); diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 74b8799543..9d6460bc0d 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -28,7 +28,7 @@ class ParMesh; /// Base class Coefficient that may optionally depend on time. - class Coefficient +class Coefficient { protected: double time; diff --git a/fem/fespace.cpp b/fem/fespace.cpp index aadfb0e4e4..07970c22bf 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -132,7 +132,8 @@ void FiniteElementSpace::AdjustVDofs (Array &vdofs) void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const { - GetElementDofs(i, vdofs); + GetElementDofs(i, vdofs); + //DofsToVDofs(vdofs); // Should it be done? } void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const { diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 8b3cca3215..a73b1939b7 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -34,16 +34,7 @@ template class TBilinearForm : public Operator { - public: - static void* operator new(size_t count) { return Allocate(count); } -private: - static void* Allocate(size_t count) { - void* result = nullptr; - const auto alloc_failed = posix_memalign(&result, 32, count); - if (alloc_failed) throw ::std::bad_alloc(); - return result; - } - protected: +protected: typedef complex_t complex_type; typedef real_t real_type; @@ -120,6 +111,9 @@ public: delete [] assembled_data; } + // Allocate aligned memory with x86 intrinsics alignment requirements + static void* operator new(size_t count) { return x86::alloc(count); } + /// Get the input finite element space prolongation matrix virtual const Operator *GetProlongation() const { return ((FiniteElementSpace &)in_fes).GetProlongationMatrix(); } @@ -180,7 +174,11 @@ public: kernel_t::Action(0, F, wQ, res, R); +#ifndef MFEM_USE_X86INTRIN + solFEval.template Assemble(R); +#else solFEval.template Assemble(el,R); +#endif } } @@ -226,7 +224,11 @@ public: kernel_t::MultAssembled(k, assembled_data[el+k], R); } +#ifndef MFEM_USE_X86INTRIN + solFEval.template Assemble(R); +#else solFEval.template Assemble(el,R); +#endif } // complex_t = double @@ -452,26 +454,28 @@ public: solShapeEval solEval(this->solEval); coeff_eval_t wQ(int_rule, coeff); +#ifndef MFEM_USE_X86INTRIN Array vdofs; - Array vdofs128; const Array *dof_map = sol_fe.GetDofMap(); const int *dof_map_ = dof_map->GetData(); DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros - TDenseMatrix tM_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros +#else // MFEM_USE_X86INTRIN + Array vdofs; + const Array *dof_map = sol_fe.GetDofMap(); + const int *dof_map_ = dof_map->GetData(); + TDenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros + MFEM_VERIFY((mesh.GetNE()%x86::width)==0,"x86::width should be modulo NE"); +#endif - TMatrix M_loc; - TMatrix tM_loc; - f_assembled_t asm_qpt_data; - const int NE = mesh.GetNE(); - - MFEM_VERIFY((NE%x86::width)==0,"x86::width should be modulo NE"); - std::cout<<"NE="<::Type F; T.Eval(el, F); @@ -483,8 +487,13 @@ public: // For now, when vdim > 1, assume block-diagonal matrix with the same // diagonal block for all components. - S_spec::ElementMatrix::Compute( - asm_qpt_data.layout, asm_qpt_data, tM_loc.layout, tM_loc, solEval); +#ifndef MFEM_USE_X86INTRIN + TMatrix M_loc; +#else // MFEM_USE_X86INTRIN + TMatrix M_loc; +#endif + S_spec::ElementMatrix::Compute( + asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval); if (dof_map) // switch from tensor-product ordering { @@ -492,19 +501,23 @@ public: { for (int j = 0; j < dofs; j++) { - tM_loc_perm(dof_map_[i],dof_map_[j]) = tM_loc(i,j); + M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j); } } for (int bi = 1; bi < vdim; bi++) { - tM_loc_perm.CopyMN(tM_loc_perm, dofs, dofs, 0, 0, + M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0, bi*dofs, bi*dofs); } - a.AssembleElementMatrix(el, tM_loc_perm, vdofs128); + a.AssembleElementMatrix(el, M_loc_perm, vdofs); } else { +#ifndef MFEM_USE_X86INTRIN DenseMatrix DM(M_loc.data, dofs, dofs); +#else + TDenseMatrix DM(M_loc.data,dofs*vdim,dofs*vdim); // initialized with zeros +#endif if (vdim == 1) { a.AssembleElementMatrix(el, DM, vdofs); diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp index a0cb9be522..e4adcaa0c6 100644 --- a/fem/teltrans.hpp +++ b/fem/teltrans.hpp @@ -75,13 +75,17 @@ public: protected: #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - TTensor3 nodes_dof; + TTensor3 nodes_dof; #endif ShapeEval evaluator; FESpace_type fes; nodeLayout_type node_layout; +#ifndef MFEM_USE_X86INTRIN + const real_t *nodes; +#else const double *nodes; +#endif const Element* const *elements; @@ -150,7 +154,7 @@ public: #endif x_type x; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -160,12 +164,16 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); +#ifndef MFEM_USE_X86INTRIN + T.fes.VectorExtract(T.node_layout, T.nodes, +#else T.fes.VectorExtract(el,T.node_layout, T.nodes, +#endif nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, x.layout.merge_23(), x); @@ -191,7 +199,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -201,12 +209,16 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); +#ifndef MFEM_USE_X86INTRIN + T.fes.VectorExtract(T.node_layout, T.nodes, +#else T.fes.VectorExtract(el,T.node_layout, T.nodes, +#endif nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -234,7 +246,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -244,12 +256,16 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); +#ifndef MFEM_USE_X86INTRIN + T.fes.VectorExtract(T.node_layout, T.nodes, +#else T.fes.VectorExtract(el,T.node_layout, T.nodes, +#endif nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, x.layout.merge_23(), x); @@ -280,7 +296,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -291,12 +307,16 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); +#ifndef MFEM_USE_X86INTRIN + T.fes.VectorExtract(T.node_layout, T.nodes, +#else T.fes.VectorExtract(el,T.node_layout, T.nodes, +#endif nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -324,7 +344,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -335,12 +355,16 @@ public: { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); +#ifndef MFEM_USE_X86INTRIN + T.fes.VectorExtract(T.node_layout, T.nodes, +#else T.fes.VectorExtract(el,T.node_layout, T.nodes, +#endif nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 35dff18bda..ff219e6eaf 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -41,19 +41,15 @@ protected: TMatrix B; TMatrix Bt; TTensor3 G; - TTensor3 Gt; + TTensor3 Gt; public: ShapeEvaluator_base(const FE &fe) { - std::cout<<"[ShapeEvaluator_base]"<(Bt.layout, Bt, B.layout.transpose_12(), B); - std::cout<<"[ShapeEvaluator_base] CalcTransposed"<(Gt.layout.merge_23(), Gt, G.layout.merge_12().transpose_12(), G); - std::cout<<"[ShapeEvaluator_base] CalcMerged"< --> #if 0 @@ -193,7 +184,6 @@ public: const D_layout_t &D_layout, D_data_t &D_data) const { - std::cout<<"[ShapeEvaluator_base::AssembleGradGrad]"< F; for (int k = 0; k < NC; k++) @@ -228,7 +218,7 @@ protected: TMatrix Bt_1d, Gt_1d; public: - TProductShapeEvaluator() { std::cout<<"[TProductShapeEvaluator<1D>]"<] NIP="<::Calc]"< NIP x DOF x NC --> NIP x NIP x NC TTensor3 A; @@ -385,7 +374,6 @@ public: void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::Calc] bis"<(dof_layout, dof_data, qpt_layout, qpt_data); } @@ -396,7 +384,6 @@ public: void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::CalcT]"< NIP x DOF x NC --> DOF x DOF x NC TTensor3 A; @@ -420,7 +407,6 @@ public: void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::Calc] bis"<(qpt_layout, qpt_data, dof_layout, dof_data); } @@ -434,7 +420,6 @@ public: const grad_layout_t &grad_layout, grad_data_t &grad_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::CalcGrad]"<(dof_layout, dof_data, grad_layout.ind2(0), grad_data); Calc(dof_layout, dof_data, @@ -453,7 +438,6 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::CalcGradT]"<(grad_layout.ind2(0), grad_data, dof_layout, dof_data); CalcT(grad_layout.ind2(1), grad_data, @@ -468,7 +452,6 @@ public: void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const M_layout_t &M_layout, M_data_t &M_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::Assemble]"< --> @@ -533,7 +516,6 @@ public: const D_layout_t &D_layout, D_data_t &D_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::Assemble] bis"< A; @@ -564,7 +546,6 @@ public: const D_layout_t &D_layout, D_data_t &D_data) const { - //std::cout<<"[TProductShapeEvaluator<2D>::AssembleGradGrad]"<(qpt_layout.ind23(0,0), qpt_data, D_layout, D_data); Assemble<1,0,true >(qpt_layout.ind23(1,0), qpt_data, D_layout, D_data); @@ -638,7 +619,7 @@ public: static const int TDOF = DOF*DOF*DOF; // total dofs static const int TNIP = NIP*NIP*NIP; // total qpts - TProductShapeEvaluator() { std::cout<<"[TProductShapeEvaluator] 3D"<(Bt_1d.layout, Bt_1d, B_1d.layout.transpose_12(), B_1d); - std::cout<<"[ShapeEvaluator_base] G Transpose:"<(Gt_1d.layout, Gt_1d, G_1d.layout.transpose_12(), G_1d); } @@ -1027,15 +1005,24 @@ protected: using base_class::fespace; using base_class::shapeEval; using base_class::vec_layout; - const double *data_in; - double *data_out; +#ifndef MFEM_USE_X86INTRIN + const complex_t *data_in; + complex_t *data_out; +#else + const double *data_in; // x86 complex_t + double *data_out; // x86 complex_t +#endif public: // With this constructor, fespace is a shallow copy of tfes. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FESpace_t &tfes, const ShapeEval_type &shape_eval, const VecLayout_type &vec_layout, +#ifndef MFEM_USE_X86INTRIN + const complex_t *global_data_in, complex_t *global_data_out) +#else const double *global_data_in, double *global_data_out) +#endif : base_class(tfes, shape_eval, vec_layout), data_in(global_data_in), data_out(global_data_out) @@ -1044,7 +1031,11 @@ public: // With this constructor, fespace is a shallow copy of f.fespace. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FieldEvaluator &f, +#ifndef MFEM_USE_X86INTRIN + const complex_t *global_data_in, complex_t *global_data_out) +#else const double *global_data_in, double *global_data_out) +#endif : base_class(f.fespace, f.shapeEval, f.vec_layout), data_in(global_data_in), data_out(global_data_out) @@ -1053,7 +1044,11 @@ public: // This constructor creates a new fespace, not a shallow copy. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FiniteElementSpace &fes, +#ifndef MFEM_USE_X86INTRIN + const complex_t *global_data_in, complex_t *global_data_out) +#else const double *global_data_in, double *global_data_out) +#endif : base_class(FE_type(*fes.FEColl()), fes), data_in(global_data_in), data_out(global_data_out) @@ -1079,7 +1074,11 @@ public: const int ne = val_layout_t::dim_3; TTensor3 val_dofs; SetElement(el); +#ifndef MFEM_USE_X86INTRIN + fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs); +#else fespace.VectorExtract(el,vec_layout, data_in, val_dofs.layout, val_dofs); +#endif shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, l.merge_23(), vals); } @@ -1091,7 +1090,11 @@ public: const int ne = grad_layout_t::dim_4; TTensor3 val_dofs; SetElement(el); +#ifndef MFEM_USE_X86INTRIN + fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs); +#else fespace.VectorExtract(el,vec_layout, data_in, val_dofs.layout, val_dofs); +#endif shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, l.merge_34(), grad); } @@ -1111,16 +1114,24 @@ public: void Eval(int el, DataType &F) { SetElement(el); - Eval(F);//Eval(el,F); + Eval(F); } template inline MFEM_ALWAYS_INLINE +#ifndef MFEM_USE_X86INTRIN + void Assemble(DataType &F) +#else void AssembleOp(int el, DataType &F) +#endif { // T.SetElement() must be called outside Action:: - template Assemble(el,vec_layout, *this, F); +#ifndef MFEM_USE_X86INTRIN + template Assemble(vec_layout, *this, F); +#else + template Assemble(el,vec_layout, *this, F); +#endif } template @@ -1128,7 +1139,11 @@ public: void Assemble(int el, DataType &F) { SetElement(el); +#ifndef MFEM_USE_X86INTRIN + Assemble(F); +#else AssembleOp(el,F); +#endif } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE @@ -1235,7 +1250,11 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif +#ifndef MFEM_USE_X86INTRIN + T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); +#else T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); +#endif T.shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); } @@ -1288,14 +1307,22 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif +#ifndef MFEM_USE_X86INTRIN + T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); +#else T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); +#endif T.shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, D.grad_qpts.layout.merge_34(), D.grad_qpts); } template static inline MFEM_ALWAYS_INLINE +#ifndef MFEM_USE_X86INTRIN + void Assemble(const vec_layout_t &l, T_type &T, AData_t &D) +#else void Assemble(int el, const vec_layout_t &l, T_type &T, AData_t &D) +#endif { const AssignOp::Type Op = Add ? AssignOp::Add : AssignOp::Set; #ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS @@ -1306,7 +1333,11 @@ public: T.shapeEval.template CalcGradT( D.grad_qpts.layout.merge_34(), D.grad_qpts, val_dofs.layout.merge_23(), val_dofs); +#ifndef MFEM_USE_X86INTRIN + T.fespace.template VectorAssemble( +#else T.fespace.template VectorAssemble(el, +#endif val_dofs.layout, val_dofs, l, T.data_out); } @@ -1341,7 +1372,11 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif +#ifndef MFEM_USE_X86INTRIN + T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); +#else T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); +#endif T.shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); T.shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, diff --git a/fem/tfe.hpp b/fem/tfe.hpp index 75d726c4b6..08e1ccb2bf 100644 --- a/fem/tfe.hpp +++ b/fem/tfe.hpp @@ -36,7 +36,7 @@ void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir, for (int id = 0; id < dof; id++) { int orig_id = dof_map ? (*dof_map)[id] : id; - B[ip+nip*id] = x86::set(shape(orig_id)); + B[ip+nip*id] = shape(orig_id); } } } @@ -60,7 +60,7 @@ void CalcGradTensor(const FiniteElement &fe, const IntegrationRule &ir, int orig_id = dof_map ? (*dof_map)[id] : id; for (int d = 0; d < dim; d++) { - G[ip+nip*(d+dim*id)] = x86::set(dshape(orig_id, d)); + G[ip+nip*(d+dim*id)] = dshape(orig_id, d); } } } @@ -70,7 +70,6 @@ template void CalcShapes(const FiniteElement &fe, const IntegrationRule &ir, real_t *B, real_t *G, const Array *dof_map) { - std::cout<<"[CalcShapes]"< void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { - std::cout<<"[CalcShapes] H1"< @@ -193,7 +191,6 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { - std::cout<<"[CalcShapes] H1 bis"< *GetDofMap() const { return NULL; } @@ -255,13 +252,11 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { - std::cout<<"[H1_FiniteElement::CalcShapes]"< void Calc1DShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { - std::cout<<"[H1_FiniteElement::Calc1DShapes]"< *GetDofMap() const { return my_dof_map; } @@ -315,7 +310,6 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *G) const { - std::cout<<"[CalcShapes] H1 TETRAHEDRON"< *GetDofMap() const { return NULL; } @@ -446,7 +440,6 @@ public: template void CalcShapes(const IntegrationRule &ir, real_t *B, real_t *Grad) const { - std::cout<<"[CalcShapes] L2"< diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index d5fc477e8f..b4595975d5 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -193,6 +193,34 @@ public: } // Multi-element VectorExtract: vdof_layout is (DOFS x NumComp x NumElems). +#ifndef MFEM_USE_X86INTRIN + template + inline MFEM_ALWAYS_INLINE + void VectorExtract(const vec_layout_t &vl, + const glob_vdof_data_t &glob_vdof_data, + const vdof_layout_t &vdof_layout, + vdof_data_t &vdof_data) const + { + const int NC = vdof_layout_t::dim_2; + const int NE = vdof_layout_t::dim_3; + MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, + "invalid number of dofs"); + MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); + for (int k = 0; k < NC; k++) + { + for (int j = 0; j < NE; j++) + { + for (int i = 0; i < FE::dofs; i++) + { + Assign(vdof_data[vdof_layout.ind(i,k,j)], + glob_vdof_data[vl.ind(ind.map(i,j), k)]); + } + } + } + } +#else template @@ -225,7 +253,59 @@ public: } } } +#endif +#ifndef MFEM_USE_X86INTRIN + template + inline MFEM_ALWAYS_INLINE + void VectorExtract(const vec_layout_t &vl, + const glob_vdof_data_t &glob_vdof_data, + const vdof_layout_t &vdof_layout, + vdof_data_t &vdof_data) const + { + VectorExtract(vl, glob_vdof_data, vdof_layout, vdof_data); + } + + // Multi-element VectorAssemble: vdof_layout is (DOFS x NumComp x NumElems). + template + inline MFEM_ALWAYS_INLINE + void VectorAssemble(const vdof_layout_t &vdof_layout, + const vdof_data_t &vdof_data, + const vec_layout_t &vl, + glob_vdof_data_t &glob_vdof_data) const + { + const int NC = vdof_layout_t::dim_2; + const int NE = vdof_layout_t::dim_3; + MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, + "invalid number of dofs"); + MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); + for (int k = 0; k < NC; k++) + { + for (int j = 0; j < NE; j++) + { + for (int i = 0; i < FE::dofs; i++) + { + Assign(glob_vdof_data[vl.ind(ind.map(i,j), k)], + vdof_data[vdof_layout.ind(i,k,j)]); + } + } + } + } + + template + inline MFEM_ALWAYS_INLINE + void VectorAssemble(const vdof_layout_t &vdof_layout, + const vdof_data_t &vdof_data, + const vec_layout_t &vl, + glob_vdof_data_t &glob_vdof_data) const + { + VectorAssemble(vdof_layout, vdof_data, vl, glob_vdof_data); + } +#else template inline MFEM_ALWAYS_INLINE @@ -270,7 +350,7 @@ public: } } } - + template inline MFEM_ALWAYS_INLINE @@ -282,6 +362,7 @@ public: { VectorAssemble(el,vdof_layout, vdof_data, vl, glob_vdof_data); } +#endif // Extract a static number of consecutive components; vdof_layout is // (dofs x NC x NE), where NC is the number of components to extract. It is diff --git a/fem/tintrules.hpp b/fem/tintrules.hpp index c4e6f45a51..0f9464f983 100644 --- a/fem/tintrules.hpp +++ b/fem/tintrules.hpp @@ -220,7 +220,7 @@ public: MFEM_ASSERT(ir_1d.GetNPoints() == qpts_1d, "quadrature rule mismatch"); for (int j = 0; j < qpts_1d; j++) { - weights_1d.data[j] = x86::set(ir_1d.IntPoint(j).weight); + weights_1d.data[j] = ir_1d.IntPoint(j).weight; } } diff --git a/general/array.cpp b/general/array.cpp index 976b7c067b..b7384bfd98 100644 --- a/general/array.cpp +++ b/general/array.cpp @@ -13,7 +13,6 @@ // Abstract array data type #include "array.hpp" -#include "x86intrin.hpp" namespace mfem { @@ -22,8 +21,7 @@ BaseArray::BaseArray(int asize, int ainc, int elementsize) { if (asize > 0) { - //data = new char[asize * elementsize]; - data = (void*)aligned_alloc(x86::align,sizeof(char)*asize*elementsize); + data = new char[asize * elementsize]; size = allocsize = asize; } else @@ -48,8 +46,7 @@ void BaseArray::GrowSize(int minsize, int elementsize) int nsize = (inc > 0) ? abs(allocsize) + inc : 2 * abs(allocsize); if (nsize < minsize) { nsize = minsize; } - //p = new char[nsize * elementsize]; - p = (void*)aligned_alloc(x86::align,sizeof(char)*nsize*elementsize); + p = new char[nsize * elementsize]; if (size > 0) { memcpy(p, data, size * elementsize); diff --git a/general/table.cpp b/general/table.cpp index efa6149431..a15a237459 100644 --- a/general/table.cpp +++ b/general/table.cpp @@ -17,8 +17,6 @@ #include "array.hpp" #include "table.hpp" #include "error.hpp" -#include "error.hpp" -#include "x86intrin.hpp" namespace mfem { @@ -31,10 +29,8 @@ Table::Table(const Table &table) if (size >= 0) { const int nnz = table.I[size]; - //I = new int[size+1]; - I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1)); - //J = new int[nnz]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(nnz)); + I = new int[size+1]; + J = new int[nnz]; memcpy(I, table.I, sizeof(int)*(size+1)); memcpy(J, table.J, sizeof(int)*nnz); } @@ -49,10 +45,8 @@ Table::Table (int dim, int connections_per_row) int i, j, sum = dim * connections_per_row; size = dim; - //I = new int[size+1]; - I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1)); - //J = new int[sum]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(sum)); + I = new int[size+1]; + J = new int[sum]; I[0] = 0; for (i = 1; i <= size; i++) @@ -66,10 +60,8 @@ Table::Table (int nrows, int *partitioning) { size = nrows; - //I = new int[size+1]; - I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1)); - //J = new int[size]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(size)); + I = new int[size+1]; + J = new int[size]; for (int i = 0; i < size; i++) { @@ -98,8 +90,7 @@ void Table::MakeJ() j = I[i], I[i] = k, k += j; } - //J = new int[I[size]=k]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(I[size]=k)); + J = new int[I[size]=k]; } void Table::AddConnections (int r, const int *c, int nc) @@ -146,16 +137,14 @@ void Table::SetDims(int rows, int nnz) if (size != rows) { size = rows; - //if (I) { delete [] I; } - //I = (rows >= 0) ? (new int[rows+1]) : (NULL); - I = (rows >= 0) ? (int*)aligned_alloc(x86::align,sizeof(int)*(rows+1)) : (NULL); + if (I) { delete [] I; } + I = (rows >= 0) ? (new int[rows+1]) : (NULL); } if (j != nnz) { - //if (J) { delete [] J; } - //J = (nnz > 0) ? (new int[nnz]) : (NULL); - J = (nnz >= 0) ? (int*)aligned_alloc(x86::align,sizeof(int)*(nnz)) : (NULL); + if (J) { delete [] J; } + J = (nnz > 0) ? (new int[nnz]) : (NULL); } if (size >= 0) @@ -249,8 +238,7 @@ void Table::Finalize() if (sum != I[size]) { - //int *NewJ = new int[sum]; - int *NewJ = (int*)aligned_alloc(x86::align,sizeof(int)*(sum)); + int *NewJ = new int[sum]; for (i=0; i &list) size = nrows; int nnz = list.Size(); - I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1));//new int[size+1]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(nnz));//new int[nnz]; + I = new int[size+1]; + J = new int[nnz]; for (int i = 0, k = 0; i <= size; i++) { @@ -359,13 +347,13 @@ void Table::Load(istream &in) delete [] J; in >> size; - I = (int*)aligned_alloc(x86::align,sizeof(int)*(size+1));//new int[size+1]; + I = new int[size+1]; for (int i = 0; i <= size; i++) { in >> I[i]; } int nnz = I[size]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(nnz));//new int[nnz]; + J = new int[nnz]; for (int j = 0; j < nnz; j++) { in >> J[j]; @@ -413,8 +401,8 @@ long Table::MemoryUsage() const Table::~Table () { - //if (I) { delete [] I; } - //if (J) { delete [] J; } + if (I) { delete [] I; } + if (J) { delete [] J; } } void Transpose (const Table &A, Table &At, int _ncols_A) diff --git a/general/x86intrin.hpp b/general/x86intrin.hpp index 72d77f24b5..25a16c6aec 100644 --- a/general/x86intrin.hpp +++ b/general/x86intrin.hpp @@ -11,6 +11,7 @@ #ifndef MFEM_X86INTRIN_HPP #define MFEM_X86INTRIN_HPP +#include #include "x86intrin.h" // x86 intrinsic class forward description @@ -53,6 +54,7 @@ public: typedef real vreal_t; typedef integer vint_t; static inline vreal_t set(double a){return _mm512_set1_pd(a);} + static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} }; #endif // __AVX512__ @@ -69,6 +71,7 @@ public: typedef real vreal_t; typedef integer vint_t; static inline vreal_t set(double a){return _mm256_set1_pd(a);} + static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} }; #endif // __AVX2__ @@ -85,6 +88,7 @@ public: typedef real vreal_t; typedef integer vint_t; static inline vreal_t set(double a){return _mm256_set1_pd(a);} + static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} }; #endif // __AVX__ @@ -101,6 +105,7 @@ public: typedef real vreal_t; typedef integer vint_t; static inline vreal_t set(double a){return _mm_set1_pd(a);} + static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} }; #endif // __SSE__ @@ -117,6 +122,7 @@ public: typedef real vreal_t; typedef integer vint_t; static inline vreal_t set(double a){return a;} + static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} }; #endif // __STD__ diff --git a/linalg/blockmatrix.cpp b/linalg/blockmatrix.cpp index cdd03e940f..f5ac83b550 100644 --- a/linalg/blockmatrix.cpp +++ b/linalg/blockmatrix.cpp @@ -10,7 +10,6 @@ // Software Foundation) version 2.1 dated February 1999. #include "../general/array.hpp" -#include "../general/x86intrin.hpp" #include "matrix.hpp" #include "sparsemat.hpp" #include "blockvector.hpp" diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index f44931bc18..6d93dbb41d 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -13,7 +13,6 @@ // Implementation of data types dense matrix, inverse dense matrix -#include "../general/x86intrin.hpp" #include "vector.hpp" #include "matrix.hpp" #include "densemat.hpp" @@ -45,7 +44,7 @@ DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.height, m.width) int hw = height * width; if (hw > 0) { - data = (double*) aligned_alloc(x86::align,sizeof(double)*(hw));//new double[hw]; + data = new double[hw]; capacity = hw; for (int i = 0; i < hw; i++) { @@ -65,7 +64,7 @@ DenseMatrix::DenseMatrix(int s) : Matrix(s) capacity = s*s; if (capacity > 0) { - data = (double*) aligned_alloc(x86::align,sizeof(double)*(capacity));//new double[capacity](); // init with zeroes + data = new double[capacity](); // init with zeroes } else { @@ -80,7 +79,7 @@ DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n) capacity = m*n; if (capacity > 0) { - data = (double*) aligned_alloc(x86::align,sizeof(double)*(capacity));//new double[capacity](); // init with zeroes + data = new double[capacity](); // init with zeroes } else { @@ -94,7 +93,7 @@ DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch) capacity = height*width; if (capacity > 0) { - data = (double*) aligned_alloc(x86::align,sizeof(double)*(capacity));//new double[capacity]; + data = new double[capacity]; for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) @@ -126,8 +125,7 @@ void DenseMatrix::SetSize(int h, int w) delete [] data; } capacity = hw; - //data = new double[hw](); // init with zeroes - data = (double*) aligned_alloc(x86::align,sizeof(double)*(hw)); // init with zeroes + data = new double[hw](); // init with zeroes } } diff --git a/linalg/matrix.hpp b/linalg/matrix.hpp index f79c5776be..9be099ba8c 100644 --- a/linalg/matrix.hpp +++ b/linalg/matrix.hpp @@ -24,7 +24,7 @@ namespace mfem class MatrixInverse; /// Abstract data type matrix - class Matrix : public Operator +class Matrix : public Operator { friend class MatrixInverse; public: diff --git a/linalg/operator.hpp b/linalg/operator.hpp index bec9051c72..86be45997a 100644 --- a/linalg/operator.hpp +++ b/linalg/operator.hpp @@ -18,7 +18,7 @@ namespace mfem { /// Abstract operator - class Operator +class Operator { protected: int height; ///< Dimension of the output / number of rows in the matrix. diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index bdde013bff..bc807eeea4 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -108,12 +108,9 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize) #ifdef MFEM_USE_MEMALLOC NodesMem = NULL; #endif - I = (int*)aligned_alloc(x86::align,sizeof(int)*(nrows+1)); - //I = new int[nrows + 1]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*(nrows*rowsize)); - //J = new int[nrows * rowsize]; - A = (double*)aligned_alloc(x86::align,sizeof(double)*nrows*rowsize); - //A = new double[nrows * rowsize]; + I = new int[nrows + 1]; + J = new int[nrows * rowsize]; + A = new double[nrows * rowsize]; for (int i = 0; i <= nrows; i++) { @@ -757,8 +754,7 @@ void SparseMatrix::Finalize(int skip_zeros, bool fix_empty_rows) delete [] ColPtrNode; ColPtrNode = NULL; - //I = new int[height+1]; - I = (int*)aligned_alloc(x86::align,sizeof(int)*(height+1)); + I = new int[height+1]; I[0] = 0; for (i = 1; i <= height; i++) { @@ -773,10 +769,8 @@ void SparseMatrix::Finalize(int skip_zeros, bool fix_empty_rows) } nz = I[height]; - //J = new int[nz]; - J = (int*)aligned_alloc(x86::align,sizeof(int)*nz); - //A = new double[nz]; - A = (double*)aligned_alloc(x86::align,sizeof(double)*nz); + J = new int[nz]; + A = new double[nz]; // Assume we're sorted until we find out otherwise isSorted = true; for (j = i = 0; i < height; i++) @@ -2537,16 +2531,15 @@ void SparseMatrix::Destroy() { if (I != NULL && ownGraph) { - //delete [] I; + delete [] I; } if (J != NULL && ownGraph) { - //delete [] J; + delete [] J; } if (A != NULL && ownData) { -#warning delete A - //delete [] A; + delete [] A; } if (Rows != NULL) diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index 8047c4b235..fd50a41524 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -14,12 +14,12 @@ // Data types for sparse matrix +#include "../general/x86intrin.hpp" #include "../general/mem_alloc.hpp" #include "../general/table.hpp" #include "densemat.hpp" +#include "tdensemat.hpp" #include -#include "../general/x86intrin.hpp" -#include "../linalg/tdensemat.hpp" namespace mfem { @@ -49,14 +49,14 @@ protected: this array is always zero, I[0] = 0, and the last entry, I[height], gives the total number of entries stored (at a minimum, all nonzeros must be represented) in the sparse matrix. */ - int *I; - /** @brief %Array with size #I[#height], containing the column indices for - all matrix entries, as indexed by the #I array. */ - int *J; - /** @brief %Array with size #I[#height], containing the actual entries of the - sparse matrix, as indexed by the #I array. */ - double *A; - ///@} + int *I; + /** @brief %Array with size #I[#height], containing the column indices for + all matrix entries, as indexed by the #I array. */ + int *J; + /** @brief %Array with size #I[#height], containing the actual entries of the + sparse matrix, as indexed by the #I array. */ + double *A; + ///@} /** @brief %Array of linked lists, one for every row. This array represents the linked list (LIL) storage format. */ @@ -501,7 +501,6 @@ inline void SparseMatrix::SearchRow(const x86::vint_t col, const x86::vreal_t a) inline void SparseMatrix::SetColPtr(const int row) const { - //std::cout<<"[SetColPtr] row:"< class TDenseMatrix : public Matrix{ private: - data_t *data; + data_t *data; int capacity; // zero or negative capacity means we do not own the data. public: @@ -41,6 +41,9 @@ public: //data = new data_t[capacity](); data = (data_t*)aligned_alloc(x86::align,capacity*sizeof(data_t)); } + + TDenseMatrix(data_t *d, int h, int w) : Matrix(h, w) + { data = d; capacity = -h*w; } /// Returns reference to a_{ij}. inline data_t &operator()(int i, int j){ diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index 17ad2a06ee..b0884a142d 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -247,12 +247,7 @@ public: static const int aligned_size = align ? MFEM_ALIGN_SIZE(S,data_t) : size; typedef data_t data_type; - //__attribute__ ((aligned(32))) data_t data[aligned_size>0?aligned_size:1]; - data_t *data = (data_t*)aligned_alloc(x86::align, sizeof(data_t)*(aligned_size>0?aligned_size:1)); - /*TVector(){ - std::cout<<"[TVector] size="<0?aligned_size:1]; typedef StridedLayout1D layout_type; static const layout_type layout; @@ -315,11 +310,6 @@ struct TMatrix : public TVector typedef ColumnMajorLayout2D layout_type; static const layout_type layout; - - /*TMatrix(){ - std::cout<<"[TMatrix]"< H; - TTensor3 H; + TTensor3 H; // H(l)_{i,k,s} = A_{i,s} C_{k,s,l} for (int s = 0; s < B1; s++) { diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index 045c40f0a1..96619a9a9d 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -53,15 +53,25 @@ typedef H1_FiniteElement sol_fe_t; typedef H1_FiniteElementSpace sol_fes_t; // Static quadrature, coefficient and integrator types +#ifdef MFEM_USE_X86INTRIN typedef TIntegrationRule int_rule_t; typedef TConstantCoefficient coeff_t; +#else +typedef TIntegrationRule int_rule_t; +typedef TConstantCoefficient<> coeff_t; +#endif + typedef TIntegrator integ_t; // Static bilinear form type, combining the above types +#ifdef MFEM_USE_X86INTRIN typedef TBilinearForm HPCBilinearForm; +#else +typedef TBilinearForm HPCBilinearForm; +#endif int main(int argc, char *argv[]) { @@ -291,7 +301,7 @@ int main(int argc, char *argv[]) else { cout << "[perf] High-performance assembly/evaluation using the templated operator type" << flush<< endl; - a_hpc = new HPCBilinearForm(integ_t(coeff_t(x86::set(1.0))), *fespace); + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); if (matrix_free) { cout<<"[perf & free] partial assembly"< Date: Fri, 15 Jun 2018 15:16:57 -0700 Subject: [PATCH 005/535] [x86] merge addon to get tensor alignment, not yet matrix-free --- INSTALL | 5 +- fem/bilinearform.cpp | 4 +- fem/bilinearform.hpp | 2 + fem/fespace.cpp | 8 +- fem/fespace.hpp | 6 +- fem/tbilinearform.hpp | 45 ++++++- fem/tbilininteg.hpp | 4 +- fem/tcoefficient.hpp | 2 +- fem/teltrans.hpp | 16 +-- fem/tevaluator.hpp | 12 +- fem/tfespace.hpp | 17 ++- fem/tintrules.hpp | 2 +- general/x86_m256.hpp | 2 +- general/x86intrin.hpp | 12 +- linalg/sparsemat.cpp | 4 +- linalg/sparsemat.hpp | 25 ++-- linalg/tdensemat.hpp | 7 +- linalg/ttensor.hpp | 2 + miniapps/performance/ex1.cpp | 223 ++++++++++++++++------------------- 19 files changed, 227 insertions(+), 171 deletions(-) diff --git a/INSTALL b/INSTALL index d185698774..26ce3644cd 100644 --- a/INSTALL +++ b/INSTALL @@ -336,11 +336,9 @@ MFEM_USE_SIDRE = YES/NO specification. When enabled, this option requires installation of HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project. -<<<<<<< HEAD MFEM_USE_X86INTRIN = YES/NO X86 intrinsics will be used. - -======= + MFEM_USE_CONDUIT = YES/NO Enables support for converting MFEM Mesh and Grid Function objects to and from Conduit Mesh Blueprint Descriptions (https://github.com/LLNL/conduit/) @@ -348,7 +346,6 @@ MFEM_USE_CONDUIT = YES/NO an installation of Conduit. If Conduit was built with HDF5 support, it also requires an installation of HDF5 (see also MFEM_USE_NETCDF). ->>>>>>> master MFEM_USE_GZSTREAM = YES/NO Enables use of on-the-fly gzip compressed streams. With this feature enabled (YES), MFEM can compress its output files on-the-fly. In addition, it can diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index a925289237..740e359299 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -263,6 +263,7 @@ void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) } } +#ifdef MFEM_USE_X86INTRIN void BilinearForm::AssembleElementMatrix(int i, const TDenseMatrix &M, Array &vdofs){ @@ -272,7 +273,8 @@ void BilinearForm::AssembleElementMatrix(int i, } mat->AddSubMatrix(vdofs, M); } - +#endif + void BilinearForm::AssembleElementMatrix( int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros) { diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index 9bf48bdfb1..a3027d1e5c 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -300,8 +300,10 @@ public: { delete element_matrices; element_matrices = NULL; } void ComputeElementMatrix(int i, DenseMatrix &elmat); +#ifdef MFEM_USE_X86INTRIN void AssembleElementMatrix(int, const TDenseMatrix&, Array&); +#endif void AssembleElementMatrix(int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros = 1); void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 7c0737258c..5148c212da 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -167,12 +167,14 @@ void FiniteElementSpace::AdjustVDofs (Array &vdofs) } } } - + +#ifdef MFEM_USE_X86INTRIN void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const { GetElementDofs(i, vdofs); //DofsToVDofs(vdofs); // Should it be done? } +#endif void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const { GetElementDofs(i, vdofs); @@ -1234,7 +1236,8 @@ void FiniteElementSpace::Construct() // Do not build elem_dof Table here: in parallel it has to be constructed // later. } - + +#ifdef MFEM_USE_X86INTRIN void FiniteElementSpace::GetElementDofs(int i, Array &dofs) const{ Array dof[x86::width]; for(int k=0; k &dofs) const{ dofs[j]=gather; } } +#endif void FiniteElementSpace::GetElementDofs (int i, Array &dofs) const { diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 2ea9bd9500..b3e720c4d8 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -316,7 +316,9 @@ public: /// Returns indexes of degrees of freedom in array dofs for i'th element. virtual void GetElementDofs(int i, Array &dofs) const; +#ifdef MFEM_USE_X86INTRIN virtual void GetElementDofs(int i, Array &dofs) const; +#endif /// Returns indexes of degrees of freedom for i'th boundary element. virtual void GetBdrElementDofs(int i, Array &dofs) const; @@ -353,8 +355,10 @@ public: /// Returns indexes of degrees of freedom in array dofs for i'th element. void GetElementVDofs(int i, Array &vdofs) const; +#ifdef MFEM_USE_X86INTRIN void GetElementVDofs(int i, Array &vdofs) const; - +#endif + /// Returns indexes of degrees of freedom for i'th boundary element. void GetBdrElementVDofs(int i, Array &vdofs) const; diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index a73b1939b7..fd1921e3a5 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -20,10 +20,33 @@ #include "tcoefficient.hpp" #include "fespace.hpp" #include "../linalg/tdensemat.hpp" - +#include namespace mfem { + +using size_t = ::std::size_t; +template +struct alignas(ALIGNMENT) AlignedNew { + static_assert(ALIGNMENT > 0, "ALIGNMENT must be positive"); + static_assert((ALIGNMENT & (ALIGNMENT - 1)) == 0, + "ALIGNMENT must be a power of 2"); + static_assert((ALIGNMENT % sizeof(void*)) == 0, + "ALIGNMENT must be a multiple of sizeof(void *)"); + static void* operator new(size_t count) { return Allocate(count); } + static void* operator new[](size_t count) { return Allocate(count); } + static void operator delete(void* ptr) { free(ptr); } + static void operator delete[](void* ptr) { free(ptr); } + + private: + static void* Allocate(size_t count) { + void* result = nullptr; + const auto alloc_failed = posix_memalign(&result, ALIGNMENT, count); + if (alloc_failed) throw ::std::bad_alloc(); + return result; + } +}; + // Templated bilinear form class, cf. bilinearform.?pp // complex_t - sol dof data type @@ -32,7 +55,7 @@ template -class TBilinearForm : public Operator +class TBilinearForm : public Operator, public AlignedNew<32> { protected: typedef complex_t complex_type; @@ -108,11 +131,17 @@ public: virtual ~TBilinearForm() { +#ifndef MFEM_USE_X86INTRIN delete [] assembled_data; +#else + free(assembled_data); +#endif } +#ifdef MFEM_USE_X86INTRIN // Allocate aligned memory with x86 intrinsics alignment requirements - static void* operator new(size_t count) { return x86::alloc(count); } + //static void* operator new(size_t count) { return x86::alloc(count); } +#endif /// Get the input finite element space prolongation matrix virtual const Operator *GetProlongation() const @@ -195,7 +224,17 @@ public: const int NE = mesh.GetNE(); if (!assembled_data) { +#ifndef MFEM_USE_X86INTRIN assembled_data = new p_assembled_t[NE]; +#else + //assembled_data = new p_assembled_t[NE]; + void* result = nullptr; + //const int aligned_size = MFEM_ALIGN_SIZE(NE,p_assembled_t); + const int size = NE*sizeof(p_assembled_t); + const auto alloc_failed = posix_memalign(&result, 32, size); + if (alloc_failed) throw ::std::bad_alloc(); + assembled_data = (p_assembled_t*) result; +#endif } for (int el = 0; el < NE; el++) // BE == 1 { diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index afed8318fa..921c8c8b46 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -173,7 +173,7 @@ struct TDiffusionKernel<1,1,complex_t> // quadrature points. This type is used in partial assembly, and partially // assembled action. template - struct p_asm_data { typedef TMatrix type; }; + struct p_asm_data { typedef TMatrix type; }; // Partially assembled data type for one element with the given number of // quadrature points. This type is used in full element matrix assembly. @@ -501,7 +501,7 @@ struct TDiffusionKernel<3,3,complex_t> const bool Symm = (asm_type::layout_type::rank == 2); for (int i = 0; i < M; i++) { - TMatrix<3,3,real_t> B; // = adj(J) + TMatrix<3,3,real_t,true> B; // = adj(J) const complex_t u = (Q.get(q,i,k) / TAdjDet(F.Jt.layout.ind14(i,k).transpose_12(), F.Jt, diff --git a/fem/tcoefficient.hpp b/fem/tcoefficient.hpp index 3b146256cd..7b0479b4e0 100644 --- a/fem/tcoefficient.hpp +++ b/fem/tcoefficient.hpp @@ -256,7 +256,7 @@ struct IntRuleCoefficient template struct Aux { typedef struct { } result_t; - TMatrix cw; + TMatrix cw; inline MFEM_ALWAYS_INLINE Aux(const IR &int_rule, const coeff_t &c) { diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp index e4adcaa0c6..810b50482b 100644 --- a/fem/teltrans.hpp +++ b/fem/teltrans.hpp @@ -153,8 +153,8 @@ public: typedef TTensor3 x_type; #endif x_type x; - - typedef TTensor3 nodes_dof_t; + + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -172,7 +172,7 @@ public: #ifndef MFEM_USE_X86INTRIN T.fes.VectorExtract(T.node_layout, T.nodes, #else - T.fes.VectorExtract(el,T.node_layout, T.nodes, + T.fes.VectorExtract(el, T.node_layout, T.nodes, #endif nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, @@ -195,11 +195,11 @@ public: #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES typedef TTensor4 Jt_type; #else - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -246,7 +246,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -296,7 +296,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -344,7 +344,7 @@ public: #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index ff219e6eaf..759f0cf68d 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -629,8 +629,8 @@ public: const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { const int NC = dof_layout_t::dim_2; - TVector QDD; - TVector QQD; + TVector QDD; + TVector QQD; // QDD_{i,jj,k} = \sum_s B_1d_{i,s} dof_data_{s,jj,k} Mult_2_1(B_1d.layout, Dx ? G_1d : B_1d, @@ -665,8 +665,8 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { const int NC = dof_layout_t::dim_2; - TVector QDD; - TVector QQD; + TVector QDD; + TVector QQD; // QQD_{ii,j,k} = \sum_s B_1d_{s,j} qpt_data_{ii,s,k} Mult_1_2(B_1d.layout, Dz ? G_1d : B_1d, @@ -1201,9 +1201,9 @@ public: typedef TTensor3 val_dofs_t; val_dofs_t val_dofs; #else - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; #endif - TTensor4 grad_qpts; + TTensor4 grad_qpts; }; template struct AData<3,NE> // 3 = Values+Gradients diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index b4595975d5..1a6b76d98c 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -63,7 +63,15 @@ public: else { // reorder the local dofs according to loc_dof_map +#ifndef MFEM_USE_X86INTRIN int *el_dof_list_ = new int[num_dofs]; +#else + //const int aligned_size = MFEM_ALIGN_SIZE(num_dofs,int); + void* result = nullptr; + const auto alloc_failed = posix_memalign(&result, 32, 2*num_dofs*sizeof(int)); + if (alloc_failed) throw ::std::bad_alloc(); + int *el_dof_list_ = (int*) result; +#endif const int *loc_dof_map_ = loc_dof_map->GetData(); for (int i = 0; i < el_dof.Size(); i++) { @@ -90,7 +98,13 @@ public: { } inline MFEM_ALWAYS_INLINE - ~ElementDofIndexer() { if (own_list) { delete [] el_dof_list; } } + ~ElementDofIndexer() { +#ifndef MFEM_USE_X86INTRIN + if (own_list) { delete [] el_dof_list; } +#else + if (own_list) { free((void*)el_dof_list); } +#endif + } inline MFEM_ALWAYS_INLINE void SetElement(int elem_idx) @@ -246,6 +260,7 @@ public: for(int n=0; n(vdof_data[vdof_layout.ind(i,k,j)],gather); diff --git a/fem/tintrules.hpp b/fem/tintrules.hpp index 0f9464f983..d460a1eeb7 100644 --- a/fem/tintrules.hpp +++ b/fem/tintrules.hpp @@ -142,7 +142,7 @@ template class TProductIntegrationRule_base<3,Q,real_t> { protected: - TVector weights_1d; + TVector weights_1d; public: // Multi-component weight assignment. qpt_layout_t must be (qpts x n1 x ...) diff --git a/general/x86_m256.hpp b/general/x86_m256.hpp index 6b8d193068..ae05260172 100644 --- a/general/x86_m256.hpp +++ b/general/x86_m256.hpp @@ -48,7 +48,7 @@ public: // * error 0x81e350 // * ok with: 0x81e020 // **************************************************************************** -struct real { +struct __attribute__ ((aligned(32))) real { protected: __m256d vec; public: diff --git a/general/x86intrin.hpp b/general/x86intrin.hpp index 25a16c6aec..05d7b3bf68 100644 --- a/general/x86intrin.hpp +++ b/general/x86intrin.hpp @@ -66,12 +66,12 @@ public: #pragma message "X86intrin::AVX2" template <> struct x86intrin<3>{ public: - static const int align = 32; - static const int width = 4; - typedef real vreal_t; - typedef integer vint_t; - static inline vreal_t set(double a){return _mm256_set1_pd(a);} - static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} + static const int align = 32; + static const int width = 4; + typedef real vreal_t; + typedef integer vint_t; + static inline vreal_t set(double a){return _mm256_set1_pd(a);} + static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} }; #endif // __AVX2__ diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index 531bf9f80f..bf3b7309e7 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -1974,7 +1974,8 @@ void SparseMatrix::Jacobi3(const Vector &b, const Vector &x0, Vector &x1, } } } - + +#ifdef MFEM_USE_X86INTRIN void SparseMatrix::AddSubMatrix(const Array &idx, const TDenseMatrix &subm){ for (int i = 0; i < idx.Size(); i++){ @@ -1984,6 +1985,7 @@ void SparseMatrix::AddSubMatrix(const Array &idx, } } } +#endif void SparseMatrix::AddSubMatrix(const Array &rows, const Array &cols, const DenseMatrix &subm, int skip_zeros) diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index e56616d13d..686bce96b7 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -14,13 +14,14 @@ // Data types for sparse matrix -#include "../general/x86intrin.hpp" #include "../general/mem_alloc.hpp" #include "../general/table.hpp" #include "../general/globals.hpp" #include "densemat.hpp" -//#include "tdensemat.hpp" -//#include + +#ifdef MFEM_USE_X86INTRIN +#include "tdensemat.hpp" +#endif namespace mfem { @@ -329,11 +330,13 @@ public: inline void _Set_(const int col, const double a) { SearchRow(col) = a; } inline double _Get_(const int col) const; - + +#ifdef MFEM_USE_X86INTRIN inline void SetColPtr(const x86::vint_t row) const; inline void SearchRow(const x86::vint_t col, const x86::vreal_t a); inline void _Add_(const x86::vint_t col, const x86::vreal_t a){ SearchRow(col,a);} - +#endif + inline double &SearchRow(const int row, const int col); inline void _Add_(const int row, const int col, const double a) { SearchRow(row, col) += a; } @@ -351,8 +354,10 @@ public: void AddSubMatrix(const Array &rows, const Array &cols, const DenseMatrix &subm, int skip_zeros = 1); +#ifdef MFEM_USE_X86INTRIN void AddSubMatrix(const Array &idx, const TDenseMatrix &subm); +#endif bool RowIsEmpty(const int row) const; @@ -496,6 +501,7 @@ SparseMatrix * Add(double a, const SparseMatrix & A, double b, SparseMatrix * Add(Array & Ai); +#ifdef MFEM_USE_X86INTRIN // Inline methods // **************************************************************************** // * SetColPtr - gather @@ -520,13 +526,14 @@ inline void SparseMatrix::SetColPtr(const x86::vint_t row) const{ // * SearchRow - scatter // **************************************************************************** inline void SparseMatrix::SearchRow(const x86::vint_t col, const x86::vreal_t a){ - for(int k=0;k #include @@ -38,8 +40,11 @@ public: "invalid TDenseMatrix size: " << m << " x " << n); capacity = m*n; MFEM_ASSERT(capacity>0,"invalid TDenseMatrix capacity"); - //data = new data_t[capacity](); +#ifndef MFEM_USE_X86INTRIN + data = new data_t[capacity](); +#else data = (data_t*)aligned_alloc(x86::align,capacity*sizeof(data_t)); +#endif } TDenseMatrix(data_t *d, int h, int w) : Matrix(h, w) diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index b0884a142d..6b1865593e 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -16,6 +16,7 @@ #include "../general/tassign.hpp" #include "tlayout.hpp" #include "tmatrix.hpp" +#include // Templated tensor implementation (up to order 4) @@ -243,6 +244,7 @@ template struct TVector { public: + //TVector(){assert(align);} static const int size = S; static const int aligned_size = align ? MFEM_ALIGN_SIZE(S,data_t) : size; typedef data_t data_type; diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index ce00d3be78..e2baf5d224 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -60,7 +60,6 @@ typedef TConstantCoefficient coeff_t; typedef TIntegrationRule int_rule_t; typedef TConstantCoefficient<> coeff_t; #endif - typedef TIntegrator integ_t; // Static bilinear form type, combining the above types @@ -82,12 +81,10 @@ int main(int argc, char *argv[]) const char *basis_type = "G"; // Gauss-Lobatto bool static_cond = false; const char *pc = "none"; - bool perf = false; - bool solve_also = true; - bool matrix_free = false; + bool perf = true; + bool matrix_free = true; bool visualization = 1; - int ref_levels = -1; - + OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); @@ -112,14 +109,9 @@ int main(int argc, char *argv[]) args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); - args.AddOption(&solve_also, "-slv", "--solve_also", "-no-slv", - "--no-solve_also", - "Enable or disable solve_also."); - args.AddOption(&ref_levels, "-lvl", "--ref-levels", - "Enable or disable linear quit."); - args.Parse(); - if (!args.Good()) - { + args.Parse(); + if (!args.Good()) + { args.PrintUsage(cout); return 1; } @@ -185,15 +177,14 @@ int main(int argc, char *argv[]) for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); - } + } } if (mesh->MeshGenerator() & 1) // simplex mesh { MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" " the LOR preconditioner yet"); } - std::cout<<"NE="<GetNE()<<""<GetTrueVSize() <<""<< endl; + cout << "Number of finite element unknowns: " + << fespace->GetTrueVSize() << endl; // Create the LOR mesh and finite element space. In the settings of this // example, we can transfer between HO and LOR with the identity operator. @@ -285,7 +276,7 @@ int main(int argc, char *argv[]) "cannot use LOR preconditioner with static condensation"); } - cout << "Assembling the bilinear form ..." << endl<AddDomainIntegrator(new DiffusionIntegrator(one)); a->Assemble(); } else { - cout << "[perf] High-performance assembly/evaluation using the templated operator type" << flush<< endl; - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - if (matrix_free) - { - cout<<"[perf & free] partial assembly"<Assemble(); // partial assembly - } + // High-performance assembly/evaluation using the templated operator type + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (matrix_free) + { + a_hpc->Assemble(); // partial assembly + } else { - cout<<"[perf & asm] full matrix assembly"<AssembleBilinearForm(*a); // full matrix assembly } } tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << " s." <FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "[perf && free] Size of linear system: " << a_hpc->Height() << endl; - } - else - { - cout << "[std] a FormLinearSystem" << endl<FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cout << "[std] Size of linear system: " << A.Height() << endl; - a_oper = &A; - } - - // Setup the matrix used for preconditioning - //cout << "Assembling the preconditioning matrix ..." << endl << flush; - tic_toc.Clear(); - tic_toc.Start(); - - SparseMatrix A_pc; - if (pc_choice == LOR) - { - cout << "pc_choice == LOR" << flush << endl; - // TODO: assemble the LOR matrix using the performance code - a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); - a_pc->UsePrecomputedSparsity(); - a_pc->Assemble(); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - else if (pc_choice == HO) - { - if (!matrix_free) - { - cout << "[std] matrix already assembled, reuse it" << flush << endl; - A_pc.MakeRef(A); // matrix already assembled, reuse it - } - else - { - cout << "[hpc && free] else" << flush << endl; - a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - } - - tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; - - // Solve with CG or PCG, depending if the matrix A_pc is available - if (pc_choice != NONE) - { - cout << "PCG" << endl; - GSSmoother M(A_pc); - PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); - } - else - { - cout << "CG" << endl; - CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); - } - - // 13. Recover the solution as a finite element grid function. - if (perf && matrix_free) - { - cout << "[hpc && free] a_hpc->RecoverFEMSolution" << endl; - a_hpc->RecoverFEMSolution(X, *b, x); - } - else - { - cout << "[std] a->RecoverFEMSolution" << endl; - a->RecoverFEMSolution(X, *b, x); - } - - // 14. Save the refined mesh and the solution. This output can be viewed later - // using GLVis: "glvis -m refined.mesh -g sol.gf". - ofstream mesh_ofs("refined.mesh"); - mesh_ofs.precision(8); - mesh->Print(mesh_ofs); - ofstream sol_ofs("sol.gf"); - sol_ofs.precision(8); - x.Save(sol_ofs); - - // 15. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock.precision(8); - sol_sock << "solution\n" << *mesh << x << flush; - } + if (perf && matrix_free) + { + a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "Size of linear system: " << a_hpc->Height() << endl; } - + else + { + a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + cout << "Size of linear system: " << A.Height() << endl; + a_oper = &A; + } + + // Setup the matrix used for preconditioning + cout << "Assembling the preconditioning matrix ..." << flush; + tic_toc.Clear(); + tic_toc.Start(); + + SparseMatrix A_pc; + if (pc_choice == LOR) + { + // TODO: assemble the LOR matrix using the performance code + a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); + a_pc->UsePrecomputedSparsity(); + a_pc->Assemble(); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + else if (pc_choice == HO) + { + if (!matrix_free) + { + A_pc.MakeRef(A); // matrix already assembled, reuse it + } + else + { + a_pc->UsePrecomputedSparsity(); + a_hpc->AssembleBilinearForm(*a_pc); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + } + + tic_toc.Stop(); + cout << " done, " << tic_toc.RealTime() << "s." << endl; + + // Solve with CG or PCG, depending if the matrix A_pc is available + if (pc_choice != NONE) + { + GSSmoother M(A_pc); + PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); + } + else + { + CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + } + + // 13. Recover the solution as a finite element grid function. + if (perf && matrix_free) + { + a_hpc->RecoverFEMSolution(X, *b, x); + } + else + { + a->RecoverFEMSolution(X, *b, x); + } + + // 14. Save the refined mesh and the solution. This output can be viewed later + // using GLVis: "glvis -m refined.mesh -g sol.gf". + ofstream mesh_ofs("refined.mesh"); + mesh_ofs.precision(8); + mesh->Print(mesh_ofs); + ofstream sol_ofs("sol.gf"); + sol_ofs.precision(8); + x.Save(sol_ofs); + + // 15. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock.precision(8); + sol_sock << "solution\n" << *mesh << x << flush; + } + // 16. Free the used memory. delete a; delete a_hpc; From e192295133b211b0f8d9eda5f7ba0ac178bd64c1 Mon Sep 17 00:00:00 2001 From: camierjs Date: Fri, 15 Jun 2018 17:46:38 -0700 Subject: [PATCH 006/535] [x86] before SIMD/BATCH patch --- fem/tbilinearform.hpp | 37 +++++++++++++++++++++++-------------- fem/tevaluator.hpp | 1 + fem/tfespace.hpp | 3 +-- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index fd1921e3a5..488e5e0535 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -55,7 +55,7 @@ template -class TBilinearForm : public Operator, public AlignedNew<32> +class TBilinearForm : public Operator//, public AlignedNew<32> { protected: typedef complex_t complex_type; @@ -140,7 +140,7 @@ public: #ifdef MFEM_USE_X86INTRIN // Allocate aligned memory with x86 intrinsics alignment requirements - //static void* operator new(size_t count) { return x86::alloc(count); } + static void* operator new(size_t count) { return x86::alloc(count); } #endif /// Get the input finite element space prolongation matrix @@ -224,20 +224,20 @@ public: const int NE = mesh.GetNE(); if (!assembled_data) { -#ifndef MFEM_USE_X86INTRIN - assembled_data = new p_assembled_t[NE]; +#ifndef MFEM_USE_X86INTRIN + assembled_data = new p_assembled_t[NE]; #else - //assembled_data = new p_assembled_t[NE]; - void* result = nullptr; - //const int aligned_size = MFEM_ALIGN_SIZE(NE,p_assembled_t); - const int size = NE*sizeof(p_assembled_t); - const auto alloc_failed = posix_memalign(&result, 32, size); - if (alloc_failed) throw ::std::bad_alloc(); - assembled_data = (p_assembled_t*) result; + assembled_data = new p_assembled_t[NE/x86::width]; #endif } +#ifndef MFEM_USE_X86INTRIN for (int el = 0; el < NE; el++) // BE == 1 +#else + assert((NE%x86::width)==0); + for (int el = 0; el < NE; el+=x86::width) +#endif { + //p_assembled_t _assembled_data; typename T_result::Type F; T.Eval(el, F); @@ -246,7 +246,7 @@ public: for (int k = 0; k < BE; k++) { - kernel_t::Assemble(k, F, wQ, res, assembled_data[el+k]); + kernel_t::Assemble(k, F, wQ, res, assembled_data[el]); } } } @@ -260,6 +260,7 @@ public: for (int k = 0; k < num_elem; k++) { + assert(k==0); kernel_t::MultAssembled(k, assembled_data[el+k], R); } @@ -275,11 +276,11 @@ public: void MultAssembled(const Vector &x, Vector &y) const { y = 0.0; - solFieldEval solFEval(solFES, solEval, solVecLayout, x.GetData(), y.GetData()); const int NE = mesh.GetNE(); +#ifndef MFEM_USE_X86INTRIN const int bNE = NE-NE%num_elem; for (int el = 0; el < bNE; el += num_elem) { @@ -289,6 +290,14 @@ public: { ElementAddMultAssembled<1>(el, solFEval); } +#else + assert(num_elem==1); + printf("\n\033[31;1m[MultAssembled] NE=%d & num_elem=%d\033[m\n",NE,num_elem); + for (int el = 0; el < NE; el += 1/*x86::width*/) + { + ElementAddMultAssembled<1>(el, solFEval); + } +#endif } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE @@ -528,7 +537,7 @@ public: // diagonal block for all components. #ifndef MFEM_USE_X86INTRIN TMatrix M_loc; -#else // MFEM_USE_X86INTRIN +#else TMatrix M_loc; #endif S_spec::ElementMatrix::Compute( diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 759f0cf68d..049a20d9a5 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -1442,6 +1442,7 @@ public: void Compute(const qpt_layout_t &a, const qpt_data_t &A, const M_layout_t &m, M_data_t &M, ShapeEval_type &ev) { + assert(false); ev.Assemble(a.template split_1(), A, m.template split_2(), M); } diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index 1a6b76d98c..d40689b85b 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -111,7 +111,7 @@ public: { loc_dof_list = el_dof_list + elem_idx * FE::dofs; } - + inline MFEM_ALWAYS_INLINE int map(int loc_dof_idx, int elem_offset) const { @@ -260,7 +260,6 @@ public: for(int n=0; n(vdof_data[vdof_layout.ind(i,k,j)],gather); From 89db8f121a6f8b575eb99a0cf38fe7cdd640b7a5 Mon Sep 17 00:00:00 2001 From: camierjs Date: Fri, 15 Jun 2018 18:21:31 -0700 Subject: [PATCH 007/535] [batch] applied --- config/tconfig.hpp | 257 ++++++++++++++++- fem/bilinearform.cpp | 12 - fem/bilinearform.hpp | 4 - fem/fespace.cpp | 23 -- fem/fespace.hpp | 6 - fem/tbilinearform.hpp | 418 ++++++++++++++-------------- fem/tbilininteg.hpp | 20 +- fem/tcoefficient.hpp | 39 ++- fem/teltrans.hpp | 183 ++++++------ fem/tevaluator.hpp | 189 ++++++------- fem/tfespace.hpp | 224 ++++++--------- fem/tintrules.hpp | 2 +- linalg/sparsemat.cpp | 12 - linalg/sparsemat.hpp | 47 +--- linalg/tdensemat.hpp | 123 -------- linalg/tmatrix.hpp | 43 ++- linalg/ttensor.hpp | 3 - miniapps/performance/CMakeLists.txt | 6 +- miniapps/performance/ex1.cpp | 16 +- miniapps/performance/makefile | 13 +- 20 files changed, 814 insertions(+), 826 deletions(-) delete mode 100644 linalg/tdensemat.hpp diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 026684d4a9..c60092ffce 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -29,15 +29,30 @@ #define MFEM_ALWAYS_INLINE #endif +// --- MFEM_VECTORIZE_LOOP (disabled) +#if (__cplusplus >= 201103L) && !defined(MFEM_DEBUG) && defined(__GNUC__) +// #define MFEM_VECTORIZE_LOOP _Pragma("GCC ivdep") +#define MFEM_VECTORIZE_LOOP +#else +#define MFEM_VECTORIZE_LOOP +#endif + +#define MFEM_TEMPLATE_BLOCK_SIZE 4 +#define MFEM_SIMD_SIZE 32 +#define MFEM_TEMPLATE_ENABLE_SERIALIZE + #ifdef MFEM_USE_X86INTRIN #include "general/x86intrin.hpp" #endif -#define MFEM_TEMPLATE_BLOCK_SIZE 4 -#ifndef MFEM_SIMD_SIZE -#define MFEM_SIMD_SIZE 32 +// -- MFEM_ALIGN_AS +#if (__cplusplus >= 201103L) +#define MFEM_ALIGN_AS(bytes) alignas(bytes) +#elif !defined(MFEM_DEBUG) && (defined(__GNUC__) || defined(__clang__)) +#define MFEM_ALIGN_AS(bytes) __attribute__ ((aligned (bytes))) +#else +#define MFEM_ALIGN_AS(bytes) #endif -#define MFEM_TEMPLATE_ENABLE_SERIALIZE // #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS // #define MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES @@ -67,4 +82,238 @@ long long flop_count; #define MFEM_FLOPS_GET() (0) #endif +template +struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = S; + static const int align_size = align_S; + + scalar_t vec[size]; + + scalar_t &operator[](int i) { return vec[i]; } + const scalar_t &operator[](int i) const { return vec[i]; } + + AutoSIMD &operator=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = v[i]; } + return *this; + } + AutoSIMD &operator=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = e; } + return *this; + } + AutoSIMD &operator+=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += v[i]; } + return *this; + } + AutoSIMD &operator+=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += e; } + return *this; + } + AutoSIMD &operator-=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] -= v[i]; } + return *this; + } + AutoSIMD &operator-=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] -= e; } + return *this; + } + AutoSIMD &operator*=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] *= v[i]; } + return *this; + } + AutoSIMD &operator*=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] *= e; } + return *this; + } + AutoSIMD &operator/=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] /= v[i]; } + return *this; + } + AutoSIMD &operator/=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] /= e; } + return *this; + } + + AutoSIMD operator-() const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = -vec[i]; } + return r; + } + + AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] + v[i]; } + return r; + } + AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] + e; } + return r; + } + AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] - v[i]; } + return r; + } + AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] - e; } + return r; + } + AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] * v[i]; } + return r; + } + AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] * e; } + return r; + } + AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] / v[i]; } + return r; + } + AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] / e; } + return r; + } + + AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += v[i] * w[i]; } + return *this; + } + AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } + return *this; + } + AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += e * v[i]; } + return *this; + } + + AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = v[i] * w[i]; } + return *this; + } + AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } + return *this; + } + AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = e * v[i]; } + return *this; + } +}; + +template +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e + v[i]; } + return r; +} + +template +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e - v[i]; } + return r; +} + +template +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e * v[i]; } + return r; +} + +template +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e / v[i]; } + return r; +} + + +template +struct AutoImplTraits +{ + static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; + static const int align_size = MFEM_SIMD_SIZE; // in bytes + + // static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); + static const int simd_size = 1; + static const int valign_size = simd_size; + // static const int valign_size = 1; + static const int batch_size = 1; + typedef AutoSIMD vcomplex_t; + typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; + typedef AutoSIMD< int,simd_size,valign_size> vint_t; +}; + #endif // MFEM_TEMPLATE_CONFIG diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index 740e359299..26da340892 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -263,18 +263,6 @@ void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) } } -#ifdef MFEM_USE_X86INTRIN -void BilinearForm::AssembleElementMatrix(int i, - const TDenseMatrix &M, - Array &vdofs){ - fes->GetElementVDofs(i, vdofs); - if (mat == NULL) { - AllocMat(); - } - mat->AddSubMatrix(vdofs, M); -} -#endif - void BilinearForm::AssembleElementMatrix( int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros) { diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index a3027d1e5c..f62582de6d 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -300,10 +300,6 @@ public: { delete element_matrices; element_matrices = NULL; } void ComputeElementMatrix(int i, DenseMatrix &elmat); -#ifdef MFEM_USE_X86INTRIN - void AssembleElementMatrix(int, const TDenseMatrix&, - Array&); -#endif void AssembleElementMatrix(int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros = 1); void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 5148c212da..ebd1acb805 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -168,13 +168,6 @@ void FiniteElementSpace::AdjustVDofs (Array &vdofs) } } -#ifdef MFEM_USE_X86INTRIN -void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const -{ - GetElementDofs(i, vdofs); - //DofsToVDofs(vdofs); // Should it be done? -} -#endif void FiniteElementSpace::GetElementVDofs(int i, Array &vdofs) const { GetElementDofs(i, vdofs); @@ -1236,22 +1229,6 @@ void FiniteElementSpace::Construct() // Do not build elem_dof Table here: in parallel it has to be constructed // later. } - -#ifdef MFEM_USE_X86INTRIN -void FiniteElementSpace::GetElementDofs(int i, Array &dofs) const{ - Array dof[x86::width]; - for(int k=0; kGetRow(i+k, dof[k]); - const int size = dof[0].Size(); - dofs.SetSize(size); - x86::vint_t gather=0; - for(int j=0;j &dofs) const { diff --git a/fem/fespace.hpp b/fem/fespace.hpp index b3e720c4d8..4a8ffa4d09 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -316,9 +316,6 @@ public: /// Returns indexes of degrees of freedom in array dofs for i'th element. virtual void GetElementDofs(int i, Array &dofs) const; -#ifdef MFEM_USE_X86INTRIN - virtual void GetElementDofs(int i, Array &dofs) const; -#endif /// Returns indexes of degrees of freedom for i'th boundary element. virtual void GetBdrElementDofs(int i, Array &dofs) const; @@ -355,9 +352,6 @@ public: /// Returns indexes of degrees of freedom in array dofs for i'th element. void GetElementVDofs(int i, Array &vdofs) const; -#ifdef MFEM_USE_X86INTRIN - void GetElementVDofs(int i, Array &vdofs) const; -#endif /// Returns indexes of degrees of freedom for i'th boundary element. void GetBdrElementVDofs(int i, Array &vdofs) const; diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 488e5e0535..1f0f082f7a 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -19,34 +19,10 @@ #include "teltrans.hpp" #include "tcoefficient.hpp" #include "fespace.hpp" -#include "../linalg/tdensemat.hpp" -#include + namespace mfem { - -using size_t = ::std::size_t; -template -struct alignas(ALIGNMENT) AlignedNew { - static_assert(ALIGNMENT > 0, "ALIGNMENT must be positive"); - static_assert((ALIGNMENT & (ALIGNMENT - 1)) == 0, - "ALIGNMENT must be a power of 2"); - static_assert((ALIGNMENT % sizeof(void*)) == 0, - "ALIGNMENT must be a multiple of sizeof(void *)"); - static void* operator new(size_t count) { return Allocate(count); } - static void* operator new[](size_t count) { return Allocate(count); } - static void operator delete(void* ptr) { free(ptr); } - static void operator delete[](void* ptr) { free(ptr); } - - private: - static void* Allocate(size_t count) { - void* result = nullptr; - const auto alloc_failed = posix_memalign(&result, ALIGNMENT, count); - if (alloc_failed) throw ::std::bad_alloc(); - return result; - } -}; - // Templated bilinear form class, cf. bilinearform.?pp // complex_t - sol dof data type @@ -54,9 +30,13 @@ struct alignas(ALIGNMENT) AlignedNew { template -class TBilinearForm : public Operator//, public AlignedNew<32> + typename complex_t = double, typename real_t = double, + typename impl_traits_t = AutoImplTraits > +class TBilinearForm : public Operator { +public: + typedef impl_traits_t impl_traits_type; + protected: typedef complex_t complex_type; typedef real_t real_type; @@ -73,25 +53,35 @@ protected: static const int vdim = solVecLayout_t::vec_dim; static const int qpts = IR::qpts; + static const int SS = impl_traits_t::simd_size; + static const int BE = impl_traits_t::batch_size; // batch-size of elements + static const int TE = SS*BE; + + typedef typename impl_traits_t::vcomplex_t vcomplex_t; + typedef typename impl_traits_t::vreal_t vreal_t; + typedef IntegratorType integ_t; typedef typename integ_t::coefficient_type coeff_t; - typedef typename integ_t::template kernel::type kernel_t; + typedef typename integ_t::template kernel::type kernel_t; typedef typename kernel_t::template p_asm_data::type p_assembled_t; typedef typename kernel_t::template f_asm_data::type f_assembled_t; + typedef typename kernel_t::template + CoefficientEval::Type coeff_eval_t; + typedef TElementTransformation Trans_t; - template struct T_result + struct T_result { static const int EvalOps = Trans_t::template Get::EvalOps; - typedef typename Trans_t::template Result Type; + typedef typename Trans_t::template Result Type; }; typedef FieldEvaluator solFieldEval; - template struct S_spec + struct S_spec { - typedef typename solFieldEval::template Spec Spec; + typedef typename solFieldEval::template Spec Spec; typedef typename Spec::DataType DataType; typedef typename Spec::ElementMatrix ElementMatrix; }; @@ -131,18 +121,9 @@ public: virtual ~TBilinearForm() { -#ifndef MFEM_USE_X86INTRIN delete [] assembled_data; -#else - free(assembled_data); -#endif } -#ifdef MFEM_USE_X86INTRIN - // Allocate aligned memory with x86 intrinsics alignment requirements - static void* operator new(size_t count) { return x86::alloc(count); } -#endif - /// Get the input finite element space prolongation matrix virtual const Operator *GetProlongation() const { return ((FiniteElementSpace &)in_fes).GetProlongationMatrix(); } @@ -154,8 +135,7 @@ public: { if (assembled_data) { - const int num_elem = 1; - MultAssembled(x, y); + MultAssembled(x, y); } else { @@ -168,10 +148,6 @@ public: { y = 0.0; - const int BE = 1; // batch-size of elements - typedef typename kernel_t::template - CoefficientEval::Type coeff_eval_t; - // For better performance, create stack copies of solFES, and solEval // inside 'solFEval'. The element-transformation 'T' also copies the // meshFES, meshEval, etc internally. @@ -182,63 +158,50 @@ public: coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); - for (int el = 0; el < NE; el++) + for (int el = 0; el < NE; el += TE) { #if 0 - typename S_spec::DataType R; + typename S_spec::DataType R; solFEval.Eval(el, R); - typename T_result::Type F; + typename T_result::Type F; T.Eval(el, F); #else - typename T_result::Type F; + typename T_result::Type F; T.Eval(el, F); - typename S_spec::DataType R; + typename S_spec::DataType R; solFEval.Eval(el, R); #endif typename coeff_eval_t::result_t res; wQ.Eval(F, res); - kernel_t::Action(0, F, wQ, res, R); + for (int k = 0; k < BE; k++) + { + kernel_t::Action(k, F, wQ, res, R); + } -#ifndef MFEM_USE_X86INTRIN solFEval.template Assemble(R); -#else - solFEval.template Assemble(el,R); -#endif } } // Partial assembly of quadrature point data void Assemble() { - const int BE = 1; // batch-size of elements - typedef typename kernel_t::template - CoefficientEval::Type coeff_eval_t; - Trans_t T(mesh, meshEval); coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); if (!assembled_data) { -#ifndef MFEM_USE_X86INTRIN - assembled_data = new p_assembled_t[NE]; -#else - assembled_data = new p_assembled_t[NE/x86::width]; -#endif + // TODO: How do we make sure that this array is aligned properly, AND + // the compiler knows that it is aligned? + assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; } -#ifndef MFEM_USE_X86INTRIN - for (int el = 0; el < NE; el++) // BE == 1 -#else - assert((NE%x86::width)==0); - for (int el = 0; el < NE; el+=x86::width) -#endif + for (int el = 0; el < NE; el += TE) { - //p_assembled_t _assembled_data; - typename T_result::Type F; + typename T_result::Type F; T.Eval(el, F); typename coeff_eval_t::result_t res; @@ -246,58 +209,38 @@ public: for (int k = 0; k < BE; k++) { - kernel_t::Assemble(k, F, wQ, res, assembled_data[el]); + kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]); } } } - template inline MFEM_ALWAYS_INLINE void ElementAddMultAssembled(int el, solFieldEval &solFEval) const { - typename S_spec::DataType R; + typename S_spec::DataType R; solFEval.Eval(el, R); - for (int k = 0; k < num_elem; k++) + for (int k = 0; k < BE; k++) { - assert(k==0); - kernel_t::MultAssembled(k, assembled_data[el+k], R); + kernel_t::MultAssembled(k, assembled_data[el/SS+k], R); } -#ifndef MFEM_USE_X86INTRIN solFEval.template Assemble(R); -#else - solFEval.template Assemble(el,R); -#endif } // complex_t = double - template void MultAssembled(const Vector &x, Vector &y) const { y = 0.0; + solFieldEval solFEval(solFES, solEval, solVecLayout, x.GetData(), y.GetData()); const int NE = mesh.GetNE(); -#ifndef MFEM_USE_X86INTRIN - const int bNE = NE-NE%num_elem; - for (int el = 0; el < bNE; el += num_elem) + for (int el = 0; el < NE; el += TE) { - ElementAddMultAssembled(el, solFEval); + ElementAddMultAssembled(el, solFEval); } - for (int el = bNE; el < NE; el++) - { - ElementAddMultAssembled<1>(el, solFEval); - } -#else - assert(num_elem==1); - printf("\n\033[31;1m[MultAssembled] NE=%d & num_elem=%d\033[m\n",NE,num_elem); - for (int el = 0; el < NE; el += 1/*x86::width*/) - { - ElementAddMultAssembled<1>(el, solFEval); - } -#endif } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE @@ -309,10 +252,10 @@ public: solVecLayout_type solVecLayout(this->solVecLayout); solFESpace solFES(this->solFES); - TTensor3 xy_dof; + TTensor3 xy_dof; const int NE = mesh.GetNE(); - for (int el = 0; el < NE; el++) + for (int el = 0; el < NE; el += TE) { solFES.SetElement(el); @@ -326,17 +269,21 @@ public: { typedef typename meshType::FESpace_type meshFESpace; meshFESpace meshFES(mesh.t_fes); - typedef TTensor3 lnodes_t; + typedef TTensor3 lnodes_t; const int NE = mesh.GetNE(); - sNodes.SetSize(lnodes_t::size*NE); - real_t *lNodes = sNodes.GetData(); - for (int el = 0; el < NE; el++) + // TODO: How do we make sure that this array is aligned properly, AND + // the compiler knows that it is aligned? + const int NVE = (NE+TE-1)/TE; + vreal_t *vsNodes = new vreal_t[lnodes_t::size*NVE]; + sNodes.NewDataAndSize(vsNodes[0].vec, (lnodes_t::size*SS)*NVE); + sNodes.MakeDataOwner(); + for (int el = 0; el < NE; el += TE) { meshFES.SetElement(el); meshFES.VectorExtract(mesh.node_layout, mesh.Nodes, - lnodes_t::layout, lNodes); - lNodes += lnodes_t::size; + lnodes_t::layout, vsNodes); + vsNodes += lnodes_t::size; } } @@ -344,45 +291,52 @@ public: // real_t = double void AssembleFromSerializedNodes(const Vector &sNodes) { - const int BE = 1; // batch-size of elements - typedef typename kernel_t::template - CoefficientEval::Type coeff_eval_t; - - Trans_t T(this->mesh, this->meshEval); + Trans_t T(mesh, meshEval); coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); if (!assembled_data) { - assembled_data = new p_assembled_t[NE]; + // TODO: How do we make sure that this array is aligned properly, AND + // the compiler knows that it is aligned? + assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; } - for (int el = 0; el < NE; el++) + const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData()); + for (int el = 0; el < NE; el += TE) { - typename T_result::Type F; - T.EvalSerialized(el, sNodes.GetData(), F); + typename T_result::Type F; + T.EvalSerialized(el, vsNodes, F); typename coeff_eval_t::result_t res; wQ.Eval(F, res); - kernel_t::Assemble(0, F, wQ, res, assembled_data[el]); + for (int k = 0; k < BE; k++) + { + kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]); + } } } // complex_t = double void Serialize(const Vector &x, Vector &sx) const { + typedef TTensor3 vdof_data_t; + solVecLayout_t solVecLayout(this->solVecLayout); - typedef TTensor3 vdof_data_t; solFESpace solFES(this->solFES); const int NE = mesh.GetNE(); - sx.SetSize(vdim*dofs*NE); - complex_t *loc_sx = sx.GetData(); - for (int el = 0; el < NE; el++) + // TODO: How do we make sure that this array is aligned properly, AND + // the compiler knows that it is aligned? + const int NVE = (NE+TE-1)/TE; + vreal_t *vsx = new vreal_t[vdof_data_t::size*NVE]; + sx.NewDataAndSize(vsx[0].vec, (vdof_data_t::size*SS)*NVE); + sx.MakeDataOwner(); + for (int el = 0; el < NE; el += TE) { solFES.SetElement(el); - solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, loc_sx); - loc_sx += vdim*dofs; + solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, vsx); + vsx += vdof_data_t::size; } } @@ -393,19 +347,26 @@ public: solFieldEval solFEval(solFES, solEval, solVecLayout, NULL, NULL); const int NE = mesh.GetNE(); - const complex_t *loc_sx = sx.GetData(); - complex_t *loc_sy = sy.GetData(); - for (int el = 0; el < NE; el++) + // TODO: How do we make sure that the compiler knows that this array is + // aligned? + const vreal_t *vsx = (const vreal_t*)(sx.GetData()); + // TODO: Check if the pointer is aligned properly. + vreal_t *vsy = (vreal_t*)(sy.GetData()); + + for (int el = 0; el < NE; el += TE) { - typename S_spec<1>::DataType R; - solFEval.EvalSerialized(loc_sx, R); + typename S_spec::DataType R; + solFEval.EvalSerialized(vsx, R); - kernel_t::MultAssembled(0, assembled_data[el], R); + for (int k = 0; k < BE; k++) + { + kernel_t::MultAssembled(k, assembled_data[el/SS+k], R); + } - solFEval.template AssembleSerialized(R, loc_sy); + solFEval.template AssembleSerialized(R, vsy); - loc_sx += vdim*dofs; - loc_sy += vdim*dofs; + vsx += vdim*dofs*BE; + vsy += vdim*dofs*BE; } } #endif // MFEM_TEMPLATE_ENABLE_SERIALIZE @@ -414,10 +375,6 @@ public: // complex_t = double void AssembleMatrix(SparseMatrix &M) const { - const int BE = 1; // batch-size of elements - typedef typename kernel_t::template - CoefficientEval::Type coeff_eval_t; - Trans_t T(mesh, meshEval); solFESpace solFES(this->solFES); solShapeEval solEval(this->solEval); @@ -425,29 +382,39 @@ public: coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); - for (int el = 0; el < NE; el++) + for (int el = 0; el < NE; el += TE) { - f_assembled_t asm_qpt_data; + f_assembled_t asm_qpt_data[BE]; { - typename T_result::Type F; + typename T_result::Type F; T.Eval(el, F); typename coeff_eval_t::result_t res; wQ.Eval(F, res); - kernel_t::Assemble(0, F, wQ, res, asm_qpt_data); + for (int k = 0; k < BE; k++) + { + kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]); + } } // For now, when vdim > 1, assume block-diagonal matrix with the same // diagonal block for all components. - TMatrix M_loc; - S_spec::ElementMatrix::Compute( - asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval); - - solFES.SetElement(el); - for (int bi = 0; bi < vdim; bi++) + for (int k = 0; k < BE; k++) { - solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M); + const int el_k = el+SS*k; + if (el_k >= NE) { break; } + + TMatrix M_loc; + S_spec::ElementMatrix::Compute( + asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc, + solEval); + + solFES.SetElement(el_k); + for (int bi = 0; bi < vdim; bi++) + { + solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M); + } } } } @@ -456,37 +423,52 @@ public: // complex_t = double void AssembleMatrix(DenseTensor &M) const { - const int BE = 1; // batch-size of elements - typedef typename kernel_t::template - CoefficientEval::Type coeff_eval_t; - Trans_t T(mesh, meshEval); solShapeEval solEval(this->solEval); coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); - for (int el = 0; el < NE; el++) + for (int el = 0; el < NE; el += TE) { - f_assembled_t asm_qpt_data; + f_assembled_t asm_qpt_data[BE]; { - typename T_result::Type F; + typename T_result::Type F; T.Eval(el, F); typename coeff_eval_t::result_t res; wQ.Eval(F, res); - kernel_t::Assemble(0, F, wQ, res, asm_qpt_data); + for (int k = 0; k < BE; k++) + { + kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]); + } } // For now, when vdim > 1, assume block-diagonal matrix with the same // diagonal block for all components. // M is assumed to be (dof x dof x NE). - TMatrix M_loc; - S_spec::ElementMatrix::Compute( - asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval); + for (int k = 0; k < BE; k++) + { + const int el_k = el+SS*k; + if (el_k >= NE) { break; } - complex_t *M_data = M.GetData(el); - M_loc.template AssignTo(M_data); + TMatrix M_loc; + S_spec::ElementMatrix::Compute( + asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc, + solEval); + + for (int s = 0; s < SS && el_k+s < NE; s++) + { + complex_t *M_data = M.GetData(el_k+s); + for (int j = 0; j < dofs; j++) + { + for (int i = 0; i < dofs; i++) + { + M_data[j+dofs*i] = M_loc(i,j)[s]; + } + } + } + } } } @@ -494,89 +476,97 @@ public: // complex_t = double void AssembleBilinearForm(BilinearForm &a) const { - const int BE = 1; // batch-size of elements - typedef typename kernel_t::template - CoefficientEval::Type coeff_eval_t; - Trans_t T(mesh, meshEval); solShapeEval solEval(this->solEval); coeff_eval_t wQ(int_rule, coeff); -#ifndef MFEM_USE_X86INTRIN Array vdofs; const Array *dof_map = sol_fe.GetDofMap(); const int *dof_map_ = dof_map->GetData(); DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros -#else // MFEM_USE_X86INTRIN - Array vdofs; - const Array *dof_map = sol_fe.GetDofMap(); - const int *dof_map_ = dof_map->GetData(); - TDenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros - MFEM_VERIFY((mesh.GetNE()%x86::width)==0,"x86::width should be modulo NE"); -#endif const int NE = mesh.GetNE(); -#ifndef MFEM_USE_X86INTRIN - for (int el = 0; el < NE; el++) -#else - for (int el = 0; el < NE; el+=x86::width) -#endif + for (int el = 0; el < NE; el += TE) { - f_assembled_t asm_qpt_data; + f_assembled_t asm_qpt_data[BE]; { - typename T_result::Type F; + typename T_result::Type F; T.Eval(el, F); typename coeff_eval_t::result_t res; wQ.Eval(F, res); - kernel_t::Assemble(0, F, wQ, res, asm_qpt_data); + for (int k = 0; k < BE; k++) + { + kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]); + } } // For now, when vdim > 1, assume block-diagonal matrix with the same // diagonal block for all components. -#ifndef MFEM_USE_X86INTRIN - TMatrix M_loc; -#else - TMatrix M_loc; -#endif - S_spec::ElementMatrix::Compute( - asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval); - - if (dof_map) // switch from tensor-product ordering + for (int k = 0; k < BE; k++) { - for (int i = 0; i < dofs; i++) + const int el_k = el+SS*k; + if (el_k >= NE) { break; } + + TMatrix M_loc; + S_spec::ElementMatrix::Compute( + asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc, + solEval); + + if (dof_map) // switch from tensor-product ordering { - for (int j = 0; j < dofs; j++) + for (int s = 0; s < SS && el_k+s < NE; s++) { - M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j); + for (int i = 0; i < dofs; i++) + { + for (int j = 0; j < dofs; j++) + { + M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j)[s]; + } + } + for (int bi = 1; bi < vdim; bi++) + { + M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0, + bi*dofs, bi*dofs); + } + a.AssembleElementMatrix(el_k+s, M_loc_perm, vdofs); } } - for (int bi = 1; bi < vdim; bi++) + else if (SS == 1) { - M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0, - bi*dofs, bi*dofs); - } - a.AssembleElementMatrix(el, M_loc_perm, vdofs); - } - else - { -#ifndef MFEM_USE_X86INTRIN - DenseMatrix DM(M_loc.data, dofs, dofs); -#else - TDenseMatrix DM(M_loc.data,dofs*vdim,dofs*vdim); // initialized with zeros -#endif - if (vdim == 1) - { - a.AssembleElementMatrix(el, DM, vdofs); + DenseMatrix DM(M_loc.data[0].vec, dofs, dofs); + if (vdim == 1) + { + a.AssembleElementMatrix(el_k, DM, vdofs); + } + else + { + for (int bi = 0; bi < vdim; bi++) + { + M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs); + } + a.AssembleElementMatrix(el_k, M_loc_perm, vdofs); + } } else { - for (int bi = 0; bi < vdim; bi++) + for (int s = 0; s < SS && el_k+s < NE; s++) { - M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs); + for (int i = 0; i < dofs; i++) + { + for (int j = 0; j < dofs; j++) + { + M_loc_perm(i,j) = M_loc(i,j)[s]; + } + } + for (int bi = 1; bi < vdim; bi++) + { + M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0, + bi*dofs, bi*dofs); + } + a.AssembleElementMatrix(el_k+s, M_loc_perm, vdofs); } - a.AssembleElementMatrix(el, M_loc_perm, vdofs); } } } @@ -593,7 +583,7 @@ public: const int NE = mesh.GetNE(); for (int el = 0; el < NE; el++) { - TTensor3 x_dof, y_dof; + TTensor3 > x_dof, y_dof; solFES.SetElement(el); solFES.VectorExtract(solVecLayout, x, x_dof.layout, x_dof); diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index 921c8c8b46..73892b8177 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -65,10 +65,10 @@ struct TMassKernel template struct f_asm_data { typedef TVector type; }; - template + template struct CoefficientEval { - typedef typename IntRuleCoefficient::Type Type; + typedef typename IntRuleCoefficient::Type Type; }; // Method used for un-assembled (matrix free) action. @@ -173,17 +173,17 @@ struct TDiffusionKernel<1,1,complex_t> // quadrature points. This type is used in partial assembly, and partially // assembled action. template - struct p_asm_data { typedef TMatrix type; }; + struct p_asm_data { typedef TMatrix type; }; // Partially assembled data type for one element with the given number of // quadrature points. This type is used in full element matrix assembly. template struct f_asm_data { typedef TTensor3 type; }; - template + template struct CoefficientEval { - typedef typename IntRuleCoefficient::Type Type; + typedef typename IntRuleCoefficient::Type Type; }; // Method used for un-assembled (matrix free) action. @@ -293,10 +293,10 @@ struct TDiffusionKernel<2,2,complex_t> template struct f_asm_data { typedef TTensor3 type; }; - template + template struct CoefficientEval { - typedef typename IntRuleCoefficient::Type Type; + typedef typename IntRuleCoefficient::Type Type; }; // Method used for un-assembled (matrix free) action. @@ -434,10 +434,10 @@ struct TDiffusionKernel<3,3,complex_t> template struct f_asm_data { typedef TTensor3 type; }; - template + template struct CoefficientEval { - typedef typename IntRuleCoefficient::Type Type; + typedef typename IntRuleCoefficient::Type Type; }; // Method used for un-assembled (matrix free) action. @@ -501,7 +501,7 @@ struct TDiffusionKernel<3,3,complex_t> const bool Symm = (asm_type::layout_type::rank == 2); for (int i = 0; i < M; i++) { - TMatrix<3,3,real_t,true> B; // = adj(J) + TMatrix<3,3,real_t> B; // = adj(J) const complex_t u = (Q.get(q,i,k) / TAdjDet(F.Jt.layout.ind14(i,k).transpose_12(), F.Jt, diff --git a/fem/tcoefficient.hpp b/fem/tcoefficient.hpp index 7b0479b4e0..5e8a1aa4b0 100644 --- a/fem/tcoefficient.hpp +++ b/fem/tcoefficient.hpp @@ -81,11 +81,15 @@ protected: { const int qpts = T_result_t::x_type::layout_type::dim_1; const int ne = T_result_t::x_type::layout_type::dim_3; + const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]); for (int k = 0; k < ne; k++) { for (int i = 0; i < qpts; i++) { - c[l.ind(i,k)] = F.Eval1D(T.x(i,0,k)); + for (int s = 0; s < vs; s++) + { + c[l.ind(i,k)][s] = F.Eval1D(T.x(i,0,k)[s]); + } } } } @@ -98,11 +102,15 @@ protected: { const int qpts = T_result_t::x_type::layout_type::dim_1; const int ne = T_result_t::x_type::layout_type::dim_3; + const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]); for (int k = 0; k < ne; k++) { for (int i = 0; i < qpts; i++) { - c[l.ind(i,k)] = F.Eval2D(T.x(i,0,k), T.x(i,1,k)); + for (int s = 0; s < vs; s++) + { + c[l.ind(i,k)][s] = F.Eval2D(T.x(i,0,k)[s], T.x(i,1,k)[s]); + } } } } @@ -115,11 +123,16 @@ protected: { const int qpts = T_result_t::x_type::layout_type::dim_1; const int ne = T_result_t::x_type::layout_type::dim_3; + const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]); for (int k = 0; k < ne; k++) { for (int i = 0; i < qpts; i++) { - c[l.ind(i,k)] = F.Eval3D(T.x(i,0,k), T.x(i,1,k), T.x(i,2,k)); + for (int s = 0; s < vs; s++) + { + c[l.ind(i,k)][s] = + F.Eval3D(T.x(i,0,k)[s], T.x(i,1,k)[s], T.x(i,2,k)[s]); + } } } } @@ -170,9 +183,16 @@ public: void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c) { const int ne = T_result_t::ne; + const int vs = sizeof(T.attrib[0])/sizeof(T.attrib[0][0]); + MFEM_STATIC_ASSERT(vs == sizeof(c[0])/sizeof(c[0][0]), ""); for (int i = 0; i < ne; i++) { - TAssign(l.ind2(i), c, constants(T.attrib[i]-1)); + typename c_data_t::data_type ci; + for (int s = 0; s < vs; s++) + { + ci[s] = constants(T.attrib[i][s]-1); + } + TAssign(l.ind2(i), c, ci); } } }; @@ -243,12 +263,13 @@ public: /// Auxiliary class that is used to simplify the evaluation of a coefficient and /// scaling it by the weights of a quadrature rule. -template +template struct IntRuleCoefficient { static const int qpts = IR::qpts; - static const int ne = NE; + static const int ne = impl_traits_t::batch_size; typedef typename coeff_t::complex_type complex_type; + typedef typename impl_traits_t::vcomplex_t vcomplex_t; template struct Aux; @@ -256,7 +277,7 @@ struct IntRuleCoefficient template struct Aux { typedef struct { } result_t; - TMatrix cw; + TMatrix cw; inline MFEM_ALWAYS_INLINE Aux(const IR &int_rule, const coeff_t &c) { @@ -277,7 +298,7 @@ struct IntRuleCoefficient // non-constant coefficient template struct Aux { - typedef TMatrix result_t; + typedef TMatrix result_t; #ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP TMatrix w; #else @@ -312,7 +333,7 @@ struct IntRuleCoefficient } inline MFEM_ALWAYS_INLINE - const complex_type &get(const result_t &res, int i, int k) const + const vcomplex_t &get(const result_t &res, int i, int k) const { return res(i,k); } diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp index 810b50482b..4edceeb93c 100644 --- a/fem/teltrans.hpp +++ b/fem/teltrans.hpp @@ -64,9 +64,9 @@ public: // Templated struct Result, used to specify the type result that is computed // by the TElementTransformation::Eval() method and stored in this structure. // The template parameter EvalOps is a sum (bitwise or) of constants from - // the enum EvalOperations. The parameter NE is the number of elements to be - // processed in the Eval() method. - template struct Result; + // the enum EvalOperations. The type impl_traits_t specifies additional + // parameters and types to be used by the Eval() method. + template struct Result; static const int dim = Mesh_t::dim; static const int sdim = Mesh_t::space_dim; @@ -81,21 +81,21 @@ protected: ShapeEval evaluator; FESpace_type fes; nodeLayout_type node_layout; -#ifndef MFEM_USE_X86INTRIN const real_t *nodes; -#else - const double *nodes; -#endif const Element* const *elements; - template + template inline MFEM_ALWAYS_INLINE - void SetAttributes(int el, int (&attrib)[NE]) const + void SetAttributes(int el, vint_t (&attrib)[NE]) const { + const int vsize = sizeof(vint_t)/sizeof(attrib[0][0]); for (int i = 0; i < NE; i++) { - attrib[i] = elements[el+i]->GetAttribute(); + for (int j = 0; j < vsize; i++) + { + attrib[i][j] = elements[el+j+i*vsize]->GetAttribute(); + } } } @@ -110,25 +110,30 @@ public: { } // Evaluate coordinates and/or Jacobian matrices at quadrature points. - template + template inline MFEM_ALWAYS_INLINE - void Eval(int el, Result &F) + void Eval(int el, Result &F) { F.Eval(el, *this); } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE - template + template inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, const real_t *nodeData, Result &F) + void EvalSerialized(int el, const typename impl_traits_t::vreal_t *nodeData, + Result &F) { F.EvalSerialized(el, *this, nodeData); } #endif - template struct Result<0,NE> // 0 = EvalNone + // Specialization of the Result<> class + + // Case EvalOps = 0 = EvalNone + template struct Result<0,it_t> { - static const int ne = NE; + static const int ne = it_t::batch_size; + typedef typename it_t::vreal_t vreal_t; // x_type x; // Jt_type Jt; // int attrib[NE]; @@ -141,20 +146,23 @@ public: } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, T_type &T, const real_t *nodeData) { } + void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { } #endif }; - template struct Result<1,NE> // 1 = EvalCoordinates + + // Case EvalOps = 1 = EvalCoordinates + template struct Result<1,it_t> { - static const int ne = NE; + static const int ne = it_t::batch_size; + typedef typename it_t::vreal_t vreal_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES - typedef TTensor3 x_type; + typedef TTensor3 x_type; #else - typedef TTensor3 x_type; + typedef TTensor3 x_type; #endif x_type x; - - typedef TTensor3 nodes_dof_t; + + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -163,17 +171,13 @@ public: void Eval(int el, T_type &T) { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported"); + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); -#ifndef MFEM_USE_X86INTRIN T.fes.VectorExtract(T.node_layout, T.nodes, -#else - T.fes.VectorExtract(el, T.node_layout, T.nodes, -#endif nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, x.layout.merge_23(), x); @@ -181,25 +185,30 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, T_type &T, const real_t *nodeData) + void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { + const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]); + MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el); T.evaluator.Calc(nodes_dof_t::layout.merge_23(), - &nodeData[el*nodes_dof_t::size], + &nodeData[el/SS*nodes_dof_t::size], x.layout.merge_23(), x); } #endif }; - template struct Result<2,NE> // 2 = EvalJacobians + + // Case EvalOps = 2 = EvalJacobians + template struct Result<2,it_t> { - static const int ne = NE; + static const int ne = it_t::batch_size; + typedef typename it_t::vreal_t vreal_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #else - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -208,17 +217,13 @@ public: void Eval(int el, T_type &T) { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported"); + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); -#ifndef MFEM_USE_X86INTRIN T.fes.VectorExtract(T.node_layout, T.nodes, -#else - T.fes.VectorExtract(el,T.node_layout, T.nodes, -#endif nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -226,27 +231,32 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, T_type &T, const real_t *nodeData) + void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { + const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]); + MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el); T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(), - &nodeData[el*nodes_dof_t::size], + &nodeData[el/SS*nodes_dof_t::size], Jt.layout.merge_34(), Jt); } #endif }; - template struct Result<3,NE> // 3 = EvalCoordinates|EvalJacobians + + // Case EvalOps = 3 = EvalCoordinates|EvalJacobians + template struct Result<3,it_t> { - static const int ne = NE; - typedef TTensor3 x_type; + static const int ne = it_t::batch_size; + typedef typename it_t::vreal_t vreal_t; + typedef TTensor3 x_type; x_type x; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #else - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -255,17 +265,13 @@ public: void Eval(int el, T_type &T) { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported"); + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); -#ifndef MFEM_USE_X86INTRIN T.fes.VectorExtract(T.node_layout, T.nodes, -#else - T.fes.VectorExtract(el,T.node_layout, T.nodes, -#endif nodes_dof.layout, nodes_dof); T.evaluator.Calc(nodes_dof.layout.merge_23(), nodes_dof, x.layout.merge_23(), x); @@ -275,48 +281,50 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, T_type &T, const real_t *nodeData) + void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { + const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]); + MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el); T.evaluator.Calc(nodes_dof_t::layout.merge_23(), - &nodeData[el*nodes_dof_t::size], + &nodeData[el/SS*nodes_dof_t::size], x.layout.merge_23(), x); T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(), - &nodeData[el*nodes_dof_t::size], + &nodeData[el/SS*nodes_dof_t::size], Jt.layout.merge_34(), Jt); } #endif }; - template struct Result<6,NE> // 6 = EvalJacobians|LoadAttributes + + // Case EvalOps = 6 = EvalJacobians|LoadAttributes + template struct Result<6,it_t> { - static const int ne = NE; + static const int ne = it_t::batch_size; + typedef typename it_t::vreal_t vreal_t; + typedef typename it_t::vint_t vint_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #else - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif - int attrib[NE]; + vint_t attrib[ne]; inline MFEM_ALWAYS_INLINE void Eval(int el, T_type &T) { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported"); + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); -#ifndef MFEM_USE_X86INTRIN T.fes.VectorExtract(T.node_layout, T.nodes, -#else - T.fes.VectorExtract(el,T.node_layout, T.nodes, -#endif nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -325,26 +333,31 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, T_type &T, const real_t *nodeData) + void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { + const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]); + MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el); T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(), - &nodeData[el*nodes_dof_t::size], + &nodeData[el/SS*nodes_dof_t::size], Jt.layout.merge_34(), Jt); T.SetAttributes(el, attrib); } #endif }; - template struct Result<10,NE> // 10 = EvalJacobians|LoadElementIdxs + + // Case EvalOps = 10 = EvalJacobians|LoadElementIdxs + template struct Result<10,it_t> { - static const int ne = NE; + static const int ne = it_t::batch_size; + typedef typename it_t::vreal_t vreal_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #else - typedef TTensor4 Jt_type; + typedef TTensor4 Jt_type; #endif Jt_type Jt; - typedef TTensor3 nodes_dof_t; + typedef TTensor3 nodes_dof_t; #ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES nodes_dof_t nodes_dof; #endif @@ -354,17 +367,13 @@ public: void Eval(int el, T_type &T) { #ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS - MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported"); - TTensor3 &nodes_dof = T.nodes_dof; + MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported"); + TTensor3 &nodes_dof = T.nodes_dof; #elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES) nodes_dof_t nodes_dof; #endif T.fes.SetElement(el); -#ifndef MFEM_USE_X86INTRIN T.fes.VectorExtract(T.node_layout, T.nodes, -#else - T.fes.VectorExtract(el,T.node_layout, T.nodes, -#endif nodes_dof.layout, nodes_dof); T.evaluator.CalcGrad(nodes_dof.layout.merge_23(), nodes_dof, Jt.layout.merge_34(), Jt); @@ -373,10 +382,12 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE inline MFEM_ALWAYS_INLINE - void EvalSerialized(int el, T_type &T, const real_t *nodeData) + void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { + const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]); + MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el); T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(), - &nodeData[el*nodes_dof_t::size], + &nodeData[el/SS*nodes_dof_t::size], Jt.layout.merge_34(), Jt); first_elem_idx = el; } diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 049a20d9a5..987b3226b3 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -185,7 +185,8 @@ public: D_data_t &D_data) const { const int NC = qpt_layout_t::dim_4; - TTensor4 F; + typedef typename qpt_data_t::data_type entry_type; + TTensor4 F; for (int k = 0; k < NC; k++) { // Next loop performs a batch of matrix-matrix products of size @@ -353,8 +354,9 @@ public: const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { const int NC = dof_layout_t::dim_2; + typedef typename qpt_data_t::data_type entry_type; // DOF x DOF x NC --> NIP x DOF x NC --> NIP x NIP x NC - TTensor3 A; + TTensor3 A; // (1) A_{i,j,k} = \sum_s B_1d_{i,s} dof_data_{s,j,k} Mult_2_1(B_1d.layout, Dx ? G_1d : B_1d, @@ -385,8 +387,9 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { const int NC = dof_layout_t::dim_2; + typedef typename qpt_data_t::data_type entry_type; // NIP x NIP X NC --> NIP x DOF x NC --> DOF x DOF x NC - TTensor3 A; + TTensor3 A; // (1) A_{i,j,k} = \sum_s B_1d_{s,j} qpt_data_{i,s,k} Mult_1_2(B_1d.layout, Dy ? G_1d : B_1d, @@ -453,6 +456,7 @@ public: const M_layout_t &M_layout, M_data_t &M_data) const { const int NC = qpt_layout_t::dim_2; + typedef typename qpt_data_t::data_type entry_type; // Using TensorAssemble: --> @@ -469,7 +473,7 @@ public: TTensor3::layout, A, M_layout.merge_23().template split_12(), M_data); #elif 1 - TTensor4 A; + TTensor4 A; // qpt_data --> A TensorAssemble( Bt_1d.layout, Bt_1d, B_1d.layout, B_1d, @@ -517,7 +521,8 @@ public: D_data_t &D_data) const { const int NC = qpt_layout_t::dim_2; - TTensor4 A; + typedef typename qpt_data_t::data_type entry_type; + TTensor4 A; // Using TensorAssemble: --> @@ -531,7 +536,7 @@ public: TensorAssemble( Bt_1d.layout, D1 == 1 ? Bt_1d : Gt_1d, B_1d.layout, D2 == 1 ? B_1d : G_1d, - TTensor3::layout, A, + A.layout.merge_34(), A, D_layout.merge_23().template split_12(), D_data); } @@ -629,8 +634,9 @@ public: const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { const int NC = dof_layout_t::dim_2; - TVector QDD; - TVector QQD; + typedef typename qpt_data_t::data_type entry_type; + TVector QDD; + TVector QQD; // QDD_{i,jj,k} = \sum_s B_1d_{i,s} dof_data_{s,jj,k} Mult_2_1(B_1d.layout, Dx ? G_1d : B_1d, @@ -665,8 +671,9 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { const int NC = dof_layout_t::dim_2; - TVector QDD; - TVector QQD; + typedef typename qpt_data_t::data_type entry_type; + TVector QDD; + TVector QQD; // QQD_{ii,j,k} = \sum_s B_1d_{s,j} qpt_data_{ii,s,k} Mult_1_2(B_1d.layout, Dz ? G_1d : B_1d, @@ -743,8 +750,9 @@ public: const M_layout_t &M_layout, M_data_t &M_data) const { const int NC = qpt_layout_t::dim_2; - TTensor4 A1; - TTensor4 A2; + typedef typename qpt_data_t::data_type entry_type; + TTensor4 A1; + TTensor4 A2; // Using TensorAssemble: --> @@ -795,8 +803,9 @@ public: D_data_t &D_data) const { const int NC = qpt_layout_t::dim_2; - TTensor4 A1; - TTensor4 A2; + typedef typename qpt_data_t::data_type entry_type; + TTensor4 A1; + TTensor4 A2; // Using TensorAssemble: --> @@ -1005,24 +1014,15 @@ protected: using base_class::fespace; using base_class::shapeEval; using base_class::vec_layout; -#ifndef MFEM_USE_X86INTRIN const complex_t *data_in; complex_t *data_out; -#else - const double *data_in; // x86 complex_t - double *data_out; // x86 complex_t -#endif public: // With this constructor, fespace is a shallow copy of tfes. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FESpace_t &tfes, const ShapeEval_type &shape_eval, const VecLayout_type &vec_layout, -#ifndef MFEM_USE_X86INTRIN const complex_t *global_data_in, complex_t *global_data_out) -#else - const double *global_data_in, double *global_data_out) -#endif : base_class(tfes, shape_eval, vec_layout), data_in(global_data_in), data_out(global_data_out) @@ -1031,11 +1031,7 @@ public: // With this constructor, fespace is a shallow copy of f.fespace. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FieldEvaluator &f, -#ifndef MFEM_USE_X86INTRIN const complex_t *global_data_in, complex_t *global_data_out) -#else - const double *global_data_in, double *global_data_out) -#endif : base_class(f.fespace, f.shapeEval, f.vec_layout), data_in(global_data_in), data_out(global_data_out) @@ -1044,11 +1040,7 @@ public: // This constructor creates a new fespace, not a shallow copy. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FiniteElementSpace &fes, -#ifndef MFEM_USE_X86INTRIN const complex_t *global_data_in, complex_t *global_data_out) -#else - const double *global_data_in, double *global_data_out) -#endif : base_class(FE_type(*fes.FEColl()), fes), data_in(global_data_in), data_out(global_data_out) @@ -1072,13 +1064,9 @@ public: void GetValues(int el, const val_layout_t &l, val_data_t &vals) { const int ne = val_layout_t::dim_3; - TTensor3 val_dofs; + TTensor3 val_dofs; SetElement(el); -#ifndef MFEM_USE_X86INTRIN fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs); -#else - fespace.VectorExtract(el,vec_layout, data_in, val_dofs.layout, val_dofs); -#endif shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, l.merge_23(), vals); } @@ -1088,13 +1076,9 @@ public: void GetGradients(int el, const grad_layout_t &l, grad_data_t &grad) { const int ne = grad_layout_t::dim_4; - TTensor3 val_dofs; + TTensor3 val_dofs; SetElement(el); -#ifndef MFEM_USE_X86INTRIN fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs); -#else - fespace.VectorExtract(el,vec_layout, data_in, val_dofs.layout, val_dofs); -#endif shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, l.merge_34(), grad); } @@ -1119,19 +1103,11 @@ public: template inline MFEM_ALWAYS_INLINE -#ifndef MFEM_USE_X86INTRIN void Assemble(DataType &F) -#else - void AssembleOp(int el, DataType &F) -#endif { // T.SetElement() must be called outside Action:: -#ifndef MFEM_USE_X86INTRIN template Assemble(vec_layout, *this, F); -#else - template Assemble(el,vec_layout, *this, F); -#endif } template @@ -1139,24 +1115,22 @@ public: void Assemble(int el, DataType &F) { SetElement(el); -#ifndef MFEM_USE_X86INTRIN Assemble(F); -#else - AssembleOp(el,F); -#endif } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE template inline MFEM_ALWAYS_INLINE - void EvalSerialized(const complex_t *loc_dofs, DataType &F) + void EvalSerialized(const typename DataType::vcomplex_t *loc_dofs, + DataType &F) { Action::EvalSerialized(*this, loc_dofs, F); } template inline MFEM_ALWAYS_INLINE - void AssembleSerialized(const DataType &F, complex_t *loc_dofs) + void AssembleSerialized(const DataType &F, + typename DataType::vcomplex_t *loc_dofs) { Action:: template AssembleSerialized(*this, F, loc_dofs); @@ -1175,56 +1149,61 @@ public: // Auxiliary templated struct AData, used by the Eval() and Assemble() // methods. The template parameter IOData is "bitwise or" of constants from - // the enum InOutData. The parameter NE is the number of elements to be - // processed in the Eval() and Assemble() methods. - template struct AData; + // the enum InOutData. The type impl_traits_t specifies parameters and types + // to be used in the Eval() and Assemble() methods. + template struct AData; - template struct AData<0,NE> // 0 = None + template struct AData<0,it_t> // 0 = None { // Do we need this? }; - template struct AData<1,NE> // 1 = Values + template struct AData<1,it_t> // 1 = Values { + static const int ne = it_t::batch_size; + typedef typename it_t::vcomplex_t vcomplex_t; #ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; val_dofs_t val_dofs; #else - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; #endif - TTensor3 val_qpts; + TTensor3 val_qpts; }; - template struct AData<2,NE> // 2 = Gradients + template struct AData<2,it_t> // 2 = Gradients { + static const int ne = it_t::batch_size; + typedef typename it_t::vcomplex_t vcomplex_t; #ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; val_dofs_t val_dofs; #else - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; #endif - TTensor4 grad_qpts; + TTensor4 grad_qpts; }; - template struct AData<3,NE> // 3 = Values+Gradients + template struct AData<3,it_t> // 3 = Values+Gradients { + static const int ne = it_t::batch_size; + typedef typename it_t::vcomplex_t vcomplex_t; #ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; val_dofs_t val_dofs; #else - typedef TTensor3 val_dofs_t; + typedef TTensor3 val_dofs_t; #endif - TTensor3 val_qpts; - TTensor4 grad_qpts; + TTensor3 val_qpts; + TTensor4 grad_qpts; }; // This struct is similar to struct AData, adding separate static data // members for the input (InData) and output (OutData) data types. - template - struct BData : public AData + template + struct BData : public AData { typedef T_type eval_type; - static const int ne = NE; static const int InData = IData; static const int OutData = OData; }; @@ -1250,11 +1229,7 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif -#ifndef MFEM_USE_X86INTRIN T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); -#else - T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); -#endif T.shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); } @@ -1279,7 +1254,9 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE template static inline MFEM_ALWAYS_INLINE - void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D) + void EvalSerialized(T_type &T, + const typename AData_t::vcomplex_t *loc_dofs, + AData_t &D) { T.shapeEval.Calc(AData_t::val_dofs_t::layout.merge_23(), loc_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); @@ -1287,7 +1264,8 @@ public: template static inline MFEM_ALWAYS_INLINE - void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs) + void AssembleSerialized(T_type &T, const AData_t &D, + typename AData_t::vcomplex_t *loc_dofs) { T.shapeEval.template CalcT( D.val_qpts.layout.merge_23(), D.val_qpts, @@ -1307,22 +1285,14 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif -#ifndef MFEM_USE_X86INTRIN T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); -#else - T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); -#endif T.shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, D.grad_qpts.layout.merge_34(), D.grad_qpts); } template static inline MFEM_ALWAYS_INLINE -#ifndef MFEM_USE_X86INTRIN void Assemble(const vec_layout_t &l, T_type &T, AData_t &D) -#else - void Assemble(int el, const vec_layout_t &l, T_type &T, AData_t &D) -#endif { const AssignOp::Type Op = Add ? AssignOp::Add : AssignOp::Set; #ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS @@ -1333,18 +1303,16 @@ public: T.shapeEval.template CalcGradT( D.grad_qpts.layout.merge_34(), D.grad_qpts, val_dofs.layout.merge_23(), val_dofs); -#ifndef MFEM_USE_X86INTRIN T.fespace.template VectorAssemble( -#else - T.fespace.template VectorAssemble(el, -#endif val_dofs.layout, val_dofs, l, T.data_out); } #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE template static inline MFEM_ALWAYS_INLINE - void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D) + void EvalSerialized(T_type &T, + const typename AData_t::vcomplex_t *loc_dofs, + AData_t &D) { T.shapeEval.CalcGrad(AData_t::val_dofs_t::layout.merge_23(), loc_dofs, D.grad_qpts.layout.merge_34(), D.grad_qpts); @@ -1352,7 +1320,8 @@ public: template static inline MFEM_ALWAYS_INLINE - void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs) + void AssembleSerialized(T_type &T, const AData_t &D, + typename AData_t::vcomplex_t *loc_dofs) { T.shapeEval.template CalcGradT( D.grad_qpts.layout.merge_34(), D.grad_qpts, @@ -1372,11 +1341,7 @@ public: #else typename AData_t::val_dofs_t val_dofs; #endif -#ifndef MFEM_USE_X86INTRIN T.fespace.VectorExtract(l, T.data_in, val_dofs.layout, val_dofs); -#else - T.fespace.VectorExtract(0,l, T.data_in, val_dofs.layout, val_dofs); -#endif T.shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); T.shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs, @@ -1406,7 +1371,9 @@ public: #ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE template static inline MFEM_ALWAYS_INLINE - void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D) + void EvalSerialized(T_type &T, + const typename AData_t::vcomplex_t *loc_dofs, + AData_t &D) { T.shapeEval.Calc(AData_t::val_dofs_t::layout.merge_23(), loc_dofs, D.val_qpts.layout.merge_23(), D.val_qpts); @@ -1416,7 +1383,8 @@ public: template static inline MFEM_ALWAYS_INLINE - void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs) + void AssembleSerialized(T_type &T, const AData_t &D, + typename AData_t::vcomplex_t *loc_dofs) { T.shapeEval.template CalcT( D.val_qpts.layout.merge_23(), D.val_qpts, @@ -1430,28 +1398,29 @@ public: // This struct implements element matrix computation for some combinations // of input (InOps) and output (OutOps) operations. - template struct TElementMatrix; + template struct TElementMatrix; - template struct TElementMatrix<1,1,NE> // 1,1 = Values,Values + // Case 1,1 = Values,Values + template struct TElementMatrix<1,1,it_t> { // qpt_layout_t is (nip), M_layout_t is (dof x dof) - // NE = 1 is assumed + // it_t::batch_size = 1 is assumed template static inline MFEM_ALWAYS_INLINE void Compute(const qpt_layout_t &a, const qpt_data_t &A, const M_layout_t &m, M_data_t &M, ShapeEval_type &ev) { - assert(false); ev.Assemble(a.template split_1(), A, m.template split_2(), M); } }; - template struct TElementMatrix<2,2,NE> // 2,2 = Gradients,Gradients + // Case 2,2 = Gradients,Gradients + template struct TElementMatrix<2,2,it_t> { // qpt_layout_t is (nip x dim x dim), M_layout_t is (dof x dof) - // NE = 1 is assumed + // it_t::batch_size = 1 is assumed template static inline MFEM_ALWAYS_INLINE @@ -1463,15 +1432,15 @@ public: } }; - template struct Spec + template struct Spec { static const int InData = Values*kernel_t::in_values + Gradients*kernel_t::in_gradients; static const int OutData = Values*kernel_t::out_values + Gradients*kernel_t::out_gradients; - typedef BData DataType; - typedef TElementMatrix ElementMatrix; + typedef BData DataType; + typedef TElementMatrix ElementMatrix; }; }; diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index d40689b85b..a24bebeef3 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -63,15 +63,7 @@ public: else { // reorder the local dofs according to loc_dof_map -#ifndef MFEM_USE_X86INTRIN int *el_dof_list_ = new int[num_dofs]; -#else - //const int aligned_size = MFEM_ALIGN_SIZE(num_dofs,int); - void* result = nullptr; - const auto alloc_failed = posix_memalign(&result, 32, 2*num_dofs*sizeof(int)); - if (alloc_failed) throw ::std::bad_alloc(); - int *el_dof_list_ = (int*) result; -#endif const int *loc_dof_map_ = loc_dof_map->GetData(); for (int i = 0; i < el_dof.Size(); i++) { @@ -98,20 +90,14 @@ public: { } inline MFEM_ALWAYS_INLINE - ~ElementDofIndexer() { -#ifndef MFEM_USE_X86INTRIN - if (own_list) { delete [] el_dof_list; } -#else - if (own_list) { free((void*)el_dof_list); } -#endif - } + ~ElementDofIndexer() { if (own_list) { delete [] el_dof_list; } } inline MFEM_ALWAYS_INLINE void SetElement(int elem_idx) { loc_dof_list = el_dof_list + elem_idx * FE::dofs; } - + inline MFEM_ALWAYS_INLINE int map(int loc_dof_idx, int elem_offset) const { @@ -131,15 +117,19 @@ public: protected: index_type ind; + int num_elems, remain_elems; public: TFiniteElementSpace_simple(const FE &fe, const FiniteElementSpace &fes) - : ind(fe, fes) { } + : ind(fe, fes), num_elems(fes.GetNE()), remain_elems(num_elems) { } // default copy constructor - void SetElement(int el) { ind.SetElement(el); } + int GetNE() const { return num_elems; } + void SetElement(int el) { ind.SetElement(el); remain_elems = num_elems-el; } + +#if 0 // Multi-element Extract: // Extract dofs for multiple elements starting with the current element. // The number of elements to extract is given by the second dimension of @@ -151,6 +141,7 @@ public: const dof_layout_t &dof_layout, dof_data_t &dof_data) const { + const int SS = sizeof(dof_data[0])/sizeof(dof_data[0][0]); const int NE = dof_layout_t::dim_2; MFEM_STATIC_ASSERT(FE::dofs == dof_layout_t::dim_1, "invalid number of dofs"); @@ -158,8 +149,11 @@ public: { for (int i = 0; i < FE::dofs; i++) { - Assign(dof_data[dof_layout.ind(i,j)], - glob_dof_data[ind.map(i,j)]); + for (int s = 0; s < SS; s++) + { + Assign(dof_data[dof_layout.ind(i,j)][s], + glob_dof_data[ind.map(i,s+SS*j)]); + } } } } @@ -183,6 +177,7 @@ public: const dof_data_t &dof_data, glob_dof_data_t &glob_dof_data) const { + const int SS = sizeof(dof_data[0])/sizeof(dof_data[0][0]); const int NE = dof_layout_t::dim_2; MFEM_STATIC_ASSERT(FE::dofs == dof_layout_t::dim_1, "invalid number of dofs"); @@ -190,8 +185,11 @@ public: { for (int i = 0; i < FE::dofs; i++) { - Assign(glob_dof_data[ind.map(i,j)], - dof_data[dof_layout.ind(i,j)]); + for (int s = 0; s < SS; s++) + { + Assign(glob_dof_data[ind.map(i,s+SS*j)], + dof_data[dof_layout.ind(i,j)][s]); + } } } } @@ -205,9 +203,9 @@ public: { Assemble(dof_layout, dof_data, glob_dof_data); } +#endif // Multi-element VectorExtract: vdof_layout is (DOFS x NumComp x NumElems). -#ifndef MFEM_USE_X86INTRIN template @@ -217,59 +215,42 @@ public: const vdof_layout_t &vdof_layout, vdof_data_t &vdof_data) const { + const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]); const int NC = vdof_layout_t::dim_2; const int NE = vdof_layout_t::dim_3; MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, "invalid number of dofs"); MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); + const int TE = std::min(SS*NE, remain_elems); + // const int TE = SS*NE; for (int k = 0; k < NC; k++) { +#if 0 for (int j = 0; j < NE; j++) { for (int i = 0; i < FE::dofs; i++) { - Assign(vdof_data[vdof_layout.ind(i,k,j)], - glob_vdof_data[vl.ind(ind.map(i,j), k)]); + for (int s = 0; s < SS; s++) + { + Assign(vdof_data[vdof_layout.ind(i,k,j)][s], + glob_vdof_data[vl.ind(ind.map(i,s+SS*j), k)]); + } } } - } - } #else - template - inline MFEM_ALWAYS_INLINE - void VectorExtract(const int el, - const vec_layout_t &vl, - const glob_vdof_data_t &glob_vdof_data, - const vdof_layout_t &vdof_layout, - vdof_data_t &vdof_data) /*const*/ - { - const int NC = vdof_layout_t::dim_2; - const int NE = vdof_layout_t::dim_3; - MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, - "invalid number of dofs"); - MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); - x86::vreal_t gather; - for (int k = 0; k < NC; k++) - { - for (int j = 0; j < NE; j++) + for (int js = 0; js < TE; js++) { for (int i = 0; i < FE::dofs; i++) { - for(int n=0; n(vdof_data[vdof_layout.ind(i,k,j)],gather); + const int s = js % SS, j = js / SS; + Assign(vdof_data[vdof_layout.ind(i,k,j)][s], + glob_vdof_data[vl.ind(ind.map(i,js), k)]); } } +#endif } } -#endif -#ifndef MFEM_USE_X86INTRIN template inline MFEM_ALWAYS_INLINE @@ -291,21 +272,39 @@ public: const vec_layout_t &vl, glob_vdof_data_t &glob_vdof_data) const { + const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]); const int NC = vdof_layout_t::dim_2; const int NE = vdof_layout_t::dim_3; MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, "invalid number of dofs"); MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); + const int TE = std::min(SS*NE, remain_elems); + // const int TE = SS*NE; for (int k = 0; k < NC; k++) { +#if 0 for (int j = 0; j < NE; j++) { for (int i = 0; i < FE::dofs; i++) { - Assign(glob_vdof_data[vl.ind(ind.map(i,j), k)], - vdof_data[vdof_layout.ind(i,k,j)]); + for (int s = 0; s < SS; s++) + { + Assign(glob_vdof_data[vl.ind(ind.map(i,s+SS*j), k)], + vdof_data[vdof_layout.ind(i,k,j)][s]); + } } } +#else + for (int js = 0; js < TE; js++) + { + for (int i = 0; i < FE::dofs; i++) + { + const int s = js % SS, j = js / SS; + Assign(glob_vdof_data[vl.ind(ind.map(i,js), k)], + vdof_data[vdof_layout.ind(i,k,j)][s]); + } + } +#endif } } @@ -319,64 +318,6 @@ public: { VectorAssemble(vdof_layout, vdof_data, vl, glob_vdof_data); } -#else - template - inline MFEM_ALWAYS_INLINE - void VectorExtract(const int el, - const vec_layout_t &vl, - const glob_vdof_data_t &glob_vdof_data, - const vdof_layout_t &vdof_layout, - vdof_data_t &vdof_data) /*const*/ - { - VectorExtract(el,vl, glob_vdof_data, vdof_layout, vdof_data); - } - - // Multi-element VectorAssemble: vdof_layout is (DOFS x NumComp x NumElems). - template - inline MFEM_ALWAYS_INLINE - void VectorAssemble(const int el, - const vdof_layout_t &vdof_layout, - const vdof_data_t &vdof_data, - const vec_layout_t &vl, - glob_vdof_data_t &glob_vdof_data) //const - { - const int NC = vdof_layout_t::dim_2; - const int NE = vdof_layout_t::dim_3; - MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, - "invalid number of dofs"); - MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components"); - for (int k = 0; k < NC; k++) - { - for (int j = 0; j < NE; j++) - { - for (int i = 0; i < FE::dofs; i++) - { - for(int n=0; n(glob_vdof_data[vl.ind(ind.map(i,j), k)], - vdof_data[vdof_layout.ind(i,k,j)][n]); - } - } - } - } - } - - template - inline MFEM_ALWAYS_INLINE - void VectorAssemble(const int el, - const vdof_layout_t &vdof_layout, - const vdof_data_t &vdof_data, - const vec_layout_t &vl, - glob_vdof_data_t &glob_vdof_data) const - { - VectorAssemble(el,vdof_layout, vdof_data, vl, glob_vdof_data); - } -#endif // Extract a static number of consecutive components; vdof_layout is // (dofs x NC x NE), where NC is the number of components to extract. It is @@ -390,21 +331,24 @@ public: const vdof_layout_t &vdof_layout, vdof_data_t &vdof_data) const { + const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]); const int NC = vdof_layout_t::dim_2; const int NE = vdof_layout_t::dim_3; + const int TE = std::min(SS*NE, remain_elems); MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, "invalid number of dofs"); MFEM_ASSERT(first_comp + NC <= vl.NumComponents(), "invalid number of components"); for (int k = 0; k < NC; k++) { - for (int j = 0; j < NE; j++) + for (int js = 0; js < TE; js++) { for (int i = 0; i < FE::dofs; i++) { + const int s = js % SS, j = js / SS; Assign( - vdof_data[vdof_layout.ind(i,k,j)], - glob_vdof_data[vl.ind(ind.map(i,j), first_comp+k)]); + vdof_data[vdof_layout.ind(i,k,j)][s], + glob_vdof_data[vl.ind(ind.map(i,js), first_comp+k)]); } } } @@ -422,55 +366,69 @@ public: const vec_layout_t &vl, glob_vdof_data_t &glob_vdof_data) const { + const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]); const int NC = vdof_layout_t::dim_2; const int NE = vdof_layout_t::dim_3; + const int TE = std::min(SS*NE, remain_elems); MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1, "invalid number of dofs"); MFEM_ASSERT(first_comp + NC <= vl.NumComponents(), "invalid number of components"); for (int k = 0; k < NC; k++) { - for (int j = 0; j < NE; j++) + for (int js = 0; js < TE; js++) { for (int i = 0; i < FE::dofs; i++) { + const int s = js % SS, j = js / SS; Assign( - glob_vdof_data[vl.ind(ind.map(i,j), first_comp+k)], - vdof_data[vdof_layout.ind(i,k,j)]); + glob_vdof_data[vl.ind(ind.map(i,js), first_comp+k)], + vdof_data[vdof_layout.ind(i,k,j)][s]); } } } } - void Assemble(const TMatrix &m, + template + void Assemble(const TMatrix &m, SparseMatrix &M) const { + const int SS = sizeof(m[0])/sizeof(m[0][0]); + const int TE = std::min(SS, remain_elems); MFEM_FLOPS_ADD(FE::dofs*FE::dofs); - for (int i = 0; i < FE::dofs; i++) + for (int s = 0; s < TE; s++) { - M.SetColPtr(ind.map(i,0)); - for (int j = 0; j < FE::dofs; j++) + for (int i = 0; i < FE::dofs; i++) { - M._Add_(ind.map(j,0), m(i,j)); + M.SetColPtr(ind.map(i,s)); + for (int j = 0; j < FE::dofs; j++) + { + M._Add_(ind.map(j,s), m(i,j)[s]); + } + M.ClearColPtr(); } - M.ClearColPtr(); } } - template + template void AssembleBlock(int block_i, int block_j, const vec_layout_t &vl, - const TMatrix &m, + const TMatrix &m, SparseMatrix &M) const { + const int SS = sizeof(m[0])/sizeof(m[0][0]); + const int TE = std::min(SS, remain_elems); MFEM_FLOPS_ADD(FE::dofs*FE::dofs); - for (int i = 0; i < FE::dofs; i++) + for (int s = 0; s < TE; s++) { - M.SetColPtr(vl.ind(ind.map(i,0), block_i)); - for (int j = 0; j < FE::dofs; j++) + for (int i = 0; i < FE::dofs; i++) { - M._Add_(vl.ind(ind.map(j,0), block_j), m(i,j)); + M.SetColPtr(vl.ind(ind.map(i,s), block_i)); + for (int j = 0; j < FE::dofs; j++) + { + M._Add_(vl.ind(ind.map(j,s), block_j), m(i,j)[s]); + } + M.ClearColPtr(); } - M.ClearColPtr(); } } }; diff --git a/fem/tintrules.hpp b/fem/tintrules.hpp index d460a1eeb7..0f9464f983 100644 --- a/fem/tintrules.hpp +++ b/fem/tintrules.hpp @@ -142,7 +142,7 @@ template class TProductIntegrationRule_base<3,Q,real_t> { protected: - TVector weights_1d; + TVector weights_1d; public: // Multi-component weight assignment. qpt_layout_t must be (qpts x n1 x ...) diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index bf3b7309e7..d480b7454c 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -1975,18 +1975,6 @@ void SparseMatrix::Jacobi3(const Vector &b, const Vector &x0, Vector &x1, } } -#ifdef MFEM_USE_X86INTRIN -void SparseMatrix::AddSubMatrix(const Array &idx, - const TDenseMatrix &subm){ - for (int i = 0; i < idx.Size(); i++){ - SetColPtr(idx[i]); - for (int j = 0; j < idx.Size(); j++){ - _Add_(idx[j],subm(i,j)); - } - } -} -#endif - void SparseMatrix::AddSubMatrix(const Array &rows, const Array &cols, const DenseMatrix &subm, int skip_zeros) { diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index 686bce96b7..da99115a37 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -19,10 +19,6 @@ #include "../general/globals.hpp" #include "densemat.hpp" -#ifdef MFEM_USE_X86INTRIN -#include "tdensemat.hpp" -#endif - namespace mfem { @@ -331,12 +327,6 @@ public: { SearchRow(col) = a; } inline double _Get_(const int col) const; -#ifdef MFEM_USE_X86INTRIN - inline void SetColPtr(const x86::vint_t row) const; - inline void SearchRow(const x86::vint_t col, const x86::vreal_t a); - inline void _Add_(const x86::vint_t col, const x86::vreal_t a){ SearchRow(col,a);} -#endif - inline double &SearchRow(const int row, const int col); inline void _Add_(const int row, const int col, const double a) { SearchRow(row, col) += a; } @@ -354,10 +344,6 @@ public: void AddSubMatrix(const Array &rows, const Array &cols, const DenseMatrix &subm, int skip_zeros = 1); -#ifdef MFEM_USE_X86INTRIN - void AddSubMatrix(const Array &idx, - const TDenseMatrix &subm); -#endif bool RowIsEmpty(const int row) const; @@ -501,39 +487,8 @@ SparseMatrix * Add(double a, const SparseMatrix & A, double b, SparseMatrix * Add(Array & Ai); -#ifdef MFEM_USE_X86INTRIN // Inline methods -// **************************************************************************** -// * SetColPtr - gather -// **************************************************************************** -inline void SparseMatrix::SetColPtr(const x86::vint_t row) const{ - if (ColPtrJ == NULL){ - ColPtrJ = new int[width*x86::width]; - for (int i = 0; i < width; i++) - for(int k = 0;k -#include -#include -#include -#include - -namespace mfem{ - -/// Data type dense matrix using column-major storage -template -class TDenseMatrix : public Matrix{ -private: - data_t *data; - int capacity; // zero or negative capacity means we do not own the data. -public: - - /// Creates rectangular matrix of size m x n. - TDenseMatrix(int m, int n) : Matrix(m, n){ - std::cout<<"[TDenseMatrix]"<= 0 && n >= 0, - "invalid TDenseMatrix size: " << m << " x " << n); - capacity = m*n; - MFEM_ASSERT(capacity>0,"invalid TDenseMatrix capacity"); -#ifndef MFEM_USE_X86INTRIN - data = new data_t[capacity](); -#else - data = (data_t*)aligned_alloc(x86::align,capacity*sizeof(data_t)); -#endif - } - - TDenseMatrix(data_t *d, int h, int w) : Matrix(h, w) - { data = d; capacity = -h*w; } - - /// Returns reference to a_{ij}. - inline data_t &operator()(int i, int j){ - MFEM_ASSERT(data && i >= 0 && i < height && j >= 0 && j < width, ""); - return data[i+j*height]; - } - /// Returns constant reference to a_{ij}. - inline const data_t &operator()(int i, int j) const{ - MFEM_ASSERT(data && i >= 0 && i < height && j >= 0 && j < width, ""); - return data[i+j*height]; - } - - inline DenseMatrix &simd(DenseMatrix &D, int k) const{ - for (int i = 0; i < height; i++) - for (int j = 0; j < width; j++) - D(i,j)=(*this)(i,j)[k]; - return D; - } - - double &Elem(int i, int j){ - MFEM_ASSERT(false,"Elem SIMD HACK"); - return (*this)(i,j)[0]; // SIMD HACK - } - - /// Returns reference to a_{ij}. - const double &Elem(int i, int j) const { - MFEM_ASSERT(false,"Elem not implemented"); - return (*this)(i,j)[0]; - } - - void Mult(const Vector &x, Vector &y) const { - MFEM_ASSERT(false,"Mult not implemented"); - } - - virtual MatrixInverse *Inverse() const { - MFEM_ASSERT(false,"Inverse not implemented"); - return NULL; - } - - /** Copy the m x n submatrix of A at row/col offsets Aro/Aco to *this at - row_offset, col_offset */ - void CopyMN(const TDenseMatrix &A, - int m, int n, int Aro, int Aco, - int row_offset, int col_offset){} - - /// Destroys dense matrix. - ~TDenseMatrix(){} - - void Print(int k,std::ostream &out = std::cout, int width_ = 4) const{ - std::ios::fmtflags old_flags = out.flags(); - // output flags = scientific + show sign - out << setiosflags(std::ios::scientific | std::ios::showpos); - for (int i = 0; i < height; i++){ - out << "[row " << i << "]\n"; - for (int j = 0; j < width; j++){ - out << (*this)(i,j)[k]; - if (j+1 == width || (j+1) % width_ == 0){ - out << '\n'; - }else{ - out << ' '; - } - } - } - // reset output flags to original values - out.flags(old_flags); - } - -}; - -} // namespace mfem - -#endif diff --git a/linalg/tmatrix.hpp b/linalg/tmatrix.hpp index 596ba59039..68eeb99b26 100644 --- a/linalg/tmatrix.hpp +++ b/linalg/tmatrix.hpp @@ -20,6 +20,18 @@ namespace mfem // Matrix-matrix products +namespace internal +{ + +template struct entry_type +{ typedef typename T::data_type type; }; + +template struct entry_type +{ typedef T type; }; + +} // namespace mfem::internal + + // C {=|+=} A.B -- simple version (no blocks) template ::type c_a1_b2; + if (Add) { - if (!Add && s == 0) - { - // C(a1,b2) = A(a1,s) * B(s,b2); - C_data[C_layout.ind(a1,b2)] = - A_data[A_layout.ind(a1,s)] * B_data[B_layout.ind(s,b2)]; - } - else - { - // C(a1,b2) += A(a1,s) * B(s,b2); - C_data[C_layout.ind(a1,b2)] += - A_data[A_layout.ind(a1,s)] * B_data[B_layout.ind(s,b2)]; - } + // C(a1,b2) += A(a1,0) * B(0,b2); + c_a1_b2 = C_data[C_layout.ind(a1,b2)]; + c_a1_b2.fma(A_data[A_layout.ind(a1,0)], B_data[B_layout.ind(0,b2)]); } + else + { + // C(a1,b2) = A(a1,0) * B(0,b2); + c_a1_b2.mul(A_data[A_layout.ind(a1,0)], B_data[B_layout.ind(0,b2)]); + } + for (int s = 1; s < A2; s++) + { + // C(a1,b2) += A(a1,s) * B(s,b2); + c_a1_b2.fma(A_data[A_layout.ind(a1,s)], B_data[B_layout.ind(s,b2)]); + } + C_data[C_layout.ind(a1,b2)] = c_a1_b2; } } } diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index 6b1865593e..cfab39cd63 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -16,7 +16,6 @@ #include "../general/tassign.hpp" #include "tlayout.hpp" #include "tmatrix.hpp" -#include // Templated tensor implementation (up to order 4) @@ -244,11 +243,9 @@ template struct TVector { public: - //TVector(){assert(align);} static const int size = S; static const int aligned_size = align ? MFEM_ALIGN_SIZE(S,data_t) : size; typedef data_t data_type; - data_t data[aligned_size>0?aligned_size:1]; typedef StridedLayout1D layout_type; diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index c3b9ffc2fc..417e9f8d6f 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -27,7 +27,11 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") "-std=c++11" "-pedantic" "-Wall" - "--param" "max-completely-peel-times=3") +# "--param" "max-completely-peel-times=3" + ) +elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") + list(APPEND PERFORMANCE_CXX_OPTIONS + "-xHost") endif() add_mfem_miniapp(performance_ex1 diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index e2baf5d224..ccfc61d371 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -53,24 +53,12 @@ typedef H1_FiniteElement sol_fe_t; typedef H1_FiniteElementSpace sol_fes_t; // Static quadrature, coefficient and integrator types -#ifdef MFEM_USE_X86INTRIN -typedef TIntegrationRule int_rule_t; -typedef TConstantCoefficient coeff_t; -#else typedef TIntegrationRule int_rule_t; typedef TConstantCoefficient<> coeff_t; -#endif typedef TIntegrator integ_t; // Static bilinear form type, combining the above types -#ifdef MFEM_USE_X86INTRIN -typedef TBilinearForm HPCBilinearForm; -#else typedef TBilinearForm HPCBilinearForm; -#endif int main(int argc, char *argv[]) { @@ -357,6 +345,8 @@ int main(int argc, char *argv[]) cout << " done, " << tic_toc.RealTime() << "s." << endl; // Solve with CG or PCG, depending if the matrix A_pc is available + tic_toc.Clear(); + tic_toc.Start(); if (pc_choice != NONE) { GSSmoother M(A_pc); @@ -366,6 +356,8 @@ int main(int argc, char *argv[]) { CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); } + tic_toc.Stop(); + cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; // 13. Recover the solution as a finite element grid function. if (perf && matrix_free) diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index d53321a20e..f5ff386523 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -24,7 +24,7 @@ MFEM_LIB_FILE = mfem_is_not_built # Distinguish x86 from PowerPC systems MFEM_MACHINE ?= $(shell uname -m) -# Choose the switch MFEM_PERF_SW: gcc_x86_64, gcc_ppc64, or clang. +# Choose the switch MFEM_PERF_SW: gcc_x86_64, gcc_ppc64, clang, or icc. # The value of MFEM_PERF_SW is used to select MFEM_PERF_CXXFLAGS below. ifneq (,$(MFEM_PERF_SW)) # Use the value of MFEM_PERF_SW if already defined @@ -36,6 +36,8 @@ else ifneq (,$(filter %g++ %mpicxx %mpic++,$(MFEM_CXX))) else ifneq (,$(findstring ppc64,$(MFEM_MACHINE))) MFEM_PERF_SW = gcc_ppc64 endif +else ifneq (,$(filter %icpc %mpiicpc,$(MFEM_CXX))) + MFEM_PERF_SW = icc endif # Compiler specific optimizations. @@ -45,8 +47,8 @@ endif # MFEM_PERF_CXXFLAGS_gcc_common += -std=c++03 MFEM_PERF_CXXFLAGS_gcc_common += -std=c++11 MFEM_PERF_CXXFLAGS_gcc_common += -pedantic -Wall -MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 -# MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks +# MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 +MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) @@ -62,6 +64,11 @@ MFEM_PERF_CXXFLAGS_clang += -fslp-vectorize MFEM_PERF_CXXFLAGS_clang += -fslp-vectorize-aggressive MFEM_PERF_CXXFLAGS_clang += -ffp-contract=fast +# - Intel C++ compiler extra options: +MFEM_PERF_CXXFLAGS_icc += -xHost +# MFEM_PERF_CXXFLAGS_icc += -std=c++03 +MFEM_PERF_CXXFLAGS_icc += -std=c++11 + # Choose MFEM_PERF_CXXFLAGS based on MFEM_PERF_SW: MFEM_PERF_CXXFLAGS = $(MFEM_PERF_CXXFLAGS_$(MFEM_PERF_SW)) # Add MFEM_PERF_CXXFLAGS to MFEM_CXXFLAGS: From eff37321d95d1b69de2fbb0d67270a48f00440b0 Mon Sep 17 00:00:00 2001 From: camierjs Date: Fri, 15 Jun 2018 19:26:33 -0700 Subject: [PATCH 008/535] [simd] auto working with posix_memalign --- config/simd/auto.hpp | 232 ++++++++++++++++ general/x86_m128.hpp => config/simd/m128.hpp | 0 general/x86_m256.hpp => config/simd/m256.hpp | 2 - general/x86_m512.hpp => config/simd/m512.hpp | 0 general/x86_m64.hpp => config/simd/m64.hpp | 0 general/x86intrin.hpp => config/simd/x86.hpp | 10 +- config/tconfig.hpp | 274 +++---------------- fem/tbilinearform.hpp | 10 +- miniapps/performance/makefile | 4 +- 9 files changed, 279 insertions(+), 253 deletions(-) create mode 100644 config/simd/auto.hpp rename general/x86_m128.hpp => config/simd/m128.hpp (100%) rename general/x86_m256.hpp => config/simd/m256.hpp (99%) rename general/x86_m512.hpp => config/simd/m512.hpp (100%) rename general/x86_m64.hpp => config/simd/m64.hpp (100%) rename general/x86intrin.hpp => config/simd/x86.hpp (97%) diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp new file mode 100644 index 0000000000..5a77455f59 --- /dev/null +++ b/config/simd/auto.hpp @@ -0,0 +1,232 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_AUTO +#define MFEM_TEMPLATE_CONFIG_SIMD_AUTO + +template +struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = S; + static const int align_size = align_S; + + scalar_t vec[size]; + + scalar_t &operator[](int i) { return vec[i]; } + const scalar_t &operator[](int i) const { return vec[i]; } + + AutoSIMD &operator=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = v[i]; } + return *this; + } + AutoSIMD &operator=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = e; } + return *this; + } + AutoSIMD &operator+=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += v[i]; } + return *this; + } + AutoSIMD &operator+=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += e; } + return *this; + } + AutoSIMD &operator-=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] -= v[i]; } + return *this; + } + AutoSIMD &operator-=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] -= e; } + return *this; + } + AutoSIMD &operator*=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] *= v[i]; } + return *this; + } + AutoSIMD &operator*=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] *= e; } + return *this; + } + AutoSIMD &operator/=(const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] /= v[i]; } + return *this; + } + AutoSIMD &operator/=(const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] /= e; } + return *this; + } + + AutoSIMD operator-() const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = -vec[i]; } + return r; + } + + AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] + v[i]; } + return r; + } + AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] + e; } + return r; + } + AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] - v[i]; } + return r; + } + AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] - e; } + return r; + } + AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] * v[i]; } + return r; + } + AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] * e; } + return r; + } + AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] / v[i]; } + return r; + } + AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { r[i] = vec[i] / e; } + return r; + } + + AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += v[i] * w[i]; } + return *this; + } + AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } + return *this; + } + AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] += e * v[i]; } + return *this; + } + + AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = v[i] * w[i]; } + return *this; + } + AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } + return *this; + } + AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + MFEM_VECTORIZE_LOOP + for (int i = 0; i < size; i++) { vec[i] = e * v[i]; } + return *this; + } +}; + +template +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e + v[i]; } + return r; +} + +template +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e - v[i]; } + return r; +} + +template +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e * v[i]; } + return r; +} + +template +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + for (int i = 0; i < S; i++) { r[i] = e / v[i]; } + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_AUTO diff --git a/general/x86_m128.hpp b/config/simd/m128.hpp similarity index 100% rename from general/x86_m128.hpp rename to config/simd/m128.hpp diff --git a/general/x86_m256.hpp b/config/simd/m256.hpp similarity index 99% rename from general/x86_m256.hpp rename to config/simd/m256.hpp index ae05260172..7412c9f2f3 100644 --- a/general/x86_m256.hpp +++ b/config/simd/m256.hpp @@ -45,8 +45,6 @@ public: // **************************************************************************** // * AVX real type class -// * error 0x81e350 -// * ok with: 0x81e020 // **************************************************************************** struct __attribute__ ((aligned(32))) real { protected: diff --git a/general/x86_m512.hpp b/config/simd/m512.hpp similarity index 100% rename from general/x86_m512.hpp rename to config/simd/m512.hpp diff --git a/general/x86_m64.hpp b/config/simd/m64.hpp similarity index 100% rename from general/x86_m64.hpp rename to config/simd/m64.hpp diff --git a/general/x86intrin.hpp b/config/simd/x86.hpp similarity index 97% rename from general/x86intrin.hpp rename to config/simd/x86.hpp index 05d7b3bf68..a54c34942b 100644 --- a/general/x86intrin.hpp +++ b/config/simd/x86.hpp @@ -44,7 +44,7 @@ template struct x86intrin; // * AVX512 (-mavx512f) // **************************************************************************** #if __SIMD__==4 -#include "x86_m512.hpp" +#include "x86/m512.hpp" #define MFEM_SIMD_SIZE 64 #pragma message "X86intrin::AVX512" template <> struct x86intrin<4>{ @@ -62,7 +62,7 @@ public: // * AVX2 (-mavx2) // **************************************************************************** #if __SIMD__==3 -#include "x86_m256.hpp" +#include "x86/m256.hpp" #pragma message "X86intrin::AVX2" template <> struct x86intrin<3>{ public: @@ -80,7 +80,7 @@ public: // **************************************************************************** #if __SIMD__==2 #pragma message "X86intrin::AVX" -#include "x86_m256.hpp" +#include "x86/m256.hpp" template <> struct x86intrin<2>{ public: static const int align = 32; @@ -96,7 +96,7 @@ public: // * SSE (-mno-avx) // **************************************************************************** #if __SIMD__==1 -#include "x86_m128.hpp" +#include "x86/m128.hpp" #pragma message "X86intrin::SSE" template <> struct x86intrin<1>{ public: @@ -113,7 +113,7 @@ public: // * 'SCALAR' (-mno-sse2) // **************************************************************************** #if __SIMD__==0 -#include "x86_m64.hpp" +#include "x86/m64.hpp" #pragma message "X86intrin::STD" template <> struct x86intrin<0>{ public: diff --git a/config/tconfig.hpp b/config/tconfig.hpp index c60092ffce..c854ea5f96 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -37,15 +37,7 @@ #define MFEM_VECTORIZE_LOOP #endif -#define MFEM_TEMPLATE_BLOCK_SIZE 4 -#define MFEM_SIMD_SIZE 32 -#define MFEM_TEMPLATE_ENABLE_SERIALIZE - -#ifdef MFEM_USE_X86INTRIN -#include "general/x86intrin.hpp" -#endif - -// -- MFEM_ALIGN_AS +// --- MFEM_ALIGN_AS #if (__cplusplus >= 201103L) #define MFEM_ALIGN_AS(bytes) alignas(bytes) #elif !defined(MFEM_DEBUG) && (defined(__GNUC__) || defined(__clang__)) @@ -54,6 +46,37 @@ #define MFEM_ALIGN_AS(bytes) #endif +// --- X86 or AutoSIMD +#ifdef MFEM_USE_X86INTRIN +#include "simd/x86.hpp" +#else +#include "simd/auto.hpp" +#endif + +// --- SIMD Traits +#define MFEM_TEMPLATE_BLOCK_SIZE 4 +#define MFEM_SIMD_SIZE 32 +template +struct AutoImplTraits +{ + static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; + static const int align_size = MFEM_SIMD_SIZE; // in bytes + + static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); + static const int valign_size = simd_size; + + //static const int simd_size = 1; + //static const int valign_size = 1; + + static const int batch_size = 1; + typedef AutoSIMD vcomplex_t; + typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; + typedef AutoSIMD< int,simd_size,valign_size> vint_t; +}; + + +#define MFEM_TEMPLATE_ENABLE_SERIALIZE + // #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS // #define MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES // #define MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS @@ -82,238 +105,5 @@ long long flop_count; #define MFEM_FLOPS_GET() (0) #endif -template -struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD -{ - typedef scalar_t scalar_type; - static const int size = S; - static const int align_size = align_S; - - scalar_t vec[size]; - - scalar_t &operator[](int i) { return vec[i]; } - const scalar_t &operator[](int i) const { return vec[i]; } - - AutoSIMD &operator=(const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] = v[i]; } - return *this; - } - AutoSIMD &operator=(const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] = e; } - return *this; - } - AutoSIMD &operator+=(const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] += v[i]; } - return *this; - } - AutoSIMD &operator+=(const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] += e; } - return *this; - } - AutoSIMD &operator-=(const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] -= v[i]; } - return *this; - } - AutoSIMD &operator-=(const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] -= e; } - return *this; - } - AutoSIMD &operator*=(const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] *= v[i]; } - return *this; - } - AutoSIMD &operator*=(const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] *= e; } - return *this; - } - AutoSIMD &operator/=(const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] /= v[i]; } - return *this; - } - AutoSIMD &operator/=(const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] /= e; } - return *this; - } - - AutoSIMD operator-() const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = -vec[i]; } - return r; - } - - AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] + v[i]; } - return r; - } - AutoSIMD operator+(const scalar_t &e) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] + e; } - return r; - } - AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] - v[i]; } - return r; - } - AutoSIMD operator-(const scalar_t &e) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] - e; } - return r; - } - AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] * v[i]; } - return r; - } - AutoSIMD operator*(const scalar_t &e) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] * e; } - return r; - } - AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] / v[i]; } - return r; - } - AutoSIMD operator/(const scalar_t &e) const - { - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { r[i] = vec[i] / e; } - return r; - } - - AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] += v[i] * w[i]; } - return *this; - } - AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } - return *this; - } - AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] += e * v[i]; } - return *this; - } - - AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] = v[i] * w[i]; } - return *this; - } - AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } - return *this; - } - AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) - { - MFEM_VECTORIZE_LOOP - for (int i = 0; i < size; i++) { vec[i] = e * v[i]; } - return *this; - } -}; - -template -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) -{ - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < S; i++) { r[i] = e + v[i]; } - return r; -} - -template -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) -{ - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < S; i++) { r[i] = e - v[i]; } - return r; -} - -template -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) -{ - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < S; i++) { r[i] = e * v[i]; } - return r; -} - -template -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) -{ - AutoSIMD r; - MFEM_VECTORIZE_LOOP - for (int i = 0; i < S; i++) { r[i] = e / v[i]; } - return r; -} - - -template -struct AutoImplTraits -{ - static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; - static const int align_size = MFEM_SIMD_SIZE; // in bytes - - // static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); - static const int simd_size = 1; - static const int valign_size = simd_size; - // static const int valign_size = 1; - static const int batch_size = 1; - typedef AutoSIMD vcomplex_t; - typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; - typedef AutoSIMD< int,simd_size,valign_size> vint_t; -}; #endif // MFEM_TEMPLATE_CONFIG diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 1f0f082f7a..644ff4d30b 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -121,7 +121,8 @@ public: virtual ~TBilinearForm() { - delete [] assembled_data; + //delete [] assembled_data; + free(assembled_data); } /// Get the input finite element space prolongation matrix @@ -197,7 +198,12 @@ public: { // TODO: How do we make sure that this array is aligned properly, AND // the compiler knows that it is aligned? - assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; + //assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; + void* result = nullptr; + const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); + const auto alloc_failed = posix_memalign(&result, 32, size); + if (alloc_failed) throw ::std::bad_alloc(); + assembled_data = (p_assembled_t*) result; } for (int el = 0; el < NE; el += TE) { diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index f5ff386523..67d8810c1f 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -47,8 +47,8 @@ endif # MFEM_PERF_CXXFLAGS_gcc_common += -std=c++03 MFEM_PERF_CXXFLAGS_gcc_common += -std=c++11 MFEM_PERF_CXXFLAGS_gcc_common += -pedantic -Wall -# MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 -MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks +#MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 +#MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) From 8af1fe9d206f96db47d4716fba1812f42fdfd3b0 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 18 Jun 2018 12:07:42 -0700 Subject: [PATCH 009/535] [simd] ex1 w/ & w/o x86 --- config/simd/m128.hpp | 327 +++++++++++++++++++++++++------------------ config/simd/m256.hpp | 322 ++++++++++++++++++++++++++---------------- config/simd/m512.hpp | 318 ++++++++++++++++++++++++++--------------- config/simd/m64.hpp | 235 +++++++++++++++++++++++++------ config/simd/x86.hpp | 110 ++------------- config/tconfig.hpp | 15 +- 6 files changed, 814 insertions(+), 513 deletions(-) diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 9e1511765f..7c3f7e51be 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -8,144 +8,201 @@ // MFEM is free software; you can redistribute it and/or modify it under the // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_X86_M128_HPP -#define MFEM_X86_M128_HPP -// **************************************************************************** -// * SSE integer -// **************************************************************************** -struct __attribute__ ((aligned(8))) integer { -protected: - __m128i vec; -public: - // Constructors - inline integer():vec(_mm_set_epi32(0,0,0,0)){} - inline integer(__m128i mm):vec(mm){} - inline integer(int i):vec(_mm_set_epi32(0,0,i,i)){} - inline integer(int i0, int i1){vec=_mm_set_epi32(0, 0, i1, i0);} - // Convertors - inline operator __m128i() const { return vec; } - // Logical Operations - inline integer& operator&=(const integer &a) { return *this = (integer) _mm_and_si128(vec,a); } - inline integer& operator|=(const integer &a) { return *this = (integer) _mm_or_si128(vec,a); } - inline integer& operator^=(const integer &a) { return *this = (integer) _mm_xor_si128(vec,a); } - friend inline integer operator<(const integer &a, const integer &b) { return _mm_cmpeq_epi32(a, b); } - // Arithmetics - friend inline integer operator+(const integer &a, const integer &b) { return _mm_add_epi32(a,b); } - friend inline integer operator-(const integer &a, const integer &b) { return _mm_sub_epi32(a,b); } - //friend inline integer operator*(const integer &a, const integer &b) { return _mm_mul_epi32(a,b); } - friend inline integer operator/(const integer &a, const integer &b) { - return _mm_set_epi32(a[0]/b[0],a[1]/b[1],0,0); - } - friend inline integer operator %(const integer &a, const integer &b) { - return _mm_set_epi32(a[0]%b[0],a[1]%b[1],0,0); - } - inline integer& operator +=(const integer &a) { return *this = (integer)_mm_add_epi32(vec,a); } - inline integer& operator -=(const integer &a) { return *this = (integer)_mm_sub_epi32(vec,a); } - //friend inline __m128d operator==(const integer &a, const int i); - inline const int& operator[](int i) const { - int *a=(int*)&vec; - return a[i]; - } - inline int& operator[](int i) { - int *a=(int*)&vec; - return a[i]; - } -}; -// Logicals -//inline integer operator&(const integer &a, const integer &b) { return _mm_and_si128(a,b); } -//inline integer operator|(const integer &a, const integer &b) { return _mm_or_si128(a,b); } -//inline integer operator^(const integer &a, const integer &b) { return _mm_xor_si128(a,b); } +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M128 +#define MFEM_TEMPLATE_CONFIG_SIMD_M128 -// **************************************************************************** -// * SSE real type class -// **************************************************************************** -struct __attribute__ ((aligned(16))) real { - protected: - __m128d vec; - public: - // Constructors - inline real(): vec(_mm_setzero_pd()){} - inline real(int i):vec(_mm_set1_pd((double)i)){} - inline real(integer i):vec(_mm_set_pd(i[1],i[0])){} - inline real(long i):vec(_mm_set1_pd((double)i)){} - inline real(double d):vec(_mm_set1_pd(d)){} - inline real(__m128d x):vec(x){} - inline real(double *x):vec(_mm_load_pd(x)){} - inline real(double d0, double d1):vec(_mm_set_pd(d1,d0)){} - // Convertors - inline operator __m128d() const { return vec; } - // Arithmetics - friend inline real operator +(const real &a, const real &b) { return _mm_add_pd(a,b); } - friend inline real operator -(const real &a, const real &b) { return _mm_sub_pd(a,b); } - friend inline real operator *(const real &a, const real &b) { return _mm_mul_pd(a,b); } - //CLANG has a built-in candidate -#ifndef __clang_major__ - friend inline real operator /(const real &a, const real &b) { return _mm_div_pd(a,b); } -#endif - inline real& operator +=(const real &a) { return *this = _mm_add_pd(vec,a); } - inline real& operator -=(const real &a) { return *this = _mm_sub_pd(vec,a); } - inline real& operator *=(const real &a) { return *this = _mm_mul_pd(vec,a); } - inline real& operator /=(const real &a) { return *this = _mm_div_pd(vec,a); } - // Unary +/- operators - inline real operator -() const { return _mm_xor_pd (_mm_set1_pd(-0.0), *this); } - inline real operator +() const { return vec; } - // Mixed vector-scalar operations - inline real& operator *=(const double &f) { return *this = _mm_mul_pd(vec,_mm_set1_pd(f)); } - inline real& operator /=(const double &f) { return *this = _mm_div_pd(vec,_mm_set1_pd(f)); } - inline real& operator +=(const double &f) { return *this = _mm_add_pd(vec,_mm_set1_pd(f)); } - inline real& operator +=(double &f) { return *this = _mm_add_pd(vec,_mm_set1_pd(f)); } - inline real& operator -=(const double &f) { return *this = _mm_sub_pd(vec,_mm_set1_pd(f)); } - // Friends operators - friend inline real operator+(const real &a, const double &f) { return _mm_add_pd(a, _mm_set1_pd(f)); } - friend inline real operator-(const real &a, const double &f) { return _mm_sub_pd(a, _mm_set1_pd(f)); } - friend inline real operator*(const real &a, const double &f) { return _mm_mul_pd(a, _mm_set1_pd(f)); } - friend inline real operator/(const real &a, const double &f) { return _mm_div_pd(a, _mm_set1_pd(f)); } - friend inline real operator+(const double &f, const real &a) { return _mm_add_pd(_mm_set1_pd(f),a); } - friend inline real operator-(const double &f, const real &a) { return _mm_sub_pd(_mm_set1_pd(f),a); } - friend inline real operator*(const double &f, const real &a) { return _mm_mul_pd(_mm_set1_pd(f),a); } - friend inline real operator/(const double &f, const real &a) { return _mm_div_pd(_mm_set1_pd(f),a); } +// ***************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 2; + static const int align_size = 16; + + union{ + __m128d m128d; + scalar_t vec[size]; + }; - friend inline real sqrt(const real &a) { return _mm_sqrt_pd(a); } - friend inline real min(const real &r, const real &s){ return _mm_min_pd(r,s);} - friend inline real max(const real &r, const real &s){ return _mm_max_pd(r,s);} - //friend inline real cube_root(const real &a){return real(::cbrt(a[0]),::cbrt(a[1]));} - //friend inline real norm(const real &u){ return real(::fabs(u[0]),::fabs(u[1]));} - // Compares: Mask is returned - friend inline real cmp_eq(const real &a, const real &b) { return _mm_cmpeq_pd(a, b); } - friend inline real cmp_lt(const real &a, const real &b) { return _mm_cmplt_pd(a, b); } - friend inline real cmp_le(const real &a, const real &b) { return _mm_cmple_pd(a, b); } - friend inline real cmp_gt(const real &a, const real &b) { return _mm_cmpgt_pd(a, b); } - friend inline real cmp_ge(const real &a, const real &b) { return _mm_cmpge_pd(a, b); } - friend inline real cmp_neq(const real &a, const real &b) { return _mm_cmpneq_pd(a, b); } - friend inline real cmp_nlt(const real &a, const real &b) { return _mm_cmpnlt_pd(a, b); } - friend inline real cmp_nle(const real &a, const real &b) { return _mm_cmpnle_pd(a, b); } - friend inline real cmp_ngt(const real &a, const real &b) { return _mm_cmpngt_pd(a, b); } - friend inline real cmp_nge(const real &a, const real &b) { return _mm_cmpnge_pd(a, b); } - // Comparison operators - friend inline real operator<(const real &a, const real& b) { return _mm_cmplt_pd(a, b); } - friend inline real operator<(const real &a, double d) { return _mm_cmplt_pd(a, _mm_set1_pd(d)); } - friend inline real operator>(const real &a, real& r) { return _mm_cmpgt_pd(a, r); } - friend inline real operator>(const real &a, const real& r) { return _mm_cmpgt_pd(a, r); } - friend inline real operator>(const real &a, double d) { return _mm_cmpgt_pd(a, _mm_set1_pd(d)); } - friend inline real operator>=(const real &a, real& r) { return _mm_cmpge_pd(a, r); } - friend inline real operator>=(const real &a, double d) { return _mm_cmpge_pd(a, _mm_set1_pd(d)); } - friend inline real operator<=(const real &a, const real& r) { return _mm_cmple_pd(a, r); } - friend inline real operator<=(const real &a, double d) { return _mm_cmple_pd(a, _mm_set1_pd(d)); } - friend inline real operator==(const real &a, const real& r) { return _mm_cmpeq_pd(a, r); } - friend inline real operator==(const real &a, double d) { return _mm_cmpeq_pd(a, _mm_set1_pd(d)); } - friend inline real operator!=(const real &a, const real& r) { return _mm_cmpneq_pd(a, r); } - friend inline real operator!=(const real &a, double d) { return _mm_cmpneq_pd(a, _mm_set1_pd(d)); } - // [] operators - inline const double& operator[](int i) const { - double *d= (double*)&vec; - return d[i]; - } - - inline double& operator[](int i) { - double *d = (double*)&vec; - return d[i]; + scalar_t &operator[](int i) { return vec[i]; } + const scalar_t &operator[](int i) const { return vec[i]; } + + AutoSIMD &operator=(const AutoSIMD &v) + { + m128d = v.m128d; + return *this; + } + AutoSIMD &operator=(const scalar_t &e) + { + m128d = _mm_set1_pd(e); + return *this; + } + AutoSIMD &operator+=(const AutoSIMD &v) + { + m128d = _mm_add_pd(m128d,v); + return *this; } + AutoSIMD &operator+=(const scalar_t &e) + { + m128d = _mm_add_pd(m128d,_mm_set1_pd(e)); + return *this; + } + AutoSIMD &operator-=(const AutoSIMD &v) + { + m128d = _mm_sub_pd(m128d,v); + return *this; + } + AutoSIMD &operator-=(const scalar_t &e) + { + m128d = _mm_sub_pd(m128d,_mm_set1_pd(e)); + return *this; + } + AutoSIMD &operator*=(const AutoSIMD &v) + { + m128d = _mm_mul_pd(m128d,v.m128d); + return *this; + } + AutoSIMD &operator*=(const scalar_t &e) + { + m128d = _mm_mul_pd(m128d,_mm_set1_pd(e)); + return *this; + } + AutoSIMD &operator/=(const AutoSIMD &v) + { + m128d = _mm_div_pd(m128d,v.m128d); + return *this; + } + AutoSIMD &operator/=(const scalar_t &e) + { + m128d = _mm_div_pd(m128d,_mm_set1_pd(e)); + return *this; + } + AutoSIMD operator-() const + { + return _mm_xor_pd(_mm_set1_pd(-0.0), m128d); + } + + AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.m128d = _mm_add_pd(m128d,v.m128d); + return r; + } + AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.m128d = _mm_add_pd(m128d, _mm_set1_pd(e)); + return r; + } + AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.m128d = _mm_sub_pd(m128d,v.m128d); + return r; + } + AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.m128d = _mm_sub_pd(m128d, _mm_set1_pd(e)); + return r; + } + AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.m128d = _mm_mul_pd(m128d,v.m128d); + return r; + } + AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.m128d = _mm_mul_pd(m128d, _mm_set1_pd(e)); + return r; + } + AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.m128d = _mm_div_pd(m128d,v.m128d); + return r; + } + AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.m128d = _mm_div_pd(m128d, _mm_set1_pd(e)); + return r; + } + + AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + m128d = _mm_add_pd(_mm_mul_pd(w.m128d,v.m128d),m128d); + return *this; + } + AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + m128d = _mm_add_pd(_mm_mul_pd(_mm_set1_pd(e),v.m128d),m128d); + return *this; + } + AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + m128d = _mm_add_pd(_mm_mul_pd(v.m128d,_mm_set1_pd(e)),m128d); + return *this; + } + + AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + m128d = _mm_mul_pd(v.m128d,w.m128d); + return *this; + } + AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + m128d = _mm_mul_pd(v.m128d,_mm_set1_pd(e)); + return *this; + } + AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d); + return *this; + } }; -#endif // MFEM_X86_M128_HPP +// ***************************************************************************** +template +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m128d = _mm_add_pd(_mm_set1_pd(e),v.m128d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m128d = _mm_sub_pd(_mm_set1_pd(e),v.m128d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m128d = _mm_div_pd(_mm_set1_pd(e),v.m128d); + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_M128 + diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 7412c9f2f3..3ee96c7f07 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -8,126 +8,212 @@ // MFEM is free software; you can redistribute it and/or modify it under the // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_X86_M256_HPP -#define MFEM_X86_M256_HPP -// **************************************************************************** -// * AVX integer type class -// **************************************************************************** -struct __attribute__ ((aligned(16))) integer { -protected: - __attribute__ ((aligned(16))) __m128i vec; -public: - // Constructors - inline integer(){} - inline integer(__m128i mm):vec(mm){} - inline integer(int i):vec(_mm_set_epi32(i,i,i,i)){} - // Convertors - inline operator __m128i() const { return vec; } - // Logical Operations - inline integer& operator&=(const integer &a) { return *this = (integer)_mm_and_si128(vec,a); } - inline integer& operator|=(const integer &a) { return *this = (integer)_mm_or_si128(vec,a); } - inline integer& operator^=(const integer &a) { return *this = (integer)_mm_xor_si128(vec,a); } - inline integer& operator+=(const integer &a) { return *this = (integer)_mm_add_epi32(vec,a); } - inline integer& operator-=(const integer &a) { return *this = (integer)_mm_sub_epi32(vec,a); } - // Friends operators - //friend inline __m256d operator==(const integer &a, const int i); - // [] operators - inline const int& operator[](int i) const { - const int *a=(int*)&vec; - return a[i]; +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M256 +#define MFEM_TEMPLATE_CONFIG_SIMD_M256 + +// ***************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 4; + static const int align_size = 32; + + union{ + __m256d m256d; + scalar_t vec[size]; + }; + + scalar_t &operator[](int i) { return vec[i]; } + const scalar_t &operator[](int i) const { return vec[i]; } + + AutoSIMD &operator=(const AutoSIMD &v) + { + m256d = v.m256d; + return *this; + } + AutoSIMD &operator=(const scalar_t &e) + { + m256d = _mm256_set1_pd(e); + return *this; + } + AutoSIMD &operator+=(const AutoSIMD &v) + { + m256d = _mm256_add_pd(m256d,v); + return *this; } - inline int& operator[](int i) { - int *a=(int*)&vec; - return a[i]; - } + AutoSIMD &operator+=(const scalar_t &e) + { + m256d = _mm256_add_pd(m256d,_mm256_set1_pd(e)); + return *this; + } + AutoSIMD &operator-=(const AutoSIMD &v) + { + m256d = _mm256_sub_pd(m256d,v); + return *this; + } + AutoSIMD &operator-=(const scalar_t &e) + { + m256d = _mm256_sub_pd(m256d,_mm256_set1_pd(e)); + return *this; + } + AutoSIMD &operator*=(const AutoSIMD &v) + { + m256d = _mm256_mul_pd(m256d,v.m256d); + return *this; + } + AutoSIMD &operator*=(const scalar_t &e) + { + m256d = _mm256_mul_pd(m256d,_mm256_set1_pd(e)); + return *this; + } + AutoSIMD &operator/=(const AutoSIMD &v) + { + m256d = _mm256_div_pd(m256d,v.m256d); + return *this; + } + AutoSIMD &operator/=(const scalar_t &e) + { + m256d = _mm256_div_pd(m256d,_mm256_set1_pd(e)); + return *this; + } + AutoSIMD operator-() const + { + return _mm256_xor_pd(_mm256_set1_pd(-0.0), m256d); + } + + AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.m256d = _mm256_add_pd(m256d,v.m256d); + return r; + } + AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.m256d = _mm256_add_pd(m256d, _mm256_set1_pd(e)); + return r; + } + AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.m256d = _mm256_sub_pd(m256d,v.m256d); + return r; + } + AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.m256d = _mm256_sub_pd(m256d, _mm256_set1_pd(e)); + return r; + } + AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.m256d = _mm256_mul_pd(m256d,v.m256d); + return r; + } + AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.m256d = _mm256_mul_pd(m256d, _mm256_set1_pd(e)); + return r; + } + AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.m256d = _mm256_div_pd(m256d,v.m256d); + return r; + } + AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.m256d = _mm256_div_pd(m256d, _mm256_set1_pd(e)); + return r; + } + + AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { +#if __SIMD__==2 //-mavx -mno-avx2 + m256d = _mm256_add_pd(_mm256_mul_pd(w.m256d,v.m256d),m256d); +#else + m256d = _mm256_fmadd_pd(w.m256d,v.m256d,m256d); +#endif + return *this; + } + AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { +#if __SIMD__==2 //-mavx -mno-avx2 + m256d = _mm256_add_pd(_mm256_mul_pd(_mm256_set1_pd(e),v.m256d),m256d); +#else + m256d = _mm256_fmadd_pd(_mm256_set1_pd(e),v.m256d,m256d); +#endif + return *this; + } + AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { +#if __SIMD__==2 //-mavx -mno-avx2 + m256d = _mm256_add_pd(_mm256_mul_pd(v.m256d,_mm256_set1_pd(e)),m256d); +#else + m256d = _mm256_fmadd_pd(v.m256d,_mm256_set1_pd(e),m256d); +#endif + return *this; + } + + AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + m256d = _mm256_mul_pd(v.m256d,w.m256d); + return *this; + } + AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + m256d = _mm256_mul_pd(v.m256d,_mm256_set1_pd(e)); + return *this; + } + AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); + return *this; + } }; -// **************************************************************************** -// * AVX real type class -// **************************************************************************** -struct __attribute__ ((aligned(32))) real { - protected: - __m256d vec; - public: - // Constructors - inline real(){} - inline real(int i):vec(_mm256_set1_pd((double)i)){} - inline real(integer i):vec(_mm256_set_pd(i[3],i[2],i[1],i[0])){} - inline real(long i):vec(_mm256_set1_pd((double)i)){} - inline real(double d):vec(_mm256_set1_pd(d)){} - inline real(__m256d x):vec(x){} - inline real(double *x):vec(_mm256_load_pd(x)){} - // Convertors - inline operator __m256d() const { return vec; } - // Arithmetics - friend inline real operator +(const real &a, const real &b) { return _mm256_add_pd(a,b); } - friend inline real operator -(const real &a, const real &b) { return _mm256_sub_pd(a,b); } - friend inline real operator *(const real &a, const real &b) { return _mm256_mul_pd(a,b); } - friend inline real operator /(const real &a, const real &b) { return _mm256_div_pd(a,b); } - // Unary - inline real operator -() const { return _mm256_xor_pd (_mm256_set1_pd(-0.0), *this); } - inline real operator +() const { return vec; } - // Assignment operations - inline real& operator +=(const real &a) { return *this = _mm256_add_pd(vec,a); } - inline real& operator -=(const real &a) { return *this = _mm256_sub_pd(vec,a); } - inline real& operator *=(const real &a) { return *this = _mm256_mul_pd(vec,a); } - inline real& operator /=(const real &a) { return *this = _mm256_div_pd(vec,a); } - // Mixed vector-scalar assignment operations - inline real& operator *=(const double &f) { return *this = _mm256_mul_pd(vec,_mm256_set1_pd(f)); } - inline real& operator /=(const double &f) { return *this = _mm256_div_pd(vec,_mm256_set1_pd(f)); } - inline real& operator +=(const double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } - inline real& operator +=(double &f) { return *this = _mm256_add_pd(vec,_mm256_set1_pd(f)); } - inline real& operator -=(const double &f) { return *this = _mm256_sub_pd(vec,_mm256_set1_pd(f)); } - // Friends operator - friend inline real operator +(const real &a, const double &f) { return _mm256_add_pd(a, _mm256_set1_pd(f)); } - friend inline real operator -(const real &a, const double &f) { return _mm256_sub_pd(a, _mm256_set1_pd(f)); } - friend inline real operator *(const real &a, const double &f) { return _mm256_mul_pd(a, _mm256_set1_pd(f)); } - friend inline real operator /(const real &a, const double &f) { return _mm256_div_pd(a, _mm256_set1_pd(f)); } - friend inline real operator +(const double &f, const real &a) { return _mm256_add_pd(_mm256_set1_pd(f),a); } - friend inline real operator -(const double &f, const real &a) { return _mm256_sub_pd(_mm256_set1_pd(f),a); } - friend inline real operator *(const double &f, const real &a) { return _mm256_mul_pd(_mm256_set1_pd(f),a); } - friend inline real operator /(const double &f, const real &a) { return _mm256_div_pd(_mm256_set1_pd(f),a); } - friend inline real sqrt(const real &a) { return _mm256_sqrt_pd(a); } - friend inline real ceil(const real &a) { return _mm256_round_pd((a), _MM_FROUND_CEIL); } - friend inline real floor(const real &a) { return _mm256_round_pd((a), _MM_FROUND_FLOOR); } - friend inline real trunc(const real &a) { return _mm256_round_pd((a), _MM_FROUND_TO_ZERO); } - friend inline real min(const real &r, const real &s){ return _mm256_min_pd(r,s);} - friend inline real max(const real &r, const real &s){ return _mm256_max_pd(r,s);} - //friend inline real round(const real &a) { return _mm256_svml_round_pd(a); } - // Comparison operator - friend inline real cmp_eq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OS); } - friend inline real cmp_lt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } - friend inline real cmp_le(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); } - friend inline real cmp_gt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GT_OS); } - friend inline real cmp_ge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_GE_OS); } - friend inline real cmp_neq(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_US); } - friend inline real cmp_nlt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); } - friend inline real cmp_nle(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); } - friend inline real cmp_ngt(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGT_US); } - friend inline real cmp_nge(const real &a, const real &b) { return _mm256_cmp_pd(a, b, _CMP_NGE_US); } - friend inline real operator<(const real &a, const real& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); } - friend inline real operator<(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LT_OS); } - friend inline real operator>(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } - friend inline real operator>(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_GT_OS); } - friend inline real operator>(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GT_OS); } - friend inline real operator>=(const real &a, real& r) { return _mm256_cmp_pd(a, r, _CMP_GE_OS); } - friend inline real operator>=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_GE_OS); } - friend inline real operator<=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_LE_OS); } - friend inline real operator<=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_LE_OS); } - friend inline real operator==(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_EQ_OQ); } - friend inline real operator==(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_EQ_OQ); } - friend inline real operator!=(const real &a, const real& r) { return _mm256_cmp_pd(a, r, _CMP_NEQ_UQ); } - friend inline real operator!=(const real &a, double d) { return _mm256_cmp_pd(a, _mm256_set1_pd(d), _CMP_NEQ_UQ); } - // [] operators - inline const double& operator[](int i) const { - const double *d = (double*)&vec; - return *(d+i); - } - inline double& operator[](int i) { - double *d = (double*)&vec; - return *(d+i); - } -}; +// ***************************************************************************** +template +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m256d = _mm256_add_pd(_mm256_set1_pd(e),v.m256d); + return r; +} -#endif // MFEM_X86_M256_HPP +// ***************************************************************************** +template +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m256d = _mm256_sub_pd(_mm256_set1_pd(e),v.m256d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m256d = _mm256_div_pd(_mm256_set1_pd(e),v.m256d); + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_M256 diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 11d360eb2c..ecdcc7e0f1 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -8,126 +8,212 @@ // MFEM is free software; you can redistribute it and/or modify it under the // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_X86_M512_HPP -#define MFEM_X86_M512_HPP -// **************************************************************************** -// * AVX512 integer type class -// **************************************************************************** -struct __attribute__ ((aligned(64))) integer { -protected: - __m512i vec; -public: - // Constructors - inline integer(){} - inline integer(__m512i mm):vec(mm){} - inline integer(int i):vec(_mm512_set_epi64(i,i,i,i,i,i,i,i)){} - inline integer(int i7, int i6, int i5, int i4, - int i3, int i2, int i1, int i0){vec=_mm512_set_epi64(i7,i6,i5,i4,i3,i2,i1,i0);} - // Convertors - inline operator __m512i() const { return vec; } - // Logical Operations - inline integer& operator&=(const integer &a) { return *this = (integer) _mm512_and_epi64(vec,a); } - inline integer& operator|=(const integer &a) { return *this = (integer) _mm512_or_epi64(vec,a); } - inline integer& operator^=(const integer &a) { return *this = (integer) _mm512_xor_epi64(vec,a); } - inline integer& operator+=(const integer &a) { return *this = (integer)_mm512_add_epi64(vec,a); } - inline integer& operator-=(const integer &a) { return *this = (integer)_mm512_sub_epi64(vec,a); } - // Friends operators - //friend inline __mmask8 operator==(const integer &a, const int i); - // [] operators - inline const int& operator[](const int i) const { - int *dp = (int*)&vec; - return *(dp+i); +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M512 +#define MFEM_TEMPLATE_CONFIG_SIMD_M512 + +// ***************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 8; + static const int align_size = 64; + + union{ + __m512d m512d; + scalar_t vec[size]; + }; + + scalar_t &operator[](int i) { return vec[i]; } + const scalar_t &operator[](int i) const { return vec[i]; } + + AutoSIMD &operator=(const AutoSIMD &v) + { + m512d = v.m512d; + return *this; + } + AutoSIMD &operator=(const scalar_t &e) + { + m512d = _mm512_set1_pd(e); + return *this; + } + AutoSIMD &operator+=(const AutoSIMD &v) + { + m512d = _mm512_add_pd(m512d,v); + return *this; } - inline int& operator[](const int i) { - int *dp = (int*)&vec; - return *(dp+i); - } -}; -// Logicals -//inline integer operator&(const integer &a, const integer &b) { return _mm512_and_epi64(a,b); } -//inline integer operator|(const integer &a, const integer &b) { return _mm512_or_epi64(a,b); } -//inline integer operator^(const integer &a, const integer &b) { return _mm512_xor_epi64(a,b); } -//inline __mmask8 operator==(const integer &a, const int i){ -// return _mm512_cmp_epi64_mask(a.vec,_mm512_set_epi64(i,i,i,i,i,i,i,i),_MM_CMPINT_EQ); -//} + AutoSIMD &operator+=(const scalar_t &e) + { + m512d = _mm512_add_pd(m512d,_mm512_set1_pd(e)); + return *this; + } + AutoSIMD &operator-=(const AutoSIMD &v) + { + m512d = _mm512_sub_pd(m512d,v); + return *this; + } + AutoSIMD &operator-=(const scalar_t &e) + { + m512d = _mm512_sub_pd(m512d,_mm512_set1_pd(e)); + return *this; + } + AutoSIMD &operator*=(const AutoSIMD &v) + { + m512d = _mm512_mul_pd(m512d,v.m512d); + return *this; + } + AutoSIMD &operator*=(const scalar_t &e) + { + m512d = _mm512_mul_pd(m512d,_mm512_set1_pd(e)); + return *this; + } + AutoSIMD &operator/=(const AutoSIMD &v) + { + m512d = _mm512_div_pd(m512d,v.m512d); + return *this; + } + AutoSIMD &operator/=(const scalar_t &e) + { + m512d = _mm512_div_pd(m512d,_mm512_set1_pd(e)); + return *this; + } + AutoSIMD operator-() const + { + return _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); + } + AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.m512d = _mm512_add_pd(m512d,v.m512d); + return r; + } + AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.m512d = _mm512_add_pd(m512d, _mm512_set1_pd(e)); + return r; + } + AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.m512d = _mm512_sub_pd(m512d,v.m512d); + return r; + } + AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.m512d = _mm512_sub_pd(m512d, _mm512_set1_pd(e)); + return r; + } + AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.m512d = _mm512_mul_pd(m512d,v.m512d); + return r; + } + AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.m512d = _mm512_mul_pd(m512d, _mm512_set1_pd(e)); + return r; + } + AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.m512d = _mm512_div_pd(m512d,v.m512d); + return r; + } + AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.m512d = _mm512_div_pd(m512d, _mm512_set1_pd(e)); + return r; + } -// **************************************************************************** -// * AVX512 real type class -// **************************************************************************** -struct __attribute__ ((aligned(64))) real { - protected: - __m512d vec; - public: - // Constructors - inline real(){} - inline real(__m512i d):vec(_mm512_set_pd(d[0],d[1],d[2],d[3], - d[4],d[5],d[6],d[7])){} - inline real(integer d):vec(_mm512_set_pd(d[0],d[1],d[2],d[3], - d[4],d[5],d[6],d[7])){} - inline real(int d):vec(_mm512_set1_pd(d)){} - inline real(double d):vec(_mm512_set1_pd(d)){} - inline real(__m512d x):vec(x){} - inline real(double *x):vec(_mm512_load_pd(x)){} - inline real(double d7, double d6, double d5, double d4, - double d3, double d2, double d1, double d0): - vec(_mm512_set_pd(d7,d6,d5,d4,d3,d2,d1,d0)){} - // Conversion operator - inline operator __m512d() const { return vec; } - // Arithmetics - friend inline real operator +(const real &a, const real &b){ return _mm512_add_pd(a,b); } - friend inline real operator -(const real &a, const real &b){ return _mm512_sub_pd(a,b); } - friend inline real operator *(const real &a, const real &b){ return _mm512_mul_pd(a,b); } -#ifndef __clang_major__ - friend inline real operator /(const real &a, const real &b){ return _mm512_div_pd(a,b); } + AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { +#if __SIMD__==2 //-mavx -mno-avx2 + m512d = _mm512_add_pd(_mm512_mul_pd(w.m512d,v.m512d),m512d); +#else + m512d = _mm512_fmadd_pd(w.m512d,v.m512d,m512d); #endif - inline real& operator +=(const real &a){ return *this = _mm512_add_pd(vec,a); } - inline real& operator -=(const real &a){ return *this = _mm512_sub_pd(vec,a); } - inline real& operator *=(const real &a){ return *this = _mm512_mul_pd(vec,a); } - inline real& operator /=(const real &a){ return *this = _mm512_div_pd(vec,a); } - // Unary + or - - inline real operator -() const { return real(0.0) - vec; } - inline real operator -() { return real(0.0) - vec; } - inline real operator +() { return vec; } - // Mixed vector-scalar operations - inline real& operator *=(const double &f){ return *this = _mm512_mul_pd(vec,_mm512_set1_pd(f)); } - inline real& operator /=(const double &f){ return *this = _mm512_div_pd(vec,_mm512_set1_pd(f)); } - inline real& operator +=(const double &f){ return *this = _mm512_add_pd(vec,_mm512_set1_pd(f)); } - inline real& operator +=(double &f){ return *this = _mm512_add_pd(vec,_mm512_set1_pd(f)); } - inline real& operator -=(const double &f){ return *this = _mm512_sub_pd(vec,_mm512_set1_pd(f)); } - // Friends operators - friend inline real operator +(const real &a, const double &f){ return _mm512_add_pd(a, _mm512_set1_pd(f)); } - friend inline real operator -(const real &a, const double &f){ return _mm512_sub_pd(a, _mm512_set1_pd(f)); } - friend inline real operator *(const real &a, const double &f){ return _mm512_mul_pd(a, _mm512_set1_pd(f)); } - friend inline real operator /(const real &a, const double &f){ return _mm512_div_pd(a, _mm512_set1_pd(f)); } - friend inline real operator +(const double &f, const real &a){ return _mm512_add_pd(_mm512_set1_pd(f),a); } - friend inline real operator -(const double &f, const real &a){ return _mm512_sub_pd(_mm512_set1_pd(f),a); } - friend inline real operator *(const double &f, const real &a){ return _mm512_mul_pd(_mm512_set1_pd(f),a); } - friend inline real operator /(const double &f, const real &a){ return _mm512_div_pd(_mm512_set1_pd(f),a); } - // Comparison operators - friend inline __mmask8 operator==(const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_EQ_OQ); } - friend inline __mmask8 operator==(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_EQ_OQ); } - friend inline __mmask8 operator< (const real &a, const real& b){ return _mm512_cmp_pd_mask(a,b,_CMP_LT_OS); } - friend inline __mmask8 operator< (const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_LT_OS); } - friend inline __mmask8 operator<=(const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_LE_OS); } - friend inline __mmask8 operator<=(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_LE_OS); } - friend inline __mmask8 operator> (const real &a, real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NLE_US); } - friend inline __mmask8 operator> (const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NLE_US); } - friend inline __mmask8 operator> (const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_NLE_US); } - friend inline __mmask8 operator>=(const real &a, real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NLT_US); } - friend inline __mmask8 operator>=(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_NLT_US); } - friend inline __mmask8 operator!=(const real &a, const real& r){ return _mm512_cmp_pd_mask(a,r,_CMP_NEQ_UQ); } - friend inline __mmask8 operator!=(const real &a, double d){ return _mm512_cmp_pd_mask(a,_mm512_set1_pd(d),_CMP_NEQ_UQ); } - // [] operators - inline const double& operator[](const int i) const { - double *dp = (double*)&vec; - return *(dp+i); - } - inline double& operator[](const int i){ - double *dp = (double*)&vec; - return *(dp+i); - } + return *this; + } + AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { +#if __SIMD__==2 //-mavx -mno-avx2 + m512d = _mm512_add_pd(_mm512_mul_pd(_mm512_set1_pd(e),v.m512d),m512d); +#else + m512d = _mm512_fmadd_pd(_mm512_set1_pd(e),v.m512d,m512d); +#endif + return *this; + } + AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { +#if __SIMD__==2 //-mavx -mno-avx2 + m512d = _mm512_add_pd(_mm512_mul_pd(v.m512d,_mm512_set1_pd(e)),m512d); +#else + m512d = _mm512_fmadd_pd(v.m512d,_mm512_set1_pd(e),m512d); +#endif + return *this; + } + + AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + m512d = _mm512_mul_pd(v.m512d,w.m512d); + return *this; + } + AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + m512d = _mm512_mul_pd(v.m512d,_mm512_set1_pd(e)); + return *this; + } + AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); + return *this; + } }; -#endif // MFEM_X86_M512_HPP +// ***************************************************************************** +template +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m512d = _mm512_add_pd(_mm512_set1_pd(e),v.m512d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m512d = _mm512_sub_pd(_mm512_set1_pd(e),v.m512d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.m512d = _mm512_div_pd(_mm512_set1_pd(e),v.m512d); + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_M512 diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index cd5b03b491..a58164e1df 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -8,47 +8,204 @@ // MFEM is free software; you can redistribute it and/or modify it under the // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_X86_M64_HPP -#define MFEM_X86_M64_HPP + +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M64 +#define MFEM_TEMPLATE_CONFIG_SIMD_M64 // **************************************************************************** -// * STD integer -// **************************************************************************** -struct integer { -protected: - int vec; -public: - // Constructors - inline integer():vec(){} - inline integer(int i):vec(i){} - // Convertors - inline operator int() const { return vec; } - // Arithmetics - friend inline integer operator *(const integer &a, const integer &b) { return a*b; } - // [] operator - inline int& operator[](int k) { return vec; } - inline const int& operator[](int k) const { return vec; } +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 1; + static const int align_size = 8; + + scalar_t vec[size]; + + scalar_t &operator[](int i) { return vec[0]; } + const scalar_t &operator[](int i) const { return vec[0]; } + + AutoSIMD &operator=(const AutoSIMD &v) + { + vec[0] = v[0]; + return *this; + } + AutoSIMD &operator=(const scalar_t &e) + { + vec[0] = e; + return *this; + } + AutoSIMD &operator+=(const AutoSIMD &v) + { + vec[0] += v[0]; + return *this; + } + AutoSIMD &operator+=(const scalar_t &e) + { + vec[0] += e; + return *this; + } + AutoSIMD &operator-=(const AutoSIMD &v) + { + vec[0] -= v[0]; + return *this; + } + AutoSIMD &operator-=(const scalar_t &e) + { + vec[0] -= e; + return *this; + } + AutoSIMD &operator*=(const AutoSIMD &v) + { + vec[0] *= v[0]; + return *this; + } + AutoSIMD &operator*=(const scalar_t &e) + { + vec[0] *= e; + return *this; + } + AutoSIMD &operator/=(const AutoSIMD &v) + { + vec[0] /= v[0]; + return *this; + } + AutoSIMD &operator/=(const scalar_t &e) + { + vec[0] /= e; + return *this; + } + + AutoSIMD operator-() const + { + AutoSIMD r; + r[0] = -vec[0]; + return r; + } + + AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] + v[0]; + return r; + } + AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] + e; + return r; + } + AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] - v[0]; + return r; + } + AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] - e; + return r; + } + AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] * v[0]; + return r; + } + AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] * e; + return r; + } + AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] / v[0]; + return r; + } + AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] / e; + return r; + } + + AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] += v[0] * w[0]; + return *this; + } + AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vec[0] += v[0] * e; + return *this; + } + AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vec[0] += e * v[0]; + return *this; + } + + AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] = v[0] * w[0]; + return *this; + } + AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vec[0] = v[0] * e; + return *this; + } + AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vec[0] = e * v[0]; + return *this; + } }; -// **************************************************************************** -// * STD real type class -// **************************************************************************** -struct real { - protected: - double vec; - public: - // Constructors - inline real(): vec(){} - inline real(double a): vec(a){} - // Convertors - inline operator double() const { return vec; } - // Arithmetics - inline real& operator+=(const real &a) { return *this = vec+a; } - // Mixed vector-scalar operations - inline real& operator*=(const double &f) { return *this = vec*f; } - // [] operators - inline const double& operator[](int k) const { return vec; } - inline double& operator[](int k) { return vec; } -}; +// ***************************************************************************** +template +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + MFEM_VECTORIZE_LOOP + r[0] = e + v[0]; + return r; +} -#endif // MFEM_X86_M64_HPP +// ***************************************************************************** +template +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e - v[0]; + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e * v[0]; + return r; +} + +// ***************************************************************************** +template +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e / v[0]; + return r; +} + + +//template typedef struct AutoSIMD AutoSIMD; + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_M64 diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index a54c34942b..71af1a7099 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -8,22 +8,15 @@ // MFEM is free software; you can redistribute it and/or modify it under the // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_X86INTRIN_HPP -#define MFEM_X86INTRIN_HPP -#include +#ifndef MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP +#define MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP + +#include "assert.h" #include "x86intrin.h" -// x86 intrinsic class forward description -template struct x86intrin; - - // **************************************************************************** // * ifdef switch between SCALAR, SSE, AVX, AVX2, AVX512F -// * gcc --machine-avx512f -ffreestanding -C -E general/x86intrin.hpp|more -// * strings /usr/local/cuda/bin/nvcc | grep [-]D -// * gcc -dM -E -m64 - < /dev/null|sort|grep -i x86 -// * __CUDA_ARCH__ vs __x86_64__ // **************************************************************************** #ifndef __SSE2__ #define __SSE2__ 0 @@ -38,97 +31,16 @@ template struct x86intrin; #define __AVX512F__ 0 #endif #define __SIMD__ __SSE2__+__AVX__+__AVX2__+__AVX512F__ -//__SIMD__ -// **************************************************************************** -// * AVX512 (-mavx512f) -// **************************************************************************** -#if __SIMD__==4 -#include "x86/m512.hpp" -#define MFEM_SIMD_SIZE 64 -#pragma message "X86intrin::AVX512" -template <> struct x86intrin<4>{ -public: - const static int align = 64; - const static int width = 8; - typedef real vreal_t; - typedef integer vint_t; - static inline vreal_t set(double a){return _mm512_set1_pd(a);} - static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} -}; -#endif // __AVX512__ +// ***************************************************************************** +template struct AutoSIMD; -// **************************************************************************** -// * AVX2 (-mavx2) -// **************************************************************************** -#if __SIMD__==3 -#include "x86/m256.hpp" -#pragma message "X86intrin::AVX2" -template <> struct x86intrin<3>{ -public: - static const int align = 32; - static const int width = 4; - typedef real vreal_t; - typedef integer vint_t; - static inline vreal_t set(double a){return _mm256_set1_pd(a);} - static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} -}; -#endif // __AVX2__ +#include "m64.hpp" -// **************************************************************************** -// * AVX (-mavx -mno-avx2) -// **************************************************************************** -#if __SIMD__==2 -#pragma message "X86intrin::AVX" -#include "x86/m256.hpp" -template <> struct x86intrin<2>{ -public: - static const int align = 32; - static const int width = 4; - typedef real vreal_t; - typedef integer vint_t; - static inline vreal_t set(double a){return _mm256_set1_pd(a);} - static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} -}; -#endif // __AVX__ +#include "m128.hpp" -// **************************************************************************** -// * SSE (-mno-avx) -// **************************************************************************** -#if __SIMD__==1 -#include "x86/m128.hpp" -#pragma message "X86intrin::SSE" -template <> struct x86intrin<1>{ -public: - static const int align = 16; - static const int width = 2; - typedef real vreal_t; - typedef integer vint_t; - static inline vreal_t set(double a){return _mm_set1_pd(a);} - static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} -}; -#endif // __SSE__ +#include "m256.hpp" -// **************************************************************************** -// * 'SCALAR' (-mno-sse2) -// **************************************************************************** -#if __SIMD__==0 -#include "x86/m64.hpp" -#pragma message "X86intrin::STD" -template <> struct x86intrin<0>{ -public: - static const int align = 8; - static const int width = 1; - typedef real vreal_t; - typedef integer vint_t; - static inline vreal_t set(double a){return a;} - static inline void* alloc(size_t size){return ::aligned_alloc(align,size);} -}; -#endif // __STD__ +#include "m512.hpp" -// **************************************************************************** -// * X86 intrinsic base class -// **************************************************************************** -class x86: public x86intrin<__SIMD__>{}; - -#endif // MFEM_X86INTRIN_HPP +#endif // MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP diff --git a/config/tconfig.hpp b/config/tconfig.hpp index c854ea5f96..708207e8bb 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -31,7 +31,7 @@ // --- MFEM_VECTORIZE_LOOP (disabled) #if (__cplusplus >= 201103L) && !defined(MFEM_DEBUG) && defined(__GNUC__) -// #define MFEM_VECTORIZE_LOOP _Pragma("GCC ivdep") +//#define MFEM_VECTORIZE_LOOP _Pragma("GCC ivdep") #define MFEM_VECTORIZE_LOOP #else #define MFEM_VECTORIZE_LOOP @@ -47,11 +47,11 @@ #endif // --- X86 or AutoSIMD -#ifdef MFEM_USE_X86INTRIN -#include "simd/x86.hpp" -#else +#ifndef MFEM_USE_X86INTRIN #include "simd/auto.hpp" -#endif +#else +#include "simd/x86.hpp" +#endif // MFEM_USE_X86INTRIN // --- SIMD Traits #define MFEM_TEMPLATE_BLOCK_SIZE 4 @@ -62,16 +62,19 @@ struct AutoImplTraits static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; static const int align_size = MFEM_SIMD_SIZE; // in bytes + static const int batch_size = 1; + static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); static const int valign_size = simd_size; //static const int simd_size = 1; //static const int valign_size = 1; - static const int batch_size = 1; typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; +#ifndef MFEM_USE_X86INTRIN typedef AutoSIMD< int,simd_size,valign_size> vint_t; +#endif // MFEM_USE_X86INTRIN }; From bccbe14a1e6bfdaef7f2a32ba6ff879d0426e9fd Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 18 Jun 2018 18:55:37 -0700 Subject: [PATCH 010/535] [x86] cleanup --- config/simd/m256.hpp | 6 +++--- config/simd/m512.hpp | 12 ------------ config/simd/m64.hpp | 3 --- config/simd/x86.hpp | 19 ------------------- config/tconfig.hpp | 18 +++++++++--------- fem/tbilinearform.hpp | 8 ++------ 6 files changed, 14 insertions(+), 52 deletions(-) diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 3ee96c7f07..d004d49782 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -133,7 +133,7 @@ template struct AutoSIMD AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { -#if __SIMD__==2 //-mavx -mno-avx2 +#ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(w.m256d,v.m256d),m256d); #else m256d = _mm256_fmadd_pd(w.m256d,v.m256d,m256d); @@ -142,7 +142,7 @@ template struct AutoSIMD } AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { -#if __SIMD__==2 //-mavx -mno-avx2 +#ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(_mm256_set1_pd(e),v.m256d),m256d); #else m256d = _mm256_fmadd_pd(_mm256_set1_pd(e),v.m256d,m256d); @@ -151,7 +151,7 @@ template struct AutoSIMD } AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { -#if __SIMD__==2 //-mavx -mno-avx2 +#ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(v.m256d,_mm256_set1_pd(e)),m256d); #else m256d = _mm256_fmadd_pd(v.m256d,_mm256_set1_pd(e),m256d); diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index ecdcc7e0f1..7163039421 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -133,29 +133,17 @@ template struct AutoSIMD AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { -#if __SIMD__==2 //-mavx -mno-avx2 - m512d = _mm512_add_pd(_mm512_mul_pd(w.m512d,v.m512d),m512d); -#else m512d = _mm512_fmadd_pd(w.m512d,v.m512d,m512d); -#endif return *this; } AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { -#if __SIMD__==2 //-mavx -mno-avx2 - m512d = _mm512_add_pd(_mm512_mul_pd(_mm512_set1_pd(e),v.m512d),m512d); -#else m512d = _mm512_fmadd_pd(_mm512_set1_pd(e),v.m512d,m512d); -#endif return *this; } AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { -#if __SIMD__==2 //-mavx -mno-avx2 - m512d = _mm512_add_pd(_mm512_mul_pd(v.m512d,_mm512_set1_pd(e)),m512d); -#else m512d = _mm512_fmadd_pd(v.m512d,_mm512_set1_pd(e),m512d); -#endif return *this; } diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index a58164e1df..5ce8f3e53f 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -205,7 +205,4 @@ AutoSIMD operator/(const scalar_t &e, return r; } - -//template typedef struct AutoSIMD AutoSIMD; - #endif // MFEM_TEMPLATE_CONFIG_SIMD_M64 diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index 71af1a7099..bf9d9b3b30 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -12,27 +12,8 @@ #ifndef MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP #define MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP -#include "assert.h" #include "x86intrin.h" -// **************************************************************************** -// * ifdef switch between SCALAR, SSE, AVX, AVX2, AVX512F -// **************************************************************************** -#ifndef __SSE2__ -#define __SSE2__ 0 -#endif -#ifndef __AVX__ -#define __AVX__ 0 -#endif -#ifndef __AVX2__ -#define __AVX2__ 0 -#endif -#ifndef __AVX512F__ -#define __AVX512F__ 0 -#endif -#define __SIMD__ __SSE2__+__AVX__+__AVX2__+__AVX512F__ - -// ***************************************************************************** template struct AutoSIMD; #include "m64.hpp" diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 708207e8bb..24ebf6ba58 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -46,30 +46,32 @@ #define MFEM_ALIGN_AS(bytes) #endif -// --- X86 or AutoSIMD +// --- AutoSIMD or X86 intrinsics #ifndef MFEM_USE_X86INTRIN #include "simd/auto.hpp" #else #include "simd/x86.hpp" -#endif // MFEM_USE_X86INTRIN +#endif // --- SIMD Traits -#define MFEM_TEMPLATE_BLOCK_SIZE 4 #define MFEM_SIMD_SIZE 32 +#define MFEM_TEMPLATE_BLOCK_SIZE 4 + template struct AutoImplTraits { static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; + static const int align_size = MFEM_SIMD_SIZE; // in bytes static const int batch_size = 1; - + static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); - static const int valign_size = simd_size; - //static const int simd_size = 1; + + static const int valign_size = simd_size; //static const int valign_size = 1; - + typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; #ifndef MFEM_USE_X86INTRIN @@ -77,7 +79,6 @@ struct AutoImplTraits #endif // MFEM_USE_X86INTRIN }; - #define MFEM_TEMPLATE_ENABLE_SERIALIZE // #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS @@ -108,5 +109,4 @@ long long flop_count; #define MFEM_FLOPS_GET() (0) #endif - #endif // MFEM_TEMPLATE_CONFIG diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 644ff4d30b..0142612fea 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -121,7 +121,6 @@ public: virtual ~TBilinearForm() { - //delete [] assembled_data; free(assembled_data); } @@ -196,13 +195,10 @@ public: const int NE = mesh.GetNE(); if (!assembled_data) { - // TODO: How do we make sure that this array is aligned properly, AND - // the compiler knows that it is aligned? - //assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; void* result = nullptr; - const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); + const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); const auto alloc_failed = posix_memalign(&result, 32, size); - if (alloc_failed) throw ::std::bad_alloc(); + if (alloc_failed) { throw ::std::bad_alloc(); } assembled_data = (p_assembled_t*) result; } for (int el = 0; el < NE; el += TE) From 299e555cf73d1f8ae6a0498c54ad8fefb1753112 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 19 Jun 2018 15:16:24 -0700 Subject: [PATCH 011/535] [x86] INSTALL and force inline for the auto class --- INSTALL | 5 +- config/simd/auto.hpp | 81 ++- config/simd/m64.hpp | 1 - fem/tevaluator.hpp | 62 +-- miniapps/performance/bp1p.cpp | 706 +++++++++++++++++++++++++ miniapps/performance/ex1.cpp | 4 +- miniapps/performance/hex-02x01x01.mesh | 9 + 7 files changed, 805 insertions(+), 63 deletions(-) create mode 100644 miniapps/performance/bp1p.cpp create mode 100644 miniapps/performance/hex-02x01x01.mesh diff --git a/INSTALL b/INSTALL index 26ce3644cd..506f3ba21b 100644 --- a/INSTALL +++ b/INSTALL @@ -336,8 +336,9 @@ MFEM_USE_SIDRE = YES/NO specification. When enabled, this option requires installation of HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project. -MFEM_USE_X86INTRIN = YES/NO - X86 intrinsics will be used. +MFEM_USE_X86INTRIN = YES/NO + Enables the high performance templated classes to use X86 intrinsics + instead of the AutoSIMD (config/simd/auto.hpp) classe. MFEM_USE_CONDUIT = YES/NO Enables support for converting MFEM Mesh and Grid Function objects to and diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index 5a77455f59..8dce51849e 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -21,71 +21,81 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD scalar_t vec[size]; - scalar_t &operator[](int i) { return vec[i]; } - const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } - AutoSIMD &operator=(const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = v[i]; } return *this; } - AutoSIMD &operator=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e; } return *this; } - AutoSIMD &operator+=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i]; } return *this; } - AutoSIMD &operator+=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e; } return *this; } - AutoSIMD &operator-=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] -= v[i]; } return *this; } - AutoSIMD &operator-=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] -= e; } return *this; } - AutoSIMD &operator*=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] *= v[i]; } return *this; } - AutoSIMD &operator*=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] *= e; } return *this; } - AutoSIMD &operator/=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] /= v[i]; } return *this; } - AutoSIMD &operator/=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] /= e; } return *this; } - AutoSIMD operator-() const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -93,56 +103,63 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return r; } - AutoSIMD operator+(const AutoSIMD &v) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] + v[i]; } return r; } - AutoSIMD operator+(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] + e; } return r; } - AutoSIMD operator-(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] - v[i]; } return r; } - AutoSIMD operator-(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] - e; } return r; } - AutoSIMD operator*(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] * v[i]; } return r; } - AutoSIMD operator*(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] * e; } return r; } - AutoSIMD operator/(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { r[i] = vec[i] / v[i]; } return r; } - AutoSIMD operator/(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -150,38 +167,42 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return r; } - AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i] * w[i]; } return *this; } - AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } return *this; } - AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e * v[i]; } return *this; } - AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = v[i] * w[i]; } return *this; } - AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } return *this; } - AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e * v[i]; } @@ -190,6 +211,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD }; template +inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { @@ -200,6 +222,7 @@ AutoSIMD operator+(const scalar_t &e, } template +inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { @@ -209,7 +232,9 @@ AutoSIMD operator-(const scalar_t &e, return r; } +// warning: always_inline function might not be inlinable template +inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { @@ -219,7 +244,9 @@ AutoSIMD operator*(const scalar_t &e, return r; } +//warning: always_inline function might not be inlinable template +inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index 5ce8f3e53f..03c09beb69 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -170,7 +170,6 @@ AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { AutoSIMD r; - MFEM_VECTORIZE_LOOP r[0] = e + v[0]; return r; } diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 987b3226b3..948d54dfdf 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -58,7 +58,7 @@ public: // dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { @@ -81,7 +81,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { @@ -103,7 +103,7 @@ public: // dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGrad(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const grad_layout_t &grad_layout, @@ -129,7 +129,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGradT(const grad_layout_t &grad_layout, const grad_data_t &grad_data, const dof_layout_t &dof_layout, @@ -154,7 +154,7 @@ public: // qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const M_layout_t &M_layout, M_data_t &M_data) const { @@ -178,7 +178,7 @@ public: // D_layout is (DOF x DOF x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void AssembleGradGrad(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const D_layout_t &D_layout, @@ -225,7 +225,7 @@ public: // dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { @@ -239,7 +239,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { @@ -252,7 +252,7 @@ public: // dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGrad(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const grad_layout_t &grad_layout, @@ -269,7 +269,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGradT(const grad_layout_t &grad_layout, const grad_data_t &grad_data, const dof_layout_t &dof_layout, @@ -286,7 +286,7 @@ public: // qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const M_layout_t &M_layout, M_data_t &M_data) const { @@ -310,7 +310,7 @@ public: // D_layout is (DOF x DOF x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void AssembleGradGrad(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const D_layout_t &D_layout, @@ -349,7 +349,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { @@ -372,7 +372,7 @@ public: // dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { @@ -382,7 +382,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { @@ -406,7 +406,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { @@ -417,7 +417,7 @@ public: // dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGrad(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const grad_layout_t &grad_layout, @@ -435,7 +435,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGradT(const grad_layout_t &grad_layout, const grad_data_t &grad_data, const dof_layout_t &dof_layout, @@ -451,7 +451,7 @@ public: // qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const M_layout_t &M_layout, M_data_t &M_data) const { @@ -514,7 +514,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const D_layout_t &D_layout, @@ -545,7 +545,7 @@ public: // D_layout is (TDOF x TDOF x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void AssembleGradGrad(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const D_layout_t &D_layout, @@ -629,7 +629,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { @@ -656,7 +656,7 @@ public: // dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const { @@ -666,7 +666,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { @@ -694,7 +694,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const dof_layout_t &dof_layout, dof_data_t &dof_data) const { @@ -705,7 +705,7 @@ public: // dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGrad(const dof_layout_t &dof_layout, const dof_data_t &dof_data, const grad_layout_t &grad_layout, @@ -727,7 +727,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void CalcGradT(const grad_layout_t &grad_layout, const grad_data_t &grad_data, const dof_layout_t &dof_layout, @@ -745,7 +745,7 @@ public: // qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const M_layout_t &M_layout, M_data_t &M_data) const { @@ -796,7 +796,7 @@ public: template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const D_layout_t &D_layout, @@ -833,7 +833,7 @@ public: #if 0 template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void Assemble(int D1, int D2, const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, @@ -873,7 +873,7 @@ public: // D_layout is (TDOF x TDOF x NumComp). template - MFEM_ALWAYS_INLINE + inline MFEM_ALWAYS_INLINE void AssembleGradGrad(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data, const D_layout_t &D_layout, diff --git a/miniapps/performance/bp1p.cpp b/miniapps/performance/bp1p.cpp new file mode 100644 index 0000000000..e8ba9735c2 --- /dev/null +++ b/miniapps/performance/bp1p.cpp @@ -0,0 +1,706 @@ +// ***************************************************************************** +// Description: BP1 benchmark (from CEED Bake-off Problems) +// test the performance of high-order mass matrix operator +// evaluation with "partial assembly" algorithms. +// ***************************************************************************** + +#include "mfem-performance.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +// ***************************************************************************** +#define GEOM Geometry::CUBE +#define MESH_P 3 +#define SOL_P 3 +#define IR_ORDER 0 +#define IR_TYPE 0 +#define PROBLEM 1 +#define USE_MPI_WTIME +#define VDIM 1 +#define VEC_LAYOUT Ordering::byVDIM + + +IntegrationRules GaussLobattoRules(0, Quadrature1D::GaussLobatto); + +template +class GaussLobattoIntegrationRule + : public TProductIntegrationRule +{ +public: + typedef TProductIntegrationRule base_class; + + using base_class::geom; + using base_class::order; + using base_class::qpts_1d; + +protected: + using base_class::weights_1d; + +public: + GaussLobattoIntegrationRule() + { + const IntegrationRule &ir_1d = Get1DIntRule(); + MFEM_ASSERT(ir_1d.GetNPoints() == qpts_1d, "quadrature rule mismatch"); + for (int j = 0; j < qpts_1d; j++) + { + weights_1d.data[j] = ir_1d.IntPoint(j).weight; + } + } + + static const IntegrationRule &Get1DIntRule() + { + return GaussLobattoRules.Get(Geometry::SEGMENT, order); + } + static const IntegrationRule &GetIntRule() + { + return GaussLobattoRules.Get(geom, order); + } +}; + + +// Define template parameters for optimized build. +const Geometry::Type geom = GEOM; // mesh elements (default: hex) +const int mesh_p = MESH_P; // mesh curvature (default: 3) +const int sol_p = SOL_P; // solution order (default: 3) +const int ir_q = IR_TYPE ? sol_p+1 : sol_p+2; +const int ir_order = IR_ORDER ? IR_ORDER : + (IR_TYPE ? 2*ir_q-3 : 2*ir_q-1); + +// Static mesh type +typedef H1_FiniteElement mesh_fe_t; +typedef H1_FiniteElementSpace mesh_fes_t; +typedef TMesh mesh_t; + +// Static solution finite element space type +typedef H1_FiniteElement sol_fe_t; +typedef H1_FiniteElementSpace sol_fes_t; + +// Static quadrature, coefficient and integrator types +#if (IR_TYPE == 0) +typedef TIntegrationRule int_rule_t; +#else +const int rdim = Geometry::Constants::Dimension; +typedef GaussLobattoIntegrationRule +int_rule_t; +#endif +typedef TConstantCoefficient<> coeff_t; +#if (PROBLEM == 0) +typedef TIntegrator integ_t; +#else +typedef TIntegrator integ_t; +#endif +#if (VDIM == 1) +typedef ScalarLayout vec_layout_t; +#else +typedef VectorLayout vec_layout_t; +#endif + +// Static bilinear form type, combining the above types +typedef TBilinearForm HPCBilinearForm; + +int main(int argc, char *argv[]) +{ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + const int vdim = VDIM; + const Ordering::Type ordering = VEC_LAYOUT; // for solution space only + + // 2. Parse command-line options. + const char *mesh_file = "../../data/fichera.mesh"; + int ser_ref_levels = -1; + int par_ref_levels = +1; + Array nxyz; + int order = sol_p; + const char *basis_type = "G"; // Gauss-Lobatto + bool static_cond = false; + const char *pc = "none";//"lor"; + bool perf = true; + bool matrix_free = true; + int max_iter = 50; + bool visualization = 1; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", + "Number of times to refine the mesh uniformly in serial."); + args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", + "Number of times to refine the mesh uniformly in parallel."); + args.AddOption(&nxyz, "-c", "--cartesian-partitioning", + "Use Cartesian partitioning."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&basis_type, "-b", "--basis-type", + "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); + args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", + "Enable high-performance, tensor-based, assembly/evaluation."); + args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", + "Use matrix-free evaluation or efficient matrix assembly in " + "the high-performance version."); + args.AddOption(&pc, "-pc", "--preconditioner", + "Preconditioner: lor - low-order-refined (matrix-free) AMG, " + "ho - high-order (assembled) AMG, none."); + args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", + "--no-static-condensation", "Enable static condensation."); + args.AddOption(&max_iter, "-mi", "--max-iter", + "Maximum number of iterations."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + if (myid == 0) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + if (static_cond && perf && matrix_free) + { + if (myid == 0) + { + cout << "\nStatic condensation can not be used with matrix-free" + " evaluation!\n" << endl; + } + MPI_Finalize(); + return 2; + } + MFEM_VERIFY(perf || !matrix_free, + "--standard-version is not compatible with --matrix-free"); + if (myid == 0) + { + args.PrintOptions(cout); + } + + enum PCType { NONE, LOR, HO }; + PCType pc_choice; + if (!strcmp(pc, "ho")) { pc_choice = HO; } + else if (!strcmp(pc, "lor")) { pc_choice = LOR; } + else if (!strcmp(pc, "none")) { pc_choice = NONE; } + else + { + mfem_error("Invalid Preconditioner specified"); + return 3; + } + + // See class BasisType in fem/fe_coll.hpp for available basis types + int basis = BasisType::GetType(basis_type[0]); + if (myid == 0) + { + cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; + } + + // 3. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 4. Check if the optimized version matches the given mesh + if (perf) + { + if (myid == 0) + { + cout << "High-performance version using integration rule with " + << int_rule_t::qpts << " points ..." << endl; + cout << "Quadrature rule type: " + << (IR_TYPE == 0 ? "Gauss" : "Gauss-Lobatto") << endl; + } + if (!mesh_t::MatchesGeometry(*mesh)) + { + if (myid == 0) + { + cout << "The given mesh does not match the optimized 'geom' parameter.\n" + << "Recompile with suitable 'geom' value." << endl; + } + delete mesh; + MPI_Finalize(); + return 4; + } + else if (!mesh_t::MatchesNodes(*mesh)) + { + if (myid == 0) + { + cout << "Switching the mesh curvature to match the " + << "optimized value (order " << mesh_p << ") ..." << endl; + } + mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); + } + } + + // 5. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 10,000 elements. + { + int ref_levels = + (int)floor(log(10000./mesh->GetNE())/log(2.)/dim); + ref_levels = (ser_ref_levels != -1) ? ser_ref_levels : ref_levels; + for (int l = 0; l < ref_levels; l++) + { + if (myid == 0) + { + cout << "Serial refinement: level " << l << " -> level " << l+1 + << " ..." << flush; + } + mesh->UniformRefinement(); + MPI_Barrier(MPI_COMM_WORLD); + if (myid == 0) + { + cout << " done." << endl; + } + } + } + if (!perf && mesh->NURBSext) + { + const int new_mesh_p = std::min(sol_p, mesh_p); + if (myid == 0) + { + cout << "NURBS mesh: switching the mesh curvature to be " + << "min(sol_p, mesh_p) = " << new_mesh_p << " ..." << endl; + } + mesh->SetCurvature(new_mesh_p, false, -1, Ordering::byNODES); + } + + // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + MFEM_VERIFY(nxyz.Size() == 0 || nxyz.Size() == mesh->SpaceDimension(), + "Expected " << mesh->SpaceDimension() << " integers with the " + "option --cartesian-partitioning."); + int *partitioning = nxyz.Size() ? mesh->CartesianPartitioning(nxyz) : NULL; + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh, partitioning); + delete [] partitioning; + delete mesh; + { + for (int l = 0; l < par_ref_levels; l++) + { + if (myid == 0) + { + cout << "Parallel refinement: level " << l << " -> level " << l+1 + << " ..." << flush; + } + pmesh->UniformRefinement(); + MPI_Barrier(MPI_COMM_WORLD); + if (myid == 0) + { + cout << " done." << endl; + } + } + } + if (pmesh->MeshGenerator() & 1) // simplex mesh + { + MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" + " the LOR preconditioner yet"); + } + + pmesh->PrintInfo(cout); + + // 7. Define a parallel finite element space on the parallel mesh. Here we + // use continuous Lagrange finite elements of the specified order. If + // order < 1, we instead use an isoparametric/isogeometric space. + FiniteElementCollection *fec; + if (order > 0) + { + fec = new H1_FECollection(order, dim, basis); + } + else if (pmesh->GetNodes()) + { + fec = pmesh->GetNodes()->OwnFEC(); + if (myid == 0) + { + cout << "Using isoparametric FEs: " << fec->Name() << endl; + } + } + else + { + fec = new H1_FECollection(order = 1, dim, basis); + } + ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec, + vdim, ordering); + HYPRE_Int size = fespace->GlobalTrueVSize(); + if (myid == 0) + { + cout << "Number of finite element unknowns: " << size << endl; + } + + ParMesh *pmesh_lor = NULL; + FiniteElementCollection *fec_lor = NULL; + ParFiniteElementSpace *fespace_lor = NULL; + if (pc_choice == LOR) + { + int basis_lor = basis; + if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } + pmesh_lor = new ParMesh(pmesh, order, basis_lor); + fec_lor = new H1_FECollection(1, dim); + fespace_lor = new ParFiniteElementSpace(pmesh_lor, fec_lor, + vdim, ordering); + } + + // 8. Check if the optimized version matches the given space + if (perf && !sol_fes_t::Matches(*fespace)) + { + if (myid == 0) + { + cout << "The given order does not match the optimized parameter.\n" + << "Recompile with suitable 'sol_p' value." << endl; + } + delete fespace; + delete fec; + delete mesh; + MPI_Finalize(); + return 5; + } + + // 9. Determine the list of true (i.e. parallel conforming) essential + // boundary dofs. In this example, the boundary conditions are defined + // by marking all the boundary attributes from the mesh as essential + // (Dirichlet) and converting them to a list of true dofs. + Array ess_tdof_list; + if (pmesh->bdr_attributes.Size()) + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 1; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + + // 10. Set up the parallel linear form b(.) which corresponds to the + // right-hand side of the FEM linear system, which in this case is + // (1,phi_i) where phi_i are the basis functions in fespace. + ParLinearForm *b = new ParLinearForm(fespace); + ConstantCoefficient one(1.0); + Vector uvec(vdim); + for (int i = 0; i < vdim; i++) + { + uvec(i) = i + 1.0; + } + uvec /= uvec.Norml2(); + VectorConstantCoefficient unit_vec(uvec); + if (vdim == 1) + { + b->AddDomainIntegrator(new DomainLFIntegrator(one)); + } + else + { + b->AddDomainIntegrator(new VectorDomainLFIntegrator(unit_vec)); + } + b->Assemble(); + + // 11. Define the solution vector x as a parallel finite element grid + // function corresponding to fespace. Initialize x with initial guess of + // zero, which satisfies the boundary conditions. + ParGridFunction x(fespace); + x = 0.0; + + // 12. Set up the parallel bilinear form a(.,.) on the finite element space + // that will hold the matrix corresponding to the Laplacian operator. + ParBilinearForm *a = new ParBilinearForm(fespace); + ParBilinearForm *a_pc = NULL; + if (pc_choice == LOR) { a_pc = new ParBilinearForm(fespace_lor); } + if (pc_choice == HO) { a_pc = new ParBilinearForm(fespace); } + + // 13. Assemble the parallel bilinear form and the corresponding linear + // system, applying any necessary transformations such as: parallel + // assembly, eliminating boundary conditions, applying conforming + // constraints for non-conforming AMR, static condensation, etc. + if (static_cond) + { + a->EnableStaticCondensation(); + MFEM_VERIFY(pc_choice != LOR, + "cannot use LOR preconditioner with static condensation"); + } + + if (myid == 0) + { + cout << "Assembling the local matrix ..." << flush; + } +#ifdef USE_MPI_WTIME + double my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + // Pre-allocate sparsity assuming dense element matrices; the actual memory + // allocation happens when a->Assemble() is called. + a->UsePrecomputedSparsity(); + + HPCBilinearForm *a_hpc = NULL; + Operator *a_oper = NULL; + + if (!perf) + { + // Standard assembly using a diffusion domain integrator + if (vdim == 1) + { + a->AddDomainIntegrator(new DiffusionIntegrator(one)); + } + else + { + a->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); + } + a->Assemble(); + } + else + { + // High-performance assembly/evaluation using the templated operator type + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (matrix_free) + { + a_hpc->Assemble(); // partial assembly + } + else + { + a_hpc->AssembleBilinearForm(*a); // full matrix assembly + } + } +#ifdef USE_MPI_WTIME + double rt_min, rt_max, my_rt; + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + double rt_min, rt_max, my_rt; + my_rt = tic_toc.RealTime(); +#endif + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + cout << " done, " << rt_max << " (" << rt_min << ") s." << endl; + cout << "\n\"DOFs/sec\" in assembly: " + << 1e-6*size/rt_max << " (" + << 1e-6*size/rt_min << ") million.\n" << endl; + } + + // 14. Define and apply a parallel PCG solver for AX=B with the BoomerAMG + // preconditioner from hypre. + + // Setup the operator matrix (if applicable) + HypreParMatrix A; + Vector B, X; + if (myid == 0) + { + cout << "FormLinearSystem() ..." << endl; + } +#ifdef USE_MPI_WTIME + my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + if (perf && matrix_free) + { + a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + if (myid == 0) + { + cout << "Size of linear system: " << size << endl; + } + } + else + { + a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + HYPRE_Int glob_size = A.GetGlobalNumRows(); + HYPRE_Int glob_nnz = A.NNZ(); + if (myid == 0) + { + cout << "Size of linear system: " << glob_size << endl; + cout << "Average nonzero entries per row: " + << 1.0*glob_nnz/glob_size << endl; + } + a_oper = &A; + } +#ifdef USE_MPI_WTIME + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + my_rt = tic_toc.RealTime(); +#endif + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + cout << "FormLinearSystem() ... done, " << rt_max << " (" << rt_min + << ") s." << endl; + cout << "\n\"DOFs/sec\" in FormLinearSystem(): " + << 1e-6*size/rt_max << " (" + << 1e-6*size/rt_min << ") million.\n" << endl; + } + + // Setup the matrix used for preconditioning + if (myid == 0) + { + cout << "Assembling the preconditioning matrix ..." << flush; + } +#ifdef USE_MPI_WTIME + my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + + HypreParMatrix A_pc; + if (pc_choice == LOR) + { + // TODO: assemble the LOR matrix using the performance code + if (vdim == 1) + { + a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); + } + else + { + a_pc->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); + } + a_pc->UsePrecomputedSparsity(); + a_pc->Assemble(); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + else if (pc_choice == HO) + { + if (!matrix_free) + { + A_pc.MakeRef(A); // matrix already assembled, reuse it + } + else + { + a_pc->UsePrecomputedSparsity(); + a_hpc->AssembleBilinearForm(*a_pc); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + } +#ifdef USE_MPI_WTIME + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + my_rt = tic_toc.RealTime(); +#endif + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + cout << " done, " << rt_max << "s." << endl; + } + + // Solve with CG or PCG, depending if the matrix A_pc is available + CGSolver *pcg; + pcg = new CGSolver(MPI_COMM_WORLD); + pcg->SetRelTol(1e-6); + pcg->SetMaxIter(max_iter); + pcg->SetPrintLevel(3); + + HypreSolver *amg = NULL; + + pcg->SetOperator(*a_oper); + if (pc_choice != NONE) + { + HypreBoomerAMG *bamg = new HypreBoomerAMG(A_pc); + if (vdim > 1 && ordering == Ordering::byVDIM) + { + bamg->SetSystemsOptions(vdim); + } + amg = bamg; + pcg->SetPreconditioner(*amg); + } + +#ifdef USE_MPI_WTIME + my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + + pcg->Mult(B, X); + +#ifdef USE_MPI_WTIME + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + my_rt = tic_toc.RealTime(); +#endif + delete amg; + + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + const int cg_num_iterations = pcg->GetNumIterations(); + // Note: In the pcg algorithm, the number of operator Mult() calls is + // N_iter and the number of preconditioner Mult() calls is N_iter+1. + cout << "Total CG time: " << rt_max << " (" << rt_min << ") sec." + << endl; + cout << "CG number of iterations: " << cg_num_iterations << endl; + cout << "Time per CG step: " + << rt_max / cg_num_iterations << " (" + << rt_min / cg_num_iterations << ") sec." << endl; + cout << "\n\"DOFs/sec\" in CG: " + << 1e-6*size*cg_num_iterations/rt_max << " (" + << 1e-6*size*cg_num_iterations/rt_min << ") million.\n" + << endl; + } + + // 15. Recover the parallel grid function corresponding to X. This is the + // local finite element solution on each processor. + if (perf && matrix_free) + { + a_hpc->RecoverFEMSolution(X, *b, x); + } + else + { + a->RecoverFEMSolution(X, *b, x); + } + + // 16. Save the refined mesh and the solution in parallel. This output can + // be viewed later using GLVis: "glvis -np -m mesh -g sol". + if (false) + { + ostringstream mesh_name, sol_name; + mesh_name << "mesh." << setfill('0') << setw(6) << myid; + sol_name << "sol." << setfill('0') << setw(6) << myid; + + ofstream mesh_ofs(mesh_name.str().c_str()); + mesh_ofs.precision(8); + pmesh->Print(mesh_ofs); + + ofstream sol_ofs(sol_name.str().c_str()); + sol_ofs.precision(8); + x.Save(sol_ofs); + } + + // 17. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock << "parallel " << num_procs << " " << myid << "\n"; + sol_sock.precision(8); + sol_sock << "solution\n" << *pmesh << x << flush; + } + + // 18. Free the used memory. + delete a; + delete a_hpc; + if (a_oper != &A) { delete a_oper; } + delete a_pc; + delete b; + delete fespace; + delete fespace_lor; + delete fec_lor; + delete pmesh_lor; + if (order > 0) { delete fec; } + delete pmesh; + delete pcg; + + MPI_Finalize(); + + return 0; +} diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index ccfc61d371..46a2a0c30c 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -38,8 +38,8 @@ using namespace mfem; // Define template parameters for optimized build. const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 3; // mesh curvature (default: 3) -const int sol_p = 3; // solution order (default: 3) +const int mesh_p = 6; // mesh curvature (default: 3) +const int sol_p = 6; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; diff --git a/miniapps/performance/hex-02x01x01.mesh b/miniapps/performance/hex-02x01x01.mesh new file mode 100644 index 0000000000..8e1c73c926 --- /dev/null +++ b/miniapps/performance/hex-02x01x01.mesh @@ -0,0 +1,9 @@ +MFEM INLINE mesh v1.0 + +type = hex +nx = 2 +ny = 1 +nz = 1 +sx = 1.0 +sy = 1.0 +sz = 1.0 From 0f9a7feefb96ddaf15dad691a3fa035b05d2f6ec Mon Sep 17 00:00:00 2001 From: camierjs Date: Thu, 21 Jun 2018 17:11:05 -0700 Subject: [PATCH 012/535] [x86] - MFEM_USE_X86INTRIN makefile if for GCC's param max-completely-peel-times option - Brought bp1p from github.com/CEED/benchmarks/blob/master/tests/mfem_bps to test the kernels --- .../inline-hex-2x1x1.mesh | 0 miniapps/performance/bp1p.cpp | 49 ++- miniapps/performance/ex1.cpp | 405 ------------------ miniapps/performance/makefile | 4 +- 4 files changed, 42 insertions(+), 416 deletions(-) rename miniapps/performance/hex-02x01x01.mesh => data/inline-hex-2x1x1.mesh (100%) delete mode 100644 miniapps/performance/ex1.cpp diff --git a/miniapps/performance/hex-02x01x01.mesh b/data/inline-hex-2x1x1.mesh similarity index 100% rename from miniapps/performance/hex-02x01x01.mesh rename to data/inline-hex-2x1x1.mesh diff --git a/miniapps/performance/bp1p.cpp b/miniapps/performance/bp1p.cpp index e8ba9735c2..fec890c4f5 100644 --- a/miniapps/performance/bp1p.cpp +++ b/miniapps/performance/bp1p.cpp @@ -2,6 +2,9 @@ // Description: BP1 benchmark (from CEED Bake-off Problems) // test the performance of high-order mass matrix operator // evaluation with "partial assembly" algorithms. +// +// More details about CEED's bake-off problems can be found at +// http://ceed.exascaleproject.org/bps. // ***************************************************************************** #include "mfem-performance.hpp" @@ -12,16 +15,42 @@ using namespace std; using namespace mfem; // ***************************************************************************** +#ifndef GEOM #define GEOM Geometry::CUBE -#define MESH_P 3 -#define SOL_P 3 -#define IR_ORDER 0 -#define IR_TYPE 0 -#define PROBLEM 1 -#define USE_MPI_WTIME -#define VDIM 1 -#define VEC_LAYOUT Ordering::byVDIM +#endif +#ifndef MESH_P +#define MESH_P 3 +#endif + +#ifndef SOL_P +#define SOL_P 3 +#endif + +#ifndef IR_ORDER +#define IR_ORDER 0 +#endif + +#ifndef IR_TYPE +// 0 - Gauss quadrature, 1 - Gauss-Lobatto quadrature +#define IR_TYPE 0 +#endif + +// 0 - TDiffusionKernel, else TMassKernel +#ifndef PROBLEM +#define PROBLEM 0 +#endif + +#ifndef VDIM +#define VDIM 1 +#endif + +// This vector layout is used for the solution space only. +#ifndef VEC_LAYOUT +#define VEC_LAYOUT Ordering::byVDIM +#endif + +#define USE_MPI_WTIME IntegrationRules GaussLobattoRules(0, Quadrature1D::GaussLobatto); @@ -114,14 +143,14 @@ int main(int argc, char *argv[]) const Ordering::Type ordering = VEC_LAYOUT; // for solution space only // 2. Parse command-line options. - const char *mesh_file = "../../data/fichera.mesh"; + const char *mesh_file = "../../data/inline-hex-2x1x1.mesh"; int ser_ref_levels = -1; int par_ref_levels = +1; Array nxyz; int order = sol_p; const char *basis_type = "G"; // Gauss-Lobatto bool static_cond = false; - const char *pc = "none";//"lor"; + const char *pc = "none"; bool perf = true; bool matrix_free = true; int max_iter = 50; diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp deleted file mode 100644 index 46a2a0c30c..0000000000 --- a/miniapps/performance/ex1.cpp +++ /dev/null @@ -1,405 +0,0 @@ -// MFEM Example 1 - High-Performance Version -// -// Compile with: make ex1 -// -// Sample runs: ex1 -m ../../data/fichera.mesh -perf -mf -pc lor -// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho -// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho -sc -// ex1 -m ../../data/fichera.mesh -std -asm -pc ho -// ex1 -m ../../data/fichera.mesh -std -asm -pc ho -sc -// ex1 -m ../../data/amr-hex.mesh -perf -asm -pc ho -sc -// ex1 -m ../../data/amr-hex.mesh -std -asm -pc ho -sc -// ex1 -m ../../data/ball-nurbs.mesh -perf -asm -pc ho -sc -// ex1 -m ../../data/ball-nurbs.mesh -std -asm -pc ho -sc -// ex1 -m ../../data/pipe-nurbs.mesh -perf -mf -pc lor -// ex1 -m ../../data/pipe-nurbs.mesh -std -asm -pc ho -sc -// -// Description: This example code demonstrates the use of MFEM to define a -// simple finite element discretization of the Laplace problem -// -Delta u = 1 with homogeneous Dirichlet boundary conditions. -// Specifically, we discretize using a FE space of the specified -// order, or if order < 1 using an isoparametric/isogeometric -// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for -// NURBS mesh, etc.) -// -// The example highlights the use of mesh refinement, finite -// element grid functions, as well as linear and bilinear forms -// corresponding to the left-hand side and right-hand side of the -// discrete linear system. We also cover the explicit elimination -// of essential boundary conditions, static condensation, and the -// optional connection to the GLVis tool for visualization. - -#include "mfem-performance.hpp" -#include -#include - -using namespace std; -using namespace mfem; - -// Define template parameters for optimized build. -const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 6; // mesh curvature (default: 3) -const int sol_p = 6; // solution order (default: 3) -const int rdim = Geometry::Constants::Dimension; -const int ir_order = 2*sol_p+rdim-1; - -// Static mesh type -typedef H1_FiniteElement mesh_fe_t; -typedef H1_FiniteElementSpace mesh_fes_t; -typedef TMesh mesh_t; - -// Static solution finite element space type -typedef H1_FiniteElement sol_fe_t; -typedef H1_FiniteElementSpace sol_fes_t; - -// Static quadrature, coefficient and integrator types -typedef TIntegrationRule int_rule_t; -typedef TConstantCoefficient<> coeff_t; -typedef TIntegrator integ_t; - -// Static bilinear form type, combining the above types -typedef TBilinearForm HPCBilinearForm; - -int main(int argc, char *argv[]) -{ - // 1. Parse command-line options. - const char *mesh_file = "../../data/fichera.mesh"; - int ref_levels = -1; - int order = sol_p; - const char *basis_type = "G"; // Gauss-Lobatto - bool static_cond = false; - const char *pc = "none"; - bool perf = true; - bool matrix_free = true; - bool visualization = 1; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&ref_levels, "-r", "--refine", - "Number of times to refine the mesh uniformly;" - " -1 = auto: <= 50,000 elements."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); - args.AddOption(&basis_type, "-b", "--basis-type", - "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); - args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", - "Enable high-performance, tensor-based, assembly/evaluation."); - args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", - "Use matrix-free evaluation or efficient matrix assembly in " - "the high-performance version."); - args.AddOption(&pc, "-pc", "--preconditioner", - "Preconditioner: lor - low-order-refined (matrix-free) GS, " - "ho - high-order (assembled) GS, none."); - args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", - "--no-static-condensation", "Enable static condensation."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - if (!args.Good()) - { - args.PrintUsage(cout); - return 1; - } - if (static_cond && perf && matrix_free) - { - cout << "\nStatic condensation can not be used with matrix-free" - " evaluation!\n" << endl; - return 2; - } - MFEM_VERIFY(perf || !matrix_free, - "--standard-version is not compatible with --matrix-free"); - args.PrintOptions(cout); - - enum PCType { NONE, LOR, HO }; - PCType pc_choice; - if (!strcmp(pc, "ho")) { pc_choice = HO; } - else if (!strcmp(pc, "lor")) { pc_choice = LOR; } - else if (!strcmp(pc, "none")) { pc_choice = NONE; } - else - { - mfem_error("Invalid Preconditioner specified"); - return 3; - } - - // See class BasisType in fem/fe_coll.hpp for available basis types - int basis = BasisType::GetType(basis_type[0]); - cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; - - // 2. Read the mesh from the given mesh file. We can handle triangular, - // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with - // the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - int dim = mesh->Dimension(); - - // 3. Check if the optimized version matches the given mesh - if (perf) - { - cout << "High-performance version using integration rule with " - << int_rule_t::qpts << " points ..." << endl; - if (!mesh_t::MatchesGeometry(*mesh)) - { - cout << "The given mesh does not match the optimized 'geom' parameter.\n" - << "Recompile with suitable 'geom' value." << endl; - delete mesh; - return 4; - } - else if (!mesh_t::MatchesNodes(*mesh)) - { - cout << "Switching the mesh curvature to match the " - << "optimized value (order " << mesh_p << ") ..." << endl; - mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); - } - } - - // 4. Refine the mesh to increase the resolution. In this example we do - // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the - // largest number that gives a final mesh with no more than 50,000 - // elements, or as specified on the command line with the option - // '--refine'. - { - ref_levels = (ref_levels != -1) ? ref_levels : - (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); - for (int l = 0; l < ref_levels; l++) - { - mesh->UniformRefinement(); - } - } - if (mesh->MeshGenerator() & 1) // simplex mesh - { - MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" - " the LOR preconditioner yet"); - } - - // 5. Define a finite element space on the mesh. Here we use continuous - // Lagrange finite elements of the specified order. If order < 1, we - // instead use an isoparametric/isogeometric space. - FiniteElementCollection *fec; - if (order > 0) - { - fec = new H1_FECollection(order, dim, basis); - } - else if (mesh->GetNodes()) - { - fec = mesh->GetNodes()->OwnFEC(); - cout << "Using isoparametric FEs: " << fec->Name() << endl; - } - else - { - fec = new H1_FECollection(order = 1, dim, basis); - } - FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); - cout << "Number of finite element unknowns: " - << fespace->GetTrueVSize() << endl; - - // Create the LOR mesh and finite element space. In the settings of this - // example, we can transfer between HO and LOR with the identity operator. - Mesh *mesh_lor = NULL; - FiniteElementCollection *fec_lor = NULL; - FiniteElementSpace *fespace_lor = NULL; - if (pc_choice == LOR) - { - int basis_lor = basis; - if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } - mesh_lor = new Mesh(mesh, order, basis_lor); - fec_lor = new H1_FECollection(1, dim); - fespace_lor = new FiniteElementSpace(mesh_lor, fec_lor); - } - - // 6. Check if the optimized version matches the given space - if (perf && !sol_fes_t::Matches(*fespace)) - { - cout << "The given order does not match the optimized parameter.\n" - << "Recompile with suitable 'sol_p' value." << endl; - delete fespace; - delete fec; - delete mesh; - return 5; - } - - // 7. Determine the list of true (i.e. conforming) essential boundary dofs. - // In this example, the boundary conditions are defined by marking all - // the boundary attributes from the mesh as essential (Dirichlet) and - // converting them to a list of true dofs. - Array ess_tdof_list; - if (mesh->bdr_attributes.Size()) - { - Array ess_bdr(mesh->bdr_attributes.Max()); - ess_bdr = 1; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - - // 8. Set up the linear form b(.) which corresponds to the right-hand side of - // the FEM linear system, which in this case is (1,phi_i) where phi_i are - // the basis functions in the finite element fespace. - LinearForm *b = new LinearForm(fespace); - ConstantCoefficient one(1.0); - b->AddDomainIntegrator(new DomainLFIntegrator(one)); - b->Assemble(); - - // 9. Define the solution vector x as a finite element grid function - // corresponding to fespace. Initialize x with initial guess of zero, - // which satisfies the boundary conditions. - GridFunction x(fespace); - x = 0.0; - - // 10. Set up the bilinear form a(.,.) on the finite element space that will - // hold the matrix corresponding to the Laplacian operator -Delta. - // Optionally setup a form to be assembled for preconditioning (a_pc). - BilinearForm *a = new BilinearForm(fespace); - BilinearForm *a_pc = NULL; - if (pc_choice == LOR) { a_pc = new BilinearForm(fespace_lor); } - if (pc_choice == HO) { a_pc = new BilinearForm(fespace); } - - // 11. Assemble the bilinear form and the corresponding linear system, - // applying any necessary transformations such as: eliminating boundary - // conditions, applying conforming constraints for non-conforming AMR, - // static condensation, etc. - if (static_cond) - { - a->EnableStaticCondensation(); - MFEM_VERIFY(pc_choice != LOR, - "cannot use LOR preconditioner with static condensation"); - } - - cout << "Assembling the bilinear form ..." << flush; - tic_toc.Clear(); - tic_toc.Start(); - // Pre-allocate sparsity assuming dense element matrices - a->UsePrecomputedSparsity(); - - HPCBilinearForm *a_hpc = NULL; - Operator *a_oper = NULL; - - if (!perf) - { - // Standard assembly using a diffusion domain integrator - a->AddDomainIntegrator(new DiffusionIntegrator(one)); - a->Assemble(); - } - else - { - // High-performance assembly/evaluation using the templated operator type - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - if (matrix_free) - { - a_hpc->Assemble(); // partial assembly - } - else - { - a_hpc->AssembleBilinearForm(*a); // full matrix assembly - } - } - tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; - - // 12. Solve the system A X = B with CG. In the standard case, use a simple - // symmetric Gauss-Seidel preconditioner. - - // Setup the operator matrix (if applicable) - SparseMatrix A; - Vector B, X; - if (perf && matrix_free) - { - a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "Size of linear system: " << a_hpc->Height() << endl; - } - else - { - a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cout << "Size of linear system: " << A.Height() << endl; - a_oper = &A; - } - - // Setup the matrix used for preconditioning - cout << "Assembling the preconditioning matrix ..." << flush; - tic_toc.Clear(); - tic_toc.Start(); - - SparseMatrix A_pc; - if (pc_choice == LOR) - { - // TODO: assemble the LOR matrix using the performance code - a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); - a_pc->UsePrecomputedSparsity(); - a_pc->Assemble(); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - else if (pc_choice == HO) - { - if (!matrix_free) - { - A_pc.MakeRef(A); // matrix already assembled, reuse it - } - else - { - a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - } - - tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; - - // Solve with CG or PCG, depending if the matrix A_pc is available - tic_toc.Clear(); - tic_toc.Start(); - if (pc_choice != NONE) - { - GSSmoother M(A_pc); - PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); - } - else - { - CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); - } - tic_toc.Stop(); - cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; - - // 13. Recover the solution as a finite element grid function. - if (perf && matrix_free) - { - a_hpc->RecoverFEMSolution(X, *b, x); - } - else - { - a->RecoverFEMSolution(X, *b, x); - } - - // 14. Save the refined mesh and the solution. This output can be viewed later - // using GLVis: "glvis -m refined.mesh -g sol.gf". - ofstream mesh_ofs("refined.mesh"); - mesh_ofs.precision(8); - mesh->Print(mesh_ofs); - ofstream sol_ofs("sol.gf"); - sol_ofs.precision(8); - x.Save(sol_ofs); - - // 15. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock.precision(8); - sol_sock << "solution\n" << *mesh << x << flush; - } - - // 16. Free the used memory. - delete a; - delete a_hpc; - if (a_oper != &A) { delete a_oper; } - delete a_pc; - delete b; - delete fespace; - delete fespace_lor; - delete fec_lor; - delete mesh_lor; - if (order > 0) { delete fec; } - delete mesh; - - return 0; -} diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 67d8810c1f..dc79da529e 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -47,7 +47,9 @@ endif # MFEM_PERF_CXXFLAGS_gcc_common += -std=c++03 MFEM_PERF_CXXFLAGS_gcc_common += -std=c++11 MFEM_PERF_CXXFLAGS_gcc_common += -pedantic -Wall -#MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 +ifeq ($(MFEM_USE_X86INTRIN),NO) +MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 +endif #MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ From 5d7177f044700d3e6d835797ca0465ec6770b420 Mon Sep 17 00:00:00 2001 From: camierjs Date: Thu, 21 Jun 2018 17:27:34 -0700 Subject: [PATCH 013/535] [x86] miss miniapps/performance/ex1.cpp --- miniapps/performance/ex1.cpp | 405 +++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 miniapps/performance/ex1.cpp diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp new file mode 100644 index 0000000000..46a2a0c30c --- /dev/null +++ b/miniapps/performance/ex1.cpp @@ -0,0 +1,405 @@ +// MFEM Example 1 - High-Performance Version +// +// Compile with: make ex1 +// +// Sample runs: ex1 -m ../../data/fichera.mesh -perf -mf -pc lor +// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho +// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho -sc +// ex1 -m ../../data/fichera.mesh -std -asm -pc ho +// ex1 -m ../../data/fichera.mesh -std -asm -pc ho -sc +// ex1 -m ../../data/amr-hex.mesh -perf -asm -pc ho -sc +// ex1 -m ../../data/amr-hex.mesh -std -asm -pc ho -sc +// ex1 -m ../../data/ball-nurbs.mesh -perf -asm -pc ho -sc +// ex1 -m ../../data/ball-nurbs.mesh -std -asm -pc ho -sc +// ex1 -m ../../data/pipe-nurbs.mesh -perf -mf -pc lor +// ex1 -m ../../data/pipe-nurbs.mesh -std -asm -pc ho -sc +// +// Description: This example code demonstrates the use of MFEM to define a +// simple finite element discretization of the Laplace problem +// -Delta u = 1 with homogeneous Dirichlet boundary conditions. +// Specifically, we discretize using a FE space of the specified +// order, or if order < 1 using an isoparametric/isogeometric +// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for +// NURBS mesh, etc.) +// +// The example highlights the use of mesh refinement, finite +// element grid functions, as well as linear and bilinear forms +// corresponding to the left-hand side and right-hand side of the +// discrete linear system. We also cover the explicit elimination +// of essential boundary conditions, static condensation, and the +// optional connection to the GLVis tool for visualization. + +#include "mfem-performance.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +// Define template parameters for optimized build. +const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) +const int mesh_p = 6; // mesh curvature (default: 3) +const int sol_p = 6; // solution order (default: 3) +const int rdim = Geometry::Constants::Dimension; +const int ir_order = 2*sol_p+rdim-1; + +// Static mesh type +typedef H1_FiniteElement mesh_fe_t; +typedef H1_FiniteElementSpace mesh_fes_t; +typedef TMesh mesh_t; + +// Static solution finite element space type +typedef H1_FiniteElement sol_fe_t; +typedef H1_FiniteElementSpace sol_fes_t; + +// Static quadrature, coefficient and integrator types +typedef TIntegrationRule int_rule_t; +typedef TConstantCoefficient<> coeff_t; +typedef TIntegrator integ_t; + +// Static bilinear form type, combining the above types +typedef TBilinearForm HPCBilinearForm; + +int main(int argc, char *argv[]) +{ + // 1. Parse command-line options. + const char *mesh_file = "../../data/fichera.mesh"; + int ref_levels = -1; + int order = sol_p; + const char *basis_type = "G"; // Gauss-Lobatto + bool static_cond = false; + const char *pc = "none"; + bool perf = true; + bool matrix_free = true; + bool visualization = 1; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ref_levels, "-r", "--refine", + "Number of times to refine the mesh uniformly;" + " -1 = auto: <= 50,000 elements."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&basis_type, "-b", "--basis-type", + "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); + args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", + "Enable high-performance, tensor-based, assembly/evaluation."); + args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", + "Use matrix-free evaluation or efficient matrix assembly in " + "the high-performance version."); + args.AddOption(&pc, "-pc", "--preconditioner", + "Preconditioner: lor - low-order-refined (matrix-free) GS, " + "ho - high-order (assembled) GS, none."); + args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", + "--no-static-condensation", "Enable static condensation."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + args.PrintUsage(cout); + return 1; + } + if (static_cond && perf && matrix_free) + { + cout << "\nStatic condensation can not be used with matrix-free" + " evaluation!\n" << endl; + return 2; + } + MFEM_VERIFY(perf || !matrix_free, + "--standard-version is not compatible with --matrix-free"); + args.PrintOptions(cout); + + enum PCType { NONE, LOR, HO }; + PCType pc_choice; + if (!strcmp(pc, "ho")) { pc_choice = HO; } + else if (!strcmp(pc, "lor")) { pc_choice = LOR; } + else if (!strcmp(pc, "none")) { pc_choice = NONE; } + else + { + mfem_error("Invalid Preconditioner specified"); + return 3; + } + + // See class BasisType in fem/fe_coll.hpp for available basis types + int basis = BasisType::GetType(basis_type[0]); + cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; + + // 2. Read the mesh from the given mesh file. We can handle triangular, + // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with + // the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 3. Check if the optimized version matches the given mesh + if (perf) + { + cout << "High-performance version using integration rule with " + << int_rule_t::qpts << " points ..." << endl; + if (!mesh_t::MatchesGeometry(*mesh)) + { + cout << "The given mesh does not match the optimized 'geom' parameter.\n" + << "Recompile with suitable 'geom' value." << endl; + delete mesh; + return 4; + } + else if (!mesh_t::MatchesNodes(*mesh)) + { + cout << "Switching the mesh curvature to match the " + << "optimized value (order " << mesh_p << ") ..." << endl; + mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); + } + } + + // 4. Refine the mesh to increase the resolution. In this example we do + // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the + // largest number that gives a final mesh with no more than 50,000 + // elements, or as specified on the command line with the option + // '--refine'. + { + ref_levels = (ref_levels != -1) ? ref_levels : + (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); + for (int l = 0; l < ref_levels; l++) + { + mesh->UniformRefinement(); + } + } + if (mesh->MeshGenerator() & 1) // simplex mesh + { + MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" + " the LOR preconditioner yet"); + } + + // 5. Define a finite element space on the mesh. Here we use continuous + // Lagrange finite elements of the specified order. If order < 1, we + // instead use an isoparametric/isogeometric space. + FiniteElementCollection *fec; + if (order > 0) + { + fec = new H1_FECollection(order, dim, basis); + } + else if (mesh->GetNodes()) + { + fec = mesh->GetNodes()->OwnFEC(); + cout << "Using isoparametric FEs: " << fec->Name() << endl; + } + else + { + fec = new H1_FECollection(order = 1, dim, basis); + } + FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); + cout << "Number of finite element unknowns: " + << fespace->GetTrueVSize() << endl; + + // Create the LOR mesh and finite element space. In the settings of this + // example, we can transfer between HO and LOR with the identity operator. + Mesh *mesh_lor = NULL; + FiniteElementCollection *fec_lor = NULL; + FiniteElementSpace *fespace_lor = NULL; + if (pc_choice == LOR) + { + int basis_lor = basis; + if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } + mesh_lor = new Mesh(mesh, order, basis_lor); + fec_lor = new H1_FECollection(1, dim); + fespace_lor = new FiniteElementSpace(mesh_lor, fec_lor); + } + + // 6. Check if the optimized version matches the given space + if (perf && !sol_fes_t::Matches(*fespace)) + { + cout << "The given order does not match the optimized parameter.\n" + << "Recompile with suitable 'sol_p' value." << endl; + delete fespace; + delete fec; + delete mesh; + return 5; + } + + // 7. Determine the list of true (i.e. conforming) essential boundary dofs. + // In this example, the boundary conditions are defined by marking all + // the boundary attributes from the mesh as essential (Dirichlet) and + // converting them to a list of true dofs. + Array ess_tdof_list; + if (mesh->bdr_attributes.Size()) + { + Array ess_bdr(mesh->bdr_attributes.Max()); + ess_bdr = 1; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + + // 8. Set up the linear form b(.) which corresponds to the right-hand side of + // the FEM linear system, which in this case is (1,phi_i) where phi_i are + // the basis functions in the finite element fespace. + LinearForm *b = new LinearForm(fespace); + ConstantCoefficient one(1.0); + b->AddDomainIntegrator(new DomainLFIntegrator(one)); + b->Assemble(); + + // 9. Define the solution vector x as a finite element grid function + // corresponding to fespace. Initialize x with initial guess of zero, + // which satisfies the boundary conditions. + GridFunction x(fespace); + x = 0.0; + + // 10. Set up the bilinear form a(.,.) on the finite element space that will + // hold the matrix corresponding to the Laplacian operator -Delta. + // Optionally setup a form to be assembled for preconditioning (a_pc). + BilinearForm *a = new BilinearForm(fespace); + BilinearForm *a_pc = NULL; + if (pc_choice == LOR) { a_pc = new BilinearForm(fespace_lor); } + if (pc_choice == HO) { a_pc = new BilinearForm(fespace); } + + // 11. Assemble the bilinear form and the corresponding linear system, + // applying any necessary transformations such as: eliminating boundary + // conditions, applying conforming constraints for non-conforming AMR, + // static condensation, etc. + if (static_cond) + { + a->EnableStaticCondensation(); + MFEM_VERIFY(pc_choice != LOR, + "cannot use LOR preconditioner with static condensation"); + } + + cout << "Assembling the bilinear form ..." << flush; + tic_toc.Clear(); + tic_toc.Start(); + // Pre-allocate sparsity assuming dense element matrices + a->UsePrecomputedSparsity(); + + HPCBilinearForm *a_hpc = NULL; + Operator *a_oper = NULL; + + if (!perf) + { + // Standard assembly using a diffusion domain integrator + a->AddDomainIntegrator(new DiffusionIntegrator(one)); + a->Assemble(); + } + else + { + // High-performance assembly/evaluation using the templated operator type + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (matrix_free) + { + a_hpc->Assemble(); // partial assembly + } + else + { + a_hpc->AssembleBilinearForm(*a); // full matrix assembly + } + } + tic_toc.Stop(); + cout << " done, " << tic_toc.RealTime() << "s." << endl; + + // 12. Solve the system A X = B with CG. In the standard case, use a simple + // symmetric Gauss-Seidel preconditioner. + + // Setup the operator matrix (if applicable) + SparseMatrix A; + Vector B, X; + if (perf && matrix_free) + { + a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "Size of linear system: " << a_hpc->Height() << endl; + } + else + { + a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + cout << "Size of linear system: " << A.Height() << endl; + a_oper = &A; + } + + // Setup the matrix used for preconditioning + cout << "Assembling the preconditioning matrix ..." << flush; + tic_toc.Clear(); + tic_toc.Start(); + + SparseMatrix A_pc; + if (pc_choice == LOR) + { + // TODO: assemble the LOR matrix using the performance code + a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); + a_pc->UsePrecomputedSparsity(); + a_pc->Assemble(); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + else if (pc_choice == HO) + { + if (!matrix_free) + { + A_pc.MakeRef(A); // matrix already assembled, reuse it + } + else + { + a_pc->UsePrecomputedSparsity(); + a_hpc->AssembleBilinearForm(*a_pc); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + } + + tic_toc.Stop(); + cout << " done, " << tic_toc.RealTime() << "s." << endl; + + // Solve with CG or PCG, depending if the matrix A_pc is available + tic_toc.Clear(); + tic_toc.Start(); + if (pc_choice != NONE) + { + GSSmoother M(A_pc); + PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); + } + else + { + CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + } + tic_toc.Stop(); + cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; + + // 13. Recover the solution as a finite element grid function. + if (perf && matrix_free) + { + a_hpc->RecoverFEMSolution(X, *b, x); + } + else + { + a->RecoverFEMSolution(X, *b, x); + } + + // 14. Save the refined mesh and the solution. This output can be viewed later + // using GLVis: "glvis -m refined.mesh -g sol.gf". + ofstream mesh_ofs("refined.mesh"); + mesh_ofs.precision(8); + mesh->Print(mesh_ofs); + ofstream sol_ofs("sol.gf"); + sol_ofs.precision(8); + x.Save(sol_ofs); + + // 15. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock.precision(8); + sol_sock << "solution\n" << *mesh << x << flush; + } + + // 16. Free the used memory. + delete a; + delete a_hpc; + if (a_oper != &A) { delete a_oper; } + delete a_pc; + delete b; + delete fespace; + delete fespace_lor; + delete fec_lor; + delete mesh_lor; + if (order > 0) { delete fec; } + delete mesh; + + return 0; +} From 65778b57577260f88bfd8eab0b16623bb20f4687 Mon Sep 17 00:00:00 2001 From: camierjs Date: Fri, 22 Jun 2018 14:43:10 -0700 Subject: [PATCH 014/535] [x86] add inline MFEM_ALWAYS_INLINE in each simd header files --- config/simd/m128.hpp | 84 ++++++++++++++++++++++++------------ config/simd/m256.hpp | 79 +++++++++++++++++++++------------ config/simd/m512.hpp | 82 +++++++++++++++++++++++------------ config/simd/m64.hpp | 79 +++++++++++++++++++++------------ config/simd/x86.hpp | 4 ++ miniapps/performance/ex1.cpp | 4 +- 6 files changed, 220 insertions(+), 112 deletions(-) diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 7c3f7e51be..4b4c1432ab 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -24,140 +24,164 @@ template struct AutoSIMD scalar_t vec[size]; }; - scalar_t &operator[](int i) { return vec[i]; } - const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } - AutoSIMD &operator=(const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { m128d = v.m128d; return *this; } - AutoSIMD &operator=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { m128d = _mm_set1_pd(e); return *this; } - AutoSIMD &operator+=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { m128d = _mm_add_pd(m128d,v); return *this; - } - AutoSIMD &operator+=(const scalar_t &e) + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { m128d = _mm_add_pd(m128d,_mm_set1_pd(e)); return *this; } - AutoSIMD &operator-=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { m128d = _mm_sub_pd(m128d,v); return *this; } - AutoSIMD &operator-=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { m128d = _mm_sub_pd(m128d,_mm_set1_pd(e)); return *this; } - AutoSIMD &operator*=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { m128d = _mm_mul_pd(m128d,v.m128d); return *this; } - AutoSIMD &operator*=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { m128d = _mm_mul_pd(m128d,_mm_set1_pd(e)); return *this; } - AutoSIMD &operator/=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { m128d = _mm_div_pd(m128d,v.m128d); return *this; } - AutoSIMD &operator/=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { m128d = _mm_div_pd(m128d,_mm_set1_pd(e)); return *this; } - AutoSIMD operator-() const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { return _mm_xor_pd(_mm_set1_pd(-0.0), m128d); } - AutoSIMD operator+(const AutoSIMD &v) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const { AutoSIMD r; r.m128d = _mm_add_pd(m128d,v.m128d); return r; } - AutoSIMD operator+(const scalar_t &e) const + + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r.m128d = _mm_add_pd(m128d, _mm_set1_pd(e)); return r; } - AutoSIMD operator-(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r.m128d = _mm_sub_pd(m128d,v.m128d); return r; } - AutoSIMD operator-(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r.m128d = _mm_sub_pd(m128d, _mm_set1_pd(e)); return r; } - AutoSIMD operator*(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r.m128d = _mm_mul_pd(m128d,v.m128d); return r; } - AutoSIMD operator*(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r.m128d = _mm_mul_pd(m128d, _mm_set1_pd(e)); return r; } - AutoSIMD operator/(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r.m128d = _mm_div_pd(m128d,v.m128d); return r; } - AutoSIMD operator/(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; r.m128d = _mm_div_pd(m128d, _mm_set1_pd(e)); return r; } - AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { m128d = _mm_add_pd(_mm_mul_pd(w.m128d,v.m128d),m128d); return *this; } - AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { m128d = _mm_add_pd(_mm_mul_pd(_mm_set1_pd(e),v.m128d),m128d); return *this; } - AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { m128d = _mm_add_pd(_mm_mul_pd(v.m128d,_mm_set1_pd(e)),m128d); return *this; } - AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) { m128d = _mm_mul_pd(v.m128d,w.m128d); return *this; } - AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { m128d = _mm_mul_pd(v.m128d,_mm_set1_pd(e)); return *this; } - AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d); return *this; @@ -166,6 +190,7 @@ template struct AutoSIMD // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { @@ -176,6 +201,7 @@ AutoSIMD operator+(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { @@ -186,6 +212,7 @@ AutoSIMD operator-(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { @@ -196,6 +223,7 @@ AutoSIMD operator*(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index d004d49782..76a6bdf856 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -24,114 +24,131 @@ template struct AutoSIMD scalar_t vec[size]; }; - scalar_t &operator[](int i) { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } const scalar_t &operator[](int i) const { return vec[i]; } - AutoSIMD &operator=(const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { m256d = v.m256d; return *this; } - AutoSIMD &operator=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { m256d = _mm256_set1_pd(e); return *this; } - AutoSIMD &operator+=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { m256d = _mm256_add_pd(m256d,v); return *this; - } - AutoSIMD &operator+=(const scalar_t &e) + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { m256d = _mm256_add_pd(m256d,_mm256_set1_pd(e)); return *this; } - AutoSIMD &operator-=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { m256d = _mm256_sub_pd(m256d,v); return *this; } - AutoSIMD &operator-=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { m256d = _mm256_sub_pd(m256d,_mm256_set1_pd(e)); return *this; } - AutoSIMD &operator*=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { m256d = _mm256_mul_pd(m256d,v.m256d); return *this; } - AutoSIMD &operator*=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { m256d = _mm256_mul_pd(m256d,_mm256_set1_pd(e)); return *this; } - AutoSIMD &operator/=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { m256d = _mm256_div_pd(m256d,v.m256d); return *this; } - AutoSIMD &operator/=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { m256d = _mm256_div_pd(m256d,_mm256_set1_pd(e)); return *this; } - AutoSIMD operator-() const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { return _mm256_xor_pd(_mm256_set1_pd(-0.0), m256d); } - AutoSIMD operator+(const AutoSIMD &v) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_add_pd(m256d,v.m256d); return r; } - AutoSIMD operator+(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_add_pd(m256d, _mm256_set1_pd(e)); return r; } - AutoSIMD operator-(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_sub_pd(m256d,v.m256d); return r; } - AutoSIMD operator-(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_sub_pd(m256d, _mm256_set1_pd(e)); return r; } - AutoSIMD operator*(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_mul_pd(m256d,v.m256d); return r; } - AutoSIMD operator*(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_mul_pd(m256d, _mm256_set1_pd(e)); return r; } - AutoSIMD operator/(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_div_pd(m256d,v.m256d); return r; } - AutoSIMD operator/(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_div_pd(m256d, _mm256_set1_pd(e)); return r; } - AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { #ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(w.m256d,v.m256d),m256d); @@ -140,7 +157,8 @@ template struct AutoSIMD #endif return *this; } - AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { #ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(_mm256_set1_pd(e),v.m256d),m256d); @@ -149,7 +167,8 @@ template struct AutoSIMD #endif return *this; } - AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { #ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(v.m256d,_mm256_set1_pd(e)),m256d); @@ -159,17 +178,19 @@ template struct AutoSIMD return *this; } - AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) { m256d = _mm256_mul_pd(v.m256d,w.m256d); return *this; } - AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { m256d = _mm256_mul_pd(v.m256d,_mm256_set1_pd(e)); return *this; } - AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); return *this; @@ -178,6 +199,7 @@ template struct AutoSIMD // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { @@ -188,6 +210,7 @@ AutoSIMD operator+(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { @@ -198,6 +221,7 @@ AutoSIMD operator-(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { @@ -208,6 +232,7 @@ AutoSIMD operator*(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 7163039421..1c8e80b24e 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -24,140 +24,162 @@ template struct AutoSIMD scalar_t vec[size]; }; - scalar_t &operator[](int i) { return vec[i]; } - const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } - AutoSIMD &operator=(const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { m512d = v.m512d; return *this; } - AutoSIMD &operator=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { m512d = _mm512_set1_pd(e); return *this; } - AutoSIMD &operator+=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { m512d = _mm512_add_pd(m512d,v); return *this; - } - AutoSIMD &operator+=(const scalar_t &e) + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { m512d = _mm512_add_pd(m512d,_mm512_set1_pd(e)); return *this; } - AutoSIMD &operator-=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { m512d = _mm512_sub_pd(m512d,v); return *this; } - AutoSIMD &operator-=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { m512d = _mm512_sub_pd(m512d,_mm512_set1_pd(e)); return *this; } - AutoSIMD &operator*=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { m512d = _mm512_mul_pd(m512d,v.m512d); return *this; } - AutoSIMD &operator*=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { m512d = _mm512_mul_pd(m512d,_mm512_set1_pd(e)); return *this; } - AutoSIMD &operator/=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { m512d = _mm512_div_pd(m512d,v.m512d); return *this; } - AutoSIMD &operator/=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { m512d = _mm512_div_pd(m512d,_mm512_set1_pd(e)); return *this; } - AutoSIMD operator-() const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { return _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); } - AutoSIMD operator+(const AutoSIMD &v) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_add_pd(m512d,v.m512d); return r; } - AutoSIMD operator+(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_add_pd(m512d, _mm512_set1_pd(e)); return r; } - AutoSIMD operator-(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_sub_pd(m512d,v.m512d); return r; } - AutoSIMD operator-(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_sub_pd(m512d, _mm512_set1_pd(e)); return r; } - AutoSIMD operator*(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_mul_pd(m512d,v.m512d); return r; } - AutoSIMD operator*(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_mul_pd(m512d, _mm512_set1_pd(e)); return r; } - AutoSIMD operator/(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_div_pd(m512d,v.m512d); return r; } - AutoSIMD operator/(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_div_pd(m512d, _mm512_set1_pd(e)); return r; } - AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { m512d = _mm512_fmadd_pd(w.m512d,v.m512d,m512d); return *this; } - AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { m512d = _mm512_fmadd_pd(_mm512_set1_pd(e),v.m512d,m512d); return *this; } - AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { m512d = _mm512_fmadd_pd(v.m512d,_mm512_set1_pd(e),m512d); return *this; } - AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) { m512d = _mm512_mul_pd(v.m512d,w.m512d); return *this; } - AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { m512d = _mm512_mul_pd(v.m512d,_mm512_set1_pd(e)); return *this; } - AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); return *this; @@ -166,6 +188,7 @@ template struct AutoSIMD // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { @@ -176,6 +199,7 @@ AutoSIMD operator+(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { @@ -186,6 +210,7 @@ AutoSIMD operator-(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { @@ -196,6 +221,7 @@ AutoSIMD operator*(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index 03c09beb69..977f3aba1b 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -21,143 +21,164 @@ template struct AutoSIMD scalar_t vec[size]; - scalar_t &operator[](int i) { return vec[0]; } - const scalar_t &operator[](int i) const { return vec[0]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[0]; } + + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[0]; } - AutoSIMD &operator=(const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { vec[0] = v[0]; return *this; } - AutoSIMD &operator=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { vec[0] = e; return *this; } - AutoSIMD &operator+=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { vec[0] += v[0]; return *this; } - AutoSIMD &operator+=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { vec[0] += e; return *this; } - AutoSIMD &operator-=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { vec[0] -= v[0]; return *this; } - AutoSIMD &operator-=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { vec[0] -= e; return *this; } - AutoSIMD &operator*=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { vec[0] *= v[0]; return *this; } - AutoSIMD &operator*=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { vec[0] *= e; return *this; } - AutoSIMD &operator/=(const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { vec[0] /= v[0]; return *this; } - AutoSIMD &operator/=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { vec[0] /= e; return *this; } - AutoSIMD operator-() const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { AutoSIMD r; r[0] = -vec[0]; return r; } - AutoSIMD operator+(const AutoSIMD &v) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] + v[0]; return r; } - AutoSIMD operator+(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] + e; return r; } - AutoSIMD operator-(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] - v[0]; return r; } - AutoSIMD operator-(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] - e; return r; } - AutoSIMD operator*(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] * v[0]; return r; } - AutoSIMD operator*(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] * e; return r; } - AutoSIMD operator/(const AutoSIMD &v) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] / v[0]; return r; } - AutoSIMD operator/(const scalar_t &e) const + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] / e; return r; } - AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) { vec[0] += v[0] * w[0]; return *this; } - AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { vec[0] += v[0] * e; return *this; } - AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { vec[0] += e * v[0]; return *this; } - AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) { vec[0] = v[0] * w[0]; return *this; } - AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { vec[0] = v[0] * e; return *this; } - AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { vec[0] = e * v[0]; return *this; @@ -166,6 +187,7 @@ template struct AutoSIMD // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { @@ -176,6 +198,7 @@ AutoSIMD operator+(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { @@ -186,6 +209,7 @@ AutoSIMD operator-(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { @@ -196,6 +220,7 @@ AutoSIMD operator*(const scalar_t &e, // ***************************************************************************** template +inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index bf9d9b3b30..262e7a0fe9 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -16,6 +16,10 @@ template struct AutoSIMD; +// We have to keep all of the folowing because AutoSIMD is chosen +// depending on the definition of MFEM_SIMD_SIZE and MFEM_TEMPLATE_BLOCK_SIZE +// in config/tconfig.h + #include "m64.hpp" #include "m128.hpp" diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index 46a2a0c30c..16e9662cb3 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -38,8 +38,8 @@ using namespace mfem; // Define template parameters for optimized build. const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 6; // mesh curvature (default: 3) -const int sol_p = 6; // solution order (default: 3) +const int mesh_p = 8; // mesh curvature (default: 3) +const int sol_p = 8; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; From 798168325bb8d7c2c785e7e23c81e891c8b4fc0a Mon Sep 17 00:00:00 2001 From: camierjs Date: Fri, 22 Jun 2018 20:47:14 -0700 Subject: [PATCH 015/535] [x86] perf vs master --- miniapps/performance/{bp1p.cpp => bp.cpp} | 101 ++++++++++++------ miniapps/performance/bp.tgp | 94 +++++++++++++++++ miniapps/performance/makefile | 120 ++++++++++++++++++++++ 3 files changed, 285 insertions(+), 30 deletions(-) rename miniapps/performance/{bp1p.cpp => bp.cpp} (89%) create mode 100644 miniapps/performance/bp.tgp diff --git a/miniapps/performance/bp1p.cpp b/miniapps/performance/bp.cpp similarity index 89% rename from miniapps/performance/bp1p.cpp rename to miniapps/performance/bp.cpp index fec890c4f5..1ecb68e953 100644 --- a/miniapps/performance/bp1p.cpp +++ b/miniapps/performance/bp.cpp @@ -1,30 +1,53 @@ -// ***************************************************************************** -// Description: BP1 benchmark (from CEED Bake-off Problems) -// test the performance of high-order mass matrix operator -// evaluation with "partial assembly" algorithms. +// Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights +// reserved. See files LICENSE and NOTICE for details. +// +// This file is part of CEED, a collection of benchmarks, miniapps, software +// libraries and APIs for efficient high-order finite element and spectral +// element discretizations for exascale applications. For more information and +// source code availability see http://github.com/ceed. +// +// The CEED research is supported by the Exascale Computing Project +// (17-SC-20-SC), a collaborative effort of two U.S. Department of Energy +// organizations (Office of Science and the National Nuclear Security +// Administration) responsible for the planning and preparation of a capable +// exascale ecosystem, including software, applications, hardware, advanced +// system engineering and early testbed platforms, in support of the nation's +// exascale computing imperative. + + +//============================================================================== +// MFEM Bake-off Problems 1, 2, 3, and 4 +// Version 1 +// +// Compile with: see README.md +// +// Sample runs: see README.md +// +// Description: These benchmarks (CEED Bake-off Problems BP1 and BP3) test the +// performance of high-order mass (BP1) and stiffness (BP3) matrix +// operator evaluation with "partial assembly" algorithms. +// +// Code is based on MFEM's HPC ex1, http://mfem.org/performance. // // More details about CEED's bake-off problems can be found at // http://ceed.exascaleproject.org/bps. -// ***************************************************************************** +//============================================================================== -#include "mfem-performance.hpp" -#include -#include +#include -using namespace std; using namespace mfem; -// ***************************************************************************** #ifndef GEOM #define GEOM Geometry::CUBE #endif #ifndef MESH_P -#define MESH_P 3 +#define MESH_P 6 #endif #ifndef SOL_P -#define SOL_P 3 +#define SOL_P 6 #endif #ifndef IR_ORDER @@ -36,8 +59,8 @@ using namespace mfem; #define IR_TYPE 0 #endif -// 0 - TDiffusionKernel, else TMassKernel #ifndef PROBLEM +// 0- Diffusion, else TMassKernel #define PROBLEM 0 #endif @@ -45,12 +68,40 @@ using namespace mfem; #define VDIM 1 #endif +#ifndef MESH_FILE +#define MESH_FILE "../../data/fichera.mesh" +#endif + // This vector layout is used for the solution space only. #ifndef VEC_LAYOUT #define VEC_LAYOUT Ordering::byVDIM #endif -#define USE_MPI_WTIME +// Define template parameters for optimized build. +const Geometry::Type geom = GEOM; // mesh elements (default: hex) +const int mesh_p = MESH_P; // mesh curvature (default: 3) +const int sol_p = SOL_P; // solution order (default: 3) +const int ir_q = IR_TYPE ? sol_p+1 : sol_p+2; +const int ir_order = IR_ORDER ? IR_ORDER : + (IR_TYPE ? 2*ir_q-3 : 2*ir_q-1); + + +// Workaround for a bug in XL C++ on BG/Q version 12.01.0000.0014 +#if defined(__xlC__) && (__xlC__ < 0x0d00) +#include <../mfem/linalg/tlayout.hpp> +namespace mfem +{ +const int mesh_dim = Geometry::Constants::Dimension; +template class StridedLayout1D; +} +#endif // defined(__xlC__) && (__xlC__ < 0x0d00) + + +#include +#include +#include + +using namespace std; IntegrationRules GaussLobattoRules(0, Quadrature1D::GaussLobatto); @@ -90,14 +141,6 @@ public: }; -// Define template parameters for optimized build. -const Geometry::Type geom = GEOM; // mesh elements (default: hex) -const int mesh_p = MESH_P; // mesh curvature (default: 3) -const int sol_p = SOL_P; // solution order (default: 3) -const int ir_q = IR_TYPE ? sol_p+1 : sol_p+2; -const int ir_order = IR_ORDER ? IR_ORDER : - (IR_TYPE ? 2*ir_q-3 : 2*ir_q-1); - // Static mesh type typedef H1_FiniteElement mesh_fe_t; typedef H1_FiniteElementSpace mesh_fes_t; @@ -113,7 +156,7 @@ typedef TIntegrationRule int_rule_t; #else const int rdim = Geometry::Constants::Dimension; typedef GaussLobattoIntegrationRule -int_rule_t; + int_rule_t; #endif typedef TConstantCoefficient<> coeff_t; #if (PROBLEM == 0) @@ -143,7 +186,7 @@ int main(int argc, char *argv[]) const Ordering::Type ordering = VEC_LAYOUT; // for solution space only // 2. Parse command-line options. - const char *mesh_file = "../../data/inline-hex-2x1x1.mesh"; + const char *mesh_file = MESH_FILE; int ser_ref_levels = -1; int par_ref_levels = +1; Array nxyz; @@ -661,18 +704,16 @@ int main(int argc, char *argv[]) MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); if (myid == 0) { - const int cg_num_iterations = pcg->GetNumIterations(); // Note: In the pcg algorithm, the number of operator Mult() calls is // N_iter and the number of preconditioner Mult() calls is N_iter+1. cout << "Total CG time: " << rt_max << " (" << rt_min << ") sec." << endl; - cout << "CG number of iterations: " << cg_num_iterations << endl; cout << "Time per CG step: " - << rt_max / cg_num_iterations << " (" - << rt_min / cg_num_iterations << ") sec." << endl; + << rt_max / pcg->GetNumIterations() << " (" + << rt_min / pcg->GetNumIterations() << ") sec." << endl; cout << "\n\"DOFs/sec\" in CG: " - << 1e-6*size*cg_num_iterations/rt_max << " (" - << 1e-6*size*cg_num_iterations/rt_min << ") million.\n" + << 1e-6*size*pcg->GetNumIterations()/rt_max << " (" + << 1e-6*size*pcg->GetNumIterations()/rt_min << ") million.\n" << endl; } diff --git a/miniapps/performance/bp.tgp b/miniapps/performance/bp.tgp new file mode 100644 index 0000000000..33ee115d2d --- /dev/null +++ b/miniapps/performance/bp.tgp @@ -0,0 +1,94 @@ +reset +set encoding iso_8859_15 +set datafile separator "|" +set datafile missing '-' + +########## +# Output # +########## +set terminal png transparent truecolor size GEOX,GEOY enhanced fontscale FNTS + +######### +# Style # +######### +set style data pm3d +set pm3d at s interpolate 0,0 nohidden3d implicit #corners2color min #hidden3d 128 +#show pm3d +set style line 128 lt 1 lw 4 + +set hidden3d +unset surf +set grid layerdefault front + +######### +# View # +######### +set size 1,1 +set origin 0,0 +set ticslevel 0.1 +set view VIEWX,VIEWY + +########### +# Palette # +########### +set palette model RGB maxcolors 256 +set palette defined (1 "blue", 2 "cyan", 3 "green", 4 "yellow", 5 "red" ) + +########### +# Contour # +# The first contour linetype, or only contour linetype when clabel is off, is the surface linetype +1 +########### +unset contour +#unset clabel +#stats 'FILE' using 11 name 'M' output +set cntrparam level auto +#set contour surface +set cntrparam bspline +set cntrparam points 16 +set cntrparam order 10 +set cntrparam levels discrete CNTD +#show contour + +######### +# Title # +######### +set title "TITLE" offset -8,-2 textcolor lt 3 enhanced +set autoscale + +########## +# X Axis # +########## +set xlabel "Order" textcolor lt 3 +#set logscale x 2 +#set xrange [1:XMAX] +#set xtics 2,2,14 offset 0,0 +#set xtics 1 offset 0,0 + +########## +# Y Axis # +# http://soc.if.usp.br/manual/gnuplot-doc/htmldocs/stats_005f_0028Statistical_005fSummary_0029.html +########## +#stats 'FILE' using 4 name 'Y' nooutput +set ylabel "Refines" textcolor lt 3 +#set logscale y +set ytics 1,YSTP,YMAX border offset 0,-0.5 +#show ytics + +########## +# Z Axis # +########## +set zlabel "Speedup" textcolor lt 3 rotate +set ztics 1 #,1,8 #offset 1 +set zrange [ZMIN:ZMAX] + +############# +# Color Box # +############# +set style line 1024 linetype -1 +set colorbox vertical border 1024 front user size .01,.25 origin 0.9,.4 +set cbtics nomirror border offset 0 +set cbrange [ZMIN:ZMAX] +set cbtics 1 + +unset multiplot +splot 'FILE' using 2:3:($NUM/$DNM):xticlabels(sprintf("%d",$2)) ls 128 title "" diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index dc79da529e..2fd294017a 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -121,3 +121,123 @@ clean-build: clean-exec: @rm -f refined.mesh mesh.* sol.* + +# ****************************************************************************** +# PERF TESTS GEN/GO/GET +# ****************************************************************************** +PWD = $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) +PERF_PATH = perf +REF_PATH = /home/camier1/home/mfem/master/miniapps/performance/perf +MAKEFILE_DUMP = MFEM_DIR=$(PWD)/../..\\nMFEM_BUILD_DIR=$(PWD)/../..\\n +MAKEFILE_DUMP += \\nMFEM_PERF_CXXFLAGS_gcc_common+=-DMESH_P=$$order +MAKEFILE_DUMP += -DSOL_P=$$order -DPROBLEM=$$problem -DMESH_FILE=\\\"$(MESH_FILE)\\\"\\n +MAKEFILE_DUMP += \\ninclude $(shell pwd)/makefile +ORDERs = 2 3 4 5 6 7 8 9 10 11 12 13 14 #15 16 +PROBLEMs = 0 1 +SREFINEs = 1 2 3 #4 +PREFINEs = 0 +MESH_FILE = $(PWD)/../../data/inline-hex-2x1x1.mesh +ECHO=/bin/echo +make_bp:;@make bp +gen: + mkdir -v -p $(PERF_PATH) + @tput reset + @echo Now launching GEN + @for problem in $(PROBLEMs);do\ + for order in $(ORDERs);do\ + $(ECHO) -e \\tpb$$problem\_o$$order;\ + path=$(PERF_PATH)/pb$$problem/o$$order;\ + mkdir -v -p $$path;\ + ln -fs $(shell pwd)/bp.cpp $$path;\ + $(ECHO) -e $(MAKEFILE_DUMP) > $$path/makefile;\ + (cd $$path && make make_bp && mv bp bp_pb$$problem\_o$$order);\ + done;\ + done + +go: + @tput reset + @echo Now launching tests + @for problem in $(PROBLEMs);do\ + for order in $(ORDERs);do\ + path=$(PERF_PATH)/pb$$problem/o$$order;\ + exec=bp"_pb"$$problem"_o"$$order;\ + for rs in $(SREFINEs);do\ + for rp in $(PREFINEs);do\ + rsp=$$(($$rs+$$rp));\ + $(ECHO) -e \\tpb$$problem\_o$$order\_rs$$rs\_rp$$rp;\ + file=bp"_pb"$$problem"_o"$$order"_rs"$$rs"_rp"$$rp;\ + perf stat -e instructions,cycles,task-clock,cpu-clock \ +-o $$path/$$file.perf $$path/$$exec -rs $$rs -rp $$rp > $$path/$$file.out;\ + done;\ + done;\ + done;\ + done + +get: + @tput reset && sync && sync + @echo Now collecting results + @for problem in $(PROBLEMs);do\ + path=$(PERF_PATH)/pb$$problem;\ + OUTPUT_FILE=mfem-pb$$problem\.org;\ + $(ECHO) -e \\tGenerating: $$OUTPUT_FILE;\ + $(ECHO) -n > $$OUTPUT_FILE;\ + $(ECHO) \#\|order\|refine\|one\|perf\| >> $$OUTPUT_FILE &&\ + for order in $(ORDERs);do\ + $(ECHO) -e \\t\\tORDER=$$order;\ + opath=$$path/o$$order;\ + for rs in $(SREFINEs);do\ + for rp in $(PREFINEs);do\ + rsp=$$(($$rs+$$rp));\ + REF_VAL=`cat $(REF_PATH)/pb$$problem/o$$order/bp_pb$$problem\_o$$order\_rs$$rs\_rp$$rp\.out|grep DOFs|grep CG|cut -d' ' -f4|tr -d [:blank:]`;\ + $(ECHO) -e \\t\\t\\trefine=$$rsp;\ + ($(ECHO) -n \|$$order\|$$rsp\|$$REF_VAL\| >> $$OUTPUT_FILE &&\ + cat $(PWD)/$$opath/bp_pb$$problem\_o$$order\_rs$$rs\_rp$$rp\.out|grep DOFs|grep CG|cut -d' ' -f4|tr -d [:blank:]|tr -d \\n >> $$OUTPUT_FILE &&\ + $(ECHO) \| >> $$OUTPUT_FILE);\ + done;\ + done;\ + $(ECHO) >> $$OUTPUT_FILE;\ + done;\ + done + +# ****************************************************************************** +GEOX ?= 3072 +GEOY ?= 2048 +FNTS ?= 4 +VIEWX ?= 40 #120 +VIEWY ?= 20 +FILE ?= mfem-pb1.org +FILE_P0 ?= mfem-pb0.org +FILE_P1 ?= mfem-pb1.org +XMAX ?= 4 +YSTP ?= 1 +YMAX ?= 3 +ZMIN ?= 1 +ZMAX ?= 3.5 +CNTD ?= 2 +TITLE ?= Total Rate +NUM ?= 20 +DNM ?= 10 +CPU = $(shell echo $(shell getconf _NPROCESSORS_ONLN)) + +gp gnuplot: + $(MAKE) -j $(CPU) bp0 bp1 + +bp0: $(FILE_P0) + FILE=$(FILE_P0) \ + TITLE="BP 3D P0 Speedup: x86\/master" \ + NUM=5 DNM=4 ZMAX= $(MAKE) mfem-$@.png + +bp1: $(FILE_P1) + FILE=$(FILE_P1) \ + TITLE="BP 3D P1 Speedup: x86\/master" \ + NUM=5 DNM=4 ZMAX= $(MAKE) mfem-$@.png + +#.PRECIOUS: %.gpi +%.gpi: makefile bp.tgp + sed 's/TITLE/$(TITLE)/g;s/XMAX/$(XMAX)/g;s/CNTD/$(CNTD)/g;s/YMAX/$(YMAX)/g;s/YSTP/$(YSTP)/g;s/ZMIN/$(ZMIN)/g;s/ZMAX/$(ZMAX)/g;s/NUM/$(NUM)/g;s/DNM/$(DNM)/g;s/GEOX/$(GEOX)/g;s/GEOY/$(GEOY)/g;s/FNTS/$(FNTS)/g;s/VIEWX/$(VIEWX)/g;s/VIEWY/$(VIEWY)/g;s/FILE/$(FILE)/g' bp.tgp > $*.gpi + +%.png:%.gpi $(FILE) + gnuplot $*.gpi > $*.png + +%.pdf:%.png + convert $(CONVERT_FLAGS) $*.png $*.pdf From d5651117329e684e6c0f414bbb29c368d8921d2a Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 25 Jun 2018 11:07:21 -0700 Subject: [PATCH 016/535] [x86] makefile cleanup --- miniapps/performance/bp.tgp | 94 -------------------------- miniapps/performance/makefile | 120 ---------------------------------- 2 files changed, 214 deletions(-) delete mode 100644 miniapps/performance/bp.tgp diff --git a/miniapps/performance/bp.tgp b/miniapps/performance/bp.tgp deleted file mode 100644 index 33ee115d2d..0000000000 --- a/miniapps/performance/bp.tgp +++ /dev/null @@ -1,94 +0,0 @@ -reset -set encoding iso_8859_15 -set datafile separator "|" -set datafile missing '-' - -########## -# Output # -########## -set terminal png transparent truecolor size GEOX,GEOY enhanced fontscale FNTS - -######### -# Style # -######### -set style data pm3d -set pm3d at s interpolate 0,0 nohidden3d implicit #corners2color min #hidden3d 128 -#show pm3d -set style line 128 lt 1 lw 4 - -set hidden3d -unset surf -set grid layerdefault front - -######### -# View # -######### -set size 1,1 -set origin 0,0 -set ticslevel 0.1 -set view VIEWX,VIEWY - -########### -# Palette # -########### -set palette model RGB maxcolors 256 -set palette defined (1 "blue", 2 "cyan", 3 "green", 4 "yellow", 5 "red" ) - -########### -# Contour # -# The first contour linetype, or only contour linetype when clabel is off, is the surface linetype +1 -########### -unset contour -#unset clabel -#stats 'FILE' using 11 name 'M' output -set cntrparam level auto -#set contour surface -set cntrparam bspline -set cntrparam points 16 -set cntrparam order 10 -set cntrparam levels discrete CNTD -#show contour - -######### -# Title # -######### -set title "TITLE" offset -8,-2 textcolor lt 3 enhanced -set autoscale - -########## -# X Axis # -########## -set xlabel "Order" textcolor lt 3 -#set logscale x 2 -#set xrange [1:XMAX] -#set xtics 2,2,14 offset 0,0 -#set xtics 1 offset 0,0 - -########## -# Y Axis # -# http://soc.if.usp.br/manual/gnuplot-doc/htmldocs/stats_005f_0028Statistical_005fSummary_0029.html -########## -#stats 'FILE' using 4 name 'Y' nooutput -set ylabel "Refines" textcolor lt 3 -#set logscale y -set ytics 1,YSTP,YMAX border offset 0,-0.5 -#show ytics - -########## -# Z Axis # -########## -set zlabel "Speedup" textcolor lt 3 rotate -set ztics 1 #,1,8 #offset 1 -set zrange [ZMIN:ZMAX] - -############# -# Color Box # -############# -set style line 1024 linetype -1 -set colorbox vertical border 1024 front user size .01,.25 origin 0.9,.4 -set cbtics nomirror border offset 0 -set cbrange [ZMIN:ZMAX] -set cbtics 1 - -unset multiplot -splot 'FILE' using 2:3:($NUM/$DNM):xticlabels(sprintf("%d",$2)) ls 128 title "" diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 2fd294017a..dc79da529e 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -121,123 +121,3 @@ clean-build: clean-exec: @rm -f refined.mesh mesh.* sol.* - -# ****************************************************************************** -# PERF TESTS GEN/GO/GET -# ****************************************************************************** -PWD = $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) -PERF_PATH = perf -REF_PATH = /home/camier1/home/mfem/master/miniapps/performance/perf -MAKEFILE_DUMP = MFEM_DIR=$(PWD)/../..\\nMFEM_BUILD_DIR=$(PWD)/../..\\n -MAKEFILE_DUMP += \\nMFEM_PERF_CXXFLAGS_gcc_common+=-DMESH_P=$$order -MAKEFILE_DUMP += -DSOL_P=$$order -DPROBLEM=$$problem -DMESH_FILE=\\\"$(MESH_FILE)\\\"\\n -MAKEFILE_DUMP += \\ninclude $(shell pwd)/makefile -ORDERs = 2 3 4 5 6 7 8 9 10 11 12 13 14 #15 16 -PROBLEMs = 0 1 -SREFINEs = 1 2 3 #4 -PREFINEs = 0 -MESH_FILE = $(PWD)/../../data/inline-hex-2x1x1.mesh -ECHO=/bin/echo -make_bp:;@make bp -gen: - mkdir -v -p $(PERF_PATH) - @tput reset - @echo Now launching GEN - @for problem in $(PROBLEMs);do\ - for order in $(ORDERs);do\ - $(ECHO) -e \\tpb$$problem\_o$$order;\ - path=$(PERF_PATH)/pb$$problem/o$$order;\ - mkdir -v -p $$path;\ - ln -fs $(shell pwd)/bp.cpp $$path;\ - $(ECHO) -e $(MAKEFILE_DUMP) > $$path/makefile;\ - (cd $$path && make make_bp && mv bp bp_pb$$problem\_o$$order);\ - done;\ - done - -go: - @tput reset - @echo Now launching tests - @for problem in $(PROBLEMs);do\ - for order in $(ORDERs);do\ - path=$(PERF_PATH)/pb$$problem/o$$order;\ - exec=bp"_pb"$$problem"_o"$$order;\ - for rs in $(SREFINEs);do\ - for rp in $(PREFINEs);do\ - rsp=$$(($$rs+$$rp));\ - $(ECHO) -e \\tpb$$problem\_o$$order\_rs$$rs\_rp$$rp;\ - file=bp"_pb"$$problem"_o"$$order"_rs"$$rs"_rp"$$rp;\ - perf stat -e instructions,cycles,task-clock,cpu-clock \ --o $$path/$$file.perf $$path/$$exec -rs $$rs -rp $$rp > $$path/$$file.out;\ - done;\ - done;\ - done;\ - done - -get: - @tput reset && sync && sync - @echo Now collecting results - @for problem in $(PROBLEMs);do\ - path=$(PERF_PATH)/pb$$problem;\ - OUTPUT_FILE=mfem-pb$$problem\.org;\ - $(ECHO) -e \\tGenerating: $$OUTPUT_FILE;\ - $(ECHO) -n > $$OUTPUT_FILE;\ - $(ECHO) \#\|order\|refine\|one\|perf\| >> $$OUTPUT_FILE &&\ - for order in $(ORDERs);do\ - $(ECHO) -e \\t\\tORDER=$$order;\ - opath=$$path/o$$order;\ - for rs in $(SREFINEs);do\ - for rp in $(PREFINEs);do\ - rsp=$$(($$rs+$$rp));\ - REF_VAL=`cat $(REF_PATH)/pb$$problem/o$$order/bp_pb$$problem\_o$$order\_rs$$rs\_rp$$rp\.out|grep DOFs|grep CG|cut -d' ' -f4|tr -d [:blank:]`;\ - $(ECHO) -e \\t\\t\\trefine=$$rsp;\ - ($(ECHO) -n \|$$order\|$$rsp\|$$REF_VAL\| >> $$OUTPUT_FILE &&\ - cat $(PWD)/$$opath/bp_pb$$problem\_o$$order\_rs$$rs\_rp$$rp\.out|grep DOFs|grep CG|cut -d' ' -f4|tr -d [:blank:]|tr -d \\n >> $$OUTPUT_FILE &&\ - $(ECHO) \| >> $$OUTPUT_FILE);\ - done;\ - done;\ - $(ECHO) >> $$OUTPUT_FILE;\ - done;\ - done - -# ****************************************************************************** -GEOX ?= 3072 -GEOY ?= 2048 -FNTS ?= 4 -VIEWX ?= 40 #120 -VIEWY ?= 20 -FILE ?= mfem-pb1.org -FILE_P0 ?= mfem-pb0.org -FILE_P1 ?= mfem-pb1.org -XMAX ?= 4 -YSTP ?= 1 -YMAX ?= 3 -ZMIN ?= 1 -ZMAX ?= 3.5 -CNTD ?= 2 -TITLE ?= Total Rate -NUM ?= 20 -DNM ?= 10 -CPU = $(shell echo $(shell getconf _NPROCESSORS_ONLN)) - -gp gnuplot: - $(MAKE) -j $(CPU) bp0 bp1 - -bp0: $(FILE_P0) - FILE=$(FILE_P0) \ - TITLE="BP 3D P0 Speedup: x86\/master" \ - NUM=5 DNM=4 ZMAX= $(MAKE) mfem-$@.png - -bp1: $(FILE_P1) - FILE=$(FILE_P1) \ - TITLE="BP 3D P1 Speedup: x86\/master" \ - NUM=5 DNM=4 ZMAX= $(MAKE) mfem-$@.png - -#.PRECIOUS: %.gpi -%.gpi: makefile bp.tgp - sed 's/TITLE/$(TITLE)/g;s/XMAX/$(XMAX)/g;s/CNTD/$(CNTD)/g;s/YMAX/$(YMAX)/g;s/YSTP/$(YSTP)/g;s/ZMIN/$(ZMIN)/g;s/ZMAX/$(ZMAX)/g;s/NUM/$(NUM)/g;s/DNM/$(DNM)/g;s/GEOX/$(GEOX)/g;s/GEOY/$(GEOY)/g;s/FNTS/$(FNTS)/g;s/VIEWX/$(VIEWX)/g;s/VIEWY/$(VIEWY)/g;s/FILE/$(FILE)/g' bp.tgp > $*.gpi - -%.png:%.gpi $(FILE) - gnuplot $*.gpi > $*.png - -%.pdf:%.png - convert $(CONVERT_FLAGS) $*.png $*.pdf From ec9a490cd270e6063af5b4093e5abc5db6295e17 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 25 Jun 2018 14:52:13 -0700 Subject: [PATCH 017/535] [vsx] (2x) double vector for __VSX__ Power8 architecture --- config/simd/auto.hpp | 2 - config/simd/vsx128.hpp | 238 ++++++++++++++++++++++++++++++++++ config/simd/vsx256.hpp | 238 ++++++++++++++++++++++++++++++++++ config/simd/vsx64.hpp | 236 +++++++++++++++++++++++++++++++++ config/tconfig.hpp | 14 ++ miniapps/performance/bp.cpp | 4 +- miniapps/performance/makefile | 8 +- 7 files changed, 735 insertions(+), 5 deletions(-) create mode 100644 config/simd/vsx128.hpp create mode 100644 config/simd/vsx256.hpp create mode 100644 config/simd/vsx64.hpp diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index 8dce51849e..4ed7ff86aa 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -232,7 +232,6 @@ AutoSIMD operator-(const scalar_t &e, return r; } -// warning: always_inline function might not be inlinable template inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, @@ -244,7 +243,6 @@ AutoSIMD operator*(const scalar_t &e, return r; } -//warning: always_inline function might not be inlinable template inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp new file mode 100644 index 0000000000..10f4d3a3a0 --- /dev/null +++ b/config/simd/vsx128.hpp @@ -0,0 +1,238 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX128 +#define MFEM_TEMPLATE_CONFIG_SIMD_VSX128 + +#include "altivec.h" +#define __ATTRS_ai __attribute__((__always_inline__)) + +template struct AutoSIMD; + +// **************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 2; + static const int align_size = 16; + + union{ + vector double vd; + scalar_t vec[size]; + }; + + inline __ATTRS_ai scalar_t &operator[](int i) { return vec[i]; } + + inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[i]; } + + inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) + { + vd = v.vd; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + { + vd = vec_splats(e); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) + { + vd = vec_add(vd,v); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + { + vd = vec_add(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) + { + vd = vec_sub(vd,v); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + { + vd = vec_sub(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) + { + vd = vec_mul(vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + { + vd = vec_mul(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) + { + vd = vec_div(vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + { + vd = vec_div(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD operator-() const + { + return vec_neg(vd); + } + + inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_add(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_add(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_sub(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_sub(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_mul(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_mul(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_div(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_div(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_madd(w.vd,vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_madd(v.vd,vec_splats(e),vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_madd(vec_splats(e),v.vd,vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_mul(v.vd,w.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_mul(v.vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_mul(vec_splats(e),v.vd); + return *this; + } +}; + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_add(vec_splats(e),v.vd); + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_sub(vec_splats(e),v.vd); + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_mul(vec_splats(e),v.vd); + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_div(vec_splats(e),v.vd); + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX128 diff --git a/config/simd/vsx256.hpp b/config/simd/vsx256.hpp new file mode 100644 index 0000000000..087d9e9da4 --- /dev/null +++ b/config/simd/vsx256.hpp @@ -0,0 +1,238 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX256 +#define MFEM_TEMPLATE_CONFIG_SIMD_VSX256 + +#include "builtins.h" +#define __ATTRS_ai __attribute__((__always_inline__)) + +template struct AutoSIMD; + +// **************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 4; + static const int align_size = 32; + + union{ + vector4double vd; + scalar_t vec[size]; + }; + + inline __ATTRS_ai scalar_t &operator[](int i) { return vec[i]; } + + inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[i]; } + + inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) + { + vd = v.vd; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + { + vd = vec_splats(e); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) + { + vd = vec_add(vd,v); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + { + vd = vec_add(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) + { + vd = vec_sub(vd,v); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + { + vd = vec_sub(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) + { + vd = vec_mul(vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + { + vd = vec_mul(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) + { + vd = vec_div(vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + { + vd = vec_div(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD operator-() const + { + return vec_neg(vd); + } + + inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_add(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_add(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_sub(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_sub(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_mul(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_mul(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_div(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_div(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_madd(w.vd,vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_madd(v.vd,vec_splats(e),vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_madd(vec_splats(e),v.vd,vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_mul(v.vd,w.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_mul(v.vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_mul(vec_splats(e),v.vd); + return *this; + } +}; + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_add(vec_splats(e),v.vd); + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_sub(vec_splats(e),v.vd); + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_mul(vec_splats(e),v.vd); + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r.vd = vec_div(vec_splats(e),v.vd); + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX256 diff --git a/config/simd/vsx64.hpp b/config/simd/vsx64.hpp new file mode 100644 index 0000000000..bfebfea1e1 --- /dev/null +++ b/config/simd/vsx64.hpp @@ -0,0 +1,236 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX64 +#define MFEM_TEMPLATE_CONFIG_SIMD_VSX64 + +#include "altivec.h" + +template struct AutoSIMD; + +// **************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 1; + static const int align_size = 8; + + scalar_t vec[size]; + + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[0]; } + + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[0]; } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) + { + vec[0] = v[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + { + vec[0] = e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) + { + vec[0] += v[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + { + vec[0] += e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) + { + vec[0] -= v[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + { + vec[0] -= e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) + { + vec[0] *= v[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + { + vec[0] *= e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) + { + vec[0] /= v[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + { + vec[0] /= e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const + { + AutoSIMD r; + r[0] = -vec[0]; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] + v[0]; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] + e; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] - v[0]; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] - e; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] * v[0]; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] * e; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] / v[0]; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] / e; + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] += v[0] * w[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vec[0] += v[0] * e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vec[0] += e * v[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] = v[0] * w[0]; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vec[0] = v[0] * e; + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vec[0] = e * v[0]; + return *this; + } +}; + +// ***************************************************************************** +template +inline MFEM_ALWAYS_INLINE +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e + v[0]; + return r; +} + +// ***************************************************************************** +template +inline MFEM_ALWAYS_INLINE +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e - v[0]; + return r; +} + +// ***************************************************************************** +template +inline MFEM_ALWAYS_INLINE +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e * v[0]; + return r; +} + +// ***************************************************************************** +template +inline MFEM_ALWAYS_INLINE +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e / v[0]; + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX64 diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 24ebf6ba58..00e182b52c 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -50,12 +50,26 @@ #ifndef MFEM_USE_X86INTRIN #include "simd/auto.hpp" #else +#ifdef __VSX__ +#include "simd/vsx128.hpp" +#else #include "simd/x86.hpp" #endif +#endif // --- SIMD Traits +#ifndef MFEM_USE_X86INTRIN #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 +#else +#ifdef __VSX__ +#define MFEM_SIMD_SIZE 16 +#define MFEM_TEMPLATE_BLOCK_SIZE 2 +#else +#define MFEM_SIMD_SIZE 32 +#define MFEM_TEMPLATE_BLOCK_SIZE 4 +#endif +#endif template struct AutoImplTraits diff --git a/miniapps/performance/bp.cpp b/miniapps/performance/bp.cpp index 1ecb68e953..89fe8a9d10 100644 --- a/miniapps/performance/bp.cpp +++ b/miniapps/performance/bp.cpp @@ -43,11 +43,11 @@ using namespace mfem; #endif #ifndef MESH_P -#define MESH_P 6 +#define MESH_P 3 #endif #ifndef SOL_P -#define SOL_P 6 +#define SOL_P 3 #endif #ifndef IR_ORDER diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index dc79da529e..35d8a4a5b3 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -40,6 +40,8 @@ else ifneq (,$(filter %icpc %mpiicpc,$(MFEM_CXX))) MFEM_PERF_SW = icc endif +#$(warning MFEM_PERF_SW = $(MFEM_PERF_SW)) + # Compiler specific optimizations. # For best performance, GCC 5 (or newer) is recommended. @@ -52,8 +54,12 @@ MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 endif #MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) -MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ +#MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) +MFEM_PERF_CXXFLAGS_gcc_ppc64 = $(MFEM_PERF_CXXFLAGS_gcc_common) +MFEM_PERF_CXXFLAGS_gcc_ppc64 += -mcpu=pwr8 -mtune=pwr8 \ + $(MFEM_PERF_CXXFLAGS_gcc_common) +#$(warning MFEM_PERF_CXXFLAGS_gcc_ppc64=$(MFEM_PERF_CXXFLAGS_gcc_ppc64)) # - Clang extra options: MFEM_PERF_CXXFLAGS_clang += -march=native From 0042234bb1867c24b72506ce405357d1fd55a0d5 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 25 Jun 2018 18:40:48 -0700 Subject: [PATCH 018/535] [BG/Q] QPX vectorization --- config/simd/{vsx256.hpp => qpx256.hpp} | 32 ++++++++++++++++++++++---- config/tconfig.hpp | 8 +++++-- fem/tbilinearform.hpp | 2 +- fem/tfespace.hpp | 2 ++ miniapps/performance/bp.cpp | 13 +++++------ miniapps/performance/makefile | 4 +--- 6 files changed, 43 insertions(+), 18 deletions(-) rename config/simd/{vsx256.hpp => qpx256.hpp} (90%) diff --git a/config/simd/vsx256.hpp b/config/simd/qpx256.hpp similarity index 90% rename from config/simd/vsx256.hpp rename to config/simd/qpx256.hpp index 087d9e9da4..b6285b7c54 100644 --- a/config/simd/vsx256.hpp +++ b/config/simd/qpx256.hpp @@ -9,8 +9,8 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX256 -#define MFEM_TEMPLATE_CONFIG_SIMD_VSX256 +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 +#define MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 #include "builtins.h" #define __ATTRS_ai __attribute__((__always_inline__)) @@ -38,7 +38,26 @@ template struct AutoSIMD vd = v.vd; return *this; } - + + inline vector4double vec_splats(const scalar_t &e){ + vector4double v; + v[0]=e; + v[1]=e; + v[2]=e; + v[3]=e; + return v; + } + + inline vector4double vec_div(vector4double a, + vector4double b){ + vector4double v; + v[0]=a[0]/b[0]; + v[1]=a[1]/b[1]; + v[2]=a[2]/b[2]; + v[3]=a[3]/b[3]; + return v; + } + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) { vd = vec_splats(e); @@ -231,8 +250,11 @@ AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { AutoSIMD r; - r.vd = vec_div(vec_splats(e),v.vd); + r.vec[0] = e/v.vec[0]; + r.vec[1] = e/v.vec[1]; + r.vec[2] = e/v.vec[2]; + r.vec[3] = e/v.vec[3]; return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX256 +#endif // MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 00e182b52c..c1e0bc9caa 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -51,7 +51,11 @@ #include "simd/auto.hpp" #else #ifdef __VSX__ +#warning __VSX__ #include "simd/vsx128.hpp" +#endif +#ifdef __bgq__ +#include "simd/qpx256.hpp" #else #include "simd/x86.hpp" #endif @@ -62,10 +66,10 @@ #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 #else -#ifdef __VSX__ +#ifdef __VSX__ // 128 #define MFEM_SIMD_SIZE 16 #define MFEM_TEMPLATE_BLOCK_SIZE 2 -#else +#else // 256 #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 #endif diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 0142612fea..992744cf03 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -195,7 +195,7 @@ public: const int NE = mesh.GetNE(); if (!assembled_data) { - void* result = nullptr; + void* result; const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); const auto alloc_failed = posix_memalign(&result, 32, size); if (alloc_failed) { throw ::std::bad_alloc(); } diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index a24bebeef3..5607c11870 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -36,6 +36,7 @@ namespace mfem // elements are assumed to have the same number of dofs. Such an array is // constructed from the J array of an element-to-dof Table with optional local // renumbering to ensure tensor-product local dof ordering when needed. + template class ElementDofIndexer { @@ -114,6 +115,7 @@ class TFiniteElementSpace_simple public: typedef FE FE_type; typedef IndexType index_type; + static const int dofs = FE::dofs; protected: index_type ind; diff --git a/miniapps/performance/bp.cpp b/miniapps/performance/bp.cpp index 89fe8a9d10..69571deed1 100644 --- a/miniapps/performance/bp.cpp +++ b/miniapps/performance/bp.cpp @@ -43,11 +43,11 @@ using namespace mfem; #endif #ifndef MESH_P -#define MESH_P 3 +#define MESH_P 6 #endif #ifndef SOL_P -#define SOL_P 3 +#define SOL_P 6 #endif #ifndef IR_ORDER @@ -60,7 +60,6 @@ using namespace mfem; #endif #ifndef PROBLEM -// 0- Diffusion, else TMassKernel #define PROBLEM 0 #endif @@ -68,8 +67,8 @@ using namespace mfem; #define VDIM 1 #endif -#ifndef MESH_FILE -#define MESH_FILE "../../data/fichera.mesh" +#ifdef __xlC__ +#define USE_MPI_WTIME #endif // This vector layout is used for the solution space only. @@ -186,14 +185,14 @@ int main(int argc, char *argv[]) const Ordering::Type ordering = VEC_LAYOUT; // for solution space only // 2. Parse command-line options. - const char *mesh_file = MESH_FILE; + const char *mesh_file = "../../data/fichera.mesh"; int ser_ref_levels = -1; int par_ref_levels = +1; Array nxyz; int order = sol_p; const char *basis_type = "G"; // Gauss-Lobatto bool static_cond = false; - const char *pc = "none"; + const char *pc = "lor"; bool perf = true; bool matrix_free = true; int max_iter = 50; diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 35d8a4a5b3..93210b075b 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -40,8 +40,6 @@ else ifneq (,$(filter %icpc %mpiicpc,$(MFEM_CXX))) MFEM_PERF_SW = icc endif -#$(warning MFEM_PERF_SW = $(MFEM_PERF_SW)) - # Compiler specific optimizations. # For best performance, GCC 5 (or newer) is recommended. @@ -57,7 +55,7 @@ MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) #MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) MFEM_PERF_CXXFLAGS_gcc_ppc64 = $(MFEM_PERF_CXXFLAGS_gcc_common) -MFEM_PERF_CXXFLAGS_gcc_ppc64 += -mcpu=pwr8 -mtune=pwr8 \ +MFEM_PERF_CXXFLAGS_gcc_ppc64 += -qsimd=auto \ $(MFEM_PERF_CXXFLAGS_gcc_common) #$(warning MFEM_PERF_CXXFLAGS_gcc_ppc64=$(MFEM_PERF_CXXFLAGS_gcc_ppc64)) From c0ba409a0685df515495e934c116f7404e7b5134 Mon Sep 17 00:00:00 2001 From: camierjs Date: Wed, 27 Jun 2018 13:54:04 -0700 Subject: [PATCH 019/535] [qpx] changed / to vec_swdiv and remove #warnings --- config/simd/qpx256.hpp | 34 ++++++---------------------------- config/tconfig.hpp | 3 --- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index b6285b7c54..cb58fe17ec 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -38,26 +38,7 @@ template struct AutoSIMD vd = v.vd; return *this; } - - inline vector4double vec_splats(const scalar_t &e){ - vector4double v; - v[0]=e; - v[1]=e; - v[2]=e; - v[3]=e; - return v; - } - - inline vector4double vec_div(vector4double a, - vector4double b){ - vector4double v; - v[0]=a[0]/b[0]; - v[1]=a[1]/b[1]; - v[2]=a[2]/b[2]; - v[3]=a[3]/b[3]; - return v; - } - + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) { vd = vec_splats(e); @@ -102,13 +83,13 @@ template struct AutoSIMD inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) { - vd = vec_div(vd,v.vd); + vd = vec_swdiv(vd,v.vd); return *this; } inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) { - vd = vec_div(vd,vec_splats(e)); + vd = vec_swdiv(vd,vec_splats(e)); return *this; } @@ -162,14 +143,14 @@ template struct AutoSIMD inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; - r.vd = vec_div(vd,v.vd); + r.vd = vec_swdiv(vd,v.vd); return r; } inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; - r.vd = vec_div(vd, vec_splats(e)); + r.vd = vec_swdiv(vd, vec_splats(e)); return r; } @@ -250,10 +231,7 @@ AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { AutoSIMD r; - r.vec[0] = e/v.vec[0]; - r.vec[1] = e/v.vec[1]; - r.vec[2] = e/v.vec[2]; - r.vec[3] = e/v.vec[3]; + r.vd = vec_swdiv(vec_splats(e),v.vd); return r; } diff --git a/config/tconfig.hpp b/config/tconfig.hpp index c1e0bc9caa..b26057dbfa 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -51,7 +51,6 @@ #include "simd/auto.hpp" #else #ifdef __VSX__ -#warning __VSX__ #include "simd/vsx128.hpp" #endif #ifdef __bgq__ @@ -85,10 +84,8 @@ struct AutoImplTraits static const int batch_size = 1; static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); - //static const int simd_size = 1; static const int valign_size = simd_size; - //static const int valign_size = 1; typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; From 02e9929fae22c959c7c772d9fe6ba62ffe68ab3c Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 14 Aug 2018 17:34:30 -0700 Subject: [PATCH 020/535] qpx, qpx64 & ex1 SIMD vs scalar test --- config/simd/qpx.hpp | 25 ++++ config/simd/qpx256.hpp | 5 - config/simd/qpx64.hpp | 232 +++++++++++++++++++++++++++++++++++ config/tconfig.hpp | 8 +- data/inline-hex-one.mesh | 9 ++ fem/tbilinearform.hpp | 3 +- miniapps/performance/ex1.cpp | 61 +++++++-- 7 files changed, 320 insertions(+), 23 deletions(-) create mode 100644 config/simd/qpx.hpp create mode 100644 config/simd/qpx64.hpp create mode 100644 data/inline-hex-one.mesh diff --git a/config/simd/qpx.hpp b/config/simd/qpx.hpp new file mode 100644 index 0000000000..78e2c05d54 --- /dev/null +++ b/config/simd/qpx.hpp @@ -0,0 +1,25 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_QPX_HPP +#define MFEM_TEMPLATE_CONFIG_QPX_HPP + +#include "builtins.h" + +#define __ATTRS_ai __attribute__((__always_inline__)) + +template struct AutoSIMD; + +#include "qpx64.hpp" + +#include "qpx256.hpp" + +#endif // MFEM_TEMPLATE_CONFIG_QPX_HPP diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index cb58fe17ec..40ebf1c3f6 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -12,11 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 -#include "builtins.h" -#define __ATTRS_ai __attribute__((__always_inline__)) - -template struct AutoSIMD; - // **************************************************************************** template struct AutoSIMD { diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp new file mode 100644 index 0000000000..4375a39d0b --- /dev/null +++ b/config/simd/qpx64.hpp @@ -0,0 +1,232 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 +#define MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 + +// **************************************************************************** +template struct AutoSIMD +{ + typedef scalar_t scalar_type; + static const int size = 1; + static const int align_size = 8; + + scalar_t vec[size]; + + inline __ATTRS_ai scalar_t &operator[](int i) { return vec[0]; } + + inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[0]; } + + inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) + { + vec[0] = v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + { + vec[0] = e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) + { + vec[0] += v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + { + vec[0] += e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) + { + vec[0] -= v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + { + vec[0] -= e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) + { + vec[0] *= v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + { + vec[0] *= e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) + { + vec[0] /= v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + { + vec[0] /= e; + return *this; + } + + inline __ATTRS_ai AutoSIMD operator-() const + { + AutoSIMD r; + r[0] = -vec[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] + v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] + e; + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] - v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] - e; + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] * v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] * e; + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] / v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] / e; + return r; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] += v[0] * w[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vec[0] += v[0] * e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vec[0] += e * v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] = v[0] * w[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vec[0] = v[0] * e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vec[0] = e * v[0]; + return *this; + } +}; + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e + v[0]; + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e - v[0]; + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e * v[0]; + return r; +} + +// ***************************************************************************** +template +inline __ATTRS_ai +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) +{ + AutoSIMD r; + r[0] = e / v[0]; + return r; +} + +#endif // MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 diff --git a/config/tconfig.hpp b/config/tconfig.hpp index b26057dbfa..8b0c96306a 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -54,7 +54,7 @@ #include "simd/vsx128.hpp" #endif #ifdef __bgq__ -#include "simd/qpx256.hpp" +#include "simd/qpx.hpp" #else #include "simd/x86.hpp" #endif @@ -74,7 +74,7 @@ #endif #endif -template +template struct AutoImplTraits { static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; @@ -83,9 +83,9 @@ struct AutoImplTraits static const int batch_size = 1; - static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); + static const int simd_size = simd?(MFEM_SIMD_SIZE/sizeof(complex_t)):1; - static const int valign_size = simd_size; + static const int valign_size = simd?simd_size:1; typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; diff --git a/data/inline-hex-one.mesh b/data/inline-hex-one.mesh new file mode 100644 index 0000000000..4285039b7a --- /dev/null +++ b/data/inline-hex-one.mesh @@ -0,0 +1,9 @@ +MFEM INLINE mesh v1.0 + +type = hex +nx = 1 +ny = 1 +nz = 1 +sx = 1.0 +sy = 1.0 +sz = 1.0 diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 992744cf03..7034e14dd4 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -29,9 +29,10 @@ namespace mfem // real_t - mesh nodes, sol basis, mesh basis data type template > + typename impl_traits_t = AutoImplTraits > class TBilinearForm : public Operator { public: diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index 16e9662cb3..87f0d9fcda 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -38,8 +38,8 @@ using namespace mfem; // Define template parameters for optimized build. const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 8; // mesh curvature (default: 3) -const int sol_p = 8; // solution order (default: 3) +const int mesh_p = 2; // mesh curvature (default: 3) +const int sol_p = 2; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; @@ -58,7 +58,8 @@ typedef TConstantCoefficient<> coeff_t; typedef TIntegrator integ_t; // Static bilinear form type, combining the above types -typedef TBilinearForm HPCBilinearForm; +typedef TBilinearForm avx_HPCBilinearForm; +typedef TBilinearForm m64_HPCBilinearForm; int main(int argc, char *argv[]) { @@ -133,7 +134,7 @@ int main(int argc, char *argv[]) // the same code. Mesh *mesh = new Mesh(mesh_file, 1, 1); int dim = mesh->Dimension(); - + // 3. Check if the optimized version matches the given mesh if (perf) { @@ -172,6 +173,16 @@ int main(int argc, char *argv[]) MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" " the LOR preconditioner yet"); } + + const int NE = mesh->GetNE(); + AutoImplTraits simd_impl; + const bool simd = (NE > simd_impl.simd_size); + printf("\033[32m[ex1] GetNE()=%d\033[m\n",NE); + if (simd){ + printf("\033[32m[ex1] SIMD!\033[m\n"); + }else{ + printf("\033[32m[ex1] SCALAR!\033[m\n"); + } // 5. Define a finite element space on the mesh. Here we use continuous // Lagrange finite elements of the specified order. If order < 1, we @@ -270,7 +281,8 @@ int main(int argc, char *argv[]) // Pre-allocate sparsity assuming dense element matrices a->UsePrecomputedSparsity(); - HPCBilinearForm *a_hpc = NULL; + avx_HPCBilinearForm *a_hpc_simd = NULL; + m64_HPCBilinearForm *a_hpc_scalar = NULL; Operator *a_oper = NULL; if (!perf) @@ -282,14 +294,23 @@ int main(int argc, char *argv[]) else { // High-performance assembly/evaluation using the templated operator type - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (simd) + a_hpc_simd = new avx_HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + else + a_hpc_scalar = new m64_HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); if (matrix_free) { - a_hpc->Assemble(); // partial assembly + if (simd) + a_hpc_simd->Assemble(); // partial assembly + else + a_hpc_scalar->Assemble(); // partial assembly } else { - a_hpc->AssembleBilinearForm(*a); // full matrix assembly + if (simd) + a_hpc_simd->AssembleBilinearForm(*a); // full matrix assembly + else + a_hpc_scalar->AssembleBilinearForm(*a); // full matrix assembly } } tic_toc.Stop(); @@ -303,8 +324,13 @@ int main(int argc, char *argv[]) Vector B, X; if (perf && matrix_free) { - a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "Size of linear system: " << a_hpc->Height() << endl; + if (simd){ + a_hpc_simd->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "Size of linear system: " << a_hpc_simd->Height() << endl; + }else{ + a_hpc_scalar->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "Size of linear system: " << a_hpc_scalar->Height() << endl; + } } else { @@ -336,7 +362,10 @@ int main(int argc, char *argv[]) else { a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); + if (simd) + a_hpc_simd->AssembleBilinearForm(*a_pc); + else + a_hpc_scalar->AssembleBilinearForm(*a_pc); a_pc->FormSystemMatrix(ess_tdof_list, A_pc); } } @@ -362,7 +391,10 @@ int main(int argc, char *argv[]) // 13. Recover the solution as a finite element grid function. if (perf && matrix_free) { - a_hpc->RecoverFEMSolution(X, *b, x); + if (simd) + a_hpc_simd->RecoverFEMSolution(X, *b, x); + else + a_hpc_scalar->RecoverFEMSolution(X, *b, x); } else { @@ -390,7 +422,10 @@ int main(int argc, char *argv[]) // 16. Free the used memory. delete a; - delete a_hpc; + if (simd) + delete a_hpc_simd; + else + delete a_hpc_scalar; if (a_oper != &A) { delete a_oper; } delete a_pc; delete b; From 4fc053f0a9e2e495deda9e89cce3d88822d558af Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 14 Aug 2018 18:14:47 -0700 Subject: [PATCH 021/535] qpx64 size fix --- config/simd/qpx64.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp index 4375a39d0b..99b4fb24f8 100644 --- a/config/simd/qpx64.hpp +++ b/config/simd/qpx64.hpp @@ -189,7 +189,7 @@ template struct AutoSIMD template inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) + const AutoSIMD &v) { AutoSIMD r; r[0] = e + v[0]; @@ -200,7 +200,7 @@ AutoSIMD operator+(const scalar_t &e, template inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) + const AutoSIMD &v) { AutoSIMD r; r[0] = e - v[0]; @@ -211,7 +211,7 @@ AutoSIMD operator-(const scalar_t &e, template inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) + const AutoSIMD &v) { AutoSIMD r; r[0] = e * v[0]; @@ -222,7 +222,7 @@ AutoSIMD operator*(const scalar_t &e, template inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) + const AutoSIMD &v) { AutoSIMD r; r[0] = e / v[0]; From 091cedfbcbb2a9122891882627494a7dba316873 Mon Sep 17 00:00:00 2001 From: camierjs Date: Wed, 15 Aug 2018 16:39:09 -0700 Subject: [PATCH 022/535] okrtc + ex1 --- miniapps/performance/bp.cpp | 7 +- miniapps/performance/bprtc.cpp | 863 ++++++++++++++++++++++++++++++++ miniapps/performance/ex1.cpp | 4 +- miniapps/performance/ex1rtc.cpp | 429 ++++++++++++++++ miniapps/performance/makefile | 19 + 5 files changed, 1316 insertions(+), 6 deletions(-) create mode 100644 miniapps/performance/bprtc.cpp create mode 100644 miniapps/performance/ex1rtc.cpp diff --git a/miniapps/performance/bp.cpp b/miniapps/performance/bp.cpp index 69571deed1..3dff14c54c 100644 --- a/miniapps/performance/bp.cpp +++ b/miniapps/performance/bp.cpp @@ -43,11 +43,11 @@ using namespace mfem; #endif #ifndef MESH_P -#define MESH_P 6 +#define MESH_P 2 #endif #ifndef SOL_P -#define SOL_P 6 +#define SOL_P 2 #endif #ifndef IR_ORDER @@ -170,8 +170,7 @@ typedef VectorLayout vec_layout_t; #endif // Static bilinear form type, combining the above types -typedef TBilinearForm HPCBilinearForm; +typedef TBilinearForm HPCBilinearForm; int main(int argc, char *argv[]) { diff --git a/miniapps/performance/bprtc.cpp b/miniapps/performance/bprtc.cpp new file mode 100644 index 0000000000..90f9b08746 --- /dev/null +++ b/miniapps/performance/bprtc.cpp @@ -0,0 +1,863 @@ +// Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights +// reserved. See files LICENSE and NOTICE for details. +// +// This file is part of CEED, a collection of benchmarks, miniapps, software +// libraries and APIs for efficient high-order finite element and spectral +// element discretizations for exascale applications. For more information and +// source code availability see http://github.com/ceed. +// +// The CEED research is supported by the Exascale Computing Project +// (17-SC-20-SC), a collaborative effort of two U.S. Department of Energy +// organizations (Office of Science and the National Nuclear Security +// Administration) responsible for the planning and preparation of a capable +// exascale ecosystem, including software, applications, hardware, advanced +// system engineering and early testbed platforms, in support of the nation's +// exascale computing imperative. + + +//============================================================================== +// MFEM Bake-off Problems 1, 2, 3, and 4 +// Version 1 +// +// Compile with: see README.md +// +// Sample runs: see README.md +// +// Description: These benchmarks (CEED Bake-off Problems BP1 and BP3) test the +// performance of high-order mass (BP1) and stiffness (BP3) matrix +// operator evaluation with "partial assembly" algorithms. +// +// Code is based on MFEM's HPC ex1, http://mfem.org/performance. +// +// More details about CEED's bake-off problems can be found at +// http://ceed.exascaleproject.org/bps. +//============================================================================== + +#include + +using namespace mfem; + +#ifndef GEOM +#define GEOM Geometry::CUBE +#endif + +#ifndef MESH_P +#define MESH_P 2 +#endif + +#ifndef SOL_P +#define SOL_P 2 +#endif + +#ifndef IR_ORDER +#define IR_ORDER 0 +#endif + +#ifndef IR_TYPE +// 0 - Gauss quadrature, 1 - Gauss-Lobatto quadrature +#define IR_TYPE 0 +#endif + +#ifndef PROBLEM +#define PROBLEM 0 +#endif + +#ifndef VDIM +#define VDIM 1 +#endif + +#ifdef __xlC__ +#define USE_MPI_WTIME +#endif + +// This vector layout is used for the solution space only. +#ifndef VEC_LAYOUT +#define VEC_LAYOUT Ordering::byVDIM +#endif + +// Define template parameters for optimized build. +const Geometry::Type geom = GEOM; // mesh elements (default: hex) +const int mesh_p = MESH_P; // mesh curvature (default: 3) +const int sol_p = SOL_P; // solution order (default: 3) +const int ir_q = IR_TYPE ? sol_p+1 : sol_p+2; +const int ir_order = IR_ORDER ? IR_ORDER : + (IR_TYPE ? 2*ir_q-3 : 2*ir_q-1); + +#include +#include +#include + +using namespace std; + +IntegrationRules GaussLobattoRules(0, Quadrature1D::GaussLobatto); + +template +class GaussLobattoIntegrationRule + : public TProductIntegrationRule +{ +public: + typedef TProductIntegrationRule base_class; + + using base_class::geom; + using base_class::order; + using base_class::qpts_1d; + +protected: + using base_class::weights_1d; + +public: + GaussLobattoIntegrationRule() + { + const IntegrationRule &ir_1d = Get1DIntRule(); + MFEM_ASSERT(ir_1d.GetNPoints() == qpts_1d, "quadrature rule mismatch"); + for (int j = 0; j < qpts_1d; j++) + { + weights_1d.data[j] = ir_1d.IntPoint(j).weight; + } + } + + static const IntegrationRule &Get1DIntRule() + { + return GaussLobattoRules.Get(Geometry::SEGMENT, order); + } + static const IntegrationRule &GetIntRule() + { + return GaussLobattoRules.Get(geom, order); + } +}; + + +// Static mesh type +typedef H1_FiniteElement mesh_fe_t; +typedef H1_FiniteElementSpace mesh_fes_t; +typedef TMesh mesh_t; + +// Static solution finite element space type +typedef H1_FiniteElement sol_fe_t; +typedef H1_FiniteElementSpace sol_fes_t; + +// Static quadrature, coefficient and integrator types +#if (IR_TYPE == 0) +typedef TIntegrationRule int_rule_t; +#else +const int rdim = Geometry::Constants::Dimension; +typedef GaussLobattoIntegrationRule + int_rule_t; +#endif +typedef TConstantCoefficient<> coeff_t; +#if (PROBLEM == 0) +typedef TIntegrator integ_t; +#else +typedef TIntegrator integ_t; +#endif +#if (VDIM == 1) +typedef ScalarLayout vec_layout_t; +#else +typedef VectorLayout vec_layout_t; +#endif + +// Static bilinear form type, combining the above types +typedef TBilinearForm HPCBilinearForm; +enum PCType { NONE, LOR, HO }; + +// Workaround for a bug in XL C++ on BG/Q version 12.01.0000.0014 +#if defined(__xlC__) && (__xlC__ < 0x0d00) +#include <../mfem/linalg/tlayout.hpp> +namespace mfem +{ +const int mesh_dim = Geometry::Constants::Dimension; +template class StridedLayout1D; +} +#endif // defined(__xlC__) && (__xlC__ < 0x0d00) + +// ***************************************************************************** +// -L/home/camier1/home/mfem/x86 -lmfem -L/home/camier1/usr/local/hypre/2.11.2/lib -lHYPRE -L/home/camier1/usr/local/metis/5.1.0/lib -lmetis -lrt -ldl +// ***************************************************************************** +void bp_kernel(const int num_procs, + const HYPRE_Int size, + const int myid, + const int dim, + const int vdim, + const Ordering::Type ordering, + const int order, + const bool static_cond, + const bool perf, + const bool matrix_free, + const int max_iter, + const bool visualization, + const int pc_choice, // PCType + const int basis, + // ************************************************************** + const bool simd, + // ************************************************************** + const Geometry::Type geom, + const int mesh_p, + const int sol_p, + const int ir_q, + const int ir_order, + // ************************************************************** + const char* __restrict mesh_file, + const ParMesh* __restrict pmesh, + ParFiniteElementSpace* __restrict fespace, + ParFiniteElementSpace* __restrict fespace_lor){ + // Should be captured while parsing + using namespace std; + using namespace mfem; + enum PCType { NONE, LOR, HO }; + const Geometry::Type g = Geometry::CUBE; + + typedef H1_FiniteElement mesh_fe_t; + typedef H1_FiniteElementSpace mesh_fes_t; + typedef TMesh mesh_t; + + typedef H1_FiniteElement sol_fe_t; + typedef H1_FiniteElementSpace sol_fes_t; + + typedef TIntegrationRule int_rule_t; + + typedef TConstantCoefficient<> coeff_t; + typedef TIntegrator integ_t; + + typedef ScalarLayout vec_layout_t; + + typedef TBilinearForm HPCBilinearForm; + + /* + typedef H1_FiniteElementSpace mesh_fes_t; + typedef TMesh mesh_t; + typedef TIntegrationRule int_rule_t; + + typedef TBilinearForm HPCBilinearForm; + */ + + // 9. Determine the list of true (i.e. parallel conforming) essential + // boundary dofs. In this example, the boundary conditions are defined + // by marking all the boundary attributes from the mesh as essential + // (Dirichlet) and converting them to a list of true dofs. + mfem::Array ess_tdof_list; + if (pmesh->bdr_attributes.Size()) + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 1; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + + // 10. Set up the parallel linear form b(.) which corresponds to the + // right-hand side of the FEM linear system, which in this case is + // (1,phi_i) where phi_i are the basis functions in fespace. + ParLinearForm *b = new ParLinearForm(fespace); + ConstantCoefficient one(1.0); + Vector uvec(vdim); + for (int i = 0; i < vdim; i++) + { + uvec(i) = i + 1.0; + } + uvec /= uvec.Norml2(); + VectorConstantCoefficient unit_vec(uvec); + if (vdim == 1) + { + b->AddDomainIntegrator(new DomainLFIntegrator(one)); + } + else + { + b->AddDomainIntegrator(new VectorDomainLFIntegrator(unit_vec)); + } + b->Assemble(); + + // 11. Define the solution vector x as a parallel finite element grid + // function corresponding to fespace. Initialize x with initial guess of + // zero, which satisfies the boundary conditions. + ParGridFunction x(fespace); + x = 0.0; + + // 12. Set up the parallel bilinear form a(.,.) on the finite element space + // that will hold the matrix corresponding to the Laplacian operator. + ParBilinearForm *a = new ParBilinearForm(fespace); + ParBilinearForm *a_pc = NULL; + if (pc_choice == LOR) { a_pc = new ParBilinearForm(fespace_lor); } + if (pc_choice == HO) { a_pc = new ParBilinearForm(fespace); } + + // 13. Assemble the parallel bilinear form and the corresponding linear + // system, applying any necessary transformations such as: parallel + // assembly, eliminating boundary conditions, applying conforming + // constraints for non-conforming AMR, static condensation, etc. + if (static_cond) + { + a->EnableStaticCondensation(); + MFEM_VERIFY(pc_choice != LOR, + "cannot use LOR preconditioner with static condensation"); + } + + if (myid == 0) + { + cout << "Assembling the local matrix ..." << flush; + } +#ifdef USE_MPI_WTIME + double my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + // Pre-allocate sparsity assuming dense element matrices; the actual memory + // allocation happens when a->Assemble() is called. + a->UsePrecomputedSparsity(); + + HPCBilinearForm *a_hpc = NULL; + Operator *a_oper = NULL; + + if (!perf) + { + // Standard assembly using a diffusion domain integrator + if (vdim == 1) + { + a->AddDomainIntegrator(new DiffusionIntegrator(one)); + } + else + { + a->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); + } + a->Assemble(); + } + else + { + // High-performance assembly/evaluation using the templated operator type + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (matrix_free) + { + a_hpc->Assemble(); // partial assembly + } + else + { + a_hpc->AssembleBilinearForm(*a); // full matrix assembly + } + } +#ifdef USE_MPI_WTIME + double rt_min, rt_max, my_rt; + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + double rt_min, rt_max, my_rt; + my_rt = tic_toc.RealTime(); +#endif + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + cout << " done, " << rt_max << " (" << rt_min << ") s." << endl; + cout << "\n\"DOFs/sec\" in assembly: " + << 1e-6*size/rt_max << " (" + << 1e-6*size/rt_min << ") million.\n" << endl; + } + + // 14. Define and apply a parallel PCG solver for AX=B with the BoomerAMG + // preconditioner from hypre. + + // Setup the operator matrix (if applicable) + HypreParMatrix A; + Vector B, X; + if (myid == 0) + { + cout << "FormLinearSystem() ..." << endl; + } +#ifdef USE_MPI_WTIME + my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + if (perf && matrix_free) + { + a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + if (myid == 0) + { + cout << "Size of linear system: " << size << endl; + } + } + else + { + a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + HYPRE_Int glob_size = A.GetGlobalNumRows(); + HYPRE_Int glob_nnz = A.NNZ(); + if (myid == 0) + { + cout << "Size of linear system: " << glob_size << endl; + cout << "Average nonzero entries per row: " + << 1.0*glob_nnz/glob_size << endl; + } + a_oper = &A; + } +#ifdef USE_MPI_WTIME + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + my_rt = tic_toc.RealTime(); +#endif + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + cout << "FormLinearSystem() ... done, " << rt_max << " (" << rt_min + << ") s." << endl; + cout << "\n\"DOFs/sec\" in FormLinearSystem(): " + << 1e-6*size/rt_max << " (" + << 1e-6*size/rt_min << ") million.\n" << endl; + } + + // Setup the matrix used for preconditioning + if (myid == 0) + { + cout << "Assembling the preconditioning matrix ..." << flush; + } +#ifdef USE_MPI_WTIME + my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + + HypreParMatrix A_pc; + if (pc_choice == LOR) + { + // TODO: assemble the LOR matrix using the performance code + if (vdim == 1) + { + a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); + } + else + { + a_pc->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); + } + a_pc->UsePrecomputedSparsity(); + a_pc->Assemble(); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + else if (pc_choice == HO) + { + if (!matrix_free) + { + A_pc.MakeRef(A); // matrix already assembled, reuse it + } + else + { + a_pc->UsePrecomputedSparsity(); + a_hpc->AssembleBilinearForm(*a_pc); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + } +#ifdef USE_MPI_WTIME + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + my_rt = tic_toc.RealTime(); +#endif + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + cout << " done, " << rt_max << "s." << endl; + } + + // Solve with CG or PCG, depending if the matrix A_pc is available + CGSolver *pcg; + pcg = new CGSolver(MPI_COMM_WORLD); + pcg->SetRelTol(1e-6); + pcg->SetMaxIter(max_iter); + pcg->SetPrintLevel(3); + + HypreSolver *amg = NULL; + + pcg->SetOperator(*a_oper); + if (pc_choice != NONE) + { + HypreBoomerAMG *bamg = new HypreBoomerAMG(A_pc); + if (vdim > 1 && ordering == Ordering::byVDIM) + { + bamg->SetSystemsOptions(vdim); + } + amg = bamg; + pcg->SetPreconditioner(*amg); + } + +#ifdef USE_MPI_WTIME + my_rt_start = MPI_Wtime(); +#else + tic_toc.Clear(); + tic_toc.Start(); +#endif + + pcg->Mult(B, X); + +#ifdef USE_MPI_WTIME + my_rt = MPI_Wtime() - my_rt_start; +#else + tic_toc.Stop(); + my_rt = tic_toc.RealTime(); +#endif + delete amg; + + MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); + MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); + if (myid == 0) + { + // Note: In the pcg algorithm, the number of operator Mult() calls is + // N_iter and the number of preconditioner Mult() calls is N_iter+1. + cout << "Total CG time: " << rt_max << " (" << rt_min << ") sec." + << endl; + cout << "Time per CG step: " + << rt_max / pcg->GetNumIterations() << " (" + << rt_min / pcg->GetNumIterations() << ") sec." << endl; + cout << "\n\"DOFs/sec\" in CG: " + << 1e-6*size*pcg->GetNumIterations()/rt_max << " (" + << 1e-6*size*pcg->GetNumIterations()/rt_min << ") million.\n" + << endl; + } + + // 15. Recover the parallel grid function corresponding to X. This is the + // local finite element solution on each processor. + if (perf && matrix_free) + { + a_hpc->RecoverFEMSolution(X, *b, x); + } + else + { + a->RecoverFEMSolution(X, *b, x); + } + + // 16. Save the refined mesh and the solution in parallel. This output can + // be viewed later using GLVis: "glvis -np -m mesh -g sol". + if (false) + { + ostringstream mesh_name, sol_name; + mesh_name << "mesh." << setfill('0') << std::setw(6) << myid; + sol_name << "sol." << setfill('0') << std::setw(6) << myid; + + ofstream mesh_ofs(mesh_name.str().c_str()); + mesh_ofs.precision(8); + pmesh->Print(mesh_ofs); + + ofstream sol_ofs(sol_name.str().c_str()); + sol_ofs.precision(8); + x.Save(sol_ofs); + } + + // 17. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock << "parallel " << num_procs << " " << myid << "\n"; + sol_sock.precision(8); + sol_sock << "solution\n" << *pmesh << x << flush; + } + + // 18. Free the used memory. + delete a; + delete a_hpc; + if (a_oper != &A) { delete a_oper; } + delete a_pc; + delete b; + delete pmesh; + delete pcg; +} + + +// ***************************************************************************** +int main(int argc, char *argv[]){ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + const int vdim = VDIM; + const Ordering::Type ordering = VEC_LAYOUT; // for solution space only + + // 2. Parse command-line options. + const char *mesh_file = "../../data/fichera.mesh"; + int ser_ref_levels = -1; + int par_ref_levels = +1; + Array nxyz; + int order = sol_p; + const char *basis_type = "G"; // Gauss-Lobatto + bool static_cond = false; + const char *pc = "lor"; + bool perf = true; + bool matrix_free = true; + int max_iter = 50; + bool visualization = 1; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", + "Number of times to refine the mesh uniformly in serial."); + args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", + "Number of times to refine the mesh uniformly in parallel."); + args.AddOption(&nxyz, "-c", "--cartesian-partitioning", + "Use Cartesian partitioning."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&basis_type, "-b", "--basis-type", + "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); + args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", + "Enable high-performance, tensor-based, assembly/evaluation."); + args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", + "Use matrix-free evaluation or efficient matrix assembly in " + "the high-performance version."); + args.AddOption(&pc, "-pc", "--preconditioner", + "Preconditioner: lor - low-order-refined (matrix-free) AMG, " + "ho - high-order (assembled) AMG, none."); + args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", + "--no-static-condensation", "Enable static condensation."); + args.AddOption(&max_iter, "-mi", "--max-iter", + "Maximum number of iterations."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + if (myid == 0) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + if (static_cond && perf && matrix_free) + { + if (myid == 0) + { + cout << "\nStatic condensation can not be used with matrix-free" + " evaluation!\n" << endl; + } + MPI_Finalize(); + return 2; + } + MFEM_VERIFY(perf || !matrix_free, + "--standard-version is not compatible with --matrix-free"); + if (myid == 0) + { + args.PrintOptions(cout); + } + + PCType pc_choice; + if (!strcmp(pc, "ho")) { pc_choice = HO; } + else if (!strcmp(pc, "lor")) { pc_choice = LOR; } + else if (!strcmp(pc, "none")) { pc_choice = NONE; } + else + { + mfem_error("Invalid Preconditioner specified"); + return 3; + } + + // See class BasisType in fem/fe_coll.hpp for available basis types + int basis = BasisType::GetType(basis_type[0]); + if (myid == 0) + { + cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; + } + // 3. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 4. Check if the optimized version matches the given mesh + if (perf) + { + if (myid == 0) + { + cout << "High-performance version using integration rule with " + << int_rule_t::qpts << " points ..." << endl; + cout << "Quadrature rule type: " + << (IR_TYPE == 0 ? "Gauss" : "Gauss-Lobatto") << endl; + } + if (!mesh_t::MatchesGeometry(*mesh)) + { + if (myid == 0) + { + cout << "The given mesh does not match the optimized 'geom' parameter.\n" + << "Recompile with suitable 'geom' value." << endl; + } + delete mesh; + MPI_Finalize(); + return 4; + } + else if (!mesh_t::MatchesNodes(*mesh)) + { + if (myid == 0) + { + cout << "Switching the mesh curvature to match the " + << "optimized value (order " << mesh_p << ") ..." << endl; + } + mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); + } + } + + // 5. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 10,000 elements. + { + int ref_levels = + (int)floor(log(10000./mesh->GetNE())/log(2.)/dim); + ref_levels = (ser_ref_levels != -1) ? ser_ref_levels : ref_levels; + for (int l = 0; l < ref_levels; l++) + { + if (myid == 0) + { + cout << "Serial refinement: level " << l << " -> level " << l+1 + << " ..." << flush; + } + mesh->UniformRefinement(); + MPI_Barrier(MPI_COMM_WORLD); + if (myid == 0) + { + cout << " done." << endl; + } + } + } + if (!perf && mesh->NURBSext) + { + const int new_mesh_p = std::min(sol_p, mesh_p); + if (myid == 0) + { + cout << "NURBS mesh: switching the mesh curvature to be " + << "min(sol_p, mesh_p) = " << new_mesh_p << " ..." << endl; + } + mesh->SetCurvature(new_mesh_p, false, -1, Ordering::byNODES); + } + + // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + MFEM_VERIFY(nxyz.Size() == 0 || nxyz.Size() == mesh->SpaceDimension(), + "Expected " << mesh->SpaceDimension() << " integers with the " + "option --cartesian-partitioning."); + int *partitioning = nxyz.Size() ? mesh->CartesianPartitioning(nxyz) : NULL; + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh, partitioning); + delete [] partitioning; + delete mesh; + { + for (int l = 0; l < par_ref_levels; l++) + { + if (myid == 0) + { + cout << "Parallel refinement: level " << l << " -> level " << l+1 + << " ..." << flush; + } + pmesh->UniformRefinement(); + MPI_Barrier(MPI_COMM_WORLD); + if (myid == 0) + { + cout << " done." << endl; + } + } + } + if (pmesh->MeshGenerator() & 1) // simplex mesh + { + MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" + " the LOR preconditioner yet"); + } + + pmesh->PrintInfo(cout); + // 7. Define a parallel finite element space on the parallel mesh. Here we + // use continuous Lagrange finite elements of the specified order. If + // order < 1, we instead use an isoparametric/isogeometric space. + FiniteElementCollection *fec; + if (order > 0) + { + fec = new H1_FECollection(order, dim, basis); + } + else if (pmesh->GetNodes()) + { + fec = pmesh->GetNodes()->OwnFEC(); + if (myid == 0) + { + cout << "Using isoparametric FEs: " << fec->Name() << endl; + } + } + else + { + fec = new H1_FECollection(order = 1, dim, basis); + } + ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec, + vdim, ordering); + HYPRE_Int size = fespace->GlobalTrueVSize(); + if (myid == 0) + { + cout << "Number of finite element unknowns: " << size << endl; + } + + ParMesh *pmesh_lor = NULL; + FiniteElementCollection *fec_lor = NULL; + ParFiniteElementSpace *fespace_lor = NULL; + if (pc_choice == LOR) + { + int basis_lor = basis; + if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } + pmesh_lor = new ParMesh(pmesh, order, basis_lor); + fec_lor = new H1_FECollection(1, dim); + fespace_lor = new ParFiniteElementSpace(pmesh_lor, fec_lor, + vdim, ordering); + } + + // 8. Check if the optimized version matches the given space + if (perf && !sol_fes_t::Matches(*fespace)) + { + if (myid == 0) + { + cout << "The given order does not match the optimized parameter.\n" + << "Recompile with suitable 'sol_p' value." << endl; + } + delete fespace; + delete fec; + delete mesh; + MPI_Finalize(); + return 5; + } + + bp_kernel(num_procs, + size, + myid, + dim, + vdim, + ordering, + order, + static_cond, + perf, + matrix_free, + max_iter, + visualization, + pc_choice, + basis, + true, // simd + geom, + mesh_p, + sol_p, + ir_q, + ir_order, + mesh_file, + pmesh, + fespace, + fespace_lor); + + delete fespace; + delete fespace_lor; + delete fec_lor; + delete pmesh_lor; + if (order > 0) { delete fec; } + + MPI_Finalize(); + + return 0; +} diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index 87f0d9fcda..e029a09c3c 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -38,8 +38,8 @@ using namespace mfem; // Define template parameters for optimized build. const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 2; // mesh curvature (default: 3) -const int sol_p = 2; // solution order (default: 3) +const int mesh_p = 3; // mesh curvature (default: 3) +const int sol_p = 3; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; diff --git a/miniapps/performance/ex1rtc.cpp b/miniapps/performance/ex1rtc.cpp new file mode 100644 index 0000000000..b39aba77c8 --- /dev/null +++ b/miniapps/performance/ex1rtc.cpp @@ -0,0 +1,429 @@ +// MFEM Example 1 - High-Performance Version +// +// Compile with: make ex1 +// +// Sample runs: ex1 -m ../../data/fichera.mesh -perf -mf -pc lor +// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho +// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho -sc +// ex1 -m ../../data/fichera.mesh -std -asm -pc ho +// ex1 -m ../../data/fichera.mesh -std -asm -pc ho -sc +// ex1 -m ../../data/amr-hex.mesh -perf -asm -pc ho -sc +// ex1 -m ../../data/amr-hex.mesh -std -asm -pc ho -sc +// ex1 -m ../../data/ball-nurbs.mesh -perf -asm -pc ho -sc +// ex1 -m ../../data/ball-nurbs.mesh -std -asm -pc ho -sc +// ex1 -m ../../data/pipe-nurbs.mesh -perf -mf -pc lor +// ex1 -m ../../data/pipe-nurbs.mesh -std -asm -pc ho -sc +// +// Description: This example code demonstrates the use of MFEM to define a +// simple finite element discretization of the Laplace problem +// -Delta u = 1 with homogeneous Dirichlet boundary conditions. +// Specifically, we discretize using a FE space of the specified +// order, or if order < 1 using an isoparametric/isogeometric +// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for +// NURBS mesh, etc.) +// +// The example highlights the use of mesh refinement, finite +// element grid functions, as well as linear and bilinear forms +// corresponding to the left-hand side and right-hand side of the +// discrete linear system. We also cover the explicit elimination +// of essential boundary conditions, static condensation, and the +// optional connection to the GLVis tool for visualization. + +#include "mfem-performance.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +enum PCType { NONE, LOR, HO }; + +// ***************************************************************************** +// * High-Performance Benchmark Open Kernel +// ***************************************************************************** +void bp_kernel(const Geometry::Type geom, + const int msh_p, + const int sol_p, + const int dim, + // ************************************************************** + const bool perf, + const bool matrix_free, + const int pc_choice, // PCType + const bool static_cond, + const bool visualization, + const Mesh* __restrict mesh, + FiniteElementSpace* __restrict fespace, + FiniteElementSpace* __restrict fespace_lor){ + // Should be captured while parsing + using namespace std; + using namespace mfem; + enum PCType { NONE, LOR, HO }; + // Hack to deal with runtime template instanciation +#ifndef __OKRTC__ +#define GEOM Geometry::CUBE +#define MSH_P 2 +#define SOL_P 2 +#define DIM 3 +#define IR_ORDER (2*SOL_P+DIM-1) +#else +#undef GEOM +#define GEOM (Geometry::Type)geom +#undef MSH_P +#define MSH_P msh_p +#undef SOL_P +#define SOL_P sol_p +#undef IR_ORDER +#define IR_ORDER 2*sol_p+dim-1 +#endif + + typedef H1_FiniteElement mesh_fe_t; + typedef H1_FiniteElementSpace mesh_fes_t; + typedef TMesh mesh_t; + typedef H1_FiniteElement sol_fe_t; + typedef H1_FiniteElementSpace sol_fes_t; + typedef TIntegrationRule int_rule_t; + typedef TConstantCoefficient<> coeff_t; + typedef TIntegrator integ_t; + typedef TBilinearForm HPCBilinearForm; + + + // 7. Determine the list of true (i.e. conforming) essential boundary dofs. + // In this example, the boundary conditions are defined by marking all + // the boundary attributes from the mesh as essential (Dirichlet) and + // converting them to a list of true dofs. + Array ess_tdof_list; + if (mesh->bdr_attributes.Size()) + { + Array ess_bdr(mesh->bdr_attributes.Max()); + ess_bdr = 1; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + + // 8. Set up the linear form b(.) which corresponds to the right-hand side of + // the FEM linear system, which in this case is (1,phi_i) where phi_i are + // the basis functions in the finite element fespace. + LinearForm *b = new LinearForm(fespace); + ConstantCoefficient one(1.0); + b->AddDomainIntegrator(new DomainLFIntegrator(one)); + b->Assemble(); + + // 9. Define the solution vector x as a finite element grid function + // corresponding to fespace. Initialize x with initial guess of zero, + // which satisfies the boundary conditions. + GridFunction x(fespace); + x = 0.0; + + // 10. Set up the bilinear form a(.,.) on the finite element space that will + // hold the matrix corresponding to the Laplacian operator -Delta. + // Optionally setup a form to be assembled for preconditioning (a_pc). + BilinearForm *a = new BilinearForm(fespace); + BilinearForm *a_pc = NULL; + if (pc_choice == LOR) { a_pc = new BilinearForm(fespace_lor); } + if (pc_choice == HO) { a_pc = new BilinearForm(fespace); } + + // 11. Assemble the bilinear form and the corresponding linear system, + // applying any necessary transformations such as: eliminating boundary + // conditions, applying conforming constraints for non-conforming AMR, + // static condensation, etc. + if (static_cond) + { + a->EnableStaticCondensation(); + MFEM_VERIFY(pc_choice != LOR, + "cannot use LOR preconditioner with static condensation"); + } + + cout << "Assembling the bilinear form ..." << flush; + tic_toc.Clear(); + tic_toc.Start(); + // Pre-allocate sparsity assuming dense element matrices + a->UsePrecomputedSparsity(); + + HPCBilinearForm *a_hpc = NULL; + Operator *a_oper = NULL; + + if (!perf) + { + // Standard assembly using a diffusion domain integrator + a->AddDomainIntegrator(new DiffusionIntegrator(one)); + a->Assemble(); + } + else + { + // High-performance assembly/evaluation using the templated operator type + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + if (matrix_free) + { + a_hpc->Assemble(); // partial assembly + } + else + { + a_hpc->AssembleBilinearForm(*a); // full matrix assembly + } + } + tic_toc.Stop(); + cout << " done, " << tic_toc.RealTime() << "s." << endl; + + // 12. Solve the system A X = B with CG. In the standard case, use a simple + // symmetric Gauss-Seidel preconditioner. + + // Setup the operator matrix (if applicable) + SparseMatrix A; + Vector B, X; + if (perf && matrix_free) + { + a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "Size of linear system: " << a_hpc->Height() << endl; + } + else + { + a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + cout << "Size of linear system: " << A.Height() << endl; + a_oper = &A; + } + + // Setup the matrix used for preconditioning + cout << "Assembling the preconditioning matrix ..." << flush; + tic_toc.Clear(); + tic_toc.Start(); + + SparseMatrix A_pc; + if (pc_choice == LOR) + { + // TODO: assemble the LOR matrix using the performance code + a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); + a_pc->UsePrecomputedSparsity(); + a_pc->Assemble(); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + else if (pc_choice == HO) + { + if (!matrix_free) + { + A_pc.MakeRef(A); // matrix already assembled, reuse it + } + else + { + a_pc->UsePrecomputedSparsity(); + a_hpc->AssembleBilinearForm(*a_pc); + a_pc->FormSystemMatrix(ess_tdof_list, A_pc); + } + } + + tic_toc.Stop(); + cout << " done, " << tic_toc.RealTime() << "s." << endl; + + // Solve with CG or PCG, depending if the matrix A_pc is available + tic_toc.Clear(); + tic_toc.Start(); + if (pc_choice != NONE) + { + GSSmoother M(A_pc); + PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); + } + else + { + CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + } + tic_toc.Stop(); + cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; + + // 13. Recover the solution as a finite element grid function. + if (perf && matrix_free) + { + a_hpc->RecoverFEMSolution(X, *b, x); + } + else + { + a->RecoverFEMSolution(X, *b, x); + } + + // 14. Save the refined mesh and the solution. This output can be viewed later + // using GLVis: "glvis -m refined.mesh -g sol.gf". + ofstream mesh_ofs("refined.mesh"); + mesh_ofs.precision(8); + mesh->Print(mesh_ofs); + ofstream sol_ofs("sol.gf"); + sol_ofs.precision(8); + x.Save(sol_ofs); + + // 15. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock.precision(8); + sol_sock << "solution\n" << *mesh << x << flush; + } + + // 16. Free the used memory. + delete a; + delete a_pc; + delete b; + if (a_oper != &A) { delete a_oper; } + delete a_hpc; +} + + +// ***************************************************************************** +// * Main driver to bp_kernel +// ***************************************************************************** +int main(int argc, char *argv[]){ + // 1. Parse command-line options. + const char *mesh_file = "../../data/fichera.mesh"; + const Geometry::Type geom = Geometry::CUBE; + int ref_levels = -1; + int order = 2; + const char *basis_type = "G"; // Gauss-Lobatto + bool static_cond = false; + const char *pc = "none"; + bool perf = true; + bool matrix_free = true; + bool visualization = 1; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ref_levels, "-r", "--refine", + "Number of times to refine the mesh uniformly;" + " -1 = auto: <= 50,000 elements."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&basis_type, "-b", "--basis-type", + "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); + args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", + "Enable high-performance, tensor-based, assembly/evaluation."); + args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", + "Use matrix-free evaluation or efficient matrix assembly in " + "the high-performance version."); + args.AddOption(&pc, "-pc", "--preconditioner", + "Preconditioner: lor - low-order-refined (matrix-free) GS, " + "ho - high-order (assembled) GS, none."); + args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", + "--no-static-condensation", "Enable static condensation."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + args.PrintUsage(cout); + return 1; + } + if (static_cond && perf && matrix_free) + { + cout << "\nStatic condensation can not be used with matrix-free" + " evaluation!\n" << endl; + return 2; + } + MFEM_VERIFY(perf || !matrix_free, + "--standard-version is not compatible with --matrix-free"); + args.PrintOptions(cout); + + PCType pc_choice; + if (!strcmp(pc, "ho")) { pc_choice = HO; } + else if (!strcmp(pc, "lor")) { pc_choice = LOR; } + else if (!strcmp(pc, "none")) { pc_choice = NONE; } + else + { + mfem_error("Invalid Preconditioner specified"); + return 3; + } + + // See class BasisType in fem/fe_coll.hpp for available basis types + const int basis = BasisType::GetType(basis_type[0]); + cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; + + // 2. Read the mesh from the given mesh file. We can handle triangular, + // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with + // the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + const int dim = mesh->Dimension(); + + // 3. Check if the optimized version matches the given mesh + if (perf) + { + cout << "Switching the mesh curvature to match the " + << "optimized value (order " << order << ") ..." << endl; + mesh->SetCurvature(order, false, -1, Ordering::byNODES); + } + + // 4. Refine the mesh to increase the resolution. In this example we do + // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the + // largest number that gives a final mesh with no more than 50,000 + // elements, or as specified on the command line with the option + // '--refine'. + { + ref_levels = (ref_levels != -1) ? ref_levels : + (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); + for (int l = 0; l < ref_levels; l++) + { + mesh->UniformRefinement(); + } + } + if (mesh->MeshGenerator() & 1) // simplex mesh + { + MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" + " the LOR preconditioner yet"); + } + + const int NE = mesh->GetNE(); + AutoImplTraits simd_impl; + const bool simd = (NE > simd_impl.simd_size); + printf("\033[32m[ex1] GetNE()=%d\033[m\n",NE); + if (simd){ + printf("\033[32m[ex1] SIMD!\033[m\n"); + }else{ + printf("\033[32m[ex1] SCALAR!\033[m\n"); + } + + // 5. Define a finite element space on the mesh. Here we use continuous + // Lagrange finite elements of the specified order. If order < 1, we + // instead use an isoparametric/isogeometric space. + FiniteElementCollection *fec; + if (order > 0) + { + fec = new H1_FECollection(order, dim, basis); + } + else if (mesh->GetNodes()) + { + fec = mesh->GetNodes()->OwnFEC(); + cout << "Using isoparametric FEs: " << fec->Name() << endl; + } + else + { + fec = new H1_FECollection(order = 1, dim, basis); + } + FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); + cout << "Number of finite element unknowns: " + << fespace->GetTrueVSize() << endl; + + // Create the LOR mesh and finite element space. In the settings of this + // example, we can transfer between HO and LOR with the identity operator. + Mesh *mesh_lor = NULL; + FiniteElementCollection *fec_lor = NULL; + FiniteElementSpace *fespace_lor = NULL; + if (pc_choice == LOR) + { + int basis_lor = basis; + if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } + mesh_lor = new Mesh(mesh, order, basis_lor); + fec_lor = new H1_FECollection(1, dim); + fespace_lor = new FiniteElementSpace(mesh_lor, fec_lor); + } + + bp_kernel(geom, order, order, dim, + perf, matrix_free, pc_choice, static_cond,visualization, + mesh, fespace, fespace_lor); + + // 16. Free the used memory. + delete fespace; + delete fespace_lor; + delete fec_lor; + delete mesh_lor; + if (order > 0) { delete fec; } + delete mesh; + + return 0; +} diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 93210b075b..c9e17e9b49 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -101,6 +101,25 @@ endif all: $(MINIAPPS) +ex1rtc:ex1rtc.cpp + okrtc g++ -O3 -march=native -std=c++11 -pedantic -Wall \ + -I/home/camier1/home/mfem/x86 \ + -o ex1rtc ex1rtc.cpp \ + -Wl,-rpath,/home/camier1/home/mfem/x86 \ + -L/home/camier1/home/mfem/x86 -lmfem -lrt + +bprtc: bprtc.cpp + okrtc mpicxx -O3 -march=native -std=c++11 -pedantic -Wall \ + -I/home/camier1/home/mfem/x86/ \ + -I/home/camier1/usr/local/hypre/2.11.2/include \ + -I/home/camier1/usr/local/metis/5.1.0/include \ + -I/home/camier1/usr/local/openmpi/3.0.0/include \ + -o $@ $< \ + -L/home/camier1/home/mfem/x86 -lmfem \ + -L/home/camier1/usr/local/hypre/2.11.2/lib -lHYPRE \ + -L/home/camier1/usr/local/metis/5.1.0/lib -lmetis \ + -lrt + MFEM_TESTS = MINIAPPS include $(MFEM_TEST_MK) From a9935c77db45778cf56c6a8a7b4a8770fe513482 Mon Sep 17 00:00:00 2001 From: camierjs Date: Wed, 15 Aug 2018 18:02:46 -0700 Subject: [PATCH 023/535] ex1rtc defines tweaks --- miniapps/performance/ex1.cpp | 4 ++-- miniapps/performance/ex1rtc.cpp | 16 +++++++++++----- miniapps/performance/makefile | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index e029a09c3c..a8e74b85e1 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -38,8 +38,8 @@ using namespace mfem; // Define template parameters for optimized build. const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 3; // mesh curvature (default: 3) -const int sol_p = 3; // solution order (default: 3) +const int mesh_p = 4; // mesh curvature (default: 3) +const int sol_p = 4; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; diff --git a/miniapps/performance/ex1rtc.cpp b/miniapps/performance/ex1rtc.cpp index b39aba77c8..507b2230ac 100644 --- a/miniapps/performance/ex1rtc.cpp +++ b/miniapps/performance/ex1rtc.cpp @@ -45,15 +45,18 @@ void bp_kernel(const Geometry::Type geom, const int msh_p, const int sol_p, const int dim, + const bool simd, // ************************************************************** const bool perf, const bool matrix_free, const int pc_choice, // PCType const bool static_cond, const bool visualization, + // ************************************************************** const Mesh* __restrict mesh, FiniteElementSpace* __restrict fespace, FiniteElementSpace* __restrict fespace_lor){ + // Should be captured while parsing using namespace std; using namespace mfem; @@ -61,10 +64,11 @@ void bp_kernel(const Geometry::Type geom, // Hack to deal with runtime template instanciation #ifndef __OKRTC__ #define GEOM Geometry::CUBE -#define MSH_P 2 -#define SOL_P 2 +#define MSH_P 1 +#define SOL_P 1 #define DIM 3 #define IR_ORDER (2*SOL_P+DIM-1) +#define SIMD true #else #undef GEOM #define GEOM (Geometry::Type)geom @@ -74,6 +78,8 @@ void bp_kernel(const Geometry::Type geom, #define SOL_P sol_p #undef IR_ORDER #define IR_ORDER 2*sol_p+dim-1 +#undef SIMD +#define SIMD simd #endif typedef H1_FiniteElement mesh_fe_t; @@ -84,7 +90,7 @@ void bp_kernel(const Geometry::Type geom, typedef TIntegrationRule int_rule_t; typedef TConstantCoefficient<> coeff_t; typedef TIntegrator integ_t; - typedef TBilinearForm HPCBilinearForm; + typedef TBilinearForm HPCBilinearForm; // 7. Determine the list of true (i.e. conforming) essential boundary dofs. @@ -266,7 +272,7 @@ void bp_kernel(const Geometry::Type geom, // ***************************************************************************** -// * Main driver to bp_kernel +// * Main driver to ex1 kernel // ***************************************************************************** int main(int argc, char *argv[]){ // 1. Parse command-line options. @@ -413,7 +419,7 @@ int main(int argc, char *argv[]){ fespace_lor = new FiniteElementSpace(mesh_lor, fec_lor); } - bp_kernel(geom, order, order, dim, + bp_kernel(geom, order, order, dim, simd, perf, matrix_free, pc_choice, static_cond,visualization, mesh, fespace, fespace_lor); diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index c9e17e9b49..976c1e3f73 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -102,7 +102,7 @@ endif all: $(MINIAPPS) ex1rtc:ex1rtc.cpp - okrtc g++ -O3 -march=native -std=c++11 -pedantic -Wall \ + dbg=1 okrtc g++ -O3 -march=native -std=c++11 -pedantic -Wall \ -I/home/camier1/home/mfem/x86 \ -o ex1rtc ex1rtc.cpp \ -Wl,-rpath,/home/camier1/home/mfem/x86 \ From 965e5c85a0836672f8eb26a6a91758d3040f1ccf Mon Sep 17 00:00:00 2001 From: camierjs Date: Fri, 2 Nov 2018 11:13:34 -0700 Subject: [PATCH 024/535] Trying runtime compilation on miniapps/performance/ex1.cpp --- config/simd/m256.hpp | 4 +- fem/tbilininteg.hpp | 4 +- miniapps/performance/ex1.cpp | 30 ++++++++++++--- miniapps/performance/ex1rtc.cpp | 65 ++++++++++++++++++--------------- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 76a6bdf856..c6ef4232a0 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -89,7 +89,9 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { - return _mm256_xor_pd(_mm256_set1_pd(-0.0), m256d); + AutoSIMD r; + r.m256d = _mm256_xor_pd(_mm256_set1_pd(-0.0), m256d); + return r; } inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index 73892b8177..1239e0e366 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -369,9 +369,9 @@ struct TDiffusionKernel<2,2,complex_t> const complex_t w_det_J = Q.get(q,i,k) / (J11 * J22 - J21 * J12); internal::MatrixOps<2,2>::Symm::Set( A.layout.ind1(i), A, - + w_det_J * (J12*J12 + J22*J22), // (1,1) + w_det_J * (J12*J12 + J22*J22), // (1,1) - w_det_J * (J11*J12 + J21*J22), // (2,1) - + w_det_J * (J11*J11 + J21*J21) // (2,2) + w_det_J * (J11*J11 + J21*J21) // (2,2) ); } } diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index a8e74b85e1..4eb8d782e6 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -37,9 +37,9 @@ using namespace std; using namespace mfem; // Define template parameters for optimized build. -const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) -const int mesh_p = 4; // mesh curvature (default: 3) -const int sol_p = 4; // solution order (default: 3) +const Geometry::Type geom = Geometry::SQUARE; // mesh elements (default: hex) +const int mesh_p = 8; // mesh curvature (default: 3) +const int sol_p = 8; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; @@ -64,9 +64,10 @@ typedef TBilinearForm m64_HPCBilinear int main(int argc, char *argv[]) { // 1. Parse command-line options. - const char *mesh_file = "../../data/fichera.mesh"; + const char *mesh_file = "../../data/star.mesh"; int ref_levels = -1; int order = sol_p; + int max_iter = 2000; const char *basis_type = "G"; // Gauss-Lobatto bool static_cond = false; const char *pc = "none"; @@ -383,7 +384,26 @@ int main(int argc, char *argv[]) } else { - CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + CGSolver *cg; + cg = new CGSolver; + cg->SetRelTol(1e-6); + cg->SetMaxIter(max_iter); + cg->SetPrintLevel(3); + cg->SetOperator(*a_oper); + + tic_toc.Clear(); + tic_toc.Start(); + cg->Mult(B, X); + + double my_rt = tic_toc.RealTime(); + cout << "\nTotal CG time: " << my_rt << " sec." << endl; + cout << "Time per CG step: " + << my_rt / cg->GetNumIterations() << " sec." << endl; + cout << "\n\"DOFs/sec\" in CG: " + << 1e-6*a_oper->Height()*cg->GetNumIterations()/my_rt << " million.\n" + << endl; + delete cg; + //CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); } tic_toc.Stop(); cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; diff --git a/miniapps/performance/ex1rtc.cpp b/miniapps/performance/ex1rtc.cpp index 507b2230ac..3068fc8af4 100644 --- a/miniapps/performance/ex1rtc.cpp +++ b/miniapps/performance/ex1rtc.cpp @@ -32,6 +32,7 @@ #include "mfem-performance.hpp" #include #include +#include using namespace std; using namespace mfem; @@ -41,27 +42,22 @@ enum PCType { NONE, LOR, HO }; // ***************************************************************************** // * High-Performance Benchmark Open Kernel // ***************************************************************************** -void bp_kernel(const Geometry::Type geom, - const int msh_p, - const int sol_p, - const int dim, - const bool simd, - // ************************************************************** +void bp_kernel(const Mesh *mesh, + FiniteElementSpace *fespace, + FiniteElementSpace *fespace_lor, const bool perf, - const bool matrix_free, - const int pc_choice, // PCType - const bool static_cond, - const bool visualization, - // ************************************************************** - const Mesh* __restrict mesh, - FiniteElementSpace* __restrict fespace, - FiniteElementSpace* __restrict fespace_lor){ - - // Should be captured while parsing - using namespace std; - using namespace mfem; - enum PCType { NONE, LOR, HO }; - // Hack to deal with runtime template instanciation + const int pc_choice, + const bool matrix_free = false, + const bool static_cond = false, + const bool visualization = false, + const int dim = 3, + const int msh_p = 1, + const int sol_p = 1, + const bool simd = true, + const int ir_order = 4, + const Geometry::Type geom = Geometry::CUBE, + const int __kernel = 0){ + // Hack to deal with runtime template instanciation #ifndef __OKRTC__ #define GEOM Geometry::CUBE #define MSH_P 1 @@ -81,7 +77,10 @@ void bp_kernel(const Geometry::Type geom, #undef SIMD #define SIMD simd #endif - + // Should be captured while parsing + using namespace std; + using namespace mfem; + enum PCType { NONE, LOR, HO }; typedef H1_FiniteElement mesh_fe_t; typedef H1_FiniteElementSpace mesh_fes_t; typedef TMesh mesh_t; @@ -223,12 +222,13 @@ void bp_kernel(const Geometry::Type geom, tic_toc.Start(); if (pc_choice != NONE) { + assert(false); GSSmoother M(A_pc); PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); } else { - CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + CG(*a_oper, B, X, 3, 2000, 1e-12, 0.0); } tic_toc.Stop(); cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; @@ -276,10 +276,11 @@ void bp_kernel(const Geometry::Type geom, // ***************************************************************************** int main(int argc, char *argv[]){ // 1. Parse command-line options. - const char *mesh_file = "../../data/fichera.mesh"; - const Geometry::Type geom = Geometry::CUBE; + const char *mesh_file = "../../data/star.mesh"; + const Geometry::Type geom = Geometry::SQUARE; int ref_levels = -1; - int order = 2; + int order = 1; + int level = -1; const char *basis_type = "G"; // Gauss-Lobatto bool static_cond = false; const char *pc = "none"; @@ -296,6 +297,7 @@ int main(int argc, char *argv[]){ args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree) or -1 for" " isoparametric space."); + args.AddOption(&level, "-l", "--level", "Refinement level"); args.AddOption(&basis_type, "-b", "--basis-type", "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", @@ -361,7 +363,7 @@ int main(int argc, char *argv[]){ // elements, or as specified on the command line with the option // '--refine'. { - ref_levels = (ref_levels != -1) ? ref_levels : + ref_levels = level>0 ? level ://(ref_levels != -1) ? ref_levels : (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); for (int l = 0; l < ref_levels; l++) { @@ -418,10 +420,13 @@ int main(int argc, char *argv[]){ fec_lor = new H1_FECollection(1, dim); fespace_lor = new FiniteElementSpace(mesh_lor, fec_lor); } - - bp_kernel(geom, order, order, dim, simd, - perf, matrix_free, pc_choice, static_cond,visualization, - mesh, fespace, fespace_lor); + + // Launch kernel + bp_kernel(mesh, fespace, fespace_lor, + perf, pc_choice, matrix_free, + static_cond, visualization, + dim, order, order, simd, + 2*order+dim-1, geom); // 16. Free the used memory. delete fespace; From 9c838adca6da772a5406994eb116c68df9149f86 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Wed, 8 May 2019 14:10:49 -0700 Subject: [PATCH 025/535] Added some doxygen to everything in general and started in fem. --- fem/bilinearform.hpp | 148 +++++++++++++++++++++++++++++--------- fem/bilinearform_ext.hpp | 13 ++-- general/array.hpp | 100 ++++++++++++++------------ general/binaryio.hpp | 2 + general/communication.hpp | 57 +++++++++------ general/cuda.hpp | 16 ++--- general/hash.hpp | 3 +- general/mem_alloc.hpp | 6 ++ general/mem_manager.hpp | 33 +++++---- general/optparser.hpp | 19 +++++ general/sets.hpp | 22 ++++-- general/socketstream.hpp | 14 +++- general/sort_pairs.hpp | 2 +- general/stable3d.hpp | 24 ++++++- general/table.hpp | 1 - general/text.hpp | 8 +-- general/tic_toc.hpp | 18 ++++- general/version.hpp | 12 ++++ 18 files changed, 358 insertions(+), 140 deletions(-) diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index e15fc7d257..07855aeeb3 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -45,14 +45,17 @@ enum class AssemblyLevel /** Class for bilinear form - "Matrix" with associated FE space and - BLFIntegrators. */ + BLFIntegrators. The sum of all the BLFIntegrators will be used + form the matrix/operator M. */ class BilinearForm : public Matrix { protected: - /// Sparse matrix to be associated with the form. Owned. + /// Sparse matrix \f$ M \f$ to be associated with the form. Owned. SparseMatrix *mat; - /// Matrix used to eliminate b.c. Owned. + /** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations + from the b.c. Owned. + \f$ M + M_e = M_{original} \f$ */ SparseMatrix *mat_e; /// FE space on which the form lives. Not owned. @@ -62,12 +65,12 @@ protected: AssemblyLevel assembly; /// Element batch size used in the form action (1, 8, num_elems, etc.) int batch; - /** Extension for supporting Full Assembly (FA), Element Assembly (EA), + /** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA), Partial Assembly (PA), or Matrix Free assembly (MF). */ BilinearFormExtension *ext; - /// Indicates the Mesh::sequence corresponding to the current state of the - /// BilinearForm. + /** @brief Indicates the Mesh::sequence corresponding to the current state of the + BilinearForm. */ long sequence; /** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi, @@ -149,32 +152,41 @@ public: /// Get the size of the BilinearForm as a square matrix. int Size() const { return height; } - /// Set the desired assembly level. The default is AssemblyLevel::FULL. - /** This method must be called before assembly. */ + /// Set the desired assembly level. + /** Valid choices are: + + - AssemblyLevel::FULL (default) + - AssemblyLevel::PARTIAL + - AssemblyLevel::ELEMENT + - AssemblyLevel::NONE + + This method must be called before assembly. */ void SetAssemblyLevel(AssemblyLevel assembly_level); - /** Enable the use of static condensation. For details see the description + /// Enable the use of static condensation. + /** For details see the description for class StaticCondensation in fem/staticcond.hpp This method should be called before assembly. If the number of unknowns after static condensation is not reduced, it is not enabled. */ void EnableStaticCondensation(); - /** Check if static condensation was actually enabled by a previous call to - EnableStaticCondensation(). */ + /** @brief Check if static condensation was actually enabled by a previous + call to EnableStaticCondensation(). */ bool StaticCondensationIsEnabled() const { return static_cond; } /// Return the trace FE space associated with static condensation. FiniteElementSpace *SCFESpace() const { return static_cond ? static_cond->GetTraceFESpace() : NULL; } - /** Enable hybridization; for details see the description for class + /// Enable hybridization. + /** For details see the description for class Hybridization in fem/hybridization.hpp. This method should be called before assembly. */ void EnableHybridization(FiniteElementSpace *constr_space, BilinearFormIntegrator *constr_integ, const Array &ess_tdof_list); - /** For scalar FE spaces, precompute the sparsity pattern of the matrix + /** @brief For scalar FE spaces, precompute the sparsity pattern of the matrix (assuming dense element matrices) based on the types of integrators present in the bilinear form. */ void UsePrecomputedSparsity(int ps = 1) { precompute_sparsity = ps; } @@ -193,15 +205,16 @@ public: /// Use the sparsity of @a A to allocate the internal SparseMatrix. void UseSparsity(SparseMatrix &A); - /** Pre-allocate the internal SparseMatrix before assembly. If the flag - 'precompute sparsity' is set, the matrix is allocated in CSR format (i.e. + /// Pre-allocate the internal SparseMatrix before assembly. + /** If the flag 'precompute sparsity' + is set, the matrix is allocated in CSR format (i.e. finalized) and the entries are initialized with zeros. */ void AllocateMatrix() { if (mat == NULL) { AllocMat(); } } - /// Access all integrators added with AddDomainIntegrator(). + /// Access all the integrators added with AddDomainIntegrator(). Array *GetDBFI() { return &dbfi; } - /// Access all integrators added with AddBoundaryIntegrator(). + /// Access all the integrators added with AddBoundaryIntegrator(). Array *GetBBFI() { return &bbfi; } /** @brief Access all boundary markers added with AddBoundaryIntegrator(). If no marker was specified when the integrator was added, the @@ -218,64 +231,85 @@ public: corresponding pointer (to Array) will be NULL. */ Array*> *GetBFBFI_Marker() { return &bfbfi_marker; } + /// Returns a reference to: \f$ M_{ij} \f$ const double &operator()(int i, int j) { return (*mat)(i,j); } - /// Returns reference to a_{ij}. + /// Returns a reference to: \f$ M_{ij} \f$ virtual double &Elem(int i, int j); - /// Returns constant reference to a_{ij}. + /// Returns constant reference to: \f$ M_{ij} \f$ virtual const double &Elem(int i, int j) const; - /// Matrix vector multiplication. + /// Matrix vector multiplication: \f$ y = M x \f$ virtual void Mult(const Vector &x, Vector &y) const { mat->Mult(x, y); } + /** @brief Matrix vector multiplication with the original uneliminated + matrix. The original matrix is \f$ M + M_e \f$ so we have: + \f$ y = M x + M_e x \f$ */ void FullMult(const Vector &x, Vector &y) const { mat->Mult(x, y); mat_e->AddMult(x, y); } + /// Add the matrix vector multiple to a vector: \f$ y += a M x \f$ virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const { mat -> AddMult (x, y, a); } + /** @brief Add the original uneliminated matrix vector multiple to a vector. + The original matrix is \f$ M + Me \f$ so we have: + \f$ y += M x + M_e x \f$ */ void FullAddMult(const Vector &x, Vector &y) const { mat->AddMult(x, y); mat_e->AddMult(x, y); } + /// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$ virtual void AddMultTranspose(const Vector & x, Vector & y, const double a = 1.0) const { mat->AddMultTranspose(x, y, a); } + /** @brief Add the original uneliminated matrix transpose vector + multiple to a vector. The original matrix is \f$ M + M_e \f$ + so we have: \f$ y += M^T x + {M_e}^T x \f$ */ void FullAddMultTranspose(const Vector & x, Vector & y) const { mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); } + /// Matrix transpose vector multiplication: \f$ y = M^T x \f$ virtual void MultTranspose(const Vector & x, Vector & y) const { y = 0.0; AddMultTranspose (x, y); } + /// Compute \f$ y^T M x \f$ double InnerProduct(const Vector &x, const Vector &y) const { return mat->InnerProduct (x, y); } - /// Returns a pointer to (approximation) of the matrix inverse. + /// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$ virtual MatrixInverse *Inverse() const; /// Finalizes the matrix initialization. virtual void Finalize(int skip_zeros = 1); - /// Returns a reference to the sparse matrix + /// Returns a const reference to the sparse matrix. const SparseMatrix &SpMat() const { MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced"); return *mat; } + + /// Returns a reference to the sparse matrix: \f$ M \f$ SparseMatrix &SpMat() { MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced"); return *mat; } + + /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer + to it. Used for transfering ownership. */ SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; } - /// Returns a reference to the sparse matrix of eliminated b.c. + /// Returns a const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$ const SparseMatrix &SpMatElim() const { MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced"); return *mat_e; } + + /// Returns a reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$ SparseMatrix &SpMatElim() { MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced"); @@ -310,6 +344,7 @@ public: void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi, Array &bdr_marker); + /// Sets all sparse values of \f$ M \f$ and \f$ M_e \f$ to 'a'. void operator=(const double a) { if (mat != NULL) { *mat = a; } @@ -319,10 +354,10 @@ public: /// Assembles the form i.e. sums over all domain/bdr integrators. void Assemble(int skip_zeros = 1); - /// Get the finite element space prolongation matrix + /// Get the finite element space prolongation operator virtual const Operator *GetProlongation() const { return fes->GetConformingProlongation(); } - /// Get the finite element space restriction matrix + /// Get the finite element space restriction operator virtual const Operator *GetRestriction() const { return fes->GetConformingRestriction(); } @@ -413,9 +448,20 @@ public: void FreeElementMatrices() { delete element_matrices; element_matrices = NULL; } + /// Compute the matrix for element @a i and store it in @a elmat. void ComputeElementMatrix(int i, DenseMatrix &elmat); + + /** @brief Take the element matrix @a elmat for element @a i and add the + values into the proper global @a vdof locations. */ + /** The @a vdofs array is overwritten with the proper locations by this + method. */ void AssembleElementMatrix(int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros = 1); + + /** @brief Take the boundary element matrix @a elmat for element @a i and + add the values into the proper global @a vdof locations. */ + /** The @a vdofs array is overwritten with the proper locations by this + method. */ void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros = 1); @@ -436,10 +482,12 @@ public: double value); /// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs. + /** In this case the eliminations are applied to the internal \f$ M \f$ + and @a rhs without storing the elimination matrix \f$ M_e \f$. */ void EliminateVDofs(const Array &vdofs, const Vector &sol, Vector &rhs, DiagonalPolicy dpolicy = DIAG_ONE); - /// Eliminate the given @a vdofs, storing the eliminated part internally. + /// Eliminate the given @a vdofs, storing the eliminated part internall in \f$ M_e \f$. /** This method works in conjunction with EliminateVDofsInRHS() and allows elimination of boundary conditions in multiple right-hand sides. In this method, @a vdofs is a list of DOFs. */ @@ -468,9 +516,11 @@ public: void EliminateVDofsInRHS(const Array &vdofs, const Vector &x, Vector &b); + /// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$ double FullInnerProduct(const Vector &x, const Vector &y) const { return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); } + /// Update the @a FiniteElementSpace and delete all data associated with the old one. virtual void Update(FiniteElementSpace *nfes = NULL); /// (DEPRECATED) Return the FE space associated with the BilinearForm. @@ -482,7 +532,13 @@ public: /// Read-only access to the associated FiniteElementSpace. const FiniteElementSpace *FESpace() const { return fes; } - /// Sets diagonal policy used upon construction of the linear system + /// Sets diagonal policy used upon construction of the linear system. + /** Policies include: + + - DIAG_ZERO (Set the diagonal value to zero) + - DIAG_ONE (Set the diagonal value to one) + - DIAG_KEEP (Keep the diagonal value) + */ void SetDiagonalPolicy(DiagonalPolicy policy); /// Destroys bilinear form. @@ -492,16 +548,16 @@ public: /** Class for assembling of bilinear forms `a(u,v)` defined on different - trial and test spaces. The assembled matrix `A` is such that + trial and test spaces. The assembled matrix `M` is such that - a(u,v) = V^t A U + a(u,v) = V^t M U where `U` and `V` are the vectors representing the functions `u` and `v`, respectively. The first argument, `u`, of `a(,)` is in the trial space and the second argument, `v`, is in the test space. Thus, - # of rows of A = dimension of the test space and - # of cols of A = dimension of the trial space. + # of rows of M = dimension of the test space and + # of cols of M = dimension of the trial space. Both trial and test spaces should be defined on the same mesh. */ @@ -552,23 +608,30 @@ public: FiniteElementSpace *te_fes, MixedBilinearForm *mbf); + /// Returns a reference to: \f$ M_{ij} \f$ virtual double &Elem(int i, int j); + /// Returns a reference to: \f$ M_{ij} \f$ virtual const double &Elem(int i, int j) const; + /// Matrix multiplication: \f$ y = M x \f$ virtual void Mult(const Vector & x, Vector & y) const; + /// Add in matrix multiplication: \f$ y += a M x \f$ virtual void AddMult(const Vector & x, Vector & y, const double a = 1.0) const; - + /// Add in matrix transpose multiplication: \f$ y += a M^T x \f$ virtual void AddMultTranspose(const Vector & x, Vector & y, const double a = 1.0) const; + /// Matrix transpose multiplication: \f$ y = M^T x \f$ virtual void MultTranspose(const Vector & x, Vector & y) const { y = 0.0; AddMultTranspose (x, y); } + /// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$ virtual MatrixInverse *Inverse() const; + /// Finalizes the matrix initialization. virtual void Finalize(int skip_zeros = 1); /** Extract the associated matrix as SparseMatrix blocks. The number of @@ -576,8 +639,14 @@ public: test and trial spaces, respectively. */ void GetBlocks(Array2D &blocks) const; + /// Returns a const reference to the sparse matrix: \f$ M \f$ const SparseMatrix &SpMat() const { return *mat; } + + /// Returns a reference to the sparse matrix: \f$ M \f$ SparseMatrix &SpMat() { return *mat; } + + /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer + to it. Used for transfering ownership. */ SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; } /// Adds a domain integrator. Assumes ownership of @a bfi. @@ -602,8 +671,10 @@ public: /// Access all integrators added with AddTraceFaceIntegrator(). Array *GetTFBFI() { return &skt; } + /// Sets all sparse values of \f$ M \f$ to @a a. void operator=(const double a) { *mat = a; } + /// Assembles the form i.e. sums over all domain/bdr integrators. void Assemble(int skip_zeros = 1); /** For partially conforming trial and/or test FE spaces, complete the @@ -613,14 +684,27 @@ public: MixedBilinearForm becomes an operator on the conforming FE spaces. */ void ConformingAssemble(); + + /// Eliminate essential boundary trial DOFs from the system. + /** The array @a bdr_attr_is_ess marks boundary attributes that constitute + the essential part of the boundary. */ void EliminateTrialDofs(Array &bdr_attr_is_ess, const Vector &sol, Vector &rhs); + + /** @brief Emiminate essential boundary trial DOFs where + @a marked_vdofs is a marker (boolean) array on all vector-dofs + where true represents a DOF to eliminate. */ void EliminateEssentialBCFromTrialDofs(Array &marked_vdofs, const Vector &sol, Vector &rhs); + /// Eliminate essential boundary test DOFs from the system. + /** The array @a bdr_attr_is_ess marks boundary attributes that constitute + the essential part of the boundary. */ virtual void EliminateTestDofs(Array &bdr_attr_is_ess); + /** @brief Delete the internal matrix and resize it to accommodate any changes + in the underlying finite element spaces. */ void Update(); virtual ~MixedBilinearForm(); diff --git a/fem/bilinearform_ext.hpp b/fem/bilinearform_ext.hpp index 62abfd0321..ee8e36a77e 100644 --- a/fem/bilinearform_ext.hpp +++ b/fem/bilinearform_ext.hpp @@ -20,7 +20,7 @@ namespace mfem class BilinearForm; -/// Element restriction operator +/// Element restriction operator \f$ R \f$ class ElemRestriction: public Operator { public: @@ -35,7 +35,11 @@ public: Array indices; public: ElemRestriction(const FiniteElementSpace&); + + /// Apply the restriction operator \f$ y = R x \f$ void Mult(const Vector &x, Vector &y) const; + + /// Apply the restriction transpose operator \f$ y = R^T x \f$ void MultTranspose(const Vector &x, Vector &y) const; }; @@ -54,6 +58,7 @@ public: /// Get the finite element space restriction matrix virtual const Operator *GetRestriction() const; + /// Assemble at the level given for the BilinearFormExtension subclass virtual void Assemble() = 0; virtual void FormSystemMatrix(const Array &ess_tdof_list, OperatorHandle &A) = 0; @@ -64,7 +69,7 @@ public: virtual void Update() = 0; }; -/// Data and methods for fully-assembled bilinear forms +/// Data and methods for fully-assembled bilinear forms NOT IMPLEMENTED HERE class FABilinearFormExtension : public BilinearFormExtension { public: @@ -83,7 +88,7 @@ public: ~FABilinearFormExtension() {} }; -/// Data and methods for element-assembled bilinear forms +/// Data and methods for element-assembled bilinear forms NOT IMPLEMENTED HERE class EABilinearFormExtension : public BilinearFormExtension { public: @@ -127,7 +132,7 @@ public: ~PABilinearFormExtension(); }; -/// Data and methods for matrix-free bilinear forms +/// Data and methods for matrix-free bilinear forms NOT IMPLEMENTED HERE class MFBilinearFormExtension : public BilinearFormExtension { public: diff --git a/general/array.hpp b/general/array.hpp index 16135a74d8..b916d0dd92 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -29,14 +29,15 @@ namespace mfem class BaseArray { protected: - /// Pointer to data + /// Pointer to data. void *data; - /// Size of the array + /// Size of the array. int size; - /// Size of the allocated memory + /** Size of the allocated memory. Will be negative + if the data is not owned by this array. */ int allocsize; /** Increment of allocated memory on overflow, - inc = 0 doubles the array */ + inc = 0 doubles the arra.y */ int inc; BaseArray() { } @@ -70,22 +71,22 @@ class Array : public BaseArray public: friend void Swap(Array &, Array &); - /// Creates array of asize elements + /// Creates an array of asize elements. explicit inline Array(int asize = 0, int ainc = 0) : BaseArray(asize, ainc, sizeof (T)) { } - /** Creates array using an existing c-array of asize elements; + /** @brief Creates array using an existing c-array of asize elements; allocsize is set to -asize to indicate that the data will not be deleted. */ inline Array(T *_data, int asize, int ainc = 0) { data = _data; size = asize; allocsize = -asize; inc = ainc; } - /// Copy constructor: deep copy + /// Copy constructor: deep copy from 'src'. Array(const Array &src) : BaseArray(src.size, 0, sizeof(T)) { mfem::Memcpy(data, src.data, size*sizeof(T)); } - /// Copy constructor (deep copy) from an Array of convertable type + /// Copy constructor (deep copy) from 'src', an Array of convertible type. template Array(const Array &src) : BaseArray(src.Size(), 0, sizeof(T)) @@ -94,10 +95,10 @@ public: /// Destructor inline ~Array() { } - /// Assignment operator: deep copy + /// Assignment operator: deep copy from 'src'. Array &operator=(const Array &src) { src.Copy(*this); return *this; } - /// Assignment operator (deep copy) from an Array of convertable type + /// Assignment operator (deep copy) from 'src', an Array of convertible type. template Array &operator=(const Array &src) { @@ -106,37 +107,38 @@ public: return *this; } - /// Return the data as 'T *' + /// Return the data as 'T *'. inline operator T *() { return (T *)data; } - /// Return the data as 'const T *' + /// Return the data as 'const T *'. inline operator const T *() const { return (const T *)data; } - /// Returns the data + /// Returns pointer to the data. inline T *GetData() { return (T *)data; } - /// Returns the data + /// Returns const pointer to the data. inline const T *GetData() const { return (T *)data; } - /// Return true if the data will be deleted by the array + /** @breif Return true if this object owns the data in the array + and will handle deallocation. */ inline bool OwnsData() const { return (allocsize > 0); } - /// Changes the ownership of the data + /// Transfer ownership of the data out of this object to 'p'. inline void StealData(T **p) { *p = (T*)data; data = 0; size = allocsize = 0; } - /// NULL-ifies the data + /// NULL-ifies the data. Careful to avoid leaking memory here. inline void LoseData() { data = 0; size = allocsize = 0; } /// Make the Array own the data void MakeDataOwner() { allocsize = abs(allocsize); } - /// Logical size of the array + /// Return the logical size of the array. inline int Size() const { return size; } - /// Change logical size of the array, keep existing entries + /// Change the logical size of the array, keep existing entries. inline void SetSize(int nsize); - /// Same as SetSize(int) plus initialize new entries with 'initval' + /// Same as SetSize(int) plus initialize new entries with 'initval'. inline void SetSize(int nsize, const T &initval); /** Maximum number of entries the array can store without allocating more @@ -147,62 +149,65 @@ public: inline void Reserve(int capacity) { if (capacity > abs(allocsize)) { GrowSize(capacity, sizeof(T)); } } - /// Access element + /// Reference access to the ith element. inline T & operator[](int i); - /// Access const element + /// Const reference access to the ith element. inline const T &operator[](int i) const; - /// Append element to array, resize if necessary + /// Append element 'el' to array, resize if necessary. inline int Append(const T & el); - /// Append another array to this array, resize if necessary + /// Append another array to this array, resize if necessary. inline int Append(const T *els, int nels); - /// Append another array to this array, resize if necessary + /// Append another array to this array, resize if necessary. inline int Append(const Array &els) { return Append(els, els.Size()); } - /// Prepend an element to the array, resize if necessary + /// Prepend an 'el' to the array, resize if necessary. inline int Prepend(const T &el); - /// Return the last element in the array + /// Return the last element in the array. inline T &Last(); + + /// Return the last element in the array. inline const T &Last() const; - /// Append element when it is not yet in the array, return index + /// Append element when it is not yet in the array, return index. inline int Union(const T & el); - /// Return the first index where 'el' is found; return -1 if not found + /// Return the first index where 'el' is found; return -1 if not found. inline int Find(const T &el) const; /// Do bisection search for 'el' in a sorted array; return -1 if not found. inline int FindSorted(const T &el) const; - /// Delete the last entry + /// Delete the last entry of the array. inline void DeleteLast() { if (size > 0) { size--; } } - /// Delete the first 'el' entry + /// Delete the first entry with value == 'el'. inline void DeleteFirst(const T &el); - /// Delete whole array + /// Delete the whole array. inline void DeleteAll(); - /// Create a copy of the current array + /// Create a copy of the internal array to the provided 'copy'. inline void Copy(Array ©) const { copy.SetSize(Size()); mfem::Memcpy(copy.GetData(), data, Size()*sizeof(T)); } - /// Make this Array a reference to a pointer + /// Make this Array a reference to a pointer. inline void MakeRef(T *, int); - /// Make this Array a reference to 'master' + /// Make this Array a reference to 'master'. inline void MakeRef(const Array &master); + /// Copy sub array starting from 'offset' out to the provided 'sa'. inline void GetSubArray(int offset, int sa_size, Array &sa); - /// Prints array to stream with width elements per row + /// Prints array to stream with width elements per row. void Print(std::ostream &out = mfem::out, int width = 4) const; /** @brief Save the Array to the stream @a out using the format @a fmt. @@ -234,42 +239,47 @@ public: operator `<` for class T. */ T Min() const; - /// Sorts the array. This requires operator< to be defined for T. + /// Sorts the array in ascending order. This requires operator< to be defined for T. void Sort() { std::sort((T*) data, (T*) data + size); } - /// Sorts the array using the supplied comparison function object. + /// Sorts the array in ascending order using the supplied comparison function object. template void Sort(Compare cmp) { std::sort((T*) data, (T*) data + size, cmp); } - /** Removes duplicities from a sorted array. This requires operator== to be - defined for T. */ + /** @brief Removes duplicities from a sorted array. This requires + operator== to be defined for T. */ void Unique() { T* end = std::unique((T*) data, (T*) data + size); SetSize(end - (T*) data); } - /// return true if the array is sorted. + /// Return 1 if the array is sorted from lowest to highest. Otherwise return 0. int IsSorted(); - /// Partial Sum + /// Fill the entries of the array with the cumulative sum of the entries. void PartialSum(); - /// Sum all entries + /// Return the sum of all the array entries using the '+'' operator for class 'T'. T Sum(); + /// Set all entries of the array to the provided constant. inline void operator=(const T &a); - /// Copy data from a pointer. Size() elements are copied. + /// Copy data from a pointer. 'Size()'' elements are copied. inline void Assign(const T *); + /// STL-like copy from begin to end. template inline void CopyTo(U *dest) { std::copy(begin(), end(), dest); } - // STL-like begin/end + /// STL-like begin. Returns pointer to the first element of the array. inline T* begin() const { return (T*) data; } + + /// STL-like end. Returns pointer after the last element of the array. inline T* end() const { return (T*) data + size; } + /// Returns the number of bytes allocated for the array including any reserve. long MemoryUsage() const { return Capacity() * sizeof(T); } }; diff --git a/general/binaryio.hpp b/general/binaryio.hpp index 98c81f9008..9ac57d2d4d 100644 --- a/general/binaryio.hpp +++ b/general/binaryio.hpp @@ -24,12 +24,14 @@ namespace mfem namespace bin_io { +/// Write 'value' to stream. template inline void write(std::ostream& os, T value) { os.write((char*) &value, sizeof(T)); } +/// Read a value from the stream and return it. template inline T read(std::istream& is) { diff --git a/general/communication.hpp b/general/communication.hpp index acfdfcd646..a4451b5fa4 100644 --- a/general/communication.hpp +++ b/general/communication.hpp @@ -47,61 +47,78 @@ public: bool Root() const { return world_rank == 0; } }; + +/** The shared entities (e.g. vertices, faces and edges) are split into + groups, each group determined by the set of participating processors. + They are numbered locally in lproc. Assumptions: + - group 0 is the 'local' group + - groupmaster_lproc[0] = 0 + - lproc_proc[0] = MyRank */ class GroupTopology { private: MPI_Comm MyComm; - /* The shared entities (e.g. vertices, faces and edges) are split into - groups, each group determined by the set of participating processors. - They are numbered locally in lproc. Assumptions: - - group 0 is the 'local' group - - groupmaster_lproc[0] = 0 - - lproc_proc[0] = MyRank */ - // Neighbor ids (lproc) in each group. + + /// Neighbor ids (lproc) in each group. Table group_lproc; - // Master neighbor id for each group. + /// Master neighbor id for each group. Array groupmaster_lproc; - // MPI rank of each neighbor. + /// MPI rank of each neighbor. Array lproc_proc; - // Group --> Group number in the master. + /// Group --> Group number in the master. Array group_mgroup; void ProcToLProc(); public: + /// Constructor with the MPI communicator = 0. GroupTopology() : MyComm(0) {} + + /// Constructor given the MPI communicator 'comm'. GroupTopology(MPI_Comm comm) { MyComm = comm; } /// Copy constructor GroupTopology(const GroupTopology >); + + /// Set the MPI communicator to 'comm'. void SetComm(MPI_Comm comm) { MyComm = comm; } + /// Return the MPI communicator. MPI_Comm GetComm() const { return MyComm; } + + /// Return the MPI rank within this object's communicator. int MyRank() const { int r; MPI_Comm_rank(MyComm, &r); return r; } + + /// Return the number of MPI ranks within this object's communicator. int NRanks() const { int s; MPI_Comm_size(MyComm, &s); return s; } void Create(ListOfIntegerSets &groups, int mpitag); + /// Return the number of groups. int NGroups() const { return group_lproc.Size(); } - // return the number of neighbors including the local processor + + /// Return the number of neighbors including the local processor. int GetNumNeighbors() const { return lproc_proc.Size(); } + + /// Return the MPI rank of neighbor 'i'. int GetNeighborRank(int i) const { return lproc_proc[i]; } - // am I master for group 'g'? + /// Return true if I am master for group 'g'. bool IAmMaster(int g) const { return (groupmaster_lproc[g] == 0); } - // return the neighbor index of the group master for a given group. - // neighbor 0 is the local processor + /** Return the neighbor index of the group master for a given group. + * Neighbor 0 is the local processor. */ int GetGroupMaster(int g) const { return groupmaster_lproc[g]; } - // return the rank of the group master for a given group + /// Return the rank of the group master for group 'g'. int GetGroupMasterRank(int g) const { return lproc_proc[groupmaster_lproc[g]]; } - // for a given group return the group number in the master + /// Return the group number in the master for group 'g'. int GetGroupMasterGroup(int g) const { return group_mgroup[g]; } - // get the number of processors in a group + /// Get the number of processors in a group int GetGroupSize(int g) const { return group_lproc.RowSize(g); } - // return a pointer to a list of neighbors for a given group. - // neighbor 0 is the local processor + + /** @brief Return a pointer to a list of neighbors for a given group. + * Neighbor 0 is the local processor */ const int *GetGroup(int g) const { return group_lproc.GetRow(g); } /// Save the data in a stream. @@ -109,7 +126,7 @@ public: /// Load the data from a stream. void Load(std::istream &in); - /// Copy + /// Copy the internal data to the external 'copy'. void Copy(GroupTopology & copy) const; virtual ~GroupTopology() {} diff --git a/general/cuda.hpp b/general/cuda.hpp index 240881a247..92a89b14a2 100644 --- a/general/cuda.hpp +++ b/general/cuda.hpp @@ -54,28 +54,28 @@ void mfem_cuda_error(cudaError_t err, const char *expr, const char *func, const char *file, int line); #endif -/// Allocates device memory +/// Allocates device memory and returns destination ptr. void* CuMemAlloc(void **d_ptr, size_t bytes); -/// Frees device memory +/// Frees device memory and returns destination ptr. void* CuMemFree(void *d_ptr); -/// Copies memory from Host to Device +/// Copies memory from Host to Device and returns destination ptr. void* CuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes); -/// Copies memory from Host to Device +/// Copies memory from Host to Device and returns destination ptr. void* CuMemcpyHtoDAsync(void *d_dst, const void *h_src, size_t bytes); -/// Copies memory from Device to Device +/// Copies memory from Device to Device and returns destination ptr. void* CuMemcpyDtoD(void *d_dst, void *d_src, size_t bytes); -/// Copies memory from Device to Device +/// Copies memory from Device to Device and returns destination ptr. void* CuMemcpyDtoDAsync(void *d_dst, void *d_src, size_t bytes); -/// Copies memory from Device to Host +/// Copies memory from Device to Host and returns destination ptr. void* CuMemcpyDtoH(void *h_dst, void *d_src, size_t bytes); -/// Copies memory from Device to Host +/// Copies memory from Device to Host and returns destination ptr. void* CuMemcpyDtoHAsync(void *h_dst, void *d_src, size_t bytes); } // namespace mfem diff --git a/general/hash.hpp b/general/hash.hpp index 5a6a094056..f8c0439e3d 100644 --- a/general/hash.hpp +++ b/general/hash.hpp @@ -77,7 +77,7 @@ public: HashTable(const HashTable& other); // deep copy ~HashTable(); - /// Get item whose parents are p1, p2... Create it if it doesn't exist. + /// Get item whose parents are 'p1', 'p2'... Create it if it doesn't exist. T* Get(int p1, int p2); T* Get(int p1, int p2, int p3, int p4); @@ -120,6 +120,7 @@ public: /// Return total size of allocated memory (tables plus items), in bytes. long MemoryUsage() const; + /// Write details of the memory usage to the mfem output stream. void PrintMemoryDetail() const; class iterator : public Base::iterator diff --git a/general/mem_alloc.hpp b/general/mem_alloc.hpp index b048fbe17e..4cd68a7cb0 100644 --- a/general/mem_alloc.hpp +++ b/general/mem_alloc.hpp @@ -33,11 +33,17 @@ private: StackPart *TopPart, *TopFreePart; int UsedInTop, SSize; public: + /// Construct an empty stack. Stack() { TopPart = TopFreePart = NULL; UsedInTop = Num; SSize = 0; } + /// Return the number of elements on the stack. int Size() const { return SSize; } + /// Push element 'E' on the stack. void Push (Elem E); + /// Pop an element off the stack and return it. Elem Pop(); + /// Clear the elements off the stack. void Clear(); + /// Return the number of bytes used by the stack. size_t MemoryUsage() const; ~Stack() { Clear(); } }; diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index b6d3753c66..f44ed2bae3 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -20,7 +20,9 @@ namespace mfem // Implementation of MFEM's lightweight device/host memory manager designed to // work seamlessly with the OCCA, RAJA, and other kernels supported by MFEM. -/// The memory manager class +/** The memory manager class. Host side pointers are inserted into this + manager which keeps track of the associated device pointer, and where + the data currently resides. */ class MemoryManager { private: @@ -35,7 +37,7 @@ public: MemoryManager(); ~MemoryManager(); - /// Adds an address in the map + /// Adds a host side address and size in the map to be managed. void *Insert(void *ptr, const std::size_t bytes); /// Remove the address from the map, as well as all its aliases @@ -52,19 +54,19 @@ public: #endif } - /// Disable the memory manager: Ptr, Push and Pull will be no-op + /// Disable the memory manager: Ptr, Push and Pull will be no-op. void Disable() { enabled = false; } - /// Enable the memory manager: Ptr, Push and Pull wont be no-op + /// Enable the memory manager: Ptr, Push and Pull wont be no-op. void Enable() { enabled = true; } - /// Return true if the memory manager is used and enabled + /// Return true if the memory manager is used and enabled. bool IsEnabled() { return UsingMM() && enabled; } /// The opposite of IsEnabled(). bool IsDisabled() { return !IsEnabled(); } - /// Return true if a global memory manager instance exists + /// Return true if a global memory manager instance exists. static bool Exists() { return exists; } /** @brief Translates ptr to host or device address, depending on what @@ -73,26 +75,27 @@ public: void *Ptr(void *ptr); const void *Ptr(const void *ptr); - /// Data will be pushed/pulled before the copy happens on the H or the D + /** Copy 'bytes' of data from 'src' to 'dst'. Data will be pushed/pulled + before the copy happens on the H or the D. */ void* Memcpy(void *dst, const void *src, std::size_t bytes, const bool async = false); - /// Return the bytes of the memory region which base address is ptr + /// Return the number of bytes of the memory region which base address is ptr. std::size_t Bytes(const void *ptr); - /// Return true if the registered pointer is on the host side + /// Return true if the registered pointer is on the host side. bool IsOnHost(const void *ptr); - /// Return true if the pointer has been registered + /// Return true if the pointer has been registered. bool IsKnown(const void *ptr); - /// Return true if the pointer is an alias inside a registered memory region + /// Return true if the pointer is an alias inside a registered memory region. bool IsAlias(const void *ptr); - /// Push the data to the device + /// Push the data to the device. void Push(const void *ptr, const std::size_t bytes =0); - /// Pull the data from the device + /// Pull the data from the device. void Pull(const void *ptr, const std::size_t bytes =0); /// Return the corresponding device pointer of ptr, allocating and moving the @@ -131,10 +134,10 @@ public: /// Check if pointer has been registered in the memory manager void RegisterCheck(void *ptr); - /// Prints all pointers known by the memory manager + /// Prints all pointers known by the memory manager. void PrintPtrs(void); - /// Copies all memory to the current memory space + /// Copies all memory to the current memory space. void GetAll(void); }; diff --git a/general/optparser.hpp b/general/optparser.hpp index a2d0ffcc39..3df4e50f51 100644 --- a/general/optparser.hpp +++ b/general/optparser.hpp @@ -66,11 +66,16 @@ private: static void WriteValue(const Option &opt, std::ostream &out); public: + + /// Comstruct a command line option parser with '_argc' and '_argv'. OptionsParser(int _argc, char *_argv[]) : argc(_argc), argv(_argv) { error_type = error_idx = 0; } + + /** Add a boolean option and set 'var' to recieve the value. Enable/disable + tags are used to set the bool to true/false respectively. */ void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, @@ -81,18 +86,24 @@ public: options.Append(Option(DISABLE, var, disable_short_name, disable_long_name, description, required)); } + + /// Add an integer option and set 'var' to recieve the value. void AddOption(int *var, const char *short_name, const char *long_name, const char *description, bool required = false) { options.Append(Option(INT, var, short_name, long_name, description, required)); } + + /// Add a double option and set 'var' to recieve the value. void AddOption(double *var, const char *short_name, const char *long_name, const char *description, bool required = false) { options.Append(Option(DOUBLE, var, short_name, long_name, description, required)); } + + /// Add a string (char*) option and set 'var' to recieve the value. void AddOption(const char **var, const char *short_name, const char *long_name, const char *description, bool required = false) @@ -100,6 +111,8 @@ public: options.Append(Option(STRING, var, short_name, long_name, description, required)); } + + /// Add an integer array (seperated by spaces) option and set 'var' to recieve the values. void AddOption(Array * var, const char *short_name, const char *long_name, const char *description, bool required = false) @@ -107,6 +120,8 @@ public: options.Append(Option(ARRAY, var, short_name, long_name, description, required)); } + + /// Add a vector (doubles seperated by spaces) option and set 'var' to recieve the values. void AddOption(Vector * var, const char *short_name, const char *long_name, const char *description, bool required = false) @@ -116,8 +131,12 @@ public: } + /// Perse the command line options and pass the values to the registered variables. void Parse(); + + /// Return true if the command line options were parsed sucessfully. bool Good() const { return (error_type == 0); } + bool Help() const { return (error_type == 1); } void PrintOptions(std::ostream &out) const; void PrintError(std::ostream &out) const; diff --git a/general/sets.hpp b/general/sets.hpp index 94e347c682..6355fb05db 100644 --- a/general/sets.hpp +++ b/general/sets.hpp @@ -26,27 +26,32 @@ private: Array me; public: + /// Create an empty set. IntegerSet() { } + /// Create a copy of set 's'. IntegerSet(IntegerSet &s); - /// Create an integer set from a block of memory containing integer values - /// ( like an array ). - /// - /// n - length ( number of integers ) - /// p - pointer to block of memory containing the integer values + /// Create an integer set from C-array 'p' of 'n' integers. IntegerSet(const int n, const int *p) { Recreate(n, p); } + /// Return the size of the set. int Size() { return me.Size(); } + /// Return a reference to the sorted array of all the set entries. operator Array& () { return me; } + /// Return the value of the lowest element of the set. int PickElement() { return me[0]; } + /// Return the value of a random element of the sest. int PickRandomElement(); + /// Return 1 if the sets are equal and 0 otherwise. int operator==(IntegerSet &s); + /** Create an integer set from C-array 'p' of 'n' integers. + Overwrites any existing set data. */ void Recreate(const int n, const int *p); }; @@ -58,16 +63,23 @@ private: public: + /// Return the number of integer sets in the list. int Size() { return TheList.Size(); } + /// Return the value of the first element of the ith set. int PickElementInSet(int i) { return TheList[i]->PickElement(); } + /// Return a random value from the ith set in the list. int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); } + /** @brief Check to see if set 's' is in the list. If not append it to the end of the + list. Returns the index of the list where set 's' can be found. */ int Insert(IntegerSet &s); + /// Return the index of the list where set 's' can be found. Returns -1 if not found. int Lookup(IntegerSet &s); + /// Write the list of sets into table 't'. void AsTable(Table &t); ~ListOfIntegerSets(); diff --git a/general/socketstream.hpp b/general/socketstream.hpp index fb13c0e1bf..7d784e8dd3 100644 --- a/general/socketstream.hpp +++ b/general/socketstream.hpp @@ -36,6 +36,7 @@ protected: char ibuf[buflen], obuf[buflen]; public: + socketbuf() { socket_descriptor = -1; @@ -53,18 +54,26 @@ public: open(hostname, port); } - /** Attach a new socket descriptor to the socketbuf. + /** @brief Attach a new socket descriptor to the socketbuf. Returns the old socket descriptor which is NOT closed. */ virtual int attach(int sd); + /// Detatch the current socket descriptor from the socketbuf. int detach() { return attach(-1); } + /** @brief Open a socket on the 'port' at 'hostname' and store the + socket descriptor. Returns 0 if there is no error, + otherwise returns -1. */ virtual int open(const char hostname[], int port); + /// Close the current socket descriptor. virtual int close(); + /// Returns the attached socket descriptor. int getsocketdescriptor() { return socket_descriptor; } + /** @brief Returns true of the socket is open and has a valid + socket descriptor. Otherwise returns false. */ bool is_open() { return (socket_descriptor >= 0); } virtual ~socketbuf() { close(); } @@ -255,10 +264,13 @@ public: socketbuf *rdbuf() { return buf__; } + /// Open the socket stream on 'port' at 'hostname'. int open(const char hostname[], int port); + /// Close the socketstream. int close() { return buf__->close(); } + /// True if the socketstream is open, false otherwise. bool is_open() { return buf__->is_open(); } virtual ~socketstream(); diff --git a/general/sort_pairs.hpp b/general/sort_pairs.hpp index 9a18bd8b61..1d359cebba 100644 --- a/general/sort_pairs.hpp +++ b/general/sort_pairs.hpp @@ -50,7 +50,7 @@ void SortPairs (Pair *pairs, int size) std::sort(pairs, pairs + size); } - +/// A triple of objects template class Triple { diff --git a/general/stable3d.hpp b/general/stable3d.hpp index f6392753af..77e55a483f 100644 --- a/general/stable3d.hpp +++ b/general/stable3d.hpp @@ -25,7 +25,14 @@ public: int Column, Floor, Number; }; -/// Symmetric 3D Table +/** @brief Symmetric 3D Table stored an array of rows each of which has + a stack of column, floor, number nodes. The number of the node + is assigned by counting the nodes from zero as they are pushed + into the table. Diagonals of any kind are not so the row, column + and floor must all be different for each node. Only one node is + stored for all 6 symmetric entries that are indexable by unique + triplets of row, column, and floor. +*/ class STable3D { private: @@ -37,20 +44,35 @@ private: #endif public: + /// Construct the table with a total of 'nr' rows. explicit STable3D (int nr); + /** @brief Check to see if this entry is in the table and add it to + the table if it is not there. Returns the number assigned to the + table entry. */ int Push (int r, int c, int f); + /// Return the number assigned to the table entry. Abort if it's not there. int operator() (int r, int c, int f) const; + /// Return the number assigned to the table entry. Return -1 if it's not there. int Index (int r, int c, int f) const; + /** @brief Check to see if this entry is in the table and add it to + the table if it is not there. The entry is addressed by the three + smallest values of (r,c,f,t). Returns the number assigned to the + table entry. */ int Push4 (int r, int c, int f, int t); + /** Return the number assigned to the table entry. The entry is + addressed by the three smallest values of (r,c,f,t). Return -1 if + it is not there. */ int operator() (int r, int c, int f, int t) const; + /// Return the number of elements added to the table. int NumberOfElements() { return NElem; } + /// Print out all of the table elements. void Print(std::ostream &out = mfem::out) const; ~STable3D (); diff --git a/general/table.hpp b/general/table.hpp index 370e0ffaae..3372835d64 100644 --- a/general/table.hpp +++ b/general/table.hpp @@ -185,7 +185,6 @@ Table * Mult (const Table &A, const Table &B); /** Data type STable. STable is similar to Table, but it's for symmetric connectivity, i.e. TYPE I is equivalent to TYPE II. In the first dimension we put the elements with smaller index. */ - class STable : public Table { public: diff --git a/general/text.hpp b/general/text.hpp index b54f8c863a..15db5f5771 100644 --- a/general/text.hpp +++ b/general/text.hpp @@ -37,7 +37,7 @@ inline void skip_comment_lines(std::istream &is, const char comment_char) } } -// Check for, and remove, a trailing '\r'. +/// Check for, and remove, a trailing '\r' from and std::string. inline void filter_dos(std::string &line) { if (!line.empty() && *line.rbegin() == '\r') @@ -46,7 +46,7 @@ inline void filter_dos(std::string &line) } } -// Convert an integer to a string +/// Convert an integer to an std::string. inline std::string to_string(int i) { std::stringstream ss; @@ -58,7 +58,7 @@ inline std::string to_string(int i) return out_str; } -// Convert an integer to a 0-padded string with the given number of 'digits' +/// Convert an integer to a 0-padded string with the given number of 'digits' inline std::string to_padded_string(int i, int digits) { std::ostringstream oss; @@ -66,7 +66,7 @@ inline std::string to_padded_string(int i, int digits) return oss.str(); } -// Convert a string to an int +/// Convert a string to an int inline int to_int(const std::string& str) { int i; diff --git a/general/tic_toc.hpp b/general/tic_toc.hpp index 073118d785..4da2f044e2 100644 --- a/general/tic_toc.hpp +++ b/general/tic_toc.hpp @@ -38,12 +38,26 @@ private: public: StopWatch(); + + /// Clear the elapsed time on the stopwatch and restart it if it's running. void Clear(); + + /// Clear the elapsed time and start the stopwatch. void Start(); + + /// Stop the stopwatch. void Stop(); + + ///Return the time resolution available to the stopwatch. double Resolution(); + + /// Return the number of real seconds elapsed since the stopwatch was started. double RealTime(); + + /// Return the number of user seconds elapsed since the stopwatch was started. double UserTime(); + + /// Return the number of system seconds elapsed since the stopwatch was started. double SystTime(); ~StopWatch(); }; @@ -51,10 +65,10 @@ public: extern StopWatch tic_toc; -/// Start timing +/// Start the tic_toc timer extern void tic(); -/// End timing +/// End timing and return the time from tic() to toc() in seconds. extern double toc(); } diff --git a/general/version.hpp b/general/version.hpp index 8294683feb..9df579c478 100644 --- a/general/version.hpp +++ b/general/version.hpp @@ -15,13 +15,25 @@ namespace mfem { +/// Return the version number as a single integer. int GetVersion(); + +/// Return the major version number as an integer. int GetVersionMajor(); + +/// Return the minor version number as an integer. int GetVersionMinor(); + +/// Return the version patch number as an integer. int GetVersionPatch(); +/// Return the version number as a string. const char *GetVersionStr(); + +/// Return the Git hash as a string. const char *GetGitStr(); + +/// Return the MFEM configuration as a string. const char *GetConfigStr(); } // namespace mfem From c388a9dd7bb26175542aa431e9747ec403eed39c Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Thu, 9 May 2019 16:24:38 -0700 Subject: [PATCH 026/535] Added doxygen for all of the coefficient code. --- fem/coefficient.hpp | 313 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 252 insertions(+), 61 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 245f985f63..782946c807 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -27,7 +27,7 @@ class ParMesh; #endif -/// Base class Coefficient that may optionally depend on time. +/// Base class Coefficients that optionally depend on space and time. class Coefficient { protected: @@ -36,7 +36,10 @@ protected: public: Coefficient() { time = 0.; } + /// Set the time for time dependent coefficients void SetTime(double t) { time = t; } + + /// Get the time for time dependent coefficients double GetTime() { return time; } /** @brief Evaluate the coefficient in the element described by @a T at the @@ -63,7 +66,7 @@ public: }; -/// Subclass constant coefficient. +/// A coefficient that is constant across space and time class ConstantCoefficient : public Coefficient { public: @@ -72,13 +75,14 @@ public: /// c is value of constant function explicit ConstantCoefficient(double c = 1.0) { constant=c; } - /// Evaluate the coefficient + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) { return (constant); } }; -/// class for piecewise constant coefficient +/** @brief A piecewise constant coefficient with the constants keyed + off the element attribute numbers. */ class PWConstCoefficient : public Coefficient { private: @@ -90,31 +94,33 @@ public: explicit PWConstCoefficient(int NumOfSubD = 0) : constants(NumOfSubD) { constants = 0.0; } - /** c should be a vector defined by attributes, so for region with - attribute i c[i] is the coefficient in that region */ + + /// Construct the constant coefficient using a vector of constants. + /** @a c should be a vector defined by attributes, so for the region + with attribute @a i @a c[i] is the coefficient in that region. */ PWConstCoefficient(Vector &c) { constants.SetSize(c.Size()); constants=c; } - /// Update constants + /// Update the constants with vector @a c. void UpdateConstants(Vector &c) { constants.SetSize(c.Size()); constants=c; } - /// Member function to access or modify the value of the i-th constant + /// Return a reference to the i-th constant double &operator()(int i) { return constants(i-1); } - /// Set domain constants equal to the same constant c + /// Set the constants for all attributes to constant @a c. void operator=(double c) { constants = c; } - /// Returns the number of constants + /// Returns the number of constants representing different attributes. int GetNConst() { return constants.Size(); } - /// Evaluate the coefficient function + /// Evaluate the coefficient. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; typedef double (*DeviceFunctionCoefficientPtr)(const Vector3&); -/// class for C-function coefficient +/// A general C-function coefficient class FunctionCoefficient : public Coefficient { protected: @@ -123,7 +129,7 @@ protected: double (*DeviceFunction)(const Vector3&); public: - /// Define a time-independent coefficient from a C-function + /// Define a time-independent coefficient from a pointer to a C-function FunctionCoefficient(double (*f)(const Vector &)) { Function = f; @@ -131,7 +137,7 @@ public: DeviceFunction = NULL; } - /// Define a time-dependent coefficient from a C-function + /// Define a time-dependent coefficient from a pointer to a C-function FunctionCoefficient(double (*tdf)(const Vector &, double)) { Function = NULL; @@ -168,13 +174,13 @@ public: DeviceFunction = NULL; } - /// Evaluate coefficient + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); /// Return the coefficient's C-function that uses Vector3. - /// Warning: for now, the returned function can only be used on the - /// host inside a MFEM_FORALL. + /** Warning: for now, the returned function can only be used on the + host inside a MFEM_FORALL. */ DeviceFunctionCoefficientPtr GetDeviceFunction(); }; @@ -194,13 +200,24 @@ public: GridFunctionCoefficient (GridFunction *gf, int comp = 1) { GridF = gf; Component = comp; } + /// Set the internal GridFunction void SetGridFunction(GridFunction *gf) { GridF = gf; } + + /// Get the internal GridFunction GridFunction * GetGridFunction() const { return GridF; } + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; + +/** @brief A coefficient that depends on 1 or 2 parent coefficients and a + transformation rule represented by a c-function. + + \f$ C(x,t) = T(Q1(x,t)) \f$ or \f$ C(x,t) = T(Q1(x,t), Q2(x,t)) \f$ + + where T is the transformation rule, and Q1/Q2 are the parent coefficients.*/ class TransformedCoefficient : public Coefficient { private: @@ -216,10 +233,20 @@ public: double (*F)(double,double)) : Q1(q1), Q2(q2), Transform2(F) { Transform1 = 0; } + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; -/// Delta function coefficient +/** @brief Delta function coefficient optionally multiplied by a weight + coefficient and a scaled time dependent c-function. + + \f$ F(x,t) = w(x,t) s T(t) d(x - xc) \f$ + + where w is the optional weight coefficient, @a s is a scale factor + T is an optional time-dependent function and d is a delta function. + + WARNING this cannot be used as a normal coefficient. The usual Eval + method is disabled. */ class DeltaCoefficient : public Coefficient { protected: @@ -229,21 +256,29 @@ protected: double (*tdf)(double); public: + + /// Construct a unit delta function centered at (0.0,0.0,0.0) DeltaCoefficient() { center[0] = center[1] = center[2] = 0.; scale = 1.; tol = 1e-12; weight = NULL; sdim = 0; tdf = NULL; } + + /// Construct a delta function scaled by @a s and centered at (x,0.0,0.0) DeltaCoefficient(double x, double s) { center[0] = x; center[1] = 0.; center[2] = 0.; scale = s; tol = 1e-12; weight = NULL; sdim = 1; tdf = NULL; } + + /// Construct a delta function scaled by @a s and centered at (x,y,0.0) DeltaCoefficient(double x, double y, double s) { center[0] = x; center[1] = y; center[2] = 0.; scale = s; tol = 1e-12; weight = NULL; sdim = 2; tdf = NULL; } + + /// Construct a delta function scaled by @a s and centered at (x,y,z) DeltaCoefficient(double x, double y, double z, double s) { center[0] = x; center[1] = y; center[2] = z; scale = s; tol = 1e-12; @@ -251,12 +286,15 @@ public: } void SetDeltaCenter(const Vector& center); void SetScale(double _s) { scale = _s; } + /// Set a time-dependent function that multiplies the Scale(). void SetFunction(double (*f)(double)) { tdf = f; } + /** @brief Set the tolerance used during projection onto GridFunction to - identifying the Mesh vertex where the Center() of the delta function - lies. */ + identify the Mesh vertex where the Center() of the delta function + lies. (default 1e-12)*/ void SetTol(double _tol) { tol = _tol; } + /// Set a weight Coefficient that multiplies the DeltaCoefficient. /** The weight Coefficient multiplies the value returned by EvalDelta() but not the value returned by Scale(). @@ -264,16 +302,23 @@ public: projecting the DeltaCoefficient onto a GridFunction, so that the weighted integral of the projection is exactly equal to the Scale(). */ void SetWeight(Coefficient *w) { weight = w; } + + /// Return a pointer to a c-array representing the center of the delta function. const double *Center() { return center; } - /** @brief Return the scale set by SetScale() multiplied by the - time-dependent function specified by SetFunction(), if set. */ + + /** @brief Return the value of the time */ double Scale() { return tdf ? (*tdf)(GetTime())*scale : scale; } - /// See SetTol() for description of the tolerance parameter. + + /// Return the tolerance used to identify the mesh vertex double Tol() { return tol; } + /// See SetWeight() for description of the weight Coefficient. Coefficient *Weight() { return weight; } + + /// Write the center of the delta function into @a center. void GetDeltaCenter(Vector& center); - /// Return the Scale() multiplied by the weight Coefficient, if any. + + /// The value of the function assuming we are evaluating at the delta center. virtual double EvalDelta(ElementTransformation &T, const IntegrationPoint &ip); /** @brief A DeltaFunction cannot be evaluated. Calling this method will cause an MFEM error, terminating the application. */ @@ -282,7 +327,8 @@ public: virtual ~DeltaCoefficient() { delete weight; } }; -/// Coefficient defined on a subset of domain or boundary attributes +/** @brief Derived coefficient that takes the value of the parent coefficient + for the active attrs and is zero otherwise. */ class RestrictedCoefficient : public Coefficient { private: @@ -290,13 +336,18 @@ private: Array active_attr; public: + /** @brief Construct with a parent coefficient and an array of zeros and + ones representing which attributes this coefficient should be active. */ RestrictedCoefficient(Coefficient &_c, Array &attr) { c = &_c; attr.Copy(active_attr); } + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) { return active_attr[T.Attribute-1] ? c->Eval(T, ip, GetTime()) : 0.0; } }; + +/// Base class for Vector Coefficients that optionally depend on time and space. class VectorCoefficient { protected: @@ -306,7 +357,10 @@ protected: public: VectorCoefficient(int vd) { vdim = vd; time = 0.; } + /// Set the time for time dependent coefficients void SetTime(double t) { time = t; } + + /// Get the time for time dependent coefficients double GetTime() { return time; } /// Returns dimension of the vector. @@ -338,18 +392,24 @@ public: virtual ~VectorCoefficient() { } }; + +/// Vector coefficient that is constant in space and time. class VectorConstantCoefficient : public VectorCoefficient { private: Vector vec; public: + /// Construct the coefficient with constant vector @a v. VectorConstantCoefficient(const Vector &v) : VectorCoefficient(v.Size()), vec(v) { } using VectorCoefficient::Eval; + + /// Evaluate the vector coefficient at @ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { V = vec; } }; +/// A general C-function vector coefficient class VectorFunctionCoefficient : public VectorCoefficient { private: @@ -378,35 +438,44 @@ public: } using VectorCoefficient::Eval; + /// Evaluate the vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); virtual ~VectorFunctionCoefficient() { } }; -/// Vector coefficient defined by an array of scalar coefficients. +/** @brief Vector coefficient defined by an array of scalar coefficients. + Coefficients that are not set will evaluate to zero in the vector. + This object takes ownership of the array of coefficients inside it and + deletes them at object destruction. */ class VectorArrayCoefficient : public VectorCoefficient { private: Array Coeff; public: - /// Construct vector of dim coefficients. + /** @brief Construct vector of dim coefficients. The actual coefficients + still need to be added with Set(). */ explicit VectorArrayCoefficient(int dim); /// Returns i'th coefficient. Coefficient* GetCoeff(int i) { return Coeff[i]; } + /// Returns the entire array of coefficients. Coefficient **GetCoeffs() { return Coeff; } - /// Sets coefficient in the vector. + //TODO: Do we really want to delete + /// Sets i'th coefficient in the array. void Set(int i, Coefficient *c) { delete Coeff[i]; Coeff[i] = c; } - /// Evaluates i'th component of the vector. + /// Evaluates i'th component of the vector of coefficients. Returns double Eval(int i, ElementTransformation &T, const IntegrationPoint &ip) { return Coeff[i] ? Coeff[i]->Eval(T, ip, GetTime()) : 0.0; } using VectorCoefficient::Eval; + /** @brief Evaluate the coefficient. Each element of vector V comes from the + associated array of scalar coefficients. */ virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -421,15 +490,24 @@ protected: GridFunction *GridFunc; public: + /** @brief Construct an empty coefficient. Calling Eval() before the grid + function is set with cause a segfault. */ VectorGridFunctionCoefficient() : VectorCoefficient(0), GridFunc(NULL) { } + + /** @brief Construct the coefficient with grid function @a gf. The + grid function is not owned by the coefficient. */ VectorGridFunctionCoefficient(GridFunction *gf); + /// Set the grid function void SetGridFunction(GridFunction *gf); GridFunction * GetGridFunction() const { return GridFunc; } + /// Evaluate the vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); + /** @brief Evaluate the vector coefficient at all of the locations in the + integration rule and write the vectors into matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -443,14 +521,23 @@ protected: GridFunction *GridFunc; public: + /** @brief Construct the coefficient with a scalar grid function + @a gf. The grid function is not owned by the coefficient. */ GradientGridFunctionCoefficient(GridFunction *gf); + ///Set the scalar grid function. void SetGridFunction(GridFunction *gf); + + ///Get the scalar grid function. GridFunction * GetGridFunction() const { return GridFunc; } + /// Evaluate the gradient vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); + /** @brief Evaluate the gradient vector coefficient at all of the + locations in the integration rule and write the vectors into + matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -464,12 +551,18 @@ protected: GridFunction *GridFunc; public: + /** @brief Construct the coefficient with a vector grid function + @a gf. The grid function is not owned by the coefficient. */ CurlGridFunctionCoefficient(GridFunction *gf); + /// Set the vector grid function. void SetGridFunction(GridFunction *gf); + + /// Get the vector grid function. GridFunction * GetGridFunction() const { return GridFunc; } using VectorCoefficient::Eval; + /// Evaluate the vector curl coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -483,18 +576,28 @@ protected: GridFunction *GridFunc; public: + /** @brief Construct the coefficient with a vector grid function + @a gf. The grid function is not owned by the coefficient. */ DivergenceGridFunctionCoefficient(GridFunction *gf); + // /Set the vector grid function. void SetGridFunction(GridFunction *gf) { GridFunc = gf; } + + /// Get the vector grid function. GridFunction * GetGridFunction() const { return GridFunc; } + /// Evaluate the scalar divergence coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); virtual ~DivergenceGridFunctionCoefficient() { } }; -/// VectorDeltaCoefficient: DeltaCoefficient with a direction +/** @brief Vector coefficient defined by a scalar DeltaCoefficient and a + constant vector direction. + + WARNING this cannot be used as a normal coefficient. The usual Eval + method is disabled. */ class VectorDeltaCoefficient : public VectorCoefficient { protected: @@ -502,32 +605,51 @@ protected: DeltaCoefficient d; public: + /// Construct with a vector of dimension @a _vdim. VectorDeltaCoefficient(int _vdim) : VectorCoefficient(_vdim), dir(_vdim), d() { } + + /** @brief Construct with a Vector object representing the direction and + a unit delta function centered at (0.0,0.0,0.0) */ VectorDeltaCoefficient(const Vector& _dir) : VectorCoefficient(_dir.Size()), dir(_dir), d() { } + + /** @brief Construct with a Vector object representing the direction and + a delta function scaled by @a s and centered at (x,0.0,0.0) */ VectorDeltaCoefficient(const Vector& _dir, double x, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,s) { } + + /** @brief Construct with a Vector object representing the direction and + a delta function scaled by @a s and centered at (x,y,0.0) */ VectorDeltaCoefficient(const Vector& _dir, double x, double y, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,s) { } + + /** @brief Construct with a Vector object representing the direction and + a delta function scaled by @a s and centered at (x,y,z) */ VectorDeltaCoefficient(const Vector& _dir, double x, double y, double z, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,z,s) { } - /// Replace the associated DeltaCoeficient with a new DeltaCoeficient. + /// Replace the associated DeltaCoefficient with a new DeltaCoeficient. /** The new DeltaCoeficient cannot have a specified weight Coefficient, i.e. DeltaCoeficient::Weight() should return NULL. */ void SetDeltaCoefficient(const DeltaCoefficient& _d) { d = _d; } + /// Return the associated scalar DeltaCoefficient. DeltaCoefficient& GetDeltaCoefficient() { return d; } + + /// Set the direction vector to @a _d. void SetDirection(const Vector& _d); + /// Get the center of the underlying delta function. void GetDeltaCenter(Vector& center) { d.GetDeltaCenter(center); } + /** @brief Return the specified direction vector multiplied by the value returned by DeltaCoefficient::EvalDelta() of the associated scalar DeltaCoefficient. */ virtual void EvalDelta(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); + using VectorCoefficient::Eval; /** @brief A VectorDeltaFunction cannot be evaluated. Calling this method will cause an MFEM error, terminating the application. */ @@ -537,7 +659,8 @@ public: virtual ~VectorDeltaCoefficient() { } }; -/// VectorCoefficient defined on a subset of domain or boundary attributes +/** @brief Derived vector coefficient that takes the value of the parent vector + coefficient for the active attrs and is zero otherwise. */ class VectorRestrictedCoefficient : public VectorCoefficient { private: @@ -545,18 +668,25 @@ private: Array active_attr; public: + /** @brief Construct with a parent vector coefficient and an array of zeros and + ones representing the attributes for which this coefficient should be active. */ VectorRestrictedCoefficient(VectorCoefficient &vc, Array &attr) : VectorCoefficient(vc.GetVDim()) { c = &vc; attr.Copy(active_attr); } + /// Evaluate the vector coefficient at @ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); + /** @brief Evaluate the vector coefficient at all of the + locations in the integration rule and write the vectors into + matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); }; +/// Base class forMatrix Coefficients that optionally depend on time and space. class MatrixCoefficient { protected: @@ -564,16 +694,25 @@ protected: double time; public: + /// Construct a dim x dim matrix coefficient. explicit MatrixCoefficient(int dim) { height = width = dim; time = 0.; } + /// Construct a h x b matrix coefficient. MatrixCoefficient(int h, int w) : height(h), width(w), time(0.) { } + /// Set the time for time dependent coefficients void SetTime(double t) { time = t; } + + /// Get the time for time dependent coefficients double GetTime() { return time; } + /// Get the height of the matrix. int GetHeight() const { return height; } + + /// Get the width of the matrix. int GetWidth() const { return width; } - // For backward compatibility + + // For backward compatibility get the width of the matrix. int GetVDim() const { return width; } /** @brief Evaluate the matrix coefficient in the element described by @a T @@ -587,18 +726,27 @@ public: virtual ~MatrixCoefficient() { } }; + +/// A matrix coefficient that is constant in space and time. class MatrixConstantCoefficient : public MatrixCoefficient { private: DenseMatrix mat; public: + ///Construct using matrix @a m for the constant. MatrixConstantCoefficient(const DenseMatrix &m) : MatrixCoefficient(m.Height(), m.Width()), mat(m) { } using MatrixCoefficient::Eval; + /// Evaluate the matrix coefficient at @ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip) { M = mat; } }; + +/** @brief A matrix coefficient with an optional scalar coefficient + multiplier \a q. The matrix function can either be represented by a + C-function or a constant matrix provided when constructiong this + object. */ class MatrixFunctionCoefficient : public MatrixCoefficient { private: @@ -608,7 +756,7 @@ private: DenseMatrix mat; public: - /// Construct a time-independent square matrix coefficient from a C-function + /// Construct a square matrix coefficient from a C-function without time dependence. MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, DenseMatrix &), Coefficient *q = NULL) : MatrixCoefficient(dim), Q(q) @@ -627,7 +775,7 @@ public: mat = m; } - /// Construct a time-dependent square matrix coefficient from a C-function + /// Construct a square matrix coefficient from a C-function with time-dependence. MatrixFunctionCoefficient(int dim, void (*TDF)(const Vector &, double, DenseMatrix &), Coefficient *q = NULL) @@ -638,35 +786,51 @@ public: mat.SetSize(0); } + /// Evaluate the matrix coefficient at @ip. virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip); virtual ~MatrixFunctionCoefficient() { } }; + + +/** @brief Matrix coefficient defined by an matrix of scalar coefficients. + Coefficients that are not set will evaluate to zero in the vector. The + of coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. + This object takes ownership of the array of coefficients inside it and + deletes them at object destruction. + */ class MatrixArrayCoefficient : public MatrixCoefficient { private: Array Coeff; public: - + /** @brief Construct matrix of dim = height*width coefficients. + The actual coefficients still need to be added with Set(). */ explicit MatrixArrayCoefficient (int dim); + /// Get the coefficient located at (i,j) in the matrix. Coefficient* GetCoeff (int i, int j) { return Coeff[i*width+j]; } + /// Set the coefficient located at (i,j) in the matrix. void Set(int i, int j, Coefficient * c) { delete Coeff[i*width+j]; Coeff[i*width+j] = c; } + /// Evaluate coefficient located at (i,j) in the matrix using integration point @a ip. double Eval(int i, int j, ElementTransformation &T, const IntegrationPoint &ip) { return Coeff[i*width+j] ? Coeff[i*width+j] -> Eval(T, ip, GetTime()) : 0.0; } + /// Evaluate the matrix coefficient @a ip. virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip); virtual ~MatrixArrayCoefficient(); }; -/// MatrixCoefficient defined on a subset of domain or boundary attributes + +/** @brief Derived matrix coefficient that takes the value of the parent + matrix coefficient for the active attrs and is zero otherwise. */ class MatrixRestrictedCoefficient : public MatrixCoefficient { private: @@ -674,10 +838,13 @@ private: Array active_attr; public: + /** @brief Construct with a parent matrix coefficient and an array of zeros and + ones representing the attributes for which this coefficient should be active. */ MatrixRestrictedCoefficient(MatrixCoefficient &mc, Array &attr) : MatrixCoefficient(mc.GetHeight(), mc.GetWidth()) { c = &mc; attr.Copy(active_attr); } + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip); }; @@ -695,12 +862,12 @@ private: double beta; public: - // Result is _alpha * A + _beta * B + /// Construct with the two coefficeints. Result is _alpha * A + _beta * B. SumCoefficient(Coefficient &A, Coefficient &B, double _alpha = 1.0, double _beta = 1.0) : a(&A), b(&B), alpha(_alpha), beta(_beta) { } - /// Evaluate the coefficient + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) { return alpha * a->Eval(T, ip) + beta * b->Eval(T, ip); } @@ -714,10 +881,11 @@ private: Coefficient * b; public: + /// Construct with the two coefficients. Result is A * B. ProductCoefficient(Coefficient &A, Coefficient &B) : a(&A), b(&B) { } - /// Evaluate the coefficient + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) { return a->Eval(T, ip) * b->Eval(T, ip); } @@ -732,16 +900,17 @@ private: double p; public: - // Result is A^p + /// Construct with a coefficient and a constant power @a _p. Result is A^p. PowerCoefficient(Coefficient &A, double _p) : a(&A), p(_p) { } - /// Evaluate the coefficient + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) { return pow(a->Eval(T, ip), p); } }; + /// Scalar coefficient defined as the inner product of two vector coefficients class InnerProductCoefficient : public Coefficient { @@ -752,14 +921,15 @@ private: mutable Vector va; mutable Vector vb; public: + /// Construxt with the two vector coefficients. Result is \f$ A \cdot B \f$. InnerProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); - /// Evaluate the coefficient + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; -/// Scalar coefficient defined as a cross product of two vectors in 2D +/// Scalar coefficient defined as a cross product of two vectors in the xy-plane. class VectorRotProductCoefficient : public Coefficient { private: @@ -770,8 +940,10 @@ private: mutable Vector vb; public: + /// Construxt with the two vector coefficients. Result is \f$ A_x B_y - A_y * B_x; \f$. VectorRotProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Evaluate the coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; @@ -785,9 +957,10 @@ private: mutable DenseMatrix ma; public: + /// Construxt with the matrix. DeterminantCoefficient(MatrixCoefficient &A); - /// Evaluate the coefficient + /// Evaluate the determinant coefficient at @a ip. virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; @@ -805,17 +978,17 @@ private: mutable Vector va; public: - // Result is _alpha * A + _beta * B + /// Construct with the two vector coefficients. Result is _alpha * A + _beta * B. VectorSumCoefficient(VectorCoefficient &A, VectorCoefficient &B, double _alpha = 1.0, double _beta = 1.0); - /// Evaluate the coefficient + /// Evaluate the coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; }; -/// Vector coefficient defined as a product of a scalar and a vector +/// Vector coefficient defined as a product of scalar and vector coefficients. class ScalarVectorProductCoefficient : public VectorCoefficient { private: @@ -823,8 +996,10 @@ private: VectorCoefficient * b; public: + /// Construct with the two coefficients. Result is A * B. ScalarVectorProductCoefficient(Coefficient &A, VectorCoefficient &B); + /// Evaluate the coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; @@ -841,14 +1016,17 @@ private: mutable Vector vb; public: + /// Construct with the two coefficients. Result is A x B. VectorCrossProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Evaluate the coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; }; -/// Vector coefficient defined as a matrix vector product +/** @brief Vector coefficient defined as a product of a matrix coeffiecient and + a vector coefficient. */ class MatVecCoefficient : public VectorCoefficient { private: @@ -859,28 +1037,32 @@ private: mutable Vector vb; public: + /// Construct with the two coefficients. Result is A*B. MatVecCoefficient(MatrixCoefficient &A, VectorCoefficient &B); + /// Evaluate the vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; }; -/// Matrix coefficient defined as the identity of dimension d +/// Constant matrix coefficient defined as the identity of dimension d class IdentityMatrixCoefficient : public MatrixCoefficient { private: int dim; public: + /// Construct with the dimension of the square identity matrix. IdentityMatrixCoefficient(int d) : MatrixCoefficient(d, d), dim(d) { } + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; -/// Matrix coefficient defined as the sum of two matrix coefficients +/// Matrix coefficient defined as the sum of two matrix coefficients. class MatrixSumCoefficient : public MatrixCoefficient { private: @@ -893,16 +1075,17 @@ private: mutable DenseMatrix ma; public: - // Result is _alpha * A + _beta * B + /// Construct with the two coefficients. Result is _alpha * A + _beta * B. MatrixSumCoefficient(MatrixCoefficient &A, MatrixCoefficient &B, double _alpha = 1.0, double _beta = 1.0); - /// Evaluate the coefficient + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; -/// Matrix coefficient defined as a product of a scalar and a matrix +/** @brief Matrix coefficient defined as a product of a scalar + coefficient and a matrix coefficient.*/ class ScalarMatrixProductCoefficient : public MatrixCoefficient { private: @@ -910,39 +1093,45 @@ private: MatrixCoefficient * b; public: + /// Construct with the two coefficients. Result is A*B. ScalarMatrixProductCoefficient(Coefficient &A, MatrixCoefficient &B); + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; -/// Matrix coefficient defined as the transpose a matrix +/// Matrix coefficient defined as the transpose a matrix coefficient class TransposeMatrixCoefficient : public MatrixCoefficient { private: MatrixCoefficient * a; public: + /// Construct with the matrix coefficient. Result is \f$ A^T \f$. TransposeMatrixCoefficient(MatrixCoefficient &A); + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; -/// Matrix coefficient defined as the inverse a matrix +/// Matrix coefficient defined as the inverse a matrix coefficient. class InverseMatrixCoefficient : public MatrixCoefficient { private: MatrixCoefficient * a; public: + /// Construct with the matrix coefficient. Result is \f$ A^{-1} \f$. InverseMatrixCoefficient(MatrixCoefficient &A); + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; -/// Matrix coefficient defined as the outer product of two vectors +/// Matrix coefficient defined as the outer product of two vector coefficients. class OuterProductCoefficient : public MatrixCoefficient { private: @@ -953,29 +1142,31 @@ private: mutable Vector vb; public: + /// Construct with two vector coefficients. Result is \f$ A B^T \f$. OuterProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; -/** Compute the Lp norm of a function f. +/** @brief Compute the Lp norm of a function f. \f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */ double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh, const IntegrationRule *irs[]); -/** Compute the Lp norm of a vector function f = {f_i}_i=1...N. +/** @brief Compute the Lp norm of a vector function f = {f_i}_i=1...N. \f$ \| f \|_{Lp} = ( \sum_i \| f_i \|_{Lp}^p )^{1/p} \f$ */ double ComputeLpNorm(double p, VectorCoefficient &coeff, Mesh &mesh, const IntegrationRule *irs[]); #ifdef MFEM_USE_MPI -/** Compute the global Lp norm of a function f. +/** @brief Compute the global Lp norm of a function f. \f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */ double ComputeGlobalLpNorm(double p, Coefficient &coeff, ParMesh &pmesh, const IntegrationRule *irs[]); -/** Compute the global Lp norm of a vector function f = {f_i}_i=1...N. +/** @brief Compute the global Lp norm of a vector function f = {f_i}_i=1...N. \f$ \| f \|_{Lp} = ( \sum_i \| f_i \|_{Lp}^p )^{1/p} \f$ */ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, const IntegrationRule *irs[]); From 9c6efb61b2ca0f05a62e8af9b8f5bf08bf39fa8f Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Fri, 10 May 2019 17:44:05 -0700 Subject: [PATCH 027/535] Added doxygen for eltrans. Added some logging for the doxygen to help find errors and undocumented stuff. --- doc/CodeDocumentation.conf.in | 4 +- doc/makefile | 9 ++++ fem/eltrans.hpp | 92 +++++++++++++++++++++++++++-------- general/array.hpp | 2 +- general/text.hpp | 6 +-- 5 files changed, 86 insertions(+), 27 deletions(-) diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in index 647043c08f..7c57b4c751 100644 --- a/doc/CodeDocumentation.conf.in +++ b/doc/CodeDocumentation.conf.in @@ -140,7 +140,7 @@ INLINE_INHERITED_MEMB = NO # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -746,7 +746,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = warnings.log #--------------------------------------------------------------------------- # Configuration options related to the input files diff --git a/doc/makefile b/doc/makefile index 4e52f96e65..7ff7652a00 100644 --- a/doc/makefile +++ b/doc/makefile @@ -12,15 +12,24 @@ MFEM_DIR ?= .. DOXYGEN_CONF = CodeDocumentation.conf + # doxygen uses: graphviz, latex html: $(DOXYGEN_CONF) doxygen $(DOXYGEN_CONF) rm -f CodeDocumentation.html ln -s CodeDocumentation/html/index.html CodeDocumentation.html + ( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ) | doxygen - + @echo "Warnings excuding undocumented:" + @wc -l < warnings.log + @echo "All warnings:" + @wc -l < undoc.log + clean: rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~ + rm -rf undoc.log warnings.log $(DOXYGEN_CONF): $(MFEM_DIR)/doc/$(DOXYGEN_CONF).in sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \ > $(DOXYGEN_CONF) + diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index ed0550baeb..0961024b2a 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -37,8 +37,8 @@ protected: Geometry::Type geom; int space_dim; - // Evaluate the Jacobian of the transformation at the IntPoint and store it - // in dFdx. + /** @brief Evaluate the Jacobian of the transformation at the IntPoint and + store it in dFdx. */ virtual const DenseMatrix &EvalJacobian() = 0; double EvalWeight(); @@ -50,14 +50,26 @@ public: ElementTransformation(); + /** @brief Set the integration point @a ip that weights and jacobians will + be evaluated at. */ void SetIntPoint(const IntegrationPoint *ip) { IntPoint = ip; EvalState = 0; } + + /// Get a const reference to the currently set integration point. const IntegrationPoint &GetIntPoint() { return *IntPoint; } + /** @brief Transform integration point from reference coordinates to + physical coordinates and store them in the vector. */ virtual void Transform(const IntegrationPoint &, Vector &) = 0; + + /** @brief Transform all the integration points from the integration rule + from reference coordinates to physical + coordinates and store them as column vectors in the matrix. */ virtual void Transform(const IntegrationRule &, DenseMatrix &) = 0; - /// Transform columns of 'matrix', store result in 'result'. + /** @brief Transform all the integration points from the column vectors + of @a matrix from reference coordinates to physical + coordinates and store them as column vectors in @a result. */ virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result) = 0; /** @brief Return the Jacobian matrix of the transformation at the currently @@ -68,24 +80,33 @@ public: const DenseMatrix &Jacobian() { return (EvalState & JACOBIAN_MASK) ? dFdx : EvalJacobian(); } + /** @brief Return the weight of the Jacobian matrix of the transformation + at the currently set IntegrationPoint, using the metion SetIntPoint(). + The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */ double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); } + /** @brief Return the adjugate of the Jacobian matrix of the transformation + at the currently set IntegrationPoint, using the method SetIntPoint(). */ const DenseMatrix &AdjugateJacobian() { return (EvalState & ADJUGATE_MASK) ? adjJ : EvalAdjugateJ(); } + /** @brief Return the inverse of the Jacobian matrix of the transformation + at the currently set IntegrationPoint, using the method SetIntPoint(). */ const DenseMatrix &InverseJacobian() { return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); } + virtual int Order() = 0; virtual int OrderJ() = 0; virtual int OrderW() = 0; - /// Order of adj(J)^t.grad(fi) + + /// Return the order of \f$ adj(J)^T \nabla fi \f$ virtual int OrderGrad(const FiniteElement *fe) = 0; /// Return the Geometry::Type of the reference element. Geometry::Type GetGeometryType() const { return geom; } - /// Return the dimension of the reference element. + /// Return the topological dimension of the reference element. int GetDimension() const { return Geometry::Dimension[geom]; } /// Get the dimension of the target (physical) space. @@ -281,7 +302,7 @@ public: virtual int Transform(const Vector &pt, IntegrationPoint &ip); }; - +/// A standard isoparametric element transformation class IsoparametricTransformation : public ElementTransformation { private: @@ -291,12 +312,15 @@ private: const FiniteElement *FElem; DenseMatrix PointMat; // dim x dof - // Evaluate the Jacobian of the transformation at the IntPoint and store it - // in dFdx. + /** @brief Evaluate the Jacobian of the transformation at the IntPoint and + store it in dFdx. */ virtual const DenseMatrix &EvalJacobian(); public: + /// Set the element that will be used to compute the transformations void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); } + + /// Get the current element used to compute the transformations const FiniteElement* GetFE() const { return FElem; } /** @brief Read and write access to the underlying point matrix describing @@ -304,26 +328,50 @@ public: /** The dimensions of the matrix are space-dim x dof. The transformation is defined as - x=F(xh)=P.phi(xh), + \f$ x = F( \hat x ) = P \phi( \hat x ) \f$ - where xh (x hat) is the reference point, x is the corresponding physical - point, P is the point matrix, and phi(xh) is the column-vector of all - basis functions evaluated at xh. The columns of P represent the control - points in physical space defining the transformation. */ + where \f$ \hat x \f$ is the reference point, @a x is the corresponding + physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is + the column-vector of all basis functions evaluated at xh. The columns of + @a P represent the control points in physical space defining the + transformation. */ DenseMatrix &GetPointMat() { return PointMat; } + + /** @brief Sets up the correct dimensions for the Jacobian computations. This + must be called after SetIdentityTransformation(), but before and calls to + EvalJacobian(). */ void FinalizeTransformation() { space_dim = PointMat.Height(); } + /// Set the FiniteElement Geometry for the reference elements being used. void SetIdentityTransformation(Geometry::Type GeomType); + /** @brief Transform integration point from reference coordinates to + physical coordinates and store them in the vector. */ virtual void Transform(const IntegrationPoint &, Vector &); + + /** @brief Transform all the integration points from the integration rule + from reference coordinates to physical + coordinates and store them as column vectors in the matrix. */ virtual void Transform(const IntegrationRule &, DenseMatrix &); + + /** @brief Transform all the integration points from the column vectors + of @a matrix from reference coordinates to physical + coordinates and store them as column vectors in @a result. */ virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); virtual int Order() { return FElem->GetOrder(); } virtual int OrderJ(); virtual int OrderW(); + + /// Return the order of \f$ adj(J)^T \nabla fi \f$ virtual int OrderGrad(const FiniteElement *fe); + /** @brief Transform a point @a pt from physical space to a point @a ip in + reference space. */ + /** Attempt to find the IntegrationPoint that is transformed into the given + point in physical space. If the inversion fails a non-zero value is + returned. This method is not 100 percent reliable for non-linear + transformations. */ virtual int TransformBack(const Vector & v, IntegrationPoint & ip) { InverseElementTransformation inv_tr(this); @@ -341,15 +389,8 @@ public: void Transform (const IntegrationRule &, IntegrationRule &); }; -class FaceElementTransformations -{ -public: - int Elem1No, Elem2No, FaceGeom; - ElementTransformation *Elem1, *Elem2, *Face; - IntegrationPointTransformation Loc1, Loc2; -}; -/* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) +/** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) Physical Space @@ -380,6 +421,15 @@ public: Reference Space */ +class FaceElementTransformations +{ +public: + int Elem1No, Elem2No, FaceGeom; + ElementTransformation *Elem1, *Elem2, *Face; + IntegrationPointTransformation Loc1, Loc2; +}; + + } diff --git a/general/array.hpp b/general/array.hpp index b916d0dd92..d04a7e9a83 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -118,7 +118,7 @@ public: /// Returns const pointer to the data. inline const T *GetData() const { return (T *)data; } - /** @breif Return true if this object owns the data in the array + /** @brief Return true if this object owns the data in the array and will handle deallocation. */ inline bool OwnsData() const { return (allocsize > 0); } diff --git a/general/text.hpp b/general/text.hpp index 15db5f5771..a8039d8a7f 100644 --- a/general/text.hpp +++ b/general/text.hpp @@ -23,7 +23,7 @@ namespace mfem { // Utilities for text parsing - +/// Check to see if the in the stream starts with @a comment_char. If so skip it. inline void skip_comment_lines(std::istream &is, const char comment_char) { while (1) @@ -37,7 +37,7 @@ inline void skip_comment_lines(std::istream &is, const char comment_char) } } -/// Check for, and remove, a trailing '\r' from and std::string. +/// Check for, and remove, a trailing '\\r' from and std::string. inline void filter_dos(std::string &line) { if (!line.empty() && *line.rbegin() == '\r') @@ -58,7 +58,7 @@ inline std::string to_string(int i) return out_str; } -/// Convert an integer to a 0-padded string with the given number of 'digits' +/// Convert an integer to a 0-padded string with the given number of @a digits inline std::string to_padded_string(int i, int digits) { std::ostringstream oss; From 2e3d917e0c5eac6a2e25813a53e23ace0c1fa58f Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Fri, 17 May 2019 16:31:51 -0700 Subject: [PATCH 028/535] Improved the doxygen warning/error logging and fixed all of the errors in existing documentation. --- doc/CodeDocumentation.conf.in | 4 ++-- doc/makefile | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in index 7c57b4c751..28568a749b 100644 --- a/doc/CodeDocumentation.conf.in +++ b/doc/CodeDocumentation.conf.in @@ -140,7 +140,7 @@ INLINE_INHERITED_MEMB = NO # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = NO +FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -698,7 +698,7 @@ CITE_BIB_FILES = # messages are off. # The default value is: NO. -QUIET = NO +QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES diff --git a/doc/makefile b/doc/makefile index 7ff7652a00..df21406624 100644 --- a/doc/makefile +++ b/doc/makefile @@ -15,11 +15,17 @@ DOXYGEN_CONF = CodeDocumentation.conf # doxygen uses: graphviz, latex html: $(DOXYGEN_CONF) + @# Generate the html documentation doxygen $(DOXYGEN_CONF) - rm -f CodeDocumentation.html - ln -s CodeDocumentation/html/index.html CodeDocumentation.html - ( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ) | doxygen - - @echo "Warnings excuding undocumented:" + @rm -f CodeDocumentation.html + @ln -s CodeDocumentation/html/index.html CodeDocumentation.html + @cat warnings.log + + @# Generate the log of undocumented methods + @( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null + + @# Display info about the warnings + @echo "Warnings excluding undocumented:" @wc -l < warnings.log @echo "All warnings:" @wc -l < undoc.log @@ -30,6 +36,6 @@ clean: rm -rf undoc.log warnings.log $(DOXYGEN_CONF): $(MFEM_DIR)/doc/$(DOXYGEN_CONF).in - sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \ + @sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \ > $(DOXYGEN_CONF) From ba5904e66aebb5132fff983393448815e32416a2 Mon Sep 17 00:00:00 2001 From: "Robert W. Anderson" Date: Tue, 21 May 2019 12:38:26 -0700 Subject: [PATCH 029/535] automatically build dof_to arrays in functions where they are needed --- fem/gridfunc.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 23eda38ccd..9bff5aa8cd 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1602,6 +1602,8 @@ void GridFunction::ProjectCoefficient( ElementTransformation *T = NULL; const FiniteElement *fe = NULL; + fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized. + for (int i = 0; i < dofs.Size(); i++) { int dof = dofs[i], j = fes->GetElementForDof(dof); @@ -1643,6 +1645,8 @@ void GridFunction::ProjectCoefficient( Vector val; + fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized. + for (int i = 0; i < dofs.Size(); i++) { int dof = dofs[i], j = fes->GetElementForDof(dof); From bb468f8e8a801a7820a6e82d09f4427fe66ce2b1 Mon Sep 17 00:00:00 2001 From: "Robert W. Anderson" Date: Tue, 21 May 2019 12:49:44 -0700 Subject: [PATCH 030/535] remove comment about calling preqreq function - moved into body of fns --- fem/gridfunc.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index f769d95894..f8698b0b09 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -218,12 +218,10 @@ public: virtual void ProjectCoefficient(Coefficient &coeff); - // call fes -> BuildDofToArrays() before using this projection void ProjectCoefficient(Coefficient &coeff, Array &dofs, int vd = 0); void ProjectCoefficient(VectorCoefficient &vcoeff); - // call fes -> BuildDofToArrays() before using this projection void ProjectCoefficient(VectorCoefficient &vcoeff, Array &dofs); void ProjectCoefficient(Coefficient *coeff[]); From b57c90e4bb7ee171472a1c2b7b9684cb6b55db3b Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Tue, 21 May 2019 14:19:35 -0700 Subject: [PATCH 031/535] Fixed some documentation errors in coefficient. --- fem/coefficient.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 782946c807..3abf350a2d 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -404,7 +404,7 @@ public: : VectorCoefficient(v.Size()), vec(v) { } using VectorCoefficient::Eval; - /// Evaluate the vector coefficient at @ip. + /// Evaluate the vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { V = vec; } }; @@ -674,7 +674,7 @@ public: : VectorCoefficient(vc.GetVDim()) { c = &vc; attr.Copy(active_attr); } - /// Evaluate the vector coefficient at @ip. + /// Evaluate the vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -737,7 +737,7 @@ public: MatrixConstantCoefficient(const DenseMatrix &m) : MatrixCoefficient(m.Height(), m.Width()), mat(m) { } using MatrixCoefficient::Eval; - /// Evaluate the matrix coefficient at @ip. + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip) { M = mat; } }; @@ -786,7 +786,7 @@ public: mat.SetSize(0); } - /// Evaluate the matrix coefficient at @ip. + /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip); From eb9abd9cf6940002151c0c6d207c38bc18968f9e Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Mon, 10 Jun 2019 11:05:43 -0700 Subject: [PATCH 032/535] Added a little bit of doxygen for all the element types and some minor documentation fixes elsewhere. --- doc/makefile | 2 + fem/estimators.hpp | 10 ++ fem/fe.cpp | 4 +- fem/fe.hpp | 388 ++++++++++++++++++++++++++++++++++++--------- fem/gridfunc.hpp | 6 +- 5 files changed, 327 insertions(+), 83 deletions(-) diff --git a/doc/makefile b/doc/makefile index df21406624..dac76d135d 100644 --- a/doc/makefile +++ b/doc/makefile @@ -9,6 +9,7 @@ # terms of the GNU Lesser General Public License (as published by the Free # Software Foundation) version 2.1 dated February 1999. +SHELL = /bin/bash MFEM_DIR ?= .. DOXYGEN_CONF = CodeDocumentation.conf @@ -25,6 +26,7 @@ html: $(DOXYGEN_CONF) @( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null @# Display info about the warnings + @pwd @echo "Warnings excluding undocumented:" @wc -l < warnings.log @echo "All warnings:" diff --git a/fem/estimators.hpp b/fem/estimators.hpp index 02b29aa090..9d24098e64 100644 --- a/fem/estimators.hpp +++ b/fem/estimators.hpp @@ -45,6 +45,7 @@ public: /// Force recomputation of the estimates on the next call to GetLocalErrors. virtual void Reset() = 0; + /// Destruct the error estimator virtual ~ErrorEstimator() { } }; @@ -66,6 +67,14 @@ public: /** @brief The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu error estimation procedure. + Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery + and a posteriori error estimates. Part 1: The recovery technique. + Int. J. Num. Meth. Engng. 33, 1331-1364 (1992). + + Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery + and a posteriori error estimates. Part 2: Error estimates and adaptivity. + Int. J. Num. Meth. Engng. 33, 1365-1382 (1992). + The required BilinearFormIntegrator must implement the methods ComputeElementFlux() and ComputeFluxEnergy(). */ @@ -210,6 +219,7 @@ protected: class when needed.*/ bool own_flux_fes; ///< Ownership flag for flux_space and smooth_flux_space. + /// Initilize with the integrator, solution, and flux finite element spaces. void Init(BilinearFormIntegrator &integ, ParGridFunction &sol, ParFiniteElementSpace *flux_fes, diff --git a/fem/fe.cpp b/fem/fe.cpp index f9f7ebbd4d..19df883fa7 100644 --- a/fem/fe.cpp +++ b/fem/fe.cpp @@ -249,7 +249,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation( IntegrationPoint f_ip; const int fs = fine_fe.GetDof(), cs = this->GetDof(); - I.SetSize(fs, cs); + I.SetSize(fs, cs ); Vector fine_shape(fs), coarse_shape(cs); DenseMatrix fine_mass(fs), fine_coarse_mass(fs, cs); // initialized with 0 const int ir_order = GetOrder() + fine_fe.GetOrder(); @@ -2705,7 +2705,7 @@ void TriLinear3DFiniteElement::CalcDShape(const IntegrationPoint &ip, P0SegmentFiniteElement::P0SegmentFiniteElement(int Ord) - : NodalFiniteElement(1, Geometry::SEGMENT, 1, Ord) // defaul Ord = 0 + : NodalFiniteElement(1, Geometry::SEGMENT, 1, Ord) // default Ord = 0 { Nodes.IntPoint(0).x = 0.5; } diff --git a/fem/fe.hpp b/fem/fe.hpp index 86b367df73..70518f8b2d 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -118,7 +118,7 @@ public: // Base and derived classes for finite elements -/// Describes the space on each element +/// Describes the function space on each element class FunctionSpace { public: @@ -155,7 +155,7 @@ protected: public: /// Enumeration for RangeType and DerivRangeType - enum { SCALAR, VECTOR }; + enum RangeT { SCALAR, VECTOR }; /** @brief Enumeration for MapType: defines how reference functions are mapped to physical space. @@ -177,7 +177,8 @@ public: \ det(J^t*J)^{1/2}, for general J, is the transformation weight factor. */ - enum { VALUE, ///< For scalar fields; preserves point values + enum MapT { + VALUE, ///< For scalar fields; preserves point values INTEGRAL, ///< For scalar fields; preserves volume integrals H_DIV, /**< For vector fields; preserves surface integrals of the normal component */ @@ -188,17 +189,18 @@ public: /** @brief Enumeration for DerivType: defines which derivative method is implemented. - Each FiniteElement class implements only one type of derivative. The + Each FiniteElement class implements up to one type of derivative. The value returned by GetDerivType() indicates which derivative method is implemented. */ - enum { NONE, ///< No derivatives implemented + enum DerivT { + NONE, ///< No derivatives implemented GRAD, ///< Implements CalcDShape methods DIV, ///< Implements CalcDivShape methods CURL ///< Implements CalcCurlShape methods }; - /** Construct FiniteElement with given + /** @brief Construct FiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @param Do Number of degrees of freedom in the FiniteElement @@ -228,17 +230,30 @@ public: /// Returns an array containing the anisotropic orders/degrees. const int *GetAnisotropicOrders() const { return Orders; } - /// Returns the type of space on each element + /// Returns the type of FunctionSpace on the element. int Space() const { return FuncSpace; } + /// Returns the FiniteElement::RangeT of the element, one of {SCALAR, VECTOR}. int GetRangeType() const { return RangeType; } + /** @brief Returns the FiniteElement::RangeT of the element derivative, either + SCALAR or VECTOR. */ int GetDerivRangeType() const { return DerivRangeType; } + /** @brief Returns the FiniteElement::MapT of the element describing how reference + functions are mapped to physical space, one of {VALUE, INTEGRAL + H_DIV, H_CURL}. */ int GetMapType() const { return MapType; } + + /** @brief Returns the FiniteElement::MapT of the element describing how reference + functions are mapped to physical space, one of {VALUE, INTEGRAL + H_DIV, H_CURL}. */ int GetDerivType() const { return DerivType; } + /** @brief Returns the FiniteElement::MapT of the element describing how reference + function derivatives are mapped to physical space, one of {VALUE, + INTEGRAL, H_DIV, H_CURL}. */ int GetDerivMapType() const { return DerivMapType; } /** @brief Evaluate the values of all shape functions of a scalar finite @@ -268,6 +283,7 @@ public: by @a Trans. */ void CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const; + /// Get a const reference to the nodes of the element const IntegrationRule & GetNodes() const { return Nodes; } // virtual functions for finite elements on vector spaces @@ -324,6 +340,10 @@ public: void CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape) const; + /** @brief Get the dofs associated with the given @a face. + @a *dofs is set to an internal array of the local dofc on the + face, while *ndofs is set to the number of dofs on that face. + */ virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const; /** each row of h contains the upper triangular part of the hessian @@ -362,63 +382,66 @@ public: allowing the "coarse" FiniteElement to be different from the "fine" FiniteElement as when h-refinement is combined with p-refinement or p-derefinement. It is assumed that both finite elements use the same - MapType. */ + FiniteElement::MapT. */ virtual void GetTransferMatrix(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const; - /** Given a coefficient and a transformation, compute its projection + /** @brief Given a coefficient and a transformation, compute its projection (approximation) in the local finite dimensional space in terms of the degrees of freedom. */ virtual void Project (Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const; - /** Given a vector coefficient and a transformation, compute its + /** @brief Given a vector coefficient and a transformation, compute its projection (approximation) in the local finite dimensional space in terms of the degrees of freedom. (VectorFiniteElements) */ virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; - /** Given a matrix coefficient and a transformation, compute an approximation + /** @brief Given a matrix coefficient and a transformation, compute an approximation ("projection") in the local finite dimensional space in terms of the degrees of freedom. For VectorFiniteElements, the rows of the coefficient are projected in the vector space. */ virtual void ProjectMatrixCoefficient( MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const; - /** Compute a representation (up to multiplicative constant) for - the delta function at the vertex with the given index. */ + /** @brief Project a delta function centered on the given @a vertex in + the local finite dimensional space represented by the @a dofs. */ virtual void ProjectDelta(int vertex, Vector &dofs) const; - /** Compute the embedding/projection matrix from the given FiniteElement + /** @brief Compute the embedding/projection matrix from the given FiniteElement onto 'this' FiniteElement. The ElementTransformation is included to support cases when the projection depends on it. */ virtual void Project(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const; - /** Compute the discrete gradient matrix from the given FiniteElement onto + /** @brief Compute the discrete gradient matrix from the given FiniteElement onto 'this' FiniteElement. The ElementTransformation is included to support cases when the matrix depends on it. */ virtual void ProjectGrad(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const; - /** Compute the discrete curl matrix from the given FiniteElement onto + /** @brief Compute the discrete curl matrix from the given FiniteElement onto 'this' FiniteElement. The ElementTransformation is included to support cases when the matrix depends on it. */ virtual void ProjectCurl(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const; - /** Compute the discrete divergence matrix from the given FiniteElement onto + /** @brief Compute the discrete divergence matrix from the given FiniteElement onto 'this' FiniteElement. The ElementTransformation is included to support cases when the matrix depends on it. */ virtual void ProjectDiv(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const; + /// Deconstruct the FiniteElement virtual ~FiniteElement () { } + /** @brief Return true if the BasisType of @a b_type is closed + (has Quadrature1D points on the boundary). */ static bool IsClosedType(int b_type) { const int q_type = BasisType::GetQuadrature1D(b_type); @@ -426,6 +449,8 @@ public: (Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid)); } + /** @brief Return true if the BasisType of @a b_type is open + (doesn't have Quadrature1D points on the boundary). */ static bool IsOpenType(int b_type) { const int q_type = BasisType::GetQuadrature1D(b_type); @@ -433,17 +458,25 @@ public: (Quadrature1D::CheckOpen(q_type) != Quadrature1D::Invalid)); } + /** @brief Ensure that the BasisType of @a b_type is closed + (has Quadrature1D points on the boundary). */ static int VerifyClosed(int b_type) { MFEM_VERIFY(IsClosedType(b_type), "invalid closed basis type: " << b_type); return b_type; } + + /** @brief Ensure that the BasisType of @a b_type is open + (doesn't have Quadrature1D points on the boundary). */ static int VerifyOpen(int b_type) { MFEM_VERIFY(IsOpenType(b_type), "invalid open basis type: " << b_type); return b_type; } + + /** @brief Ensure that the BasisType of @a b_type nodal + (satisfies the interpolation property). */ static int VerifyNodal(int b_type) { return BasisType::CheckNodal(b_type); @@ -465,6 +498,13 @@ protected: } public: + /** @brief Construct FiniteElement with given + @param D Reference space dimension + @param G Geometry type (of type Geometry::Type) + @param Do Number of degrees of freedom in the FiniteElement + @param O Order/degree of the FiniteElement + @param F FunctionSpace type of the FiniteElement + */ ScalarFiniteElement(int D, Geometry::Type G, int Do, int O, int F = FunctionSpace::Pk) #ifdef MFEM_THREAD_SAFE @@ -475,6 +515,8 @@ public: { DerivType = GRAD; DerivRangeType = VECTOR; DerivMapType = H_CURL; } #endif + /** @brief Set the FiniteElement::MapT of the element to either VALUE or INTEGRAL. + Also sets the FiniteElement::DerivT to GRAD if the FiniteElement::MapT is VALUE. */ void SetMapType(int M) { MFEM_VERIFY(M == VALUE || M == INTEGRAL, "unknown MapType"); @@ -482,12 +524,15 @@ public: DerivType = (M == VALUE) ? GRAD : NONE; } - /// Nodal interpolation. + + /** @brief Get the matrix @a I that defines nodal interpolation + @a between this element and the refined element @a fine_fe. */ void NodalLocalInterpolation(ElementTransformation &Trans, DenseMatrix &I, const ScalarFiniteElement &fine_fe) const; - /// "Interpolation" defined through local L2-projection. + /** @brief Get matrix @a I "Interpolation" defined through local + L2-projection in the space defined by the @a fine_fe. */ /** If the "fine" elements cannot represent all basis functions of the "coarse" element, then boundary values from different sub-elements are generally different. */ @@ -504,6 +549,13 @@ protected: DenseMatrix &curl) const; public: + /** @brief Construct FiniteElement with given + @param D Reference space dimension + @param G Geometry type (of type Geometry::Type) + @param Do Number of degrees of freedom in the FiniteElement + @param O Order/degree of the FiniteElement + @param F FunctionSpace type of the FiniteElement + */ NodalFiniteElement(int D, Geometry::Type G, int Do, int O, int F = FunctionSpace::Pk) : ScalarFiniteElement(D, G, Do, O, F) { } @@ -546,6 +598,13 @@ public: class PositiveFiniteElement : public ScalarFiniteElement { public: + /** @brief Construct FiniteElement with given + @param D Reference space dimension + @param G Geometry type (of type Geometry::Type) + @param Do Number of degrees of freedom in the FiniteElement + @param O Order/degree of the FiniteElement + @param F FunctionSpace type of the FiniteElement + */ PositiveFiniteElement(int D, Geometry::Type G, int Do, int O, int F = FunctionSpace::Pk) : ScalarFiniteElement(D, G, Do, O, F) @@ -631,7 +690,7 @@ protected: VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; - // project the rows of the matrix coefficient in an ND space + /// project the rows of the matrix coefficient in an ND space void ProjectMatrixCoefficient_ND( const double *tk, const Array &d2t, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const; @@ -681,9 +740,11 @@ public: #endif }; +/// A 0D point finite element class PointFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement PointFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -692,11 +753,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for linear FE on interval +/// A 1D linear element with nodes on the endpoints class Linear1DFiniteElement : public NodalFiniteElement { public: - /// Construct a linear FE on interval + /// Construct the FiniteElement Linear1DFiniteElement(); /** virtual function which evaluates the values of all @@ -712,11 +773,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for linear FE on triangle +/// A 2D linear element on triangle with nodes at the vertices of the triangle class Linear2DFiniteElement : public NodalFiniteElement { public: - /// Construct a linear FE on triangle + /// Construct the FiniteElement Linear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -734,11 +795,11 @@ public: { dofs = 0.0; dofs(vertex) = 1.0; } }; -/// Class for bilinear FE on quadrilateral +/// A 2D bi-linear element on a square with nodes at the vertices of the square class BiLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct a bilinear FE on quadrilateral + /// Construct the FiniteElement BiLinear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -758,10 +819,11 @@ public: { dofs = 0.0; dofs(vertex) = 1.0; } // { dofs = 1.0; } }; -/// Class for linear FE on triangle with nodes at the 3 "Gaussian" points +/// A linear element on a triangle with nodes at the 3 "Gaussian" points class GaussLinear2DFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement GaussLinear2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -769,13 +831,14 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; -/// Class for bilinear FE on quad with nodes at the 4 Gaussian points +/// A 2D bi-linear element on a square with nodes at the "Gaussian" points class GaussBiLinear2DFiniteElement : public NodalFiniteElement { private: static const double p[2]; public: + /// Construct the FiniteElement GaussBiLinear2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -783,9 +846,12 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; +/** @brief A degenerate 2D linear element on a square with nodes at the + vertices of the lower left triangle */ class P1OnQuadFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P1OnQuadFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -794,11 +860,11 @@ public: { dofs = 1.0; } }; -/// Class for quadratic FE on interval +/// A 1D quadractic finite element with uniformly spaced nodes class Quad1DFiniteElement : public NodalFiniteElement { public: - /// Construct a quadratic FE on interval + /// Construct the FiniteElement Quad1DFiniteElement(); /** virtual function which evaluates the values of all @@ -814,20 +880,23 @@ public: DenseMatrix &dshape) const; }; +/// A 1D quadratic positive element utilizing the 2nd order Bernstein basis class QuadPos1DFiniteElement : public PositiveFiniteElement { public: + /// Construct the FiniteElement QuadPos1DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; -/// Class for quadratic FE on triangle +/** @brief A 2D quadratic element on triangle with nodes at the + vertices and midpoints of the triangle. */ class Quad2DFiniteElement : public NodalFiniteElement { public: - /// Construct a quadratic FE on triangle + /// Construct the FiniteElement Quad2DFiniteElement(); /** virtual function which evaluates the values of all @@ -847,7 +916,7 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; -/// Class for quadratic FE on triangle with nodes at the "Gaussian" points +/// A quadratic element on triangle with nodes at the "Gaussian" points class GaussQuad2DFiniteElement : public NodalFiniteElement { private: @@ -856,6 +925,7 @@ private: mutable DenseMatrix D; mutable Vector pol; public: + /// Construct the FiniteElement GaussQuad2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -863,11 +933,11 @@ public: // virtual void ProjectDelta(int vertex, Vector &dofs) const; }; -/// Class for bi-quadratic FE on quadrilateral +/// A 2D bi-quadratic element on a square with uniformly spaced nodes class BiQuad2DFiniteElement : public NodalFiniteElement { public: - /// Construct a biquadratic FE on quadrilateral + /// Construct the FiniteElement BiQuad2DFiniteElement(); /** virtual function which evaluates the values of all @@ -884,9 +954,12 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; + +/// A 2D positive bi-quadratic element on a square utilizing the 2nd order Bernstein basis class BiQuadPos2DFiniteElement : public PositiveFiniteElement { public: + /// Construct the FiniteElement BiQuadPos2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -902,10 +975,11 @@ public: { dofs = 0.; dofs(vertex) = 1.; } }; -/// Bi-quadratic element on quad with nodes at the 9 Gaussian points +/// A 2D bi-quadratic element on a square with nodes at the 9 "Gaussian" points class GaussBiQuad2DFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement GaussBiQuad2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -913,20 +987,27 @@ public: // virtual void ProjectDelta(int vertex, Vector &dofs) const { dofs = 1.; } }; + +/// A 2D bi-cubic element on a square with uniformly spaces nodes class BiCubic2DFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement BiCubic2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; + + /// Compute the Hessian of second order partial derivatives at @a ip. virtual void CalcHessian (const IntegrationPoint &ip, DenseMatrix &h) const; }; +/// A 1D cubic element with uniformly spaced nodes class Cubic1DFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement Cubic1DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -935,9 +1016,11 @@ public: DenseMatrix &dshape) const; }; +/// A 2D cubic element on a triangle with uniformly spaced nodes class Cubic2DFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement Cubic2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -949,11 +1032,11 @@ public: DenseMatrix &h) const; }; -/// Class for cubic FE on tetrahedron +/// A 3D cubic element on a tetrahedron with 20 nodes at the thirds of the tetrahedron class Cubic3DFiniteElement : public NodalFiniteElement { public: - /// Construct a cubic FE on tetrahedron + /// Construct the FiniteElement Cubic3DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -962,11 +1045,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for constant FE on triangle +/// A 2D constant element on a triangle class P0TriangleFiniteElement : public NodalFiniteElement { public: - /// Construct P0 triangle finite element + /// Construct the FiniteElement P0TriangleFiniteElement(); /// evaluate shape function - constant 1 @@ -980,9 +1063,11 @@ public: }; +/// A 2D constant element on a square class P0QuadFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P0QuadFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -992,19 +1077,20 @@ public: }; -/// Class for linear FE on tetrahedron +/** @brief A 3D linear element on a tetrahedron with nodes at the + vertices of the tetrahedron */ class Linear3DFiniteElement : public NodalFiniteElement { public: - /// Construct a linear FE on tetrahedron + /// Construct the FiniteElement Linear3DFiniteElement(); - /** virtual function which evaluates the values of all + /** @brief virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (4) */ virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; - /** virtual function which evaluates the values of all + /** @brief virtual function which evaluates the values of all partial derivatives of all shape functions at a given point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3) so that each row contains the derivatives of one shape function */ @@ -1014,14 +1100,18 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const { dofs = 0.0; dofs(vertex) = 1.0; } + /** @brief Get the dofs associated with the given @a face. + @a *dofs is set to an internal array of the local dofc on the + face, while *ndofs is set to the number of dofs on that face. + */ virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const; }; -/// Class for quadratic FE on tetrahedron +/// A 3D quadratic element on a tetrahedron with uniformly spaced nodes class Quadratic3DFiniteElement : public NodalFiniteElement { public: - /// Construct a quadratic FE on tetrahedron + /// Construct the FiniteElement Quadratic3DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1030,11 +1120,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for tri-linear FE on cube +/// A 3D tri-linear element on a cube with nodes at the vertices of the cube class TriLinear3DFiniteElement : public NodalFiniteElement { public: - /// Construct a tri-linear FE on cube + /// Construct the FiniteElement TriLinear3DFiniteElement(); /** virtual function which evaluates the values of all @@ -1054,10 +1144,11 @@ public: }; -/// Crouzeix-Raviart finite element on triangle +/// A 2D Crouzeix-Raviart element on triangle class CrouzeixRaviartFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement CrouzeixRaviartFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1066,10 +1157,11 @@ public: { dofs = 1.0; } }; -/// Crouzeix-Raviart finite element on quadrilateral +/// A 2D Crouzeix-Raviart finite element on square class CrouzeixRaviartQuadFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement CrouzeixRaviartQuadFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1079,18 +1171,21 @@ public: class P0SegmentFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement with dummy order @a Ord P0SegmentFiniteElement(int Ord = 0); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; +/** @brief A 2D 0-order Raviart-Thomas vector element on a triangle */ class RT0TriangleFiniteElement : public VectorFiniteElement { private: static const double nk[3][2]; public: + /// Construct the FiniteElement RT0TriangleFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1112,12 +1207,14 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; +/** @brief A 2D 0-order Raviart-Thomas vector element on a square*/ class RT0QuadFiniteElement : public VectorFiniteElement { private: static const double nk[4][2]; public: + /// Construct the FiniteElement RT0QuadFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1139,12 +1236,14 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; +/** @brief A 2D 1-order Raviart-Thomas vector element on a triangle */ class RT1TriangleFiniteElement : public VectorFiniteElement { private: static const double nk[8][2]; public: + /// Construct the FiniteElement RT1TriangleFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1166,12 +1265,14 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; +/** @brief A 2D 1-order Raviart-Thomas vector element on a square */ class RT1QuadFiniteElement : public VectorFiniteElement { private: static const double nk[12][2]; public: + /// Construct the FiniteElement RT1QuadFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1193,11 +1294,13 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; +/** @brief A 2D 2-order Raviart-Thomas vector element on a triangle */ class RT2TriangleFiniteElement : public VectorFiniteElement { private: static const double M[15][15]; public: + /// Construct the FiniteElement RT2TriangleFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1211,6 +1314,7 @@ public: Vector &divshape) const; }; +/** @brief A 2D 2-order Raviart-Thomas vector element on a square */ class RT2QuadFiniteElement : public VectorFiniteElement { private: @@ -1219,6 +1323,7 @@ private: static const double dpt[3]; public: + /// Construct the FiniteElement RT2QuadFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1240,26 +1345,29 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/// Linear 1D element with nodes 1/3 and 2/3 (trace of RT1) +/// A 1D linear element with nodes at 1/3 and 2/3 (trace of RT1) class P1SegmentFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P1SegmentFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; -/// Quadratic 1D element with nodes the Gaussian points in [0,1] (trace of RT2) +/// A 1D quadratic element with nodes at the Gaussian points (trace of RT2) class P2SegmentFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P2SegmentFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; +/// A 1D element with uniform nodes class Lagrange1DFiniteElement : public NodalFiniteElement { private: @@ -1268,24 +1376,29 @@ private: mutable Vector rxxk; #endif public: + /// Construct the FiniteElement with the provided @a degree Lagrange1DFiniteElement (int degree); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; + class P1TetNonConfFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P1TetNonConfFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; +/// A 3D constant element on a tetrahedron class P0TetFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P0TetFiniteElement (); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1294,9 +1407,11 @@ public: { dofs(0) = 1.0; } }; +/// A 3D constant element on a cube class P0HexFiniteElement : public NodalFiniteElement { public: + /// Construct the FiniteElement P0HexFiniteElement (); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1305,7 +1420,8 @@ public: { dofs(0) = 1.0; } }; -/// Tensor products of 1D FEs (only degree 2 is functional) +/** @brief Tensor products of 1D Lagrange1DFiniteElement + (only degree 2 is functional) */ class LagrangeHexFiniteElement : public NodalFiniteElement { private: @@ -1318,6 +1434,7 @@ private: #endif public: + /// Construct the FiniteElement with the provided @a degree LagrangeHexFiniteElement (int degree); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1326,11 +1443,11 @@ public: }; -/// Class for refined linear FE on interval +/// A 1D refined linear element class RefinedLinear1DFiniteElement : public NodalFiniteElement { public: - /// Construct a quadratic FE on interval + /// Construct the FiniteElement RefinedLinear1DFiniteElement(); /** virtual function which evaluates the values of all @@ -1346,11 +1463,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for refined linear FE on triangle +/// A 2D refined linear element on a triangle class RefinedLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct a quadratic FE on triangle + /// Construct the FiniteElement RefinedLinear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -1366,11 +1483,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for refined linear FE on tetrahedron +/// A 2D refined linear element on a tetrahedron class RefinedLinear3DFiniteElement : public NodalFiniteElement { public: - /// Construct a quadratic FE on tetrahedron + /// Construct the FiniteElement RefinedLinear3DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1379,11 +1496,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for refined bi-linear FE on quadrilateral +/// A 2D refined bi-linear FE on a square class RefinedBiLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct a biquadratic FE on quadrilateral + /// Construct the FiniteElement RefinedBiLinear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -1399,11 +1516,11 @@ public: DenseMatrix &dshape) const; }; -/// Class for refined trilinear FE on a hexahedron +/// A 3D refined tri-linear element on a cube class RefinedTriLinear3DFiniteElement : public NodalFiniteElement { public: - /// Construct a biquadratic FE on quadrilateral + /// Construct the FiniteElement RefinedTriLinear3DFiniteElement(); /** virtual function which evaluates the values of all @@ -1420,12 +1537,14 @@ public: }; +/// A 3D 1st order Nedelec element on a cube class Nedelec1HexFiniteElement : public VectorFiniteElement { private: static const double tk[12][3]; public: + /// Construct the FiniteElement Nedelec1HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1442,12 +1561,14 @@ public: }; +/// A 3D 1st order Nedelec element on a tetrahedron class Nedelec1TetFiniteElement : public VectorFiniteElement { private: static const double tk[6][3]; public: + /// Construct the FiniteElement Nedelec1TetFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1464,12 +1585,14 @@ public: }; +/// A 3D 0th order Raviert-Thomas element on a cube class RT0HexFiniteElement : public VectorFiniteElement { private: static const double nk[6][3]; public: + /// Construct the FiniteElement RT0HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1492,12 +1615,14 @@ public: }; +/// A 3D 1st order Raviert-Thomas element on a cube class RT1HexFiniteElement : public VectorFiniteElement { private: static const double nk[36][3]; public: + /// Construct the FiniteElement RT1HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1520,12 +1645,14 @@ public: }; +/// A 3D 0th order Raviert-Thomas element on a tetrahedron class RT0TetFiniteElement : public VectorFiniteElement { private: static const double nk[4][3]; public: + /// Construct the FiniteElement RT0TetFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1558,6 +1685,7 @@ public: }; +/// Class for computing 1D special polynomials and their associated basis functions class Poly_1D { public: @@ -1622,9 +1750,13 @@ public: points. Returns NULL if the BasisType has no associated set of points. */ const double *GetPoints(const int p, const int btype); + + /// Get coordinates of an open (GaussLegendre) set of points if degree @a p const double *OpenPoints(const int p, const int btype = BasisType::GaussLegendre) { return GetPoints(p, btype); } + + /// Get coordinates of a closed (GaussLegendre) set of points if degree @a p const double *ClosedPoints(const int p, const int btype = BasisType::GaussLobatto) { return GetPoints(p, btype); } @@ -1639,8 +1771,8 @@ public: the requested basis type. */ Basis &GetBasis(const int p, const int btype); - // Evaluate the values of a hierarchical 1D basis at point x - // hierarchical = k-th basis function is degree k polynomial + /** @brief Evaluate the values of a hierarchical 1D basis at point x + hierarchical = k-th basis function is degree k polynomial */ static void CalcBasis(const int p, const double x, double *u) // { CalcMono(p, x, u); } // Bernstein basis is not hierarchical --> does not work for triangles @@ -1649,14 +1781,14 @@ public: // { CalcLegendre(p, x, u); } { CalcChebyshev(p, x, u); } - // Evaluate the values and derivatives of a hierarchical 1D basis at point x + /// Evaluate the values and derivatives of a hierarchical 1D basis at point @a x static void CalcBasis(const int p, const double x, double *u, double *d) // { CalcMono(p, x, u, d); } // { CalcBernstein(p, x, u, d); } // { CalcLegendre(p, x, u, d); } { CalcChebyshev(p, x, u, d); } - // Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x + /// Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x static void CalcBasis(const int p, const double x, double *u, double *d, double *dd) // { CalcMono(p, x, u, d); } @@ -1664,25 +1796,38 @@ public: // { CalcLegendre(p, x, u, d); } { CalcChebyshev(p, x, u, d, dd); } - // Evaluate a representation of a Delta function at point x + /// Evaluate a representation of a Delta function at point x static double CalcDelta(const int p, const double x) { return pow(x, (double) p); } + /** @brief Compute the points for the Chebyshev polynomials of order @a p + and place them in the already allocated @a x array. */ static void ChebyshevPoints(const int p, double *x); - /// Compute the terms in the expansion of the binomial (x + y)^p + /** @brief Compute the @a p terms in the expansion of the binomial (x + y)^p + and store them in the allready allocated @a u array. */ static void CalcBinomTerms(const int p, const double x, const double y, double *u); - /** Compute the terms in the expansion of the binomial (x + y)^p and their - derivatives with respect to x assuming that dy/dx = -1. */ + /** @brief Compute the terms in the expansion of the binomial (x + y)^p and + their derivatives with respect to x assuming that dy/dx = -1. Store the + results in the already allocated @a u and @a d arrays.*/ static void CalcBinomTerms(const int p, const double x, const double y, double *u, double *d); - /** Compute the derivatives (w.r.t. x) of the terms in the expansion of the - binomial (x + y)^p assuming that dy/dx = -1. */ + /** @brief Compute the derivatives (w.r.t. x) of the terms in the expansion + of the binomial (x + y)^p assuming that dy/dx = -1. Store the results + in the already allocated @a d array.*/ static void CalcDBinomTerms(const int p, const double x, const double y, double *d); + + /** @brief Compute the values of the Bernstein basis functions of order + @a p at coordinate @a x and store the results in the already allocated + @a u array. */ static void CalcBernstein(const int p, const double x, double *u) { CalcBinomTerms(p, x, 1. - x, u); } + + /** @brief Compute the values and derivatives of the Bernstein basis functions + of order @a p at coordinate @a x and store the results in the already allocated + @a u and @a d arrays. */ static void CalcBernstein(const int p, const double x, double *u, double *d) { CalcBinomTerms(p, x, 1. - x, u, d); } @@ -1691,6 +1836,8 @@ public: extern Poly_1D poly1d; + +/// An element defined as an ND tensor product of 1D elements on a segement, square, or cube class TensorBasisElement { protected: @@ -1760,6 +1907,7 @@ public: const DofMapType dmtype); }; +/// Arbitrary H1 elements in 1D class H1_SegmentElement : public NodalTensorFiniteElement { private: @@ -1768,6 +1916,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p and BasisType @a btype H1_SegmentElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1776,6 +1925,7 @@ public: }; +/// Arbitrary H1 elements in 2D on a square class H1_QuadrilateralElement : public NodalTensorFiniteElement { private: @@ -1784,6 +1934,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p and BasisType @a btype H1_QuadrilateralElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1793,6 +1944,7 @@ public: }; +/// Arbitrary H1 elements in 3D on a cube class H1_HexahedronElement : public NodalTensorFiniteElement { private: @@ -1801,6 +1953,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p and BasisType @a btype H1_HexahedronElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1808,6 +1961,7 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; +/// Arbitrary order H1 elements in 1D utilizing the Bernstein basis class H1Pos_SegmentElement : public PositiveTensorFiniteElement { private: @@ -1821,6 +1975,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p H1Pos_SegmentElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1829,6 +1984,7 @@ public: }; +/// Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a square class H1Pos_QuadrilateralElement : public PositiveTensorFiniteElement { private: @@ -1838,6 +1994,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p H1Pos_QuadrilateralElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1846,6 +2003,7 @@ public: }; +/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a cube class H1Pos_HexahedronElement : public PositiveTensorFiniteElement { private: @@ -1855,6 +2013,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p H1Pos_HexahedronElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1863,6 +2022,7 @@ public: }; +/// Arbitrary order H1 elements in 2D on a tiangle class H1_TriangleElement : public NodalFiniteElement { private: @@ -1874,6 +2034,7 @@ private: DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p and BasisType @a btype H1_TriangleElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1883,6 +2044,7 @@ public: }; +/// Arbitrary order H1 elements in 3D on a tetrahedron class H1_TetrahedronElement : public NodalFiniteElement { private: @@ -1895,6 +2057,7 @@ private: DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p and BasisType @a btype H1_TetrahedronElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1905,6 +2068,7 @@ public: }; +/// Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a triangle class H1Pos_TriangleElement : public PositiveFiniteElement { protected: @@ -1915,6 +2079,7 @@ protected: Array dof_map; public: + /// Construct the FiniteElement of order @a p H1Pos_TriangleElement(const int p); // The size of shape is (p+1)(p+2)/2 (dof). @@ -1931,6 +2096,7 @@ public: }; +/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a tetrahedron class H1Pos_TetrahedronElement : public PositiveFiniteElement { protected: @@ -1941,6 +2107,7 @@ protected: Array dof_map; public: + /// Construct the FiniteElement of order @a p H1Pos_TetrahedronElement(const int p); // The size of shape is (p+1)(p+2)(p+3)/6 (dof). @@ -1957,6 +2124,7 @@ public: }; +/// Arbitrary order H1 elements in 3D on a wedge class H1_WedgeElement : public NodalFiniteElement { private: @@ -1970,6 +2138,7 @@ private: H1_SegmentElement SegmentFE; public: + /// Construct the FiniteElement of order @a p and BasisType @a btype H1_WedgeElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2001,6 +2170,7 @@ public: BiCubic3DFiniteElement() : H1_WedgeElement(3) {} }; +/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a wedge class H1Pos_WedgeElement : public PositiveFiniteElement { protected: @@ -2014,6 +2184,7 @@ protected: H1Pos_SegmentElement SegmentFE; public: + /// Construct the FiniteElement of order @a p H1Pos_WedgeElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2022,6 +2193,7 @@ public: }; +/// Arbitrary L2 elements in 1D on a segment class L2_SegmentElement : public NodalTensorFiniteElement { private: @@ -2030,6 +2202,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p and BasisType @a btype L2_SegmentElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2037,7 +2210,7 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; - +/// Arbitrary order L2 elements in 1D utilizing the Bernstein basis on a segment class L2Pos_SegmentElement : public PositiveTensorFiniteElement { private: @@ -2046,6 +2219,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p L2Pos_SegmentElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2054,6 +2228,7 @@ public: }; +/// Arbitrary order L2 elements in 2D on a square class L2_QuadrilateralElement : public NodalTensorFiniteElement { private: @@ -2062,6 +2237,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p and BasisType @a btype L2_QuadrilateralElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2074,7 +2250,7 @@ public: { ProjectCurl_2D(fe, Trans, curl); } }; - +/// Arbitrary order L2 elements in 2D utilizing the Bernstein basis on a square class L2Pos_QuadrilateralElement : public PositiveTensorFiniteElement { private: @@ -2083,6 +2259,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p L2Pos_QuadrilateralElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2090,7 +2267,7 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; - +/// Arbitrary order L2 elements in 3D on a cube class L2_HexahedronElement : public NodalTensorFiniteElement { private: @@ -2099,6 +2276,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p and BasisType @a btype L2_HexahedronElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2108,6 +2286,7 @@ public: }; +/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a cube class L2Pos_HexahedronElement : public PositiveTensorFiniteElement { private: @@ -2116,6 +2295,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p L2Pos_HexahedronElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2124,6 +2304,7 @@ public: }; +/// Arbitrary order L2 elements in 2D on a triangle class L2_TriangleElement : public NodalFiniteElement { private: @@ -2134,6 +2315,7 @@ private: DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p and BasisType @a btype L2_TriangleElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2146,7 +2328,7 @@ public: { ProjectCurl_2D(fe, Trans, curl); } }; - +/// Arbitrary order L2 elements in 2D utilizing the Bernstein basis on a triangle class L2Pos_TriangleElement : public PositiveFiniteElement { private: @@ -2155,6 +2337,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p L2Pos_TriangleElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2163,6 +2346,7 @@ public: }; +/// Arbitrary order L2 elements in 3D on a tetrahedron class L2_TetrahedronElement : public NodalFiniteElement { private: @@ -2174,6 +2358,7 @@ private: DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p and BasisType @a btype L2_TetrahedronElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2183,6 +2368,7 @@ public: }; +/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a tetrahedron class L2Pos_TetrahedronElement : public PositiveFiniteElement { private: @@ -2191,6 +2377,7 @@ private: #endif public: + /// Construct the FiniteElement of order @a p L2Pos_TetrahedronElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2199,6 +2386,7 @@ public: }; +/// Arbitrary order L2 elements in 3D on a wedge class L2_WedgeElement : public NodalFiniteElement { private: @@ -2212,6 +2400,7 @@ private: L2_SegmentElement SegmentFE; public: + /// Construct the FiniteElement of order @a p and BasisType @a btype L2_WedgeElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2219,12 +2408,14 @@ public: DenseMatrix &dshape) const; }; +/// A 0th order L2 element on a Wedge class P0WedgeFiniteElement : public L2_WedgeElement { public: P0WedgeFiniteElement () : L2_WedgeElement(0) {} }; +/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a wedge class L2Pos_WedgeElement : public PositiveFiniteElement { protected: @@ -2238,6 +2429,7 @@ protected: L2Pos_SegmentElement SegmentFE; public: + /// Construct the FiniteElement of order @a p L2Pos_WedgeElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2245,7 +2437,7 @@ public: DenseMatrix &dshape) const; }; - +/// Arbitrary order Raviart-Thomas elements in 2D on a square class RT_QuadrilateralElement : public VectorFiniteElement { private: @@ -2259,6 +2451,8 @@ private: Array dof_map, dof2nk; public: + /** @brief Construct the FiniteElement of order @a p and closed and open + BasisType @a cb_type and @a ob_type */ RT_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2301,7 +2495,7 @@ public: { ProjectGrad_RT(nk, dof2nk, fe, Trans, curl); } }; - +/// Arbitrary order Raviart-Thomas elements in 3D on a cube class RT_HexahedronElement : public VectorFiniteElement { static const double nk[18]; @@ -2314,6 +2508,8 @@ class RT_HexahedronElement : public VectorFiniteElement Array dof_map, dof2nk; public: + /** @brief Construct the FiniteElement of order @a p and closed and open + BasisType @a cb_type and @a ob_type */ RT_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2352,6 +2548,7 @@ public: }; +/// Arbitrary order Raviart-Thomas elements in 2D on a triangle class RT_TriangleElement : public VectorFiniteElement { static const double nk[6], c; @@ -2366,6 +2563,7 @@ class RT_TriangleElement : public VectorFiniteElement DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p RT_TriangleElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2407,6 +2605,7 @@ public: }; +/// Arbitrary order Raviart-Thomas elements in 3D on a tetrahedron class RT_TetrahedronElement : public VectorFiniteElement { static const double nk[12], c; @@ -2421,6 +2620,7 @@ class RT_TetrahedronElement : public VectorFiniteElement DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p RT_TetrahedronElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2456,6 +2656,7 @@ public: }; +/// Arbitrary order Nedelec elements in 3D on a cube class ND_HexahedronElement : public VectorFiniteElement { static const double tk[18]; @@ -2468,6 +2669,8 @@ class ND_HexahedronElement : public VectorFiniteElement Array dof_map, dof2tk; public: + /** @brief Construct the FiniteElement of order @a p and closed and open + BasisType @a cb_type and @a ob_type */ ND_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2522,6 +2725,7 @@ public: }; +/// Arbitrary order Nedelec elements in 2D on a square class ND_QuadrilateralElement : public VectorFiniteElement { static const double tk[8]; @@ -2534,6 +2738,8 @@ class ND_QuadrilateralElement : public VectorFiniteElement Array dof_map, dof2tk; public: + /** @brief Construct the FiniteElement of order @a p and closed and open + BasisType @a cb_type and @a ob_type */ ND_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2572,6 +2778,7 @@ public: }; +/// Arbitrary order Nedelec elements in 3D on a tetrahedron class ND_TetrahedronElement : public VectorFiniteElement { static const double tk[18], c; @@ -2585,6 +2792,7 @@ class ND_TetrahedronElement : public VectorFiniteElement DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p ND_TetrahedronElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2625,6 +2833,7 @@ public: { ProjectCurl_ND(tk, dof2tk, fe, Trans, curl); } }; +/// Arbitrary order Nedelec elements in 2D on a triangle class ND_TriangleElement : public VectorFiniteElement { static const double tk[8], c; @@ -2639,6 +2848,7 @@ class ND_TriangleElement : public VectorFiniteElement DenseMatrixInverse Ti; public: + /// Construct the FiniteElement of order @a p ND_TriangleElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2675,6 +2885,7 @@ public: }; +/// Arbitrary order Nedelec elements in 1D on a segment class ND_SegmentElement : public VectorFiniteElement { static const double tk[1]; @@ -2683,6 +2894,8 @@ class ND_SegmentElement : public VectorFiniteElement Array dof2tk; public: + /** @brief Construct the FiniteElement of order @a p and open + BasisType @a ob_type */ ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const { obasis1d.Eval(ip.x, shape); } @@ -2721,6 +2934,7 @@ public: }; +/// An arbitrary order and dimension NURBS element class NURBSFiniteElement : public ScalarFiniteElement { protected: @@ -2730,6 +2944,13 @@ protected: mutable Vector weights; public: + /** @brief Construct FiniteElement with given + @param D Reference space dimension + @param G Geometry type (of type Geometry::Type) + @param Do Number of degrees of freedom in the FiniteElement + @param O Order/degree of the FiniteElement + @param F FunctionSpace type of the FiniteElement + */ NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F) : ScalarFiniteElement(D, G, Do, O, F) { @@ -2752,12 +2973,15 @@ public: virtual void SetOrder () const { } }; + +/// An arbitrary order 1D NURBS element on a segment class NURBS1DFiniteElement : public NURBSFiniteElement { protected: mutable Vector shape_x; public: + /// Construct the FiniteElement of order @a p NURBS1DFiniteElement(int p) : NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk), shape_x(p + 1) { } @@ -2768,18 +2992,21 @@ public: DenseMatrix &dshape) const; }; +/// An arbitrary order 2D NURBS element on a square class NURBS2DFiniteElement : public NURBSFiniteElement { protected: mutable Vector u, shape_x, shape_y, dshape_x, dshape_y; public: + /// Construct the FiniteElement of order @a p NURBS2DFiniteElement(int p) : NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p, FunctionSpace::Qk), u(Dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1), dshape_y(p + 1) { Orders[0] = Orders[1] = p; } + /// Construct the FiniteElement with x-order @a px and y-order @a py NURBS2DFiniteElement(int px, int py) : NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1), std::max(px, py), FunctionSpace::Qk), @@ -2793,12 +3020,14 @@ public: DenseMatrix &dshape) const; }; +/// An arbitrary order 3D NURBS element on a cube class NURBS3DFiniteElement : public NURBSFiniteElement { protected: mutable Vector u, shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z; public: + /// Construct the FiniteElement of order @a p NURBS3DFiniteElement(int p) : NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p, FunctionSpace::Qk), @@ -2806,6 +3035,7 @@ public: dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1) { Orders[0] = Orders[1] = Orders[2] = p; } + /// Construct the FiniteElement with x-order @a px and y-order @a py and z-order @a pz NURBS3DFiniteElement(int px, int py, int pz) : NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1), std::max(std::max(px,py),pz), FunctionSpace::Qk), diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index f769d95894..70b84e9008 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -469,11 +469,13 @@ public: /// Save the GridFunction to an output stream. virtual void Save(std::ostream &out) const; - /** Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be - called first. The parameter ref > 0 must match the one used in + /** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK must + be called first. The parameter ref > 0 must match the one used in Mesh::PrintVTK. */ void SaveVTK(std::ostream &out, const std::string &field_name, int ref); + /** @brief Write the GridFunction in STL format. Note that the mesh dimension + must be 2 and that quad elements will be broken into two triangles.*/ void SaveSTL(std::ostream &out, int TimesToRefine = 1); /// Destroys grid function. From f04242da6ee21264e9b9986902f3eacd4d9d9031 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Wed, 3 Jul 2019 14:03:09 -0700 Subject: [PATCH 033/535] Added some documentation for fe and fe_coll, inculding a nice table. --- doc/CodeDocumentation.conf.in | 2 +- fem/fe.hpp | 48 +++++++--------- fem/fe_coll.hpp | 104 +++++++++++++++++++++++++++------- 3 files changed, 107 insertions(+), 47 deletions(-) diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in index 28568a749b..66822f3d8e 100644 --- a/doc/CodeDocumentation.conf.in +++ b/doc/CodeDocumentation.conf.in @@ -1466,7 +1466,7 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = https://cdn.llnl.gov/mathjax/2.7.2 +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example diff --git a/fem/fe.hpp b/fem/fe.hpp index 70518f8b2d..f297d7949d 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -160,30 +160,24 @@ public: /** @brief Enumeration for MapType: defines how reference functions are mapped to physical space. - A reference function, `uh(xh)`, can be mapped to a function, `u(x)`, on a - general physical element in following ways: - - VALUE u(x) = uh(xh) - INTEGRAL u(x) = (1/w) * uh(xh) - H_DIV u(x) = (J/w) * uh(xh) - H_CURL u(x) = J^{-t} * uh(xh) (square J) - H_CURL u(x) = J*(J^t*J)^{-1} * uh(xh) (general J) - - where - - x = T(xh) is the image of the reference point xh ("x hat"), - J = J(xh) is the Jacobian matrix of the transformation T, and - w = w(xh) = / det(J), for square J, - \ det(J^t*J)^{1/2}, for general J, - is the transformation weight factor. + A reference function \f$ \hat u(\hat x) \f$ can be mapped to a function + \f$ u(x) \f$ on a general physical element in following where: + - \f$ x = T(\hat x) \f$ is the image of the reference point \f$ \hat x \f$ + - \f$ J = J(\hat x) \f$ is the Jacobian matrix of the transformation T + - \f$ w = w(\hat x) = det(J) \f$ is the transformation weight factor for square J + - \f$ w = w(\hat x) = det(J^t J)^{1/2} \f$ is the transformation weight factor in general */ enum MapT { - VALUE, ///< For scalar fields; preserves point values - INTEGRAL, ///< For scalar fields; preserves volume integrals + VALUE, /**< For scalar fields; preserves point values + \f$ u(x) = \hat u(\hat x) \f$ */ + INTEGRAL, /**< For scalar fields; preserves volume integrals + \f$ u(x) = (1/w) \hat u(\hat x) \f$ */ H_DIV, /**< For vector fields; preserves surface integrals of the - normal component */ + normal component \f$ u(x) = (J/w) \hat u(\hat x) \f$ */ H_CURL /**< For vector fields; preserves line integrals of the - tangential component */ + tangential component + \f$ u(x) = J^{-t} \hat u(\hat x) \f$ (square J), + \f$ u(x) = J(J^t J)^{-1} \hat u(\hat x) \f$ (general J) */ }; /** @brief Enumeration for DerivType: defines which derivative method @@ -846,7 +840,7 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; -/** @brief A degenerate 2D linear element on a square with nodes at the +/** @brief A 2D linear element on a square with 3 nodes at the vertices of the lower left triangle */ class P1OnQuadFiniteElement : public NodalFiniteElement { @@ -1178,7 +1172,7 @@ public: DenseMatrix &dshape) const; }; -/** @brief A 2D 0-order Raviart-Thomas vector element on a triangle */ +/** @brief A 2D 1st Raviart-Thomas vector element on a triangle */ class RT0TriangleFiniteElement : public VectorFiniteElement { private: @@ -1207,7 +1201,7 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 0-order Raviart-Thomas vector element on a square*/ +/** @brief A 2D 1st Raviart-Thomas vector element on a square*/ class RT0QuadFiniteElement : public VectorFiniteElement { private: @@ -1236,7 +1230,7 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 1-order Raviart-Thomas vector element on a triangle */ +/** @brief A 2D 2nd Raviart-Thomas vector element on a triangle */ class RT1TriangleFiniteElement : public VectorFiniteElement { private: @@ -1265,7 +1259,7 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 1-order Raviart-Thomas vector element on a square */ +/** @brief A 2D 2nd Raviart-Thomas vector element on a square */ class RT1QuadFiniteElement : public VectorFiniteElement { private: @@ -1294,7 +1288,7 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 2-order Raviart-Thomas vector element on a triangle */ +/** @brief A 2D 3rd Raviart-Thomas vector element on a triangle */ class RT2TriangleFiniteElement : public VectorFiniteElement { private: @@ -1314,7 +1308,7 @@ public: Vector &divshape) const; }; -/** @brief A 2D 2-order Raviart-Thomas vector element on a square */ +/** @brief A 2D 3rd Raviart-Thomas vector element on a square */ class RT2QuadFiniteElement : public VectorFiniteElement { private: diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index fb9e75d579..e2f197e27c 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -19,7 +19,7 @@ namespace mfem { -/** Collection of finite elements from the same family in multiple dimensions. +/** @brief Collection of finite elements from the same family in multiple dimensions. This class is used to match the degrees of freedom of a FiniteElementSpace between elements, and to provide the finite element restriction from an element to its boundary. */ @@ -66,6 +66,72 @@ public: /** @brief Factory method: return a newly allocated FiniteElementCollection according to the given name. */ + /** + | FEC Name | Space | Order | BasisType | FiniteElement::MapT | Notes | + | :------: | :---: | :---: | :-------: | :-----: | :---: | + | H1_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements | + | H1@[BTYPE]_[DIM]_[ORDER] | H1 | * | * | VALUE | H1 nodal elements | + | H1Pos_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements | + | H1Pos_Trace_[DIM]_[ORDER] | H^{1/2} | * | 2 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) | + | H1_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) | + | H1_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) | + | ND_[DIM]_[ORDER] | H(curl) | * | 1 / 0 | H_CURL | Nedelec vector elements | + | ND@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(curl) | * | * / * | H_CURL | Nedelec vector elements | + | ND_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) | + | ND_Trace@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) | + | RT_[DIM]_[ORDER] | H(div) | * | 1 / 0 | H_DIV | Raviart-Thomas vector elements | + | RT@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(div) | * | * / * | H_DIV | Raviart-Thomas vector elements | + | RT_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) | + | RT_ValTrace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) | + | RT_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) | + | RT_ValTrace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) | + | L2_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements | + | L2_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements | + | L2Int_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements | + | L2Int_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements | + | DG_Iface_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) | + | DG_Iface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) | + | DG_IntIface_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) | + | DG_IntIface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) | + | NURBS[ORDER] | - | * | - | VALUE | Non-Uniform Rational B-Splines (NURBS) elements | + | LinearNonConf3D | - | 1 | 1 | VALUE | Piecewise-linear nonconforming finite elements in 3D | + | CrouzeixRaviart | - | - | - | - | Crouzeix-Raviart nonconforming elements in 2D | + | Local_[FENAME] | - | - | - | - | Special collection that builds a local version out of the FENAME collection | + |-|-|-|-|-|-| + | Linear | H1 | 1 | 1 | VALUE | Left in for backward compatibility, consider using H1_ | + | Quadratic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ | + | QuadraticPos | H1 | 2 | 2 | VALUE | Left in for backward compatibility, consider using H1_ | + | Cubic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ | + | Const2D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | Const3D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | LinearDiscont2D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | GaussLinearDiscont2D | L2 | 1 | 0 | VALUE | Left in for backward compatibility, consider using L2_ | + | P1OnQuad | H1 | 1 | 1 | VALUE | Linear P1 element with 3 nodes on a square | + | QuadraticDiscont2D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | QuadraticPosDiscont2D | L2 | 2 | 2 | VALUE | Left in for backward compatibility, consider using L2_ | + | GaussQuadraticDiscont2D | L2 | 2 | 0 | VALUE | Left in for backward compatibility, consider using L2_ | + | CubicDiscont2D | L2 | 3 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | LinearDiscont3D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | QuadraticDiscont3D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | ND1_3D | H(Curl) | 1 | 1 / 0 | H_CURL | Left in for backward compatibility, consider using ND_ | + | RT0_2D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ | + | RT1_2D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ | + | RT2_2D | H(Div) | 3 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ | + | RT0_3D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ | + | RT1_3D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ | + + | Tag | Description | + | :------: | :--------: | + | [DIM] | Dimension of the elements (1D, 2D, 3D) | + | [ORDER] | Approximation order of the elements (P0, P1, P2, ...) | + | [BTYPE] | BasisType of the element (0-GaussLegendre, 1 - GaussLobatto, 2-Bernstein, 3-OpenUniform, 4-CloseUniform, 5-OpenHalfUniform) | + | [OBTYPE] | Open BasisType of the element for elements which have both types | + | [CBTYPE] | Closed BasisType of the element for elements which have both types | + + [FENAME] Is a special case for the Local FEC which generates a local version of a given + FEC. It is selected from one of (BiCubic2DFiniteElement, Quad_Q3, Nedelec1HexFiniteElement, + Hex_ND1, H1_[DIM]_[ORDER],H1Pos_[DIM]_[ORDER], L2_[DIM]_[ORDER] ) + */ static FiniteElementCollection *New(const char *name); /** @brief Get the local dofs for a given sub-manifold. @@ -111,7 +177,7 @@ public: virtual ~H1_FECollection(); }; -/** Arbitrary order H1-conforming (continuous) finite elements with positive +/** @brief Arbitrary order H1-conforming (continuous) finite elements with positive basis functions. */ class H1Pos_FECollection : public H1_FECollection { @@ -120,7 +186,7 @@ public: : H1_FECollection(p, dim, BasisType::Positive) { } }; -/** Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the +/** @brief Arbitrary order "H^{1/2}-conformring" trace finite elements defined on the interface between mesh elements (faces,edges,vertices); these are the trace FEs of the H1-conforming FEs. */ class H1_Trace_FECollection : public H1_FECollection @@ -214,7 +280,7 @@ public: virtual ~RT_FECollection(); }; -/** Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the +/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the interface between mesh elements (faces); these are the normal trace FEs of the H(div)-conforming FEs. */ class RT_Trace_FECollection : public RT_FECollection @@ -263,7 +329,7 @@ public: virtual ~ND_FECollection(); }; -/** Arbitrary order H(curl)-trace finite elements defined on the interface +/** @brief Arbitrary order H(curl)-trace finite elements defined on the interface between mesh elements (faces,edges); these are the tangential trace FEs of the H(curl)-conforming FEs. */ class ND_Trace_FECollection : public ND_FECollection @@ -328,7 +394,7 @@ public: }; -/// Piecewise-(bi)linear continuous finite elements. +/// Piecewise-(bi/tri)linear continuous finite elements. class LinearFECollection : public FiniteElementCollection { private: @@ -472,7 +538,7 @@ public: }; -/** First order Raviart-Thomas finite elements in 2D. This class is kept only +/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept only for backward compatibility, consider using RT_FECollection instead. */ class RT0_2DFECollection : public FiniteElementCollection { @@ -494,7 +560,7 @@ public: virtual const char * Name() const { return "RT0_2D"; } }; -/** Second order Raviart-Thomas finite elements in 2D. This class is kept only +/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept only for backward compatibility, consider using RT_FECollection instead. */ class RT1_2DFECollection : public FiniteElementCollection { @@ -516,7 +582,7 @@ public: virtual const char * Name() const { return "RT1_2D"; } }; -/** Third order Raviart-Thomas finite elements in 2D. This class is kept only +/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept only for backward compatibility, consider using RT_FECollection instead. */ class RT2_2DFECollection : public FiniteElementCollection { @@ -538,7 +604,7 @@ public: virtual const char * Name() const { return "RT2_2D"; } }; -/** Piecewise-constant discontinuous finite elements in 2D. This class is kept +/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class Const2DFECollection : public FiniteElementCollection { @@ -559,7 +625,7 @@ public: virtual const char * Name() const { return "Const2D"; } }; -/** Piecewise-linear discontinuous finite elements in 2D. This class is kept +/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class LinearDiscont2DFECollection : public FiniteElementCollection { @@ -618,7 +684,7 @@ public: virtual const char * Name() const { return "P1OnQuad"; } }; -/** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept +/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class QuadraticDiscont2DFECollection : public FiniteElementCollection { @@ -679,7 +745,7 @@ public: virtual const char * Name() const { return "GaussQuadraticDiscont2D"; } }; -/** Piecewise-cubic discontinuous finite elements in 2D. This class is kept +/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class CubicDiscont2DFECollection : public FiniteElementCollection { @@ -701,7 +767,7 @@ public: virtual const char * Name() const { return "CubicDiscont2D"; } }; -/** Piecewise-constant discontinuous finite elements in 3D. This class is kept +/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class Const3DFECollection : public FiniteElementCollection { @@ -724,7 +790,7 @@ public: virtual const char * Name() const { return "Const3D"; } }; -/** Piecewise-linear discontinuous finite elements in 3D. This class is kept +/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class LinearDiscont3DFECollection : public FiniteElementCollection { @@ -746,7 +812,7 @@ public: virtual const char * Name() const { return "LinearDiscont3D"; } }; -/** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept +/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class is kept only for backward compatibility, consider using L2_FECollection instead. */ class QuadraticDiscont3DFECollection : public FiniteElementCollection { @@ -793,7 +859,7 @@ public: virtual const char * Name() const { return "RefinedLinear"; } }; -/** Lowest order Nedelec finite elements in 3D. This class is kept only for +/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only for backward compatibility, consider using the new ND_FECollection instead. */ class ND1_3DFECollection : public FiniteElementCollection { @@ -815,7 +881,7 @@ public: virtual const char * Name() const { return "ND1_3D"; } }; -/** First order Raviart-Thomas finite elements in 3D. This class is kept only +/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept only for backward compatibility, consider using RT_FECollection instead. */ class RT0_3DFECollection : public FiniteElementCollection { @@ -838,7 +904,7 @@ public: virtual const char * Name() const { return "RT0_3D"; } }; -/** Second order Raviart-Thomas finite elements in 3D. This class is kept only +/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept only for backward compatibility, consider using RT_FECollection instead. */ class RT1_3DFECollection : public FiniteElementCollection { From eb216b91e30178eded1d3d51aa84fbcfe9e9acd0 Mon Sep 17 00:00:00 2001 From: "Andrew T. Barker" Date: Tue, 9 Jul 2019 16:02:40 -0700 Subject: [PATCH 034/535] A few updates to documentation. --- fem/bilininteg.hpp | 5 +++++ fem/fe.hpp | 2 ++ fem/fespace.hpp | 29 +++++++++++++++++------------ fem/pfespace.hpp | 2 +- linalg/matrix.hpp | 2 +- linalg/ode.hpp | 6 +++--- linalg/vector.hpp | 1 + 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/fem/bilininteg.hpp b/fem/bilininteg.hpp index 04b4cb8956..7131903084 100644 --- a/fem/bilininteg.hpp +++ b/fem/bilininteg.hpp @@ -167,6 +167,10 @@ public: virtual ~BilinearFormIntegrator() { } }; +/** Wraps a given @a BilinearFormIntegrator and transposes the resulting + element matrices. + + See for example ex9, ex9p. */ class TransposeIntegrator : public BilinearFormIntegrator { private: @@ -1766,6 +1770,7 @@ public: ElementTransformation &Trans); }; +/** Mass integrator (u, v) restricted to the boundary of a domain */ class BoundaryMassIntegrator : public MassIntegrator { public: diff --git a/fem/fe.hpp b/fem/fe.hpp index 96fe89617e..98120d70ff 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -732,6 +732,8 @@ public: DenseMatrix &I) const; }; +/** Abstract base clase for finite elements whose basis functions are + vector valued. */ class VectorFiniteElement : public FiniteElement { // Hide the scalar functions CalcShape and CalcDShape. diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 5924778ed0..c4023f4f6a 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -176,7 +176,7 @@ protected: virtual ~RefinementOperator(); }; - // Derefinement operator, used by the friend class InterpolationGridTransfer. + /// Derefinement operator, used by the friend class InterpolationGridTransfer. class DerefinementOperator : public Operator { const FiniteElementSpace *fine_fes; // Not owned. @@ -195,12 +195,12 @@ protected: virtual ~DerefinementOperator(); }; - // This method makes the same assumptions as the method: - // void GetLocalRefinementMatrices( - // const FiniteElementSpace &coarse_fes, Geometry::Type geom, - // DenseTensor &localP) const - // which is defined below. It also assumes that the coarse fes and this have - // the same vector dimension, vdim. + /** This method makes the same assumptions as the method: + void GetLocalRefinementMatrices( + const FiniteElementSpace &coarse_fes, Geometry::Type geom, + DenseTensor &localP) const + which is defined below. It also assumes that the coarse fes and this have + the same vector dimension, vdim. */ SparseMatrix *RefinementMatrix_main(const int coarse_ndofs, const Table &coarse_elem_dof, const DenseTensor localP[]) const; @@ -218,11 +218,13 @@ protected: /// Calculate GridFunction restriction matrix after mesh derefinement. SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof); - // This method assumes that this->mesh is a refinement of coarse_fes->mesh - // and that the CoarseFineTransformations of this->mesh are set accordingly. - // Another assumption is that the FEs of this use the same MapType as the FEs - // of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are - // NOT variable-order spaces. + /** @brief Return in @a localP the local refinement matrices that map + between fespaces after mesh refinement. */ + /** This method assumes that this->mesh is a refinement of coarse_fes->mesh + and that the CoarseFineTransformations of this->mesh are set accordingly. + Another assumption is that the FEs of this use the same MapType as the FEs + of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are + NOT variable-order spaces. */ void GetLocalRefinementMatrices(const FiniteElementSpace &coarse_fes, Geometry::Type geom, DenseTensor &localP) const; @@ -490,8 +492,10 @@ public: /// Returns pointer to the FiniteElement for the i'th boundary element. const FiniteElement *GetBE(int i) const; + /// Return pointer for an internal face between elements const FiniteElement *GetFaceElement(int i) const; + /// Returns pointer for edge in 3D or face in 2D const FiniteElement *GetEdgeElement(int i) const; /// Return the trace element from element 'i' to the given 'geom_type' @@ -613,6 +617,7 @@ public: /// Return update counter (see Mesh::sequence) long GetSequence() const { return sequence; } + /// Save finite element space to output stream @a out. void Save(std::ostream &out) const; /** @brief Read a FiniteElementSpace from a stream. The returned diff --git a/fem/pfespace.hpp b/fem/pfespace.hpp index a8297c21f1..d0db7c2a21 100644 --- a/fem/pfespace.hpp +++ b/fem/pfespace.hpp @@ -367,7 +367,7 @@ public: void PrintPartitionStats(); - // Obsolete, kept for backward compatibility + /// Obsolete, kept for backward compatibility int TrueVSize() const { return ltdof_size; } }; diff --git a/linalg/matrix.hpp b/linalg/matrix.hpp index f547c910d7..18780712d1 100644 --- a/linalg/matrix.hpp +++ b/linalg/matrix.hpp @@ -28,7 +28,7 @@ class Matrix : public Operator { friend class MatrixInverse; public: - //// Defines matrix diagonal policy upon elimination of rows and/or columns. + /// Defines matrix diagonal policy upon elimination of rows and/or columns. enum DiagonalPolicy { DIAG_ZERO, ///< Set the diagonal value to zero diff --git a/linalg/ode.hpp b/linalg/ode.hpp index f542c55411..06067a3fe7 100644 --- a/linalg/ode.hpp +++ b/linalg/ode.hpp @@ -342,7 +342,7 @@ protected: mutable Vector dq_; }; -// First Order Symplectic Integration Algorithm +/// First Order Symplectic Integration Algorithm class SIA1Solver : public SIASolver { public: @@ -350,7 +350,7 @@ public: void Step(Vector &q, Vector &p, double &t, double &dt); }; -// Second Order Symplectic Integration Algorithm +/// Second Order Symplectic Integration Algorithm class SIA2Solver : public SIASolver { public: @@ -358,7 +358,7 @@ public: void Step(Vector &q, Vector &p, double &t, double &dt); }; -// Variable order Symplectic Integration Algorithm (orders 1-4) +/// Variable order Symplectic Integration Algorithm (orders 1-4) class SIAVSolver : public SIASolver { public: diff --git a/linalg/vector.hpp b/linalg/vector.hpp index 64abb86c06..148c15892f 100644 --- a/linalg/vector.hpp +++ b/linalg/vector.hpp @@ -271,6 +271,7 @@ public: /// v = median(v,lo,hi) entrywise. Implementation assumes lo <= hi. void median(const Vector &lo, const Vector &hi); + /// Extract entries listed in `dofs` to the output `elemvect` void GetSubVector(const Array &dofs, Vector &elemvect) const; void GetSubVector(const Array &dofs, double *elem_data) const; From 2def41540d069533bd218f7a8608de17a96b65df Mon Sep 17 00:00:00 2001 From: camierjs Date: Wed, 28 Aug 2019 10:47:17 -0700 Subject: [PATCH 035/535] X86 => SIMD --- INSTALL | 4 +- config/config.hpp.in | 4 +- config/config.mk.in | 2 +- config/defaults.mk | 2 +- config/tconfig.hpp | 10 +- data/inline-hex-2x1x1.mesh | 9 - data/inline-hex-one.mesh | 9 - fem/tbilinearform.hpp | 2 +- fem/tbilininteg.hpp | 4 +- fem/tfespace.hpp | 1 - makefile | 4 +- miniapps/performance/CMakeLists.txt | 3 +- miniapps/performance/bp.cpp | 774 ------------------------- miniapps/performance/bprtc.cpp | 863 ---------------------------- miniapps/performance/ex1.cpp | 91 +-- miniapps/performance/ex1rtc.cpp | 440 -------------- miniapps/performance/makefile | 28 +- 17 files changed, 35 insertions(+), 2215 deletions(-) delete mode 100644 data/inline-hex-2x1x1.mesh delete mode 100644 data/inline-hex-one.mesh delete mode 100644 miniapps/performance/bp.cpp delete mode 100644 miniapps/performance/bprtc.cpp delete mode 100644 miniapps/performance/ex1rtc.cpp diff --git a/INSTALL b/INSTALL index 5b7debfed3..d38db9a678 100644 --- a/INSTALL +++ b/INSTALL @@ -378,8 +378,8 @@ MFEM_USE_SIDRE = YES/NO specification. When enabled, this option requires installation of HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project. -MFEM_USE_X86INTRIN = YES/NO - Enables the high performance templated classes to use X86 intrinsics +MFEM_USE_SIMD = YES/NO + Enables the high performance templated classes to use specific intrinsics instead of the AutoSIMD (config/simd/auto.hpp) classe. MFEM_USE_CONDUIT = YES/NO diff --git a/config/config.hpp.in b/config/config.hpp.in index 124f87220b..2ad865dd20 100644 --- a/config/config.hpp.in +++ b/config/config.hpp.in @@ -106,8 +106,8 @@ // Enable Sidre support // #define MFEM_USE_SIDRE -// Enable x86intrin support -// #define MFEM_USE_X86INTRIN +// Enable the high performance templated classes to use SIMD +// #define MFEM_USE_SIMD // Enable Conduit support // #define MFEM_USE_CONDUIT diff --git a/config/config.mk.in b/config/config.mk.in index 83b68e7bab..f1ed431213 100644 --- a/config/config.mk.in +++ b/config/config.mk.in @@ -44,7 +44,7 @@ MFEM_USE_PUMI = @MFEM_USE_PUMI@ MFEM_USE_CUDA = @MFEM_USE_CUDA@ MFEM_USE_RAJA = @MFEM_USE_RAJA@ MFEM_USE_OCCA = @MFEM_USE_OCCA@ -MFEM_USE_X86INTRIN = @MFEM_USE_X86INTRIN +MFEM_USE_SIMD = @MFEM_USE_SIMD@ # Compiler, compile options, and link options MFEM_CXX = @MFEM_CXX@ diff --git a/config/defaults.mk b/config/defaults.mk index 056e2cdbf8..fa65c7ad44 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -124,7 +124,7 @@ MFEM_USE_PUMI = NO MFEM_USE_CUDA = NO MFEM_USE_RAJA = NO MFEM_USE_OCCA = NO -MFEM_USE_X86INTRIN = NO +MFEM_USE_SIMD = NO # Compile and link options for zlib. ZLIB_DIR = diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 9282ac3665..ac2c01e7eb 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -46,8 +46,8 @@ #define MFEM_ALIGN_AS(bytes) #endif -// --- AutoSIMD or X86 intrinsics -#ifndef MFEM_USE_X86INTRIN +// --- AutoSIMD or intrinsics +#ifndef MFEM_USE_SIMD #include "simd/auto.hpp" #else #ifdef __VSX__ @@ -61,7 +61,7 @@ #endif // --- SIMD Traits -#ifndef MFEM_USE_X86INTRIN +#ifndef MFEM_USE_SIMD #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 #else @@ -89,9 +89,9 @@ struct AutoImplTraits typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; -#ifndef MFEM_USE_X86INTRIN +#ifndef MFEM_USE_SIMD typedef AutoSIMD< int,simd_size,valign_size> vint_t; -#endif // MFEM_USE_X86INTRIN +#endif // MFEM_USE_SIMD }; #define MFEM_TEMPLATE_ENABLE_SERIALIZE diff --git a/data/inline-hex-2x1x1.mesh b/data/inline-hex-2x1x1.mesh deleted file mode 100644 index 8e1c73c926..0000000000 --- a/data/inline-hex-2x1x1.mesh +++ /dev/null @@ -1,9 +0,0 @@ -MFEM INLINE mesh v1.0 - -type = hex -nx = 2 -ny = 1 -nz = 1 -sx = 1.0 -sy = 1.0 -sz = 1.0 diff --git a/data/inline-hex-one.mesh b/data/inline-hex-one.mesh deleted file mode 100644 index 4285039b7a..0000000000 --- a/data/inline-hex-one.mesh +++ /dev/null @@ -1,9 +0,0 @@ -MFEM INLINE mesh v1.0 - -type = hex -nx = 1 -ny = 1 -nz = 1 -sx = 1.0 -sy = 1.0 -sz = 1.0 diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 7034e14dd4..6a57bb5038 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -29,7 +29,7 @@ namespace mfem // real_t - mesh nodes, sol basis, mesh basis data type template > diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index 1239e0e366..73892b8177 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -369,9 +369,9 @@ struct TDiffusionKernel<2,2,complex_t> const complex_t w_det_J = Q.get(q,i,k) / (J11 * J22 - J21 * J12); internal::MatrixOps<2,2>::Symm::Set( A.layout.ind1(i), A, - w_det_J * (J12*J12 + J22*J22), // (1,1) + + w_det_J * (J12*J12 + J22*J22), // (1,1) - w_det_J * (J11*J12 + J21*J22), // (2,1) - w_det_J * (J11*J11 + J21*J21) // (2,2) + + w_det_J * (J11*J11 + J21*J21) // (2,2) ); } } diff --git a/fem/tfespace.hpp b/fem/tfespace.hpp index 5607c11870..a971301808 100644 --- a/fem/tfespace.hpp +++ b/fem/tfespace.hpp @@ -36,7 +36,6 @@ namespace mfem // elements are assumed to have the same number of dofs. Such an array is // constructed from the J array of an element-to-dof Table with optional local // renumbering to ensure tensor-product local dof ordering when needed. - template class ElementDofIndexer { diff --git a/makefile b/makefile index d1baf2b147..7cc64f4ebe 100644 --- a/makefile +++ b/makefile @@ -294,7 +294,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\ MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS MFEM_USE_NETCDF\ MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT MFEM_USE_PUMI\ MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA MFEM_SOURCE_DIR MFEM_INSTALL_DIR\ - MFEM_USE_X86INTRIN + MFEM_USE_SIMD # List of makefile variables that will be written to config.mk: MFEM_CONFIG_VARS = MFEM_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS MFEM_INC_DIR\ @@ -616,7 +616,7 @@ status info: $(info MFEM_MPIEXEC = $(MFEM_MPIEXEC)) $(info MFEM_MPIEXEC_NP = $(MFEM_MPIEXEC_NP)) $(info MFEM_MPI_NP = $(MFEM_MPI_NP)) - $(info MFEM_USE_X86INTRIN = $(MFEM_USE_X86INTRIN)) + $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) @true ASTYLE = astyle --options=$(SRC)config/mfem.astylerc diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index ef903af741..95a3a0ed2a 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -27,8 +27,7 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") "-std=c++11" "-pedantic" "-Wall" -# "--param" "max-completely-peel-times=3" - ) + "--param" "max-completely-peel-times=3") elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") list(APPEND PERFORMANCE_CXX_OPTIONS "-xHost") diff --git a/miniapps/performance/bp.cpp b/miniapps/performance/bp.cpp deleted file mode 100644 index 3dff14c54c..0000000000 --- a/miniapps/performance/bp.cpp +++ /dev/null @@ -1,774 +0,0 @@ -// Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights -// reserved. See files LICENSE and NOTICE for details. -// -// This file is part of CEED, a collection of benchmarks, miniapps, software -// libraries and APIs for efficient high-order finite element and spectral -// element discretizations for exascale applications. For more information and -// source code availability see http://github.com/ceed. -// -// The CEED research is supported by the Exascale Computing Project -// (17-SC-20-SC), a collaborative effort of two U.S. Department of Energy -// organizations (Office of Science and the National Nuclear Security -// Administration) responsible for the planning and preparation of a capable -// exascale ecosystem, including software, applications, hardware, advanced -// system engineering and early testbed platforms, in support of the nation's -// exascale computing imperative. - - -//============================================================================== -// MFEM Bake-off Problems 1, 2, 3, and 4 -// Version 1 -// -// Compile with: see README.md -// -// Sample runs: see README.md -// -// Description: These benchmarks (CEED Bake-off Problems BP1 and BP3) test the -// performance of high-order mass (BP1) and stiffness (BP3) matrix -// operator evaluation with "partial assembly" algorithms. -// -// Code is based on MFEM's HPC ex1, http://mfem.org/performance. -// -// More details about CEED's bake-off problems can be found at -// http://ceed.exascaleproject.org/bps. -//============================================================================== - -#include - -using namespace mfem; - -#ifndef GEOM -#define GEOM Geometry::CUBE -#endif - -#ifndef MESH_P -#define MESH_P 2 -#endif - -#ifndef SOL_P -#define SOL_P 2 -#endif - -#ifndef IR_ORDER -#define IR_ORDER 0 -#endif - -#ifndef IR_TYPE -// 0 - Gauss quadrature, 1 - Gauss-Lobatto quadrature -#define IR_TYPE 0 -#endif - -#ifndef PROBLEM -#define PROBLEM 0 -#endif - -#ifndef VDIM -#define VDIM 1 -#endif - -#ifdef __xlC__ -#define USE_MPI_WTIME -#endif - -// This vector layout is used for the solution space only. -#ifndef VEC_LAYOUT -#define VEC_LAYOUT Ordering::byVDIM -#endif - -// Define template parameters for optimized build. -const Geometry::Type geom = GEOM; // mesh elements (default: hex) -const int mesh_p = MESH_P; // mesh curvature (default: 3) -const int sol_p = SOL_P; // solution order (default: 3) -const int ir_q = IR_TYPE ? sol_p+1 : sol_p+2; -const int ir_order = IR_ORDER ? IR_ORDER : - (IR_TYPE ? 2*ir_q-3 : 2*ir_q-1); - - -// Workaround for a bug in XL C++ on BG/Q version 12.01.0000.0014 -#if defined(__xlC__) && (__xlC__ < 0x0d00) -#include <../mfem/linalg/tlayout.hpp> -namespace mfem -{ -const int mesh_dim = Geometry::Constants::Dimension; -template class StridedLayout1D; -} -#endif // defined(__xlC__) && (__xlC__ < 0x0d00) - - -#include -#include -#include - -using namespace std; - -IntegrationRules GaussLobattoRules(0, Quadrature1D::GaussLobatto); - -template -class GaussLobattoIntegrationRule - : public TProductIntegrationRule -{ -public: - typedef TProductIntegrationRule base_class; - - using base_class::geom; - using base_class::order; - using base_class::qpts_1d; - -protected: - using base_class::weights_1d; - -public: - GaussLobattoIntegrationRule() - { - const IntegrationRule &ir_1d = Get1DIntRule(); - MFEM_ASSERT(ir_1d.GetNPoints() == qpts_1d, "quadrature rule mismatch"); - for (int j = 0; j < qpts_1d; j++) - { - weights_1d.data[j] = ir_1d.IntPoint(j).weight; - } - } - - static const IntegrationRule &Get1DIntRule() - { - return GaussLobattoRules.Get(Geometry::SEGMENT, order); - } - static const IntegrationRule &GetIntRule() - { - return GaussLobattoRules.Get(geom, order); - } -}; - - -// Static mesh type -typedef H1_FiniteElement mesh_fe_t; -typedef H1_FiniteElementSpace mesh_fes_t; -typedef TMesh mesh_t; - -// Static solution finite element space type -typedef H1_FiniteElement sol_fe_t; -typedef H1_FiniteElementSpace sol_fes_t; - -// Static quadrature, coefficient and integrator types -#if (IR_TYPE == 0) -typedef TIntegrationRule int_rule_t; -#else -const int rdim = Geometry::Constants::Dimension; -typedef GaussLobattoIntegrationRule - int_rule_t; -#endif -typedef TConstantCoefficient<> coeff_t; -#if (PROBLEM == 0) -typedef TIntegrator integ_t; -#else -typedef TIntegrator integ_t; -#endif -#if (VDIM == 1) -typedef ScalarLayout vec_layout_t; -#else -typedef VectorLayout vec_layout_t; -#endif - -// Static bilinear form type, combining the above types -typedef TBilinearForm HPCBilinearForm; - -int main(int argc, char *argv[]) -{ - // 1. Initialize MPI. - int num_procs, myid; - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - MPI_Comm_rank(MPI_COMM_WORLD, &myid); - - const int vdim = VDIM; - const Ordering::Type ordering = VEC_LAYOUT; // for solution space only - - // 2. Parse command-line options. - const char *mesh_file = "../../data/fichera.mesh"; - int ser_ref_levels = -1; - int par_ref_levels = +1; - Array nxyz; - int order = sol_p; - const char *basis_type = "G"; // Gauss-Lobatto - bool static_cond = false; - const char *pc = "lor"; - bool perf = true; - bool matrix_free = true; - int max_iter = 50; - bool visualization = 1; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", - "Number of times to refine the mesh uniformly in serial."); - args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", - "Number of times to refine the mesh uniformly in parallel."); - args.AddOption(&nxyz, "-c", "--cartesian-partitioning", - "Use Cartesian partitioning."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); - args.AddOption(&basis_type, "-b", "--basis-type", - "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); - args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", - "Enable high-performance, tensor-based, assembly/evaluation."); - args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", - "Use matrix-free evaluation or efficient matrix assembly in " - "the high-performance version."); - args.AddOption(&pc, "-pc", "--preconditioner", - "Preconditioner: lor - low-order-refined (matrix-free) AMG, " - "ho - high-order (assembled) AMG, none."); - args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", - "--no-static-condensation", "Enable static condensation."); - args.AddOption(&max_iter, "-mi", "--max-iter", - "Maximum number of iterations."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - if (!args.Good()) - { - if (myid == 0) - { - args.PrintUsage(cout); - } - MPI_Finalize(); - return 1; - } - if (static_cond && perf && matrix_free) - { - if (myid == 0) - { - cout << "\nStatic condensation can not be used with matrix-free" - " evaluation!\n" << endl; - } - MPI_Finalize(); - return 2; - } - MFEM_VERIFY(perf || !matrix_free, - "--standard-version is not compatible with --matrix-free"); - if (myid == 0) - { - args.PrintOptions(cout); - } - - enum PCType { NONE, LOR, HO }; - PCType pc_choice; - if (!strcmp(pc, "ho")) { pc_choice = HO; } - else if (!strcmp(pc, "lor")) { pc_choice = LOR; } - else if (!strcmp(pc, "none")) { pc_choice = NONE; } - else - { - mfem_error("Invalid Preconditioner specified"); - return 3; - } - - // See class BasisType in fem/fe_coll.hpp for available basis types - int basis = BasisType::GetType(basis_type[0]); - if (myid == 0) - { - cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; - } - - // 3. Read the (serial) mesh from the given mesh file on all processors. We - // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface - // and volume meshes with the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - int dim = mesh->Dimension(); - - // 4. Check if the optimized version matches the given mesh - if (perf) - { - if (myid == 0) - { - cout << "High-performance version using integration rule with " - << int_rule_t::qpts << " points ..." << endl; - cout << "Quadrature rule type: " - << (IR_TYPE == 0 ? "Gauss" : "Gauss-Lobatto") << endl; - } - if (!mesh_t::MatchesGeometry(*mesh)) - { - if (myid == 0) - { - cout << "The given mesh does not match the optimized 'geom' parameter.\n" - << "Recompile with suitable 'geom' value." << endl; - } - delete mesh; - MPI_Finalize(); - return 4; - } - else if (!mesh_t::MatchesNodes(*mesh)) - { - if (myid == 0) - { - cout << "Switching the mesh curvature to match the " - << "optimized value (order " << mesh_p << ") ..." << endl; - } - mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); - } - } - - // 5. Refine the serial mesh on all processors to increase the resolution. In - // this example we do 'ref_levels' of uniform refinement. We choose - // 'ref_levels' to be the largest number that gives a final mesh with no - // more than 10,000 elements. - { - int ref_levels = - (int)floor(log(10000./mesh->GetNE())/log(2.)/dim); - ref_levels = (ser_ref_levels != -1) ? ser_ref_levels : ref_levels; - for (int l = 0; l < ref_levels; l++) - { - if (myid == 0) - { - cout << "Serial refinement: level " << l << " -> level " << l+1 - << " ..." << flush; - } - mesh->UniformRefinement(); - MPI_Barrier(MPI_COMM_WORLD); - if (myid == 0) - { - cout << " done." << endl; - } - } - } - if (!perf && mesh->NURBSext) - { - const int new_mesh_p = std::min(sol_p, mesh_p); - if (myid == 0) - { - cout << "NURBS mesh: switching the mesh curvature to be " - << "min(sol_p, mesh_p) = " << new_mesh_p << " ..." << endl; - } - mesh->SetCurvature(new_mesh_p, false, -1, Ordering::byNODES); - } - - // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine - // this mesh further in parallel to increase the resolution. Once the - // parallel mesh is defined, the serial mesh can be deleted. - MFEM_VERIFY(nxyz.Size() == 0 || nxyz.Size() == mesh->SpaceDimension(), - "Expected " << mesh->SpaceDimension() << " integers with the " - "option --cartesian-partitioning."); - int *partitioning = nxyz.Size() ? mesh->CartesianPartitioning(nxyz) : NULL; - ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh, partitioning); - delete [] partitioning; - delete mesh; - { - for (int l = 0; l < par_ref_levels; l++) - { - if (myid == 0) - { - cout << "Parallel refinement: level " << l << " -> level " << l+1 - << " ..." << flush; - } - pmesh->UniformRefinement(); - MPI_Barrier(MPI_COMM_WORLD); - if (myid == 0) - { - cout << " done." << endl; - } - } - } - if (pmesh->MeshGenerator() & 1) // simplex mesh - { - MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" - " the LOR preconditioner yet"); - } - - pmesh->PrintInfo(cout); - - // 7. Define a parallel finite element space on the parallel mesh. Here we - // use continuous Lagrange finite elements of the specified order. If - // order < 1, we instead use an isoparametric/isogeometric space. - FiniteElementCollection *fec; - if (order > 0) - { - fec = new H1_FECollection(order, dim, basis); - } - else if (pmesh->GetNodes()) - { - fec = pmesh->GetNodes()->OwnFEC(); - if (myid == 0) - { - cout << "Using isoparametric FEs: " << fec->Name() << endl; - } - } - else - { - fec = new H1_FECollection(order = 1, dim, basis); - } - ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec, - vdim, ordering); - HYPRE_Int size = fespace->GlobalTrueVSize(); - if (myid == 0) - { - cout << "Number of finite element unknowns: " << size << endl; - } - - ParMesh *pmesh_lor = NULL; - FiniteElementCollection *fec_lor = NULL; - ParFiniteElementSpace *fespace_lor = NULL; - if (pc_choice == LOR) - { - int basis_lor = basis; - if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } - pmesh_lor = new ParMesh(pmesh, order, basis_lor); - fec_lor = new H1_FECollection(1, dim); - fespace_lor = new ParFiniteElementSpace(pmesh_lor, fec_lor, - vdim, ordering); - } - - // 8. Check if the optimized version matches the given space - if (perf && !sol_fes_t::Matches(*fespace)) - { - if (myid == 0) - { - cout << "The given order does not match the optimized parameter.\n" - << "Recompile with suitable 'sol_p' value." << endl; - } - delete fespace; - delete fec; - delete mesh; - MPI_Finalize(); - return 5; - } - - // 9. Determine the list of true (i.e. parallel conforming) essential - // boundary dofs. In this example, the boundary conditions are defined - // by marking all the boundary attributes from the mesh as essential - // (Dirichlet) and converting them to a list of true dofs. - Array ess_tdof_list; - if (pmesh->bdr_attributes.Size()) - { - Array ess_bdr(pmesh->bdr_attributes.Max()); - ess_bdr = 1; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - - // 10. Set up the parallel linear form b(.) which corresponds to the - // right-hand side of the FEM linear system, which in this case is - // (1,phi_i) where phi_i are the basis functions in fespace. - ParLinearForm *b = new ParLinearForm(fespace); - ConstantCoefficient one(1.0); - Vector uvec(vdim); - for (int i = 0; i < vdim; i++) - { - uvec(i) = i + 1.0; - } - uvec /= uvec.Norml2(); - VectorConstantCoefficient unit_vec(uvec); - if (vdim == 1) - { - b->AddDomainIntegrator(new DomainLFIntegrator(one)); - } - else - { - b->AddDomainIntegrator(new VectorDomainLFIntegrator(unit_vec)); - } - b->Assemble(); - - // 11. Define the solution vector x as a parallel finite element grid - // function corresponding to fespace. Initialize x with initial guess of - // zero, which satisfies the boundary conditions. - ParGridFunction x(fespace); - x = 0.0; - - // 12. Set up the parallel bilinear form a(.,.) on the finite element space - // that will hold the matrix corresponding to the Laplacian operator. - ParBilinearForm *a = new ParBilinearForm(fespace); - ParBilinearForm *a_pc = NULL; - if (pc_choice == LOR) { a_pc = new ParBilinearForm(fespace_lor); } - if (pc_choice == HO) { a_pc = new ParBilinearForm(fespace); } - - // 13. Assemble the parallel bilinear form and the corresponding linear - // system, applying any necessary transformations such as: parallel - // assembly, eliminating boundary conditions, applying conforming - // constraints for non-conforming AMR, static condensation, etc. - if (static_cond) - { - a->EnableStaticCondensation(); - MFEM_VERIFY(pc_choice != LOR, - "cannot use LOR preconditioner with static condensation"); - } - - if (myid == 0) - { - cout << "Assembling the local matrix ..." << flush; - } -#ifdef USE_MPI_WTIME - double my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - // Pre-allocate sparsity assuming dense element matrices; the actual memory - // allocation happens when a->Assemble() is called. - a->UsePrecomputedSparsity(); - - HPCBilinearForm *a_hpc = NULL; - Operator *a_oper = NULL; - - if (!perf) - { - // Standard assembly using a diffusion domain integrator - if (vdim == 1) - { - a->AddDomainIntegrator(new DiffusionIntegrator(one)); - } - else - { - a->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); - } - a->Assemble(); - } - else - { - // High-performance assembly/evaluation using the templated operator type - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - if (matrix_free) - { - a_hpc->Assemble(); // partial assembly - } - else - { - a_hpc->AssembleBilinearForm(*a); // full matrix assembly - } - } -#ifdef USE_MPI_WTIME - double rt_min, rt_max, my_rt; - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - double rt_min, rt_max, my_rt; - my_rt = tic_toc.RealTime(); -#endif - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - cout << " done, " << rt_max << " (" << rt_min << ") s." << endl; - cout << "\n\"DOFs/sec\" in assembly: " - << 1e-6*size/rt_max << " (" - << 1e-6*size/rt_min << ") million.\n" << endl; - } - - // 14. Define and apply a parallel PCG solver for AX=B with the BoomerAMG - // preconditioner from hypre. - - // Setup the operator matrix (if applicable) - HypreParMatrix A; - Vector B, X; - if (myid == 0) - { - cout << "FormLinearSystem() ..." << endl; - } -#ifdef USE_MPI_WTIME - my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - if (perf && matrix_free) - { - a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - if (myid == 0) - { - cout << "Size of linear system: " << size << endl; - } - } - else - { - a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - HYPRE_Int glob_size = A.GetGlobalNumRows(); - HYPRE_Int glob_nnz = A.NNZ(); - if (myid == 0) - { - cout << "Size of linear system: " << glob_size << endl; - cout << "Average nonzero entries per row: " - << 1.0*glob_nnz/glob_size << endl; - } - a_oper = &A; - } -#ifdef USE_MPI_WTIME - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - my_rt = tic_toc.RealTime(); -#endif - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - cout << "FormLinearSystem() ... done, " << rt_max << " (" << rt_min - << ") s." << endl; - cout << "\n\"DOFs/sec\" in FormLinearSystem(): " - << 1e-6*size/rt_max << " (" - << 1e-6*size/rt_min << ") million.\n" << endl; - } - - // Setup the matrix used for preconditioning - if (myid == 0) - { - cout << "Assembling the preconditioning matrix ..." << flush; - } -#ifdef USE_MPI_WTIME - my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - - HypreParMatrix A_pc; - if (pc_choice == LOR) - { - // TODO: assemble the LOR matrix using the performance code - if (vdim == 1) - { - a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); - } - else - { - a_pc->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); - } - a_pc->UsePrecomputedSparsity(); - a_pc->Assemble(); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - else if (pc_choice == HO) - { - if (!matrix_free) - { - A_pc.MakeRef(A); // matrix already assembled, reuse it - } - else - { - a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - } -#ifdef USE_MPI_WTIME - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - my_rt = tic_toc.RealTime(); -#endif - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - cout << " done, " << rt_max << "s." << endl; - } - - // Solve with CG or PCG, depending if the matrix A_pc is available - CGSolver *pcg; - pcg = new CGSolver(MPI_COMM_WORLD); - pcg->SetRelTol(1e-6); - pcg->SetMaxIter(max_iter); - pcg->SetPrintLevel(3); - - HypreSolver *amg = NULL; - - pcg->SetOperator(*a_oper); - if (pc_choice != NONE) - { - HypreBoomerAMG *bamg = new HypreBoomerAMG(A_pc); - if (vdim > 1 && ordering == Ordering::byVDIM) - { - bamg->SetSystemsOptions(vdim); - } - amg = bamg; - pcg->SetPreconditioner(*amg); - } - -#ifdef USE_MPI_WTIME - my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - - pcg->Mult(B, X); - -#ifdef USE_MPI_WTIME - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - my_rt = tic_toc.RealTime(); -#endif - delete amg; - - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - // Note: In the pcg algorithm, the number of operator Mult() calls is - // N_iter and the number of preconditioner Mult() calls is N_iter+1. - cout << "Total CG time: " << rt_max << " (" << rt_min << ") sec." - << endl; - cout << "Time per CG step: " - << rt_max / pcg->GetNumIterations() << " (" - << rt_min / pcg->GetNumIterations() << ") sec." << endl; - cout << "\n\"DOFs/sec\" in CG: " - << 1e-6*size*pcg->GetNumIterations()/rt_max << " (" - << 1e-6*size*pcg->GetNumIterations()/rt_min << ") million.\n" - << endl; - } - - // 15. Recover the parallel grid function corresponding to X. This is the - // local finite element solution on each processor. - if (perf && matrix_free) - { - a_hpc->RecoverFEMSolution(X, *b, x); - } - else - { - a->RecoverFEMSolution(X, *b, x); - } - - // 16. Save the refined mesh and the solution in parallel. This output can - // be viewed later using GLVis: "glvis -np -m mesh -g sol". - if (false) - { - ostringstream mesh_name, sol_name; - mesh_name << "mesh." << setfill('0') << setw(6) << myid; - sol_name << "sol." << setfill('0') << setw(6) << myid; - - ofstream mesh_ofs(mesh_name.str().c_str()); - mesh_ofs.precision(8); - pmesh->Print(mesh_ofs); - - ofstream sol_ofs(sol_name.str().c_str()); - sol_ofs.precision(8); - x.Save(sol_ofs); - } - - // 17. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock << "parallel " << num_procs << " " << myid << "\n"; - sol_sock.precision(8); - sol_sock << "solution\n" << *pmesh << x << flush; - } - - // 18. Free the used memory. - delete a; - delete a_hpc; - if (a_oper != &A) { delete a_oper; } - delete a_pc; - delete b; - delete fespace; - delete fespace_lor; - delete fec_lor; - delete pmesh_lor; - if (order > 0) { delete fec; } - delete pmesh; - delete pcg; - - MPI_Finalize(); - - return 0; -} diff --git a/miniapps/performance/bprtc.cpp b/miniapps/performance/bprtc.cpp deleted file mode 100644 index 90f9b08746..0000000000 --- a/miniapps/performance/bprtc.cpp +++ /dev/null @@ -1,863 +0,0 @@ -// Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights -// reserved. See files LICENSE and NOTICE for details. -// -// This file is part of CEED, a collection of benchmarks, miniapps, software -// libraries and APIs for efficient high-order finite element and spectral -// element discretizations for exascale applications. For more information and -// source code availability see http://github.com/ceed. -// -// The CEED research is supported by the Exascale Computing Project -// (17-SC-20-SC), a collaborative effort of two U.S. Department of Energy -// organizations (Office of Science and the National Nuclear Security -// Administration) responsible for the planning and preparation of a capable -// exascale ecosystem, including software, applications, hardware, advanced -// system engineering and early testbed platforms, in support of the nation's -// exascale computing imperative. - - -//============================================================================== -// MFEM Bake-off Problems 1, 2, 3, and 4 -// Version 1 -// -// Compile with: see README.md -// -// Sample runs: see README.md -// -// Description: These benchmarks (CEED Bake-off Problems BP1 and BP3) test the -// performance of high-order mass (BP1) and stiffness (BP3) matrix -// operator evaluation with "partial assembly" algorithms. -// -// Code is based on MFEM's HPC ex1, http://mfem.org/performance. -// -// More details about CEED's bake-off problems can be found at -// http://ceed.exascaleproject.org/bps. -//============================================================================== - -#include - -using namespace mfem; - -#ifndef GEOM -#define GEOM Geometry::CUBE -#endif - -#ifndef MESH_P -#define MESH_P 2 -#endif - -#ifndef SOL_P -#define SOL_P 2 -#endif - -#ifndef IR_ORDER -#define IR_ORDER 0 -#endif - -#ifndef IR_TYPE -// 0 - Gauss quadrature, 1 - Gauss-Lobatto quadrature -#define IR_TYPE 0 -#endif - -#ifndef PROBLEM -#define PROBLEM 0 -#endif - -#ifndef VDIM -#define VDIM 1 -#endif - -#ifdef __xlC__ -#define USE_MPI_WTIME -#endif - -// This vector layout is used for the solution space only. -#ifndef VEC_LAYOUT -#define VEC_LAYOUT Ordering::byVDIM -#endif - -// Define template parameters for optimized build. -const Geometry::Type geom = GEOM; // mesh elements (default: hex) -const int mesh_p = MESH_P; // mesh curvature (default: 3) -const int sol_p = SOL_P; // solution order (default: 3) -const int ir_q = IR_TYPE ? sol_p+1 : sol_p+2; -const int ir_order = IR_ORDER ? IR_ORDER : - (IR_TYPE ? 2*ir_q-3 : 2*ir_q-1); - -#include -#include -#include - -using namespace std; - -IntegrationRules GaussLobattoRules(0, Quadrature1D::GaussLobatto); - -template -class GaussLobattoIntegrationRule - : public TProductIntegrationRule -{ -public: - typedef TProductIntegrationRule base_class; - - using base_class::geom; - using base_class::order; - using base_class::qpts_1d; - -protected: - using base_class::weights_1d; - -public: - GaussLobattoIntegrationRule() - { - const IntegrationRule &ir_1d = Get1DIntRule(); - MFEM_ASSERT(ir_1d.GetNPoints() == qpts_1d, "quadrature rule mismatch"); - for (int j = 0; j < qpts_1d; j++) - { - weights_1d.data[j] = ir_1d.IntPoint(j).weight; - } - } - - static const IntegrationRule &Get1DIntRule() - { - return GaussLobattoRules.Get(Geometry::SEGMENT, order); - } - static const IntegrationRule &GetIntRule() - { - return GaussLobattoRules.Get(geom, order); - } -}; - - -// Static mesh type -typedef H1_FiniteElement mesh_fe_t; -typedef H1_FiniteElementSpace mesh_fes_t; -typedef TMesh mesh_t; - -// Static solution finite element space type -typedef H1_FiniteElement sol_fe_t; -typedef H1_FiniteElementSpace sol_fes_t; - -// Static quadrature, coefficient and integrator types -#if (IR_TYPE == 0) -typedef TIntegrationRule int_rule_t; -#else -const int rdim = Geometry::Constants::Dimension; -typedef GaussLobattoIntegrationRule - int_rule_t; -#endif -typedef TConstantCoefficient<> coeff_t; -#if (PROBLEM == 0) -typedef TIntegrator integ_t; -#else -typedef TIntegrator integ_t; -#endif -#if (VDIM == 1) -typedef ScalarLayout vec_layout_t; -#else -typedef VectorLayout vec_layout_t; -#endif - -// Static bilinear form type, combining the above types -typedef TBilinearForm HPCBilinearForm; -enum PCType { NONE, LOR, HO }; - -// Workaround for a bug in XL C++ on BG/Q version 12.01.0000.0014 -#if defined(__xlC__) && (__xlC__ < 0x0d00) -#include <../mfem/linalg/tlayout.hpp> -namespace mfem -{ -const int mesh_dim = Geometry::Constants::Dimension; -template class StridedLayout1D; -} -#endif // defined(__xlC__) && (__xlC__ < 0x0d00) - -// ***************************************************************************** -// -L/home/camier1/home/mfem/x86 -lmfem -L/home/camier1/usr/local/hypre/2.11.2/lib -lHYPRE -L/home/camier1/usr/local/metis/5.1.0/lib -lmetis -lrt -ldl -// ***************************************************************************** -void bp_kernel(const int num_procs, - const HYPRE_Int size, - const int myid, - const int dim, - const int vdim, - const Ordering::Type ordering, - const int order, - const bool static_cond, - const bool perf, - const bool matrix_free, - const int max_iter, - const bool visualization, - const int pc_choice, // PCType - const int basis, - // ************************************************************** - const bool simd, - // ************************************************************** - const Geometry::Type geom, - const int mesh_p, - const int sol_p, - const int ir_q, - const int ir_order, - // ************************************************************** - const char* __restrict mesh_file, - const ParMesh* __restrict pmesh, - ParFiniteElementSpace* __restrict fespace, - ParFiniteElementSpace* __restrict fespace_lor){ - // Should be captured while parsing - using namespace std; - using namespace mfem; - enum PCType { NONE, LOR, HO }; - const Geometry::Type g = Geometry::CUBE; - - typedef H1_FiniteElement mesh_fe_t; - typedef H1_FiniteElementSpace mesh_fes_t; - typedef TMesh mesh_t; - - typedef H1_FiniteElement sol_fe_t; - typedef H1_FiniteElementSpace sol_fes_t; - - typedef TIntegrationRule int_rule_t; - - typedef TConstantCoefficient<> coeff_t; - typedef TIntegrator integ_t; - - typedef ScalarLayout vec_layout_t; - - typedef TBilinearForm HPCBilinearForm; - - /* - typedef H1_FiniteElementSpace mesh_fes_t; - typedef TMesh mesh_t; - typedef TIntegrationRule int_rule_t; - - typedef TBilinearForm HPCBilinearForm; - */ - - // 9. Determine the list of true (i.e. parallel conforming) essential - // boundary dofs. In this example, the boundary conditions are defined - // by marking all the boundary attributes from the mesh as essential - // (Dirichlet) and converting them to a list of true dofs. - mfem::Array ess_tdof_list; - if (pmesh->bdr_attributes.Size()) - { - Array ess_bdr(pmesh->bdr_attributes.Max()); - ess_bdr = 1; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - - // 10. Set up the parallel linear form b(.) which corresponds to the - // right-hand side of the FEM linear system, which in this case is - // (1,phi_i) where phi_i are the basis functions in fespace. - ParLinearForm *b = new ParLinearForm(fespace); - ConstantCoefficient one(1.0); - Vector uvec(vdim); - for (int i = 0; i < vdim; i++) - { - uvec(i) = i + 1.0; - } - uvec /= uvec.Norml2(); - VectorConstantCoefficient unit_vec(uvec); - if (vdim == 1) - { - b->AddDomainIntegrator(new DomainLFIntegrator(one)); - } - else - { - b->AddDomainIntegrator(new VectorDomainLFIntegrator(unit_vec)); - } - b->Assemble(); - - // 11. Define the solution vector x as a parallel finite element grid - // function corresponding to fespace. Initialize x with initial guess of - // zero, which satisfies the boundary conditions. - ParGridFunction x(fespace); - x = 0.0; - - // 12. Set up the parallel bilinear form a(.,.) on the finite element space - // that will hold the matrix corresponding to the Laplacian operator. - ParBilinearForm *a = new ParBilinearForm(fespace); - ParBilinearForm *a_pc = NULL; - if (pc_choice == LOR) { a_pc = new ParBilinearForm(fespace_lor); } - if (pc_choice == HO) { a_pc = new ParBilinearForm(fespace); } - - // 13. Assemble the parallel bilinear form and the corresponding linear - // system, applying any necessary transformations such as: parallel - // assembly, eliminating boundary conditions, applying conforming - // constraints for non-conforming AMR, static condensation, etc. - if (static_cond) - { - a->EnableStaticCondensation(); - MFEM_VERIFY(pc_choice != LOR, - "cannot use LOR preconditioner with static condensation"); - } - - if (myid == 0) - { - cout << "Assembling the local matrix ..." << flush; - } -#ifdef USE_MPI_WTIME - double my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - // Pre-allocate sparsity assuming dense element matrices; the actual memory - // allocation happens when a->Assemble() is called. - a->UsePrecomputedSparsity(); - - HPCBilinearForm *a_hpc = NULL; - Operator *a_oper = NULL; - - if (!perf) - { - // Standard assembly using a diffusion domain integrator - if (vdim == 1) - { - a->AddDomainIntegrator(new DiffusionIntegrator(one)); - } - else - { - a->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); - } - a->Assemble(); - } - else - { - // High-performance assembly/evaluation using the templated operator type - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - if (matrix_free) - { - a_hpc->Assemble(); // partial assembly - } - else - { - a_hpc->AssembleBilinearForm(*a); // full matrix assembly - } - } -#ifdef USE_MPI_WTIME - double rt_min, rt_max, my_rt; - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - double rt_min, rt_max, my_rt; - my_rt = tic_toc.RealTime(); -#endif - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - cout << " done, " << rt_max << " (" << rt_min << ") s." << endl; - cout << "\n\"DOFs/sec\" in assembly: " - << 1e-6*size/rt_max << " (" - << 1e-6*size/rt_min << ") million.\n" << endl; - } - - // 14. Define and apply a parallel PCG solver for AX=B with the BoomerAMG - // preconditioner from hypre. - - // Setup the operator matrix (if applicable) - HypreParMatrix A; - Vector B, X; - if (myid == 0) - { - cout << "FormLinearSystem() ..." << endl; - } -#ifdef USE_MPI_WTIME - my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - if (perf && matrix_free) - { - a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - if (myid == 0) - { - cout << "Size of linear system: " << size << endl; - } - } - else - { - a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - HYPRE_Int glob_size = A.GetGlobalNumRows(); - HYPRE_Int glob_nnz = A.NNZ(); - if (myid == 0) - { - cout << "Size of linear system: " << glob_size << endl; - cout << "Average nonzero entries per row: " - << 1.0*glob_nnz/glob_size << endl; - } - a_oper = &A; - } -#ifdef USE_MPI_WTIME - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - my_rt = tic_toc.RealTime(); -#endif - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - cout << "FormLinearSystem() ... done, " << rt_max << " (" << rt_min - << ") s." << endl; - cout << "\n\"DOFs/sec\" in FormLinearSystem(): " - << 1e-6*size/rt_max << " (" - << 1e-6*size/rt_min << ") million.\n" << endl; - } - - // Setup the matrix used for preconditioning - if (myid == 0) - { - cout << "Assembling the preconditioning matrix ..." << flush; - } -#ifdef USE_MPI_WTIME - my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - - HypreParMatrix A_pc; - if (pc_choice == LOR) - { - // TODO: assemble the LOR matrix using the performance code - if (vdim == 1) - { - a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); - } - else - { - a_pc->AddDomainIntegrator(new VectorDiffusionIntegrator(one)); - } - a_pc->UsePrecomputedSparsity(); - a_pc->Assemble(); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - else if (pc_choice == HO) - { - if (!matrix_free) - { - A_pc.MakeRef(A); // matrix already assembled, reuse it - } - else - { - a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - } -#ifdef USE_MPI_WTIME - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - my_rt = tic_toc.RealTime(); -#endif - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - cout << " done, " << rt_max << "s." << endl; - } - - // Solve with CG or PCG, depending if the matrix A_pc is available - CGSolver *pcg; - pcg = new CGSolver(MPI_COMM_WORLD); - pcg->SetRelTol(1e-6); - pcg->SetMaxIter(max_iter); - pcg->SetPrintLevel(3); - - HypreSolver *amg = NULL; - - pcg->SetOperator(*a_oper); - if (pc_choice != NONE) - { - HypreBoomerAMG *bamg = new HypreBoomerAMG(A_pc); - if (vdim > 1 && ordering == Ordering::byVDIM) - { - bamg->SetSystemsOptions(vdim); - } - amg = bamg; - pcg->SetPreconditioner(*amg); - } - -#ifdef USE_MPI_WTIME - my_rt_start = MPI_Wtime(); -#else - tic_toc.Clear(); - tic_toc.Start(); -#endif - - pcg->Mult(B, X); - -#ifdef USE_MPI_WTIME - my_rt = MPI_Wtime() - my_rt_start; -#else - tic_toc.Stop(); - my_rt = tic_toc.RealTime(); -#endif - delete amg; - - MPI_Reduce(&my_rt, &rt_min, 1, MPI_DOUBLE, MPI_MIN, 0, pmesh->GetComm()); - MPI_Reduce(&my_rt, &rt_max, 1, MPI_DOUBLE, MPI_MAX, 0, pmesh->GetComm()); - if (myid == 0) - { - // Note: In the pcg algorithm, the number of operator Mult() calls is - // N_iter and the number of preconditioner Mult() calls is N_iter+1. - cout << "Total CG time: " << rt_max << " (" << rt_min << ") sec." - << endl; - cout << "Time per CG step: " - << rt_max / pcg->GetNumIterations() << " (" - << rt_min / pcg->GetNumIterations() << ") sec." << endl; - cout << "\n\"DOFs/sec\" in CG: " - << 1e-6*size*pcg->GetNumIterations()/rt_max << " (" - << 1e-6*size*pcg->GetNumIterations()/rt_min << ") million.\n" - << endl; - } - - // 15. Recover the parallel grid function corresponding to X. This is the - // local finite element solution on each processor. - if (perf && matrix_free) - { - a_hpc->RecoverFEMSolution(X, *b, x); - } - else - { - a->RecoverFEMSolution(X, *b, x); - } - - // 16. Save the refined mesh and the solution in parallel. This output can - // be viewed later using GLVis: "glvis -np -m mesh -g sol". - if (false) - { - ostringstream mesh_name, sol_name; - mesh_name << "mesh." << setfill('0') << std::setw(6) << myid; - sol_name << "sol." << setfill('0') << std::setw(6) << myid; - - ofstream mesh_ofs(mesh_name.str().c_str()); - mesh_ofs.precision(8); - pmesh->Print(mesh_ofs); - - ofstream sol_ofs(sol_name.str().c_str()); - sol_ofs.precision(8); - x.Save(sol_ofs); - } - - // 17. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock << "parallel " << num_procs << " " << myid << "\n"; - sol_sock.precision(8); - sol_sock << "solution\n" << *pmesh << x << flush; - } - - // 18. Free the used memory. - delete a; - delete a_hpc; - if (a_oper != &A) { delete a_oper; } - delete a_pc; - delete b; - delete pmesh; - delete pcg; -} - - -// ***************************************************************************** -int main(int argc, char *argv[]){ - // 1. Initialize MPI. - int num_procs, myid; - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - MPI_Comm_rank(MPI_COMM_WORLD, &myid); - - const int vdim = VDIM; - const Ordering::Type ordering = VEC_LAYOUT; // for solution space only - - // 2. Parse command-line options. - const char *mesh_file = "../../data/fichera.mesh"; - int ser_ref_levels = -1; - int par_ref_levels = +1; - Array nxyz; - int order = sol_p; - const char *basis_type = "G"; // Gauss-Lobatto - bool static_cond = false; - const char *pc = "lor"; - bool perf = true; - bool matrix_free = true; - int max_iter = 50; - bool visualization = 1; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", - "Number of times to refine the mesh uniformly in serial."); - args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", - "Number of times to refine the mesh uniformly in parallel."); - args.AddOption(&nxyz, "-c", "--cartesian-partitioning", - "Use Cartesian partitioning."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); - args.AddOption(&basis_type, "-b", "--basis-type", - "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); - args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", - "Enable high-performance, tensor-based, assembly/evaluation."); - args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", - "Use matrix-free evaluation or efficient matrix assembly in " - "the high-performance version."); - args.AddOption(&pc, "-pc", "--preconditioner", - "Preconditioner: lor - low-order-refined (matrix-free) AMG, " - "ho - high-order (assembled) AMG, none."); - args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", - "--no-static-condensation", "Enable static condensation."); - args.AddOption(&max_iter, "-mi", "--max-iter", - "Maximum number of iterations."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - if (!args.Good()) - { - if (myid == 0) - { - args.PrintUsage(cout); - } - MPI_Finalize(); - return 1; - } - if (static_cond && perf && matrix_free) - { - if (myid == 0) - { - cout << "\nStatic condensation can not be used with matrix-free" - " evaluation!\n" << endl; - } - MPI_Finalize(); - return 2; - } - MFEM_VERIFY(perf || !matrix_free, - "--standard-version is not compatible with --matrix-free"); - if (myid == 0) - { - args.PrintOptions(cout); - } - - PCType pc_choice; - if (!strcmp(pc, "ho")) { pc_choice = HO; } - else if (!strcmp(pc, "lor")) { pc_choice = LOR; } - else if (!strcmp(pc, "none")) { pc_choice = NONE; } - else - { - mfem_error("Invalid Preconditioner specified"); - return 3; - } - - // See class BasisType in fem/fe_coll.hpp for available basis types - int basis = BasisType::GetType(basis_type[0]); - if (myid == 0) - { - cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; - } - // 3. Read the (serial) mesh from the given mesh file on all processors. We - // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface - // and volume meshes with the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - int dim = mesh->Dimension(); - - // 4. Check if the optimized version matches the given mesh - if (perf) - { - if (myid == 0) - { - cout << "High-performance version using integration rule with " - << int_rule_t::qpts << " points ..." << endl; - cout << "Quadrature rule type: " - << (IR_TYPE == 0 ? "Gauss" : "Gauss-Lobatto") << endl; - } - if (!mesh_t::MatchesGeometry(*mesh)) - { - if (myid == 0) - { - cout << "The given mesh does not match the optimized 'geom' parameter.\n" - << "Recompile with suitable 'geom' value." << endl; - } - delete mesh; - MPI_Finalize(); - return 4; - } - else if (!mesh_t::MatchesNodes(*mesh)) - { - if (myid == 0) - { - cout << "Switching the mesh curvature to match the " - << "optimized value (order " << mesh_p << ") ..." << endl; - } - mesh->SetCurvature(mesh_p, false, -1, Ordering::byNODES); - } - } - - // 5. Refine the serial mesh on all processors to increase the resolution. In - // this example we do 'ref_levels' of uniform refinement. We choose - // 'ref_levels' to be the largest number that gives a final mesh with no - // more than 10,000 elements. - { - int ref_levels = - (int)floor(log(10000./mesh->GetNE())/log(2.)/dim); - ref_levels = (ser_ref_levels != -1) ? ser_ref_levels : ref_levels; - for (int l = 0; l < ref_levels; l++) - { - if (myid == 0) - { - cout << "Serial refinement: level " << l << " -> level " << l+1 - << " ..." << flush; - } - mesh->UniformRefinement(); - MPI_Barrier(MPI_COMM_WORLD); - if (myid == 0) - { - cout << " done." << endl; - } - } - } - if (!perf && mesh->NURBSext) - { - const int new_mesh_p = std::min(sol_p, mesh_p); - if (myid == 0) - { - cout << "NURBS mesh: switching the mesh curvature to be " - << "min(sol_p, mesh_p) = " << new_mesh_p << " ..." << endl; - } - mesh->SetCurvature(new_mesh_p, false, -1, Ordering::byNODES); - } - - // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine - // this mesh further in parallel to increase the resolution. Once the - // parallel mesh is defined, the serial mesh can be deleted. - MFEM_VERIFY(nxyz.Size() == 0 || nxyz.Size() == mesh->SpaceDimension(), - "Expected " << mesh->SpaceDimension() << " integers with the " - "option --cartesian-partitioning."); - int *partitioning = nxyz.Size() ? mesh->CartesianPartitioning(nxyz) : NULL; - ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh, partitioning); - delete [] partitioning; - delete mesh; - { - for (int l = 0; l < par_ref_levels; l++) - { - if (myid == 0) - { - cout << "Parallel refinement: level " << l << " -> level " << l+1 - << " ..." << flush; - } - pmesh->UniformRefinement(); - MPI_Barrier(MPI_COMM_WORLD); - if (myid == 0) - { - cout << " done." << endl; - } - } - } - if (pmesh->MeshGenerator() & 1) // simplex mesh - { - MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" - " the LOR preconditioner yet"); - } - - pmesh->PrintInfo(cout); - // 7. Define a parallel finite element space on the parallel mesh. Here we - // use continuous Lagrange finite elements of the specified order. If - // order < 1, we instead use an isoparametric/isogeometric space. - FiniteElementCollection *fec; - if (order > 0) - { - fec = new H1_FECollection(order, dim, basis); - } - else if (pmesh->GetNodes()) - { - fec = pmesh->GetNodes()->OwnFEC(); - if (myid == 0) - { - cout << "Using isoparametric FEs: " << fec->Name() << endl; - } - } - else - { - fec = new H1_FECollection(order = 1, dim, basis); - } - ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec, - vdim, ordering); - HYPRE_Int size = fespace->GlobalTrueVSize(); - if (myid == 0) - { - cout << "Number of finite element unknowns: " << size << endl; - } - - ParMesh *pmesh_lor = NULL; - FiniteElementCollection *fec_lor = NULL; - ParFiniteElementSpace *fespace_lor = NULL; - if (pc_choice == LOR) - { - int basis_lor = basis; - if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } - pmesh_lor = new ParMesh(pmesh, order, basis_lor); - fec_lor = new H1_FECollection(1, dim); - fespace_lor = new ParFiniteElementSpace(pmesh_lor, fec_lor, - vdim, ordering); - } - - // 8. Check if the optimized version matches the given space - if (perf && !sol_fes_t::Matches(*fespace)) - { - if (myid == 0) - { - cout << "The given order does not match the optimized parameter.\n" - << "Recompile with suitable 'sol_p' value." << endl; - } - delete fespace; - delete fec; - delete mesh; - MPI_Finalize(); - return 5; - } - - bp_kernel(num_procs, - size, - myid, - dim, - vdim, - ordering, - order, - static_cond, - perf, - matrix_free, - max_iter, - visualization, - pc_choice, - basis, - true, // simd - geom, - mesh_p, - sol_p, - ir_q, - ir_order, - mesh_file, - pmesh, - fespace, - fespace_lor); - - delete fespace; - delete fespace_lor; - delete fec_lor; - delete pmesh_lor; - if (order > 0) { delete fec; } - - MPI_Finalize(); - - return 0; -} diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index 4eb8d782e6..c0b3ab69a3 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -37,9 +37,9 @@ using namespace std; using namespace mfem; // Define template parameters for optimized build. -const Geometry::Type geom = Geometry::SQUARE; // mesh elements (default: hex) -const int mesh_p = 8; // mesh curvature (default: 3) -const int sol_p = 8; // solution order (default: 3) +const Geometry::Type geom = Geometry::CUBE; // mesh elements (default: hex) +const int mesh_p = 3; // mesh curvature (default: 3) +const int sol_p = 3; // solution order (default: 3) const int rdim = Geometry::Constants::Dimension; const int ir_order = 2*sol_p+rdim-1; @@ -58,16 +58,14 @@ typedef TConstantCoefficient<> coeff_t; typedef TIntegrator integ_t; // Static bilinear form type, combining the above types -typedef TBilinearForm avx_HPCBilinearForm; -typedef TBilinearForm m64_HPCBilinearForm; +typedef TBilinearForm HPCBilinearForm; int main(int argc, char *argv[]) { // 1. Parse command-line options. - const char *mesh_file = "../../data/star.mesh"; + const char *mesh_file = "../../data/fichera.mesh"; int ref_levels = -1; int order = sol_p; - int max_iter = 2000; const char *basis_type = "G"; // Gauss-Lobatto bool static_cond = false; const char *pc = "none"; @@ -135,7 +133,7 @@ int main(int argc, char *argv[]) // the same code. Mesh *mesh = new Mesh(mesh_file, 1, 1); int dim = mesh->Dimension(); - + // 3. Check if the optimized version matches the given mesh if (perf) { @@ -174,16 +172,6 @@ int main(int argc, char *argv[]) MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" " the LOR preconditioner yet"); } - - const int NE = mesh->GetNE(); - AutoImplTraits simd_impl; - const bool simd = (NE > simd_impl.simd_size); - printf("\033[32m[ex1] GetNE()=%d\033[m\n",NE); - if (simd){ - printf("\033[32m[ex1] SIMD!\033[m\n"); - }else{ - printf("\033[32m[ex1] SCALAR!\033[m\n"); - } // 5. Define a finite element space on the mesh. Here we use continuous // Lagrange finite elements of the specified order. If order < 1, we @@ -282,8 +270,7 @@ int main(int argc, char *argv[]) // Pre-allocate sparsity assuming dense element matrices a->UsePrecomputedSparsity(); - avx_HPCBilinearForm *a_hpc_simd = NULL; - m64_HPCBilinearForm *a_hpc_scalar = NULL; + HPCBilinearForm *a_hpc = NULL; Operator *a_oper = NULL; if (!perf) @@ -295,23 +282,14 @@ int main(int argc, char *argv[]) else { // High-performance assembly/evaluation using the templated operator type - if (simd) - a_hpc_simd = new avx_HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - else - a_hpc_scalar = new m64_HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); + a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); if (matrix_free) { - if (simd) - a_hpc_simd->Assemble(); // partial assembly - else - a_hpc_scalar->Assemble(); // partial assembly + a_hpc->Assemble(); // partial assembly } else { - if (simd) - a_hpc_simd->AssembleBilinearForm(*a); // full matrix assembly - else - a_hpc_scalar->AssembleBilinearForm(*a); // full matrix assembly + a_hpc->AssembleBilinearForm(*a); // full matrix assembly } } tic_toc.Stop(); @@ -325,13 +303,8 @@ int main(int argc, char *argv[]) Vector B, X; if (perf && matrix_free) { - if (simd){ - a_hpc_simd->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "Size of linear system: " << a_hpc_simd->Height() << endl; - }else{ - a_hpc_scalar->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "Size of linear system: " << a_hpc_scalar->Height() << endl; - } + a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); + cout << "Size of linear system: " << a_hpc->Height() << endl; } else { @@ -363,10 +336,7 @@ int main(int argc, char *argv[]) else { a_pc->UsePrecomputedSparsity(); - if (simd) - a_hpc_simd->AssembleBilinearForm(*a_pc); - else - a_hpc_scalar->AssembleBilinearForm(*a_pc); + a_hpc->AssembleBilinearForm(*a_pc); a_pc->FormSystemMatrix(ess_tdof_list, A_pc); } } @@ -375,8 +345,6 @@ int main(int argc, char *argv[]) cout << " done, " << tic_toc.RealTime() << "s." << endl; // Solve with CG or PCG, depending if the matrix A_pc is available - tic_toc.Clear(); - tic_toc.Start(); if (pc_choice != NONE) { GSSmoother M(A_pc); @@ -384,37 +352,13 @@ int main(int argc, char *argv[]) } else { - CGSolver *cg; - cg = new CGSolver; - cg->SetRelTol(1e-6); - cg->SetMaxIter(max_iter); - cg->SetPrintLevel(3); - cg->SetOperator(*a_oper); - - tic_toc.Clear(); - tic_toc.Start(); - cg->Mult(B, X); - - double my_rt = tic_toc.RealTime(); - cout << "\nTotal CG time: " << my_rt << " sec." << endl; - cout << "Time per CG step: " - << my_rt / cg->GetNumIterations() << " sec." << endl; - cout << "\n\"DOFs/sec\" in CG: " - << 1e-6*a_oper->Height()*cg->GetNumIterations()/my_rt << " million.\n" - << endl; - delete cg; - //CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); + CG(*a_oper, B, X, 1, 500, 1e-12, 0.0); } - tic_toc.Stop(); - cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; // 13. Recover the solution as a finite element grid function. if (perf && matrix_free) { - if (simd) - a_hpc_simd->RecoverFEMSolution(X, *b, x); - else - a_hpc_scalar->RecoverFEMSolution(X, *b, x); + a_hpc->RecoverFEMSolution(X, *b, x); } else { @@ -442,10 +386,7 @@ int main(int argc, char *argv[]) // 16. Free the used memory. delete a; - if (simd) - delete a_hpc_simd; - else - delete a_hpc_scalar; + delete a_hpc; if (a_oper != &A) { delete a_oper; } delete a_pc; delete b; diff --git a/miniapps/performance/ex1rtc.cpp b/miniapps/performance/ex1rtc.cpp deleted file mode 100644 index 3068fc8af4..0000000000 --- a/miniapps/performance/ex1rtc.cpp +++ /dev/null @@ -1,440 +0,0 @@ -// MFEM Example 1 - High-Performance Version -// -// Compile with: make ex1 -// -// Sample runs: ex1 -m ../../data/fichera.mesh -perf -mf -pc lor -// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho -// ex1 -m ../../data/fichera.mesh -perf -asm -pc ho -sc -// ex1 -m ../../data/fichera.mesh -std -asm -pc ho -// ex1 -m ../../data/fichera.mesh -std -asm -pc ho -sc -// ex1 -m ../../data/amr-hex.mesh -perf -asm -pc ho -sc -// ex1 -m ../../data/amr-hex.mesh -std -asm -pc ho -sc -// ex1 -m ../../data/ball-nurbs.mesh -perf -asm -pc ho -sc -// ex1 -m ../../data/ball-nurbs.mesh -std -asm -pc ho -sc -// ex1 -m ../../data/pipe-nurbs.mesh -perf -mf -pc lor -// ex1 -m ../../data/pipe-nurbs.mesh -std -asm -pc ho -sc -// -// Description: This example code demonstrates the use of MFEM to define a -// simple finite element discretization of the Laplace problem -// -Delta u = 1 with homogeneous Dirichlet boundary conditions. -// Specifically, we discretize using a FE space of the specified -// order, or if order < 1 using an isoparametric/isogeometric -// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for -// NURBS mesh, etc.) -// -// The example highlights the use of mesh refinement, finite -// element grid functions, as well as linear and bilinear forms -// corresponding to the left-hand side and right-hand side of the -// discrete linear system. We also cover the explicit elimination -// of essential boundary conditions, static condensation, and the -// optional connection to the GLVis tool for visualization. - -#include "mfem-performance.hpp" -#include -#include -#include - -using namespace std; -using namespace mfem; - -enum PCType { NONE, LOR, HO }; - -// ***************************************************************************** -// * High-Performance Benchmark Open Kernel -// ***************************************************************************** -void bp_kernel(const Mesh *mesh, - FiniteElementSpace *fespace, - FiniteElementSpace *fespace_lor, - const bool perf, - const int pc_choice, - const bool matrix_free = false, - const bool static_cond = false, - const bool visualization = false, - const int dim = 3, - const int msh_p = 1, - const int sol_p = 1, - const bool simd = true, - const int ir_order = 4, - const Geometry::Type geom = Geometry::CUBE, - const int __kernel = 0){ - // Hack to deal with runtime template instanciation -#ifndef __OKRTC__ -#define GEOM Geometry::CUBE -#define MSH_P 1 -#define SOL_P 1 -#define DIM 3 -#define IR_ORDER (2*SOL_P+DIM-1) -#define SIMD true -#else -#undef GEOM -#define GEOM (Geometry::Type)geom -#undef MSH_P -#define MSH_P msh_p -#undef SOL_P -#define SOL_P sol_p -#undef IR_ORDER -#define IR_ORDER 2*sol_p+dim-1 -#undef SIMD -#define SIMD simd -#endif - // Should be captured while parsing - using namespace std; - using namespace mfem; - enum PCType { NONE, LOR, HO }; - typedef H1_FiniteElement mesh_fe_t; - typedef H1_FiniteElementSpace mesh_fes_t; - typedef TMesh mesh_t; - typedef H1_FiniteElement sol_fe_t; - typedef H1_FiniteElementSpace sol_fes_t; - typedef TIntegrationRule int_rule_t; - typedef TConstantCoefficient<> coeff_t; - typedef TIntegrator integ_t; - typedef TBilinearForm HPCBilinearForm; - - - // 7. Determine the list of true (i.e. conforming) essential boundary dofs. - // In this example, the boundary conditions are defined by marking all - // the boundary attributes from the mesh as essential (Dirichlet) and - // converting them to a list of true dofs. - Array ess_tdof_list; - if (mesh->bdr_attributes.Size()) - { - Array ess_bdr(mesh->bdr_attributes.Max()); - ess_bdr = 1; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - - // 8. Set up the linear form b(.) which corresponds to the right-hand side of - // the FEM linear system, which in this case is (1,phi_i) where phi_i are - // the basis functions in the finite element fespace. - LinearForm *b = new LinearForm(fespace); - ConstantCoefficient one(1.0); - b->AddDomainIntegrator(new DomainLFIntegrator(one)); - b->Assemble(); - - // 9. Define the solution vector x as a finite element grid function - // corresponding to fespace. Initialize x with initial guess of zero, - // which satisfies the boundary conditions. - GridFunction x(fespace); - x = 0.0; - - // 10. Set up the bilinear form a(.,.) on the finite element space that will - // hold the matrix corresponding to the Laplacian operator -Delta. - // Optionally setup a form to be assembled for preconditioning (a_pc). - BilinearForm *a = new BilinearForm(fespace); - BilinearForm *a_pc = NULL; - if (pc_choice == LOR) { a_pc = new BilinearForm(fespace_lor); } - if (pc_choice == HO) { a_pc = new BilinearForm(fespace); } - - // 11. Assemble the bilinear form and the corresponding linear system, - // applying any necessary transformations such as: eliminating boundary - // conditions, applying conforming constraints for non-conforming AMR, - // static condensation, etc. - if (static_cond) - { - a->EnableStaticCondensation(); - MFEM_VERIFY(pc_choice != LOR, - "cannot use LOR preconditioner with static condensation"); - } - - cout << "Assembling the bilinear form ..." << flush; - tic_toc.Clear(); - tic_toc.Start(); - // Pre-allocate sparsity assuming dense element matrices - a->UsePrecomputedSparsity(); - - HPCBilinearForm *a_hpc = NULL; - Operator *a_oper = NULL; - - if (!perf) - { - // Standard assembly using a diffusion domain integrator - a->AddDomainIntegrator(new DiffusionIntegrator(one)); - a->Assemble(); - } - else - { - // High-performance assembly/evaluation using the templated operator type - a_hpc = new HPCBilinearForm(integ_t(coeff_t(1.0)), *fespace); - if (matrix_free) - { - a_hpc->Assemble(); // partial assembly - } - else - { - a_hpc->AssembleBilinearForm(*a); // full matrix assembly - } - } - tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; - - // 12. Solve the system A X = B with CG. In the standard case, use a simple - // symmetric Gauss-Seidel preconditioner. - - // Setup the operator matrix (if applicable) - SparseMatrix A; - Vector B, X; - if (perf && matrix_free) - { - a_hpc->FormLinearSystem(ess_tdof_list, x, *b, a_oper, X, B); - cout << "Size of linear system: " << a_hpc->Height() << endl; - } - else - { - a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cout << "Size of linear system: " << A.Height() << endl; - a_oper = &A; - } - - // Setup the matrix used for preconditioning - cout << "Assembling the preconditioning matrix ..." << flush; - tic_toc.Clear(); - tic_toc.Start(); - - SparseMatrix A_pc; - if (pc_choice == LOR) - { - // TODO: assemble the LOR matrix using the performance code - a_pc->AddDomainIntegrator(new DiffusionIntegrator(one)); - a_pc->UsePrecomputedSparsity(); - a_pc->Assemble(); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - else if (pc_choice == HO) - { - if (!matrix_free) - { - A_pc.MakeRef(A); // matrix already assembled, reuse it - } - else - { - a_pc->UsePrecomputedSparsity(); - a_hpc->AssembleBilinearForm(*a_pc); - a_pc->FormSystemMatrix(ess_tdof_list, A_pc); - } - } - - tic_toc.Stop(); - cout << " done, " << tic_toc.RealTime() << "s." << endl; - - // Solve with CG or PCG, depending if the matrix A_pc is available - tic_toc.Clear(); - tic_toc.Start(); - if (pc_choice != NONE) - { - assert(false); - GSSmoother M(A_pc); - PCG(*a_oper, M, B, X, 1, 500, 1e-12, 0.0); - } - else - { - CG(*a_oper, B, X, 3, 2000, 1e-12, 0.0); - } - tic_toc.Stop(); - cout << "Solve time: " << tic_toc.RealTime() << "s." << endl; - - // 13. Recover the solution as a finite element grid function. - if (perf && matrix_free) - { - a_hpc->RecoverFEMSolution(X, *b, x); - } - else - { - a->RecoverFEMSolution(X, *b, x); - } - - // 14. Save the refined mesh and the solution. This output can be viewed later - // using GLVis: "glvis -m refined.mesh -g sol.gf". - ofstream mesh_ofs("refined.mesh"); - mesh_ofs.precision(8); - mesh->Print(mesh_ofs); - ofstream sol_ofs("sol.gf"); - sol_ofs.precision(8); - x.Save(sol_ofs); - - // 15. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock.precision(8); - sol_sock << "solution\n" << *mesh << x << flush; - } - - // 16. Free the used memory. - delete a; - delete a_pc; - delete b; - if (a_oper != &A) { delete a_oper; } - delete a_hpc; -} - - -// ***************************************************************************** -// * Main driver to ex1 kernel -// ***************************************************************************** -int main(int argc, char *argv[]){ - // 1. Parse command-line options. - const char *mesh_file = "../../data/star.mesh"; - const Geometry::Type geom = Geometry::SQUARE; - int ref_levels = -1; - int order = 1; - int level = -1; - const char *basis_type = "G"; // Gauss-Lobatto - bool static_cond = false; - const char *pc = "none"; - bool perf = true; - bool matrix_free = true; - bool visualization = 1; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&ref_levels, "-r", "--refine", - "Number of times to refine the mesh uniformly;" - " -1 = auto: <= 50,000 elements."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); - args.AddOption(&level, "-l", "--level", "Refinement level"); - args.AddOption(&basis_type, "-b", "--basis-type", - "Basis: G - Gauss-Lobatto, P - Positive, U - Uniform"); - args.AddOption(&perf, "-perf", "--hpc-version", "-std", "--standard-version", - "Enable high-performance, tensor-based, assembly/evaluation."); - args.AddOption(&matrix_free, "-mf", "--matrix-free", "-asm", "--assembly", - "Use matrix-free evaluation or efficient matrix assembly in " - "the high-performance version."); - args.AddOption(&pc, "-pc", "--preconditioner", - "Preconditioner: lor - low-order-refined (matrix-free) GS, " - "ho - high-order (assembled) GS, none."); - args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", - "--no-static-condensation", "Enable static condensation."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - if (!args.Good()) - { - args.PrintUsage(cout); - return 1; - } - if (static_cond && perf && matrix_free) - { - cout << "\nStatic condensation can not be used with matrix-free" - " evaluation!\n" << endl; - return 2; - } - MFEM_VERIFY(perf || !matrix_free, - "--standard-version is not compatible with --matrix-free"); - args.PrintOptions(cout); - - PCType pc_choice; - if (!strcmp(pc, "ho")) { pc_choice = HO; } - else if (!strcmp(pc, "lor")) { pc_choice = LOR; } - else if (!strcmp(pc, "none")) { pc_choice = NONE; } - else - { - mfem_error("Invalid Preconditioner specified"); - return 3; - } - - // See class BasisType in fem/fe_coll.hpp for available basis types - const int basis = BasisType::GetType(basis_type[0]); - cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; - - // 2. Read the mesh from the given mesh file. We can handle triangular, - // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with - // the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - const int dim = mesh->Dimension(); - - // 3. Check if the optimized version matches the given mesh - if (perf) - { - cout << "Switching the mesh curvature to match the " - << "optimized value (order " << order << ") ..." << endl; - mesh->SetCurvature(order, false, -1, Ordering::byNODES); - } - - // 4. Refine the mesh to increase the resolution. In this example we do - // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the - // largest number that gives a final mesh with no more than 50,000 - // elements, or as specified on the command line with the option - // '--refine'. - { - ref_levels = level>0 ? level ://(ref_levels != -1) ? ref_levels : - (int)floor(log(50000./mesh->GetNE())/log(2.)/dim); - for (int l = 0; l < ref_levels; l++) - { - mesh->UniformRefinement(); - } - } - if (mesh->MeshGenerator() & 1) // simplex mesh - { - MFEM_VERIFY(pc_choice != LOR, "triangle and tet meshes do not support" - " the LOR preconditioner yet"); - } - - const int NE = mesh->GetNE(); - AutoImplTraits simd_impl; - const bool simd = (NE > simd_impl.simd_size); - printf("\033[32m[ex1] GetNE()=%d\033[m\n",NE); - if (simd){ - printf("\033[32m[ex1] SIMD!\033[m\n"); - }else{ - printf("\033[32m[ex1] SCALAR!\033[m\n"); - } - - // 5. Define a finite element space on the mesh. Here we use continuous - // Lagrange finite elements of the specified order. If order < 1, we - // instead use an isoparametric/isogeometric space. - FiniteElementCollection *fec; - if (order > 0) - { - fec = new H1_FECollection(order, dim, basis); - } - else if (mesh->GetNodes()) - { - fec = mesh->GetNodes()->OwnFEC(); - cout << "Using isoparametric FEs: " << fec->Name() << endl; - } - else - { - fec = new H1_FECollection(order = 1, dim, basis); - } - FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); - cout << "Number of finite element unknowns: " - << fespace->GetTrueVSize() << endl; - - // Create the LOR mesh and finite element space. In the settings of this - // example, we can transfer between HO and LOR with the identity operator. - Mesh *mesh_lor = NULL; - FiniteElementCollection *fec_lor = NULL; - FiniteElementSpace *fespace_lor = NULL; - if (pc_choice == LOR) - { - int basis_lor = basis; - if (basis == BasisType::Positive) { basis_lor=BasisType::ClosedUniform; } - mesh_lor = new Mesh(mesh, order, basis_lor); - fec_lor = new H1_FECollection(1, dim); - fespace_lor = new FiniteElementSpace(mesh_lor, fec_lor); - } - - // Launch kernel - bp_kernel(mesh, fespace, fespace_lor, - perf, pc_choice, matrix_free, - static_cond, visualization, - dim, order, order, simd, - 2*order+dim-1, geom); - - // 16. Free the used memory. - delete fespace; - delete fespace_lor; - delete fec_lor; - delete mesh_lor; - if (order > 0) { delete fec; } - delete mesh; - - return 0; -} diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 976c1e3f73..817d507605 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -47,17 +47,13 @@ endif # MFEM_PERF_CXXFLAGS_gcc_common += -std=c++03 MFEM_PERF_CXXFLAGS_gcc_common += -std=c++11 MFEM_PERF_CXXFLAGS_gcc_common += -pedantic -Wall -ifeq ($(MFEM_USE_X86INTRIN),NO) +ifeq ($(MFEM_USE_SIMD),NO) MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 endif #MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) -#MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ +MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) -MFEM_PERF_CXXFLAGS_gcc_ppc64 = $(MFEM_PERF_CXXFLAGS_gcc_common) -MFEM_PERF_CXXFLAGS_gcc_ppc64 += -qsimd=auto \ - $(MFEM_PERF_CXXFLAGS_gcc_common) -#$(warning MFEM_PERF_CXXFLAGS_gcc_ppc64=$(MFEM_PERF_CXXFLAGS_gcc_ppc64)) # - Clang extra options: MFEM_PERF_CXXFLAGS_clang += -march=native @@ -72,7 +68,6 @@ MFEM_PERF_CXXFLAGS_clang += -ffp-contract=fast # - Intel C++ compiler extra options: MFEM_PERF_CXXFLAGS_icc += -xHost -# MFEM_PERF_CXXFLAGS_icc += -std=c++03 MFEM_PERF_CXXFLAGS_icc += -std=c++11 # Choose MFEM_PERF_CXXFLAGS based on MFEM_PERF_SW: @@ -101,25 +96,6 @@ endif all: $(MINIAPPS) -ex1rtc:ex1rtc.cpp - dbg=1 okrtc g++ -O3 -march=native -std=c++11 -pedantic -Wall \ - -I/home/camier1/home/mfem/x86 \ - -o ex1rtc ex1rtc.cpp \ - -Wl,-rpath,/home/camier1/home/mfem/x86 \ - -L/home/camier1/home/mfem/x86 -lmfem -lrt - -bprtc: bprtc.cpp - okrtc mpicxx -O3 -march=native -std=c++11 -pedantic -Wall \ - -I/home/camier1/home/mfem/x86/ \ - -I/home/camier1/usr/local/hypre/2.11.2/include \ - -I/home/camier1/usr/local/metis/5.1.0/include \ - -I/home/camier1/usr/local/openmpi/3.0.0/include \ - -o $@ $< \ - -L/home/camier1/home/mfem/x86 -lmfem \ - -L/home/camier1/usr/local/hypre/2.11.2/lib -lHYPRE \ - -L/home/camier1/usr/local/metis/5.1.0/lib -lmetis \ - -lrt - MFEM_TESTS = MINIAPPS include $(MFEM_TEST_MK) From eef8f6ce8eff0c48580784122e3187e7930123da Mon Sep 17 00:00:00 2001 From: "Robert W. Anderson" Date: Tue, 3 Sep 2019 16:28:36 -0700 Subject: [PATCH 036/535] add a facility to map between local and global element numberings --- mesh/mesh.hpp | 10 +++++++++ mesh/pmesh.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++---- mesh/pmesh.hpp | 13 +++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index cb24d69889..f347fd3aef 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -690,6 +690,16 @@ public: /// Utility function: sum integers from all processors (Allreduce). virtual long ReduceInt(int value) const { return value; } + /// Map a global element number to a local element number. (For a + /// serial mesh, the numberings are the same.) + virtual long GetLocalElementNum(long global_element_num) const + { return global_element_num; } + + /// Map a local element number to a global element number. (For a + /// serial mesh, the numberings are the same.) + virtual long GetGlobalElementNum(long local_element_num) const + { return local_element_num; } + /// Return the total (global) number of elements. long GetGlobalNE() const { return ReduceInt(NumOfElements); } diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 8d35b715f4..9bb959ac23 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -34,7 +34,8 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes) group_sedge(pmesh.group_sedge), group_stria(pmesh.group_stria), group_squad(pmesh.group_squad), - gtopo(pmesh.gtopo) + gtopo(pmesh.gtopo), + have_global_element_offset(false) { MyComm = pmesh.MyComm; NRanks = pmesh.NRanks; @@ -92,7 +93,8 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes) ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_, int part_method) - : gtopo(comm) + : gtopo(comm), + have_global_element_offset(false) { int *partitioning = NULL; Array activeBdrElem; @@ -835,12 +837,26 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh) , MyRank(pncmesh.MyRank) , gtopo(MyComm) , pncmesh(NULL) + , have_global_element_offset(false) { Mesh::InitFromNCMesh(pncmesh); ReduceMeshGen(); have_face_nbr_data = false; } +void ParMesh::ComputeGlobalElementOffset() +{ + long local_elems = NumOfElements; + long total_elems = 0; + MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM, MyComm); + + global_element_offset = 0; + MPI_Scan(&local_elems, &global_element_offset, 1, MPI_LONG, MPI_SUM, MyComm); + global_element_offset -= local_elems; + + have_global_element_offset = true; +} + void ParMesh::ReduceMeshGen() { int loc_meshgen = meshgen; @@ -885,7 +901,8 @@ void ParMesh::FinalizeParTopo() } ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) - : gtopo(comm) + : gtopo(comm), + have_global_element_offset(false) { MyComm = comm; MPI_Comm_size(MyComm, &NRanks); @@ -1064,7 +1081,8 @@ ParMesh::ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type) MyRank(orig_mesh->GetMyRank()), gtopo(orig_mesh->gtopo), have_face_nbr_data(false), - pncmesh(NULL) + pncmesh(NULL), + have_global_element_offset(false) { // Need to initialize: // - shared_edges, shared_{trias,quads} @@ -1292,6 +1310,24 @@ void ParMesh::Finalize(bool refine, bool fix_orientation) FinalizeParTopo(); } +int ParMesh::GetLocalElementNum(long global_element_num) +{ + if (!have_global_element_offset) { + ComputeGlobalElementOffset(); + } + int local = global_element_num -global_element_offset; + if (local < 0 || local >= NumOfElements) return -1; + return local; +} + +long ParMesh::GetGlobalElementNum(int local_element_num) +{ + if (!have_global_element_offset) { + ComputeGlobalElementOffset(); + } + return global_element_offset +local_element_num; +} + void ParMesh::GroupEdge(int group, int i, int &edge, int &o) { int sedge = group_sedge.GetRow(group-1)[i]; @@ -2475,6 +2511,8 @@ void ParMesh::LocalRefinement(const Array &marked_el, int type) MFEM_ABORT("Local and nonconforming refinements cannot be mixed."); } + have_global_element_offset = false; + DeleteFaceNbrData(); InitRefinementTransforms(); @@ -2988,6 +3026,8 @@ void ParMesh::NonconformingRefinement(const Array &refinements, "serial Mesh)"); } + have_global_element_offset = false; + DeleteFaceNbrData(); // NOTE: no check of !refinements.Size(), in parallel we would have to reduce @@ -3031,6 +3071,8 @@ bool ParMesh::NonconformingDerefinement(Array &elem_error, MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. " "Project the NURBS to Nodes first."); + have_global_element_offset = false; + const Table &dt = pncmesh->GetDerefinementTable(); pncmesh->SynchronizeDerefinementData(elem_error, dt); @@ -3107,6 +3149,8 @@ void ParMesh::Rebalance() Nodes = new_nodes; } + have_global_element_offset = false; + DeleteFaceNbrData(); pncmesh->Rebalance(); @@ -3589,6 +3633,8 @@ void ParMesh::UniformRefineGroups3D(int old_nv, int old_nedges, void ParMesh::UniformRefinement2D() { + have_global_element_offset = false; + DeleteFaceNbrData(); const int old_nv = NumOfVertices; @@ -3609,6 +3655,8 @@ void ParMesh::UniformRefinement2D() void ParMesh::UniformRefinement3D() { + have_global_element_offset = false; + DeleteFaceNbrData(); const int old_nv = NumOfVertices; @@ -3640,6 +3688,8 @@ void ParMesh::UniformRefinement3D() void ParMesh::NURBSUniformRefinement() { + have_global_element_offset = false; + if (MyRank == 0) { mfem::out << "\nParMesh::NURBSUniformRefinement : Not supported yet!\n"; diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 1c3fbd6ac5..07b4c3f5e4 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -38,6 +38,12 @@ protected: MPI_Comm MyComm; int NRanks, MyRank; + /// global_element_offset + local element number defines a global + /// numbering for elements + void ComputeGlobalElementOffset(); + bool have_global_element_offset; + long global_element_offset; + struct Vert3 { int v[3]; @@ -224,6 +230,13 @@ public: int GetNRanks() const { return NRanks; } int GetMyRank() const { return MyRank; } + /// Map a global element number to a local element number. If the + /// global element is not on this processor, return -1. + int GetLocalElementNum(long global_element_num); + + /// Map a local element number to a global element number. + long GetGlobalElementNum(int local_element_num); + GroupTopology gtopo; // Face-neighbor elements and vertices From a953f6ee2a4d34f117f9bb93f09418cd196ac765 Mon Sep 17 00:00:00 2001 From: "Robert W. Anderson" Date: Tue, 3 Sep 2019 16:45:24 -0700 Subject: [PATCH 037/535] make translation functions const (even though they have mutable internal cached state) --- mesh/mesh.hpp | 2 +- mesh/pmesh.cpp | 6 +++--- mesh/pmesh.hpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index f347fd3aef..640c8f49ad 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -692,7 +692,7 @@ public: /// Map a global element number to a local element number. (For a /// serial mesh, the numberings are the same.) - virtual long GetLocalElementNum(long global_element_num) const + virtual int GetLocalElementNum(long global_element_num) const { return global_element_num; } /// Map a local element number to a global element number. (For a diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 9bb959ac23..09e834e582 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -844,7 +844,7 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh) have_face_nbr_data = false; } -void ParMesh::ComputeGlobalElementOffset() +void ParMesh::ComputeGlobalElementOffset() const { long local_elems = NumOfElements; long total_elems = 0; @@ -1310,7 +1310,7 @@ void ParMesh::Finalize(bool refine, bool fix_orientation) FinalizeParTopo(); } -int ParMesh::GetLocalElementNum(long global_element_num) +int ParMesh::GetLocalElementNum(long global_element_num) const { if (!have_global_element_offset) { ComputeGlobalElementOffset(); @@ -1320,7 +1320,7 @@ int ParMesh::GetLocalElementNum(long global_element_num) return local; } -long ParMesh::GetGlobalElementNum(int local_element_num) +long ParMesh::GetGlobalElementNum(int local_element_num) const { if (!have_global_element_offset) { ComputeGlobalElementOffset(); diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 07b4c3f5e4..047e4f9db0 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -40,9 +40,9 @@ protected: /// global_element_offset + local element number defines a global /// numbering for elements - void ComputeGlobalElementOffset(); - bool have_global_element_offset; - long global_element_offset; + void ComputeGlobalElementOffset() const; + mutable bool have_global_element_offset; + mutable long global_element_offset; struct Vert3 { @@ -232,10 +232,10 @@ public: /// Map a global element number to a local element number. If the /// global element is not on this processor, return -1. - int GetLocalElementNum(long global_element_num); + int GetLocalElementNum(long global_element_num) const; /// Map a local element number to a global element number. - long GetGlobalElementNum(int local_element_num); + long GetGlobalElementNum(int local_element_num) const; GroupTopology gtopo; From 31cc6f47f2f9fee33d2484c530004fa1bde1ee4b Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 23 Sep 2019 10:07:38 -0700 Subject: [PATCH 038/535] WIN32: posix_memalign => _aligned_malloc --- fem/tbilinearform.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 6a57bb5038..de27e9b631 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -20,6 +20,10 @@ #include "tcoefficient.hpp" #include "fespace.hpp" +#ifdef _WIN32 +#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 +#endif + namespace mfem { From 94a91e2f5e7ff883322782d27fea08b6ccc17349 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 23 Sep 2019 14:56:00 -0700 Subject: [PATCH 039/535] Typo fix --- fem/tbilinearform.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index de27e9b631..6a1f2be901 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -21,7 +21,7 @@ #include "fespace.hpp" #ifdef _WIN32 -#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 +#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0) #endif namespace mfem From 1642001d2da862c253980253c368d7d855d38f1d Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 23 Sep 2019 18:51:56 -0700 Subject: [PATCH 040/535] Win32 posix_memalign logic --- fem/tbilinearform.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 6a1f2be901..760966bf63 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -202,8 +202,8 @@ public: { void* result; const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); - const auto alloc_failed = posix_memalign(&result, 32, size); - if (alloc_failed) { throw ::std::bad_alloc(); } + posix_memalign(&result, 32, size); + if (!result) { throw ::std::bad_alloc(); } assembled_data = (p_assembled_t*) result; } for (int el = 0; el < NE; el += TE) From 244a59d7ade981cb1b6d5f3563279daa8ea7384e Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 24 Sep 2019 09:21:40 -0700 Subject: [PATCH 041/535] _WIN32 posix_memalign _aligned_malloc macro --- fem/tbilinearform.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 760966bf63..3303d2b138 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -21,7 +21,7 @@ #include "fespace.hpp" #ifdef _WIN32 -#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0) +#define posix_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno) #endif namespace mfem From 3e8acd547c4afa62bf050ac0efc31135efdf332f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C4=8Cerven=C3=BD?= Date: Thu, 7 Nov 2019 15:54:52 +0100 Subject: [PATCH 042/535] Refactored, removed the "have_" flag. --- mesh/pmesh.cpp | 66 ++++++++++++++++++++------------------------------ mesh/pmesh.hpp | 14 +++++------ 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 09e834e582..b70819180a 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -34,8 +34,9 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes) group_sedge(pmesh.group_sedge), group_stria(pmesh.group_stria), group_squad(pmesh.group_squad), - gtopo(pmesh.gtopo), - have_global_element_offset(false) + glob_elem_offset(-1), + glob_offset_sequence(-1), + gtopo(pmesh.gtopo) { MyComm = pmesh.MyComm; NRanks = pmesh.NRanks; @@ -93,8 +94,9 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes) ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_, int part_method) - : gtopo(comm), - have_global_element_offset(false) + : glob_elem_offset(-1) + , glob_offset_sequence(-1) + , gtopo(comm) { int *partitioning = NULL; Array activeBdrElem; @@ -835,9 +837,10 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh) : MyComm(pncmesh.MyComm) , NRanks(pncmesh.NRanks) , MyRank(pncmesh.MyRank) + , glob_elem_offset(-1) + , glob_offset_sequence(-1) , gtopo(MyComm) , pncmesh(NULL) - , have_global_element_offset(false) { Mesh::InitFromNCMesh(pncmesh); ReduceMeshGen(); @@ -846,15 +849,14 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh) void ParMesh::ComputeGlobalElementOffset() const { - long local_elems = NumOfElements; - long total_elems = 0; - MPI_Allreduce(&local_elems, &total_elems, 1, MPI_LONG, MPI_SUM, MyComm); + if (glob_offset_sequence != sequence) // mesh has changed + { + long local_elems = NumOfElements; + MPI_Scan(&local_elems, &glob_elem_offset, 1, MPI_LONG, MPI_SUM, MyComm); + glob_elem_offset -= local_elems; - global_element_offset = 0; - MPI_Scan(&local_elems, &global_element_offset, 1, MPI_LONG, MPI_SUM, MyComm); - global_element_offset -= local_elems; - - have_global_element_offset = true; + glob_offset_sequence = sequence; // don't recalculate until refinement etc. + } } void ParMesh::ReduceMeshGen() @@ -901,8 +903,9 @@ void ParMesh::FinalizeParTopo() } ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) - : gtopo(comm), - have_global_element_offset(false) + : glob_elem_offset(-1) + , glob_offset_sequence(-1) + , gtopo(comm) { MyComm = comm; MPI_Comm_size(MyComm, &NRanks); @@ -1079,10 +1082,11 @@ ParMesh::ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type) MyComm(orig_mesh->GetComm()), NRanks(orig_mesh->GetNRanks()), MyRank(orig_mesh->GetMyRank()), + glob_elem_offset(-1), + glob_offset_sequence(-1), gtopo(orig_mesh->gtopo), have_face_nbr_data(false), - pncmesh(NULL), - have_global_element_offset(false) + pncmesh(NULL) { // Need to initialize: // - shared_edges, shared_{trias,quads} @@ -1312,20 +1316,16 @@ void ParMesh::Finalize(bool refine, bool fix_orientation) int ParMesh::GetLocalElementNum(long global_element_num) const { - if (!have_global_element_offset) { - ComputeGlobalElementOffset(); - } - int local = global_element_num -global_element_offset; - if (local < 0 || local >= NumOfElements) return -1; + ComputeGlobalElementOffset(); + long local = global_element_num - glob_elem_offset; + if (local < 0 || local >= NumOfElements) { return -1; } return local; } long ParMesh::GetGlobalElementNum(int local_element_num) const { - if (!have_global_element_offset) { - ComputeGlobalElementOffset(); - } - return global_element_offset +local_element_num; + ComputeGlobalElementOffset(); + return glob_elem_offset + local_element_num; } void ParMesh::GroupEdge(int group, int i, int &edge, int &o) @@ -2511,8 +2511,6 @@ void ParMesh::LocalRefinement(const Array &marked_el, int type) MFEM_ABORT("Local and nonconforming refinements cannot be mixed."); } - have_global_element_offset = false; - DeleteFaceNbrData(); InitRefinementTransforms(); @@ -3026,8 +3024,6 @@ void ParMesh::NonconformingRefinement(const Array &refinements, "serial Mesh)"); } - have_global_element_offset = false; - DeleteFaceNbrData(); // NOTE: no check of !refinements.Size(), in parallel we would have to reduce @@ -3071,8 +3067,6 @@ bool ParMesh::NonconformingDerefinement(Array &elem_error, MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. " "Project the NURBS to Nodes first."); - have_global_element_offset = false; - const Table &dt = pncmesh->GetDerefinementTable(); pncmesh->SynchronizeDerefinementData(elem_error, dt); @@ -3149,8 +3143,6 @@ void ParMesh::Rebalance() Nodes = new_nodes; } - have_global_element_offset = false; - DeleteFaceNbrData(); pncmesh->Rebalance(); @@ -3633,8 +3625,6 @@ void ParMesh::UniformRefineGroups3D(int old_nv, int old_nedges, void ParMesh::UniformRefinement2D() { - have_global_element_offset = false; - DeleteFaceNbrData(); const int old_nv = NumOfVertices; @@ -3655,8 +3645,6 @@ void ParMesh::UniformRefinement2D() void ParMesh::UniformRefinement3D() { - have_global_element_offset = false; - DeleteFaceNbrData(); const int old_nv = NumOfVertices; @@ -3688,8 +3676,6 @@ void ParMesh::UniformRefinement3D() void ParMesh::NURBSUniformRefinement() { - have_global_element_offset = false; - if (MyRank == 0) { mfem::out << "\nParMesh::NURBSUniformRefinement : Not supported yet!\n"; diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 047e4f9db0..5f9d2ca8f9 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -38,12 +38,6 @@ protected: MPI_Comm MyComm; int NRanks, MyRank; - /// global_element_offset + local element number defines a global - /// numbering for elements - void ComputeGlobalElementOffset() const; - mutable bool have_global_element_offset; - mutable long global_element_offset; - struct Vert3 { int v[3]; @@ -84,6 +78,10 @@ protected: // sface ids: all triangles first, then all quads Array sface_lface; + // glob_elem_offset + local element number defines a global element numbering + mutable long glob_elem_offset, glob_offset_sequence; + void ComputeGlobalElementOffset() const; + /// Create from a nonconforming mesh. ParMesh(const ParNCMesh &pncmesh); @@ -230,8 +228,8 @@ public: int GetNRanks() const { return NRanks; } int GetMyRank() const { return MyRank; } - /// Map a global element number to a local element number. If the - /// global element is not on this processor, return -1. + /** Map a global element number to a local element number. If the + global element is not on this processor, return -1. */ int GetLocalElementNum(long global_element_num) const; /// Map a local element number to a global element number. From e24b839f228223e58687cbee2110872ce96c82f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C4=8Cerven=C3=BD?= Date: Thu, 7 Nov 2019 15:57:18 +0100 Subject: [PATCH 043/535] Added 'virtual' to the ParMesh overrrides. --- mesh/pmesh.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 5f9d2ca8f9..8535afcea6 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -230,10 +230,10 @@ public: /** Map a global element number to a local element number. If the global element is not on this processor, return -1. */ - int GetLocalElementNum(long global_element_num) const; + virtual int GetLocalElementNum(long global_element_num) const; /// Map a local element number to a global element number. - long GetGlobalElementNum(int local_element_num) const; + virtual long GetGlobalElementNum(int local_element_num) const; GroupTopology gtopo; From 52a7ea01dadc25147287cbe3c66a65caecf82c36 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 15 Dec 2019 23:33:52 -0800 Subject: [PATCH 044/535] Adding and populating an ElementType data member in ElementTransformation class --- fem/eltrans.hpp | 10 +++++++++- mesh/mesh.cpp | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index ed0550baeb..bb81f21156 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -46,7 +46,15 @@ protected: const DenseMatrix &EvalInverseJ(); public: - int Attribute, ElementNo; + enum IndexType + { + ELEMENT = 1, + BDR_ELEMENT = 2, + EDGE = 3, + FACE = 4 + }; + + int Attribute, ElementNo, ElementType; ElementTransformation(); diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index b8ed54a376..df70cceb71 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -337,6 +337,7 @@ void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr) { ElTr->Attribute = GetAttribute(i); ElTr->ElementNo = i; + ElTr->ElementType = ElementTransformation::ELEMENT; if (Nodes == NULL) { GetPointMatrix(i, ElTr->GetPointMat()); @@ -368,6 +369,7 @@ void Mesh::GetElementTransformation(int i, const Vector &nodes, { ElTr->Attribute = GetAttribute(i); ElTr->ElementNo = i; + ElTr->ElementType = ElementTransformation::ELEMENT; DenseMatrix &pm = ElTr->GetPointMat(); if (Nodes == NULL) { @@ -421,6 +423,7 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr) { ElTr->Attribute = GetBdrAttribute(i); ElTr->ElementNo = i; // boundary element number + ElTr->ElementType = ElementTransformation::BDR_ELEMENT; DenseMatrix &pm = ElTr->GetPointMat(); if (Nodes == NULL) { @@ -476,6 +479,7 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr) { FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute(); FTr->ElementNo = FaceNo; + FTr->ElementType = ElementTransformation::FACE; DenseMatrix &pm = FTr->GetPointMat(); if (Nodes == NULL) { @@ -557,6 +561,7 @@ void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr) EdTr->Attribute = 1; EdTr->ElementNo = EdgeNo; + EdTr->ElementType = ElementTransformation::EDGE; DenseMatrix &pm = EdTr->GetPointMat(); if (Nodes == NULL) { @@ -939,6 +944,8 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) } tr = GetFaceElementTransformations(fn); tr->Face->Attribute = boundary[BdrElemNo]->GetAttribute(); + tr->Face->ElementNo = BdrElemNo; + tr->Face->ElementType = ElementTransformation::BDR_ELEMENT; return tr; } From 37408efcaedbbcf9cf6def9f89382fb7e4c020ed Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 15 Dec 2019 23:34:49 -0800 Subject: [PATCH 045/535] Adding convenience methods to FaceElementTransformations class --- fem/eltrans.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ fem/eltrans.hpp | 13 +++++++ 2 files changed, 114 insertions(+) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index b6552a3409..4ef407eaee 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -536,4 +536,105 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1, } } +int FaceElementTransformations::SetActiveSide(int s) +{ + int dir; + + if (s == 2) // automatic choice of side + { + if (Elem1 && Elem2) + { + dir = (Elem1->Attribute <= Elem2->Attribute) ? 0 : 1; + } + else if (Elem1) + { + dir = 0; + } + else if (Elem2) + { + dir = 1; + } + else + { + MFEM_ABORT("FaceElementTransformation: both Elem1 and Elem2 are NULL. " + "Automatic side selection failed!"); + } + } + else + { + if (s == 0 && Elem1) + { + dir = 0; + } + else if (s == 1 && Elem2) + { + dir = 1; + } + else + { + MFEM_ABORT("FaceElementTransformation: the ElementTransformation " + "for the requested side is NULL."); + } + } + side = dir; + + return dir; +} + +ElementTransformation * +FaceElementTransformations::GetActiveElementTransformation() +{ + if (side == 0) + { + return Elem1; + } + else if (side == 1) + { + return Elem2; + } + + // Automatic selection has not yet occured. + SetActiveSide(2); + return GetActiveElementTransformation(); +} + +IntegrationPointTransformation * +FaceElementTransformations::GetActivePointTransformation() +{ + if (side == 0) + { + return &Loc1; + } + else if (side == 1) + { + return &Loc2; + } + + // Automatic selection has not yet occured. + SetActiveSide(2); + return GetActivePointTransformation(); +} + +void FaceElementTransformations::Transform(const IntegrationPoint &ip, + Vector &tr) +{ + IntegrationPoint eip; + GetActivePointTransformation()->Transform(ip, eip); + + ElementTransformation * T = GetActiveElementTransformation(); + T->SetIntPoint(&eip); + T->Transform(eip, tr); +} + +void FaceElementTransformations::Transform(const IntegrationRule &ir, + DenseMatrix &tr) +{ + IntegrationRule eir; + eir.SetSize(ir.GetNPoints()); + GetActivePointTransformation()->Transform(ir, eir); + + ElementTransformation * T = GetActiveElementTransformation(); + T->Transform(eir, tr); +} + } diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index bb81f21156..2a79b2e4ca 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -351,10 +351,23 @@ public: class FaceElementTransformations { +private: + int side; + public: int Elem1No, Elem2No, FaceGeom; ElementTransformation *Elem1, *Elem2, *Face; IntegrationPointTransformation Loc1, Loc2; + + FaceElementTransformations() : side(2) {} + + int SetActiveSide(int s); + int GetActiveSide() const { return side; } + + ElementTransformation * GetActiveElementTransformation(); + IntegrationPointTransformation * GetActivePointTransformation(); + void Transform(const IntegrationPoint &, Vector &); + void Transform(const IntegrationRule &, DenseMatrix &); }; /* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) From d8ed4d4cd2f8c4f3943fc2499e30c00af9495fde Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 15 Dec 2019 23:35:58 -0800 Subject: [PATCH 046/535] Adding GridFunction::GetValue methods that take transformation objects rather than simple indices --- fem/gridfunc.cpp | 110 +++++++++++++++++++++++++++++++++++++++++++++-- fem/gridfunc.hpp | 38 +++++++++++++--- 2 files changed, 138 insertions(+), 10 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index b243b071f3..d03f8e3c2b 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -524,7 +524,7 @@ int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir, return dir; } - +/* void GridFunction::GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals) const @@ -578,6 +578,106 @@ void GridFunction::GetVectorValues(int i, const IntegrationRule &ir, GetVectorValues(*Tr, ir, vals); } +*/ +double GridFunction::GetValue(ElementTransformation &T, + const IntegrationPoint &ip, + int comp, Vector *tr) const +{ + if (tr) + { + T.SetIntPoint(&ip); + T.Transform(ip, *tr); + } + Array dofs; + const FiniteElement * fe = NULL; + if (T.ElementType == ElementTransformation::ELEMENT) + { + fes->GetElementDofs(T.ElementNo, dofs); + fe = fes->GetFE(T.ElementNo); + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + fes->GetBdrElementDofs(T.ElementNo, dofs); + fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field called in a non-DG context. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + return GetValue(*FET, ip, comp); + } + } + fes->DofsToVDofs(comp-1, dofs); + Vector DofVal(dofs.Size()), LocVec; + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); + fe->CalcShape(ip, DofVal); + GetSubVector(dofs, LocVec); + + return (DofVal * LocVec); +} + +double GridFunction::GetValue(FaceElementTransformations &FET, + const IntegrationPoint &ip, + int comp, Vector *tr) const +{ + ElementTransformation * T = FET.GetActiveElementTransformation(); + + IntegrationPoint eip; + FET.GetActivePointTransformation()->Transform(ip, eip); + + return GetValue(*T, eip, comp, tr); +} + +void GridFunction::GetVectorValues(ElementTransformation &T, + const IntegrationRule &ir, + DenseMatrix &vals, + DenseMatrix *tr) const +{ + if (tr) + { + T.Transform(ir, *tr); + } + const FiniteElement *FElem = fes->GetFE(T.ElementNo); + int dof = FElem->GetDof(); + Array vdofs; + fes->GetElementVDofs(T.ElementNo, vdofs); + Vector loc_data; + GetSubVector(vdofs, loc_data); + int nip = ir.GetNPoints(); + if (FElem->GetRangeType() == FiniteElement::SCALAR) + { + MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + Vector shape(dof); + int vdim = fes->GetVDim(); + vals.SetSize(vdim, nip); + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + FElem->CalcShape(ip, shape); + for (int k = 0; k < vdim; k++) + { + vals(k,j) = shape * ((const double *)loc_data + dof * k); + } + } + } + else + { + int spaceDim = fes->GetMesh()->SpaceDimension(); + DenseMatrix vshape(dof, spaceDim); + vals.SetSize(spaceDim, nip); + Vector val_j; + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + T.SetIntPoint(&ip); + FElem->CalcVShape(T, vshape); + vals.GetColumnReference(j, val_j); + vshape.MultTranspose(loc_data, val_j); + } + } +} int GridFunction::GetFaceVectorValues( int i, int side, const IntegrationRule &ir, @@ -610,13 +710,13 @@ int GridFunction::GetFaceVectorValues( { Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4); Transf->Loc1.Transform(ir, eir); - GetVectorValues(Transf->Elem1No, eir, vals, tr); + GetVectorValues(*Transf->Elem1, eir, vals, &tr); } else { Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8); Transf->Loc2.Transform(ir, eir); - GetVectorValues(Transf->Elem2No, eir, vals, tr); + GetVectorValues(*Transf->Elem2, eir, vals, &tr); } return di; @@ -2686,7 +2786,9 @@ void GridFunction::SaveVTK(std::ostream &out, const std::string &field_name, RefG = GlobGeometryRefiner.Refine( mesh->GetElementBaseGeometry(i), ref, 1); - GetVectorValues(i, RefG->RefPts, vval, pmat); + // GetVectorValues(i, RefG->RefPts, vval, pmat); + ElementTransformation * T = mesh->GetElementTransformation(i); + GetVectorValues(*T, RefG->RefPts, vval, &pmat); for (int j = 0; j < vval.Width(); j++) { diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 39f520460b..72ceea7893 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -154,16 +154,42 @@ public: int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim = 1) const; + /* + void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, + DenseMatrix &vals) const; - void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, - DenseMatrix &vals) const; - - void GetVectorValues(int i, const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix &tr) const; - + void GetVectorValues(int i, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix &tr) const; + */ int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const; + double GetValue(ElementTransformation &T, const IntegrationPoint &ip, + int comp = 0, Vector *tr = NULL) const; + + double GetValue(FaceElementTransformations &T, const IntegrationPoint &ip, + int comp = 0, Vector *tr = NULL) const; + + void GetValues(ElementTransformation &T, const IntegrationRule &ir, + Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; + + void GetValues(FaceElementTransformations &T, const IntegrationRule &ir, + Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; + + void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, + Vector &val, Vector *tr = NULL) const; + + void GetVectorValue(FaceElementTransformations &T, + const IntegrationPoint &ip, + Vector &val, Vector *tr = NULL) const; + + void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix *tr = NULL) const; + + void GetVectorValues(FaceElementTransformations &T, + const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix *tr = NULL) const; + void GetValuesFrom(const GridFunction &orig_func); void GetBdrValuesFrom(const GridFunction &orig_func); From 35f82a4c9ddbc5fd98d4858d9099c6dcb6fed0fb Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 15 Dec 2019 23:37:05 -0800 Subject: [PATCH 047/535] Adding GridFunctionCoefficient::Eval method using FaceElementTransformations object --- fem/coefficient.cpp | 8 +++++++- fem/coefficient.hpp | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 4bf36c4fc9..2524ded388 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -49,7 +49,13 @@ double FunctionCoefficient::Eval(ElementTransformation & T, double GridFunctionCoefficient::Eval (ElementTransformation &T, const IntegrationPoint &ip) { - return GridF -> GetValue (T.ElementNo, ip, Component); + return GridF -> GetValue (T, ip, Component); +} + +double GridFunctionCoefficient::Eval (FaceElementTransformations &T, + const IntegrationPoint &ip) +{ + return GridF -> GetValue (T, ip, Component); } double TransformedCoefficient::Eval(ElementTransformation &T, diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 4a8e8336cc..6d82ac6e97 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -179,6 +179,8 @@ public: virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); + virtual double Eval(FaceElementTransformations &T, + const IntegrationPoint &ip); }; class TransformedCoefficient : public Coefficient From 41764a6c64b76cfd894429756251591a9da516c5 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 15 Dec 2019 23:38:00 -0800 Subject: [PATCH 048/535] Adding draft of test program for new GridFunctionCoefficient::Eval methods --- examples/test_gfc.cpp | 431 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 examples/test_gfc.cpp diff --git a/examples/test_gfc.cpp b/examples/test_gfc.cpp new file mode 100644 index 0000000000..b07bc8b221 --- /dev/null +++ b/examples/test_gfc.cpp @@ -0,0 +1,431 @@ +#include "mfem.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +double func(const Vector &x) { return x[0] + 2.0 * x[1]; } + +int main(int argc, char *argv[]) +{ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + // 2. Parse command-line options. + const char *mesh_file = "../data/star.mesh"; + int order = 1; + int ser_ref_levels = 0; + int par_ref_levels = 0; + int log = 0; + bool dg = false; + bool di = true; // Domain Integration + bool bi = true; // Boundary Integration + bool fi = true; // Interior Face Integration + bool bfi = true; // Boundary Face Integration + bool visualization = true; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", + "Number of times to refine the mesh uniformly in serial."); + args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", + "Number of times to refine the mesh uniformly in parallel."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&log, "-l", "--log", + "Adjust level of screen output."); + args.AddOption(&dg, "-dg", "--discontinuous-galerkin", "-h1", + "--continuous", "Select H1 or DG space."); + args.AddOption(&di, "-di", "--domain-integration", "-no-di", + "--no-domain-integration", + "Enable or disable domain integration test."); + args.AddOption(&bi, "-bi", "--boundary-integration", "-no-bi", + "--no-boundary-integration", + "Enable or disable boundary integration test."); + args.AddOption(&fi, "-fi", "--face-integration", "-no-fi", + "--no-face-integration", + "Enable or disable interior face integration test."); + args.AddOption(&bfi, "-bfi", "--bdr-face-integration", "-no-bfi", + "--no-bdr-face-integration", + "Enable or disable boundary face integration test."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + if (myid == 0) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + if (myid == 0) + { + args.PrintOptions(cout); + } + + // 4. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 5. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 10,000 elements. + { + for (int l = 0; l < ser_ref_levels; l++) + { + mesh->UniformRefinement(); + } + } + + // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + { + for (int l = 0; l < par_ref_levels; l++) + { + pmesh->UniformRefinement(); + } + } + + // 7. Define a parallel finite element space on the parallel mesh. Here we + // use continuous Lagrange finite elements of the specified order. If + // order < 1, we instead use an isoparametric/isogeometric space. + FiniteElementCollection *h1_fec; + FiniteElementCollection *dg_fec; + h1_fec = new H1_FECollection(order, dim); + dg_fec = new DG_FECollection(order, dim); + + ParFiniteElementSpace *h1_fespace = new ParFiniteElementSpace(pmesh, h1_fec); + ParFiniteElementSpace *dg_fespace = new ParFiniteElementSpace(pmesh, dg_fec); + + ParFiniteElementSpace *fespace = dg ? dg_fespace : h1_fespace; + HYPRE_Int size = fespace->GlobalTrueVSize(); + if (myid == 0) + { + cout << "Number of finite element unknowns: " << size << endl; + } + + // 10. Define the solution vector x as a parallel finite element grid function + // corresponding to fespace. Initialize x with initial guess of zero, + // which satisfies the boundary conditions. + ParGridFunction x(fespace); + FunctionCoefficient coef(func); + x.ProjectCoefficient(coef); + + GridFunctionCoefficient xCoef(&x); + + double tol = 1e-6; + int npts = 0; + + if (di) + { + // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm + // Domain Integrators and GridFunction::ProjectCoefficient. + cout << "Checking " << pmesh->GetNE() + << " elements in a non-DG context" << endl; + for (int i=0; iGetNE(); i++) + { + ElementTransformation *T = h1_fespace->GetElementTransformation(i); + const FiniteElement *fe = h1_fespace->GetFE(i); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func(tip); + double gf_val = xCoef.Eval(*T, ip); + + if (fabs(f_val - gf_val) > tol) + { + cout << f_val << " " << gf_val << endl; + } + } + } + cout << "Checked " << npts << " points within elements" << endl; + + // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm + // Domain Integrators and GridFunction::ProjectCoefficient. + npts = 0; + cout << "Checking " << pmesh->GetNE() + << " elements in a DG context" << endl; + for (int i=0; iGetNE(); i++) + { + ElementTransformation *T = dg_fespace->GetElementTransformation(i); + const FiniteElement *fe = dg_fespace->GetFE(i); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func(tip); + double gf_val = xCoef.Eval(*T, ip); + + if (fabs(f_val - gf_val) > tol) + { + cout << f_val << " " << gf_val << endl; + } + } + } + cout << "Checked " << npts << " points within elements" << endl; + } + + if (bi) + { + // Testing Coefficient::Eval as it appears in Bilinear- and LinearForm + // Boundary Integrators and GridFunction::ProjectBdrCoefficient* methods. + npts = 0; + cout << "Checking " << pmesh->GetNBE() + << " boundary elements in a non-DG context" << endl; + for (int i=0; iGetNBE(); i++) + { + ElementTransformation *T = h1_fespace->GetBdrElementTransformation(i); + const FiniteElement *fe = h1_fespace->GetBE(i); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func(tip); + double gf_val = xCoef.Eval(*T, ip); + + if (fabs(f_val - gf_val) > tol) + { + cout << f_val << " " << gf_val << endl; + } + } + } + cout << "Checked " << npts << " points within boundary elements" << endl; + } + + if (fi) + { + // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm + // Face Integrators + npts = 0; + cout << "Checking " << pmesh->GetNumFaces() + << " faces in a DG context" << endl; + for (int i=0; iGetNumFaces(); i++) + { + if (log > 0) { cout << "Getting trans for face " << i << endl; } + FaceElementTransformations *T = + pmesh->GetInteriorFaceTransformations(i); + if (T != NULL) + { + const IntegrationRule &ir = IntRules.Get(T->FaceGeom, 2*order + 2); + + if (log > 0) + { + cout << i << " " << T->Elem1No + << " " << T->Elem2No << endl; + } + + double tip_data[3]; + double tip1_data[3]; + double tip2_data[3]; + Vector tip(tip_data, 3); + Vector tip1(tip1_data, 3); + Vector tip2(tip2_data, 3); + for (int j=0; jLoc1.Transform(ip, eip1); + T->Loc2.Transform(ip, eip2); + + double gf_val1 = NAN; + double gf_val2 = NAN; + + if (T->Elem1) + { + T->Elem1->SetIntPoint(&eip1); + T->Elem1->Transform(eip1, tip1); + gf_val1 = xCoef.Eval(*T->Elem1, eip1); + if (log > 0) + { + cout << "Elem1 (" << tip1[0] << "," << tip1[1] << "," + << tip1[2] << ") -> " << gf_val1 << endl; + } + } + if (T->Elem2) + { + T->Elem2->SetIntPoint(&eip2); + T->Elem2->Transform(eip2, tip2); + gf_val2 = xCoef.Eval(*T->Elem2, eip2); + if (log > 0) + { + cout << "Elem2 (" << tip2[0] << "," << tip2[1] << "," + << tip2[2] << ") -> " << gf_val2 << endl; + } + } + + if (T->Face) + { + T->Face->SetIntPoint(&ip); + T->Face->Transform(ip, tip); + } + + double f_val = func(tip); + // double gf_val = (T->Face) ? xCoef.Eval(*T->Face, ip) : NAN; + double gf_val = xCoef.Eval(*T, ip); + if (log > 0) + { + cout << "Face (" << tip[0] << "," << tip[1] << "," + << tip[2] << ") -> " << gf_val << endl; + } + + if (fabs(f_val - gf_val) > tol) + { + cout << i << " " << f_val << " " << gf_val << endl; + } + } + } + } + cout << "Checked " << npts << " points within faces" << endl; + } + + if (bfi) + { + // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm + // Boundary Face Integrators + npts = 0; + cout << "Checking " << pmesh->GetNBE() + << " boundary faces in a DG contextx" << endl; + for (int i=0; iGetNBE(); i++) + { + if (log > 0) + { + cout << "Getting trans for boundary face " << i << endl; + } + FaceElementTransformations *T = pmesh->GetBdrFaceTransformations(i); + if (T != NULL) + { + const IntegrationRule &ir = IntRules.Get(T->FaceGeom, 2*order + 2); + + if (log > 0) + { + cout << i << " " << T->Elem1No << " " << T->Elem2No << endl; + } + + double tip_data[3]; + double tip1_data[3]; + Vector tip(tip_data, 3); + Vector tip1(tip1_data, 3); + for (int j=0; jLoc1.Transform(ip, eip1); + + double gf_val1 = NAN; + + if (T->Elem1) + { + T->Elem1->SetIntPoint(&eip1); + T->Elem1->Transform(eip1, tip1); + gf_val1 = xCoef.Eval(*T->Elem1, eip1); + if (log > 0) + { + cout << "Elem1 (" << tip1[0] << "," << tip1[1] << "," + << tip1[2] << ") -> " << gf_val1 << endl; + } + } + + T->Face->SetIntPoint(&ip); + T->Face->Transform(ip, tip); + + double f_val = func(tip); + // double gf_val = xCoef.Eval(*T->Face, ip); + double gf_val = xCoef.Eval(*T, ip); + + if (log > 0) + { + cout << "Face (" << tip[0] << "," << tip[1] << "," + << tip[2] << ") -> " << gf_val << endl; + } + + if (fabs(f_val - gf_val) > tol) + { + cout << i << " " << f_val << " " << gf_val << endl; + } + } + } + } + cout << "Checked " << npts << " points within boundary faces" << endl; + } + + // 15. Save the refined mesh and the solution in parallel. This output can + // be viewed later using GLVis: "glvis -np -m mesh -g sol". + { + ostringstream mesh_name, sol_name; + mesh_name << "mesh." << setfill('0') << setw(6) << myid; + sol_name << "sol." << setfill('0') << setw(6) << myid; + + ofstream mesh_ofs(mesh_name.str().c_str()); + mesh_ofs.precision(8); + pmesh->Print(mesh_ofs); + + ofstream sol_ofs(sol_name.str().c_str()); + sol_ofs.precision(8); + x.Save(sol_ofs); + } + + // 16. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock << "parallel " << num_procs << " " << myid << "\n"; + sol_sock.precision(8); + sol_sock << "solution\n" << *pmesh << x << flush; + } + + // 17. Free the used memory. + delete dg_fespace; + delete h1_fespace; + delete dg_fec; + delete h1_fec; + delete pmesh; + + MPI_Finalize(); + + return 0; +} From 11cde1acddb4c1d55111be5fdaacc7be201f423c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 21:50:15 -0800 Subject: [PATCH 049/535] Promoting FaceElementTransformation to a subclass of IsoparametricTransformation --- fem/eltrans.cpp | 22 ---------------------- fem/eltrans.hpp | 8 +++----- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index 4ef407eaee..ee9fce7193 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -615,26 +615,4 @@ FaceElementTransformations::GetActivePointTransformation() return GetActivePointTransformation(); } -void FaceElementTransformations::Transform(const IntegrationPoint &ip, - Vector &tr) -{ - IntegrationPoint eip; - GetActivePointTransformation()->Transform(ip, eip); - - ElementTransformation * T = GetActiveElementTransformation(); - T->SetIntPoint(&eip); - T->Transform(eip, tr); -} - -void FaceElementTransformations::Transform(const IntegrationRule &ir, - DenseMatrix &tr) -{ - IntegrationRule eir; - eir.SetSize(ir.GetNPoints()); - GetActivePointTransformation()->Transform(ir, eir); - - ElementTransformation * T = GetActiveElementTransformation(); - T->Transform(eir, tr); -} - } diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 2a79b2e4ca..7947fe0ccf 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -349,14 +349,14 @@ public: void Transform (const IntegrationRule &, IntegrationRule &); }; -class FaceElementTransformations +class FaceElementTransformations : public IsoparametricTransformation { private: int side; public: - int Elem1No, Elem2No, FaceGeom; - ElementTransformation *Elem1, *Elem2, *Face; + int Elem1No, Elem2No; + ElementTransformation *Elem1, *Elem2; IntegrationPointTransformation Loc1, Loc2; FaceElementTransformations() : side(2) {} @@ -366,8 +366,6 @@ public: ElementTransformation * GetActiveElementTransformation(); IntegrationPointTransformation * GetActivePointTransformation(); - void Transform(const IntegrationPoint &, Vector &); - void Transform(const IntegrationRule &, DenseMatrix &); }; /* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) From e14011fcbb9c3101081a23587898f64afa2c5ef8 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 21:50:59 -0800 Subject: [PATCH 050/535] Removing FaceElementTransformation specializations from coefficient classes --- fem/coefficient.cpp | 8 +------- fem/coefficient.hpp | 2 -- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 2524ded388..d199389205 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -52,12 +52,6 @@ double GridFunctionCoefficient::Eval (ElementTransformation &T, return GridF -> GetValue (T, ip, Component); } -double GridFunctionCoefficient::Eval (FaceElementTransformations &T, - const IntegrationPoint &ip) -{ - return GridF -> GetValue (T, ip, Component); -} - double TransformedCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) { @@ -180,7 +174,7 @@ void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf) void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { - GridFunc->GetVectorValue(T.ElementNo, ip, V); + GridFunc->GetVectorValue(T, ip, V); } void VectorGridFunctionCoefficient::Eval( diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 6d82ac6e97..4a8e8336cc 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -179,8 +179,6 @@ public: virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); - virtual double Eval(FaceElementTransformations &T, - const IntegrationPoint &ip); }; class TransformedCoefficient : public Coefficient From c0a4a3b0d5b8a89a1fe31bf47ff0f67901488276 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 21:52:17 -0800 Subject: [PATCH 051/535] Adding more general GetValue and GetVectorValue methods to GridFunction --- fem/gridfunc.cpp | 137 ++++++++++++++++++++++++++++++++++++++++++++--- fem/gridfunc.hpp | 7 --- 2 files changed, 131 insertions(+), 13 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index d03f8e3c2b..622434af61 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -602,16 +602,43 @@ double GridFunction::GetValue(ElementTransformation &T, if (fe == NULL) { - // This must be a DG field called in a non-DG context. + // This must be a DG field. Check for DG context. FaceElementTransformations * FET = - fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } return GetValue(*FET, ip, comp); } } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + return GetValue(*FET, ip, comp); + } + } + else + { + MFEM_ABORT("GridFunction::GetValue: Unsupported element type \"" + << T.ElementType << "\""); + } + fes->DofsToVDofs(comp-1, dofs); Vector DofVal(dofs.Size()), LocVec; - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); - fe->CalcShape(ip, DofVal); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, DofVal); + } + else + { + fe->CalcPhysShape(T, DofVal); + } GetSubVector(dofs, LocVec); return (DofVal * LocVec); @@ -625,10 +652,108 @@ double GridFunction::GetValue(FaceElementTransformations &FET, IntegrationPoint eip; FET.GetActivePointTransformation()->Transform(ip, eip); + T->SetIntPoint(&eip); return GetValue(*T, eip, comp, tr); } +void GridFunction::GetVectorValue(ElementTransformation &T, + const IntegrationPoint &ip, + Vector &val, Vector *tr) const +{ + if (tr) + { + T.SetIntPoint(&ip); + T.Transform(ip, *tr); + } + Array vdofs; + const FiniteElement *fe = NULL; + if (T.ElementType == ElementTransformation::ELEMENT) + { + fes->GetElementVDofs(T.ElementNo, vdofs); + fe = fes->GetFE(T.ElementNo); + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + fes->GetBdrElementVDofs(T.ElementNo, vdofs); + fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field. Check for DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } + GetVectorValue(*FET, ip, val); + return; + } + } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + GetVectorValue(*FET, ip, val); + return; + } + } + else + { + MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \"" + << T.ElementType << "\""); + } + + int dof = fe->GetDof(); + Vector loc_data; + GetSubVector(vdofs, loc_data); + if (fe->GetRangeType() == FiniteElement::SCALAR) + { + Vector shape(dof); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, shape); + } + else + { + fe->CalcPhysShape(T, shape); + } + int vdim = fes->GetVDim(); + val.SetSize(vdim); + for (int k = 0; k < vdim; k++) + { + val(k) = shape * ((const double *)loc_data + dof * k); + } + } + else + { + int spaceDim = fes->GetMesh()->SpaceDimension(); + DenseMatrix vshape(dof, spaceDim); + T.SetIntPoint(&ip); + fe->CalcVShape(T, vshape); + val.SetSize(spaceDim); + vshape.MultTranspose(loc_data, val); + } +} + +void GridFunction::GetVectorValue(FaceElementTransformations &FET, + const IntegrationPoint &ip, + Vector &val, Vector *tr) const +{ + ElementTransformation * T = FET.GetActiveElementTransformation(); + + IntegrationPoint eip; + FET.GetActivePointTransformation()->Transform(ip, eip); + T->SetIntPoint(&eip); + + GetVectorValue(*T, eip, val, tr); +} + void GridFunction::GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals, @@ -2165,7 +2290,7 @@ double GridFunction::ComputeH1Error( } intorder = 2 * intorder; // <------------- const IntegrationRule &ir = - IntRules.Get(face_elem_transf->FaceGeom, intorder); + IntRules.Get(face_elem_transf->GetGeometryType(), intorder); err_val.SetSize(ir.GetNPoints()); ell_coeff_val.SetSize(ir.GetNPoints()); // side 1 @@ -2222,7 +2347,7 @@ double GridFunction::ComputeH1Error( } } face_elem_transf = mesh->GetFaceElementTransformations(i, 16); - transf = face_elem_transf->Face; + transf = face_elem_transf; for (j = 0; j < ir.GetNPoints(); j++) { const IntegrationPoint &ip = ir.IntPoint(j); diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 72ceea7893..693af1dd38 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -173,9 +173,6 @@ public: void GetValues(ElementTransformation &T, const IntegrationRule &ir, Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; - void GetValues(FaceElementTransformations &T, const IntegrationRule &ir, - Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; - void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; @@ -186,10 +183,6 @@ public: void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix *tr = NULL) const; - void GetVectorValues(FaceElementTransformations &T, - const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix *tr = NULL) const; - void GetValuesFrom(const GridFunction &orig_func); void GetBdrValuesFrom(const GridFunction &orig_func); From 254feae591023cacbd3802033966ff37e4470040 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 21:53:05 -0800 Subject: [PATCH 052/535] Modifying mesh classes to produce new FaceElementTransformations object --- mesh/mesh.cpp | 9 ++++----- mesh/pmesh.cpp | 18 ++++++++---------- mesh/pmesh.hpp | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index df70cceb71..76f329815e 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -867,8 +867,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, } // setup the face transformation - FaceElemTr.FaceGeom = GetFaceGeometryType(FaceNo); - FaceElemTr.Face = (mask & 16) ? GetFaceTransformation(FaceNo) : NULL; + GetFaceTransformation(FaceNo, &FaceElemTr); // setup Loc1 & Loc2 int face_type = GetFaceElementType(FaceNo); @@ -943,9 +942,9 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) return NULL; } tr = GetFaceElementTransformations(fn); - tr->Face->Attribute = boundary[BdrElemNo]->GetAttribute(); - tr->Face->ElementNo = BdrElemNo; - tr->Face->ElementType = ElementTransformation::BDR_ELEMENT; + tr->Attribute = boundary[BdrElemNo]->GetAttribute(); + tr->ElementNo = BdrElemNo; + tr->ElementType = ElementTransformation::BDR_ELEMENT; return tr; } diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index bc97df2aac..e886e234d9 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2241,16 +2241,16 @@ Table *ParMesh::GetFaceToAllElementTable() const return face_elem; } -ElementTransformation* ParMesh::GetGhostFaceTransformation( +void ParMesh::GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom) { // calculate composition of FETr->Loc1 and FETr->Elem1 - DenseMatrix &face_pm = FaceTransformation.GetPointMat(); + DenseMatrix &face_pm = FETr->GetPointMat(); if (Nodes == NULL) { FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm); - FaceTransformation.SetFE(GetTransformationFEforElementType(face_type)); + FETr->SetFE(GetTransformationFEforElementType(face_type)); } else { @@ -2266,10 +2266,9 @@ ElementTransformation* ParMesh::GetGhostFaceTransformation( FETr->Loc1.Transform(face_el->GetNodes(), eir); Nodes->GetVectorValues(*FETr->Elem1, eir, face_pm); #endif - FaceTransformation.SetFE(face_el); + FETr->SetFE(face_el); } - FaceTransformation.FinalizeTransformation(); - return &FaceTransformation; + FETr->FinalizeTransformation(); } FaceElementTransformations *ParMesh:: @@ -2307,10 +2306,10 @@ GetSharedFaceTransformations(int sf, bool fill2) } // setup the face transformation if the face is not a ghost - FaceElemTr.FaceGeom = face_geom; + // FaceElemTr.FaceGeom = face_geom; if (!is_ghost) { - FaceElemTr.Face = GetFaceTransformation(FaceNo); + GetFaceTransformation(FaceNo, &FaceElemTr); // NOTE: The above call overwrites FaceElemTr.Loc1 } @@ -2351,8 +2350,7 @@ GetSharedFaceTransformations(int sf, bool fill2) // for ghost faces we need a special version of GetFaceTransformation if (is_ghost) { - FaceElemTr.Face = - GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); + GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); } return &FaceElemTr; diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 386a15fdcd..0fcf74ae7c 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -103,7 +103,7 @@ protected: void GetFaceNbrElementTransformation( int i, IsoparametricTransformation *ElTr); - ElementTransformation* GetGhostFaceTransformation( + void GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom); From c7f00662e812b4d74d1f6d6998edb9fecbec59fd Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 21:53:59 -0800 Subject: [PATCH 053/535] Modifying integrator classes to use FaceElementTransformations rather than its Face data member when appropriate --- fem/bilininteg.cpp | 38 ++++++++++++++++++---------------- fem/lininteg.cpp | 51 ++++++++++++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp index b50bccc75d..ed2433f93d 100644 --- a/fem/bilininteg.cpp +++ b/fem/bilininteg.cpp @@ -788,6 +788,8 @@ void BoundaryMassIntegrator::AssembleFaceMatrix( int nd1 = el1.GetDof(); double w; + Trans.SetActiveSide(0); + #ifdef MFEM_THREAD_SAFE Vector shape; #endif @@ -799,7 +801,7 @@ void BoundaryMassIntegrator::AssembleFaceMatrix( { int order = 2 * el1.GetOrder(); - ir = &IntRules.Get(Trans.FaceGeom, order); + ir = &IntRules.Get(Trans.GetGeometryType(), order); } elmat = 0.0; @@ -810,11 +812,11 @@ void BoundaryMassIntegrator::AssembleFaceMatrix( Trans.Loc1.Transform(ip, eip); el1.CalcShape(eip, shape); - Trans.Face->SetIntPoint(&ip); - w = Trans.Face->Weight() * ip.weight; + Trans.SetIntPoint(&ip); + w = Trans.Weight() * ip.weight; if (Q) { - w *= Q -> Eval(*Trans.Face, ip); + w *= Q -> Eval(Trans, ip); } AddMult_a_VVt(w, shape, elmat); @@ -2435,7 +2437,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1, { order++; } - ir = &IntRules.Get(Trans.FaceGeom, order); + ir = &IntRules.Get(Trans.GetGeometryType(), order); } for (int p = 0; p < ir->GetNPoints(); p++) @@ -2449,7 +2451,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1, } el1.CalcShape(eip1, shape1); - Trans.Face->SetIntPoint(&ip); + Trans.SetIntPoint(&ip); Trans.Elem1->SetIntPoint(&eip1); u->Eval(vu, *Trans.Elem1, eip1); @@ -2460,7 +2462,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1, } else { - CalcOrtho(Trans.Face->Jacobian(), nor); + CalcOrtho(Trans.Jacobian(), nor); } un = vu * nor; @@ -2583,7 +2585,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix( { order = 2*el1.GetOrder(); } - ir = &IntRules.Get(Trans.FaceGeom, order); + ir = &IntRules.Get(Trans.GetGeometryType(), order); } // assemble: < {(Q \nabla u).n},[v] > --> elmat @@ -2594,14 +2596,14 @@ void DGDiffusionIntegrator::AssembleFaceMatrix( IntegrationPoint eip1, eip2; Trans.Loc1.Transform(ip, eip1); - Trans.Face->SetIntPoint(&ip); + Trans.SetIntPoint(&ip); if (dim == 1) { nor(0) = 2*eip1.x - 1.0; } else { - CalcOrtho(Trans.Face->Jacobian(), nor); + CalcOrtho(Trans.Jacobian(), nor); } el1.CalcShape(eip1, shape1); @@ -2865,7 +2867,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix( { // a simple choice for the integration order; is this OK? const int order = 2 * max(el1.GetOrder(), ndofs2 ? el2.GetOrder() : 0); - ir = &IntRules.Get(Trans.FaceGeom, order); + ir = &IntRules.Get(Trans.GetGeometryType(), order); } for (int pind = 0; pind < ir->GetNPoints(); ++pind) @@ -2873,7 +2875,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix( const IntegrationPoint &ip = ir->IntPoint(pind); IntegrationPoint eip1, eip2; // integration point in the reference space Trans.Loc1.Transform(ip, eip1); - Trans.Face->SetIntPoint(&ip); + Trans.SetIntPoint(&ip); Trans.Elem1->SetIntPoint(&eip1); el1.CalcShape(eip1, shape1); @@ -2888,7 +2890,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix( } else { - CalcOrtho(Trans.Face->Jacobian(), nor); + CalcOrtho(Trans.Jacobian(), nor); } double w, wLM; @@ -3025,9 +3027,9 @@ void TraceJumpIntegrator::AssembleFaceMatrix( order += trial_face_fe.GetOrder(); if (trial_face_fe.GetMapType() == FiniteElement::VALUE) { - order += Trans.Face->OrderW(); + order += Trans.OrderW(); } - ir = &IntRules.Get(Trans.FaceGeom, order); + ir = &IntRules.Get(Trans.GetGeometryType(), order); } for (int p = 0; p < ir->GetNPoints(); p++) @@ -3035,7 +3037,7 @@ void TraceJumpIntegrator::AssembleFaceMatrix( const IntegrationPoint &ip = ir->IntPoint(p); IntegrationPoint eip1, eip2; // Trace finite element shape function - Trans.Face->SetIntPoint(&ip); + Trans.SetIntPoint(&ip); trial_face_fe.CalcShape(ip, face_shape); // Side 1 finite element shape function Trans.Loc1.Transform(ip, eip1); @@ -3051,7 +3053,7 @@ void TraceJumpIntegrator::AssembleFaceMatrix( w = ip.weight; if (trial_face_fe.GetMapType() == FiniteElement::VALUE) { - w *= Trans.Face->Weight(); + w *= Trans.Weight(); } face_shape *= w; for (i = 0; i < ndof1; i++) @@ -3116,7 +3118,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix( order = test_fe1.GetOrder() - 1; } order += trial_face_fe.GetOrder(); - ir = &IntRules.Get(Trans.FaceGeom, order); + ir = &IntRules.Get(Trans.GetGeometryType(), order); } for (int p = 0; p < ir->GetNPoints(); p++) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index a4d0ea72f3..7a922bf12a 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -276,7 +276,7 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect( if (ir == NULL) { int intorder = 2*el.GetOrder(); - ir = &IntRules.Get(Tr.FaceGeom, intorder); + ir = &IntRules.Get(Tr.GetGeometryType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) @@ -285,9 +285,12 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect( IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); - Tr.Face->SetIntPoint(&ip); - Q.Eval(vec, *Tr.Face, ip); - vec *= Tr.Face->Weight() * ip.weight; + Tr.SetIntPoint(&ip); + Tr.SetActiveSide(0); + + // Use Tr transformation in case Q depends on boundary attribute + Q.Eval(vec, Tr, ip); + vec *= Tr.Weight() * ip.weight; el.CalcShape(eip, shape); for (int k = 0; k < vdim; k++) { @@ -477,7 +480,7 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( { order++; } - ir = &IntRules.Get(Tr.FaceGeom, order); + ir = &IntRules.Get(Tr.GetGeometryType(), order); } shape.SetSize(ndof); @@ -491,9 +494,11 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( Tr.Loc1.Transform(ip, eip); el.CalcShape(eip, shape); - Tr.Face->SetIntPoint(&ip); - - u->Eval(vu, *Tr.Elem1, eip); + Tr.SetIntPoint(&ip); + Tr.SetActiveSide(0); + + // Use Tr transformation in case u or f depends on boundary attribute + u->Eval(vu, Tr, ip); if (dim == 1) { @@ -501,12 +506,12 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( } else { - CalcOrtho(Tr.Face->Jacobian(), nor); + CalcOrtho(Tr.Jacobian(), nor); } un = vu * nor; w = 0.5*alpha*un - beta*fabs(un); - w *= ip.weight*f->Eval(*Tr.Elem1, eip); + w *= ip.weight*f->Eval(Tr, ip); elvect.Add(w, shape); } } @@ -549,7 +554,7 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( { // a simple choice for the integration order; is this OK? int order = 2*el.GetOrder(); - ir = &IntRules.Get(Tr.FaceGeom, order); + ir = &IntRules.Get(Tr.GetGeometryType(), order); } for (int p = 0; p < ir->GetNPoints(); p++) @@ -558,33 +563,34 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); - Tr.Face->SetIntPoint(&ip); + Tr.SetIntPoint(&ip); + Tr.SetActiveSide(0); if (dim == 1) { nor(0) = 2*eip.x - 1.0; } else { - CalcOrtho(Tr.Face->Jacobian(), nor); + CalcOrtho(Tr.Jacobian(), nor); } el.CalcShape(eip, shape); el.CalcDShape(eip, dshape); Tr.Elem1->SetIntPoint(&eip); // compute uD through the face transformation - w = ip.weight * uD->Eval(*Tr.Face, ip) / Tr.Elem1->Weight(); + w = ip.weight * uD->Eval(Tr, ip) / Tr.Elem1->Weight(); if (!MQ) { if (Q) { - w *= Q->Eval(*Tr.Elem1, eip); + w *= Q->Eval(Tr, ip); } ni.Set(w, nor); } else { nh.Set(w, nor); - MQ->Eval(mq, *Tr.Elem1, eip); + MQ->Eval(mq, Tr, ip); mq.MultTranspose(nh, ni); } CalcAdjugate(Tr.Elem1->Jacobian(), adjJ); @@ -643,7 +649,7 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( if (ir == NULL) { const int order = 2*el.GetOrder(); // <----- - ir = &IntRules.Get(Tr.FaceGeom, order); + ir = &IntRules.Get(Tr.GetGeometryType(), order); } for (int pi = 0; pi < ir->GetNPoints(); ++pi) @@ -651,11 +657,12 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( const IntegrationPoint &ip = ir->IntPoint(pi); IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); - Tr.Face->SetIntPoint(&ip); + Tr.SetIntPoint(&ip); + Tr.SetActiveSide(0); Tr.Elem1->SetIntPoint(&eip); // Evaluate the Dirichlet b.c. using the face transformation. - uD.Eval(u_dir, *Tr.Face, ip); + uD.Eval(u_dir, Tr, ip); el.CalcShape(eip, shape); el.CalcDShape(eip, dshape); @@ -669,14 +676,14 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( } else { - CalcOrtho(Tr.Face->Jacobian(), nor); + CalcOrtho(Tr.Jacobian(), nor); } double wL, wM, jcoef; { const double w = ip.weight / Tr.Elem1->Weight(); - wL = w * lambda->Eval(*Tr.Elem1, eip); - wM = w * mu->Eval(*Tr.Elem1, eip); + wL = w * lambda->Eval(Tr, ip); + wM = w * mu->Eval(Tr, ip); jcoef = kappa * (wL + 2.0*wM) * (nor*nor); dshape_ps.Mult(nor, dshape_dn); dshape_ps.Mult(u_dir, dshape_du); From e3e768ec53335999b29ae30979d060ec7a818be3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 21:54:41 -0800 Subject: [PATCH 054/535] Updating test program to also test scalar fields using INTEGRAL map type --- examples/test_gfc.cpp | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/examples/test_gfc.cpp b/examples/test_gfc.cpp index b07bc8b221..57b02a6b65 100644 --- a/examples/test_gfc.cpp +++ b/examples/test_gfc.cpp @@ -22,6 +22,7 @@ int main(int argc, char *argv[]) int par_ref_levels = 0; int log = 0; bool dg = false; + bool mtv = true; bool di = true; // Domain Integration bool bi = true; // Boundary Integration bool fi = true; // Interior Face Integration @@ -42,6 +43,8 @@ int main(int argc, char *argv[]) "Adjust level of screen output."); args.AddOption(&dg, "-dg", "--discontinuous-galerkin", "-h1", "--continuous", "Select H1 or DG space."); + args.AddOption(&mtv, "-mtv", "--map-type-value", "-mti", + "--map-type-integral", "Select VALUE or INTEGRAL map type."); args.AddOption(&di, "-di", "--domain-integration", "-no-di", "--no-domain-integration", "Enable or disable domain integration test."); @@ -107,7 +110,9 @@ int main(int argc, char *argv[]) FiniteElementCollection *h1_fec; FiniteElementCollection *dg_fec; h1_fec = new H1_FECollection(order, dim); - dg_fec = new DG_FECollection(order, dim); + dg_fec = new DG_FECollection(order, dim, BasisType::GaussLegendre, + mtv ? FiniteElement::VALUE + : FiniteElement::INTEGRAL); ParFiniteElementSpace *h1_fespace = new ParFiniteElementSpace(pmesh, h1_fec); ParFiniteElementSpace *dg_fespace = new ParFiniteElementSpace(pmesh, dg_fec); @@ -158,7 +163,8 @@ int main(int argc, char *argv[]) if (fabs(f_val - gf_val) > tol) { - cout << f_val << " " << gf_val << endl; + cout << i << ":" << j << " " << f_val << " " << gf_val + << " " << fabs(f_val - gf_val) << endl; } } } @@ -190,7 +196,8 @@ int main(int argc, char *argv[]) if (fabs(f_val - gf_val) > tol) { - cout << f_val << " " << gf_val << endl; + cout << i << ":" << j << " " << f_val << " " << gf_val + << " " << fabs(f_val - gf_val) << endl; } } } @@ -224,7 +231,8 @@ int main(int argc, char *argv[]) if (fabs(f_val - gf_val) > tol) { - cout << f_val << " " << gf_val << endl; + cout << i << ":" << j << " " << f_val << " " << gf_val + << " " << fabs(f_val - gf_val) << endl; } } } @@ -245,7 +253,8 @@ int main(int argc, char *argv[]) pmesh->GetInteriorFaceTransformations(i); if (T != NULL) { - const IntegrationRule &ir = IntRules.Get(T->FaceGeom, 2*order + 2); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); if (log > 0) { @@ -294,15 +303,13 @@ int main(int argc, char *argv[]) } } - if (T->Face) - { - T->Face->SetIntPoint(&ip); - T->Face->Transform(ip, tip); - } + T->SetIntPoint(&ip); + T->Transform(ip, tip); double f_val = func(tip); // double gf_val = (T->Face) ? xCoef.Eval(*T->Face, ip) : NAN; double gf_val = xCoef.Eval(*T, ip); + if (log > 0) { cout << "Face (" << tip[0] << "," << tip[1] << "," @@ -311,7 +318,8 @@ int main(int argc, char *argv[]) if (fabs(f_val - gf_val) > tol) { - cout << i << " " << f_val << " " << gf_val << endl; + cout << i << " " << f_val << " " << gf_val + << " " << fabs(f_val - gf_val) << endl; } } } @@ -325,7 +333,7 @@ int main(int argc, char *argv[]) // Boundary Face Integrators npts = 0; cout << "Checking " << pmesh->GetNBE() - << " boundary faces in a DG contextx" << endl; + << " boundary faces in a DG context" << endl; for (int i=0; iGetNBE(); i++) { if (log > 0) @@ -335,7 +343,8 @@ int main(int argc, char *argv[]) FaceElementTransformations *T = pmesh->GetBdrFaceTransformations(i); if (T != NULL) { - const IntegrationRule &ir = IntRules.Get(T->FaceGeom, 2*order + 2); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); if (log > 0) { @@ -368,8 +377,8 @@ int main(int argc, char *argv[]) } } - T->Face->SetIntPoint(&ip); - T->Face->Transform(ip, tip); + T->SetIntPoint(&ip); + T->Transform(ip, tip); double f_val = func(tip); // double gf_val = xCoef.Eval(*T->Face, ip); @@ -383,7 +392,8 @@ int main(int argc, char *argv[]) if (fabs(f_val - gf_val) > tol) { - cout << i << " " << f_val << " " << gf_val << endl; + cout << i << ":" << j << " " << f_val << " " << gf_val + << " " << fabs(f_val - gf_val) << endl; } } } From f683d75c8be7da13b78a2344805938b496eebe22 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Dec 2019 22:09:27 -0800 Subject: [PATCH 055/535] Updating ex18 to use the new FaceElementTransformation object --- examples/ex18.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/ex18.hpp b/examples/ex18.hpp index fe0e38ffc2..75fa5e885b 100644 --- a/examples/ex18.hpp +++ b/examples/ex18.hpp @@ -418,7 +418,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, { intorder++; } - const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder); + const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder); for (int i = 0; i < ir->GetNPoints(); i++) { @@ -435,10 +435,10 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, elfun1_mat.MultTranspose(shape1, funval1); elfun2_mat.MultTranspose(shape2, funval2); - Tr.Face->SetIntPoint(&ip); + Tr.SetIntPoint(&ip); // Get the normal vector and the flux on the face - CalcOrtho(Tr.Face->Jacobian(), nor); + CalcOrtho(Tr.Jacobian(), nor); const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN); // Update max char speed From 3c7f9d7f87ead47faf2eed6ba40f920c90a50b50 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 6 Jan 2020 14:37:06 -0800 Subject: [PATCH 056/535] CMAKE_CXX_COMPILER_ID for MSVC: O2 & Ob2 --- miniapps/performance/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 95a3a0ed2a..c3a0a8be17 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -31,6 +31,10 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") list(APPEND PERFORMANCE_CXX_OPTIONS "-xHost") +elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "MSVC") + list(APPEND PERFORMANCE_CXX_OPTIONS + "/O2" + "/Ob2") endif() add_mfem_miniapp(performance_ex1 From 9be3aad19d7ca68ed08413f4231111e150915682 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 6 Jan 2020 16:37:41 -0800 Subject: [PATCH 057/535] Debug CMAKE_CXX_COMPILER_ID and PERFORMANCE_CXX_OPTIONS --- miniapps/performance/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index c3a0a8be17..f9f82c1f87 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -37,6 +37,9 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "MSVC") "/Ob2") endif() +message(WARNING CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) +message(WARNING PERFORMANCE_CXX_OPTIONS=${PERFORMANCE_CXX_OPTIONS}) + add_mfem_miniapp(performance_ex1 MAIN ex1.cpp LIBRARIES mfem From 941f5b85ba8225bd95a8f705ce9bfb4c64742d07 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 6 Jan 2020 17:43:14 -0800 Subject: [PATCH 058/535] Try CMAKE_CXX_COMPILER_ID MATCHES "MSVC" --- miniapps/performance/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index f9f82c1f87..200ceff087 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -31,7 +31,7 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") list(APPEND PERFORMANCE_CXX_OPTIONS "-xHost") -elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "MSVC") +elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") list(APPEND PERFORMANCE_CXX_OPTIONS "/O2" "/Ob2") From 02febb1445264fd8f83c43cd4d8c4c1a61936797 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 6 Jan 2020 18:06:59 -0800 Subject: [PATCH 059/535] Incompatible '/O2' and '/RTC1' command-line options --- miniapps/performance/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 200ceff087..9a3b7ddc92 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -33,7 +33,6 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") "-xHost") elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") list(APPEND PERFORMANCE_CXX_OPTIONS - "/O2" "/Ob2") endif() From 76f36cb1eef2783c71440de5f5c17f3c8b68fda9 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 6 Jan 2020 18:14:31 -0800 Subject: [PATCH 060/535] appveyor config Release --- .appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3a01b0f866..8de1837d1c 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -40,11 +40,11 @@ before_build: - cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE build_script: -- cmake --build build_parallel -- cmake --build build_serial -- cmake --build build_serial --target exec +- cmake --build build_parallel --config Release -j 4 +- cmake --build build_serial --config Release -j 4 +- cmake --build build_serial --target exec --config Release -j 4 after_build: # - cmake --build build_parallel --target check -- cmake --build build_serial --target RUN_TESTS +- cmake --build build_serial --target RUN_TESTS --config Release From b10e9a9b4a07462bbbc99647387cc7068c89d376 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 6 Jan 2020 19:39:12 -0800 Subject: [PATCH 061/535] Revert MSVC inline option --- miniapps/performance/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 9a3b7ddc92..72783d02d4 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -31,9 +31,6 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") list(APPEND PERFORMANCE_CXX_OPTIONS "-xHost") -elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - list(APPEND PERFORMANCE_CXX_OPTIONS - "/Ob2") endif() message(WARNING CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) From 592757bfa312798e362d3935e8ab60f694844365 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 10:46:10 -0800 Subject: [PATCH 062/535] AutoImplTraits simd & valign size set to 1 --- .appveyor.yml | 6 +++--- config/tconfig.hpp | 4 ++-- fem/tbilinearform.hpp | 5 ++++- makefile | 2 +- miniapps/performance/CMakeLists.txt | 3 --- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 8de1837d1c..5633c8c8cd 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -40,9 +40,9 @@ before_build: - cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE build_script: -- cmake --build build_parallel --config Release -j 4 -- cmake --build build_serial --config Release -j 4 -- cmake --build build_serial --target exec --config Release -j 4 +- cmake --build build_parallel --config Release +- cmake --build build_serial --config Release +- cmake --build build_serial --target exec --config Release after_build: # - cmake --build build_parallel --target check diff --git a/config/tconfig.hpp b/config/tconfig.hpp index ac2c01e7eb..8c351f3a24 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -83,9 +83,9 @@ struct AutoImplTraits static const int batch_size = 1; - static const int simd_size = simd?(MFEM_SIMD_SIZE/sizeof(complex_t)):1; + static const int simd_size = 1;//simd?(MFEM_SIMD_SIZE/sizeof(complex_t)):1; - static const int valign_size = simd?simd_size:1; + static const int valign_size = 1;//simd?simd_size:1; typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 3303d2b138..ff9f940d9a 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -22,6 +22,9 @@ #ifdef _WIN32 #define posix_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno) +#define posix_memalign_free _aligned_free +#else +#define posix_memalign_free free #endif namespace mfem @@ -126,7 +129,7 @@ public: virtual ~TBilinearForm() { - free(assembled_data); + posix_memalign_free(assembled_data); } /// Get the input finite element space prolongation matrix diff --git a/makefile b/makefile index 75828ac39a..5cb57b29de 100644 --- a/makefile +++ b/makefile @@ -637,6 +637,7 @@ status info: $(info MFEM_CXX = $(value MFEM_CXX)) $(info MFEM_CPPFLAGS = $(value MFEM_CPPFLAGS)) $(info MFEM_CXXFLAGS = $(value MFEM_CXXFLAGS)) + $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) $(info MFEM_TPLFLAGS = $(value MFEM_TPLFLAGS)) $(info MFEM_INCFLAGS = $(value MFEM_INCFLAGS)) $(info MFEM_FLAGS = $(value MFEM_FLAGS)) @@ -654,7 +655,6 @@ status info: $(info MFEM_MPIEXEC = $(MFEM_MPIEXEC)) $(info MFEM_MPIEXEC_NP = $(MFEM_MPIEXEC_NP)) $(info MFEM_MPI_NP = $(MFEM_MPI_NP)) - $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) @true ASTYLE = astyle --options=$(SRC)config/mfem.astylerc diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 72783d02d4..95a3a0ed2a 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -33,9 +33,6 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") "-xHost") endif() -message(WARNING CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) -message(WARNING PERFORMANCE_CXX_OPTIONS=${PERFORMANCE_CXX_OPTIONS}) - add_mfem_miniapp(performance_ex1 MAIN ex1.cpp LIBRARIES mfem From 532e5371bddb64504ae9b1fca61ba8dbd2772f75 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 11:14:39 -0800 Subject: [PATCH 063/535] Default MFEM_SIMD_SIZE and MFEM_TEMPLATE_BLOCK_SIZE for _WIN32 --- config/tconfig.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 8c351f3a24..a27f2f443f 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -62,8 +62,13 @@ // --- SIMD Traits #ifndef MFEM_USE_SIMD +#ifdef _WIN32 // 64 +#define MFEM_SIMD_SIZE 8 +#define MFEM_TEMPLATE_BLOCK_SIZE 1 +#else #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 +#endif #else #ifdef __VSX__ // 128 #define MFEM_SIMD_SIZE 16 @@ -83,9 +88,9 @@ struct AutoImplTraits static const int batch_size = 1; - static const int simd_size = 1;//simd?(MFEM_SIMD_SIZE/sizeof(complex_t)):1; + static const int simd_size = simd?(MFEM_SIMD_SIZE/sizeof(complex_t)):1; - static const int valign_size = 1;//simd?simd_size:1; + static const int valign_size = simd?simd_size:1; typedef AutoSIMD vcomplex_t; typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; From 2a3dc3c0b1a165ed3957a6d0662d9d1345c3af36 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 11:20:40 -0800 Subject: [PATCH 064/535] Global default SIMD and BLOCK sizes --- config/tconfig.hpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index a27f2f443f..f144a64785 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -60,22 +60,26 @@ #endif #endif -// --- SIMD Traits -#ifndef MFEM_USE_SIMD -#ifdef _WIN32 // 64 -#define MFEM_SIMD_SIZE 8 -#define MFEM_TEMPLATE_BLOCK_SIZE 1 +// --- Default SIMD and BLOCK sizes +#ifdef _WIN32 +#define MFEM_SIMD_DEFAULT_SIZE 8 +#define MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE 1 #else -#define MFEM_SIMD_SIZE 32 -#define MFEM_TEMPLATE_BLOCK_SIZE 4 +#define MFEM_SIMD_DEFAULT_SIZE 32 +#define MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE 4 #endif + +// --- SIMD and BLOCK sizes +#ifndef MFEM_USE_SIMD +#define MFEM_SIMD_SIZE MFEM_SIMD_DEFAULT_SIZE +#define MFEM_TEMPLATE_BLOCK_SIZE MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE #else -#ifdef __VSX__ // 128 +#ifdef __VSX__ #define MFEM_SIMD_SIZE 16 #define MFEM_TEMPLATE_BLOCK_SIZE 2 -#else // 256 -#define MFEM_SIMD_SIZE 32 -#define MFEM_TEMPLATE_BLOCK_SIZE 4 +#else +#define MFEM_SIMD_SIZE MFEM_SIMD_DEFAULT_SIZE +#define MFEM_TEMPLATE_BLOCK_SIZE MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE #endif #endif From 6147b72ec16caceb02ee2616546ca370583a07b8 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 12:04:28 -0800 Subject: [PATCH 065/535] Cleanup and Style --- config/simd/auto.hpp | 52 +++--- config/simd/m128.hpp | 40 ++--- config/simd/m256.hpp | 60 +++---- config/simd/m512.hpp | 60 +++---- config/simd/m64.hpp | 52 +++--- config/simd/qpx.hpp | 6 - config/simd/qpx256.hpp | 364 ++++++++++++++++++++-------------------- config/simd/qpx64.hpp | 353 ++++++++++++++++++++------------------- config/simd/vsx128.hpp | 370 +++++++++++++++++++++-------------------- config/simd/vsx64.hpp | 52 +++--- config/simd/x86.hpp | 8 - fem/tbilinearform.hpp | 2 +- 12 files changed, 715 insertions(+), 704 deletions(-) diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index 4ed7ff86aa..dc82f88dee 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -12,7 +12,15 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_AUTO #define MFEM_TEMPLATE_CONFIG_SIMD_AUTO -template +template struct AutoSIMD; +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif +#ifndef MFEM_VECTORIZE_LOOP +#define MFEM_VECTORIZE_LOOP +#endif + +template struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD { typedef scalar_t scalar_type; @@ -22,7 +30,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD scalar_t vec[size]; inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } - + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) @@ -31,63 +39,63 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { vec[i] = v[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] -= v[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] -= e; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] *= v[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] *= e; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] /= v[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { MFEM_VECTORIZE_LOOP @@ -110,7 +118,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] + v[i]; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; @@ -118,7 +126,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] + e; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; @@ -126,7 +134,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] - v[i]; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; @@ -134,7 +142,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] - e; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; @@ -142,7 +150,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] * v[i]; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; @@ -150,7 +158,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] * e; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; @@ -158,7 +166,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { r[i] = vec[i] / v[i]; } return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; @@ -173,14 +181,14 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { vec[i] += v[i] * w[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP @@ -194,14 +202,14 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD for (int i = 0; i < size; i++) { vec[i] = v[i] * w[i]; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 4b4c1432ab..f94e6f6e80 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -12,20 +12,26 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M128 #define MFEM_TEMPLATE_CONFIG_SIMD_M128 -// ***************************************************************************** +#include "x86intrin.h" +template struct AutoSIMD; +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif + template struct AutoSIMD { typedef scalar_t scalar_type; static const int size = 2; static const int align_size = 16; - - union{ + + union + { __m128d m128d; scalar_t vec[size]; }; inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } - + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) @@ -33,61 +39,61 @@ template struct AutoSIMD m128d = v.m128d; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { m128d = _mm_set1_pd(e); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { m128d = _mm_add_pd(m128d,v); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { m128d = _mm_add_pd(m128d,_mm_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { m128d = _mm_sub_pd(m128d,v); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { m128d = _mm_sub_pd(m128d,_mm_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { m128d = _mm_mul_pd(m128d,v.m128d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { m128d = _mm_mul_pd(m128d,_mm_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { m128d = _mm_div_pd(m128d,v.m128d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { m128d = _mm_div_pd(m128d,_mm_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { return _mm_xor_pd(_mm_set1_pd(-0.0), m128d); @@ -99,7 +105,7 @@ template struct AutoSIMD r.m128d = _mm_add_pd(m128d,v.m128d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { @@ -188,7 +194,6 @@ template struct AutoSIMD } }; -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, @@ -199,7 +204,6 @@ AutoSIMD operator+(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, @@ -210,7 +214,6 @@ AutoSIMD operator-(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, @@ -221,7 +224,6 @@ AutoSIMD operator*(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index c6ef4232a0..4e5121eaa6 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -12,14 +12,20 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M256 #define MFEM_TEMPLATE_CONFIG_SIMD_M256 -// ***************************************************************************** +#include "x86intrin.h" +template struct AutoSIMD; +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif + template struct AutoSIMD { typedef scalar_t scalar_type; static const int size = 4; static const int align_size = 32; - - union{ + + union + { __m256d m256d; scalar_t vec[size]; }; @@ -32,61 +38,61 @@ template struct AutoSIMD m256d = v.m256d; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { m256d = _mm256_set1_pd(e); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { m256d = _mm256_add_pd(m256d,v); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { m256d = _mm256_add_pd(m256d,_mm256_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { m256d = _mm256_sub_pd(m256d,v); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { m256d = _mm256_sub_pd(m256d,_mm256_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { m256d = _mm256_mul_pd(m256d,v.m256d); return *this; } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { m256d = _mm256_mul_pd(m256d,_mm256_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { m256d = _mm256_div_pd(m256d,v.m256d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { m256d = _mm256_div_pd(m256d,_mm256_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { AutoSIMD r; @@ -100,49 +106,49 @@ template struct AutoSIMD r.m256d = _mm256_add_pd(m256d,v.m256d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_add_pd(m256d, _mm256_set1_pd(e)); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_sub_pd(m256d,v.m256d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_sub_pd(m256d, _mm256_set1_pd(e)); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_mul_pd(m256d,v.m256d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r.m256d = _mm256_mul_pd(m256d, _mm256_set1_pd(e)); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r.m256d = _mm256_div_pd(m256d,v.m256d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; @@ -159,7 +165,7 @@ template struct AutoSIMD #endif return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { #ifndef __AVX2__ @@ -169,7 +175,7 @@ template struct AutoSIMD #endif return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { #ifndef __AVX2__ @@ -185,13 +191,13 @@ template struct AutoSIMD m256d = _mm256_mul_pd(v.m256d,w.m256d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { m256d = _mm256_mul_pd(v.m256d,_mm256_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); @@ -199,7 +205,6 @@ template struct AutoSIMD } }; -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, @@ -210,7 +215,6 @@ AutoSIMD operator+(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, @@ -221,7 +225,6 @@ AutoSIMD operator-(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, @@ -232,7 +235,6 @@ AutoSIMD operator*(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 1c8e80b24e..1fa93ee391 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -12,20 +12,26 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M512 #define MFEM_TEMPLATE_CONFIG_SIMD_M512 -// ***************************************************************************** +#include "x86intrin.h" +template struct AutoSIMD; +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif + template struct AutoSIMD { typedef scalar_t scalar_type; static const int size = 8; static const int align_size = 64; - - union{ + + union + { __m512d m512d; scalar_t vec[size]; }; inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } - + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) @@ -33,61 +39,61 @@ template struct AutoSIMD m512d = v.m512d; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { m512d = _mm512_set1_pd(e); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { m512d = _mm512_add_pd(m512d,v); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { m512d = _mm512_add_pd(m512d,_mm512_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { m512d = _mm512_sub_pd(m512d,v); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { m512d = _mm512_sub_pd(m512d,_mm512_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { m512d = _mm512_mul_pd(m512d,v.m512d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { m512d = _mm512_mul_pd(m512d,_mm512_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { m512d = _mm512_div_pd(m512d,v.m512d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { m512d = _mm512_div_pd(m512d,_mm512_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { return _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); @@ -99,49 +105,49 @@ template struct AutoSIMD r.m512d = _mm512_add_pd(m512d,v.m512d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_add_pd(m512d, _mm512_set1_pd(e)); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_sub_pd(m512d,v.m512d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_sub_pd(m512d, _mm512_set1_pd(e)); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_mul_pd(m512d,v.m512d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r.m512d = _mm512_mul_pd(m512d, _mm512_set1_pd(e)); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r.m512d = _mm512_div_pd(m512d,v.m512d); return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; @@ -154,13 +160,13 @@ template struct AutoSIMD m512d = _mm512_fmadd_pd(w.m512d,v.m512d,m512d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { m512d = _mm512_fmadd_pd(_mm512_set1_pd(e),v.m512d,m512d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { m512d = _mm512_fmadd_pd(v.m512d,_mm512_set1_pd(e),m512d); @@ -172,13 +178,13 @@ template struct AutoSIMD m512d = _mm512_mul_pd(v.m512d,w.m512d); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { m512d = _mm512_mul_pd(v.m512d,_mm512_set1_pd(e)); return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); @@ -186,7 +192,6 @@ template struct AutoSIMD } }; -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, @@ -197,7 +202,6 @@ AutoSIMD operator+(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, @@ -208,7 +212,6 @@ AutoSIMD operator-(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, @@ -219,7 +222,6 @@ AutoSIMD operator*(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index 977f3aba1b..54f3540097 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -12,7 +12,11 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M64 #define MFEM_TEMPLATE_CONFIG_SIMD_M64 -// **************************************************************************** +template struct AutoSIMD; +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif + template struct AutoSIMD { typedef scalar_t scalar_type; @@ -22,7 +26,7 @@ template struct AutoSIMD scalar_t vec[size]; inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[0]; } - + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[0]; } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) @@ -30,55 +34,55 @@ template struct AutoSIMD vec[0] = v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { vec[0] = e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { vec[0] += v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { vec[0] += e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { vec[0] -= v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { vec[0] -= e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { vec[0] *= v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { vec[0] *= e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { vec[0] /= v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { vec[0] /= e; @@ -98,49 +102,49 @@ template struct AutoSIMD r[0] = vec[0] + v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] + e; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] - v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] - e; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] * v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] * e; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] / v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; @@ -153,13 +157,13 @@ template struct AutoSIMD vec[0] += v[0] * w[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { vec[0] += v[0] * e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { vec[0] += e * v[0]; @@ -171,13 +175,13 @@ template struct AutoSIMD vec[0] = v[0] * w[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { vec[0] = v[0] * e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { vec[0] = e * v[0]; @@ -185,7 +189,6 @@ template struct AutoSIMD } }; -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, @@ -196,7 +199,6 @@ AutoSIMD operator+(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, @@ -207,7 +209,6 @@ AutoSIMD operator-(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, @@ -218,7 +219,6 @@ AutoSIMD operator*(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, diff --git a/config/simd/qpx.hpp b/config/simd/qpx.hpp index 78e2c05d54..a28927c82b 100644 --- a/config/simd/qpx.hpp +++ b/config/simd/qpx.hpp @@ -12,12 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_QPX_HPP #define MFEM_TEMPLATE_CONFIG_QPX_HPP -#include "builtins.h" - -#define __ATTRS_ai __attribute__((__always_inline__)) - -template struct AutoSIMD; - #include "qpx64.hpp" #include "qpx256.hpp" diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index 40ebf1c3f6..0a8fee4b1f 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -12,222 +12,228 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 -// **************************************************************************** +#include "builtins.h" +template struct AutoSIMD; +#ifndef __ATTRS_ai +#define __ATTRS_ai +#endif +#ifndef vector4double +#define vector4double double +#error Undefined vector4double +#endif + template struct AutoSIMD { - typedef scalar_t scalar_type; - static const int size = 4; - static const int align_size = 32; + typedef scalar_t scalar_type; + static const int size = 4; + static const int align_size = 32; - union{ - vector4double vd; - scalar_t vec[size]; - }; + union + { + vector4double vd; + scalar_t vec[size]; + }; - inline __ATTRS_ai scalar_t &operator[](int i) { return vec[i]; } - - inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[i]; } + inline __ATTRS_ai scalar_t &operator[](int i) { return vec[i]; } - inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) - { - vd = v.vd; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) - { - vd = vec_splats(e); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) - { - vd = vec_add(vd,v); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) - { - vd = vec_add(vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) - { - vd = vec_sub(vd,v); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) - { - vd = vec_sub(vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) - { - vd = vec_mul(vd,v.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) - { - vd = vec_mul(vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) - { - vd = vec_swdiv(vd,v.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) - { - vd = vec_swdiv(vd,vec_splats(e)); - return *this; - } + inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[i]; } - inline __ATTRS_ai AutoSIMD operator-() const - { - return vec_neg(vd); - } + inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) + { + vd = v.vd; + return *this; + } - inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_add(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_add(vd, vec_splats(e)); - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_sub(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_sub(vd, vec_splats(e)); - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_mul(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_mul(vd, vec_splats(e)); - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_swdiv(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_swdiv(vd, vec_splats(e)); - return r; - } + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + { + vd = vec_splats(e); + return *this; + } - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - vd = vec_madd(w.vd,vd,v.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) - { - vd = vec_madd(v.vd,vec_splats(e),vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) - { - vd = vec_madd(vec_splats(e),v.vd,vd); - return *this; - } + inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) + { + vd = vec_add(vd,v); + return *this; + } - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - vd = vec_mul(v.vd,w.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) - { - vd = vec_mul(v.vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) - { - vd = vec_mul(vec_splats(e),v.vd); - return *this; - } + inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + { + vd = vec_add(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) + { + vd = vec_sub(vd,v); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + { + vd = vec_sub(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) + { + vd = vec_mul(vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + { + vd = vec_mul(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) + { + vd = vec_swdiv(vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + { + vd = vec_swdiv(vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD operator-() const + { + return vec_neg(vd); + } + + inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_add(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_add(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_sub(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_sub(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_mul(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_mul(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_swdiv(vd,v.vd); + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_swdiv(vd, vec_splats(e)); + return r; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_madd(w.vd,vd,v.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_madd(v.vd,vec_splats(e),vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_madd(vec_splats(e),v.vd,vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_mul(v.vd,w.vd); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_mul(v.vd,vec_splats(e)); + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_mul(vec_splats(e),v.vd); + return *this; + } }; -// ***************************************************************************** template inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_add(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_add(vec_splats(e),v.vd); + return r; } -// ***************************************************************************** template inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_sub(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_sub(vec_splats(e),v.vd); + return r; } -// ***************************************************************************** template inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_mul(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_mul(vec_splats(e),v.vd); + return r; } -// ***************************************************************************** template inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_swdiv(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_swdiv(vec_splats(e),v.vd); + return r; } #endif // MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp index 99b4fb24f8..649e9d6f62 100644 --- a/config/simd/qpx64.hpp +++ b/config/simd/qpx64.hpp @@ -12,177 +12,182 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 -// **************************************************************************** +#include "builtins.h" +template struct AutoSIMD; +#ifndef __ATTRS_ai +#define __ATTRS_ai +#endif + template struct AutoSIMD { - typedef scalar_t scalar_type; - static const int size = 1; - static const int align_size = 8; + typedef scalar_t scalar_type; + static const int size = 1; + static const int align_size = 8; - scalar_t vec[size]; + scalar_t vec[size]; - inline __ATTRS_ai scalar_t &operator[](int i) { return vec[0]; } - - inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[0]; } + inline __ATTRS_ai scalar_t &operator[](int i) { return vec[0]; } - inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) - { - vec[0] = v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) - { - vec[0] = e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) - { - vec[0] += v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) - { - vec[0] += e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) - { - vec[0] -= v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) - { - vec[0] -= e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) - { - vec[0] *= v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) - { - vec[0] *= e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) - { - vec[0] /= v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) - { - vec[0] /= e; - return *this; - } + inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[0]; } - inline __ATTRS_ai AutoSIMD operator-() const - { - AutoSIMD r; - r[0] = -vec[0]; - return r; - } + inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) + { + vec[0] = v[0]; + return *this; + } - inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] + v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const - { - AutoSIMD r; - r[0] = vec[0] + e; - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] - v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const - { - AutoSIMD r; - r[0] = vec[0] - e; - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] * v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const - { - AutoSIMD r; - r[0] = vec[0] * e; - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] / v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const - { - AutoSIMD r; - r[0] = vec[0] / e; - return r; - } + inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + { + vec[0] = e; + return *this; + } - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] += v[0] * w[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) - { - vec[0] += v[0] * e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) - { - vec[0] += e * v[0]; - return *this; - } + inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) + { + vec[0] += v[0]; + return *this; + } - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] = v[0] * w[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) - { - vec[0] = v[0] * e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) - { - vec[0] = e * v[0]; - return *this; - } + inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + { + vec[0] += e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) + { + vec[0] -= v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + { + vec[0] -= e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) + { + vec[0] *= v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + { + vec[0] *= e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) + { + vec[0] /= v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + { + vec[0] /= e; + return *this; + } + + inline __ATTRS_ai AutoSIMD operator-() const + { + AutoSIMD r; + r[0] = -vec[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] + v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] + e; + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] - v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] - e; + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] * v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] * e; + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r[0] = vec[0] / v[0]; + return r; + } + + inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r[0] = vec[0] / e; + return r; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] += v[0] * w[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vec[0] += v[0] * e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vec[0] += e * v[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vec[0] = v[0] * w[0]; + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vec[0] = v[0] * e; + return *this; + } + + inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vec[0] = e * v[0]; + return *this; + } }; // ***************************************************************************** @@ -191,9 +196,9 @@ inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r[0] = e + v[0]; - return r; + AutoSIMD r; + r[0] = e + v[0]; + return r; } // ***************************************************************************** @@ -202,9 +207,9 @@ inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r[0] = e - v[0]; - return r; + AutoSIMD r; + r[0] = e - v[0]; + return r; } // ***************************************************************************** @@ -213,9 +218,9 @@ inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r[0] = e * v[0]; - return r; + AutoSIMD r; + r[0] = e * v[0]; + return r; } // ***************************************************************************** @@ -224,9 +229,9 @@ inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r[0] = e / v[0]; - return r; + AutoSIMD r; + r[0] = e / v[0]; + return r; } #endif // MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp index 10f4d3a3a0..966f746b85 100644 --- a/config/simd/vsx128.hpp +++ b/config/simd/vsx128.hpp @@ -13,226 +13,228 @@ #define MFEM_TEMPLATE_CONFIG_SIMD_VSX128 #include "altivec.h" -#define __ATTRS_ai __attribute__((__always_inline__)) +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif +#ifndef vector +#define vector +#error Undefined vector +#endif template struct AutoSIMD; -// **************************************************************************** template struct AutoSIMD { - typedef scalar_t scalar_type; - static const int size = 2; - static const int align_size = 16; + typedef scalar_t scalar_type; + static const int size = 2; + static const int align_size = 16; - union{ - vector double vd; - scalar_t vec[size]; - }; + union + { + vector double vd; + scalar_t vec[size]; + }; - inline __ATTRS_ai scalar_t &operator[](int i) { return vec[i]; } - - inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } - inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) - { - vd = v.vd; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) - { - vd = vec_splats(e); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) - { - vd = vec_add(vd,v); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) - { - vd = vec_add(vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) - { - vd = vec_sub(vd,v); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) - { - vd = vec_sub(vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) - { - vd = vec_mul(vd,v.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) - { - vd = vec_mul(vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) - { - vd = vec_div(vd,v.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) - { - vd = vec_div(vd,vec_splats(e)); - return *this; - } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } - inline __ATTRS_ai AutoSIMD operator-() const - { - return vec_neg(vd); - } + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) + { + vd = v.vd; + return *this; + } - inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_add(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_add(vd, vec_splats(e)); - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_sub(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_sub(vd, vec_splats(e)); - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_mul(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_mul(vd, vec_splats(e)); - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - r.vd = vec_div(vd,v.vd); - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const - { - AutoSIMD r; - r.vd = vec_div(vd, vec_splats(e)); - return r; - } + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + { + vd = vec_splats(e); + return *this; + } - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - vd = vec_madd(w.vd,vd,v.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) - { - vd = vec_madd(v.vd,vec_splats(e),vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) - { - vd = vec_madd(vec_splats(e),v.vd,vd); - return *this; - } + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) + { + vd = vec_add(vd,v); + return *this; + } - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - vd = vec_mul(v.vd,w.vd); - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) - { - vd = vec_mul(v.vd,vec_splats(e)); - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) - { - vd = vec_mul(vec_splats(e),v.vd); - return *this; - } + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + { + vd = vec_add(vd,vec_splats(e)); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) + { + vd = vec_sub(vd,v); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + { + vd = vec_sub(vd,vec_splats(e)); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) + { + vd = vec_mul(vd,v.vd); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + { + vd = vec_mul(vd,vec_splats(e)); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) + { + vd = vec_div(vd,v.vd); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + { + vd = vec_div(vd,vec_splats(e)); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const + { + return vec_neg(vd); + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_add(vd,v.vd); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_add(vd, vec_splats(e)); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_sub(vd,v.vd); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_sub(vd, vec_splats(e)); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_mul(vd,v.vd); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_mul(vd, vec_splats(e)); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const + { + AutoSIMD r; + r.vd = vec_div(vd,v.vd); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + { + AutoSIMD r; + r.vd = vec_div(vd, vec_splats(e)); + return r; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_madd(w.vd,vd,v.vd); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_madd(v.vd,vec_splats(e),vd); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_madd(vec_splats(e),v.vd,vd); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) + { + vd = vec_mul(v.vd,w.vd); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + { + vd = vec_mul(v.vd,vec_splats(e)); + return *this; + } + + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + { + vd = vec_mul(vec_splats(e),v.vd); + return *this; + } }; -// ***************************************************************************** template -inline __ATTRS_ai +inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_add(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_add(vec_splats(e),v.vd); + return r; } -// ***************************************************************************** template -inline __ATTRS_ai +inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_sub(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_sub(vec_splats(e),v.vd); + return r; } -// ***************************************************************************** template -inline __ATTRS_ai +inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_mul(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_mul(vec_splats(e),v.vd); + return r; } -// ***************************************************************************** template -inline __ATTRS_ai +inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, const AutoSIMD &v) { - AutoSIMD r; - r.vd = vec_div(vec_splats(e),v.vd); - return r; + AutoSIMD r; + r.vd = vec_div(vec_splats(e),v.vd); + return r; } #endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX128 diff --git a/config/simd/vsx64.hpp b/config/simd/vsx64.hpp index bfebfea1e1..320a4ceac3 100644 --- a/config/simd/vsx64.hpp +++ b/config/simd/vsx64.hpp @@ -13,10 +13,12 @@ #define MFEM_TEMPLATE_CONFIG_SIMD_VSX64 #include "altivec.h" +#ifndef MFEM_ALWAYS_INLINE +#define MFEM_ALWAYS_INLINE +#endif -template struct AutoSIMD; +template struct AutoSIMD; -// **************************************************************************** template struct AutoSIMD { typedef scalar_t scalar_type; @@ -26,7 +28,7 @@ template struct AutoSIMD scalar_t vec[size]; inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[0]; } - + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[0]; } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) @@ -34,55 +36,55 @@ template struct AutoSIMD vec[0] = v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { vec[0] = e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { vec[0] += v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { vec[0] += e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { vec[0] -= v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { vec[0] -= e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) { vec[0] *= v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { vec[0] *= e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) { vec[0] /= v[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { vec[0] /= e; @@ -102,49 +104,49 @@ template struct AutoSIMD r[0] = vec[0] + v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] + e; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] - v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] - e; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] * v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; r[0] = vec[0] * e; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const { AutoSIMD r; r[0] = vec[0] / v[0]; return r; } - + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; @@ -157,13 +159,13 @@ template struct AutoSIMD vec[0] += v[0] * w[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { vec[0] += v[0] * e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { vec[0] += e * v[0]; @@ -175,13 +177,13 @@ template struct AutoSIMD vec[0] = v[0] * w[0]; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { vec[0] = v[0] * e; return *this; } - + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { vec[0] = e * v[0]; @@ -189,7 +191,6 @@ template struct AutoSIMD } }; -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e, @@ -200,7 +201,6 @@ AutoSIMD operator+(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e, @@ -211,7 +211,6 @@ AutoSIMD operator-(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e, @@ -222,7 +221,6 @@ AutoSIMD operator*(const scalar_t &e, return r; } -// ***************************************************************************** template inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e, diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index 262e7a0fe9..1dea627dc2 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -12,14 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP #define MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP -#include "x86intrin.h" - -template struct AutoSIMD; - -// We have to keep all of the folowing because AutoSIMD is chosen -// depending on the definition of MFEM_SIMD_SIZE and MFEM_TEMPLATE_BLOCK_SIZE -// in config/tconfig.h - #include "m64.hpp" #include "m128.hpp" diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index ff9f940d9a..7f2af90a81 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -593,7 +593,7 @@ public: const int NE = mesh.GetNE(); for (int el = 0; el < NE; el++) { - TTensor3 > x_dof, y_dof; + TTensor3 > x_dof, y_dof; solFES.SetElement(el); solFES.VectorExtract(solVecLayout, x, x_dof.layout, x_dof); From 696950f296a441e94d20ae78aea47b000da9a321 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 15:12:58 -0800 Subject: [PATCH 066/535] Move MFEM_POSIX_MEMALIGN to tconfig.hpp --- config/tconfig.hpp | 9 +++++++++ fem/tbilinearform.hpp | 27 ++++++++------------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index f144a64785..6cd470ab67 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -46,6 +46,15 @@ #define MFEM_ALIGN_AS(bytes) #endif +// --- POSIX MEMALIGN +#ifdef _WIN32 +#define MFEM_POSIX_MEMALIGN(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno) +#define MFEM_POSIX_MEMALIGN_FREE _aligned_free +#else +#define MFEM_POSIX_MEMALIGN posix_memalign +#define MFEM_POSIX_MEMALIGN_FREE free +#endif + // --- AutoSIMD or intrinsics #ifndef MFEM_USE_SIMD #include "simd/auto.hpp" diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 7f2af90a81..485814304e 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -20,13 +20,6 @@ #include "tcoefficient.hpp" #include "fespace.hpp" -#ifdef _WIN32 -#define posix_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno) -#define posix_memalign_free _aligned_free -#else -#define posix_memalign_free free -#endif - namespace mfem { @@ -60,10 +53,9 @@ protected: static const int dofs = solFE_type::dofs; static const int vdim = solVecLayout_t::vec_dim; static const int qpts = IR::qpts; - - static const int SS = impl_traits_t::simd_size; - static const int BE = impl_traits_t::batch_size; // batch-size of elements - static const int TE = SS*BE; + static const int SS = impl_traits_t::simd_size; + static const int BE = impl_traits_t::batch_size; + static const int TE = SS*BE; typedef typename impl_traits_t::vcomplex_t vcomplex_t; typedef typename impl_traits_t::vreal_t vreal_t; @@ -129,7 +121,7 @@ public: virtual ~TBilinearForm() { - posix_memalign_free(assembled_data); + MFEM_POSIX_MEMALIGN_FREE(assembled_data); } /// Get the input finite element space prolongation matrix @@ -205,7 +197,7 @@ public: { void* result; const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); - posix_memalign(&result, 32, size); + MFEM_POSIX_MEMALIGN(&result, 32, size); if (!result) { throw ::std::bad_alloc(); } assembled_data = (p_assembled_t*) result; } @@ -283,7 +275,7 @@ public: const int NE = mesh.GetNE(); // TODO: How do we make sure that this array is aligned properly, AND - // the compiler knows that it is aligned? + // the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready const int NVE = (NE+TE-1)/TE; vreal_t *vsNodes = new vreal_t[lnodes_t::size*NVE]; sNodes.NewDataAndSize(vsNodes[0].vec, (lnodes_t::size*SS)*NVE); @@ -308,7 +300,7 @@ public: if (!assembled_data) { // TODO: How do we make sure that this array is aligned properly, AND - // the compiler knows that it is aligned? + // the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; } const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData()); @@ -337,7 +329,7 @@ public: const int NE = mesh.GetNE(); // TODO: How do we make sure that this array is aligned properly, AND - // the compiler knows that it is aligned? + // the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready const int NVE = (NE+TE-1)/TE; vreal_t *vsx = new vreal_t[vdof_data_t::size*NVE]; sx.NewDataAndSize(vsx[0].vec, (vdof_data_t::size*SS)*NVE); @@ -357,10 +349,7 @@ public: solFieldEval solFEval(solFES, solEval, solVecLayout, NULL, NULL); const int NE = mesh.GetNE(); - // TODO: How do we make sure that the compiler knows that this array is - // aligned? const vreal_t *vsx = (const vreal_t*)(sx.GetData()); - // TODO: Check if the pointer is aligned properly. vreal_t *vsy = (vreal_t*)(sy.GetData()); for (int el = 0; el < NE; el += TE) From b625f628d4ae42bc1adaec5fff775f06e1e0d932 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 15:36:09 -0800 Subject: [PATCH 067/535] ABI of passing aggregates with 32-byte alignment warning fix --- linalg/tmatrix.hpp | 8 ++++---- linalg/ttensor.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/linalg/tmatrix.hpp b/linalg/tmatrix.hpp index 68eeb99b26..328b8b80e7 100644 --- a/linalg/tmatrix.hpp +++ b/linalg/tmatrix.hpp @@ -449,8 +449,8 @@ struct MatrixOps<3,3>::Symm template static inline MFEM_ALWAYS_INLINE void Set(const A_layout_t &a, A_data_t &A, - const scalar_t a11, const scalar_t a21, const scalar_t a31, - const scalar_t a22, const scalar_t a32, const scalar_t a33) + const scalar_t &a11, const scalar_t &a21, const scalar_t &a31, + const scalar_t &a22, const scalar_t &a32, const scalar_t &a33) { A[a.ind(0)] = a11; A[a.ind(1)] = a21; @@ -467,8 +467,8 @@ struct MatrixOps<3,3>::Symm template static inline MFEM_ALWAYS_INLINE void Set(const A_layout_t &a, A_data_t &A, - const scalar_t a11, const scalar_t a21, const scalar_t a31, - const scalar_t a22, const scalar_t a32, const scalar_t a33) + const scalar_t &a11, const scalar_t &a21, const scalar_t &a31, + const scalar_t &a22, const scalar_t &a32, const scalar_t &a33) { A[a.ind(0,0)] = a11; A[a.ind(1,0)] = a21; diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index cfab39cd63..fea23c0e02 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -37,7 +37,7 @@ struct TensorOps<1> // rank = 1 template static void Assign(const A_layout_t &A_layout, A_data_t &A_data, - scalar_t value) + const scalar_t &value) { MFEM_STATIC_ASSERT(A_layout_t::rank == 1, "invalid rank"); for (int i1 = 0; i1 < A_layout_t::dim_1; i1++) @@ -217,7 +217,7 @@ struct TensorOps<4> // rank = 4 template inline void TAssign(const A_layout_t &A_layout, A_data_t &A_data, - scalar_t value) + const scalar_t &value) { internal::TensorOps:: template Assign(A_layout, A_data, value); @@ -255,7 +255,7 @@ public: const data_t &operator[](int i) const { return data[i]; } template - void Assign(const data_t d) + void Assign(const data_t &d) { TAssign(layout, data, d); } @@ -289,7 +289,7 @@ public: AssignTo(dest); } - void Scale(const data_t scale) + void Scale(const data_t &scale) { Assign(scale); } From 40e68f7f21d00fb082ca5c7b2d6260d81d8c2c20 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 15:49:01 -0800 Subject: [PATCH 068/535] tconfig MFEM_USE_SIMD definitions fix --- config/tconfig.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 6cd470ab67..05789c64d0 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -59,13 +59,14 @@ #ifndef MFEM_USE_SIMD #include "simd/auto.hpp" #else -#ifdef __VSX__ +#if defined(__VSX__) #include "simd/vsx128.hpp" -#endif -#ifdef __bgq__ +#elif defined (__bgq__) #include "simd/qpx.hpp" -#else +#elif defined(__x86_64__) #include "simd/x86.hpp" +#else +#error Unknown SIMD architecture #endif #endif From 4b894a089a2b9f298da66766da10db4981fbee07 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 16:15:13 -0800 Subject: [PATCH 069/535] Add vsx header file and logic for Lassen --- config/simd/m128.hpp | 6 ------ config/simd/m256.hpp | 6 ------ config/simd/m512.hpp | 6 ------ config/simd/m64.hpp | 5 ----- config/simd/qpx.hpp | 4 ++++ config/simd/qpx256.hpp | 10 ---------- config/simd/qpx64.hpp | 6 ------ config/simd/vsx.hpp | 23 +++++++++++++++++++++++ config/simd/vsx128.hpp | 11 ----------- config/simd/vsx64.hpp | 7 ------- config/simd/x86.hpp | 4 ++++ 11 files changed, 31 insertions(+), 57 deletions(-) create mode 100644 config/simd/vsx.hpp diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index f94e6f6e80..6743eeebc9 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -12,12 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M128 #define MFEM_TEMPLATE_CONFIG_SIMD_M128 -#include "x86intrin.h" -template struct AutoSIMD; -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 4e5121eaa6..baf829f856 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -12,12 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M256 #define MFEM_TEMPLATE_CONFIG_SIMD_M256 -#include "x86intrin.h" -template struct AutoSIMD; -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 1fa93ee391..26cfec78d4 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -12,12 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M512 #define MFEM_TEMPLATE_CONFIG_SIMD_M512 -#include "x86intrin.h" -template struct AutoSIMD; -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index 54f3540097..40bdf4424f 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -12,11 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M64 #define MFEM_TEMPLATE_CONFIG_SIMD_M64 -template struct AutoSIMD; -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/qpx.hpp b/config/simd/qpx.hpp index a28927c82b..254504bfde 100644 --- a/config/simd/qpx.hpp +++ b/config/simd/qpx.hpp @@ -12,6 +12,10 @@ #ifndef MFEM_TEMPLATE_CONFIG_QPX_HPP #define MFEM_TEMPLATE_CONFIG_QPX_HPP +#include "builtins.h" + +template struct AutoSIMD; + #include "qpx64.hpp" #include "qpx256.hpp" diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index 0a8fee4b1f..20dbdf4966 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -12,16 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 -#include "builtins.h" -template struct AutoSIMD; -#ifndef __ATTRS_ai -#define __ATTRS_ai -#endif -#ifndef vector4double -#define vector4double double -#error Undefined vector4double -#endif - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp index 649e9d6f62..e6e27d5931 100644 --- a/config/simd/qpx64.hpp +++ b/config/simd/qpx64.hpp @@ -12,12 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 -#include "builtins.h" -template struct AutoSIMD; -#ifndef __ATTRS_ai -#define __ATTRS_ai -#endif - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/vsx.hpp b/config/simd/vsx.hpp new file mode 100644 index 0000000000..365f8b95eb --- /dev/null +++ b/config/simd/vsx.hpp @@ -0,0 +1,23 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_TEMPLATE_CONFIG_VSX_HPP +#define MFEM_TEMPLATE_CONFIG_VSX_HPP + +#include "altivec.h" + +template struct AutoSIMD; + +#include "vsx64.hpp" + +#include "vsx128.hpp" + +#endif // MFEM_TEMPLATE_CONFIG_VSX_HPP diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp index 966f746b85..488e2f3ec7 100644 --- a/config/simd/vsx128.hpp +++ b/config/simd/vsx128.hpp @@ -12,17 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX128 #define MFEM_TEMPLATE_CONFIG_SIMD_VSX128 -#include "altivec.h" -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif -#ifndef vector -#define vector -#error Undefined vector -#endif - -template struct AutoSIMD; - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/vsx64.hpp b/config/simd/vsx64.hpp index 320a4ceac3..0a5abbcd7b 100644 --- a/config/simd/vsx64.hpp +++ b/config/simd/vsx64.hpp @@ -12,13 +12,6 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX64 #define MFEM_TEMPLATE_CONFIG_SIMD_VSX64 -#include "altivec.h" -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif - -template struct AutoSIMD; - template struct AutoSIMD { typedef scalar_t scalar_type; diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index 1dea627dc2..10b02c4394 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -12,6 +12,10 @@ #ifndef MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP #define MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP +#include "x86intrin.h" + +template struct AutoSIMD; + #include "m64.hpp" #include "m128.hpp" From cafe87ba34f29f5afc650bdee71cfac96290c452 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 16:34:44 -0800 Subject: [PATCH 070/535] xlc makefile --- miniapps/performance/makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 817d507605..6be9f5c0ed 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -38,14 +38,14 @@ else ifneq (,$(filter %g++ %mpicxx %mpic++,$(MFEM_CXX))) endif else ifneq (,$(filter %icpc %mpiicpc,$(MFEM_CXX))) MFEM_PERF_SW = icc +else ifneq (,$(filter %xlc++ %mpixlC,$(MFEM_CXX))) + MFEM_PERF_SW = xlc endif # Compiler specific optimizations. # For best performance, GCC 5 (or newer) is recommended. # - GCC extra options: -# MFEM_PERF_CXXFLAGS_gcc_common += -std=c++03 -MFEM_PERF_CXXFLAGS_gcc_common += -std=c++11 MFEM_PERF_CXXFLAGS_gcc_common += -pedantic -Wall ifeq ($(MFEM_USE_SIMD),NO) MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 @@ -55,10 +55,12 @@ MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) +# - XLC extra options: +MFEM_PERF_CXXFLAGS_xlc = -mcpu=native -mtune=native + # - Clang extra options: MFEM_PERF_CXXFLAGS_clang += -march=native # MFEM_PERF_CXXFLAGS_clang += -std=c++03 -MFEM_PERF_CXXFLAGS_clang += -std=c++11 MFEM_PERF_CXXFLAGS_clang += -pedantic -Wall MFEM_PERF_CXXFLAGS_clang += -fcolor-diagnostics MFEM_PERF_CXXFLAGS_clang += -fvectorize @@ -68,7 +70,6 @@ MFEM_PERF_CXXFLAGS_clang += -ffp-contract=fast # - Intel C++ compiler extra options: MFEM_PERF_CXXFLAGS_icc += -xHost -MFEM_PERF_CXXFLAGS_icc += -std=c++11 # Choose MFEM_PERF_CXXFLAGS based on MFEM_PERF_SW: MFEM_PERF_CXXFLAGS = $(MFEM_PERF_CXXFLAGS_$(MFEM_PERF_SW)) From 25961fd099e862eaa30f80cab4bd82ad0642d37a Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 16:36:06 -0800 Subject: [PATCH 071/535] Use vsx header --- config/tconfig.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 05789c64d0..8ec5488435 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -60,7 +60,7 @@ #include "simd/auto.hpp" #else #if defined(__VSX__) -#include "simd/vsx128.hpp" +#include "simd/vsx.hpp" #elif defined (__bgq__) #include "simd/qpx.hpp" #elif defined(__x86_64__) From af10111e3512531b24eb7ac5300f26a994bdfccc Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 16:37:13 -0800 Subject: [PATCH 072/535] Remove unsupported mtune option --- miniapps/performance/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 6be9f5c0ed..48b1228e50 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -56,7 +56,7 @@ MFEM_PERF_CXXFLAGS_gcc_ppc64 = -mcpu=native -mtune=native\ $(MFEM_PERF_CXXFLAGS_gcc_common) # - XLC extra options: -MFEM_PERF_CXXFLAGS_xlc = -mcpu=native -mtune=native +MFEM_PERF_CXXFLAGS_xlc = -mcpu=native # - Clang extra options: MFEM_PERF_CXXFLAGS_clang += -march=native From cec012321ba37ca2c0e046f35642a855098b44f2 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Jan 2020 17:12:19 -0800 Subject: [PATCH 073/535] VSX tconfig logic --- config/tconfig.hpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 8ec5488435..a5369c6574 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -70,27 +70,18 @@ #endif #endif -// --- Default SIMD and BLOCK sizes -#ifdef _WIN32 -#define MFEM_SIMD_DEFAULT_SIZE 8 -#define MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE 1 -#else -#define MFEM_SIMD_DEFAULT_SIZE 32 -#define MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE 4 -#endif - // --- SIMD and BLOCK sizes -#ifndef MFEM_USE_SIMD -#define MFEM_SIMD_SIZE MFEM_SIMD_DEFAULT_SIZE -#define MFEM_TEMPLATE_BLOCK_SIZE MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE -#else -#ifdef __VSX__ +#if defined(_WIN32) +#define MFEM_SIMD_SIZE 8 +#define MFEM_TEMPLATE_BLOCK_SIZE 1 +#elif defined(__VSX__) #define MFEM_SIMD_SIZE 16 #define MFEM_TEMPLATE_BLOCK_SIZE 2 +#elif defined(__x86_64__) +#define MFEM_SIMD_SIZE 32 +#define MFEM_TEMPLATE_BLOCK_SIZE 4 #else -#define MFEM_SIMD_SIZE MFEM_SIMD_DEFAULT_SIZE -#define MFEM_TEMPLATE_BLOCK_SIZE MFEM_TEMPLATE_BLOCK_DEFAULT_SIZE -#endif +#error Unknown SIMD architecture #endif template From e801b87fdabe44c02e336369944f70dcc88ad41d Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 11:55:56 -0800 Subject: [PATCH 074/535] Fixing getVectorValues usage --- fem/datacollection.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fem/datacollection.cpp b/fem/datacollection.cpp index 27fdaf0fae..ba76495ffd 100644 --- a/fem/datacollection.cpp +++ b/fem/datacollection.cpp @@ -966,7 +966,9 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &out, int ref_, { RefinedGeometry *RefG; Vector val; - DenseMatrix vval, pmat; + DenseMatrix vval; + + const FiniteElementSpace *fes = it->second->FESpace(); int vec_dim = it->second->VectorDim(); if (vec_dim == 1) { @@ -975,9 +977,10 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &out, int ref_, out << "\" NumberOfComponents=\"1\" format=\"ascii\" >" << std::endl; for (int i = 0; i < mesh->GetNE(); i++) { + ElementTransformation *Tr = fes->GetElementTransformation(i); RefG = GlobGeometryRefiner.Refine( mesh->GetElementBaseGeometry(i), ref_, 1); - it->second->GetValues(i, RefG->RefPts, val, pmat); + it->second->GetValues(*Tr, RefG->RefPts, val); for (int j = 0; j < val.Size(); j++) { out << val(j) << '\n'; @@ -993,10 +996,11 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &out, int ref_, std::endl; for (int i = 0; i < mesh->GetNE(); i++) { + ElementTransformation *Tr = fes->GetElementTransformation(i); RefG = GlobGeometryRefiner.Refine( mesh->GetElementBaseGeometry(i), ref_, 1); - it->second->GetVectorValues(i, RefG->RefPts, vval, pmat); + it->second->GetVectorValues(*Tr, RefG->RefPts, vval); for (int jj = 0; jj < vval.Width(); jj++) { From f3888a5a73ecd1c8b1927f18c0ebf099e9dbe2f2 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 13:50:10 -0800 Subject: [PATCH 075/535] make style --- fem/lininteg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 831259dddc..b6e57b1f01 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -502,7 +502,7 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( Tr.SetIntPoint(&ip); Tr.SetActiveSide(0); - + // Use Tr transformation in case u or f depends on boundary attribute u->Eval(vu, Tr, ip); From 08c6d61928c7f53a4e64e1e3c5e8eccbab85cfd0 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 14:29:32 -0800 Subject: [PATCH 076/535] Adding implementation of GetValues method so that examples will compile --- fem/gridfunc.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 622434af61..13064af53e 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -644,6 +644,89 @@ double GridFunction::GetValue(ElementTransformation &T, return (DofVal * LocVec); } +void GridFunction::GetValues(ElementTransformation &T, + const IntegrationRule &ir, + Vector &vals, int comp, + DenseMatrix *tr) const +{ + if (tr) + { + T.Transform(ir, *tr); + } + + int nip = ir.GetNPoints(); + vals.SetSize(nip); + + Array dofs; + const FiniteElement * fe = NULL; + if (T.ElementType == ElementTransformation::ELEMENT) + { + fes->GetElementDofs(T.ElementNo, dofs); + fe = fes->GetFE(T.ElementNo); + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + fes->GetBdrElementDofs(T.ElementNo, dofs); + fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field. Check for DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + vals[j] = GetValue(*FET, ip, comp); + } + return; + } + } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + vals[j] = GetValue(*FET, ip, comp); + } + return; + } + } + else + { + MFEM_ABORT("GridFunction::GetValue: Unsupported element type \"" + << T.ElementType << "\""); + } + + fes->DofsToVDofs(comp-1, dofs); + Vector DofVal(dofs.Size()), LocVec; + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, DofVal); + } + else + { + fe->CalcPhysShape(T, DofVal); + } + GetSubVector(dofs, LocVec); + + vals[j] = (DofVal * LocVec); + } +} + double GridFunction::GetValue(FaceElementTransformations &FET, const IntegrationPoint &ip, int comp, Vector *tr) const From 69f6e413f1beca2dca5ad6d5bc9e02db250ad484 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 14:52:05 -0800 Subject: [PATCH 077/535] Simplifying GetValues methods by using GetValue methods --- fem/gridfunc.cpp | 110 ++++------------------------------------------- 1 file changed, 9 insertions(+), 101 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 13064af53e..36c92123b1 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -656,74 +656,10 @@ void GridFunction::GetValues(ElementTransformation &T, int nip = ir.GetNPoints(); vals.SetSize(nip); - - Array dofs; - const FiniteElement * fe = NULL; - if (T.ElementType == ElementTransformation::ELEMENT) - { - fes->GetElementDofs(T.ElementNo, dofs); - fe = fes->GetFE(T.ElementNo); - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - fes->GetBdrElementDofs(T.ElementNo, dofs); - fe = fes->GetBE(T.ElementNo); - - if (fe == NULL) - { - // This must be a DG field. Check for DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET == NULL) - { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - } - for (int j = 0; j < nip; j++) - { - const IntegrationPoint &ip = ir.IntPoint(j); - vals[j] = GetValue(*FET, ip, comp); - } - return; - } - } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) - { - for (int j = 0; j < nip; j++) - { - const IntegrationPoint &ip = ir.IntPoint(j); - vals[j] = GetValue(*FET, ip, comp); - } - return; - } - } - else - { - MFEM_ABORT("GridFunction::GetValue: Unsupported element type \"" - << T.ElementType << "\""); - } - - fes->DofsToVDofs(comp-1, dofs); - Vector DofVal(dofs.Size()), LocVec; for (int j = 0; j < nip; j++) { const IntegrationPoint &ip = ir.IntPoint(j); - if (fe->GetMapType() == FiniteElement::VALUE) - { - fe->CalcShape(ip, DofVal); - } - else - { - fe->CalcPhysShape(T, DofVal); - } - GetSubVector(dofs, LocVec); - - vals[j] = (DofVal * LocVec); + vals[j] = GetValue(T, ip, comp); } } @@ -846,44 +782,16 @@ void GridFunction::GetVectorValues(ElementTransformation &T, { T.Transform(ir, *tr); } - const FiniteElement *FElem = fes->GetFE(T.ElementNo); - int dof = FElem->GetDof(); - Array vdofs; - fes->GetElementVDofs(T.ElementNo, vdofs); - Vector loc_data; - GetSubVector(vdofs, loc_data); + + int vdim = fes->GetVDim(); int nip = ir.GetNPoints(); - if (FElem->GetRangeType() == FiniteElement::SCALAR) + vals.SetSize(vdim, nip); + Vector val; + for (int j = 0; j < nip; j++) { - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - Vector shape(dof); - int vdim = fes->GetVDim(); - vals.SetSize(vdim, nip); - for (int j = 0; j < nip; j++) - { - const IntegrationPoint &ip = ir.IntPoint(j); - FElem->CalcShape(ip, shape); - for (int k = 0; k < vdim; k++) - { - vals(k,j) = shape * ((const double *)loc_data + dof * k); - } - } - } - else - { - int spaceDim = fes->GetMesh()->SpaceDimension(); - DenseMatrix vshape(dof, spaceDim); - vals.SetSize(spaceDim, nip); - Vector val_j; - for (int j = 0; j < nip; j++) - { - const IntegrationPoint &ip = ir.IntPoint(j); - T.SetIntPoint(&ip); - FElem->CalcVShape(T, vshape); - vals.GetColumnReference(j, val_j); - vshape.MultTranspose(loc_data, val_j); - } + const IntegrationPoint &ip = ir.IntPoint(j); + vals.GetColumnReference(j, val); + GetVectorValue(T, ip, val); } } From 57bd13e29eade1d12d2df25942bf977344fe6df0 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 15:59:00 -0800 Subject: [PATCH 078/535] Setting index type in a couple missed locations --- mesh/mesh.cpp | 2 ++ mesh/pmesh.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 18878682c7..33ce28ea45 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -467,6 +467,7 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr) IntegrationRule eir(face_el->GetDof()); FaceElemTr.Loc1.Transf.ElementNo = elem_id; + FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT; FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir); Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm); @@ -533,6 +534,7 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr) IntegrationRule eir(face_el->GetDof()); FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No; + FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT; FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir); Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm); diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index ff1b447b18..4ad500386f 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -1587,6 +1587,7 @@ void ParMesh::GetFaceNbrElementTransformation( ElTr->Attribute = elem->GetAttribute(); ElTr->ElementNo = NumOfElements + i; + ElTr->ElementType = ElementTransformation::ELEMENT; if (Nodes == NULL) { From d8c11bb42d0b38063f3f726d3b68cbe4b3668d16 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 16:03:02 -0800 Subject: [PATCH 079/535] Setting index type in TMOP classes --- fem/tmop.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 10a093f421..3cfa4dab70 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -906,6 +906,7 @@ void AnalyticAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, IsoparametricTransformation Tpr; Tpr.SetFE(&fe); Tpr.ElementNo = e_id; + Tpr.ElementType = ElementTransformation::ELEMENT; Tpr.GetPointMat().Transpose(point_mat); for (int i = 0; i < ir.GetNPoints(); i++) @@ -1124,6 +1125,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); Tpr->ElementNo = T.ElementNo; + Tpr->ElementType = ElementTransformation::ELEMENT; Tpr->Attribute = T.Attribute; Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T } @@ -1220,6 +1222,7 @@ void TMOP_Integrator::AssembleElementVector(const FiniteElement &el, Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); Tpr->ElementNo = T.ElementNo; + Tpr->ElementType = ElementTransformation::ELEMENT; Tpr->Attribute = T.Attribute; Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T } @@ -1313,6 +1316,7 @@ void TMOP_Integrator::AssembleElementGrad(const FiniteElement &el, Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); Tpr->ElementNo = T.ElementNo; + Tpr->ElementType = ElementTransformation::ELEMENT; Tpr->Attribute = T.Attribute; Tpr->GetPointMat().Transpose(PMatI); } From 8fb34a4cadee06237559bd00830232c0b0e33b5b Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 23 Jan 2020 17:03:06 -0800 Subject: [PATCH 080/535] Bug fixes in GetValues methods (thanks to unit testing) --- fem/gridfunc.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 36c92123b1..6703a1d010 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -659,6 +659,7 @@ void GridFunction::GetValues(ElementTransformation &T, for (int j = 0; j < nip; j++) { const IntegrationPoint &ip = ir.IntPoint(j); + T.SetIntPoint(&ip); vals[j] = GetValue(T, ip, comp); } } @@ -790,8 +791,9 @@ void GridFunction::GetVectorValues(ElementTransformation &T, for (int j = 0; j < nip; j++) { const IntegrationPoint &ip = ir.IntPoint(j); - vals.GetColumnReference(j, val); + T.SetIntPoint(&ip); GetVectorValue(T, ip, val); + vals.SetCol(j, val); } } From b7ca7c3ca02ed05ab543dd7fe0217084e851bec2 Mon Sep 17 00:00:00 2001 From: rcarson3 Date: Tue, 4 Feb 2020 09:17:14 -0800 Subject: [PATCH 081/535] Initial QuadratureFunction Coefficient and VectorCoefficient implementations --- fem/coefficient.cpp | 47 ++++++++++++++++++++++++++++++++++++ fem/coefficient.hpp | 59 +++++++++++++++++++++++++++++++++++++++++++++ fem/gridfunc.hpp | 15 ++++++++++++ 3 files changed, 121 insertions(+) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 4bf36c4fc9..da9d23b430 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -758,4 +758,51 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, } #endif +void QuadratureVectorFunctionCoefficient::SetLength(int _length) +{ + int vdim = QuadF->GetVDim(); + + MFEM_ASSERT(_length > 0, "Length must be > 0"); + vdim -= index; + MFEM_ASSERT(_length <= vdim, "Length must be <= (QuadratureFunction length - index)"); + + length = _length; +} + +void QuadratureVectorFunctionCoefficient::SetIndex(int _index) +{ + MFEM_ASSERT(_index >= 0, "Index must be >= 0"); + MFEM_ASSERT(_index < QuadF->GetVDim(), "Index must be < the QuadratureFunction length"); + index = _index; +} + +void QuadratureVectorFunctionCoefficient::Eval(Vector &V, + ElementTransformation &T, + const IntegrationPoint &ip) +{ + int elem_no = T.ElementNo; + if (index == 0 && length == QuadF->GetVDim()) { + QuadF->GetElementValues(elem_no, ip.index, V); + } + else { + // This will need to be improved upon... + Vector temp; + QuadF->GetElementValues(elem_no, ip.index, temp); + double *data = temp.GetData(); + V.NewDataAndSize(data + index, length); + } + + return; +} + +/// Evaluate the function coefficient at a specific quadrature point +double QuadratureFunctionCoefficient::Eval(ElementTransformation &T, + const IntegrationPoint &ip) +{ + int elem_no = T.ElementNo; + Vector temp(1); + QuadF->GetElementValues(elem_no, ip.index, temp); + return temp[0]; +} + } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 4a8e8336cc..9ef00851e7 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -945,6 +945,65 @@ public: const IntegrationPoint &ip); }; +class QuadratureFunction; + +/// Quadrature function coefficient +class QuadratureVectorFunctionCoefficient : public VectorCoefficient +{ + private: + QuadratureFunction *QuadF; + int index; + int length; + + public: + // constructor with a quadrature function as input + QuadratureVectorFunctionCoefficient(QuadratureFunction *qf) + : VectorCoefficient(0) + { + QuadF = qf; + index = 0; + length = -1;//qf->GetVDim(); + } + + // constructor with a null qf + QuadratureVectorFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } + + void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } + + void SetIndex(int _index); + void SetLength(int _length); + + QuadratureFunction *GetQuadFunction() const { return QuadF; } + + using VectorCoefficient::Eval; + virtual void Eval(Vector &V, ElementTransformation &T, + const IntegrationPoint &ip); + + virtual ~QuadratureVectorFunctionCoefficient() { }; +}; + +/// Generic quadrature function coefficient class for using +/// coefficients which only live at integration points +class QuadratureFunctionCoefficient : public Coefficient +{ + private: + QuadratureFunction *QuadF; + + public: + QuadratureFunctionCoefficient(QuadratureFunction *qf) { QuadF = qf; } + + QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } + + void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } + + QuadratureFunction *GetQuadFunction() const { return QuadF; } + + virtual double Eval(ElementTransformation &T, + const IntegrationPoint &ip); + + virtual ~QuadratureFunctionCoefficient() { }; +}; + /** Compute the Lp norm of a function f. \f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */ double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh, diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 39f520460b..85100a9ae8 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -611,6 +611,12 @@ public: */ inline void GetElementValues(int idx, Vector &values) const; + /// Return the quadrature function values at an integration point + /** The result is stored in the Vector @a values as a reference to the + global values. + */ + inline void GetElementValues(int idx, const int ip_num, Vector &values); + /// Return all values associated with mesh element @a idx in a DenseMatrix. /** The result is stored in the DenseMatrix @a values as a reference to the global values. @@ -713,6 +719,15 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const values(i) = *(q++); } } +// fix me: This function should have a more efficient method for doing this operation. +inline void QuadratureFunction::GetElementValues(int idx, const int ip_num, + Vector &values) +{ + Vector elem_vec; + GetElementValues(idx, elem_vec); + int vDim = GetVDim(); + values.NewDataAndSize(elem_vec + ip_num * vDim, vDim); +} inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values) { From f8b0ecdba8b5ff041f8a8724286ed996e7064fa6 Mon Sep 17 00:00:00 2001 From: rcarson3 Date: Tue, 4 Feb 2020 11:50:21 -0800 Subject: [PATCH 082/535] make style --- fem/coefficient.cpp | 12 +++++--- fem/coefficient.hpp | 68 ++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index da9d23b430..da098963e4 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -764,7 +764,8 @@ void QuadratureVectorFunctionCoefficient::SetLength(int _length) MFEM_ASSERT(_length > 0, "Length must be > 0"); vdim -= index; - MFEM_ASSERT(_length <= vdim, "Length must be <= (QuadratureFunction length - index)"); + MFEM_ASSERT(_length <= vdim, + "Length must be <= (QuadratureFunction length - index)"); length = _length; } @@ -772,7 +773,8 @@ void QuadratureVectorFunctionCoefficient::SetLength(int _length) void QuadratureVectorFunctionCoefficient::SetIndex(int _index) { MFEM_ASSERT(_index >= 0, "Index must be >= 0"); - MFEM_ASSERT(_index < QuadF->GetVDim(), "Index must be < the QuadratureFunction length"); + MFEM_ASSERT(_index < QuadF->GetVDim(), + "Index must be < the QuadratureFunction length"); index = _index; } @@ -781,10 +783,12 @@ void QuadratureVectorFunctionCoefficient::Eval(Vector &V, const IntegrationPoint &ip) { int elem_no = T.ElementNo; - if (index == 0 && length == QuadF->GetVDim()) { + if (index == 0 && length == QuadF->GetVDim()) + { QuadF->GetElementValues(elem_no, ip.index, V); } - else { + else + { // This will need to be improved upon... Vector temp; QuadF->GetElementValues(elem_no, ip.index, temp); diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 9ef00851e7..e3a06c5fda 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -950,58 +950,58 @@ class QuadratureFunction; /// Quadrature function coefficient class QuadratureVectorFunctionCoefficient : public VectorCoefficient { - private: - QuadratureFunction *QuadF; - int index; - int length; +private: + QuadratureFunction *QuadF; + int index; + int length; - public: - // constructor with a quadrature function as input - QuadratureVectorFunctionCoefficient(QuadratureFunction *qf) - : VectorCoefficient(0) - { - QuadF = qf; - index = 0; - length = -1;//qf->GetVDim(); - } +public: + // constructor with a quadrature function as input + QuadratureVectorFunctionCoefficient(QuadratureFunction *qf) + : VectorCoefficient(0) + { + QuadF = qf; + index = 0; + length = -1;//qf->GetVDim(); + } - // constructor with a null qf - QuadratureVectorFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } + // constructor with a null qf + QuadratureVectorFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } - void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } + void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } - void SetIndex(int _index); - void SetLength(int _length); + void SetIndex(int _index); + void SetLength(int _length); - QuadratureFunction *GetQuadFunction() const { return QuadF; } + QuadratureFunction *GetQuadFunction() const { return QuadF; } - using VectorCoefficient::Eval; - virtual void Eval(Vector &V, ElementTransformation &T, - const IntegrationPoint &ip); + using VectorCoefficient::Eval; + virtual void Eval(Vector &V, ElementTransformation &T, + const IntegrationPoint &ip); - virtual ~QuadratureVectorFunctionCoefficient() { }; + virtual ~QuadratureVectorFunctionCoefficient() { }; }; /// Generic quadrature function coefficient class for using /// coefficients which only live at integration points class QuadratureFunctionCoefficient : public Coefficient { - private: - QuadratureFunction *QuadF; +private: + QuadratureFunction *QuadF; - public: - QuadratureFunctionCoefficient(QuadratureFunction *qf) { QuadF = qf; } +public: + QuadratureFunctionCoefficient(QuadratureFunction *qf) { QuadF = qf; } - QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } + QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } - void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } + void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } - QuadratureFunction *GetQuadFunction() const { return QuadF; } + QuadratureFunction *GetQuadFunction() const { return QuadF; } - virtual double Eval(ElementTransformation &T, - const IntegrationPoint &ip); - - virtual ~QuadratureFunctionCoefficient() { }; + virtual double Eval(ElementTransformation &T, + const IntegrationPoint &ip); + + virtual ~QuadratureFunctionCoefficient() { }; }; /** Compute the Lp norm of a function f. From 364c3fe055486dc193cd248b978f0e4fcc4b906e Mon Sep 17 00:00:00 2001 From: rcarson3 Date: Wed, 5 Feb 2020 09:20:20 -0800 Subject: [PATCH 083/535] Additional run-time checks and nicer class construction --- fem/coefficient.cpp | 43 +++++++++++++++++++++++++++++++++++++------ fem/coefficient.hpp | 16 +++++----------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index da098963e4..37667427a6 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -758,13 +758,30 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, } #endif +QuadratureVectorFunctionCoefficient::QuadratureVectorFunctionCoefficient( + QuadratureFunction *qf) + : VectorCoefficient(qf->GetVDim()) +{ + QuadF = qf; + index = 0; + length = qf->GetVDim(); +} + +void QuadratureVectorFunctionCoefficient::SetQuadratureFunction( + QuadratureFunction *qf) +{ + index = 0; + length = qf->GetVDim(); + vdim = length; + QuadF = qf; +} + void QuadratureVectorFunctionCoefficient::SetLength(int _length) { - int vdim = QuadF->GetVDim(); - MFEM_ASSERT(_length > 0, "Length must be > 0"); - vdim -= index; - MFEM_ASSERT(_length <= vdim, + + int diff = vdim - index; + MFEM_ASSERT(_length <= diff, "Length must be <= (QuadratureFunction length - index)"); length = _length; @@ -773,7 +790,7 @@ void QuadratureVectorFunctionCoefficient::SetLength(int _length) void QuadratureVectorFunctionCoefficient::SetIndex(int _index) { MFEM_ASSERT(_index >= 0, "Index must be >= 0"); - MFEM_ASSERT(_index < QuadF->GetVDim(), + MFEM_ASSERT(_index < vdim, "Index must be < the QuadratureFunction length"); index = _index; } @@ -783,7 +800,7 @@ void QuadratureVectorFunctionCoefficient::Eval(Vector &V, const IntegrationPoint &ip) { int elem_no = T.ElementNo; - if (index == 0 && length == QuadF->GetVDim()) + if (index == 0 && length == vdim) { QuadF->GetElementValues(elem_no, ip.index, V); } @@ -799,6 +816,20 @@ void QuadratureVectorFunctionCoefficient::Eval(Vector &V, return; } +QuadratureFunctionCoefficient::QuadratureFunctionCoefficient( + QuadratureFunction *qf) +{ + MFEM_ASSERT(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); + QuadF = qf; +} + +void QuadratureFunctionCoefficient::SetQuadratureFunction( + QuadratureFunction *qf) +{ + MFEM_ASSERT(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); + QuadF = qf; +} + /// Evaluate the function coefficient at a specific quadrature point double QuadratureFunctionCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index e3a06c5fda..29fef352b2 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -947,7 +947,7 @@ public: class QuadratureFunction; -/// Quadrature function coefficient +/// Quadrature function vector coefficient class QuadratureVectorFunctionCoefficient : public VectorCoefficient { private: @@ -957,18 +957,12 @@ private: public: // constructor with a quadrature function as input - QuadratureVectorFunctionCoefficient(QuadratureFunction *qf) - : VectorCoefficient(0) - { - QuadF = qf; - index = 0; - length = -1;//qf->GetVDim(); - } + QuadratureVectorFunctionCoefficient(QuadratureFunction *qf); // constructor with a null qf QuadratureVectorFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } - void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } + void SetQuadratureFunction(QuadratureFunction *qf); void SetIndex(int _index); void SetLength(int _length); @@ -990,11 +984,11 @@ private: QuadratureFunction *QuadF; public: - QuadratureFunctionCoefficient(QuadratureFunction *qf) { QuadF = qf; } + QuadratureFunctionCoefficient(QuadratureFunction *qf); QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } - void SetQuadratureFunction(QuadratureFunction *qf) { QuadF = qf; } + void SetQuadratureFunction(QuadratureFunction *qf); QuadratureFunction *GetQuadFunction() const { return QuadF; } From 54764ae988712fc34d027eaa6cb292fe512ddb50 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Fri, 28 Feb 2020 16:34:23 -0800 Subject: [PATCH 084/535] working version for multiple discrete fields --- fem/gslib.cpp | 54 ++-- fem/tmop.cpp | 391 ++++++++++++++++++++------- fem/tmop.hpp | 34 ++- fem/tmop_tools.cpp | 15 +- fem/tmop_tools.hpp | 8 - miniapps/meshing/mesh-optimizer.cpp | 187 ++++++++++--- miniapps/meshing/pmesh-optimizer.cpp | 196 +++++++++++--- 7 files changed, 664 insertions(+), 221 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 54e9424b6a..d120ffd05f 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -158,27 +158,43 @@ void FindPointsGSLIB::Interpolate(Array &codes, Vector &ref_pos, const GridFunction &field_in, Vector &field_out) { - Vector node_vals; - GetNodeValues(field_in, node_vals); - const int points_cnt = ref_pos.Size() / dim; - if (dim==2) + H1_FECollection ind_fec(mesh->GetNodalFESpace()->GetFE(0)->GetOrder(), dim); + FiniteElementSpace ind_fes(mesh, &ind_fec); + GridFunction field_in_scalar; + field_in_scalar.SetSpace(&ind_fes); + Vector node_vals; + + int ncomp = field_in.FESpace()->GetVDim(); + for (int i=0;i0," Must set atleast 1 discrete target spec"); + + adapt_eval->SetParMetaInfo(*ptspec_fes->GetParMesh(), + *ptspec_fes->FEColl(), + ncomp); + adapt_eval->SetInitialField + (*tspec_fes->GetMesh()->GetNodes(), tspec); + + tspec_sav.SetSize(tspec.Size()); + BackupTargetSpecification(); + + tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), + tspec_fes->FEColl(), + ncomp); +} + +void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) +{ + if (ncomp==0) + { + tspec_fes = tspec_.FESpace(); + ptspec_fes = tspec_.ParFESpace(); + } + MFEM_VERIFY(tspec_.FESpace()->GetVDim()==1,"Only GridFunctions defined " + "on Scalar FESpace are accepted"); + ncomp += 1; + int sz = tspec_.Size(); + Vector tspec_temp; + tspec_temp.SetSize(tspec.Size()); + for (int i=0;iGetVDim()==1,"Only GridFunctions defined " + "on Scalar FESpace are accepted"); + ncomp += 1; + int sz = tspec_.Size(); + Vector tspec_temp; + tspec_temp.SetSize(tspec.Size()); + for (int i=0;i0," Must set atleast 1 discrete target spec"); + + adapt_eval->SetSerialMetaInfo(*tspec_fes->GetMesh(), + *tspec_fes->FEColl(), + ncomp); + adapt_eval->SetInitialField + (*tspec_fes->GetMesh()->GetNodes(), tspec); + + tspec_sav.SetSize(tspec.Size()); + BackupTargetSpecification(); + + tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), + tspec_fes->FEColl(), + ncomp); +} + void DiscreteAdaptTC::UpdateTargetSpecification(const Vector &new_x) { MFEM_VERIFY(tspec.Size() > 0, "Target specification is not set!"); @@ -1017,18 +1162,27 @@ void DiscreteAdaptTC::UpdateTargetSpecificationAtNode(const FiniteElement &el, Array dofs; tspec_fes->GetElementDofs(T.ElementNo, dofs); - int cnt = tspec.Size(); - tspec(dofs[nodenum]) = IntData(dofs[nodenum]+idir*cnt); + int cnt = tspec.Size()/ncomp; + int dimmax = IntData.Size()/tspec.Size(); +// std::cout << tspec.Size() << " " << IntData.Size() << " k10check\n"; + for (int i=0;i 0, "Target specification is not set!"); Array dofs; tspec_fes->GetElementDofs(T.ElementNo, dofs); - tspec(dofs[nodenum]) = tspec_sav(dofs[nodenum]); + int cnt = tspec.Size()/ncomp; + for (int i=0;iGetFE(0)->GetDof(); + ntspec_dofs = ncomp*tspec_fes->GetFE(0)->GetDof(); - Vector shape(ntspec_dofs), tspec_vals(ntspec_dofs); + Vector shape(ntspec_dofs/ncomp), tspec_vals(ntspec_dofs); Array dofs; - tspec_fes->GetElementDofs(e_id, dofs); + tspec_fesv->GetElementVDofs(e_id, dofs); tspec.GetSubVector(dofs, tspec_vals); - const double min_size = tspec_vals.Min(); - MFEM_ASSERT(min_size > 0.0, - "Non-positive size propagated in the target definition."); - for (int i = 0; i < ir.GetNPoints(); i++) { const IntegrationPoint &ip = ir.IntPoint(i); tspec_fes->GetFE(e_id)->CalcShape(ip, shape); - const double size = std::max(shape * tspec_vals, min_size); - Jtr(i).Set(std::pow(size / Wideal.Det(), 1.0/dim), Wideal); + Jtr(i) = Wideal; //Initialize to identity } + + int ndofs = ntspec_dofs/ncomp; + Vector par_vals; + + if (sizeidx>-1) //Set size spec + { + par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs,ndofs); + const double min_size = par_vals.Min(); + MFEM_VERIFY(min_size > 0.0, + "Non-positive size propagated in the target definition."); + + for (int i = 0; i < ir.GetNPoints(); i++) + { + const IntegrationPoint &ip = ir.IntPoint(i); + tspec_fes->GetFE(e_id)->CalcShape(ip, shape); + const double size = std::max(shape * par_vals, min_size); + Jtr(i).Set(std::pow(size, 1.0/dim), Jtr(i)); + } + } + if (target_type==IDEAL_SHAPE_GIVEN_SIZE) {break;} + + if (aspectratioidx>-1) //Set aspect ratio spec + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + aspectratioidx*ndofs,ndofs); + const double min_size = par_vals.Min(); + MFEM_VERIFY(dim==2," Aspect ratio adaptivity only available in 2D"); + + for (int i = 0; i < ir.GetNPoints(); i++) + { + const IntegrationPoint &ip = ir.IntPoint(i); + tspec_fes->GetFE(e_id)->CalcShape(ip, shape); + const double aspectratio = std::max(shape * par_vals, min_size); + Jtr(i)(0,0) *= 1./pow(aspectratio,0.5); + Jtr(i)(1,1) *= pow(aspectratio,0.5); + } + } + + //MFEM_VERIFY(skewidx==-1,"Skew-based target construction not yet supported"); + //MFEM_VERIFY(orientationidx==-1,"Skew-based target construction not yet supported"); break; } default: - MFEM_ABORT("Incompatible target type for analytic adaptation!"); + MFEM_ABORT("Incompatible target type for discrete adaptation!"); } } @@ -1524,103 +1714,112 @@ void TMOP_Integrator::SetFDh(const Vector &x, const FiniteElementSpace &fes) void TMOP_Integrator::SetupElementVectorTSpec(const Vector &x, const FiniteElementSpace &fes) { - if (fdflag!=0) - { - (this)->SetFDh(x,fes); + if (fdflag==0) {return;} + (this)->SetFDh(x,fes); - const int dim = fes.GetFE(0)->GetDim(); - const int cnt = x.Size()/dim; + const int dim = fes.GetFE(0)->GetDim(), + cnt = x.Size()/dim, + ncomp = discr_tc->GetNComponents(); - if (discr_tc->tspec_perth.Size() != x.Size()) - { - discr_tc->tspec_perth.SetSize(x.Size()); - } + if (discr_tc->tspec_perth.Size() != x.Size()) + { + discr_tc->tspec_perth.SetSize(cnt*dim*ncomp); + } - Vector TSpecTemp; - TSpecTemp.SetSize(x.Size()/dim); - Vector xtemp = x; - for (int j=0; jUpdateTargetSpecification(xtemp,TSpecTemp); + + + for (int i=0; iUpdateTargetSpecification(xtemp,TSpecTemp); - - for (int i=0; itspec_perth(j*cnt+i) = TSpecTemp(i); - xtemp(j*cnt+i) -= fdeps; - } //loop-i - } // loop-j - } + discr_tc->tspec_perth(k*cnt*dim+j*cnt+i) = TSpecTemp(i+k*cnt); + } //loop-k + xtemp(j*cnt+i) -= fdeps; + } //loop-i + } // loop-j } void TMOP_Integrator::SetupElementGradTSpec(const Vector &x, const FiniteElementSpace &fes) { - if (fdflag!=0) + if (fdflag==0) {return;} + const int dim = fes.GetFE(0)->GetDim(), + cnt = x.Size()/dim, + ncomp = discr_tc->GetNComponents(); + + if (discr_tc->tspec_pert2h.Size() != x.Size()) { - const int dim = fes.GetFE(0)->GetDim(); - const int cnt = x.Size()/dim; + discr_tc->tspec_pert2h.SetSize(cnt*dim*ncomp); + discr_tc->tspec_pertmix.SetSize(cnt*(1+2*(dim-2))*ncomp); + } + int totidx = 1+2*(dim-2); - if (discr_tc->tspec_pert2h.Size() != x.Size()) - { - discr_tc->tspec_pert2h.SetSize(x.Size()); - discr_tc->tspec_pertmix.SetSize(cnt*(1+2*(dim-2))); - } + Vector TSpecTemp; + TSpecTemp.SetSize(cnt*ncomp); + Vector xtemp = x; - Vector TSpecTemp; - TSpecTemp.SetSize(cnt); - Vector xtemp = x; + if (discr_tc->TSpecMixIdx.NumRows()==0) + { + discr_tc->TSpecMixIdx.SetSize(dim,dim); + } - if (discr_tc->TSpecMixIdx.NumRows()==0) - { - discr_tc->TSpecMixIdx.SetSize(dim,dim); - } + // T(x+2h) + for (int j=0; jUpdateTargetSpecification(xtemp,TSpecTemp); + + for (int i=0; itspec_pert2h(k*cnt*dim+j*cnt+i) = TSpecTemp(k*cnt+i); + } //loop-k + xtemp(j*cnt+i) -= 2*fdeps; + } //loop-i + } - discr_tc->UpdateTargetSpecification(xtemp,TSpecTemp); + // T(x+h,y+h) + int idx = 0; + for (int k1=0; k1UpdateTargetSpecification(xtemp,TSpecTemp); - for (int i=0; itspec_pert2h(j*cnt+i) = TSpecTemp(i); - xtemp(j*cnt+i) -= 2*fdeps; - } //loop-i - } // loop-j - - // T(x+h,y+h) - int idx = 0; - for (int k1=0; k1UpdateTargetSpecification(xtemp,TSpecTemp); - - for (int i=0; itspec_pertmix(idx*cnt+i) = TSpecTemp(i); - xtemp(k1*cnt+i) -= fdeps; - xtemp(k2*cnt+i) -= fdeps; - } - discr_tc->TSpecMixIdx(k1,k2) = idx; - discr_tc->TSpecMixIdx(k2,k1) = idx; - idx += 1; - } - } + discr_tc->tspec_pertmix(k*cnt*totidx+idx*cnt+i) = TSpecTemp(k*cnt+i); + } //loop-k + xtemp(k1*cnt+i) -= fdeps; + xtemp(k2*cnt+i) -= fdeps; + } //loop-i + discr_tc->TSpecMixIdx(k1,k2) = idx; + discr_tc->TSpecMixIdx(k2,k1) = idx; + idx += 1; + } } } @@ -1685,7 +1884,7 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, el,T,i,j,discr_tc->tspec_perth); } elvect(j*dof+i) = (this)->GetFDDerivative(el,T,elfunmod,i,j); - if (discr_tc) {discr_tc->RestoreTargetSpecificationAtNode(T,i);} + if (discr_tc) {discr_tc->RestoreTargetSpecificationAtNode(el,T,i);} } } } @@ -1755,8 +1954,8 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, elmat(k1*dof+i,k2*dof+j) = (energy1-energy2)/(fdeps); elmat(k2*dof+j,k1*dof+i) = (energy1-energy2)/(fdeps); - if (discr_tc) {discr_tc->RestoreTargetSpecificationAtNode(T,i);} - if (discr_tc) {discr_tc->RestoreTargetSpecificationAtNode(T,j);} + if (discr_tc) {discr_tc->RestoreTargetSpecificationAtNode(el,T,i);} + if (discr_tc) {discr_tc->RestoreTargetSpecificationAtNode(el,T,j);} } } } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 8e0f14edc1..b7a52458c8 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -706,16 +706,28 @@ class DiscreteAdaptTC : public TargetConstructor protected: // Discrete target specification. // Data is owned, updated by UpdateTargetSpecification. + int ncomp; + int sizeidx, skewidx, aspectratioidx, orientationidx; Vector tspec; //eta(x) // Note: do not use the Nodes of this space as they may not be on the // positions corresponding to the values of tspec. +#ifdef MFEM_USE_MPI + ParFiniteElementSpace *ptspec_fes; +#endif const FiniteElementSpace *tspec_fes; + const FiniteElementSpace *tspec_fesv; // Evaluation of the discrete target specification on different meshes. // Owned. AdaptivityEvaluator *adapt_eval; + void SetSerialDiscreteTargetBase(GridFunction &tspec_); +#ifdef MFEM_USE_MPI + void SetParDiscreteTargetBase(ParGridFunction &tspec_); +#endif + + public: Vector tspec_sav; Vector tspec_perth; //eta(x+h) @@ -725,15 +737,30 @@ public: DiscreteAdaptTC(TargetType ttype) : TargetConstructor(ttype), + ncomp(0), + sizeidx(-1), skewidx(-1), aspectratioidx(-1), orientationidx(-1), tspec(), tspec_fes(NULL), adapt_eval(NULL) { } - virtual ~DiscreteAdaptTC() { delete adapt_eval; } + virtual ~DiscreteAdaptTC() { delete adapt_eval; delete tspec_fesv; } virtual void SetSerialDiscreteTargetSpec(GridFunction &tspec_); #ifdef MFEM_USE_MPI virtual void SetParDiscreteTargetSpec(ParGridFunction &tspec_); #endif + virtual void SetSerialDiscreteTargetSize(GridFunction &tspec_); + virtual void SetSerialDiscreteTargetSkew(GridFunction &tspec_); + virtual void SetSerialDiscreteTargetAspectRatio(GridFunction &tspec_); + virtual void SetSerialDiscreteTargetOrientation(GridFunction &tspec_); + virtual void FinalizeSerialDiscreteTargetSpec(); +#ifdef MFEM_USE_MPI + virtual void SetParDiscreteTargetSize(ParGridFunction &tspec_); + virtual void SetParDiscreteTargetSkew(ParGridFunction &tspec_); + virtual void SetParDiscreteTargetAspectRatio(ParGridFunction &tspec_); + virtual void SetParDiscreteTargetOrientation(ParGridFunction &tspec_); + virtual void FinalizeParDiscreteTargetSpec(); +#endif + /** Used to update the target specification after the mesh has changed. The new mesh positions are given by new_x. */ void UpdateTargetSpecification(const Vector &new_x); @@ -746,12 +773,15 @@ public: int nodenum, int idir, Vector &IntData); - void RestoreTargetSpecificationAtNode(ElementTransformation &T, int nodenum); + void RestoreTargetSpecificationAtNode(const FiniteElement &el, + ElementTransformation &T, int nodenum); void BackupTargetSpecification(); void RestoreTargetSpecification(); + int GetNComponents() {return ncomp;} + void SetAdaptivityEvaluator(AdaptivityEvaluator *ae) { if (adapt_eval) { delete adapt_eval; } diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 8b03109a19..078119058e 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -222,7 +222,6 @@ void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const void InterpolatorFP::SetInitialField(const Vector &init_nodes, const Vector &init_field) { - const bool serial = !parallel; nodes0 = init_nodes; field0 = init_field; Mesh *m = mesh; @@ -236,7 +235,7 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes, const int npts_at_once = 256; #ifdef MFEM_USE_MPI - if (!serial) {finder = new FindPointsGSLIB(pfes->GetComm());} + if (pmesh) {finder = new FindPointsGSLIB(pfes->GetComm());} else {finder = new FindPointsGSLIB();} #else finder = new FindPointsGSLIB(); @@ -273,18 +272,6 @@ void InterpolatorFP::ComputeAtNewPosition(const Vector &new_nodes, finder->Interpolate(code_out, task_id_out, el_id_out, pos_r_out, field0_gf, new_field); - int face_pts = 0, not_found = 0, found = 0; - - for (int i = 0; i < pts_cnt; i++) - { - if (code_out[i] < 2) - { - found++; - - if (code_out[i] == 1) { face_pts++; } - } - else { not_found++;} - } } #endif diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index 5e346c2920..636ee8d90a 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -44,16 +44,8 @@ class InterpolatorFP : public AdaptivityEvaluator private: Vector nodes0; Vector field0; - bool parallel; //for GSLIB FindPointsGSLIB *finder; public: -#ifdef MFEM_USE_MPI - InterpolatorFP(bool flag) : AdaptivityEvaluator(), - nodes0(), field0(), parallel(flag), finder(NULL) { } -#endif - InterpolatorFP() : AdaptivityEvaluator(), - nodes0(), field0(), parallel(false), finder(NULL) { } - virtual void SetInitialField(const Vector &init_nodes, const Vector &init_field); diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index f62ca35284..6620d71e9c 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -63,7 +63,7 @@ // mesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -#include "mfem.hpp" +#include "../../mfem.hpp" #include #include @@ -71,6 +71,7 @@ using namespace mfem; using namespace std; double weight_fun(const Vector &x); +void DiffuseField(GridFunction &field, int smooth_steps); double ind_values(const Vector &x) { @@ -86,7 +87,6 @@ double ind_values(const Vector &x) return ind * small + (1.0 - ind) * big; } - if (opt==2) { // Circle in the middle. @@ -113,43 +113,7 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } - if (opt==4) - { - // Multiple circles - double r1,r2,val,rval; - double sf = 10; - val = 0.; - // circle 1 - r1= 0.25; r2 = 0.25; rval = 0.1; - double xc = x(0) - r1, yc = x(1) - r2; - double r = sqrt(xc*xc+yc*yc); - val = 0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf* - (r-rval)));// std::exp(val1); - // circle 2 - r1= 0.75; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += (0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf* - (r-rval))));// std::exp(val1); - // circle 3 - r1= 0.75; r2 = 0.25; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf* - (r-rval)));// std::exp(val1); - // circle 4 - r1= 0.25; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf*(r-rval))); - if (val > 1.0) {val = 1.;} - if (val < 0.0) {val = 0.;} - - return val * small + (1.0 - val) * big; - } - - if (opt==5) { // cross double val = 0.; @@ -170,7 +134,7 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } - if (opt==6) + if (opt==5) { double val = 0.; const double xc = x(0) - 0.0, yc = x(1) - 0.5; @@ -183,6 +147,29 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } + if (opt==6) //rotated sine wave + { + double val = 0.; + const double X = x(0); + const double Y = x(1); + + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc = xn/stretch;yc = yn/stretch; + double tfac = 20; + double s1 = 3; + double s2 = 3; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); + if (wgt > 1) wgt = 1; + if (wgt < 0) wgt = 0; + val = wgt; + return val; + } + return 0.0; } @@ -537,7 +524,7 @@ int main (int argc, char *argv[]) HessianCoefficient *adapt_coeff = NULL; H1_FECollection ind_fec(mesh_poly_deg, dim); FiniteElementSpace ind_fes(mesh, &ind_fec); - GridFunction size; + GridFunction size, aspr, disc; switch (target_id) { case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break; @@ -564,10 +551,105 @@ int main (int argc, char *argv[]) #else if (fdscheme==0) {tc->SetAdaptivityEvaluator(new AdvectorCG);} #endif - tc->SetSerialDiscreteTargetSpec(size); + tc->SetSerialDiscreteTargetSize(size); + tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; break; } + case 6: + { + GridFunction d_x, d_y; + d_x.SetSpace(&ind_fes); + d_y.SetSpace(&ind_fes); + size.SetSpace(&ind_fes); + aspr.SetSpace(&ind_fes); + disc.SetSpace(&ind_fes); + + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + FunctionCoefficient ind_coeff(ind_values); + disc.ProjectCoefficient(ind_coeff); +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + if (fdscheme==0) {tc->SetAdaptivityEvaluator(new AdvectorCG);} +#endif + + //Diffuse the interface + DiffuseField(disc,2); + + //Get partials with respect to x and y of the grid function + disc.GetDerivative(1,0,d_x); + disc.GetDerivative(1,1,d_y); + + //Compute the squared magnitude of the gradient + for (int i = 0; i < size.Size(); i++) + { + size(i) = std::pow(d_x(i),2)+std::pow(d_y(i),2); + } + const double max = size.Max(); + + for (int i = 0; i < d_x.Size(); i++) + { + d_x(i) = std::abs(d_x(i)); + d_y(i) = std::abs(d_y(i)); + } + const double eps = 0.01; + const double ratio = 20.0; + const double big_small_ratio = 40.0; + + for (int i = 0; i < size.Size(); i++) + { + size(i) = (size(i)/max); + aspr(i) = (d_x(i)+eps)/(d_y(i)+eps); + aspr(i) = 0.1 + 0.9*(1-size(i))*(1-size(i)); + if (aspr(i) > ratio){aspr(i) = ratio;} + if (aspr(i) < 1.0/ratio){aspr(i) = 1.0/ratio;} + } + Vector vals; + const int NE = mesh->GetNE(); + double volume = 0.0, volume_ind = 0.0; + + for (int i = 0; i < NE; i++) + { + ElementTransformation *Tr = mesh->GetElementTransformation(i); + const IntegrationRule &ir = + IntRules.Get(mesh->GetElementBaseGeometry(i), Tr->OrderJ()); + size.GetValues(i, ir, vals); + for (int j = 0; j < ir.GetNPoints(); j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + Tr->SetIntPoint(&ip); + volume += ip.weight * Tr->Weight(); + volume_ind += vals(j) * ip.weight * Tr->Weight(); + } + } + + const double avg_zone_size = volume / NE; + + const double small_avg_ratio = (volume_ind + (volume - volume_ind) / big_small_ratio) / + volume; + + const double small_zone_size = small_avg_ratio * avg_zone_size; + const double big_zone_size = big_small_ratio * small_zone_size; + + for (int i = 0; i < size.Size(); i++) + { + const double val = size(i); + const double a = (big_zone_size - small_zone_size) / small_zone_size; + size(i) = big_zone_size / (1.0+a*val); + } + + + DiffuseField(size, 2); + DiffuseField(aspr, 2); + + tc->SetSerialDiscreteTargetSize(size); + tc->SetSerialDiscreteTargetAspectRatio(aspr); + tc->FinalizeSerialDiscreteTargetSpec(); + target_c = tc; + break; + } default: cout << "Unknown target_id: " << target_id << endl; return 3; } if (target_c == NULL) @@ -577,7 +659,7 @@ int main (int argc, char *argv[]) target_c->SetNodes(x0); TMOP_Integrator *he_nlf_integ = new TMOP_Integrator(metric, target_c); he_nlf_integ->SetFDPar(fdscheme, mesh->GetNE()); - if (target_id == 5) + if (target_id == 5 || target_id == 6) { he_nlf_integ->SetDiscreteAdaptTC(dynamic_cast(target_c)); } @@ -859,3 +941,24 @@ double weight_fun(const Vector &x) + 0.5*std::tanh((r-0.23)/den) - 0.5*std::tanh((r-0.24)/den); return l2; } + +void DiffuseField(GridFunction &field, int smooth_steps) +{ + //Setup the Laplacian operator + BilinearForm *Lap = new BilinearForm(field.FESpace()); + Lap->AddDomainIntegrator(new DiffusionIntegrator()); + Lap->Assemble(); + Lap->Finalize(); + + //Setup the smoothing operator + DSmoother *S = new DSmoother(0,1.0,smooth_steps); + S->iterative_mode = true; + S->SetOperator(Lap->SpMat()); + + Vector tmp(field.Size()); + tmp = 0.0; + S->Mult(tmp, field); + + delete S; + delete Lap; +} diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 4d11ac7862..83498dab0e 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -59,7 +59,7 @@ // 2D non-conforming shape and equal size: // mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -#include "mfem.hpp" +#include "../../mfem.hpp" #include #include @@ -67,6 +67,7 @@ using namespace mfem; using namespace std; double weight_fun(const Vector &x); +void DiffuseField(ParGridFunction &field, int smooth_steps); double ind_values(const Vector &x) { @@ -111,41 +112,6 @@ double ind_values(const Vector &x) } if (opt==4) - { - // Multiple circles - double r1,r2,val,rval; - double sf = 10; - val = 0.; - // circle 1 - r1= 0.25; r2 = 0.25; rval = 0.1; - double xc = x(0) - r1, yc = x(1) - r2; - double r = sqrt(xc*xc+yc*yc); - val = 0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf* - (r-rval)));// std::exp(val1); - // circle 2 - r1= 0.75; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += (0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf* - (r-rval))));// std::exp(val1); - // circle 3 - r1= 0.75; r2 = 0.25; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf* - (r-rval)));// std::exp(val1); - // circle 4 - r1= 0.25; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - 0.5*(1+std::tanh(sf*(r-rval))); - if (val > 1.0) {val = 1.;} - if (val < 0.0) {val = 0.;} - - return val * small + (1.0 - val) * big; - } - - if (opt==5) { // cross double val = 0.; @@ -166,7 +132,7 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } - if (opt==6) + if (opt==5) { double val = 0.; const double xc = x(0) - 0.0, yc = x(1) - 0.5; @@ -179,6 +145,30 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } + if (opt==6) //rotated sine wave + { + double val = 0.; + const double X = x(0); + const double Y = x(1); + + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc = xn/stretch;yc = yn/stretch; + double tfac = 20; + double s1 = 3; + double s2 = 3; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); + if (wgt > 1) wgt = 1; + if (wgt < 0) wgt = 0; + val = wgt; + return val; + } + + return 0.0; } @@ -557,7 +547,7 @@ int main (int argc, char *argv[]) HessianCoefficient *adapt_coeff = NULL; H1_FECollection ind_fec(mesh_poly_deg, dim); ParFiniteElementSpace ind_fes(pmesh, &ind_fec); - ParGridFunction size; + ParGridFunction size, aspr, disc; switch (target_id) { case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break; @@ -580,7 +570,7 @@ int main (int argc, char *argv[]) FunctionCoefficient ind_coeff(ind_values); size.ProjectCoefficient(ind_coeff); #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP(true)); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #else if (fdscheme==0) {tc->SetAdaptivityEvaluator(new AdvectorCG);} #endif @@ -588,6 +578,107 @@ int main (int argc, char *argv[]) target_c = tc; break; } + case 6: + { + ParGridFunction d_x, d_y; + d_x.SetSpace(&ind_fes); + d_y.SetSpace(&ind_fes); + size.SetSpace(&ind_fes); + aspr.SetSpace(&ind_fes); + disc.SetSpace(&ind_fes); + + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + FunctionCoefficient ind_coeff(ind_values); + disc.ProjectCoefficient(ind_coeff); +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + if (fdscheme==0) {tc->SetAdaptivityEvaluator(new AdvectorCG);} +#endif + + //Diffuse the interface + DiffuseField(disc,2); + + //Get partials with respect to x and y of the grid function + disc.GetDerivative(1,0,d_x); + disc.GetDerivative(1,1,d_y); + + //Compute the squared magnitude of the gradient + for (int i = 0; i < size.Size(); i++) + { + size(i) = std::pow(d_x(i),2)+std::pow(d_y(i),2); + } + const double max = size.Max(); + double max_all; + MPI_Allreduce(&max, &max_all, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + + for (int i = 0; i < d_x.Size(); i++) + { + d_x(i) = std::abs(d_x(i)); + d_y(i) = std::abs(d_y(i)); + } + const double eps = 0.01; + const double ratio = 20.0; + const double big_small_ratio = 40.0; + + for (int i = 0; i < size.Size(); i++) + { + size(i) = (size(i)/max_all); + aspr(i) = (d_x(i)+eps)/(d_y(i)+eps); + aspr(i) = 0.1 + 0.9*(1-size(i))*(1-size(i)); + if (aspr(i) > ratio){aspr(i) = ratio;} + if (aspr(i) < 1.0/ratio){aspr(i) = 1.0/ratio;} + } + Vector vals; + const int NE = pmesh->GetNE(); + double volume = 0.0, volume_ind = 0.0; + + for (int i = 0; i < NE; i++) + { + ElementTransformation *Tr = pmesh->GetElementTransformation(i); + const IntegrationRule &ir = + IntRules.Get(pmesh->GetElementBaseGeometry(i), Tr->OrderJ()); + size.GetValues(i, ir, vals); + for (int j = 0; j < ir.GetNPoints(); j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + Tr->SetIntPoint(&ip); + volume += ip.weight * Tr->Weight(); + volume_ind += vals(j) * ip.weight * Tr->Weight(); + } + } + double volume_all, volume_ind_all; + int NE_ALL; + MPI_Allreduce(&volume, &volume_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&volume_ind, &volume_ind_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&NE, &NE_ALL, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + + const double avg_zone_size = volume_all / NE_ALL; + + const double small_avg_ratio = + (volume_ind_all + (volume_all - volume_ind_all) / big_small_ratio) + / volume_all; + + const double small_zone_size = small_avg_ratio * avg_zone_size; + const double big_zone_size = big_small_ratio * small_zone_size; + + for (int i = 0; i < size.Size(); i++) + { + const double val = size(i); + const double a = (big_zone_size - small_zone_size) / small_zone_size; + size(i) = big_zone_size / (1.0+a*val); + } + + DiffuseField(size, 2); + DiffuseField(aspr, 2); + + tc->SetParDiscreteTargetSize(size); + tc->SetParDiscreteTargetAspectRatio(aspr); + tc->FinalizeParDiscreteTargetSpec(); + target_c = tc; + break; + } default: if (myid == 0) { cout << "Unknown target_id: " << target_id << endl; } return 3; @@ -600,7 +691,7 @@ int main (int argc, char *argv[]) target_c->SetNodes(x0); TMOP_Integrator *he_nlf_integ= new TMOP_Integrator(metric, target_c); he_nlf_integ->SetFDPar(fdscheme, pmesh->GetNE()); - if (target_id == 5) + if (target_id == 5 || target_id == 6) { he_nlf_integ->SetDiscreteAdaptTC(dynamic_cast(target_c)); } @@ -673,6 +764,7 @@ int main (int argc, char *argv[]) else { a.AddDomainIntegrator(he_nlf_integ); } const double init_energy = a.GetParGridFunctionEnergy(x); + //std::cout << init_energy << " k10initenergy\n"; // 16. Visualize the starting mesh and metric values. if (visualization) @@ -906,3 +998,27 @@ double weight_fun(const Vector &x) + std::tanh((r-0.23)/den) - std::tanh((r-0.24)/den)); return l2; } + +void DiffuseField(ParGridFunction &field, int smooth_steps) +{ + //Setup the Laplacian operator + ParBilinearForm *Lap = new ParBilinearForm(field.ParFESpace()); + Lap->AddDomainIntegrator(new DiffusionIntegrator()); + Lap->Assemble(); + Lap->Finalize(); + HypreParMatrix *A = Lap->ParallelAssemble(); + + HypreSmoother *S = new HypreSmoother(*A,0,smooth_steps); + S->iterative_mode = true; + + Vector tmp(A->Width()); + field.SetTrueVector(); + Vector fieldtrue = field.GetTrueVector(); + tmp = 0.0; + S->Mult(tmp, fieldtrue); + + field.SetFromTrueDofs(fieldtrue); + + delete S; + delete Lap; +} From 54d57691de837feea8b084bbc9367ce1d074017e Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Fri, 6 Mar 2020 12:12:41 +0100 Subject: [PATCH 085/535] Add weak bcs to NURBS miniapp, also improve refinement mechanism --- miniapps/nurbs/nurbs_ex1.cpp | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index f6f57c1873..32d3b6833b 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -119,22 +119,34 @@ public: }; + +double Neum(const Vector & x) +{ + return 10.0*x[0]; +} + + int main(int argc, char *argv[]) { // 1. Parse command-line options. const char *mesh_file = "../../data/star.mesh"; const char *per_file = "none"; + int ref_levels = -1; Array master(0); Array slave(0); bool static_cond = false; bool visualization = 1; bool ibp = 1; + bool strongBC = 1; + double kappa = -1; Array order(1); order[0] = 1; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); + args.AddOption(&ref_levels, "-r", "--refine", + "Number of times to refine the mesh uniformly, -1 for auto."); args.AddOption(&per_file, "-p", "--per", "Periodic BCS file."); args.AddOption(&master, "-pm", "--master", @@ -147,6 +159,12 @@ int main(int argc, char *argv[]) args.AddOption(&ibp, "-ibp", "--ibp", "-no-ibp", "--no-ibp", "Selects the standard weak form (IBP) or the nonstandard (NO-IBP)."); + args.AddOption(&strongBC, "-sbc", "--strong-bc", "-wbc", + "--weak-bc", + "Selects strong or weak enforcement of Dirichlet BCs."); + args.AddOption(&kappa, "-k", "--kappa", + "One of the two DG penalty parameters, should be positive." + " Negative values are replaced with (order+1)^2."); args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", "--no-static-condensation", "Enable static condensation."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", @@ -158,6 +176,10 @@ int main(int argc, char *argv[]) args.PrintUsage(cout); return 1; } + if (strongBC & (kappa < 0)) + { + kappa = (order+1)*(order+1); + } args.PrintOptions(cout); // 2. Read the mesh from the given mesh file. We can handle triangular, @@ -171,8 +193,11 @@ int main(int argc, char *argv[]) // largest number that gives a final mesh with no more than 50,000 // elements. { + if (ref_levels < 0) + { int ref_levels = (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); + } for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); @@ -278,7 +303,15 @@ int main(int argc, char *argv[]) if (mesh->bdr_attributes.Size()) { Array ess_bdr(mesh->bdr_attributes.Max()); - ess_bdr = 1; + if (strongBC) + { + ess_bdr = 1; + } + else + { + ess_bdr = 0; + } + // Remove periodic BCs for (int i = 0; i < master.Size(); i++) { @@ -291,9 +324,14 @@ int main(int argc, char *argv[]) // 6. Set up the linear form b(.) which corresponds to the right-hand side of // the FEM linear system, which in this case is (1,phi_i) where phi_i are // the basis functions in the finite element fespace. - LinearForm *b = new LinearForm(fespace); ConstantCoefficient one(1.0); + ConstantCoefficient zero(0.0); + + LinearForm *b = new LinearForm(fespace); b->AddDomainIntegrator(new DomainLFIntegrator(one)); + if (!strongBC) + b->AddBdrFaceIntegrator( + new DGDirichletLFIntegrator(zero, one, -1.0, kappa)); b->Assemble(); // 7. Define the solution vector x as a finite element grid function @@ -315,6 +353,9 @@ int main(int argc, char *argv[]) a->AddDomainIntegrator(new Diffusion2Integrator(one)); } + if (!strongBC) + a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa)); + // 9. Assemble the bilinear form and the corresponding linear system, // applying any necessary transformations such as: eliminating boundary // conditions, applying conforming constraints for non-conforming AMR, From 8cd4c0049f4b1c9fbd0bc06d231502c6ec5bd52d Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Fri, 6 Mar 2020 12:20:06 +0100 Subject: [PATCH 086/535] Order and refinement bugfixes --- miniapps/nurbs/nurbs_ex1.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index 32d3b6833b..29c10f966e 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -3,6 +3,7 @@ // Compile with: make nurbs_ex1 // // Sample runs: nurbs_ex1 -m square-nurbs.mesh -o 2 -no-ibp +// nurbs_ex1 -m square-nurbs.mesh -o 2 --weak-bc // nurbs_ex1 -m cube-nurbs.mesh -o 2 -no-ibp // nurbs_ex1 -m pipe-nurbs-2d.mesh -o 2 -no-ibp // nurbs_ex1 -m ../../data/square-disc-nurbs.mesh -o -1 @@ -119,13 +120,6 @@ public: }; - -double Neum(const Vector & x) -{ - return 10.0*x[0]; -} - - int main(int argc, char *argv[]) { // 1. Parse command-line options. @@ -178,7 +172,7 @@ int main(int argc, char *argv[]) } if (strongBC & (kappa < 0)) { - kappa = (order+1)*(order+1); + kappa = (order.Max()+1)*(order.Max()+1); } args.PrintOptions(cout); @@ -195,9 +189,10 @@ int main(int argc, char *argv[]) { if (ref_levels < 0) { - int ref_levels = - (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); + ref_levels = + (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); } +cout<UniformRefinement(); @@ -293,8 +288,6 @@ int main(int argc, char *argv[]) } } - - // 5. Determine the list of true (i.e. conforming) essential boundary dofs. // In this example, the boundary conditions are defined by marking all // the boundary attributes from the mesh as essential (Dirichlet) and From e673b80a9f2282b2abb8a09c7301bee74b223cd6 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Fri, 6 Mar 2020 12:20:39 +0100 Subject: [PATCH 087/535] Delete output statement --- miniapps/nurbs/nurbs_ex1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index 29c10f966e..2a7210a61b 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -192,7 +192,7 @@ int main(int argc, char *argv[]) ref_levels = (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); } -cout<UniformRefinement(); From d4697dd6923436007a33c88c8c624c979a95a3cb Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 15:34:53 -0700 Subject: [PATCH 088/535] Adding comment block describing "active side" concept for FaceElementTransformations objects --- fem/eltrans.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 7947fe0ccf..1102d2dd51 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -361,6 +361,21 @@ public: FaceElementTransformations() : side(2) {} + /** FaceElementTransformations objects are often used when + performing the surface integrals on the interfaces between + elements needed by Discontinuous Galerkin methods. Since the + fields are generally multivalued on such interfaces it is + important to specify which neighboring element should supply + the field values. This is controlled by setting the "active + side" in the FaceElementTransformations object. + + Possible values for s are 0, 1, and 2: + 0 - Set Elem1No as the active side + 1 - Set Elem2No as the active side + 2 - Choose the active side automatically. This selects Elem1No + unless Elem2No exists and has a lower attribute number than + Elem1No. + */ int SetActiveSide(int s); int GetActiveSide() const { return side; } From 80158f14b6024d7401af031c75e2846e69eefbb3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 15:35:44 -0700 Subject: [PATCH 089/535] Removing unnecessary temporary variable --- fem/eltrans.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index ee9fce7193..a197c94274 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -538,21 +538,19 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1, int FaceElementTransformations::SetActiveSide(int s) { - int dir; - if (s == 2) // automatic choice of side { if (Elem1 && Elem2) { - dir = (Elem1->Attribute <= Elem2->Attribute) ? 0 : 1; + side = (Elem1->Attribute <= Elem2->Attribute) ? 0 : 1; } else if (Elem1) { - dir = 0; + side = 0; } else if (Elem2) { - dir = 1; + side = 1; } else { @@ -564,11 +562,11 @@ int FaceElementTransformations::SetActiveSide(int s) { if (s == 0 && Elem1) { - dir = 0; + side = 0; } else if (s == 1 && Elem2) { - dir = 1; + side = 1; } else { @@ -576,9 +574,8 @@ int FaceElementTransformations::SetActiveSide(int s) "for the requested side is NULL."); } } - side = dir; - return dir; + return side; } ElementTransformation * From 540e4deb5f0e7e645b25d209b615f53f67e1b070 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 15:36:24 -0700 Subject: [PATCH 090/535] Removing unnecessary recursive method call --- fem/eltrans.cpp | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index a197c94274..b8e4a18707 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -581,35 +581,39 @@ int FaceElementTransformations::SetActiveSide(int s) ElementTransformation * FaceElementTransformations::GetActiveElementTransformation() { - if (side == 0) + while(1) { - return Elem1; - } - else if (side == 1) - { - return Elem2; - } + if (side == 0) + { + return Elem1; + } + else if (side == 1) + { + return Elem2; + } - // Automatic selection has not yet occured. - SetActiveSide(2); - return GetActiveElementTransformation(); + // Automatic selection has not yet occured. + SetActiveSide(2); + } } IntegrationPointTransformation * FaceElementTransformations::GetActivePointTransformation() { - if (side == 0) + while(1) { - return &Loc1; - } - else if (side == 1) - { - return &Loc2; - } + if (side == 0) + { + return &Loc1; + } + else if (side == 1) + { + return &Loc2; + } - // Automatic selection has not yet occured. - SetActiveSide(2); - return GetActivePointTransformation(); + // Automatic selection has not yet occured. + SetActiveSide(2); + } } } From 18c9103305b530677ece70e610963a5882271122 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 15:36:55 -0700 Subject: [PATCH 091/535] Removing dead code --- fem/gridfunc.cpp | 47 +---------------------------------------------- fem/gridfunc.hpp | 9 +++------ 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 6703a1d010..257b8fddc7 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -524,51 +524,6 @@ int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir, return dir; } -/* -void GridFunction::GetVectorValues(ElementTransformation &T, - const IntegrationRule &ir, - DenseMatrix &vals) const -{ - const FiniteElement *FElem = fes->GetFE(T.ElementNo); - int dof = FElem->GetDof(); - Array vdofs; - fes->GetElementVDofs(T.ElementNo, vdofs); - Vector loc_data; - GetSubVector(vdofs, loc_data); - int nip = ir.GetNPoints(); - if (FElem->GetRangeType() == FiniteElement::SCALAR) - { - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - Vector shape(dof); - int vdim = fes->GetVDim(); - vals.SetSize(vdim, nip); - for (int j = 0; j < nip; j++) - { - const IntegrationPoint &ip = ir.IntPoint(j); - FElem->CalcShape(ip, shape); - for (int k = 0; k < vdim; k++) - { - vals(k,j) = shape * ((const double *)loc_data + dof * k); - } - } - } - else - { - int spaceDim = fes->GetMesh()->SpaceDimension(); - DenseMatrix vshape(dof, spaceDim); - vals.SetSize(spaceDim, nip); - Vector val_j; - for (int j = 0; j < nip; j++) - { - const IntegrationPoint &ip = ir.IntPoint(j); - T.SetIntPoint(&ip); - FElem->CalcVShape(T, vshape); - vals.GetColumnReference(j, val_j); - vshape.MultTranspose(loc_data, val_j); - } - } -} void GridFunction::GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const @@ -578,7 +533,7 @@ void GridFunction::GetVectorValues(int i, const IntegrationRule &ir, GetVectorValues(*Tr, ir, vals); } -*/ + double GridFunction::GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp, Vector *tr) const diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 693af1dd38..daf73ebe80 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -154,13 +154,10 @@ public: int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim = 1) const; - /* - void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, - DenseMatrix &vals) const; - void GetVectorValues(int i, const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix &tr) const; - */ + void GetVectorValues(int i, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix &tr) const; + int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const; From 2da035cbdc1767a3e7ae9ba50061a8299838a6af Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 18:00:28 -0700 Subject: [PATCH 092/535] Rearranging and documenting the various GridFunction::GetValue methods --- fem/gridfunc.hpp | 85 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index daf73ebe80..296d2e5017 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -141,44 +141,107 @@ public: /// Returns the values in the vertices of i'th element for dimension vdim. void GetNodalValues(int i, Array &nval, int vdim = 1) const; + ///@{ + /** GetValue methods taking an integer element index. + + These methods take an element index and return the interpolated + value of the field at a given reference point within the + element. + */ virtual double GetValue(int i, const IntegrationPoint &ip, int vdim = 1) const; void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const; + ///@} + ///@{ + /** GetValues method taking an integer element index. + + These are convenience methods for repeatedly calling GetValue + for multiple points within a given element. The GetValues + methods are optimized and should perform better than repeatedly + calling GetValue. The GetVectorValues method simply calls + GetVectorValue repeatedly. + */ void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim = 1) const; void GetValues(int i, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim = 1) const; - int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, - DenseMatrix &tr, int vdim = 1) const; - void GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const; + ///@} - int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix &tr) const; + ///@{ + /** GetValue methods taking a ElementTransformation argument. + These member functions are designed for use within + GridFunctionCoefficient objects. These can be used with + ElementTransformation objects coming from either + Mesh::GetElementTransformation() or + Mesh::GetBdrElementTransformation(). + */ double GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp = 0, Vector *tr = NULL) const; - double GetValue(FaceElementTransformations &T, const IntegrationPoint &ip, - int comp = 0, Vector *tr = NULL) const; - - void GetValues(ElementTransformation &T, const IntegrationRule &ir, - Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; - void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; + ///@} + + ///@{ + /** GetValue methods taking a FaceElementTransformations argument. + + These member functions are designed for use within + GridFunctionCoefficient objects. These can be used with + FaceElementTransformations objects coming from + Mesh::GetFaceElementTransformations(), + Mesh::GetInteriorFaceElementTransformations(), or + Mesh::GetBdrFaceElementTransformations(). + */ + double GetValue(FaceElementTransformations &T, const IntegrationPoint &ip, + int comp = 0, Vector *tr = NULL) const; void GetVectorValue(FaceElementTransformations &T, const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; + ///@} + + ///@{ + /** GetValues methods taking a ElementTransformation argument. + + These are convenience methods for repeatedly calling GetValue + for multiple points within a given element. They work by + calling either the ElementTransformation or + FaceElementTransformations versions described above. + Consequently, these methods should not be expected to run + faster than calling the above methods in an external loop. + */ + void GetValues(ElementTransformation &T, const IntegrationRule &ir, + Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix *tr = NULL) const; + ///@} + + ///@{ + /** GetFaceValues methods take a face index argument. + + These methods are designed to work with Discontinuous Galerkin + basis functions. They compute field values on the interface + between elements, or on boundary elements, by interpolating the + field in a neighboring element. The \a side argument indices + which neighboring element should be used: 0, 1, or 2 + (automatically chosen). See the FaceElementTransformations + documentation in eltrans.hpp for more information on the \a + side parameter. + */ + int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, + DenseMatrix &tr, int vdim = 1) const; + + int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix &tr) const; + ///@} void GetValuesFrom(const GridFunction &orig_func); From b33654bfa420ecdcf385e5bffeff007447f682bd Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 18:00:42 -0700 Subject: [PATCH 093/535] make style --- fem/eltrans.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index b8e4a18707..4d586339f3 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -581,7 +581,7 @@ int FaceElementTransformations::SetActiveSide(int s) ElementTransformation * FaceElementTransformations::GetActiveElementTransformation() { - while(1) + while (1) { if (side == 0) { @@ -600,7 +600,7 @@ FaceElementTransformations::GetActiveElementTransformation() IntegrationPointTransformation * FaceElementTransformations::GetActivePointTransformation() { - while(1) + while (1) { if (side == 0) { From b6e1430a4645f5f29f2a45fe6987e863a55225fb Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 21:20:44 -0700 Subject: [PATCH 094/535] Fixing implementation that was overwritten by merge with master --- fem/gridfunc.cpp | 51 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index b056e99171..49bcb01d56 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -831,16 +831,51 @@ void GridFunction::GetVectorValues(ElementTransformation &T, T.Transform(ir, *tr); } - int vdim = fes->GetVDim(); + const FiniteElement *FElem = fes->GetFE(T.ElementNo); + int dof = FElem->GetDof(); + + Array vdofs; + fes->GetElementVDofs(T.ElementNo, vdofs); + + Vector loc_data; + GetSubVector(vdofs, loc_data); int nip = ir.GetNPoints(); - vals.SetSize(vdim, nip); - Vector val; - for (int j = 0; j < nip; j++) + + if (FElem->GetRangeType() == FiniteElement::SCALAR) { - const IntegrationPoint &ip = ir.IntPoint(j); - T.SetIntPoint(&ip); - GetVectorValue(T, ip, val); - vals.SetCol(j, val); + MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + Vector shape(dof); + int vdim = fes->GetVDim(); + vals.SetSize(vdim, nip); + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + FElem->CalcShape(ip, shape); + + for (int k = 0; k < vdim; k++) + { + vals(k,j) = shape * ((const double *)loc_data + dof * k); + } + } + } + else + { + int spaceDim = fes->GetMesh()->SpaceDimension(); + DenseMatrix vshape(dof, spaceDim); + + vals.SetSize(spaceDim, nip); + Vector val_j; + + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + T.SetIntPoint(&ip); + FElem->CalcVShape(T, vshape); + + vals.GetColumnReference(j, val_j); + vshape.MultTranspose(loc_data, val_j); + } } } From c3f42bff3b8bf1a9db94cfef075b47a583b108c9 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 12 Mar 2020 23:04:10 -0700 Subject: [PATCH 095/535] make style --- fem/gridfunc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 49bcb01d56..77a831e1b4 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -836,7 +836,7 @@ void GridFunction::GetVectorValues(ElementTransformation &T, Array vdofs; fes->GetElementVDofs(T.ElementNo, vdofs); - + Vector loc_data; GetSubVector(vdofs, loc_data); int nip = ir.GetNPoints(); From 5d8aac53d1361f983fa44e6153fec265e849879e Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 13 Mar 2020 00:08:37 -0700 Subject: [PATCH 096/535] Documenting the enumeration used in ElementTransformation --- fem/eltrans.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index b881ddad43..1e0ee84821 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -49,7 +49,20 @@ protected: const DenseMatrix &EvalInverseJ(); public: - enum IndexType + + /** This enumeration declares the values stored in + ElementTransformation::ElementType and indicates which group of + objects the index stored in ElementTransformation::ElementNo + refers: + + | ElementType | Range of ElementNo + +-------------+------------------------- + | ELEMENT | [0, Mesh::GetNE() ) + | BDR_ELEMENT | [0, Mesh::GetNBE() ) + | EDGE | [0, Mesh::GetNEdges() ) + | FACE | [0, Mesh::GetNFaces() ) + */ + enum { ELEMENT = 1, BDR_ELEMENT = 2, From 1420be0a4246725e6b1d433bf18e799f73d514ff Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Fri, 13 Mar 2020 09:57:43 -0700 Subject: [PATCH 097/535] changes to tmop_tools --- fem/tmop_tools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 6f1034bb7b..8da60c748d 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -380,7 +380,7 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0) { if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Increasing energy.\n"; } + { mfem::out << "Scale = " << scale << " " << energy_out << " " << "Increasing energy.\n"; } scale *= 0.5; continue; } From 1ed8afdf938d8b016c515a53b644f122872a773b Mon Sep 17 00:00:00 2001 From: camierjs Date: Sun, 15 Mar 2020 16:03:11 -0700 Subject: [PATCH 098/535] Merge leftovers fix --- makefile | 7 +------ miniapps/performance/CMakeLists.txt | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/makefile b/makefile index 941bd3cc2b..b66e50371f 100644 --- a/makefile +++ b/makefile @@ -322,13 +322,8 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\ MFEM_USE_GECKO MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS\ MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT\ MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\ -<<<<<<< HEAD - MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_SIMD\ - MFEM_SOURCE_DIR MFEM_INSTALL_DIR -======= MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_SOURCE_DIR\ - MFEM_INSTALL_DIR ->>>>>>> master + MFEM_INSTALL_DIR MFEM_USE_SIMD # List of makefile variables that will be written to config.mk: MFEM_CONFIG_VARS = MFEM_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS MFEM_INC_DIR\ diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 56e45e796a..168ff72dab 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -31,15 +31,11 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") ${MFEM_PERF_CXX_ARCH_FLAGS} "-Wall" "--param" "max-completely-peel-times=3") -<<<<<<< HEAD -elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") - list(APPEND PERFORMANCE_CXX_OPTIONS - "-xHost") -======= if (NOT MFEM_USE_CUDA) list(APPEND PERFORMANCE_CXX_OPTIONS "-pedantic") endif() ->>>>>>> master +elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") + list(APPEND PERFORMANCE_CXX_OPTIONS "-xHost") endif() add_mfem_miniapp(performance_ex1 From 5a031461f7e8acb1dbfff371a08a65dcd06fcf53 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 15 Mar 2020 17:15:51 -0700 Subject: [PATCH 099/535] Adding unit test for FaceElementTransformations --- tests/unit/fem/test_face_elem_trans.cpp | 228 ++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 tests/unit/fem/test_face_elem_trans.cpp diff --git a/tests/unit/fem/test_face_elem_trans.cpp b/tests/unit/fem/test_face_elem_trans.cpp new file mode 100644 index 0000000000..d3f43910c1 --- /dev/null +++ b/tests/unit/fem/test_face_elem_trans.cpp @@ -0,0 +1,228 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "mfem.hpp" +#include "catch.hpp" + +using namespace mfem; + +namespace face_elem_trans +{ + +TEST_CASE("3D FaceElementTransformations", + "[FaceElementTransformations]") +{ + int log = 0; + int n = 1; + int dim = 3; + int order = 1; + + Mesh mesh(n, n, n, Element::TETRAHEDRON, 1, 2.0, 3.0, 5.0); + + SECTION("SetActiveSide 0") + { + int f = 2; + if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(2); + + if (T != NULL) + { + int attr1 = mesh.GetElement(T->Elem1No)->GetAttribute(); + int attr2 = (T->Elem2No >= 0) ? + mesh.GetElement(T->Elem2No)->GetAttribute() : -1; + + T->SetActiveSide(0); + REQUIRE(T->GetActiveSide() == 0); + REQUIRE(T->GetActiveElementTransformation() == T->Elem1); + REQUIRE(T->GetActivePointTransformation() == &T->Loc1); + } + } + + SECTION("SetActiveSide 1") + { + int f = 2; + if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(2); + + if (T != NULL) + { + int attr1 = mesh.GetElement(T->Elem1No)->GetAttribute(); + int attr2 = (T->Elem2No >= 0) ? + mesh.GetElement(T->Elem2No)->GetAttribute() : -1; + + T->SetActiveSide(1); + REQUIRE(T->GetActiveSide() == 1); + REQUIRE(T->GetActiveElementTransformation() == T->Elem2); + REQUIRE(T->GetActivePointTransformation() == &T->Loc2); + } + } + + SECTION("SetActiveSide 2") + { + int f = 2; + if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(2); + + if (T != NULL) + { + int attr1 = mesh.GetElement(T->Elem1No)->GetAttribute(); + int attr2 = (T->Elem2No >= 0) ? + mesh.GetElement(T->Elem2No)->GetAttribute() : -1; + + SECTION("Both Elements present with Elem1.Attr == Elem2.Attr") + { + T->SetActiveSide(2); + REQUIRE(T->GetActiveSide() == 0); + REQUIRE(T->GetActiveElementTransformation() == T->Elem1); + REQUIRE(T->GetActivePointTransformation() == &T->Loc1); + } + SECTION("Both Elements present with Elem1.Attr < Elem2.Attr") + { + T->Elem1->Attribute = 1; + T->Elem2->Attribute = 2; + + T->SetActiveSide(2); + REQUIRE(T->GetActiveSide() == 0); + REQUIRE(T->GetActiveElementTransformation() == T->Elem1); + REQUIRE(T->GetActivePointTransformation() == &T->Loc1); + + T->Elem1->Attribute = 1; + T->Elem2->Attribute = 1; + } + SECTION("Both Elements present with Elem1.Attr > Elem2.Attr") + { + T->Elem1->Attribute = 2; + T->Elem2->Attribute = 1; + + T->SetActiveSide(2); + REQUIRE(T->GetActiveSide() == 1); + REQUIRE(T->GetActiveElementTransformation() == T->Elem2); + REQUIRE(T->GetActivePointTransformation() == &T->Loc2); + + T->Elem1->Attribute = 1; + T->Elem2->Attribute = 1; + } + SECTION("Element 2 absent") + { + ElementTransformation * T2 = T->Elem2; + T->Elem2 = NULL; + + T->SetActiveSide(2); + REQUIRE(T->GetActiveSide() == 0); + REQUIRE(T->GetActiveElementTransformation() == T->Elem1); + REQUIRE(T->GetActivePointTransformation() == &T->Loc1); + + T->Elem2 = T2; + } + SECTION("Element 1 absent") + { + ElementTransformation * T1 = T->Elem1; + T->Elem1 = NULL; + + T->SetActiveSide(2); + REQUIRE(T->GetActiveSide() == 1); + REQUIRE(T->GetActiveElementTransformation() == T->Elem2); + REQUIRE(T->GetActivePointTransformation() == &T->Loc2); + + T->Elem1 = T1; + } + } + } + + SECTION("GetActiveElementTransformation Without Calling SetActiveSide") + { + int f = 2; + if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(2); + + if (T != NULL) + { + REQUIRE(T->GetActiveSide() == 2); + REQUIRE(T->GetActiveElementTransformation() == T->Elem1); + } + } + + SECTION("GetActivePointTransformation Without Calling SetActiveSide") + { + int f = 2; + if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(2); + + if (T != NULL) + { + REQUIRE(T->GetActiveSide() == 2); + REQUIRE(T->GetActivePointTransformation() == &T->Loc1); + } + } + + SECTION("Transform") + { + int npts = 0; + int f = 2; + if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(f); + + if (T != NULL) + { + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + if (log > 0) + { + std::cout << f << " " << T->Elem1No + << " " << T->Elem2No << std::endl; + } + + double tip_data[3]; + double tip1_data[3]; + double tip2_data[3]; + Vector tip(tip_data, 3); + Vector tip1(tip1_data, 3); + Vector tip2(tip2_data, 3); + + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + T->Loc1.Transform(ip, eip1); + T->Elem1->SetIntPoint(&eip1); + T->Elem1->Transform(eip1, tip1); + + T->Loc2.Transform(ip, eip2); + T->Elem2->SetIntPoint(&eip2); + T->Elem2->Transform(eip2, tip2); + + tip1 -= tip; + tip2 -= tip; + + REQUIRE(tip1.Norml2() == Approx(0.0)); + REQUIRE(tip2.Norml2() == Approx(0.0)); + } + } + if (log > 0) + { + std::cout << "Checked " << npts << " points within face " + << f << std::endl; + } + } +} + +} // namespace face_elem_trans From 59f037d46c3633399de8e6825dd361a10a3fb6a2 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Mar 2020 11:15:40 -0700 Subject: [PATCH 100/535] Adding unit test for new GridFunction::GetValue variants --- tests/unit/fem/test_get_value.cpp | 347 ++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 tests/unit/fem/test_get_value.cpp diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp new file mode 100644 index 0000000000..c80bdbf4bd --- /dev/null +++ b/tests/unit/fem/test_get_value.cpp @@ -0,0 +1,347 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "mfem.hpp" +#include "catch.hpp" + +using namespace mfem; + +double func_3D_lin(const Vector &x) +{ + return x[0] + 2.0 * x[1] + 3.0 * x[2]; +} + +namespace get_value +{ + +TEST_CASE("3D GetValue", + "[GridFunction]" + "[GridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 3; + int order = 1; + double tol = 1e-6; + + Mesh mesh(n, n, n, Element::TETRAHEDRON, 1, 2.0, 3.0, 5.0); + + FunctionCoefficient linCoef(func_3D_lin); + + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + FiniteElementSpace dgi_fespace(&mesh, &dgi_fec); + + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + GridFunction dgi_x(&dgi_fespace); + + GridFunctionCoefficient h1_xCoef(&h1_x); + GridFunctionCoefficient dgv_xCoef(&dgv_x); + GridFunctionCoefficient dgi_xCoef(&dgi_x); + + h1_x.ProjectCoefficient(linCoef); + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + int npts = 0; + + SECTION("Domain Evaluation (H1 Context)") + { + int e = 1; + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + + SECTION("Boundary Evaluation (H1 Context)") + { + int be = 1; + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + + SECTION("Domain Evaluation (DG Context)") + { + int e = 1; + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + + SECTION("Interior Face Evaluation (DG Context)") + { + int be = 2; + FaceElementTransformations *T = mesh.GetInteriorFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + + SECTION("Boundary Evaluation (DG Context)") + { + int be = 1; + FaceElementTransformations *T = mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + + std::cout << "Checked GridFunction::GetValue at " + << npts << " points" << std::endl; +} + +} // namespace get_value From 0472eca7d3213612cfa7c97010783dcafa46ddbc Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Mar 2020 12:02:19 -0700 Subject: [PATCH 101/535] make style --- tests/unit/fem/test_get_value.cpp | 494 +++++++++++++++--------------- 1 file changed, 247 insertions(+), 247 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index c80bdbf4bd..7e85d74179 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -16,7 +16,7 @@ using namespace mfem; double func_3D_lin(const Vector &x) { - return x[0] + 2.0 * x[1] + 3.0 * x[2]; + return x[0] + 2.0 * x[1] + 3.0 * x[2]; } namespace get_value @@ -31,16 +31,16 @@ TEST_CASE("3D GetValue", int dim = 3; int order = 1; double tol = 1e-6; - + Mesh mesh(n, n, n, Element::TETRAHEDRON, 1, 2.0, 3.0, 5.0); FunctionCoefficient linCoef(func_3D_lin); H1_FECollection h1_fec(order, dim); DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, - FiniteElement::VALUE); + FiniteElement::VALUE); DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, - FiniteElement::INTEGRAL); + FiniteElement::INTEGRAL); FiniteElementSpace h1_fespace(&mesh, &h1_fec); FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); @@ -53,7 +53,7 @@ TEST_CASE("3D GetValue", GridFunctionCoefficient h1_xCoef(&h1_x); GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); - + h1_x.ProjectCoefficient(linCoef); dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); @@ -62,286 +62,286 @@ TEST_CASE("3D GetValue", SECTION("Domain Evaluation (H1 Context)") { - int e = 1; - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = h1_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); + int e = 1; + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double f_val = func_3D_lin(tip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); } SECTION("Boundary Evaluation (H1 Context)") { - int be = 1; - ElementTransformation *T = mesh.GetBdrElementTransformation(be); - const FiniteElement *fe = h1_fespace.GetBE(be); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); + int be = 1; + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double f_val = func_3D_lin(tip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); } - + SECTION("Domain Evaluation (DG Context)") { - int e = 1; - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); + int e = 1; + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double f_val = func_3D_lin(tip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); } SECTION("Interior Face Evaluation (DG Context)") { - int be = 2; - FaceElementTransformations *T = mesh.GetInteriorFaceTransformations(be); - const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), - 2*order + 2); + int be = 2; + FaceElementTransformations *T = mesh.GetInteriorFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); + T->SetIntPoint(&ip); + T->Transform(ip, tip); - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double f_val = func_3D_lin(tip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); } - + SECTION("Boundary Evaluation (DG Context)") { - int be = 1; - FaceElementTransformations *T = mesh.GetBdrFaceTransformations(be); - const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), - 2*order + 2); + int be = 1; + FaceElementTransformations *T = mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); + T->SetIntPoint(&ip); + T->Transform(ip, tip); - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double f_val = func_3D_lin(tip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val + << " " << fabs(f_val - h1_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val + << " " << fabs(f_val - dgv_gf_val) << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val + << " " << fabs(f_val - dgi_gf_val) << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); } - + std::cout << "Checked GridFunction::GetValue at " - << npts << " points" << std::endl; + << npts << " points" << std::endl; } } // namespace get_value From 0bf973d760c1b6cb38d36284eb4409af08489c5b Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 16 Mar 2020 21:32:40 -0700 Subject: [PATCH 102/535] Removing temporary example --- examples/test_gfc.cpp | 441 ------------------------------------------ 1 file changed, 441 deletions(-) delete mode 100644 examples/test_gfc.cpp diff --git a/examples/test_gfc.cpp b/examples/test_gfc.cpp deleted file mode 100644 index 57b02a6b65..0000000000 --- a/examples/test_gfc.cpp +++ /dev/null @@ -1,441 +0,0 @@ -#include "mfem.hpp" -#include -#include - -using namespace std; -using namespace mfem; - -double func(const Vector &x) { return x[0] + 2.0 * x[1]; } - -int main(int argc, char *argv[]) -{ - // 1. Initialize MPI. - int num_procs, myid; - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - MPI_Comm_rank(MPI_COMM_WORLD, &myid); - - // 2. Parse command-line options. - const char *mesh_file = "../data/star.mesh"; - int order = 1; - int ser_ref_levels = 0; - int par_ref_levels = 0; - int log = 0; - bool dg = false; - bool mtv = true; - bool di = true; // Domain Integration - bool bi = true; // Boundary Integration - bool fi = true; // Interior Face Integration - bool bfi = true; // Boundary Face Integration - bool visualization = true; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", - "Number of times to refine the mesh uniformly in serial."); - args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", - "Number of times to refine the mesh uniformly in parallel."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); - args.AddOption(&log, "-l", "--log", - "Adjust level of screen output."); - args.AddOption(&dg, "-dg", "--discontinuous-galerkin", "-h1", - "--continuous", "Select H1 or DG space."); - args.AddOption(&mtv, "-mtv", "--map-type-value", "-mti", - "--map-type-integral", "Select VALUE or INTEGRAL map type."); - args.AddOption(&di, "-di", "--domain-integration", "-no-di", - "--no-domain-integration", - "Enable or disable domain integration test."); - args.AddOption(&bi, "-bi", "--boundary-integration", "-no-bi", - "--no-boundary-integration", - "Enable or disable boundary integration test."); - args.AddOption(&fi, "-fi", "--face-integration", "-no-fi", - "--no-face-integration", - "Enable or disable interior face integration test."); - args.AddOption(&bfi, "-bfi", "--bdr-face-integration", "-no-bfi", - "--no-bdr-face-integration", - "Enable or disable boundary face integration test."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - if (!args.Good()) - { - if (myid == 0) - { - args.PrintUsage(cout); - } - MPI_Finalize(); - return 1; - } - if (myid == 0) - { - args.PrintOptions(cout); - } - - // 4. Read the (serial) mesh from the given mesh file on all processors. We - // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface - // and volume meshes with the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - int dim = mesh->Dimension(); - - // 5. Refine the serial mesh on all processors to increase the resolution. In - // this example we do 'ref_levels' of uniform refinement. We choose - // 'ref_levels' to be the largest number that gives a final mesh with no - // more than 10,000 elements. - { - for (int l = 0; l < ser_ref_levels; l++) - { - mesh->UniformRefinement(); - } - } - - // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine - // this mesh further in parallel to increase the resolution. Once the - // parallel mesh is defined, the serial mesh can be deleted. - ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); - delete mesh; - { - for (int l = 0; l < par_ref_levels; l++) - { - pmesh->UniformRefinement(); - } - } - - // 7. Define a parallel finite element space on the parallel mesh. Here we - // use continuous Lagrange finite elements of the specified order. If - // order < 1, we instead use an isoparametric/isogeometric space. - FiniteElementCollection *h1_fec; - FiniteElementCollection *dg_fec; - h1_fec = new H1_FECollection(order, dim); - dg_fec = new DG_FECollection(order, dim, BasisType::GaussLegendre, - mtv ? FiniteElement::VALUE - : FiniteElement::INTEGRAL); - - ParFiniteElementSpace *h1_fespace = new ParFiniteElementSpace(pmesh, h1_fec); - ParFiniteElementSpace *dg_fespace = new ParFiniteElementSpace(pmesh, dg_fec); - - ParFiniteElementSpace *fespace = dg ? dg_fespace : h1_fespace; - HYPRE_Int size = fespace->GlobalTrueVSize(); - if (myid == 0) - { - cout << "Number of finite element unknowns: " << size << endl; - } - - // 10. Define the solution vector x as a parallel finite element grid function - // corresponding to fespace. Initialize x with initial guess of zero, - // which satisfies the boundary conditions. - ParGridFunction x(fespace); - FunctionCoefficient coef(func); - x.ProjectCoefficient(coef); - - GridFunctionCoefficient xCoef(&x); - - double tol = 1e-6; - int npts = 0; - - if (di) - { - // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm - // Domain Integrators and GridFunction::ProjectCoefficient. - cout << "Checking " << pmesh->GetNE() - << " elements in a non-DG context" << endl; - for (int i=0; iGetNE(); i++) - { - ElementTransformation *T = h1_fespace->GetElementTransformation(i); - const FiniteElement *fe = h1_fespace->GetFE(i); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func(tip); - double gf_val = xCoef.Eval(*T, ip); - - if (fabs(f_val - gf_val) > tol) - { - cout << i << ":" << j << " " << f_val << " " << gf_val - << " " << fabs(f_val - gf_val) << endl; - } - } - } - cout << "Checked " << npts << " points within elements" << endl; - - // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm - // Domain Integrators and GridFunction::ProjectCoefficient. - npts = 0; - cout << "Checking " << pmesh->GetNE() - << " elements in a DG context" << endl; - for (int i=0; iGetNE(); i++) - { - ElementTransformation *T = dg_fespace->GetElementTransformation(i); - const FiniteElement *fe = dg_fespace->GetFE(i); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func(tip); - double gf_val = xCoef.Eval(*T, ip); - - if (fabs(f_val - gf_val) > tol) - { - cout << i << ":" << j << " " << f_val << " " << gf_val - << " " << fabs(f_val - gf_val) << endl; - } - } - } - cout << "Checked " << npts << " points within elements" << endl; - } - - if (bi) - { - // Testing Coefficient::Eval as it appears in Bilinear- and LinearForm - // Boundary Integrators and GridFunction::ProjectBdrCoefficient* methods. - npts = 0; - cout << "Checking " << pmesh->GetNBE() - << " boundary elements in a non-DG context" << endl; - for (int i=0; iGetNBE(); i++) - { - ElementTransformation *T = h1_fespace->GetBdrElementTransformation(i); - const FiniteElement *fe = h1_fespace->GetBE(i); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func(tip); - double gf_val = xCoef.Eval(*T, ip); - - if (fabs(f_val - gf_val) > tol) - { - cout << i << ":" << j << " " << f_val << " " << gf_val - << " " << fabs(f_val - gf_val) << endl; - } - } - } - cout << "Checked " << npts << " points within boundary elements" << endl; - } - - if (fi) - { - // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm - // Face Integrators - npts = 0; - cout << "Checking " << pmesh->GetNumFaces() - << " faces in a DG context" << endl; - for (int i=0; iGetNumFaces(); i++) - { - if (log > 0) { cout << "Getting trans for face " << i << endl; } - FaceElementTransformations *T = - pmesh->GetInteriorFaceTransformations(i); - if (T != NULL) - { - const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), - 2*order + 2); - - if (log > 0) - { - cout << i << " " << T->Elem1No - << " " << T->Elem2No << endl; - } - - double tip_data[3]; - double tip1_data[3]; - double tip2_data[3]; - Vector tip(tip_data, 3); - Vector tip1(tip1_data, 3); - Vector tip2(tip2_data, 3); - for (int j=0; jLoc1.Transform(ip, eip1); - T->Loc2.Transform(ip, eip2); - - double gf_val1 = NAN; - double gf_val2 = NAN; - - if (T->Elem1) - { - T->Elem1->SetIntPoint(&eip1); - T->Elem1->Transform(eip1, tip1); - gf_val1 = xCoef.Eval(*T->Elem1, eip1); - if (log > 0) - { - cout << "Elem1 (" << tip1[0] << "," << tip1[1] << "," - << tip1[2] << ") -> " << gf_val1 << endl; - } - } - if (T->Elem2) - { - T->Elem2->SetIntPoint(&eip2); - T->Elem2->Transform(eip2, tip2); - gf_val2 = xCoef.Eval(*T->Elem2, eip2); - if (log > 0) - { - cout << "Elem2 (" << tip2[0] << "," << tip2[1] << "," - << tip2[2] << ") -> " << gf_val2 << endl; - } - } - - T->SetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func(tip); - // double gf_val = (T->Face) ? xCoef.Eval(*T->Face, ip) : NAN; - double gf_val = xCoef.Eval(*T, ip); - - if (log > 0) - { - cout << "Face (" << tip[0] << "," << tip[1] << "," - << tip[2] << ") -> " << gf_val << endl; - } - - if (fabs(f_val - gf_val) > tol) - { - cout << i << " " << f_val << " " << gf_val - << " " << fabs(f_val - gf_val) << endl; - } - } - } - } - cout << "Checked " << npts << " points within faces" << endl; - } - - if (bfi) - { - // Testing Coefficient::Eval as it occurs in Bilinear- and LinearForm - // Boundary Face Integrators - npts = 0; - cout << "Checking " << pmesh->GetNBE() - << " boundary faces in a DG context" << endl; - for (int i=0; iGetNBE(); i++) - { - if (log > 0) - { - cout << "Getting trans for boundary face " << i << endl; - } - FaceElementTransformations *T = pmesh->GetBdrFaceTransformations(i); - if (T != NULL) - { - const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), - 2*order + 2); - - if (log > 0) - { - cout << i << " " << T->Elem1No << " " << T->Elem2No << endl; - } - - double tip_data[3]; - double tip1_data[3]; - Vector tip(tip_data, 3); - Vector tip1(tip1_data, 3); - for (int j=0; jLoc1.Transform(ip, eip1); - - double gf_val1 = NAN; - - if (T->Elem1) - { - T->Elem1->SetIntPoint(&eip1); - T->Elem1->Transform(eip1, tip1); - gf_val1 = xCoef.Eval(*T->Elem1, eip1); - if (log > 0) - { - cout << "Elem1 (" << tip1[0] << "," << tip1[1] << "," - << tip1[2] << ") -> " << gf_val1 << endl; - } - } - - T->SetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func(tip); - // double gf_val = xCoef.Eval(*T->Face, ip); - double gf_val = xCoef.Eval(*T, ip); - - if (log > 0) - { - cout << "Face (" << tip[0] << "," << tip[1] << "," - << tip[2] << ") -> " << gf_val << endl; - } - - if (fabs(f_val - gf_val) > tol) - { - cout << i << ":" << j << " " << f_val << " " << gf_val - << " " << fabs(f_val - gf_val) << endl; - } - } - } - } - cout << "Checked " << npts << " points within boundary faces" << endl; - } - - // 15. Save the refined mesh and the solution in parallel. This output can - // be viewed later using GLVis: "glvis -np -m mesh -g sol". - { - ostringstream mesh_name, sol_name; - mesh_name << "mesh." << setfill('0') << setw(6) << myid; - sol_name << "sol." << setfill('0') << setw(6) << myid; - - ofstream mesh_ofs(mesh_name.str().c_str()); - mesh_ofs.precision(8); - pmesh->Print(mesh_ofs); - - ofstream sol_ofs(sol_name.str().c_str()); - sol_ofs.precision(8); - x.Save(sol_ofs); - } - - // 16. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream sol_sock(vishost, visport); - sol_sock << "parallel " << num_procs << " " << myid << "\n"; - sol_sock.precision(8); - sol_sock << "solution\n" << *pmesh << x << flush; - } - - // 17. Free the used memory. - delete dg_fespace; - delete h1_fespace; - delete dg_fec; - delete h1_fec; - delete pmesh; - - MPI_Finalize(); - - return 0; -} From 3dc292f9f2c56254aee8d89f632df887e631f6ec Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 17 Mar 2020 15:35:29 -0700 Subject: [PATCH 103/535] adding some 3D functionality --- fem/gslib.cpp | 50 +++---- fem/tmop.cpp | 201 ++++++++++++++++----------- fem/tmop.hpp | 15 +- fem/tmop_tools.cpp | 94 ++++++++++++- fem/tmop_tools.hpp | 3 + miniapps/meshing/mesh-optimizer.cpp | 77 +++++++--- miniapps/meshing/pmesh-optimizer.cpp | 81 +++++++---- 7 files changed, 349 insertions(+), 172 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 20c5c2e86f..bf73a817b1 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -168,33 +168,33 @@ void FindPointsGSLIB::Interpolate(Array &codes, int ncomp = field_in.FESpace()->GetVDim(); const int points_cnt = ref_pos.Size() / dim; - for (int i=0;iSetParMetaInfo(*tspec_.ParFESpace()->GetParMesh(), - *tspec_.FESpace()->FEColl(), - tspec_.FESpace()->GetVDim()); - - adapt_eval->SetInitialField - (*tspec_.FESpace()->GetMesh()->GetNodes(), tspec); - - tspec_sav = tspec; -} - void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() { if (!adapt_eval) {MFEM_ABORT("Set adaptivity evaluator\n");} @@ -995,92 +977,114 @@ void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) { + const int vdim = tspec_.FESpace()->GetVDim(); if (ncomp==0) { - tspec_fes = tspec_.FESpace(); + tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), + tspec_.FESpace()->FEColl(), + 1); ptspec_fes = tspec_.ParFESpace(); } - MFEM_VERIFY(tspec_.FESpace()->GetVDim()==1,"Only GridFunctions defined " - "on Scalar FESpace are accepted"); - ncomp += 1; - int sz = tspec_.Size(); + + if (ncomp == 0) + { + ncomp += vdim; + tspec = tspec_; + return; + } + + ncomp += vdim; + int cnt = tspec_.Size()/vdim; + //need to append data to tspec + // make a copy of tspec->tspec_temp, increase its size, and + // copy data from tspec_temp -> tspec, then add new entries + Vector tspec_temp = tspec; - tspec.SetSize(ncomp*sz); - for (int i=0; iSetSerialMetaInfo(*tspec_.FESpace()->GetMesh(), - *tspec_.FESpace()->FEColl(), - tspec_.FESpace()->GetVDim()); - adapt_eval->SetInitialField - (*tspec_.FESpace()->GetMesh()->GetNodes(), tspec); - - tspec_sav = tspec; -} - void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) { - if (ncomp==0) { - tspec_fes = tspec_.FESpace(); + const int vdim = tspec_.FESpace()->GetVDim(), + cnt = tspec_.Size()/vdim; + + if (ncomp == 0) + { + tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), + tspec_.FESpace()->FEColl(), + 1); + // we don't do tspec_.FESpace() here because it can be a vector FESpace + // for 3D cases (e.g., aspect ratio has 3 components in 3D). } - else { - MFEM_VERIFY(tspec_fes->GetNDofs()==tspec_.FESpace()->GetNDofs(), - " The FiniteElementSpace should be same for all discrete functions.") + else + { + MFEM_VERIFY(tspec_fes->GetNDofs() == tspec_.FESpace()->GetNDofs(), + " The FiniteElementSpace should be same for all discrete functions.") } - MFEM_VERIFY(tspec_.FESpace()->GetVDim()==1,"Only GridFunctions defined " - "on Scalar FESpace are accepted"); - ncomp += 1; - int sz = tspec_.Size(); + + ncomp += vdim; + + if (ncomp == vdim) + { + tspec = tspec_; + return; + } + + // need to append data to tspec + // make a copy of tspec->tspec_temp, increase its size, and + // copy data from tspec_temp -> tspec, then add new entries Vector tspec_temp = tspec; - tspec.SetSize(ncomp*sz); - for (int i=0; i0," Must set atleast 1 discrete target spec"); + MFEM_VERIFY(ncomp > 0," Must set atleast 1 discrete target spec"); adapt_eval->SetSerialMetaInfo(*tspec_fes->GetMesh(), *tspec_fes->FEColl(), ncomp); + adapt_eval->SetInitialField (*tspec_fes->GetMesh()->GetNodes(), tspec); @@ -1154,12 +1159,13 @@ void DiscreteAdaptTC::UpdateTargetSpecificationAtNode(const FiniteElement &el, int cnt = tspec.Size()/ncomp; //dofs per scalar-field int dim = tspec_fes->GetFE(0)->GetDim(); //dim int dimmax; //maximum number of components in tspec_perth/2h/mix - (!MixTerm) ? dimmax = dim : dimmax = 1+2*(dim-2); + (!MixTerm) ? dimmax = ncomp : dimmax = 1+2*(dim-2); - for (int i=0; iGetFE(0)->GetDof(); + ndofs = tspec_fes->GetFE(0)->GetDof(), + ntspec_dofs = ndofs*ncomp; - Vector shape(ntspec_dofs/ncomp), tspec_vals(ntspec_dofs); + + Vector shape(ndofs), tspec_vals(ntspec_dofs); Array dofs; tspec_fesv->GetElementVDofs(e_id, dofs); tspec.GetSubVector(dofs, tspec_vals); @@ -1205,12 +1213,12 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, Jtr(i) = Wideal; //Initialize to identity } - int ndofs = ntspec_dofs/ncomp; Vector par_vals; + Vector par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs); - if (sizeidx>-1) //Set size spec + if (sizeidx != -1) //Set size spec { - par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs,ndofs); + par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs, ndofs); const double min_size = par_vals.Min(); MFEM_VERIFY(min_size > 0.0, "Non-positive size propagated in the target definition."); @@ -1223,27 +1231,51 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, Jtr(i).Set(std::pow(size, 1.0/dim), Jtr(i)); } } - if (target_type==IDEAL_SHAPE_GIVEN_SIZE) {break;} + if (target_type==IDEAL_SHAPE_GIVEN_SIZE) { break; } - if (aspectratioidx>-1) //Set aspect ratio spec + if (aspectratioidx != -1) //Set aspect ratio spec { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - aspectratioidx*ndofs,ndofs); + if (dim == 2) + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + aspectratioidx*ndofs, ndofs); + } + else + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + aspectratioidx*ndofs, ndofs*3); + par_vals_c1.SetData(par_vals.GetData()); + par_vals_c2.SetData(par_vals.GetData()+ndofs); + par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + } + const double min_size = par_vals.Min(); - MFEM_VERIFY(dim==2," Aspect ratio adaptivity only available in 2D"); for (int i = 0; i < ir.GetNPoints(); i++) { const IntegrationPoint &ip = ir.IntPoint(i); tspec_fes->GetFE(e_id)->CalcShape(ip, shape); - const double aspectratio = std::max(shape * par_vals, min_size); - Jtr(i)(0,0) *= 1./pow(aspectratio,0.5); - Jtr(i)(1,1) *= pow(aspectratio,0.5); + if (dim == 2) + { + const double aspectratio = std::max(shape * par_vals, min_size); + Jtr(i)(0,0) *= 1./pow(aspectratio,0.5); + Jtr(i)(1,1) *= pow(aspectratio,0.5); + } + else + { + const double rho1 = shape * par_vals_c1; + const double rho2 = shape * par_vals_c2; + const double rho3 = shape * par_vals_c3; + Jtr(i)(0,0) *= rho1; + Jtr(i)(1,1) *= rho2; + Jtr(i)(2,2) *= rho3; + } } } - //MFEM_VERIFY(skewidx==-1,"Skew-based target construction not yet supported"); - //MFEM_VERIFY(orientationidx==-1,"Skew-based target construction not yet supported"); + MFEM_VERIFY(skewidx == -1, " Skew-based target construction not yet supported"); + MFEM_VERIFY(orientationidx == -1, + " Skew-based target construction not yet supported"); break; } default: @@ -1276,10 +1308,10 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x, void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, const double dx) { - const int dim = tspec_fes->GetFE(0)->GetDim(); - const int cnt = x.Size()/dim; - const int totidx = 1+2*(dim-2); - tspec_pert2h.SetSize(x.Size()*ncomp); + const int dim = tspec_fes->GetFE(0)->GetDim(), + cnt = x.Size()/dim, + totidx = 1+2*(dim-2); + tspec_pert2h.SetSize(cnt*dim*ncomp); tspec_pertmix.SetSize(cnt*totidx*ncomp); Vector TSpecTemp; @@ -1309,7 +1341,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, xtemp(k2*cnt+i) += dx; } - TSpecTemp.SetDataAndSize(tspec_pertmix.GetData() + idx*cnt*totidx, cnt*totidx); + TSpecTemp.SetDataAndSize(tspec_pertmix.GetData() + idx*cnt*ncomp, cnt*ncomp); UpdateTargetSpecification(xtemp, TSpecTemp); for (int i = 0; i < cnt; i++) @@ -1750,6 +1782,9 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, Vector elfunmod(elfun); // Energy for unperturbed configuration + + //discr_tc->GetTspecPert1H().Print(); + //std::cout << dx << " " << discr_tc->GetTspecPert1H().Size() << " K10assembleelementvector\n"; double e_fx = GetElementEnergy(el, T, elfun); for (int j = 0; j < dim; j++) @@ -1759,7 +1794,7 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, if (discr_tc) { discr_tc->UpdateTargetSpecificationAtNode( - el, T, i, j, discr_tc->GetTspecPert1H(),false); + el, T, i, j, discr_tc->GetTspecPert1H(), false); } elvect(j*dof+i) = GetFDDerivative(el, T, elfunmod, i, j, e_fx, true); if (discr_tc) { discr_tc->RestoreTargetSpecificationAtNode(T, i); } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index c3d6fdd6a3..53691a3ba7 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -713,12 +713,14 @@ protected: Vector tspec_perth; //eta(x+h) Vector tspec_pert2h; //eta(x+2*h) Vector tspec_pertmix; //eta(x+h,y+h) + // The new order for these vectors is + // eta1(x+h),eta2(x+h)...etan(x+h),eta1(y+h),eta2(y+h)...etan(y+h). + // same for tspec_pert2h and tspec_pertmix. // Note: do not use the Nodes of this space as they may not be on the // positions corresponding to the values of tspec. #ifdef MFEM_USE_MPI ParFiniteElementSpace *ptspec_fes; - ParFiniteElementSpace *ptspec_fesv; #endif const FiniteElementSpace *tspec_fes; const FiniteElementSpace *tspec_fesv; @@ -739,12 +741,11 @@ public: sizeidx(-1), skewidx(-1), aspectratioidx(-1), orientationidx(-1), tspec(), tspec_fes(NULL), adapt_eval(NULL) { } - virtual ~DiscreteAdaptTC() { delete adapt_eval; delete tspec_fesv; } - - virtual void SetSerialDiscreteTargetSpec(GridFunction &tspec_); -#ifdef MFEM_USE_MPI - virtual void SetParDiscreteTargetSpec(ParGridFunction &tspec_); -#endif + virtual ~DiscreteAdaptTC() + { + delete adapt_eval; + delete tspec_fesv; + } virtual void SetSerialDiscreteTargetSize(GridFunction &tspec_); virtual void SetSerialDiscreteTargetSkew(GridFunction &tspec_); diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 72e8c9e232..d68bae9f2d 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -44,17 +44,84 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, // This will be used to move the positions. GridFunction *mesh_nodes = m->GetNodes(); *mesh_nodes = nodes0; + int dim, ncomp; + if (fes) + { + dim = fes->GetFE(0)->GetDim(); + ncomp = fes->GetVDim(); + } + else + { +#ifdef MFEM_USE_MPI + if (pfes) + { + dim = pfes->GetFE(0)->GetDim(); + ncomp = pfes->GetVDim(); + } +#endif + } + const int pnt_cnt = new_nodes.Size()/dim; + new_field = field0; + for (int i = 0; i < ncomp; i++) + { + Vector new_field_temp(new_field.GetData()+i*pnt_cnt, pnt_cnt); + ComputeAtNewPositionScalar(new_nodes, new_field_temp); + } + + // This function will not work for AMR meshes in the current state. + // The two lines below are optional. + field0 = new_field; + nodes0 = new_nodes; +} + +void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, + Vector &new_field) +{ +#if defined(MFEM_DEBUG) || defined(MFEM_USE_MPI) + int myid = 0; +#endif + Mesh *m = mesh; + +#ifdef MFEM_USE_MPI + if (pfes) { MPI_Comm_rank(pfes->GetComm(), &myid); } + if (pmesh) { m = pmesh; } +#endif + + MFEM_VERIFY(m != NULL, "No mesh has been given to the AdaptivityEvaluator."); + + // This will be used to move the positions. + GridFunction *mesh_nodes = m->GetNodes(); + *mesh_nodes = nodes0; + double minv = new_field.Min(), maxv = new_field.Max(); + // Velocity of the positions. GridFunction u(mesh_nodes->FESpace()); subtract(new_nodes, nodes0, u); TimeDependentOperator *oper = NULL; - // This must be the fes of the ind, associated with the object's mesh. - if (fes) { oper = new SerialAdvectorCGOper(nodes0, u, *fes); } + FiniteElementSpace *fess = NULL; #ifdef MFEM_USE_MPI - else if (pfes) { oper = new ParAdvectorCGOper(nodes0, u, *pfes); } + ParFiniteElementSpace *pfess = NULL; +#endif + // This must be the fes of the ind, associated with the object's mesh. + + if (fes) + { + fess = new FiniteElementSpace(fes->GetMesh(), + fes->FEColl(), + 1); + oper = new SerialAdvectorCGOper(nodes0, u, *fess); + } +#ifdef MFEM_USE_MPI + else if (pfes) + { + pfess = new ParFiniteElementSpace(pfes->GetParMesh(), + pfes->FEColl(), + 1); + oper = new ParAdvectorCGOper(nodes0, u, *pfess); + } #endif MFEM_VERIFY(oper != NULL, "No FE space has been given to the AdaptivityEvaluator."); @@ -75,6 +142,9 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, } if (v_max == 0.0) { + delete oper; + delete fess; + delete pfess; // No need to change the field. return; } @@ -106,18 +176,28 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, ode_solver.Step(new_field, t, glob_dt); } + double glob_minv = minv; + double glob_maxv = maxv; +#ifdef MFEM_USE_MPI + if (pfes) + { + MPI_Allreduce(&minv, &glob_minv, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm()); + MPI_Allreduce(&maxv, &glob_maxv, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm()); + } +#endif + minv = glob_minv; + maxv = glob_maxv; + // Trim the overshoots and undershoots. - const double minv = field0.Min(), maxv = field0.Max(); for (int i = 0; i < new_field.Size(); i++) { if (new_field(i) < minv) { new_field(i) = minv; } if (new_field(i) > maxv) { new_field(i) = maxv; } } - nodes0 = new_nodes; - field0 = new_field; - delete oper; + delete fess; + delete pfess; } SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start, diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index a554d293dc..18f02c26fd 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -36,6 +36,9 @@ public: virtual void ComputeAtNewPosition(const Vector &new_nodes, Vector &new_field); + + virtual void ComputeAtNewPositionScalar(const Vector &new_nodes, + Vector &new_field); }; #ifdef MFEM_USE_GSLIB diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 9fcb63d751..525b790a5a 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -166,25 +166,25 @@ double ind_values(const Vector &x) double discr_values(const Vector &x) { - double val = 0.; - const double X = x(0); - const double Y = x(1); + double val = 0.; + const double X = x(0); + const double Y = x(1); - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; - double tfac = 20; - double s1 = 3; - double s2 = 3; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } - val = wgt; - return val; + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc = xn/stretch; yc = yn/stretch; + double tfac = 20; + double s1 = 3; + double s2 = 3; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + val = wgt; + return val; } double ori_values(const Vector &x) @@ -215,6 +215,19 @@ double ori_values(const Vector &x) return 0.0; } +void aspr_ratio_values_3d(const Vector &x, Vector &v) +{ + int dim = x.Size(); + v.SetSize(dim); + double l1, l2, l3; + l1 = 1.; + l2 = 1. + 5*x(1); + l3 = 1. + 10*x(2); + v[0] = l1/pow(l2*l3,0.5); + v[1] = l2/pow(l1*l3,0.5); + v[2] = l3/pow(l2*l1,0.5); +} + class HessianCoefficient : public MatrixCoefficient { private: @@ -534,7 +547,9 @@ int main(int argc, char *argv[]) HessianCoefficient *adapt_coeff = NULL; H1_FECollection ind_fec(mesh_poly_deg, dim); FiniteElementSpace ind_fes(mesh, &ind_fec); + FiniteElementSpace ind_fesv(mesh, &ind_fec, dim); GridFunction size, aspr, disc; + GridFunction aspr3d; switch (target_id) { case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break; @@ -553,14 +568,14 @@ int main(int argc, char *argv[]) { target_t = TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); - size.SetSpace(&ind_fes); - FunctionCoefficient ind_coeff(ind_values); - size.ProjectCoefficient(ind_coeff); #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); #else tc->SetAdaptivityEvaluator(new AdvectorCG); #endif + size.SetSpace(&ind_fes); + FunctionCoefficient ind_coeff(ind_values); + size.ProjectCoefficient(ind_coeff); tc->SetSerialDiscreteTargetSize(size); tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; @@ -582,7 +597,7 @@ int main(int argc, char *argv[]) #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); #else - if (fdscheme==0) {tc->SetAdaptivityEvaluator(new AdvectorCG);} + tc->SetAdaptivityEvaluator(new AdvectorCG); #endif //Diffuse the interface @@ -661,6 +676,24 @@ int main(int argc, char *argv[]) target_c = tc; break; } + case 7: + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + tc->SetAdaptivityEvaluator(new AdvectorCG); +#endif + VectorFunctionCoefficient fd_aspr3d(dim, aspr_ratio_values_3d); + aspr3d.SetSpace(&ind_fesv); + aspr3d.ProjectCoefficient(fd_aspr3d); + + tc->SetSerialDiscreteTargetAspectRatio(aspr3d); + tc->FinalizeSerialDiscreteTargetSpec(); + target_c = tc; + break; + } default: cout << "Unknown target_id: " << target_id << endl; return 3; } if (target_c == NULL) diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 7f4dc708f3..ad0ffb7f56 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -164,35 +164,26 @@ double ind_values(const Vector &x) double disc_values(const Vector &x) { - double val = 0.; - const double X = x(0); - const double Y = x(1); + double val = 0.; + const double X = x(0); + const double Y = x(1); - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; - double tfac = 20; - double s1 = 3; - double s2 = 3; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } - val = wgt; - return val; + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc = xn/stretch; yc = yn/stretch; + double tfac = 20; + double s1 = 3; + double s2 = 3; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + val = wgt; + return val; } -======= - - val = std::max(0.,val); - val = std::min(1.,val); - - return val * small + (1.0 - val) * big; -} - ->>>>>>> 6576e8a408a90f36a3bbbfa62470b5b2061e4216 double ori_values(const Vector &x) { @@ -222,6 +213,19 @@ double ori_values(const Vector &x) return 0.0; } +void aspr_ratio_values_3d(const Vector &x, Vector &v) +{ + int dim = x.Size(); + v.SetSize(dim); + double l1, l2, l3; + l1 = 1.; + l2 = 1. + 5*x(1); + l3 = 1. + 10*x(2); + v[0] = l1/pow(l2*l3,0.5); + v[1] = l2/pow(l1*l3,0.5); + v[2] = l3/pow(l2*l1,0.5); +} + class HessianCoefficient : public MatrixCoefficient { private: @@ -572,6 +576,9 @@ int main (int argc, char *argv[]) H1_FECollection ind_fec(mesh_poly_deg, dim); ParFiniteElementSpace ind_fes(pmesh, &ind_fec); ParGridFunction size, aspr, disc; + ParFiniteElementSpace ind_fesv(pmesh, &ind_fec, dim); + ParGridFunction aspr3d; + switch (target_id) { case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break; @@ -619,7 +626,7 @@ int main (int argc, char *argv[]) #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); #else - if (fdscheme==0) {tc->SetAdaptivityEvaluator(new AdvectorCG);} + tc->SetAdaptivityEvaluator(new AdvectorCG); #endif //Diffuse the interface @@ -705,6 +712,24 @@ int main (int argc, char *argv[]) target_c = tc; break; } + case 7: + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + tc->SetAdaptivityEvaluator(new AdvectorCG); +#endif + VectorFunctionCoefficient fd_aspr3d(dim, aspr_ratio_values_3d); + aspr3d.SetSpace(&ind_fesv); + aspr3d.ProjectCoefficient(fd_aspr3d); + + tc->SetParDiscreteTargetAspectRatio(aspr3d); + tc->FinalizeParDiscreteTargetSpec(); + target_c = tc; + break; + } default: if (myid == 0) { cout << "Unknown target_id: " << target_id << endl; } return 3; From aa8987cc1067e3d7bf6f9642f9be625e0d9c5f8d Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 17 Mar 2020 15:36:37 -0700 Subject: [PATCH 104/535] make style --- fem/tmop.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index e99cd3e26c..149a483f3c 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1782,9 +1782,6 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, Vector elfunmod(elfun); // Energy for unperturbed configuration - - //discr_tc->GetTspecPert1H().Print(); - //std::cout << dx << " " << discr_tc->GetTspecPert1H().Size() << " K10assembleelementvector\n"; double e_fx = GetElementEnergy(el, T, elfun); for (int j = 0; j < dim; j++) From 45f4209fd29ca833ebe2f6735b0c18024d0f3444 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 17 Mar 2020 16:28:55 -0700 Subject: [PATCH 105/535] minor --- miniapps/meshing/pmesh-optimizer.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index ad0ffb7f56..111e032512 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -712,24 +712,24 @@ int main (int argc, char *argv[]) target_c = tc; break; } - case 7: - { - target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; - DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + case 7: + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new AdvectorCG); #endif - VectorFunctionCoefficient fd_aspr3d(dim, aspr_ratio_values_3d); - aspr3d.SetSpace(&ind_fesv); - aspr3d.ProjectCoefficient(fd_aspr3d); + VectorFunctionCoefficient fd_aspr3d(dim, aspr_ratio_values_3d); + aspr3d.SetSpace(&ind_fesv); + aspr3d.ProjectCoefficient(fd_aspr3d); - tc->SetParDiscreteTargetAspectRatio(aspr3d); - tc->FinalizeParDiscreteTargetSpec(); - target_c = tc; - break; - } + tc->SetParDiscreteTargetAspectRatio(aspr3d); + tc->FinalizeParDiscreteTargetSpec(); + target_c = tc; + break; + } default: if (myid == 0) { cout << "Unknown target_id: " << target_id << endl; } return 3; From 6943d175bae4481ececd9314c31ab63646db594c Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Wed, 18 Mar 2020 12:11:05 -0700 Subject: [PATCH 106/535] minor --- fem/tmop.cpp | 122 ++++++++++++++++++++++++--- fem/tmop_tools.cpp | 85 ++++++++----------- miniapps/meshing/mesh-optimizer.cpp | 92 +++++++++++++------- miniapps/meshing/pmesh-optimizer.cpp | 73 ++++++++++++++-- 4 files changed, 270 insertions(+), 102 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 149a483f3c..c514406cbd 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1203,6 +1203,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, Vector shape(ndofs), tspec_vals(ntspec_dofs); Array dofs; + DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim); tspec_fesv->GetElementVDofs(e_id, dofs); tspec.GetSubVector(dofs, tspec_vals); @@ -1249,6 +1250,48 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, par_vals_c3.SetData(par_vals.GetData()+2*ndofs); } + for (int i = 0; i < ir.GetNPoints(); i++) + { + const IntegrationPoint &ip = ir.IntPoint(i); + tspec_fes->GetFE(e_id)->CalcShape(ip, shape); + if (dim == 2) + { + const double aspectratio = shape * par_vals; + D_rho = 0.; + D_rho(0,0) = 1./pow(aspectratio,0.5); + D_rho(1,1) = pow(aspectratio,0.5); + } + else + { + const double rho1 = shape * par_vals_c1; + const double rho2 = shape * par_vals_c2; + const double rho3 = shape * par_vals_c3; + D_rho = 0.; + D_rho(0,0) = rho1; + D_rho(1,1) = rho2; + D_rho(2,2) = rho3; + } + DenseMatrix Temp = Jtr(i); + Mult(D_rho, Temp, Jtr(i)); + } + } + + if (skewidx != -1) //Set skew + { + if (dim == 2) + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + skewidx*ndofs, ndofs); + } + else + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + skewidx*ndofs, ndofs*3); + par_vals_c1.SetData(par_vals.GetData()); + par_vals_c2.SetData(par_vals.GetData()+ndofs); + par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + } + const double min_size = par_vals.Min(); for (int i = 0; i < ir.GetNPoints(); i++) @@ -1257,25 +1300,78 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, tspec_fes->GetFE(e_id)->CalcShape(ip, shape); if (dim == 2) { - const double aspectratio = std::max(shape * par_vals, min_size); - Jtr(i)(0,0) *= 1./pow(aspectratio,0.5); - Jtr(i)(1,1) *= pow(aspectratio,0.5); + const double skew = std::max(shape * par_vals, min_size); + + Q_phi = 0.; + Q_phi(0,0) = 1.; + Q_phi(0,1) = cos(skew); + Q_phi(1,1) = sin(skew); } else { - const double rho1 = shape * par_vals_c1; - const double rho2 = shape * par_vals_c2; - const double rho3 = shape * par_vals_c3; - Jtr(i)(0,0) *= rho1; - Jtr(i)(1,1) *= rho2; - Jtr(i)(2,2) *= rho3; + const double phi12 = shape * par_vals_c1; + const double phi13 = shape * par_vals_c2; + const double phichi = shape * par_vals_c3; + + Q_phi = 0.; + Q_phi(0,0) = 1.; + Q_phi(0,1) = cos(phi12); + Q_phi(0,2) = cos(phi13); + + Q_phi(1,1) = sin(phi12); + Q_phi(1,2) = sin(phi13)*cos(phichi); + + Q_phi(2,2) = sin(phi13)*sin(phichi); } + + + DenseMatrix Temp = Jtr(i); + Mult(Q_phi, Temp, Jtr(i)); } } - MFEM_VERIFY(skewidx == -1, " Skew-based target construction not yet supported"); - MFEM_VERIFY(orientationidx == -1, - " Skew-based target construction not yet supported"); + if (orientationidx != -1) //Set skew + { + if (dim == 2) + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + orientationidx*ndofs, ndofs); + } + else + { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + orientationidx*ndofs, ndofs*3); + par_vals_c1.SetData(par_vals.GetData()); + par_vals_c2.SetData(par_vals.GetData()+ndofs); + par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + } + + const double min_size = par_vals.Min(); + + for (int i = 0; i < ir.GetNPoints(); i++) + { + const IntegrationPoint &ip = ir.IntPoint(i); + tspec_fes->GetFE(e_id)->CalcShape(ip, shape); + if (dim == 2) + { + const double theta = std::max(shape * par_vals, min_size); + R_theta(0,0) = cos(theta); + R_theta(0,1) = -sin(theta); + R_theta(1,0) = sin(theta); + R_theta(1,1) = cos(theta); + } + else + { + //const double theta1 = shape * par_vals_c1; + //const double theta2 = shape * par_vals_c2; + //const double theta3 = shape * par_vals_c3; + + MFEM_ABORT("Orientation target construction not available in 3D") + } + DenseMatrix Temp = Jtr(i); + Mult(R_theta, Temp, Jtr(i)); + } + } break; } default: @@ -1373,6 +1469,7 @@ void AdaptivityEvaluator::SetParMetaInfo(const ParMesh &m, delete pmesh; pmesh = new ParMesh(m, true); pfes = new ParFiniteElementSpace(pmesh, &fec, num_comp); + fes = pfes; } #endif @@ -1381,7 +1478,6 @@ AdaptivityEvaluator::~AdaptivityEvaluator() delete fes; delete mesh; #ifdef MFEM_USE_MPI - delete pfes; delete pmesh; #endif } diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index d68bae9f2d..4cf579ca74 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -29,38 +29,9 @@ void AdvectorCG::SetInitialField(const Vector &init_nodes, void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, Vector &new_field) { -#if defined(MFEM_DEBUG) || defined(MFEM_USE_MPI) - int myid = 0; -#endif - Mesh *m = mesh; - -#ifdef MFEM_USE_MPI - if (pfes) { MPI_Comm_rank(pfes->GetComm(), &myid); } - if (pmesh) { m = pmesh; } -#endif - - MFEM_VERIFY(m != NULL, "No mesh has been given to the AdaptivityEvaluator."); - - // This will be used to move the positions. - GridFunction *mesh_nodes = m->GetNodes(); - *mesh_nodes = nodes0; - int dim, ncomp; - if (fes) - { - dim = fes->GetFE(0)->GetDim(); - ncomp = fes->GetVDim(); - } - else - { -#ifdef MFEM_USE_MPI - if (pfes) - { - dim = pfes->GetFE(0)->GetDim(); - ncomp = pfes->GetVDim(); - } -#endif - } - const int pnt_cnt = new_nodes.Size()/dim; + const int dim = fes->GetFE(0)->GetDim(), + ncomp = fes->GetVDim(), + pnt_cnt = new_nodes.Size()/dim; new_field = field0; @@ -79,12 +50,10 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, Vector &new_field) { -#if defined(MFEM_DEBUG) || defined(MFEM_USE_MPI) - int myid = 0; -#endif Mesh *m = mesh; #ifdef MFEM_USE_MPI + int myid = 0; if (pfes) { MPI_Comm_rank(pfes->GetComm(), &myid); } if (pmesh) { m = pmesh; } #endif @@ -133,21 +102,39 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, { min_h = std::min(min_h, m->GetElementSize(i)); } - double v_max = 0.0; - const int s = u.FESpace()->GetVSize() / 2; + double v_max = 0.0, v_max_glob = 0.0; + const int dim = fes->GetFE(0)->GetDim(), + s = new_field.Size() ; + for (int i = 0; i < s; i++) { - const double vel = u(i) * u(i) + u(i+s) * u(i+s); + double vel = 0.; + for (int j = 0; j < dim; j++) + { + vel += u(i+j*s)*u(i+j*s); + } v_max = std::max(v_max, vel); } - if (v_max == 0.0) + + v_max_glob = v_max; +#ifdef MFEM_USE_MPI + if (pfes) + { + MPI_Allreduce(&v_max, &v_max_glob, 1, MPI_DOUBLE, MPI_MAX, pfes->GetComm()); + } +#endif + v_max = v_max_glob; + + if (v_max == 0.0) // No need to change the field. { delete oper; delete fess; +#ifdef MFEM_USE_MPI delete pfess; - // No need to change the field. +#endif return; } + v_max = std::sqrt(v_max); double dt = 0.5 * min_h / v_max; double glob_dt = dt; @@ -164,12 +151,6 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, { if (t + glob_dt >= 1.0) { -#ifdef MFEM_DEBUG - if (myid == 0) - { - mfem::out << "Remap took " << ti << " steps." << std::endl; - } -#endif glob_dt = 1.0 - t; last_step = true; } @@ -182,22 +163,22 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, if (pfes) { MPI_Allreduce(&minv, &glob_minv, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm()); - MPI_Allreduce(&maxv, &glob_maxv, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm()); + MPI_Allreduce(&maxv, &glob_maxv, 1, MPI_DOUBLE, MPI_MAX, pfes->GetComm()); } #endif - minv = glob_minv; - maxv = glob_maxv; // Trim the overshoots and undershoots. - for (int i = 0; i < new_field.Size(); i++) + for (int i = 0; i < s; i++) { - if (new_field(i) < minv) { new_field(i) = minv; } - if (new_field(i) > maxv) { new_field(i) = maxv; } + if (new_field(i) < glob_minv) { new_field(i) = glob_minv; } + if (new_field(i) > glob_maxv) { new_field(i) = glob_maxv; } } delete oper; delete fess; +#ifdef MFEM_USE_MPI delete pfess; +#endif } SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start, diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 525b790a5a..97805c87c3 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -183,39 +183,36 @@ double discr_values(const Vector &x) double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); if (wgt > 1) { wgt = 1; } if (wgt < 0) { wgt = 0; } - val = wgt; - return val; + return wgt; } -double ori_values(const Vector &x) +double ori_values_2d(const Vector &x) { - const int opt = 2; - - // circle - if (opt == 1) - { - double val = 0.; - const double xc = x(0) - 0.5, yc = x(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = -0.2; double r2 = 0.3; double sf=2.0; - val = 0.5*(std::tanh(sf*(r-r1)) - std::tanh(sf*(r-r2))); - val = 0; - if (r 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc /= stretch; yc /= stretch; + + double tfac = 20; + double s1 = 3; + double s2 = 2; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) + - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + return 0.1 + 1*(1-wgt)*(1-wgt); +} + +void aspr_values_3d(const Vector &x, Vector &v) { int dim = x.Size(); v.SetSize(dim); @@ -548,7 +545,7 @@ int main(int argc, char *argv[]) H1_FECollection ind_fec(mesh_poly_deg, dim); FiniteElementSpace ind_fes(mesh, &ind_fec); FiniteElementSpace ind_fesv(mesh, &ind_fec, dim); - GridFunction size, aspr, disc; + GridFunction size, aspr, disc, ori; GridFunction aspr3d; switch (target_id) { @@ -581,6 +578,41 @@ int main(int argc, char *argv[]) target_c = tc; break; } + case 60: + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + tc->SetAdaptivityEvaluator(new AdvectorCG); +#endif + + ori.SetSpace(&ind_fes); + FunctionCoefficient ori_coeff(ori_values_2d); + ori.ProjectCoefficient(ori_coeff); + + if (metric_id == 14) + { + size.SetSpace(&ind_fes); + ConstantCoefficient ind_coeff(0.1*0.1); + size.ProjectCoefficient(ind_coeff); + tc->SetSerialDiscreteTargetSize(size); + } + + if (metric_id == 87) + { + aspr.SetSpace(&ind_fes); + FunctionCoefficient aspr_coeff(aspr_values_2d); + aspr.ProjectCoefficient(aspr_coeff); + tc->SetSerialDiscreteTargetAspectRatio(aspr); + } + + tc->SetSerialDiscreteTargetOrientation(ori); + tc->FinalizeSerialDiscreteTargetSpec(); + target_c = tc; + break; + } case 6: { GridFunction d_x, d_y; @@ -685,7 +717,7 @@ int main(int argc, char *argv[]) #else tc->SetAdaptivityEvaluator(new AdvectorCG); #endif - VectorFunctionCoefficient fd_aspr3d(dim, aspr_ratio_values_3d); + VectorFunctionCoefficient fd_aspr3d(dim, aspr_values_3d); aspr3d.SetSpace(&ind_fesv); aspr3d.ProjectCoefficient(fd_aspr3d); diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 111e032512..000dee3123 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -181,8 +181,7 @@ double disc_values(const Vector &x) double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); if (wgt > 1) { wgt = 1; } if (wgt < 0) { wgt = 0; } - val = wgt; - return val; + return wgt; } double ori_values(const Vector &x) @@ -213,7 +212,33 @@ double ori_values(const Vector &x) return 0.0; } -void aspr_ratio_values_3d(const Vector &x, Vector &v) +double ori_values_2d(const Vector &x) +{ + const double xc = x(0), yc = x(1); + return M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); +} + +double aspr_values_2d(const Vector &x) +{ + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc /= stretch; yc /= stretch; + + double tfac = 20; + double s1 = 3; + double s2 = 2; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) + - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + return 0.1 + 1*(1-wgt)*(1-wgt); +} + +void aspr_values_3d(const Vector &x, Vector &v) { int dim = x.Size(); v.SetSize(dim); @@ -287,7 +312,6 @@ public: - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); if (wgt > 1) { wgt = 1; } if (wgt < 0) { wgt = 0; } - double val = wgt; xc = pos(0), yc = pos(1); double theta = M_PI * (yc) * (1.0 - yc) * cos(2 * M_PI * xc); @@ -297,7 +321,7 @@ public: K(0, 1) = -sin(theta); K(1, 1) = cos(theta); - double asp_ratio_tar = 0.1 + 1*(1-val)*(1-val); + double asp_ratio_tar = 0.1 + 1*(1-wgt)*(1-wgt); K(0, 0) *= 1/pow(asp_ratio_tar,0.5); K(1, 0) *= 1/pow(asp_ratio_tar,0.5); @@ -575,7 +599,7 @@ int main (int argc, char *argv[]) HessianCoefficient *adapt_coeff = NULL; H1_FECollection ind_fec(mesh_poly_deg, dim); ParFiniteElementSpace ind_fes(pmesh, &ind_fec); - ParGridFunction size, aspr, disc; + ParGridFunction size, aspr, disc, ori; ParFiniteElementSpace ind_fesv(pmesh, &ind_fec, dim); ParGridFunction aspr3d; @@ -610,6 +634,41 @@ int main (int argc, char *argv[]) target_c = tc; break; } + case 60: + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + tc->SetAdaptivityEvaluator(new AdvectorCG); +#endif + + ori.SetSpace(&ind_fes); + FunctionCoefficient ori_coeff(ori_values_2d); + ori.ProjectCoefficient(ori_coeff); + + if (metric_id == 14) + { + size.SetSpace(&ind_fes); + ConstantCoefficient ind_coeff(0.1*0.1); + size.ProjectCoefficient(ind_coeff); + tc->SetParDiscreteTargetSize(size); + } + + if (metric_id == 87) + { + aspr.SetSpace(&ind_fes); + FunctionCoefficient aspr_coeff(aspr_values_2d); + aspr.ProjectCoefficient(aspr_coeff); + tc->SetParDiscreteTargetAspectRatio(aspr); + } + + tc->SetParDiscreteTargetOrientation(ori); + tc->FinalizeParDiscreteTargetSpec(); + target_c = tc; + break; + } case 6: { ParGridFunction d_x, d_y; @@ -721,7 +780,7 @@ int main (int argc, char *argv[]) #else tc->SetAdaptivityEvaluator(new AdvectorCG); #endif - VectorFunctionCoefficient fd_aspr3d(dim, aspr_ratio_values_3d); + VectorFunctionCoefficient fd_aspr3d(dim, aspr_values_3d); aspr3d.SetSpace(&ind_fesv); aspr3d.ProjectCoefficient(fd_aspr3d); From 911e383c69277ae54b33d82a0721f2fa8580391d Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Wed, 18 Mar 2020 14:26:06 -0700 Subject: [PATCH 107/535] unused variables --- fem/tmop.cpp | 33 ++++++++++++---------------- fem/tmop.hpp | 3 +-- miniapps/meshing/mesh-optimizer.cpp | 11 +++------- miniapps/meshing/pmesh-optimizer.cpp | 11 +++------- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index c514406cbd..c79f870e59 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -977,7 +977,8 @@ void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) { - const int vdim = tspec_.FESpace()->GetVDim(); + const int vdim = tspec_.FESpace()->GetVDim(), + cnt = tspec_.Size()/vdim; if (ncomp==0) { tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), @@ -994,7 +995,6 @@ void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) } ncomp += vdim; - int cnt = tspec_.Size()/vdim; //need to append data to tspec // make a copy of tspec->tspec_temp, increase its size, and // copy data from tspec_temp -> tspec, then add new entries @@ -1047,7 +1047,7 @@ void DiscreteAdaptTC::SetParDiscreteTargetOrientation(ParGridFunction &tspec_) void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) { const int vdim = tspec_.FESpace()->GetVDim(), - cnt = tspec_.Size()/vdim; + cnt = tspec_.Size()/vdim; if (ncomp == 0) { @@ -1149,23 +1149,18 @@ void DiscreteAdaptTC::UpdateTargetSpecification(Vector &new_x, void DiscreteAdaptTC::UpdateTargetSpecificationAtNode(const FiniteElement &el, ElementTransformation &T, int dofidx, int dir, - const Vector &IntData, - bool MixTerm) + const Vector &IntData) { MFEM_VERIFY(tspec.Size() > 0, "Target specification is not set!"); Array dofs; tspec_fes->GetElementDofs(T.ElementNo, dofs); - int cnt = tspec.Size()/ncomp; //dofs per scalar-field - int dim = tspec_fes->GetFE(0)->GetDim(); //dim - int dimmax; //maximum number of components in tspec_perth/2h/mix - (!MixTerm) ? dimmax = ncomp : dimmax = 1+2*(dim-2); + const int cnt = tspec.Size()/ncomp; //dofs per scalar-field for (int i = 0; i < ncomp; i++) { - tspec(dofs[dofidx]+i*cnt) = IntData(dofs[dofidx]+i*cnt+dir*cnt*dimmax); + tspec(dofs[dofidx]+i*cnt) = IntData(dofs[dofidx] + i*cnt + dir*cnt*ncomp); } - } void DiscreteAdaptTC::RestoreTargetSpecificationAtNode(ElementTransformation &T, @@ -1175,10 +1170,10 @@ void DiscreteAdaptTC::RestoreTargetSpecificationAtNode(ElementTransformation &T, Array dofs; tspec_fes->GetElementDofs(T.ElementNo, dofs); - int cnt = tspec.Size()/ncomp; - for (int i=0; iUpdateTargetSpecificationAtNode( - el, T, i, j, discr_tc->GetTspecPert1H(), false); + el, T, i, j, discr_tc->GetTspecPert1H()); } elvect(j*dof+i) = GetFDDerivative(el, T, elfunmod, i, j, e_fx, true); if (discr_tc) { discr_tc->RestoreTargetSpecificationAtNode(T, i); } @@ -1921,11 +1916,11 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, if (discr_tc) { discr_tc->UpdateTargetSpecificationAtNode( - el, T, j, k2, discr_tc->GetTspecPert1H(),false); + el, T, j, k2, discr_tc->GetTspecPert1H()); if (j != i) { discr_tc->UpdateTargetSpecificationAtNode( - el, T, i, k1, discr_tc->GetTspecPert1H(),false); + el, T, i, k1, discr_tc->GetTspecPert1H()); } else // j==i { @@ -1933,12 +1928,12 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, { int idx = k1+k2-1; discr_tc->UpdateTargetSpecificationAtNode( - el, T, i, idx, discr_tc->GetTspecPertMixH(),true); + el, T, i, idx, discr_tc->GetTspecPertMixH()); } else // j==i && k1==k2 { discr_tc->UpdateTargetSpecificationAtNode( - el, T, i, k1, discr_tc->GetTspecPert2H(),false); + el, T, i, k1, discr_tc->GetTspecPert2H()); } } } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 53691a3ba7..86541b7f2a 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -769,8 +769,7 @@ public: void UpdateTargetSpecificationAtNode(const FiniteElement &el, ElementTransformation &T, int nodenum, int idir, - const Vector &IntData, - bool MixTerm); + const Vector &IntData); void RestoreTargetSpecificationAtNode(ElementTransformation &T, int nodenum); diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 97805c87c3..50324a6d6f 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -63,7 +63,7 @@ // mesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -#include "../../mfem.hpp" +#include "mfem.hpp" #include #include @@ -166,10 +166,6 @@ double ind_values(const Vector &x) double discr_values(const Vector &x) { - double val = 0.; - const double X = x(0); - const double Y = x(1); - double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; double xn = cos(th)*xc + sin(th)*yc; @@ -188,8 +184,7 @@ double discr_values(const Vector &x) double ori_values_2d(const Vector &x) { - const double xc = x(0), yc = x(1); - return M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); + return M_PI * yc * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } double aspr_values_2d(const Vector &x) @@ -200,7 +195,7 @@ double aspr_values_2d(const Vector &x) double yn = -sin(th)*xc + cos(th)*yc; double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; double stretch = 1/cos(th2); - xc /= stretch; yc /= stretch; + xc = xn/stretch; yc = yn/stretch; double tfac = 20; double s1 = 3; diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 000dee3123..c78c842245 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -61,7 +61,7 @@ // 2D non-conforming shape and equal size: // mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -#include "../../mfem.hpp" +#include "mfem.hpp" #include #include @@ -164,10 +164,6 @@ double ind_values(const Vector &x) double disc_values(const Vector &x) { - double val = 0.; - const double X = x(0); - const double Y = x(1); - double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; double xn = cos(th)*xc + sin(th)*yc; @@ -214,8 +210,7 @@ double ori_values(const Vector &x) double ori_values_2d(const Vector &x) { - const double xc = x(0), yc = x(1); - return M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); + return M_PI * yc * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } double aspr_values_2d(const Vector &x) @@ -226,7 +221,7 @@ double aspr_values_2d(const Vector &x) double yn = -sin(th)*xc + cos(th)*yc; double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; double stretch = 1/cos(th2); - xc /= stretch; yc /= stretch; + xc = xn/stretch; yc = yn/stretch; double tfac = 20; double s1 = 3; From c616458da68887f70282bbb136f257d8b399497e Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Wed, 18 Mar 2020 14:30:01 -0700 Subject: [PATCH 108/535] minor --- miniapps/meshing/mesh-optimizer.cpp | 2 +- miniapps/meshing/pmesh-optimizer.cpp | 27 ++------------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 50324a6d6f..c78d011043 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -184,7 +184,7 @@ double discr_values(const Vector &x) double ori_values_2d(const Vector &x) { - return M_PI * yc * (1.0 - x(1)) * cos(2 * M_PI * x(0)); + return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } double aspr_values_2d(const Vector &x) diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index c78c842245..ef7d384313 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -182,35 +182,12 @@ double disc_values(const Vector &x) double ori_values(const Vector &x) { - const int opt = 2; - - // circle - if (opt == 1) - { - double val = 0.; - const double xc = x(0) - 0.5, yc = x(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = -0.2; double r2 = 0.3; double sf=2.0; - val = 0.5*(std::tanh(sf*(r-r1)) - std::tanh(sf*(r-r2))); - val = 0; - if (r < r2) { val = 1; } - val = 0 + (M_PI/4)*val; - - return val; - } - else if (opt == 2) - { - const double xc = x(0), yc = x(1); - double theta = M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); - return theta; - } - - return 0.0; + return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } double ori_values_2d(const Vector &x) { - return M_PI * yc * (1.0 - x(1)) * cos(2 * M_PI * x(0)); + return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } double aspr_values_2d(const Vector &x) From 9c9e02f4278eb6ff81dc51fe03ebdaa4e8f61862 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Fri, 20 Mar 2020 10:14:57 -0700 Subject: [PATCH 109/535] clean up --- fem/gslib.cpp | 28 +++++----- fem/tmop.cpp | 80 ++++++++++++++++++----------- miniapps/meshing/mesh-optimizer.cpp | 3 +- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index bf73a817b1..f3702e8227 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -166,33 +166,31 @@ void FindPointsGSLIB::Interpolate(Array &codes, field_in_scalar.SetSpace(&ind_fes); Vector node_vals; - int ncomp = field_in.FESpace()->GetVDim(); - const int points_cnt = ref_pos.Size() / dim; + const int ncomp = field_in.FESpace()->GetVDim(), + points_cnt = field_in.Size() / ncomp; + for (int i = 0; i < ncomp; i++) { - int dataptr = i*field_in_scalar.Size(); - for (int j = 0; j < field_in_scalar.Size(); j++) - { - field_in_scalar(j) = field_in(j+dataptr); - } + int dataptr = i*points_cnt; + field_in_scalar.SetData(field_in.GetData()+dataptr); GetNodeValues(field_in_scalar, node_vals); if (dim==2) { findpts_eval_2(field_out.GetData()+dataptr, sizeof(double), - codes.GetData(), sizeof(unsigned int), - proc_ids.GetData(), sizeof(unsigned int), - elem_ids.GetData(), sizeof(unsigned int), - ref_pos.GetData(), sizeof(double) * dim, + codes.GetData(), sizeof(unsigned int), + proc_ids.GetData(), sizeof(unsigned int), + elem_ids.GetData(), sizeof(unsigned int), + ref_pos.GetData(), sizeof(double) * dim, points_cnt, node_vals.GetData(), fdata2D); } else { findpts_eval_3(field_out.GetData()+dataptr, sizeof(double), - codes.GetData(), sizeof(unsigned int), - proc_ids.GetData(), sizeof(unsigned int), - elem_ids.GetData(), sizeof(unsigned int), - ref_pos.GetData(), sizeof(double) * dim, + codes.GetData(), sizeof(unsigned int), + proc_ids.GetData(), sizeof(unsigned int), + elem_ids.GetData(), sizeof(unsigned int), + ref_pos.GetData(), sizeof(double) * dim, points_cnt, node_vals.GetData(), fdata3D); } } diff --git a/fem/tmop.cpp b/fem/tmop.cpp index c79f870e59..c3e39aca32 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1212,7 +1212,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, Vector par_vals; Vector par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs); - if (sizeidx != -1) //Set size spec + if (sizeidx != -1) //Set size { par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs, ndofs); const double min_size = par_vals.Min(); @@ -1226,10 +1226,11 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, const double size = std::max(shape * par_vals, min_size); Jtr(i).Set(std::pow(size, 1.0/dim), Jtr(i)); } - } + } //Done size + if (target_type==IDEAL_SHAPE_GIVEN_SIZE) { break; } - if (aspectratioidx != -1) //Set aspect ratio spec + if (aspectratioidx != -1) //Set aspect ratio { if (dim == 2) { @@ -1262,14 +1263,14 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, const double rho2 = shape * par_vals_c2; const double rho3 = shape * par_vals_c3; D_rho = 0.; - D_rho(0,0) = rho1; - D_rho(1,1) = rho2; - D_rho(2,2) = rho3; + D_rho(0,0) = pow(rho1,2./3.); + D_rho(1,1) = pow(rho2,2./3.); + D_rho(2,2) = pow(rho3,2./3.); } DenseMatrix Temp = Jtr(i); Mult(D_rho, Temp, Jtr(i)); } - } + } //Done aspect ratio if (skewidx != -1) //Set skew { @@ -1287,15 +1288,13 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, par_vals_c3.SetData(par_vals.GetData()+2*ndofs); } - const double min_size = par_vals.Min(); - for (int i = 0; i < ir.GetNPoints(); i++) { const IntegrationPoint &ip = ir.IntPoint(i); tspec_fes->GetFE(e_id)->CalcShape(ip, shape); if (dim == 2) { - const double skew = std::max(shape * par_vals, min_size); + const double skew = shape * par_vals; Q_phi = 0.; Q_phi(0,0) = 1.; @@ -1304,9 +1303,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } else { - const double phi12 = shape * par_vals_c1; - const double phi13 = shape * par_vals_c2; - const double phichi = shape * par_vals_c3; + const double phi12 = shape * par_vals_c1; + const double phi13 = shape * par_vals_c2; + const double chi = shape * par_vals_c3; Q_phi = 0.; Q_phi(0,0) = 1.; @@ -1314,18 +1313,17 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, Q_phi(0,2) = cos(phi13); Q_phi(1,1) = sin(phi12); - Q_phi(1,2) = sin(phi13)*cos(phichi); + Q_phi(1,2) = sin(phi13)*cos(chi); - Q_phi(2,2) = sin(phi13)*sin(phichi); + Q_phi(2,2) = sin(phi13)*sin(chi); } - DenseMatrix Temp = Jtr(i); Mult(Q_phi, Temp, Jtr(i)); } - } + } // done skew - if (orientationidx != -1) //Set skew + if (orientationidx != -1) //Set orientation { if (dim == 2) { @@ -1341,15 +1339,13 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, par_vals_c3.SetData(par_vals.GetData()+2*ndofs); } - const double min_size = par_vals.Min(); - for (int i = 0; i < ir.GetNPoints(); i++) { const IntegrationPoint &ip = ir.IntPoint(i); tspec_fes->GetFE(e_id)->CalcShape(ip, shape); if (dim == 2) { - const double theta = std::max(shape * par_vals, min_size); + const double theta = shape * par_vals; R_theta(0,0) = cos(theta); R_theta(0,1) = -sin(theta); R_theta(1,0) = sin(theta); @@ -1357,16 +1353,38 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } else { - //const double theta1 = shape * par_vals_c1; - //const double theta2 = shape * par_vals_c2; - //const double theta3 = shape * par_vals_c3; + const double theta = shape * par_vals_c1; + const double psi = shape * par_vals_c2; + const double beta = shape * par_vals_c3; - MFEM_ABORT("Orientation target construction not available in 3D") + DenseMatrix R_tp(dim), R_beta(dim), R_theta(dim); + double ct = cos(theta), st = sin(theta), + cp = cos(psi), sp = sin(psi); + R_tp(0,0) = ct*sp; + R_tp(1,0) = st*sp; + R_tp(2,0) = cp; + + R_tp(0,1) = -(ct*st*sp*sp)/(1+cp); + R_tp(1,1) = cp+(pow(ct,2.)*pow(sp,2.))/(1+cp); + R_tp(2,1) = -st*sp; + + R_tp(0,2) = -cp-(pow(st,2.)*pow(sp,2.))/(1+cp); + R_tp(1,2) = -R_tp(0,1); + R_tp(2,2) = ct*sp; + + R_beta = 0.; + R_beta(0,0) = 1.; + R_beta(1,1) = cos(beta); + R_beta(1,2) = -sin(beta); + R_beta(2,1) = sin(beta); + R_beta(2,2) = cos(beta); + + Mult(R_tp, R_beta, R_theta); } DenseMatrix Temp = Jtr(i); Mult(R_theta, Temp, Jtr(i)); } - } + } // done orientation break; } default: @@ -1401,9 +1419,9 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, { const int dim = tspec_fes->GetFE(0)->GetDim(), cnt = x.Size()/dim, - totidx = 1+2*(dim-2); + totmix = 1+2*(dim-2); tspec_pert2h.SetSize(cnt*dim*ncomp); - tspec_pertmix.SetSize(cnt*totidx*ncomp); + tspec_pertmix.SetSize(cnt*totmix*ncomp); Vector TSpecTemp; TSpecTemp.SetSize(cnt*ncomp); @@ -1421,7 +1439,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, } // T(x+h,y+h) - int idx = 0; + int j = 0; for (int k1 = 0; k1 < dim; k1++) { for (int k2 = 0; (k1 != k2) && (k2 < dim); k2++) @@ -1432,7 +1450,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, xtemp(k2*cnt+i) += dx; } - TSpecTemp.SetDataAndSize(tspec_pertmix.GetData() + idx*cnt*ncomp, cnt*ncomp); + TSpecTemp.SetDataAndSize(tspec_pertmix.GetData() + j*cnt*ncomp, cnt*ncomp); UpdateTargetSpecification(xtemp, TSpecTemp); for (int i = 0; i < cnt; i++) @@ -1440,7 +1458,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, xtemp(k1*cnt+i) -= dx; xtemp(k2*cnt+i) -= dx; } - idx++; + j++; } } } diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index c78d011043..71789a9cc6 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -281,7 +281,6 @@ public: - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); if (wgt > 1) { wgt = 1; } if (wgt < 0) { wgt = 0; } - double val = wgt; xc = pos(0), yc = pos(1); double theta = M_PI * (yc) * (1.0 - yc) * cos(2 * M_PI * xc); @@ -291,7 +290,7 @@ public: K(0, 1) = -sin(theta); K(1, 1) = cos(theta); - double asp_ratio_tar = 0.1 + 1*(1-val)*(1-val); + double asp_ratio_tar = 0.1 + 1*(1-wgt)*(1-wgt); K(0, 0) *= 1/pow(asp_ratio_tar,0.5); K(1, 0) *= 1/pow(asp_ratio_tar,0.5); From a7c2e91915e3c140a83781316c480c42924f3236 Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 20 Mar 2020 11:27:09 -0700 Subject: [PATCH 110/535] Initial tests for tangential limiting. --- fem/tmop.cpp | 11 +++++++- fem/tmop.hpp | 12 +++++++++ miniapps/meshing/makefile | 3 +++ miniapps/meshing/pmesh-optimizer.cpp | 38 +++++++++++++++++++++++----- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 7e15327b21..18e44327ff 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1260,7 +1260,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, // Define ref->physical transformation, when a Coefficient is specified. IsoparametricTransformation *Tpr = NULL; - if (coeff1 || coeff0) + if (coeff1 || coeff0 || xi_0) { Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); @@ -1299,6 +1299,15 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, val += lim_normal * lim_func->Eval(p, p0, d_vals(i)) * coeff0->Eval(*Tpr, ip); } + + if (xi_0) + { + // Adaptive limiting. + const double diff = + xi_0->GetValue(T.ElementNo, ip) - xi->Eval(*Tpr, ip); + val += 10.0 * lim_normal * diff * diff; + } + energy += weight * val; } delete Tpr; diff --git a/fem/tmop.hpp b/fem/tmop.hpp index f57abcec27..56aa9af534 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -810,6 +810,10 @@ protected: // Normalization factor for the limiting term. double lim_normal; + // Adaptive limiting. + const GridFunction *xi_0; + Coefficient *xi; + DiscreteAdaptTC *discr_tc; // Parameters for FD-based Gradient & Hessian calculation. @@ -873,6 +877,7 @@ public: coeff1(NULL), metric_normal(1.0), nodes0(NULL), coeff0(NULL), lim_dist(NULL), lim_func(NULL), lim_normal(1.0), + xi_0(NULL), xi(NULL), discr_tc(dynamic_cast(tc)), fdflag(false), dxscale(1.0e3) { } @@ -914,6 +919,13 @@ public: void EnableLimiting(const GridFunction &n0, Coefficient &w0, TMOP_LimiterFunction *lfunc = NULL); + void EnableAnalyticAdaptiveLimiting(const GridFunction &xi0_gf, + Coefficient &xi_coeff) + { + xi_0 = &xi0_gf; + xi = &xi_coeff; + } + /// Update the original/reference nodes used for limiting. void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; } diff --git a/miniapps/meshing/makefile b/miniapps/meshing/makefile index d358b9d087..74e4208b41 100644 --- a/miniapps/meshing/makefile +++ b/miniapps/meshing/makefile @@ -30,6 +30,9 @@ else MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS) endif +MFEM_LIBS += -L$(MFEM_DIR)/miniapps/common -lmfem-common -Wl,-rpath,$(abspath\ + $(MFEM_DIR)/miniapps/common) + .SUFFIXES: .SUFFIXES: .o .cpp .mk .PHONY: all clean clean-build clean-exec diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 58295a08fd..1d838d312f 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -62,6 +62,7 @@ // mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 #include "mfem.hpp" +#include "miniapps/common/pfem_extras.hpp" #include #include @@ -70,6 +71,8 @@ using namespace std; double weight_fun(const Vector &x); +double adapt_lim_fun(const Vector &x); + double ind_values(const Vector &x) { const int opt = 6; @@ -304,7 +307,7 @@ int main (int argc, char *argv[]) bool normalization = false; bool visualization = true; int verbosity_level = 0; - int fdscheme = 0; + bool fdscheme = false; // 2. Parse command-line options. OptionsParser args(argc, argv); @@ -370,7 +373,7 @@ int main (int argc, char *argv[]) args.AddOption(&normalization, "-nor", "--normalization", "-no-nor", "--no-normalization", "Make all terms in the optimization functional unitless."); - args.AddOption(&fdscheme, "-fd", "--fd_approximation", + args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", "Enable finite difference based derivative computations."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", @@ -399,6 +402,7 @@ int main (int argc, char *argv[]) else { cout << "(NONE)"; } cout << endl; } + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; @@ -494,10 +498,10 @@ int main (int argc, char *argv[]) // num_mpi_tasks". { ostringstream mesh_name; - mesh_name << "perturbed." << setfill('0') << setw(6) << myid; + mesh_name << "perturbed.mesh"; ofstream mesh_ofs(mesh_name.str().c_str()); mesh_ofs.precision(8); - pmesh->Print(mesh_ofs); + pmesh->PrintAsOne(mesh_ofs); } // 11. Store the starting (prior to the optimization) positions. @@ -610,6 +614,15 @@ int main (int argc, char *argv[]) ConstantCoefficient lim_coeff(lim_const); if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); } + // Adaptive limiting. + ParGridFunction xi_0; + xi_0.SetSpace(&ind_fes); + FunctionCoefficient alim_coeff(adapt_lim_fun); + xi_0.ProjectCoefficient(alim_coeff); + he_nlf_integ->EnableAnalyticAdaptiveLimiting(xi_0, alim_coeff); + socketstream vis1; + common::VisualizeField(vis1, "localhost", 19916, xi_0, "Xi 0", 300, 600, 300, 300); + // 15. Setup the final NonlinearForm (which defines the integral of interest, // its first and second derivatives). Here we can use a combination of // metrics, i.e., optimize the sum of two integrals, where both are @@ -804,10 +817,10 @@ int main (int argc, char *argv[]) // using GLVis: "glvis -m optimized -np num_mpi_tasks". { ostringstream mesh_name; - mesh_name << "optimized." << setfill('0') << setw(6) << myid; + mesh_name << "optimized.mesh"; ofstream mesh_ofs(mesh_name.str().c_str()); mesh_ofs.precision(8); - pmesh->Print(mesh_ofs); + pmesh->PrintAsOne(mesh_ofs); } // 22. Compute the amount of energy decrease. @@ -838,6 +851,9 @@ int main (int argc, char *argv[]) vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 600); } + socketstream vis0; + common::VisualizeField(vis0, "localhost", 19916, xi_0, "Xi 0", 600, 600, 300, 300); + // 23. Visualize the mesh displacement. if (visualization) { @@ -884,3 +900,13 @@ double weight_fun(const Vector &x) + std::tanh((r-0.23)/den) - std::tanh((r-0.24)/den)); return l2; } + +double adapt_lim_fun(const Vector &x) +{ + const double X = x(0), Y = x(1); + double val = std::tanh((10*(Y-0.5) + std::cos(3.0*M_PI*X)) + 1) - + std::tanh((10*(Y-0.5) + std::cos(3.0*M_PI*X)) - 1); + val = std::max(0.,val); + val = std::min(1.,val); + return val; +} From e23720880064ba02a7e863d853c30a71a79c0459 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 20 Mar 2020 13:51:40 -0700 Subject: [PATCH 111/535] Add unit tests for QuadVecFuncCoeff an QuadFuncCoeff --- fem/coefficient.cpp | 19 ++- fem/coefficient.hpp | 20 +++- tests/unit/fem/test_quadf_coef.cpp | 180 +++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 tests/unit/fem/test_quadf_coef.cpp diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 6b3091997b..dafe7b7ea9 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -778,10 +778,10 @@ void QuadratureVectorFunctionCoefficient::SetQuadratureFunction( void QuadratureVectorFunctionCoefficient::SetLength(int _length) { - MFEM_ASSERT(_length > 0, "Length must be > 0"); + MFEM_VERIFY(_length > 0, "Length must be > 0"); int diff = vdim - index; - MFEM_ASSERT(_length <= diff, + MFEM_VERIFY(_length <= diff, "Length must be <= (QuadratureFunction length - index)"); length = _length; @@ -789,16 +789,22 @@ void QuadratureVectorFunctionCoefficient::SetLength(int _length) void QuadratureVectorFunctionCoefficient::SetIndex(int _index) { - MFEM_ASSERT(_index >= 0, "Index must be >= 0"); - MFEM_ASSERT(_index < vdim, + MFEM_VERIFY(_index >= 0, "Index must be >= 0"); + MFEM_VERIFY(_index < vdim, "Index must be < the QuadratureFunction length"); index = _index; + // check to see if length needs to be modified + int diff = vdim - index; + if (length > diff) { + length = diff; + } } void QuadratureVectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { + QuadF->HostRead(); int elem_no = T.ElementNo; if (index == 0 && length == vdim) { @@ -819,14 +825,14 @@ void QuadratureVectorFunctionCoefficient::Eval(Vector &V, QuadratureFunctionCoefficient::QuadratureFunctionCoefficient( QuadratureFunction *qf) { - MFEM_ASSERT(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); + MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); QuadF = qf; } void QuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) { - MFEM_ASSERT(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); + MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); QuadF = qf; } @@ -834,6 +840,7 @@ void QuadratureFunctionCoefficient::SetQuadratureFunction( double QuadratureFunctionCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) { + QuadF->HostRead(); int elem_no = T.ElementNo; Vector temp(1); QuadF->GetElementValues(elem_no, ip.index, temp); diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 53d9541f25..2e29473723 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -957,17 +957,27 @@ private: int length; public: - // constructor with a quadrature function as input + /// constructor with a quadrature function as input QuadratureVectorFunctionCoefficient(QuadratureFunction *qf); - // constructor with a null qf + /// constructor with a null qf QuadratureVectorFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } + /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); - + + /// set the starting index within the QuadFunc that'll be used to project outwards + /// if length is set to a value which will go out of bounds after this is changed than + /// it will be changed so that things still work. You should always change length right + /// after this is changed. void SetIndex(int _index); + + /// set the length of the function that you want to project + /// the projected length should have the bounds of 1 <= len <= (length QuadFunc - index) + /// where index is the starting location within the QuadFunc that you want projected void SetLength(int _length); + /// getter function for the internal quadrature function QuadratureFunction *GetQuadFunction() const { return QuadF; } using VectorCoefficient::Eval; @@ -985,12 +995,16 @@ private: QuadratureFunction *QuadF; public: + /// constructor with a quadrature function as input QuadratureFunctionCoefficient(QuadratureFunction *qf); + /// constructor with a null qf QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } + /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); + /// getter function for the internal quadrature function QuadratureFunction *GetQuadFunction() const { return QuadF; } virtual double Eval(ElementTransformation &T, diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp new file mode 100644 index 0000000000..e34a66cc4d --- /dev/null +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -0,0 +1,180 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "mfem.hpp" +#include "catch.hpp" + +#ifdef MFEM_USE_EXCEPTIONS + +using namespace mfem; + +namespace qf_coeff +{ + +TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients]") +{ + int order_h1 = 1, n = 3, dim = 3; + double tol = 1e-9; + + Mesh mesh(n, n, n, Element::HEXAHEDRON, false, 1.0, 1.0, 1.0); + + int intOrder = 2 * order_h1 + 1; + + QuadratureSpace qspace(&mesh, intOrder); + QuadratureFunction quadf_coeff(&qspace, 1); + QuadratureFunction quadf_vcoeff(&qspace, dim); + + { + int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim(); + int vdim = quadf_coeff.GetVDim(); + + for(int i = 0; i < nelems; i++){ + for(int j = 0; j < vdim; j++){ + quadf_coeff((i * vdim) + j) = 1.0; + } + } + } + + { + int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim(); + int vdim = quadf_vcoeff.GetVDim(); + + for(int i = 0; i < nelems; i++){ + for(int j = 0; j < vdim; j++){ + quadf_vcoeff((i * vdim) + j) = j; + } + } + } + + QuadratureFunctionCoefficient qfc(&quadf_coeff); + QuadratureVectorFunctionCoefficient qfvc(&quadf_vcoeff); + + SECTION("Operators on QuadVecFuncCoeff") + { + std::cout << "Testing QuadVecFuncCoeff: " << std::endl; + std::cout << " Setting Index" << std::endl; + REQUIRE_THROWS(qfvc.SetIndex(3)); + REQUIRE_THROWS(qfvc.SetIndex(-1)); + REQUIRE_NOTHROW(qfvc.SetIndex(1)); + qfvc.SetIndex(0); + std::cout << " Setting Length" << std::endl; + REQUIRE_THROWS(qfvc.SetLength(4)); + qfvc.SetIndex(1); + REQUIRE_THROWS(qfvc.SetLength(3)); + REQUIRE_NOTHROW(qfvc.SetLength(2)); + REQUIRE_THROWS(qfvc.SetLength(0)); + qfvc.SetIndex(0); + qfvc.SetLength(3); + + SECTION("Gridfunction L2 tests") + { + L2_FECollection fec_l2(order_h1, dim); + FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); + GridFunction g0(&fespace_l2); + GridFunction gtrue(&fespace_l2); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for(int i = 0; i < vdim; i++) { + for(int j = 0; j < nnodes; j++) { + gtrue((i * nnodes) + j) = i; + } + } + } + + g0 = 0.0; + g0.ProjectDiscCoefficient(qfvc, GridFunction::ARITHMETIC); + gtrue -= g0; + REQUIRE(gtrue.Norml2() < tol); + } + + SECTION("Gridfunction H1 tests") + { + L2_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); + GridFunction g0(&fespace_h1); + GridFunction gtrue(&fespace_h1); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for(int i = 0; i < vdim; i++) { + for(int j = 0; j < nnodes; j++) { + gtrue((i * nnodes) + j) = i; + } + } + } + + g0 = 0.0; + g0.ProjectCoefficient(qfvc); + gtrue -= g0; + REQUIRE(gtrue.Norml2() < tol); + } + } + + SECTION("Operators on QuadFuncCoeff") + { + SECTION("Gridfunction L2 tests") + { + L2_FECollection fec_l2(order_h1, dim); + FiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); + GridFunction g0(&fespace_l2); + GridFunction gtrue(&fespace_l2); + + { + int nnodes = gtrue.Size(); + int vdim = 1; + + for(int i = 0; i < vdim; i++) { + for(int j = 0; j < nnodes; j++) { + gtrue((i * nnodes) + j) = 1.0; + } + } + } + + g0 = 0.0; + g0.ProjectDiscCoefficient(qfc, GridFunction::ARITHMETIC); + gtrue -= g0; + REQUIRE(gtrue.Norml2() < tol); + } + + SECTION("Gridfunction H1 tests") + { + L2_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); + GridFunction g0(&fespace_h1); + GridFunction gtrue(&fespace_h1); + + { + int nnodes = gtrue.Size(); + int vdim = 1; + + for(int i = 0; i < vdim; i++) { + for(int j = 0; j < nnodes; j++) { + gtrue((i * nnodes) + j) = 1.0; + } + } + } + + g0 = 0.0; + g0.ProjectCoefficient(qfc); + gtrue -= g0; + REQUIRE(gtrue.Norml2() < tol); + } + } +} + +} // namespace qf_coeff + +#endif // MFEM_USE_EXCEPTIONS From b6dddeb01e978737ade06e797fd0442493af436d Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 20 Mar 2020 13:59:31 -0700 Subject: [PATCH 112/535] make style --- fem/coefficient.cpp | 3 ++- fem/coefficient.hpp | 4 +-- tests/unit/CMakeLists.txt | 1 + tests/unit/fem/test_quadf_coef.cpp | 39 ++++++++++++++++++++---------- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index dafe7b7ea9..2689c33040 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -795,7 +795,8 @@ void QuadratureVectorFunctionCoefficient::SetIndex(int _index) index = _index; // check to see if length needs to be modified int diff = vdim - index; - if (length > diff) { + if (length > diff) + { length = diff; } } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 2e29473723..5ae5cb2043 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -965,13 +965,13 @@ public: /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); - + /// set the starting index within the QuadFunc that'll be used to project outwards /// if length is set to a value which will go out of bounds after this is changed than /// it will be changed so that things still work. You should always change length right /// after this is changed. void SetIndex(int _index); - + /// set the length of the function that you want to project /// the projected length should have the bounds of 1 <= len <= (length QuadFunc - index) /// where index is the starting location within the QuadFunc that you want projected diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a309825c3f..6ee12ca97f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -47,6 +47,7 @@ set(UNIT_TESTS_SRCS fem/test_operatorjacobismoother.cpp fem/test_pa_coeff.cpp fem/test_pa_kernels.cpp + fem/test_quadf_coef.cpp fem/test_quadraturefunc.cpp miniapps/test_sedov.cpp ) diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index e34a66cc4d..92a527e744 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -19,7 +19,8 @@ using namespace mfem; namespace qf_coeff { -TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients]") +TEST_CASE("Quadrature Function Coefficients", + "[Quadrature Function Coefficients]") { int order_h1 = 1, n = 3, dim = 3; double tol = 1e-9; @@ -36,8 +37,10 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim(); int vdim = quadf_coeff.GetVDim(); - for(int i = 0; i < nelems; i++){ - for(int j = 0; j < vdim; j++){ + for (int i = 0; i < nelems; i++) + { + for (int j = 0; j < vdim; j++) + { quadf_coeff((i * vdim) + j) = 1.0; } } @@ -47,8 +50,10 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim(); int vdim = quadf_vcoeff.GetVDim(); - for(int i = 0; i < nelems; i++){ - for(int j = 0; j < vdim; j++){ + for (int i = 0; i < nelems; i++) + { + for (int j = 0; j < vdim; j++) + { quadf_vcoeff((i * vdim) + j) = j; } } @@ -85,8 +90,10 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients int nnodes = gtrue.Size() / dim; int vdim = dim; - for(int i = 0; i < vdim; i++) { - for(int j = 0; j < nnodes; j++) { + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { gtrue((i * nnodes) + j) = i; } } @@ -109,8 +116,10 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients int nnodes = gtrue.Size() / dim; int vdim = dim; - for(int i = 0; i < vdim; i++) { - for(int j = 0; j < nnodes; j++) { + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { gtrue((i * nnodes) + j) = i; } } @@ -136,8 +145,10 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients int nnodes = gtrue.Size(); int vdim = 1; - for(int i = 0; i < vdim; i++) { - for(int j = 0; j < nnodes; j++) { + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { gtrue((i * nnodes) + j) = 1.0; } } @@ -160,8 +171,10 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients int nnodes = gtrue.Size(); int vdim = 1; - for(int i = 0; i < vdim; i++) { - for(int j = 0; j < nnodes; j++) { + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { gtrue((i * nnodes) + j) = 1.0; } } From 5d7811a854106bc8434559acf849d413db0d4a8c Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 24 Mar 2020 07:53:09 -0700 Subject: [PATCH 113/535] minor --- fem/gslib.cpp | 9 +++------ fem/tmop_tools.cpp | 1 - fem/tmop_tools.hpp | 5 ++--- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 56cb66a405..3ba8ec9add 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -68,10 +68,7 @@ void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max) dim = mesh->Dimension(); const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0); unsigned dof1D = fe->GetOrder() + 1; - int NE = mesh->GetNE(), - dof_cnt = fe->GetDof(), - pts_cnt = NE * dof_cnt, - gt = fe->GetGeomType(); + const int gt = fe->GetGeomType(); if (gt == Geometry::TRIANGLE || gt == Geometry::TETRAHEDRON || gt == Geometry::PRISM) @@ -87,8 +84,8 @@ void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max) MFEM_ABORT("Element type not currently supported in FindPointsGSLIB."); } - pts_cnt = gsl_mesh.Size()/dim; - int NEtot = pts_cnt/(int)pow(dof1D, dim); + const int pts_cnt = gsl_mesh.Size()/dim, + NEtot = pts_cnt/(int)pow(dof1D, dim); if (dim == 2) { diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 4cf579ca74..e6b340d34e 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -42,7 +42,6 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, } // This function will not work for AMR meshes in the current state. - // The two lines below are optional. field0 = new_field; nodes0 = new_nodes; } diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index 18f02c26fd..64eebe1055 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -28,6 +28,8 @@ private: Vector nodes0; Vector field0; + virtual void ComputeAtNewPositionScalar(const Vector &new_nodes, + Vector &new_field); public: AdvectorCG() : AdaptivityEvaluator(), ode_solver(), nodes0(), field0() { } @@ -36,9 +38,6 @@ public: virtual void ComputeAtNewPosition(const Vector &new_nodes, Vector &new_field); - - virtual void ComputeAtNewPositionScalar(const Vector &new_nodes, - Vector &new_field); }; #ifdef MFEM_USE_GSLIB From b608ffafd6c07dbebaba297946fb628398fbbf19 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 24 Mar 2020 13:09:00 -0700 Subject: [PATCH 114/535] Rename QuadratureVectorFunctionCoefficient to VectorQuadratureFunctionCoefficient --- fem/coefficient.cpp | 10 +++++----- fem/coefficient.hpp | 10 +++++----- tests/unit/fem/test_quadf_coef.cpp | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 2689c33040..4e56732601 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -758,7 +758,7 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, } #endif -QuadratureVectorFunctionCoefficient::QuadratureVectorFunctionCoefficient( +VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient( QuadratureFunction *qf) : VectorCoefficient(qf->GetVDim()) { @@ -767,7 +767,7 @@ QuadratureVectorFunctionCoefficient::QuadratureVectorFunctionCoefficient( length = qf->GetVDim(); } -void QuadratureVectorFunctionCoefficient::SetQuadratureFunction( +void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) { index = 0; @@ -776,7 +776,7 @@ void QuadratureVectorFunctionCoefficient::SetQuadratureFunction( QuadF = qf; } -void QuadratureVectorFunctionCoefficient::SetLength(int _length) +void VectorQuadratureFunctionCoefficient::SetLength(int _length) { MFEM_VERIFY(_length > 0, "Length must be > 0"); @@ -787,7 +787,7 @@ void QuadratureVectorFunctionCoefficient::SetLength(int _length) length = _length; } -void QuadratureVectorFunctionCoefficient::SetIndex(int _index) +void VectorQuadratureFunctionCoefficient::SetIndex(int _index) { MFEM_VERIFY(_index >= 0, "Index must be >= 0"); MFEM_VERIFY(_index < vdim, @@ -801,7 +801,7 @@ void QuadratureVectorFunctionCoefficient::SetIndex(int _index) } } -void QuadratureVectorFunctionCoefficient::Eval(Vector &V, +void VectorQuadratureFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 5ae5cb2043..4ca0a4e347 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -949,19 +949,19 @@ public: class QuadratureFunction; /// Quadrature function vector coefficient -class QuadratureVectorFunctionCoefficient : public VectorCoefficient +class VectorQuadratureFunctionCoefficient : public VectorCoefficient { private: - QuadratureFunction *QuadF; + QuadratureFunction *QuadF; //do not own int index; int length; public: /// constructor with a quadrature function as input - QuadratureVectorFunctionCoefficient(QuadratureFunction *qf); + VectorQuadratureFunctionCoefficient(QuadratureFunction *qf); /// constructor with a null qf - QuadratureVectorFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } + VectorQuadratureFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); @@ -984,7 +984,7 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - virtual ~QuadratureVectorFunctionCoefficient() { }; + virtual ~VectorQuadratureFunctionCoefficient() { }; }; /// Generic quadrature function coefficient class for using diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 92a527e744..3477a95317 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -60,11 +60,11 @@ TEST_CASE("Quadrature Function Coefficients", } QuadratureFunctionCoefficient qfc(&quadf_coeff); - QuadratureVectorFunctionCoefficient qfvc(&quadf_vcoeff); + VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); - SECTION("Operators on QuadVecFuncCoeff") + SECTION("Operators on VecQuadFuncCoeff") { - std::cout << "Testing QuadVecFuncCoeff: " << std::endl; + std::cout << "Testing VecQuadFuncCoeff: " << std::endl; std::cout << " Setting Index" << std::endl; REQUIRE_THROWS(qfvc.SetIndex(3)); REQUIRE_THROWS(qfvc.SetIndex(-1)); From d4d2c96646c54906f8b54485e8cd7cc70df917e2 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 24 Mar 2020 13:20:19 -0700 Subject: [PATCH 115/535] unit test fixes --- tests/unit/fem/test_quadf_coef.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 3477a95317..47581ee681 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -12,8 +12,6 @@ #include "mfem.hpp" #include "catch.hpp" -#ifdef MFEM_USE_EXCEPTIONS - using namespace mfem; namespace qf_coeff @@ -65,6 +63,7 @@ TEST_CASE("Quadrature Function Coefficients", SECTION("Operators on VecQuadFuncCoeff") { std::cout << "Testing VecQuadFuncCoeff: " << std::endl; +#ifdef MFEM_USE_EXCEPTIONS std::cout << " Setting Index" << std::endl; REQUIRE_THROWS(qfvc.SetIndex(3)); REQUIRE_THROWS(qfvc.SetIndex(-1)); @@ -76,11 +75,13 @@ TEST_CASE("Quadrature Function Coefficients", REQUIRE_THROWS(qfvc.SetLength(3)); REQUIRE_NOTHROW(qfvc.SetLength(2)); REQUIRE_THROWS(qfvc.SetLength(0)); +#endif qfvc.SetIndex(0); qfvc.SetLength(3); SECTION("Gridfunction L2 tests") { + std::cout << " Testing GridFunc L2 projection" << std::endl; L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); GridFunction g0(&fespace_l2); @@ -107,7 +108,8 @@ TEST_CASE("Quadrature Function Coefficients", SECTION("Gridfunction H1 tests") { - L2_FECollection fec_h1(order_h1, dim); + std::cout << " Testing GridFunc H1 projection" << std::endl; + H1_FECollection fec_h1(order_h1, dim); FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); GridFunction g0(&fespace_h1); GridFunction gtrue(&fespace_h1); @@ -136,6 +138,8 @@ TEST_CASE("Quadrature Function Coefficients", { SECTION("Gridfunction L2 tests") { + std::cout << "Testing QuadFuncCoeff:"; + std::cout << " Testing GridFunc L2 projection" << std::endl; L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); GridFunction g0(&fespace_l2); @@ -162,7 +166,8 @@ TEST_CASE("Quadrature Function Coefficients", SECTION("Gridfunction H1 tests") { - L2_FECollection fec_h1(order_h1, dim); + std::cout << " Testing GridFunc H1 projection" << std::endl; + H1_FECollection fec_h1(order_h1, dim); FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); GridFunction g0(&fespace_h1); GridFunction gtrue(&fespace_h1); @@ -190,4 +195,3 @@ TEST_CASE("Quadrature Function Coefficients", } // namespace qf_coeff -#endif // MFEM_USE_EXCEPTIONS From bf532352500d1ea89a05f1186e38f401080dce3d Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Fri, 27 Mar 2020 02:05:11 -0400 Subject: [PATCH 116/535] Calls Finalize at the end of ParPumiMesh ctor This is to fix the orientation for 2D meshes. --- mesh/pumi.cpp | 5 ++++- mesh/pumi.hpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 38c009bb9f..f47a1d2236 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -267,7 +267,8 @@ Element *ParPumiMesh::ReadElement(apf::MeshEntity* Ent, const int geom, // This function loads a parallel PUMI mesh and returns the parallel MFEM mesh // corresponding to it. -ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh) +ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, + int refine, bool fix_orientation) { // Set the communicator for gtopo gtopo.SetComm(comm); @@ -690,6 +691,8 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh) this->edge_vertex = NULL; own_nodes = 1; } + + Finalize(refine, fix_orientation); } diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 360015b205..2f6eeacf92 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -30,7 +30,6 @@ #include "mesh.hpp" #include "pmesh.hpp" -#include #include #include #include @@ -80,7 +79,8 @@ protected: public: /// Build a parallel MFEM mesh from a parallel PUMI mesh. - ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh); + ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, + int refine = 1, bool fix_orientation = true); /// Transfer field from MFEM mesh to PUMI mesh [Mixed]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, From 8b166f918be21b2e3d99759f1017296af7791c87 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Fri, 27 Mar 2020 11:09:59 -0700 Subject: [PATCH 117/535] misc changes --- fem/gslib.cpp | 6 +- fem/tmop.cpp | 184 ++++++++------------ fem/tmop.hpp | 1 + fem/tmop_tools.cpp | 9 +- miniapps/meshing/mesh-optimizer.cpp | 225 +++++++++--------------- miniapps/meshing/pmesh-optimizer.cpp | 249 ++++++++++----------------- 6 files changed, 252 insertions(+), 422 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 3ba8ec9add..013777c845 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -154,10 +154,8 @@ void FindPointsGSLIB::Interpolate(Array &codes, Vector &field_out) { - H1_FECollection ind_fec(mesh->GetNodalFESpace()->GetFE(0)->GetOrder(), dim); - FiniteElementSpace ind_fes(mesh, &ind_fec); - GridFunction field_in_scalar; - field_in_scalar.SetSpace(&ind_fes); + FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl()); + GridFunction field_in_scalar(&ind_fes); Vector node_vals; const int ncomp = field_in.FESpace()->GetVDim(), diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 86b7f43737..e5b00f0bc8 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -979,26 +979,23 @@ void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) { const int vdim = tspec_.FESpace()->GetVDim(), cnt = tspec_.Size()/vdim; - if (ncomp==0) - { - tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), - tspec_.FESpace()->FEColl(), - 1); - ptspec_fes = tspec_.ParFESpace(); - } - if (ncomp == 0) + ncomp += vdim; + + if (ncomp == vdim) { - ncomp += vdim; + tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), + tspec_.FESpace()->FEColl(), + 1); + ptspec_fes = tspec_.ParFESpace(); tspec = tspec_; + return; } - ncomp += vdim; - //need to append data to tspec + // need to append data to tspec // make a copy of tspec->tspec_temp, increase its size, and // copy data from tspec_temp -> tspec, then add new entries - Vector tspec_temp = tspec; tspec.SetSize(ncomp*cnt); @@ -1049,25 +1046,18 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) const int vdim = tspec_.FESpace()->GetVDim(), cnt = tspec_.Size()/vdim; - if (ncomp == 0) - { - tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), - tspec_.FESpace()->FEColl(), - 1); - // we don't do tspec_.FESpace() here because it can be a vector FESpace - // for 3D cases (e.g., aspect ratio has 3 components in 3D). - } - else - { - MFEM_VERIFY(tspec_fes->GetNDofs() == tspec_.FESpace()->GetNDofs(), - " The FiniteElementSpace should be same for all discrete functions.") - } - ncomp += vdim; if (ncomp == vdim) { + tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), + tspec_.FESpace()->FEColl(), + 1); + // we don't do tspec_.FESpace() here because it can be a vector FESpace + // for 3D cases (e.g., aspect ratio has 3 components in 3D). + tspec = tspec_; + return; } @@ -1155,7 +1145,7 @@ void DiscreteAdaptTC::UpdateTargetSpecificationAtNode(const FiniteElement &el, Array dofs; tspec_fes->GetElementDofs(T.ElementNo, dofs); - const int cnt = tspec.Size()/ncomp; //dofs per scalar-field + const int cnt = tspec.Size()/ncomp; //dofs per scalar-field for (int i = 0; i < ncomp; i++) { @@ -1196,7 +1186,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, ntspec_dofs = ndofs*ncomp; - Vector shape(ndofs), tspec_vals(ntspec_dofs); + Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals, + par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs); + Array dofs; DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim); tspec_fesv->GetElementVDofs(e_id, dofs); @@ -1207,51 +1199,26 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, const IntegrationPoint &ip = ir.IntPoint(i); tspec_fes->GetFE(e_id)->CalcShape(ip, shape); Jtr(i) = Wideal; //Initialize to identity - } - Vector par_vals; - Vector par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs); - - if (sizeidx != -1) //Set size - { - par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs, ndofs); - const double min_size = par_vals.Min(); - MFEM_VERIFY(min_size > 0.0, - "Non-positive size propagated in the target definition."); - - for (int i = 0; i < ir.GetNPoints(); i++) + if (sizeidx != -1) //Set size { - const IntegrationPoint &ip = ir.IntPoint(i); - tspec_fes->GetFE(e_id)->CalcShape(ip, shape); + par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs, ndofs); + const double min_size = par_vals.Min(); + MFEM_VERIFY(min_size > 0.0, + "Non-positive size propagated in the target definition."); const double size = std::max(shape * par_vals, min_size); Jtr(i).Set(std::pow(size, 1.0/dim), Jtr(i)); - } - } //Done size + } //Done size - if (target_type==IDEAL_SHAPE_GIVEN_SIZE) { break; } + if (target_type == IDEAL_SHAPE_GIVEN_SIZE) { continue; } - if (aspectratioidx != -1) //Set aspect ratio - { - if (dim == 2) + if (aspectratioidx != -1) //Set aspect ratio { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - aspectratioidx*ndofs, ndofs); - } - else - { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - aspectratioidx*ndofs, ndofs*3); - par_vals_c1.SetData(par_vals.GetData()); - par_vals_c2.SetData(par_vals.GetData()+ndofs); - par_vals_c3.SetData(par_vals.GetData()+2*ndofs); - } - - for (int i = 0; i < ir.GetNPoints(); i++) - { - const IntegrationPoint &ip = ir.IntPoint(i); - tspec_fes->GetFE(e_id)->CalcShape(ip, shape); if (dim == 2) { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + aspectratioidx*ndofs, ndofs); + const double aspectratio = shape * par_vals; D_rho = 0.; D_rho(0,0) = 1./pow(aspectratio,0.5); @@ -1259,6 +1226,12 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } else { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + aspectratioidx*ndofs, ndofs*3); + par_vals_c1.SetData(par_vals.GetData()); + par_vals_c2.SetData(par_vals.GetData()+ndofs); + par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + const double rho1 = shape * par_vals_c1; const double rho2 = shape * par_vals_c2; const double rho3 = shape * par_vals_c3; @@ -1267,33 +1240,18 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, D_rho(1,1) = pow(rho2,2./3.); D_rho(2,2) = pow(rho3,2./3.); } + DenseMatrix Temp = Jtr(i); Mult(D_rho, Temp, Jtr(i)); - } - } //Done aspect ratio + } //Done aspect ratio - if (skewidx != -1) //Set skew - { - if (dim == 2) + if (skewidx != -1) //Set skew { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - skewidx*ndofs, ndofs); - } - else - { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - skewidx*ndofs, ndofs*3); - par_vals_c1.SetData(par_vals.GetData()); - par_vals_c2.SetData(par_vals.GetData()+ndofs); - par_vals_c3.SetData(par_vals.GetData()+2*ndofs); - } - - for (int i = 0; i < ir.GetNPoints(); i++) - { - const IntegrationPoint &ip = ir.IntPoint(i); - tspec_fes->GetFE(e_id)->CalcShape(ip, shape); if (dim == 2) { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + skewidx*ndofs, ndofs); + const double skew = shape * par_vals; Q_phi = 0.; @@ -1303,6 +1261,12 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } else { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + skewidx*ndofs, ndofs*3); + par_vals_c1.SetData(par_vals.GetData()); + par_vals_c2.SetData(par_vals.GetData()+ndofs); + par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + const double phi12 = shape * par_vals_c1; const double phi13 = shape * par_vals_c2; const double chi = shape * par_vals_c3; @@ -1320,31 +1284,15 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, DenseMatrix Temp = Jtr(i); Mult(Q_phi, Temp, Jtr(i)); - } - } // done skew + } // done skew - if (orientationidx != -1) //Set orientation - { - if (dim == 2) + if (orientationidx != -1) //Set orientation { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - orientationidx*ndofs, ndofs); - } - else - { - par_vals.SetDataAndSize(tspec_vals.GetData()+ - orientationidx*ndofs, ndofs*3); - par_vals_c1.SetData(par_vals.GetData()); - par_vals_c2.SetData(par_vals.GetData()+ndofs); - par_vals_c3.SetData(par_vals.GetData()+2*ndofs); - } - - for (int i = 0; i < ir.GetNPoints(); i++) - { - const IntegrationPoint &ip = ir.IntPoint(i); - tspec_fes->GetFE(e_id)->CalcShape(ip, shape); if (dim == 2) { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + orientationidx*ndofs, ndofs); + const double theta = shape * par_vals; R_theta(0,0) = cos(theta); R_theta(0,1) = -sin(theta); @@ -1353,6 +1301,12 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } else { + par_vals.SetDataAndSize(tspec_vals.GetData()+ + orientationidx*ndofs, ndofs*3); + par_vals_c1.SetData(par_vals.GetData()); + par_vals_c2.SetData(par_vals.GetData()+ndofs); + par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + const double theta = shape * par_vals_c1; const double psi = shape * par_vals_c2; const double beta = shape * par_vals_c3; @@ -1383,8 +1337,8 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } DenseMatrix Temp = Jtr(i); Mult(R_theta, Temp, Jtr(i)); - } - } // done orientation + } // done orientation + } break; } default: @@ -1395,14 +1349,13 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x, const double dx) { - const int dim = tspec_fes->GetFE(0)->GetDim(); - const int cnt = x.Size()/dim; + const int dim = tspec_fes->GetFE(0)->GetDim(), + cnt = x.Size()/dim; tspec_perth.SetSize(x.Size()*ncomp); - Vector TSpecTemp; - TSpecTemp.SetSize(ncomp*cnt); - Vector xtemp = x; + Vector TSpecTemp(ncomp*cnt); + Vector xtemp(x.GetData(), x.Size()); for (int j = 0; j < dim; j++) { for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) += dx; } @@ -1423,9 +1376,8 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, tspec_pert2h.SetSize(cnt*dim*ncomp); tspec_pertmix.SetSize(cnt*totmix*ncomp); - Vector TSpecTemp; - TSpecTemp.SetSize(cnt*ncomp); - Vector xtemp = x; + Vector TSpecTemp(cnt*ncomp); + Vector xtemp(x.GetData(), x.Size()); // T(x+2h) for (int j = 0; j < dim; j++) diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 80ef96b01c..c28559f3bd 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -746,6 +746,7 @@ public: virtual ~DiscreteAdaptTC() { delete adapt_eval; + delete tspec_fes; delete tspec_fesv; } diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index a0aa3d0953..1f732ae193 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -50,10 +50,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, Vector &new_field) { Mesh *m = mesh; - #ifdef MFEM_USE_MPI - int myid = 0; - if (pfes) { MPI_Comm_rank(pfes->GetComm(), &myid); } if (pmesh) { m = pmesh; } #endif @@ -103,7 +100,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, } double v_max = 0.0, v_max_glob = 0.0; const int dim = fes->GetFE(0)->GetDim(), - s = new_field.Size() ; + s = new_field.Size() ; for (int i = 0; i < s; i++) { @@ -135,8 +132,8 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, } v_max = std::sqrt(v_max); - double dt = 0.5 * min_h / v_max; - double glob_dt = dt; + double dt = 0.5 * min_h / v_max, + glob_dt = dt; #ifdef MFEM_USE_MPI if (pfes) { diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 4aa7a7bfa8..c8b3c6353c 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -73,84 +73,19 @@ using namespace std; double weight_fun(const Vector &x); void DiffuseField(GridFunction &field, int smooth_steps); -double ind_values(const Vector &x) +double discrete_size_2d(const Vector &x) { - const int opt = 6; + int opt = 2; const double small = 0.001, big = 0.01; double val = 0.; - // Sine wave. - if (opt == 1) + if (opt == 1) // sine wave. { const double X = x(0), Y = x(1); val = std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) + 1) - std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) - 1); } - else if (opt == 2) - { - // Circle in the middle. - const double xc = x(0) - 0.5, yc = x(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.15; double r2 = 0.35; double sf=30.0; - val = 0.5*(std::tanh(sf*(r-r1)) - std::tanh(sf*(r-r2))); - } - else if (opt == 3) - { - // cross - const double X = x(0), Y = x(1); - const double r1 = 0.45, r2 = 0.55; - const double sf = 40.0; - - val = 0.5 * (std::tanh(sf*(X-r1)) - std::tanh(sf*(X-r2)) + - std::tanh(sf*(Y-r1)) - std::tanh(sf*(Y-r2))); - } - else if (opt == 4) - { - // Multiple circles - double r1,r2,val,rval; - double sf = 10; - val = 0.; - // circle 1 - r1= 0.25; r2 = 0.25; rval = 0.1; - double xc = x(0) - r1, yc = x(1) - r2; - double r = sqrt(xc*xc+yc*yc); - val = 0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval))); // std::exp(val1); - // circle 2 - r1= 0.75; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += (0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval)))); // std::exp(val1); - // circle 3 - r1= 0.75; r2 = 0.25; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval))); // std::exp(val1); - // circle 4 - r1= 0.25; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval))); - } - else if (opt == 5) - { - // cross - double X = x(0)-0.5, Y = x(1)-0.5; - double rval = std::sqrt(X*X + Y*Y); - double thval = 60.*M_PI/180.; - double Xmod,Ymod; - Xmod = X*std::cos(thval) + Y*std::sin(thval); - Ymod= -X*std::sin(thval) + Y*std::cos(thval); - X = Xmod+0.5; Y = Ymod+0.5; - double r1 = 0.45; double r2 = 0.55; double sf=30.0; - val = (0.5*(1+std::tanh(sf*(X-r1))) - 0.5*(1+std::tanh(sf*(X-r2))) + - 0.5*(1+std::tanh(sf*(Y-r1))) - 0.5*(1+std::tanh(sf*(Y-r2)))); - if (rval > 0.4) { val = 0.; } - } - else if (opt == 6) + else if (opt == 2) // semi-circle { const double xc = x(0) - 0.0, yc = x(1) - 0.5; const double r = sqrt(xc*xc + yc*yc); @@ -164,7 +99,7 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } -double discr_values(const Vector &x) +double material_indicator_2d(const Vector &x) { double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; @@ -182,12 +117,12 @@ double discr_values(const Vector &x) return wgt; } -double ori_values_2d(const Vector &x) +double discrete_ori_2d(const Vector &x) { return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } -double aspr_values_2d(const Vector &x) +double discrete_aspr_2d(const Vector &x) { double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; @@ -195,7 +130,7 @@ double aspr_values_2d(const Vector &x) double yn = -sin(th)*xc + cos(th)*yc; double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; + xc = xn; yc = yn; double tfac = 20; double s1 = 3; @@ -207,7 +142,7 @@ double aspr_values_2d(const Vector &x) return 0.1 + 1*(1-wgt)*(1-wgt); } -void aspr_values_3d(const Vector &x, Vector &v) +void discrete_aspr_3d(const Vector &x, Vector &v) { int dim = x.Size(); v.SetSize(dim); @@ -262,16 +197,13 @@ public: K *= alpha_bar; } - else if (metric == 87) // Shape + Size + Alignment + else if (metric == 87) // Shape + Alignment { Vector x = pos; double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; double xn = cos(th)*xc + sin(th)*yc; double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; xc = xn; yc=yn; double tfac = 20; @@ -327,6 +259,7 @@ int main(int argc, char *argv[]) bool visualization = true; int verbosity_level = 0; int fdscheme = 0; + int adapt_eval = 0; // 1. Parse command-line options. OptionsParser args(argc, argv); @@ -398,6 +331,8 @@ int main(int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); + args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluatior", + "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) { @@ -539,14 +474,14 @@ int main(int argc, char *argv[]) H1_FECollection ind_fec(mesh_poly_deg, dim); FiniteElementSpace ind_fes(mesh, &ind_fec); FiniteElementSpace ind_fesv(mesh, &ind_fec, dim); - GridFunction size, aspr, disc, ori; - GridFunction aspr3d; + GridFunction size(&ind_fes), aspr(&ind_fes), disc(&ind_fes), ori(&ind_fes); + GridFunction aspr3d(&ind_fesv), size3d(&ind_fesv); switch (target_id) { case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break; case 2: target_t = TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE; break; case 3: target_t = TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE; break; - case 4: + case 4: // Analytic { target_t = TargetConstructor::GIVEN_FULL; AnalyticAdaptTC *tc = new AnalyticAdaptTC(target_t); @@ -555,76 +490,45 @@ int main(int argc, char *argv[]) target_c = tc; break; } - case 5: + case 5: // Discrete size 2D { target_t = TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #endif - size.SetSpace(&ind_fes); - FunctionCoefficient ind_coeff(ind_values); + } + FunctionCoefficient ind_coeff(discrete_size_2d); size.ProjectCoefficient(ind_coeff); tc->SetSerialDiscreteTargetSize(size); tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; break; } - case 60: + case 6: // Discrete size + aspect ratio - 2D { - target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; - DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); -#ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); -#endif - - ori.SetSpace(&ind_fes); - FunctionCoefficient ori_coeff(ori_values_2d); - ori.ProjectCoefficient(ori_coeff); - - if (metric_id == 14) - { - size.SetSpace(&ind_fes); - ConstantCoefficient ind_coeff(0.1*0.1); - size.ProjectCoefficient(ind_coeff); - tc->SetSerialDiscreteTargetSize(size); - } - - if (metric_id == 87) - { - aspr.SetSpace(&ind_fes); - FunctionCoefficient aspr_coeff(aspr_values_2d); - aspr.ProjectCoefficient(aspr_coeff); - tc->SetSerialDiscreteTargetAspectRatio(aspr); - } - - tc->SetSerialDiscreteTargetOrientation(ori); - tc->FinalizeSerialDiscreteTargetSpec(); - target_c = tc; - break; - } - case 6: - { - GridFunction d_x, d_y; - d_x.SetSpace(&ind_fes); - d_y.SetSpace(&ind_fes); - size.SetSpace(&ind_fes); - aspr.SetSpace(&ind_fes); - disc.SetSpace(&ind_fes); + GridFunction d_x(&ind_fes), d_y(&ind_fes); target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); - FunctionCoefficient ind_coeff(discr_values); + FunctionCoefficient ind_coeff(material_indicator_2d); disc.ProjectCoefficient(ind_coeff); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #endif + } //Diffuse the interface DiffuseField(disc,2); @@ -702,17 +606,21 @@ int main(int argc, char *argv[]) target_c = tc; break; } - case 7: + case 7: // Discrete aspect ratio 3D { target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #endif - VectorFunctionCoefficient fd_aspr3d(dim, aspr_values_3d); - aspr3d.SetSpace(&ind_fesv); + } + VectorFunctionCoefficient fd_aspr3d(dim, discrete_aspr_3d); aspr3d.ProjectCoefficient(fd_aspr3d); tc->SetSerialDiscreteTargetAspectRatio(aspr3d); @@ -720,6 +628,43 @@ int main(int argc, char *argv[]) target_c = tc; break; } + case 8: // shape/size + orientation 2D + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#endif + } + + if (metric_id == 14) + { + ConstantCoefficient ind_coeff(0.1*0.1); + size.ProjectCoefficient(ind_coeff); + tc->SetSerialDiscreteTargetSize(size); + } + + if (metric_id == 87) + { + FunctionCoefficient aspr_coeff(discrete_aspr_2d); + aspr.ProjectCoefficient(aspr_coeff); + DiffuseField(aspr,2); + tc->SetSerialDiscreteTargetAspectRatio(aspr); + } + + FunctionCoefficient ori_coeff(discrete_ori_2d); + ori.ProjectCoefficient(ori_coeff); + tc->SetSerialDiscreteTargetOrientation(ori); + tc->FinalizeSerialDiscreteTargetSpec(); + target_c = tc; + break; + } default: cout << "Unknown target_id: " << target_id << endl; return 3; } if (target_c == NULL) @@ -778,6 +723,7 @@ int main(int argc, char *argv[]) he_nlf_integ->SetCoefficient(*coeff1); a.AddDomainIntegrator(he_nlf_integ); + // Second metric. metric2 = new TMOP_Metric_077; target_c2 = new TargetConstructor( TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE); @@ -989,6 +935,7 @@ int main(int argc, char *argv[]) delete metric2; delete coeff1; delete target_c; + delete adapt_coeff; delete metric; delete fespace; delete fec; diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index e7dfbb3d37..faeab59921 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -71,84 +71,19 @@ using namespace std; double weight_fun(const Vector &x); void DiffuseField(ParGridFunction &field, int smooth_steps); -double ind_values(const Vector &x) +double discrete_size_2d(const Vector &x) { - const int opt = 6; + int opt = 2; const double small = 0.001, big = 0.01; double val = 0.; - // Sine wave. - if (opt == 1) + if (opt == 1) // sine wave { const double X = x(0), Y = x(1); val = std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) + 1) - std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) - 1); } - else if (opt == 2) - { - // Circle in the middle. - const double xc = x(0) - 0.5, yc = x(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.15; double r2 = 0.35; double sf=30.0; - val = 0.5*(std::tanh(sf*(r-r1)) - std::tanh(sf*(r-r2))); - } - else if (opt == 3) - { - // cross - const double X = x(0), Y = x(1); - const double r1 = 0.45, r2 = 0.55; - const double sf = 40.0; - - val = 0.5 * (std::tanh(sf*(X-r1)) - std::tanh(sf*(X-r2)) + - std::tanh(sf*(Y-r1)) - std::tanh(sf*(Y-r2))); - } - else if (opt == 4) - { - // Multiple circles - double r1,r2,val,rval; - double sf = 10; - val = 0.; - // circle 1 - r1= 0.25; r2 = 0.25; rval = 0.1; - double xc = x(0) - r1, yc = x(1) - r2; - double r = sqrt(xc*xc+yc*yc); - val = 0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval))); // std::exp(val1); - // circle 2 - r1= 0.75; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += (0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval)))); // std::exp(val1); - // circle 3 - r1= 0.75; r2 = 0.25; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval))); // std::exp(val1); - // circle 4 - r1= 0.25; r2 = 0.75; - xc = x(0) - r1, yc = x(1) - r2; - r = sqrt(xc*xc+yc*yc); - val += 0.5*(1+std::tanh(sf*(r+rval))) - - 0.5*(1+std::tanh(sf*(r-rval))); - } - else if (opt == 5) - { - // cross - double X = x(0)-0.5, Y = x(1)-0.5; - double rval = std::sqrt(X*X + Y*Y); - double thval = 60.*M_PI/180.; - double Xmod,Ymod; - Xmod = X*std::cos(thval) + Y*std::sin(thval); - Ymod= -X*std::sin(thval) + Y*std::cos(thval); - X = Xmod+0.5; Y = Ymod+0.5; - double r1 = 0.45; double r2 = 0.55; double sf=30.0; - val = (0.5*(1+std::tanh(sf*(X-r1))) - 0.5*(1+std::tanh(sf*(X-r2))) + - 0.5*(1+std::tanh(sf*(Y-r1))) - 0.5*(1+std::tanh(sf*(Y-r2)))); - if (rval > 0.4) { val = 0.; } - } - else if (opt == 6) + else if (opt == 2) // semi-circle { const double xc = x(0) - 0.0, yc = x(1) - 0.5; const double r = sqrt(xc*xc + yc*yc); @@ -162,7 +97,7 @@ double ind_values(const Vector &x) return val * small + (1.0 - val) * big; } -double disc_values(const Vector &x) +double material_indicator_2d(const Vector &x) { double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; @@ -175,42 +110,35 @@ double disc_values(const Vector &x) double s1 = 3; double s2 = 3; double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } + wgt = std::max(0., wgt); + wgt = std::min(1., wgt); return wgt; } -double ori_values(const Vector &x) +double discrete_ori_2d(const Vector &x) { return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); } -double ori_values_2d(const Vector &x) -{ - return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); -} - -double aspr_values_2d(const Vector &x) +double discrete_aspr_2d(const Vector &x) { double xc = x(0)-0.5, yc = x(1)-0.5; double th = 22.5*M_PI/180.; double xn = cos(th)*xc + sin(th)*yc; double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; + xc = xn; yc = yn; double tfac = 20; double s1 = 3; double s2 = 2; double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } + wgt = std::max(0., wgt); + wgt = std::min(1., wgt); return 0.1 + 1*(1-wgt)*(1-wgt); } -void aspr_values_3d(const Vector &x, Vector &v) +void discrete_aspr_3d(const Vector &x, Vector &v) { int dim = x.Size(); v.SetSize(dim); @@ -268,22 +196,17 @@ public: else if (metric == 87) // Shape + Size + Alignment { Vector x = pos; - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; + double xc = x(0)-0.5, yc = x(1)-0.5, + th = 22.5*M_PI/180.; double xn = cos(th)*xc + sin(th)*yc; double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; xc = xn; yc=yn; - double tfac = 20; - double s1 = 3; - double s2 = 2; + double tfac = 20, s1 = 3, s2 = 2; double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } + wgt = std::max(0., wgt); + wgt = std::min(1., wgt); xc = pos(0), yc = pos(1); double theta = M_PI * (yc) * (1.0 - yc) * cos(2 * M_PI * xc); @@ -337,6 +260,7 @@ int main (int argc, char *argv[]) bool visualization = true; int verbosity_level = 0; int fdscheme = 0; + int adapt_eval = 0; // 2. Parse command-line options. OptionsParser args(argc, argv); @@ -409,6 +333,8 @@ int main (int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); + args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluatior", + "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) { @@ -571,9 +497,9 @@ int main (int argc, char *argv[]) HessianCoefficient *adapt_coeff = NULL; H1_FECollection ind_fec(mesh_poly_deg, dim); ParFiniteElementSpace ind_fes(pmesh, &ind_fec); - ParGridFunction size, aspr, disc, ori; ParFiniteElementSpace ind_fesv(pmesh, &ind_fec, dim); - ParGridFunction aspr3d; + ParGridFunction size(&ind_fes), aspr(&ind_fes), disc(&ind_fes), ori(&ind_fes); + ParGridFunction aspr3d(&ind_fesv), size3d(&ind_fesv); switch (target_id) { @@ -593,73 +519,41 @@ int main (int argc, char *argv[]) { target_t = TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); - size.SetSpace(&ind_fes); - FunctionCoefficient ind_coeff(ind_values); - size.ProjectCoefficient(ind_coeff); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #endif + } + FunctionCoefficient ind_coeff(discrete_size_2d); + size.ProjectCoefficient(ind_coeff); tc->SetParDiscreteTargetSize(size); tc->FinalizeParDiscreteTargetSpec(); target_c = tc; break; } - case 60: + case 6: //material indicator 2D { - target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; - DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); -#ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); -#endif - - ori.SetSpace(&ind_fes); - FunctionCoefficient ori_coeff(ori_values_2d); - ori.ProjectCoefficient(ori_coeff); - - if (metric_id == 14) - { - size.SetSpace(&ind_fes); - ConstantCoefficient ind_coeff(0.1*0.1); - size.ProjectCoefficient(ind_coeff); - tc->SetParDiscreteTargetSize(size); - } - - if (metric_id == 87) - { - aspr.SetSpace(&ind_fes); - FunctionCoefficient aspr_coeff(aspr_values_2d); - aspr.ProjectCoefficient(aspr_coeff); - tc->SetParDiscreteTargetAspectRatio(aspr); - } - - tc->SetParDiscreteTargetOrientation(ori); - tc->FinalizeParDiscreteTargetSpec(); - target_c = tc; - break; - } - case 6: - { - ParGridFunction d_x, d_y; - d_x.SetSpace(&ind_fes); - d_y.SetSpace(&ind_fes); - size.SetSpace(&ind_fes); - aspr.SetSpace(&ind_fes); - disc.SetSpace(&ind_fes); + ParGridFunction d_x(&ind_fes), d_y(&ind_fes); target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); - FunctionCoefficient ind_coeff(disc_values); + FunctionCoefficient ind_coeff(material_indicator_2d); disc.ProjectCoefficient(ind_coeff); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #endif - + } //Diffuse the interface DiffuseField(disc,2); @@ -743,20 +637,61 @@ int main (int argc, char *argv[]) target_c = tc; break; } - case 7: + case 7: // aspect-ratio 3D { target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { #ifdef MFEM_USE_GSLIB - tc->SetAdaptivityEvaluator(new InterpolatorFP); -#else - tc->SetAdaptivityEvaluator(new AdvectorCG); + tc->SetAdaptivityEvaluator(new InterpolatorFP); #endif - VectorFunctionCoefficient fd_aspr3d(dim, aspr_values_3d); - aspr3d.SetSpace(&ind_fesv); + } + VectorFunctionCoefficient fd_aspr3d(dim, discrete_aspr_3d); aspr3d.ProjectCoefficient(fd_aspr3d); - tc->SetParDiscreteTargetAspectRatio(aspr3d); + + tc->FinalizeParDiscreteTargetSpec(); + target_c = tc; + break; + } + case 8: // shape/size + orientation 2D + { + target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE; + DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t); + if (adapt_eval == 0) + { + tc->SetAdaptivityEvaluator(new AdvectorCG); + } + else + { +#ifdef MFEM_USE_GSLIB + tc->SetAdaptivityEvaluator(new InterpolatorFP); +#endif + } + + if (metric_id == 14) + { + ConstantCoefficient ind_coeff(0.1*0.1); + size.ProjectCoefficient(ind_coeff); + tc->SetParDiscreteTargetSize(size); + } + + if (metric_id == 87) + { + FunctionCoefficient aspr_coeff(discrete_aspr_2d); + aspr.ProjectCoefficient(aspr_coeff); + DiffuseField(aspr,2); + tc->SetParDiscreteTargetAspectRatio(aspr); + } + + FunctionCoefficient ori_coeff(discrete_ori_2d); + ori.ProjectCoefficient(ori_coeff); + tc->SetParDiscreteTargetOrientation(ori); tc->FinalizeParDiscreteTargetSpec(); target_c = tc; break; From 80d1533590b4a966758462bf989b0ebd78a2ebbf Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 30 Mar 2020 19:42:08 -0700 Subject: [PATCH 118/535] First draft of Gmsh periodic data parser --- mesh/mesh_readers.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index 703d410ae5..8c0c04154c 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1291,6 +1291,61 @@ void Mesh::ReadGmshMesh(std::istream &input) MFEM_CONTRACT_VAR(elem_domain); } // section '$Elements' + else if (buff == "$Periodic") // reading master/slave node pairs + { + Array v2v(NumOfVertices); + for (int i = 0; i < v2v.Size(); i++) + { + v2v[i] = i; + } + int num_per_ent; + int num_nodes; + int slave, master; + input >> num_per_ent; + getline(input, buff); // Read end-of-line + for (int i = 0; i < num_per_ent; i++) + { + getline(input, buff); // Read entity dimension and tags + cout << i << " \"" << buff << "\"" << endl; + getline(input, buff); // Read affine mapping + cout << i << " \"" << buff << "\"" << endl; + input >> num_nodes; + for (int j=0; j> slave >> master; + v2v[slave - 1] = master - 1; + } + getline(input, buff); // Read end-of-line + } + + // Convert nodes to discontinuous GridFunction + this->SetCurvature(1, true); + + // renumber elements + for (int i = 0; i < this->GetNE(); i++) + { + Element *el = this->GetElement(i); + int *v = el->GetVertices(); + int nv = el->GetNVertices(); + for (int j = 0; j < nv; j++) + { + v[j] = v2v[v[j]]; + } + } + // renumber boundary elements + for (int i = 0; i < this->GetNBE(); i++) + { + Element *el = this->GetBdrElement(i); + int *v = el->GetVertices(); + int nv = el->GetNVertices(); + for (int j = 0; j < nv; j++) + { + v[j] = v2v[v[j]]; + } + } + this->RemoveUnusedVertices(); + this->RemoveInternalBoundaries(); + } } // we reach the end of the file } From b32955bba774d7f27965d21719ede962f2fbbb8e Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 30 Mar 2020 21:16:00 -0700 Subject: [PATCH 119/535] Adding GridFunction coords to ReadGmshMesh --- mesh/mesh.cpp | 2 +- mesh/mesh.hpp | 2 +- mesh/mesh_readers.cpp | 80 ++++++++++++++++++++++--------------------- 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index cef74d7252..c52d8a5d9d 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -3281,7 +3281,7 @@ void Mesh::Loader(std::istream &input, int generate_edges, } else if (mesh_type == "$MeshFormat") // Gmsh { - ReadGmshMesh(input); + ReadGmshMesh(input, curved, read_gf); } else if ((mesh_type.size() > 2 && diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index c67c9982fe..4303776d64 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -235,7 +235,7 @@ protected: bool &finalize_topo); void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf); void ReadInlineMesh(std::istream &input, bool generate_edges = false); - void ReadGmshMesh(std::istream &input); + void ReadGmshMesh(std::istream &input, int &curved, int &read_gf); /* Note NetCDF (optional library) is used for reading cubit files */ #ifdef MFEM_USE_NETCDF void ReadCubit(const char *filename, int &curved, int &read_gf); diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index 8c0c04154c..5a2366ea5e 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -887,7 +887,7 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges) } } -void Mesh::ReadGmshMesh(std::istream &input) +void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) { string buff; double version; @@ -1293,58 +1293,60 @@ void Mesh::ReadGmshMesh(std::istream &input) } // section '$Elements' else if (buff == "$Periodic") // reading master/slave node pairs { + curved = 1; + read_gf = 0; + spaceDim = 3; + Array v2v(NumOfVertices); for (int i = 0; i < v2v.Size(); i++) { v2v[i] = i; } - int num_per_ent; - int num_nodes; - int slave, master; - input >> num_per_ent; - getline(input, buff); // Read end-of-line - for (int i = 0; i < num_per_ent; i++) - { - getline(input, buff); // Read entity dimension and tags - cout << i << " \"" << buff << "\"" << endl; - getline(input, buff); // Read affine mapping - cout << i << " \"" << buff << "\"" << endl; - input >> num_nodes; - for (int j=0; j> slave >> master; - v2v[slave - 1] = master - 1; - } - getline(input, buff); // Read end-of-line - } + int num_per_ent; + int num_nodes; + int slave, master; + input >> num_per_ent; + getline(input, buff); // Read end-of-line + for (int i = 0; i < num_per_ent; i++) + { + getline(input, buff); // Read entity dimension and tags + getline(input, buff); // Read affine mapping + input >> num_nodes; + for (int j=0; j> slave >> master; + v2v[slave - 1] = master - 1; + } + getline(input, buff); // Read end-of-line + } - // Convert nodes to discontinuous GridFunction - this->SetCurvature(1, true); + // Convert nodes to discontinuous GridFunction + this->SetCurvature(1, true, Dim, Ordering::byVDIM); - // renumber elements - for (int i = 0; i < this->GetNE(); i++) - { + // renumber elements + for (int i = 0; i < this->GetNE(); i++) + { Element *el = this->GetElement(i); - int *v = el->GetVertices(); - int nv = el->GetNVertices(); - for (int j = 0; j < nv; j++) + int *v = el->GetVertices(); + int nv = el->GetNVertices(); + for (int j = 0; j < nv; j++) { v[j] = v2v[v[j]]; - } - } - // renumber boundary elements - for (int i = 0; i < this->GetNBE(); i++) + } + } + // renumber boundary elements + for (int i = 0; i < this->GetNBE(); i++) { Element *el = this->GetBdrElement(i); - int *v = el->GetVertices(); - int nv = el->GetNVertices(); - for (int j = 0; j < nv; j++) + int *v = el->GetVertices(); + int nv = el->GetNVertices(); + for (int j = 0; j < nv; j++) { v[j] = v2v[v[j]]; - } - } - this->RemoveUnusedVertices(); - this->RemoveInternalBoundaries(); + } + } + this->RemoveUnusedVertices(); + this->RemoveInternalBoundaries(); } } // we reach the end of the file } From ab2bc2aa508390cdfe6609c084a73787ca389083 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 31 Mar 2020 14:36:08 -0700 Subject: [PATCH 120/535] make style --- fem/tmop_tools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 1d554fee60..e6aaa640e6 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -29,7 +29,7 @@ void AdvectorCG::SetInitialField(const Vector &init_nodes, void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, Vector &new_field) { - // This function will not work for AMR meshes in the current state. + // This function will not work for AMR meshes in the current state. const int dim = fes->GetFE(0)->GetDim(), ncomp = fes->GetVDim(), pnt_cnt = new_nodes.Size()/dim; From efb8627383d96f37f9dfea2b87870da99e4f4de9 Mon Sep 17 00:00:00 2001 From: rcarson3 Date: Wed, 1 Apr 2020 12:46:47 -0700 Subject: [PATCH 121/535] Fix bugs for when vector coeff length isn't equal to quadfunc length for projections --- fem/coefficient.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 4e56732601..a76cad0650 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -780,24 +780,26 @@ void VectorQuadratureFunctionCoefficient::SetLength(int _length) { MFEM_VERIFY(_length > 0, "Length must be > 0"); - int diff = vdim - index; + int diff = QuadF->GetVDim() - index; MFEM_VERIFY(_length <= diff, "Length must be <= (QuadratureFunction length - index)"); length = _length; + vdim = length; } void VectorQuadratureFunctionCoefficient::SetIndex(int _index) { MFEM_VERIFY(_index >= 0, "Index must be >= 0"); - MFEM_VERIFY(_index < vdim, + MFEM_VERIFY(_index < QuadF->GetVDim(), "Index must be < the QuadratureFunction length"); index = _index; // check to see if length needs to be modified - int diff = vdim - index; + int diff = QuadF->GetVDim() - index; if (length > diff) { length = diff; + vdim = length; } } @@ -807,7 +809,7 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, { QuadF->HostRead(); int elem_no = T.ElementNo; - if (index == 0 && length == vdim) + if (index == 0 && length == QuadF->GetVDim()) { QuadF->GetElementValues(elem_no, ip.index, V); } @@ -816,7 +818,7 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, // This will need to be improved upon... Vector temp; QuadF->GetElementValues(elem_no, ip.index, temp); - double *data = temp.GetData(); + double *data = temp.HostReadWrite(); V.NewDataAndSize(data + index, length); } From 9dae5eec55ea32f83335df5bcae12106cf57858c Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Wed, 1 Apr 2020 16:19:44 -0400 Subject: [PATCH 122/535] Cleans the pumi related codes 1- Code repetition for ReadElement was fixed 2- getting nodes associated with an entity is repeated for MFEMToPUMI field transfer routines (one of the is fixed in this commit but not yet tested. Others need to be cleaned up as well. 3- TODO: It's probably possible to have one general field transfer routine as opposed to multiples ones for different fields types. --- mesh/pumi.cpp | 434 ++++++++++++++++++++++---------------------------- mesh/pumi.hpp | 8 +- 2 files changed, 187 insertions(+), 255 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index f47a1d2236..d9598bbb9d 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -33,21 +33,31 @@ using namespace std; namespace mfem { -PumiMesh::PumiMesh(apf::Mesh2* apf_mesh, int generate_edges, int refine, - bool fix_orientation) +static void getPumiNodeXis(apf::FieldShape* fs, + int type, + IntegrationRule& xis) { - Load(apf_mesh, generate_edges, refine, fix_orientation); + apf::NewArray pumiXis; + apf::getElementNodeXis(fs, type, pumiXis); + xis.SetSize(pumiXis.size()); + for (size_t i = 0; i < pumiXis.size(); i++) { + IntegrationPoint& ip = xis.IntPoint(i); + double xi[3]; + pumiXis[i].toArray(xi); + ip.Set(xi, 3); + } } -Element *PumiMesh::ReadElement(apf::MeshEntity* Ent, const int geom, - apf::Downward Verts, - const int Attr, apf::Numbering* vert_num) + +static void ReadPumiElement(apf::MeshEntity* Ent, /* ptr to pumi entity */ + apf::Downward Verts, + const int Attr, apf::Numbering* vert_num, + Element* el /* ptr to mfem entity being created */ + ) { - Element *el; int nv, *v; // Create element in MFEM - el = NewElement(geom); nv = el->GetNVertices(); v = el->GetVertices(); @@ -59,10 +69,16 @@ Element *PumiMesh::ReadElement(apf::MeshEntity* Ent, const int geom, // Assign attribute el->SetAttribute(Attr); - - return el; } +PumiMesh::PumiMesh(apf::Mesh2* apf_mesh, int generate_edges, int refine, + bool fix_orientation) +{ + Load(apf_mesh, generate_edges, refine, fix_orientation); +} + + + void PumiMesh::CountBoundaryEntity(apf::Mesh2* apf_mesh, const int BcDim, int &NumBc) { @@ -185,7 +201,8 @@ void PumiMesh::ReadSCORECMesh(apf::Mesh2* apf_mesh, apf::Numbering* v_num_loc, int attr = 1; int geom_type = apf_mesh->getType(ent); - elements[j] = ReadElement(ent, geom_type, verts, attr, v_num_loc); + elements[j] = NewElement(geom_type); + ReadPumiElement(ent, verts, attr, v_num_loc, elements[j]); j++; } // End iterator @@ -211,7 +228,8 @@ void PumiMesh::ReadSCORECMesh(apf::Mesh2* apf_mesh, apf::Numbering* v_num_loc, apf_mesh->getDownward(ent, 0, verts); int attr = 1; int geom_type = apf_mesh->getType(ent); - boundary[j] = ReadElement( ent, geom_type, verts, attr, v_num_loc); + boundary[j] = NewElement(geom_type); + ReadPumiElement(ent, verts, attr, v_num_loc, boundary[j]); j++; } } @@ -241,30 +259,6 @@ void PumiMesh::ReadSCORECMesh(apf::Mesh2* apf_mesh, apf::Numbering* v_num_loc, } // ParPumiMesh implementation -Element *ParPumiMesh::ReadElement(apf::MeshEntity* Ent, const int geom, - apf::Downward Verts, - const int Attr, apf::Numbering* vert_num) -{ - Element *el; - int nv, *v; - - // Create element in MFEM - el = NewElement(geom); - nv = el->GetNVertices(); - v = el->GetVertices(); - - // Fill the connectivity - for (int i = 0; i < nv; ++i) - { - v[i] = apf::getNumber(vert_num, Verts[i], 0, 0); - } - - // Assign attribute - el->SetAttribute(Attr); - - return el; -} - // This function loads a parallel PUMI mesh and returns the parallel MFEM mesh // corresponding to it. ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, @@ -353,7 +347,8 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, // Get attribute Tag vs Geometry int attr = 1; int geom_type = apf_mesh->getType(ent); - elements[j] = ReadElement(ent, geom_type, verts, attr, v_num_loc); + elements[j] = NewElement(geom_type); + ReadPumiElement(ent, verts, attr, v_num_loc, elements[j]); } // End iterator apf_mesh->end(itr); @@ -385,8 +380,9 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, apf_mesh->getDownward(ent, 0, verts); int attr = 1 ; int geom_type = apf_mesh->getType(ent); - boundary[bdr_ctr++] = ReadElement(ent, geom_type, verts, attr, - v_num_loc); + boundary[bdr_ctr] = NewElement(geom_type); + ReadPumiElement(ent, verts, attr, v_num_loc, boundary[bdr_ctr]); + bdr_ctr++; } } apf_mesh->end(itr); @@ -931,115 +927,20 @@ void ParPumiMesh::UpdateMesh(const ParMesh* AdaptedpMesh) void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* grid_vel, ParGridFunction* grid_pr, - apf::Field* VelField, - apf::Field* PrField, - apf::Field* VelMagField) + apf::Field* vel_field, + apf::Field* pr_field, + apf::Field* vel_mag_field) { - apf::FieldShape* VelFieldShape = getShape(VelField); - int num_nodes = 4 * VelFieldShape->countNodesOn(0) + // Vertex - 6 * VelFieldShape->countNodesOn(1) + // Edge - 4 * VelFieldShape->countNodesOn(2) + // Triangle - VelFieldShape->countNodesOn(4); // Tetrahedron + int dim = apf_mesh->getDimension(); // dimension of mesh + int type = apf::Mesh::simplexTypes[dim]; // highest dim entity simplex type + apf::FieldShape* field_shape = getShape(vel_field); + apf::EntityShape* es = field_shape->getEntityShape(type); - // Define integration points - IntegrationRule pumi_nodes(num_nodes); - int ip_cnt = 0; - apf::Vector3 xi_crd(0.,0.,0.); + IntegrationRule pumi_nodes; + getPumiNodeXis(field_shape, type, pumi_nodes); - // Create a template of dof holders coordinates in parametric coordinates. - // The ordering is taken care of when the field is transferred to PUMI. - - // Dofs on Vertices - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - double pt_crd[3] = {0., 0., 0.}; - ip.Set(pt_crd, 3); - for (int kk = 0; kk < 3; kk++) - { - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - double pt_crd[3] = {0.,0.,0.}; - pt_crd[kk] = 1.0; - ip.Set(pt_crd, 3); - } - // Dofs on Edges - if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE)) - { - const int nn = VelFieldShape->countNodesOn(apf::Mesh::EDGE); - for (int ii = 0; ii < 6; ii++) - { - for (int jj = 0; jj < nn; jj++) - { - VelFieldShape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd); - xi_crd[0] = 0.5 * (xi_crd[0] + 1.);// from (-1,1) to (0,1) - double pt_crd[3] = {0., 0., 0.}; - switch (ii) - { - case 0: - pt_crd[0] = xi_crd[0]; - break; - case 1: - pt_crd[0] = 1. - xi_crd[0]; - pt_crd[1] = xi_crd[0]; - break; - case 2: - pt_crd[1] = xi_crd[0]; - break; - case 3: - pt_crd[2] = xi_crd[0]; - break; - case 4: - pt_crd[0] = 1. - xi_crd[0]; - pt_crd[2] = xi_crd[0]; - break; - case 5: - pt_crd[1] = 1. - xi_crd[0]; - pt_crd[2] = xi_crd[0]; - break; - } - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - ip.Set(pt_crd, 3); - } - } - } - // Dofs on Faces - if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE)) - { - const int nn = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE); - for (int ii = 0; ii < 4; ii++) - { - for (int jj = 0; jj < nn; jj++) - { - VelFieldShape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd); - double pt_crd[3] = {0., 0., 0.}; - switch (ii) - { - case 0: - pt_crd[0] = xi_crd[0]; - pt_crd[1] = xi_crd[1]; - break; - case 1: - pt_crd[0] = xi_crd[0]; - pt_crd[2] = xi_crd[2]; - break; - case 2: - pt_crd[0] = xi_crd[0]; - pt_crd[1] = xi_crd[1]; - pt_crd[2] = xi_crd[2]; - break; - case 3: - pt_crd[1] = xi_crd[0]; - pt_crd[2] = xi_crd[1]; - break; - } - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - ip.Set(pt_crd, 3); - } - } - } - MFEM_ASSERT(ip_cnt == num_nodes, ""); - - // Other dofs apf::MeshEntity* ent; - apf::MeshIterator* itr = apf_mesh->begin(3); + apf::MeshIterator* itr = apf_mesh->begin(dim); int iel = 0; while ((ent = apf_mesh->iterate(itr))) { @@ -1052,98 +953,134 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, Vector pr; grid_pr->GetValues(iel, pumi_nodes, pr, 1); - // Transfer - apf::Downward vtxs; - int num_vts = apf_mesh->getDownward(ent, 0, vtxs); - for (int kk = 0; kk < num_vts; kk++) - { - double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] + - w_vel[kk] * w_vel[kk]; - mag = sqrt(mag); - apf::setScalar(VelMagField, vtxs[kk], 0, mag); - // Set vel - double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]}; - apf::setComponents(VelField, vtxs[kk], 0, vels); + int dof_id = 0; + for (int d = 0; d <= dim; d++) { + int d_type = apf::Mesh::simplexTypes[d]; + if (field_shape->hasNodesIn(d_type)) + { + int non = field_shape->countNodesOn(d_type); + Array order(non); + // initialize to 0 in case alignSharedNodes does not do anything + order = 0; - // Set Pr - apf::setScalar(PrField, vtxs[kk], 0, pr[kk]); + apf::Downward down; + int nd = apf_mesh->getDownward(ent, d_type, down); + for (int ii = 0 ; ii < nd; ++ii) + { + es->alignSharedNodes(apf_mesh, ent, down[ii], order); + for (int jj = 0; jj < non; jj++) + { + int cnt = dof_id + order[jj]; + double mag = u_vel[cnt] * u_vel[cnt] + + v_vel[cnt] * v_vel[cnt] + + w_vel[cnt] * w_vel[cnt]; + mag = sqrt(mag); + apf::setScalar(vel_mag_field, down[ii], jj, mag); + + // Set vel + double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; + apf::setComponents(vel_field, down[ii], jj, vels); + + // Set Pr + apf::setScalar(pr_field, down[ii], jj, pr[cnt]); + + } + // Counter + dof_id += non; + } + } } + /* // Transfer */ + /* apf::Downward vtxs; */ + /* int num_vts = apf_mesh->getDownward(ent, 0, vtxs); */ + /* for (int kk = 0; kk < num_vts; kk++) */ + /* { */ + /* double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] + */ + /* w_vel[kk] * w_vel[kk]; */ + /* mag = sqrt(mag); */ + /* apf::setScalar(vel_mag_field, vtxs[kk], 0, mag); */ + /* // Set vel */ + /* double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]}; */ + /* apf::setComponents(vel_field, vtxs[kk], 0, vels); */ - int dofId = num_vts; + /* // Set Pr */ + /* apf::setScalar(pr_field, vtxs[kk], 0, pr[kk]); */ + /* } */ - apf::EntityShape* es = VelFieldShape->getEntityShape(apf::Mesh::TET); - // Edge Dofs - if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE)) - { - int ndOnEdge = VelFieldShape->countNodesOn(apf::Mesh::EDGE); - Array order(ndOnEdge); + /* int dofId = num_vts; */ - apf::Downward edges; - int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges); - for (int ii = 0 ; ii < num_edge; ++ii) - { - es->alignSharedNodes(apf_mesh, ent, edges[ii], order); - for (int jj = 0; jj < ndOnEdge; jj++) - { - int cnt = dofId + order[jj]; - double mag = u_vel[cnt] * u_vel[cnt] + - v_vel[cnt] * v_vel[cnt] + - w_vel[cnt] * w_vel[cnt]; - mag = sqrt(mag); - apf::setScalar(VelMagField, edges[ii], jj, mag); + /* // Edge Dofs */ + /* if (field_shape->hasNodesIn(apf::Mesh::EDGE)) */ + /* { */ + /* int ndOnEdge = field_shape->countNodesOn(apf::Mesh::EDGE); */ + /* Array order(ndOnEdge); */ - // Set vel - double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(VelField, edges[ii], jj, vels); + /* apf::Downward edges; */ + /* int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges); */ + /* for (int ii = 0 ; ii < num_edge; ++ii) */ + /* { */ + /* es->alignSharedNodes(apf_mesh, ent, edges[ii], order); */ + /* for (int jj = 0; jj < ndOnEdge; jj++) */ + /* { */ + /* int cnt = dofId + order[jj]; */ + /* double mag = u_vel[cnt] * u_vel[cnt] + */ + /* v_vel[cnt] * v_vel[cnt] + */ + /* w_vel[cnt] * w_vel[cnt]; */ + /* mag = sqrt(mag); */ + /* apf::setScalar(vel_mag_field, edges[ii], jj, mag); */ - // Set Pr - apf::setScalar(PrField, edges[ii], jj, pr[cnt]); + /* // Set vel */ + /* double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; */ + /* apf::setComponents(vel_field, edges[ii], jj, vels); */ - } - // Counter - dofId += ndOnEdge; - } - } - // Face Dofs - if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE)) - { - int ndOnFace = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE); - Array order(ndOnFace); + /* // Set Pr */ + /* apf::setScalar(pr_field, edges[ii], jj, pr[cnt]); */ - apf::Downward faces; - int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces); - for (int ii = 0; ii < num_face; ii++) - { - if ( ndOnFace > 1) - { - es->alignSharedNodes(apf_mesh, ent, faces[ii], order); - } - else - { - order[0] = 0; - } - for (int jj = 0; jj < ndOnFace; jj++) - { - int cnt = dofId + order[jj]; - double mag = u_vel[cnt] * u_vel[cnt] + - v_vel[cnt] * v_vel[cnt] + - w_vel[cnt] * w_vel[cnt]; - mag = sqrt(mag); - apf::setScalar(VelMagField, faces[ii], jj, mag); + /* } */ + /* // Counter */ + /* dofId += ndOnEdge; */ + /* } */ + /* } */ + /* // Face Dofs */ + /* if (field_shape->hasNodesIn(apf::Mesh::TRIANGLE)) */ + /* { */ + /* int ndOnFace = field_shape->countNodesOn(apf::Mesh::TRIANGLE); */ + /* Array order(ndOnFace); */ - // Set vel - double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(VelField, faces[ii], jj, vels); + /* apf::Downward faces; */ + /* int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces); */ + /* for (int ii = 0; ii < num_face; ii++) */ + /* { */ + /* if ( ndOnFace > 1) */ + /* { */ + /* es->alignSharedNodes(apf_mesh, ent, faces[ii], order); */ + /* } */ + /* else */ + /* { */ + /* order[0] = 0; */ + /* } */ + /* for (int jj = 0; jj < ndOnFace; jj++) */ + /* { */ + /* int cnt = dofId + order[jj]; */ + /* double mag = u_vel[cnt] * u_vel[cnt] + */ + /* v_vel[cnt] * v_vel[cnt] + */ + /* w_vel[cnt] * w_vel[cnt]; */ + /* mag = sqrt(mag); */ + /* apf::setScalar(vel_mag_field, faces[ii], jj, mag); */ - // Set Pr - apf::setScalar(PrField, faces[ii], jj, pr[cnt]); - } - // Counter - dofId += ndOnFace; - } - } + /* // Set vel */ + /* double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; */ + /* apf::setComponents(vel_field, faces[ii], jj, vels); */ - iel++; + /* // Set Pr */ + /* apf::setScalar(pr_field, faces[ii], jj, pr[cnt]); */ + /* } */ + /* // Counter */ + /* dofId += ndOnFace; */ + /* } */ + /* } */ + + /* iel++; */ } apf_mesh->end(itr); } @@ -1351,14 +1288,15 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, // adaptation void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* grid_vel, - apf::Field* VelField, - apf::Field* VelMagField) + apf::Field* vel_field, + apf::Field* vel_mag_field) { - apf::FieldShape* VelFieldShape = getShape(VelField); - int num_nodes = 4 * VelFieldShape->countNodesOn(0) + // Vertex - 6 * VelFieldShape->countNodesOn(1) + // Edge - 4 * VelFieldShape->countNodesOn(2) + // Triangle - VelFieldShape->countNodesOn(4);// Tetrahedron + apf::FieldShape* field_shape = getShape(vel_field); + + int num_nodes = 4 * field_shape->countNodesOn(0) + // Vertex + 6 * field_shape->countNodesOn(1) + // Edge + 4 * field_shape->countNodesOn(2) + // Triangle + field_shape->countNodesOn(4);// Tetrahedron // Define integration points IntegrationRule pumi_nodes(num_nodes); @@ -1380,14 +1318,14 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ip.Set(pt_crd, 3); } // Dofs on Edges - if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE)) + if (field_shape->hasNodesIn(apf::Mesh::EDGE)) { - const int nn = VelFieldShape->countNodesOn(apf::Mesh::EDGE); + const int nn = field_shape->countNodesOn(apf::Mesh::EDGE); for (int ii = 0; ii < 6; ii++) { for (int jj = 0; jj < nn; jj++) { - VelFieldShape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd); + field_shape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd); xi_crd[0] = 0.5 * (xi_crd[0] + 1.); // from (-1,1) to (0,1) double pt_crd[3] = {0., 0., 0.}; switch (ii) @@ -1420,14 +1358,14 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, } } // Dofs on Faces - if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE)) + if (field_shape->hasNodesIn(apf::Mesh::TRIANGLE)) { - const int nn = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE); + const int nn = field_shape->countNodesOn(apf::Mesh::TRIANGLE); for (int ii = 0; ii < 4; ii++) { for (int jj = 0; jj < nn; jj++) { - VelFieldShape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd); + field_shape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd); double pt_crd[3] = {0., 0., 0.}; switch (ii) { @@ -1476,19 +1414,19 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] + w_vel[kk] * w_vel[kk]; mag = sqrt(mag); - apf::setScalar(VelMagField, vtxs[kk], 0, mag); + apf::setScalar(vel_mag_field, vtxs[kk], 0, mag); // Set vel double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]}; - apf::setComponents(VelField, vtxs[kk], 0, vels); + apf::setComponents(vel_field, vtxs[kk], 0, vels); } int dofId = num_vts; - apf::EntityShape* es = VelFieldShape->getEntityShape(apf::Mesh::TET); + apf::EntityShape* es = field_shape->getEntityShape(apf::Mesh::TET); // Edge Dofs - if (VelFieldShape->hasNodesIn(apf::Mesh::EDGE)) + if (field_shape->hasNodesIn(apf::Mesh::EDGE)) { - int ndOnEdge = VelFieldShape->countNodesOn(apf::Mesh::EDGE); + int ndOnEdge = field_shape->countNodesOn(apf::Mesh::EDGE); Array order(ndOnEdge); apf::Downward edges; @@ -1503,11 +1441,11 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, v_vel[cnt] * v_vel[cnt] + w_vel[cnt] * w_vel[cnt]; mag = sqrt(mag); - apf::setScalar(VelMagField, edges[ii], jj, mag); + apf::setScalar(vel_mag_field, edges[ii], jj, mag); // Set vel double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(VelField, edges[ii], jj, vels); + apf::setComponents(vel_field, edges[ii], jj, vels); } // Counter dofId += ndOnEdge; @@ -1515,9 +1453,9 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, } // Face Dofs - if (VelFieldShape->hasNodesIn(apf::Mesh::TRIANGLE)) + if (field_shape->hasNodesIn(apf::Mesh::TRIANGLE)) { - int ndOnFace = VelFieldShape->countNodesOn(apf::Mesh::TRIANGLE); + int ndOnFace = field_shape->countNodesOn(apf::Mesh::TRIANGLE); Array order(ndOnFace); apf::Downward faces; @@ -1539,11 +1477,11 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, v_vel[cnt] * v_vel[cnt] + w_vel[cnt] * w_vel[cnt]; mag = sqrt(mag); - apf::setScalar(VelMagField, faces[ii], jj, mag); + apf::setScalar(vel_mag_field, faces[ii], jj, mag); // Set vel double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(VelField, faces[ii], jj, vels); + apf::setComponents(vel_field, faces[ii], jj, vels); } // Counter dofId += ndOnFace; diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 2f6eeacf92..10aa161ca9 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -43,8 +43,6 @@ namespace mfem class PumiMesh : public Mesh { protected: - Element *ReadElement(apf::MeshEntity* Ent, const int geom, apf::Downward Verts, - const int Attr, apf::Numbering* vert_num); void CountBoundaryEntity(apf::Mesh2* apf_mesh, const int BcDim, int &NumBC); // Readers for PUMI mesh formats, used in the Load() method. @@ -56,7 +54,7 @@ public: PumiMesh(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1, bool fix_orientation = true); - using Mesh::Load; + /* using Mesh::Load; */ /// Load a PUMI mesh (following the steps in the MFEM Load function). void Load(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1, @@ -73,10 +71,6 @@ class ParPumiMesh : public ParMesh private: apf::Numbering* v_num_loc; -protected: - Element *ReadElement(apf::MeshEntity* Ent, const int geom, apf::Downward Verts, - const int Attr, apf::Numbering* vert_num); - public: /// Build a parallel MFEM mesh from a parallel PUMI mesh. ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, From ce4d12c8cbc12b982075b7fce7d59ce9991a74a2 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Mon, 6 Apr 2020 15:52:14 +0200 Subject: [PATCH 123/535] Correct penalty selection --- miniapps/nurbs/nurbs_ex1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index 2a7210a61b..db57375112 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) args.PrintUsage(cout); return 1; } - if (strongBC & (kappa < 0)) + if (!strongBC & (kappa < 0)) { kappa = (order.Max()+1)*(order.Max()+1); } From 7c23c922ec583220e84a3ac9641d097bdba92924 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 6 Apr 2020 13:15:19 -0700 Subject: [PATCH 124/535] Address coefficient comments --- fem/coefficient.cpp | 12 ++++++------ fem/coefficient.hpp | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 4e56732601..cfe2d298a9 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -760,12 +760,8 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient( QuadratureFunction *qf) - : VectorCoefficient(qf->GetVDim()) -{ - QuadF = qf; - index = 0; - length = qf->GetVDim(); -} + : VectorCoefficient(qf->GetVDim()), QuadF(qf), index(0), + length(qf->GetVDim()) {} void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) @@ -805,6 +801,8 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { + MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); + QuadF->HostRead(); int elem_no = T.ElementNo; if (index == 0 && length == vdim) @@ -841,6 +839,8 @@ void QuadratureFunctionCoefficient::SetQuadratureFunction( double QuadratureFunctionCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) { + MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); + QuadF->HostRead(); int elem_no = T.ElementNo; Vector temp(1); diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 4ca0a4e347..13f32afd63 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -961,9 +961,9 @@ public: VectorQuadratureFunctionCoefficient(QuadratureFunction *qf); /// constructor with a null qf - VectorQuadratureFunctionCoefficient() : VectorCoefficient(0) { QuadF = NULL; } + VectorQuadratureFunctionCoefficient() : VectorCoefficient(0), QuadF(NULL), + index(-1), length(0) {} - /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); /// set the starting index within the QuadFunc that'll be used to project outwards @@ -1004,7 +1004,6 @@ public: /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); - /// getter function for the internal quadrature function QuadratureFunction *GetQuadFunction() const { return QuadF; } virtual double Eval(ElementTransformation &T, From fbdb989776f34f7871983d8aa0fbde3908445ab6 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 6 Apr 2020 13:44:59 -0700 Subject: [PATCH 125/535] Fix slow QuadratureFunction::GetElementValues when provided int pt --- fem/gridfunc.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index bf8df4c767..a7e2e94145 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -732,14 +732,12 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const values(i) = *(q++); } } -// fix me: This function should have a more efficient method for doing this operation. + inline void QuadratureFunction::GetElementValues(int idx, const int ip_num, Vector &values) { - Vector elem_vec; - GetElementValues(idx, elem_vec); - int vDim = GetVDim(); - values.NewDataAndSize(elem_vec + ip_num * vDim, vDim); + const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim; + values.NewDataAndSize(data + s_offset, vdim); } inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values) From b776d12f1ddb822c81658a28de94f6a6d1460475 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 6 Apr 2020 14:00:32 -0700 Subject: [PATCH 126/535] Remove comment that's not needed --- fem/coefficient.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 13f32afd63..de6a1b5e77 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -1001,7 +1001,6 @@ public: /// constructor with a null qf QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } - /// setter function for the internal quadrature function void SetQuadratureFunction(QuadratureFunction *qf); QuadratureFunction *GetQuadFunction() const { return QuadF; } From 8d627d84c180bcb5460403b15a7216dc222cfce7 Mon Sep 17 00:00:00 2001 From: Tomov Date: Tue, 7 Apr 2020 00:15:07 -0700 Subject: [PATCH 127/535] Minor. --- fem/coefficient.cpp | 3 +-- fem/gridfunc.hpp | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 8c15e0b2b7..690892d0c0 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -844,9 +844,8 @@ double QuadratureFunctionCoefficient::Eval(ElementTransformation &T, MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); QuadF->HostRead(); - int elem_no = T.ElementNo; Vector temp(1); - QuadF->GetElementValues(elem_no, ip.index, temp); + QuadF->GetElementValues(T.ElementNo, ip.index, temp); return temp[0]; } diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index a7e2e94145..1f4bb8234f 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -623,10 +623,9 @@ public: */ inline void GetElementValues(int idx, Vector &values) const; - /// Return the quadrature function values at an integration point + /// Return the quadrature function values at an integration point. /** The result is stored in the Vector @a values as a reference to the - global values. - */ + global values. */ inline void GetElementValues(int idx, const int ip_num, Vector &values); /// Return all values associated with mesh element @a idx in a DenseMatrix. From 75173ce65c22dd483bbe8769289e53dcfd9b25ba Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 10:48:40 -0700 Subject: [PATCH 128/535] Cleanup config/tconfig --- config/tconfig.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/tconfig.hpp b/config/tconfig.hpp index fccb679fc9..dcc2968209 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -93,14 +93,14 @@ struct AutoImplTraits static const int batch_size = 1; - static const int simd_size = simd?(MFEM_SIMD_SIZE/sizeof(complex_t)):1; + static const int simd_size = simd ? (MFEM_SIMD_SIZE/sizeof(complex_t)) : 1; - static const int valign_size = simd?simd_size:1; + static const int valign_size = simd ? simd_size : 1; - typedef AutoSIMD vcomplex_t; - typedef AutoSIMD< real_t,simd_size,valign_size> vreal_t; + typedef AutoSIMD vcomplex_t; + typedef AutoSIMD vreal_t; #ifndef MFEM_USE_SIMD - typedef AutoSIMD< int,simd_size,valign_size> vint_t; + typedef AutoSIMD vint_t; #endif // MFEM_USE_SIMD }; From b75b24ddfa277cfdc6233405c0d938e56b914754 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 7 Apr 2020 10:58:06 -0700 Subject: [PATCH 129/535] QuadratureFunctionCoeff tests now have a nonuniform project test --- tests/unit/fem/test_quadf_coef.cpp | 38 +++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 47581ee681..76bd45e5d2 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -31,20 +31,27 @@ TEST_CASE("Quadrature Function Coefficients", QuadratureFunction quadf_coeff(&qspace, 1); QuadratureFunction quadf_vcoeff(&qspace, dim); + const IntegrationRule ir = qspace.GetElementIntRule(0); + + const GeometricFactors *geom_facts = mesh.GetGeometricFactors(ir, + GeometricFactors::COORDINATES); + { - int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim(); - int vdim = quadf_coeff.GetVDim(); + int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim() / ir.GetNPoints(); + int vdim = ir.GetNPoints(); for (int i = 0; i < nelems; i++) { for (int j = 0; j < vdim; j++) { - quadf_coeff((i * vdim) + j) = 1.0; + //X has dims nqpts x sdim x ne + quadf_coeff((i * vdim) + j) = geom_facts->X((i * vdim * dim) + (vdim * 2) + j ); } } } { + //More like nelems * nqpts int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim(); int vdim = quadf_vcoeff.GetVDim(); @@ -145,15 +152,18 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); + // When using an L2 FE space of the same order as the mesh, the below highlights + // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. { - int nnodes = gtrue.Size(); - int vdim = 1; + int ne = mesh.GetNE(); + int int_points = ir.GetNPoints(); - for (int i = 0; i < vdim; i++) + for (int i = 0; i < ne; i++) { - for (int j = 0; j < nnodes; j++) + for (int j = 0; j < int_points; j++) { - gtrue((i * nnodes) + j) = 1.0; + gtrue((i * int_points) + j) = geom_facts->X((i * int_points * dim) + + (2 * int_points) + j); } } } @@ -176,18 +186,18 @@ TEST_CASE("Quadrature Function Coefficients", int nnodes = gtrue.Size(); int vdim = 1; - for (int i = 0; i < vdim; i++) + Vector nodes; + mesh.GetNodes(nodes); + for (int i = 0; i < nnodes; i++) { - for (int j = 0; j < nnodes; j++) - { - gtrue((i * nnodes) + j) = 1.0; - } + gtrue(i) = nodes(i * dim + 2); } } - + //If this was actually doing something akin to an L2 projection these values would be fairly close. g0 = 0.0; g0.ProjectCoefficient(qfc); gtrue -= g0; + //This currently fails... REQUIRE(gtrue.Norml2() < tol); } } From 80ab2f4671f3363f18fe10f6e988231d8ddd9b52 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 11:13:42 -0700 Subject: [PATCH 130/535] SIMD headers cleanup --- config/simd/auto.hpp | 18 +++++++++--------- config/simd/m128.hpp | 16 ++++++++++++---- config/simd/m256.hpp | 17 +++++++++++++---- config/simd/m512.hpp | 16 ++++++++++++---- config/simd/m64.hpp | 16 ++++++++++++---- config/simd/qpx.hpp | 2 +- config/simd/qpx256.hpp | 6 ++++-- config/simd/qpx64.hpp | 6 ++++-- config/simd/vsx128.hpp | 16 ++++++++++++---- config/simd/vsx64.hpp | 16 ++++++++++++---- config/simd/x86.hpp | 2 +- 11 files changed, 92 insertions(+), 39 deletions(-) diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index dc82f88dee..b0815d19ab 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -12,13 +12,7 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_AUTO #define MFEM_TEMPLATE_CONFIG_SIMD_AUTO -template struct AutoSIMD; -#ifndef MFEM_ALWAYS_INLINE -#define MFEM_ALWAYS_INLINE -#endif -#ifndef MFEM_VECTORIZE_LOOP -#define MFEM_VECTORIZE_LOOP -#endif +#include "../tconfig.hpp" template struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD @@ -29,9 +23,15 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD scalar_t vec[size]; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + { + return vec[i]; + } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + { + return vec[i]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 6743eeebc9..5b8c66a6c6 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -12,11 +12,13 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M128 #define MFEM_TEMPLATE_CONFIG_SIMD_M128 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 2; - static const int align_size = 16; + static constexpr int size = 2; + static constexpr int align_size = 16; union { @@ -24,9 +26,15 @@ template struct AutoSIMD scalar_t vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + { + return vec[i]; + } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + { + return vec[i]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index baf829f856..9bbc5036da 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -12,11 +12,13 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M256 #define MFEM_TEMPLATE_CONFIG_SIMD_M256 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 4; - static const int align_size = 32; + static constexpr int size = 4; + static constexpr int align_size = 32; union { @@ -24,8 +26,15 @@ template struct AutoSIMD scalar_t vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } - const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + { + return vec[i]; + } + + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + { + return vec[i]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 26cfec78d4..2a06b3b10e 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -12,11 +12,13 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M512 #define MFEM_TEMPLATE_CONFIG_SIMD_M512 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 8; - static const int align_size = 64; + static constexpr int size = 8; + static constexpr int align_size = 64; union { @@ -24,9 +26,15 @@ template struct AutoSIMD scalar_t vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + { + return vec[i]; + } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + { + return vec[i]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index 40bdf4424f..95837972ca 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -12,17 +12,25 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_M64 #define MFEM_TEMPLATE_CONFIG_SIMD_M64 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 1; - static const int align_size = 8; + static constexpr int size = 1; + static constexpr int align_size = 8; scalar_t vec[size]; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[0]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int) + { + return vec[0]; + } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[0]; } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int) const + { + return vec[0]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/qpx.hpp b/config/simd/qpx.hpp index 254504bfde..54797fd761 100644 --- a/config/simd/qpx.hpp +++ b/config/simd/qpx.hpp @@ -14,7 +14,7 @@ #include "builtins.h" -template struct AutoSIMD; +//template struct AutoSIMD; #include "qpx64.hpp" diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index 20dbdf4966..fffa8621b9 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -12,11 +12,13 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 4; - static const int align_size = 32; + static constexpr int size = 4; + static constexpr int align_size = 32; union { diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp index e6e27d5931..b4c0f39e6f 100644 --- a/config/simd/qpx64.hpp +++ b/config/simd/qpx64.hpp @@ -12,11 +12,13 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 #define MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 1; - static const int align_size = 8; + static constexpr int size = 1; + static constexpr int align_size = 8; scalar_t vec[size]; diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp index 488e2f3ec7..5397ba6571 100644 --- a/config/simd/vsx128.hpp +++ b/config/simd/vsx128.hpp @@ -12,11 +12,13 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX128 #define MFEM_TEMPLATE_CONFIG_SIMD_VSX128 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 2; - static const int align_size = 16; + static constexpr int size = 2; + static constexpr int align_size = 16; union { @@ -24,9 +26,15 @@ template struct AutoSIMD scalar_t vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + { + return vec[i]; + } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + { + return vec[i]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/vsx64.hpp b/config/simd/vsx64.hpp index 0a5abbcd7b..ae5b705feb 100644 --- a/config/simd/vsx64.hpp +++ b/config/simd/vsx64.hpp @@ -12,17 +12,25 @@ #ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX64 #define MFEM_TEMPLATE_CONFIG_SIMD_VSX64 +#include "../tconfig.hpp" + template struct AutoSIMD { typedef scalar_t scalar_type; - static const int size = 1; - static const int align_size = 8; + static constexpr int size = 1; + static constexpr int align_size = 8; scalar_t vec[size]; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[0]; } + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + { + return vec[0]; + } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[0]; } + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + { + return vec[0]; + } inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) { diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index 10b02c4394..1920934f99 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -14,7 +14,7 @@ #include "x86intrin.h" -template struct AutoSIMD; +template struct AutoSIMD; #include "m64.hpp" From a08e2b2b5ea2c6b2d975075dfec9e1494a41b1d8 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 11:33:44 -0700 Subject: [PATCH 131/535] Meld toward master --- fem/bilinearform.cpp | 2 +- linalg/tmatrix.hpp | 14 ++++++-------- linalg/ttensor.hpp | 8 ++++---- makefile | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index 9e7074b506..1aec3960b5 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -55,7 +55,7 @@ void BilinearForm::AllocMat() int *I = dof_dof.GetI(); int *J = dof_dof.GetJ(); - double *data = Memory(I[height]); // ALIGN32 ? + double *data = Memory(I[height]); mat = new SparseMatrix(I, J, data, height, height, true, true, true); *mat = 0.0; diff --git a/linalg/tmatrix.hpp b/linalg/tmatrix.hpp index 61cd8e74fc..57a5ab589e 100644 --- a/linalg/tmatrix.hpp +++ b/linalg/tmatrix.hpp @@ -25,11 +25,9 @@ namespace mfem namespace internal { -template struct entry_type -{ typedef typename T::data_type type; }; +template struct entry_type { typedef typename T::data_type type; }; -template struct entry_type -{ typedef T type; }; +template struct entry_type { typedef T type; }; } // namespace mfem::internal @@ -458,8 +456,8 @@ struct MatrixOps<3,3>::Symm template static inline MFEM_ALWAYS_INLINE void Set(const A_layout_t &a, A_data_t &A, - const scalar_t &a11, const scalar_t &a21, const scalar_t &a31, - const scalar_t &a22, const scalar_t &a32, const scalar_t &a33) + const scalar_t a11, const scalar_t a21, const scalar_t a31, + const scalar_t a22, const scalar_t a32, const scalar_t a33) { A[a.ind(0)] = a11; A[a.ind(1)] = a21; @@ -476,8 +474,8 @@ struct MatrixOps<3,3>::Symm template static inline MFEM_ALWAYS_INLINE void Set(const A_layout_t &a, A_data_t &A, - const scalar_t &a11, const scalar_t &a21, const scalar_t &a31, - const scalar_t &a22, const scalar_t &a32, const scalar_t &a33) + const scalar_t a11, const scalar_t a21, const scalar_t a31, + const scalar_t a22, const scalar_t a32, const scalar_t a33) { A[a.ind(0,0)] = a11; A[a.ind(1,0)] = a21; diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index 1979a3997f..42d1ffaddd 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -40,7 +40,7 @@ struct TensorOps<1> // rank = 1 typename scalar_t> MFEM_HOST_DEVICE static void Assign(const A_layout_t &A_layout, A_data_t &A_data, - const scalar_t &value) + const scalar_t value) { MFEM_STATIC_ASSERT(A_layout_t::rank == 1, "invalid rank"); for (int i1 = 0; i1 < A_layout_t::dim_1; i1++) @@ -222,7 +222,7 @@ template MFEM_HOST_DEVICE inline void TAssign(const A_layout_t &A_layout, A_data_t &A_data, - const scalar_t &value) + const scalar_t value) { internal::TensorOps:: template Assign(A_layout, A_data, value); @@ -260,7 +260,7 @@ public: MFEM_HOST_DEVICE const data_t &operator[](int i) const { return data[i]; } template - void Assign(const data_t &d) + void Assign(const data_t d) { TAssign(layout, data, d); } @@ -294,7 +294,7 @@ public: AssignTo(dest); } - void Scale(const data_t &scale) + void Scale(const data_t scale) { Assign(scale); } diff --git a/makefile b/makefile index baec07f060..a45d667800 100644 --- a/makefile +++ b/makefile @@ -644,10 +644,10 @@ status info: $(info MFEM_USE_OCCA = $(MFEM_USE_OCCA)) $(info MFEM_USE_CEED = $(MFEM_USE_CEED)) $(info MFEM_USE_UMPIRE = $(MFEM_USE_UMPIRE)) + $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) $(info MFEM_CXX = $(value MFEM_CXX)) $(info MFEM_CPPFLAGS = $(value MFEM_CPPFLAGS)) $(info MFEM_CXXFLAGS = $(value MFEM_CXXFLAGS)) - $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) $(info MFEM_TPLFLAGS = $(value MFEM_TPLFLAGS)) $(info MFEM_INCFLAGS = $(value MFEM_INCFLAGS)) $(info MFEM_FLAGS = $(value MFEM_FLAGS)) From 8f76ce56fbfa64661a209d4f6cf84a6ae0b8f5c5 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 7 Apr 2020 12:03:39 -0700 Subject: [PATCH 132/535] Backward compatibility changes in FaceElementTransformations --- examples/ex18.hpp | 6 +++--- fem/eltrans.hpp | 6 +++--- mesh/mesh.cpp | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/ex18.hpp b/examples/ex18.hpp index 75fa5e885b..fe0e38ffc2 100644 --- a/examples/ex18.hpp +++ b/examples/ex18.hpp @@ -418,7 +418,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, { intorder++; } - const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder); + const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder); for (int i = 0; i < ir->GetNPoints(); i++) { @@ -435,10 +435,10 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, elfun1_mat.MultTranspose(shape1, funval1); elfun2_mat.MultTranspose(shape2, funval2); - Tr.SetIntPoint(&ip); + Tr.Face->SetIntPoint(&ip); // Get the normal vector and the flux on the face - CalcOrtho(Tr.Jacobian(), nor); + CalcOrtho(Tr.Face->Jacobian(), nor); const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN); // Update max char speed diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 1e0ee84821..b91f90fad2 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -376,11 +376,11 @@ private: int side; public: - int Elem1No, Elem2No; - ElementTransformation *Elem1, *Elem2; + int Elem1No, Elem2No, FaceGeom; + ElementTransformation *Elem1, *Elem2, *Face; IntegrationPointTransformation Loc1, Loc2; - FaceElementTransformations() : side(2) {} + FaceElementTransformations() : side(2), Face(this) {} /** FaceElementTransformations objects are often used when performing the surface integrals on the interfaces between diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 73125ee4a6..941d325226 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -484,6 +484,12 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr) FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute(); FTr->ElementNo = FaceNo; FTr->ElementType = ElementTransformation::FACE; + FaceElementTransformations * FETr = + dynamic_cast(FTr); + if (FETr) + { + FETr->FaceGeom = GetFaceGeometryType(FaceNo); + } DenseMatrix &pm = FTr->GetPointMat(); if (Nodes == NULL) { From 4ec1f7782aa42f10241224d48d1822ae9991dd09 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 13:53:48 -0700 Subject: [PATCH 133/535] Update CHANGELOG, remove MFEM_POSIX_MEMALIGN to use aligned Memory. --- CHANGELOG | 8 ++++++++ config/tconfig.hpp | 9 --------- fem/tbilinearform.hpp | 13 +++++-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2b2a7442e0..ff3ed68846 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -46,6 +46,14 @@ Improved testing Miscellaneous ------------- +- Added support for explicit vectorization for the high-performance templated + code, which can now take advantage of specific intrinsics classes on the + following architectures: + - x86 (SSE/AVX/AVX2/AVX512), + - Power8 & Power9 (VSX), + - BG/Q (QPX). + It can be enabled with MFEM_USE_SIMD=YES. + - In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the solver can work with non-SPD preconditioner B. diff --git a/config/tconfig.hpp b/config/tconfig.hpp index dcc2968209..19b59f80cd 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -46,15 +46,6 @@ #define MFEM_ALIGN_AS(bytes) #endif -// --- POSIX MEMALIGN -#ifdef _WIN32 -#define MFEM_POSIX_MEMALIGN(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno) -#define MFEM_POSIX_MEMALIGN_FREE _aligned_free -#else -#define MFEM_POSIX_MEMALIGN posix_memalign -#define MFEM_POSIX_MEMALIGN_FREE free -#endif - // --- AutoSIMD or intrinsics #ifndef MFEM_USE_SIMD #include "simd/auto.hpp" diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 1c34abf3c6..11e6959b2f 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -100,7 +100,7 @@ protected: coeff_t coeff; - p_assembled_t *assembled_data; + Memory assembled_data; const FiniteElementSpace &in_fes; @@ -115,13 +115,13 @@ public: solVecLayout(sol_fes), int_rule(), coeff(integ.coeff), - assembled_data(NULL), + assembled_data(), in_fes(sol_fes) { } virtual ~TBilinearForm() { - MFEM_POSIX_MEMALIGN_FREE(assembled_data); + assembled_data.Delete(); } /// Get the input finite element space prolongation matrix @@ -195,11 +195,8 @@ public: const int NE = mesh.GetNE(); if (!assembled_data) { - void* result; - const int size = ((NE+TE-1)/TE)*BE*sizeof(p_assembled_t); - MFEM_POSIX_MEMALIGN(&result, 32, size); - if (!result) { throw ::std::bad_alloc(); } - assembled_data = (p_assembled_t*) result; + const int size = ((NE+TE-1)/TE)*BE; + assembled_data = Memory(size, MemoryType::HOST_64); } for (int el = 0; el < NE; el += TE) { From b1e7bbaa112ca5fb6465b21041b4eb960cecbff5 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 14:07:31 -0700 Subject: [PATCH 134/535] Simplify assembled_data allocation --- fem/tbilinearform.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 11e6959b2f..a706053852 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -115,7 +115,7 @@ public: solVecLayout(sol_fes), int_rule(), coeff(integ.coeff), - assembled_data(), + assembled_data(((mesh.GetNE()+TE-1)/TE)*BE, MemoryType::HOST_64), in_fes(sol_fes) { } @@ -193,11 +193,6 @@ public: coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); - if (!assembled_data) - { - const int size = ((NE+TE-1)/TE)*BE; - assembled_data = Memory(size, MemoryType::HOST_64); - } for (int el = 0; el < NE; el += TE) { typename T_result::Type F; From e6fd16e6a5100407f9d047f0b36c87ad0a38b176 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 7 Apr 2020 14:54:17 -0700 Subject: [PATCH 135/535] Rearranging the comments to produce more effective doxygen output --- fem/gridfunc.hpp | 52 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 0c4c84786c..81c007deea 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -141,31 +141,37 @@ public: /// Returns the values in the vertices of i'th element for dimension vdim. void GetNodalValues(int i, Array &nval, int vdim = 1) const; - ///@{ - /** GetValue methods taking an integer element index. + /** @name Element index Get Value Methods These methods take an element index and return the interpolated value of the field at a given reference point within the element. */ + ///@{ + /** Return a scalar value from within the given element. */ virtual double GetValue(int i, const IntegrationPoint &ip, int vdim = 1) const; + /** Return a vector value from within the given element. */ void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const; ///@} - ///@{ - /** GetValues method taking an integer element index. + /** @name Element Index Get Values Methods These are convenience methods for repeatedly calling GetValue for multiple points within a given element. The GetValues methods are optimized and should perform better than repeatedly calling GetValue. The GetVectorValues method simply calls GetVectorValue repeatedly. - */ + */ + ///@{ + /** Compute a collection of scalar values from within the element + indicated by the index i. */ void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim = 1) const; + /** Compute a collection of vector values from within the element + indicated by the index i. */ void GetValues(int i, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim = 1) const; @@ -173,8 +179,7 @@ public: DenseMatrix &vals, DenseMatrix &tr) const; ///@} - ///@{ - /** GetValue methods taking a ElementTransformation argument. + /** @name ElementTransformation Get Value Methods These member functions are designed for use within GridFunctionCoefficient objects. These can be used with @@ -182,15 +187,21 @@ public: Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation(). */ + ///@{ + /** Return a scalar value from within the element indicated by the + ElementTransformation Object. + */ double GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp = 0, Vector *tr = NULL) const; + /** Return a vector value from within the element indicated by the + ElementTransformation Object. + */ void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; ///@} - ///@{ - /** GetValue methods taking a FaceElementTransformations argument. + /** @name FaceElementTransformations Get Value Methods These member functions are designed for use within GridFunctionCoefficient objects. These can be used with @@ -199,16 +210,22 @@ public: Mesh::GetInteriorFaceElementTransformations(), or Mesh::GetBdrFaceElementTransformations(). */ + ///@{ + /** Return a scalar value from within the face indicated by the + FaceElementTransformations object. + */ double GetValue(FaceElementTransformations &T, const IntegrationPoint &ip, int comp = 0, Vector *tr = NULL) const; + /** Return a vector value from within the face indicated by the + FaceElementTransformations object. + */ void GetVectorValue(FaceElementTransformations &T, const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; ///@} - ///@{ - /** GetValues methods taking a ElementTransformation argument. + /** ElementTransformation Get Values Methods These are convenience methods for repeatedly calling GetValue for multiple points within a given element. They work by @@ -217,15 +234,19 @@ public: Consequently, these methods should not be expected to run faster than calling the above methods in an external loop. */ + ///@{ + /** Compute a collection of scalar values from within the element + indicated by the ElementTransformation object. */ void GetValues(ElementTransformation &T, const IntegrationRule &ir, Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; + /** Compute a collection of vector values from within the element + indicated by the ElementTransformation object. */ void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix *tr = NULL) const; ///@} - ///@{ - /** GetFaceValues methods take a face index argument. + /** @name Face Index Get Values Methods These methods are designed to work with Discontinuous Galerkin basis functions. They compute field values on the interface @@ -236,9 +257,14 @@ public: documentation in eltrans.hpp for more information on the \a side parameter. */ + ///@{ + /** Compute a collection of scalar values from within the face + indicated by the index i. */ int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim = 1) const; + /** Compute a collection of vector values from within the face + indicated by the index i. */ int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const; ///@} From 6c63638300be81aa4800f0f662165e591a22d7a2 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 15:39:12 -0700 Subject: [PATCH 136/535] Fix zstr.hpp(178): warning C4101: 'e': unreferenced local variable and try HOST_32 --- fem/tbilinearform.hpp | 2 +- general/zstr.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index a706053852..5dab4f1826 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -115,7 +115,7 @@ public: solVecLayout(sol_fes), int_rule(), coeff(integ.coeff), - assembled_data(((mesh.GetNE()+TE-1)/TE)*BE, MemoryType::HOST_64), + assembled_data(((mesh.GetNE()+TE-1)/TE)*BE, MemoryType::HOST_32), in_fes(sol_fes) { } diff --git a/general/zstr.hpp b/general/zstr.hpp index dc61bcdcce..407e2976eb 100644 --- a/general/zstr.hpp +++ b/general/zstr.hpp @@ -175,7 +175,7 @@ struct static_method_holder is_p->peek(); peek_failed = is_p->fail(); } - catch (std::ios_base::failure &e) {} + catch (std::ios_base::failure&) {} if (peek_failed) { throw Exception(std::string("strict_fstream: open('") From d058f7959113b5d694523196531924bd06e7c273 Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 16:47:19 -0700 Subject: [PATCH 137/535] Reset assembled_data --- fem/tbilinearform.hpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 5dab4f1826..ddfd2741fe 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -115,9 +115,9 @@ public: solVecLayout(sol_fes), int_rule(), coeff(integ.coeff), - assembled_data(((mesh.GetNE()+TE-1)/TE)*BE, MemoryType::HOST_32), + assembled_data(), in_fes(sol_fes) - { } + { assembled_data.Reset(); } virtual ~TBilinearForm() { @@ -133,7 +133,7 @@ public: virtual void Mult(const Vector &x, Vector &y) const { - if (assembled_data) + if (!assembled_data.Empty()) { MultAssembled(x, y); } @@ -193,6 +193,11 @@ public: coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); + if (assembled_data.Empty()) + { + const int size = ((NE+TE-1)/TE)*BE; + assembled_data = Memory(size, MemoryType::HOST_64); + } for (int el = 0; el < NE; el += TE) { typename T_result::Type F; @@ -289,11 +294,10 @@ public: coeff_eval_t wQ(int_rule, coeff); const int NE = mesh.GetNE(); - if (!assembled_data) + if (assembled_data.Empty()) { - // TODO: How do we make sure that this array is aligned properly, AND - // the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready - assembled_data = new p_assembled_t[((NE+TE-1)/TE)*BE]; + const int size = ((NE+TE-1)/TE)*BE; + assembled_data = Memory(size, MemoryType::HOST_64); } const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData()); for (int el = 0; el < NE; el += TE) From 7df19938c429460bebc7f56d71a80797637ca14a Mon Sep 17 00:00:00 2001 From: camierjs Date: Tue, 7 Apr 2020 17:44:57 -0700 Subject: [PATCH 138/535] Use _aligned_free --- fem/tbilinearform.hpp | 6 +++--- general/mem_manager.cpp | 5 ++++- general/mem_manager.hpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index ddfd2741fe..68c3f7040b 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -117,7 +117,7 @@ public: coeff(integ.coeff), assembled_data(), in_fes(sol_fes) - { assembled_data.Reset(); } + { assembled_data.Reset(MemoryType::HOST_32); } virtual ~TBilinearForm() { @@ -196,7 +196,7 @@ public: if (assembled_data.Empty()) { const int size = ((NE+TE-1)/TE)*BE; - assembled_data = Memory(size, MemoryType::HOST_64); + assembled_data = Memory(size, MemoryType::HOST_32); } for (int el = 0; el < NE; el += TE) { @@ -297,7 +297,7 @@ public: if (assembled_data.Empty()) { const int size = ((NE+TE-1)/TE)*BE; - assembled_data = Memory(size, MemoryType::HOST_64); + assembled_data = Memory(size, MemoryType::HOST_32); } const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData()); for (int el = 0; el < NE; el += TE) diff --git a/general/mem_manager.cpp b/general/mem_manager.cpp index 54f09418c8..30872bb60a 100644 --- a/general/mem_manager.cpp +++ b/general/mem_manager.cpp @@ -26,8 +26,10 @@ #include #include #define mfem_memalign(p,a,s) posix_memalign(p,a,s) +#define mfem_aligned_free free #else #define mfem_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno) +#define mfem_aligned_free _aligned_free #endif #ifdef MFEM_USE_UMPIRE @@ -212,7 +214,7 @@ public: Aligned32HostMemorySpace(): HostMemorySpace() { } void Alloc(void **ptr, size_t bytes) { if (mfem_memalign(ptr, 32, bytes) != 0) { throw ::std::bad_alloc(); } } - void Dealloc(void *ptr) { std::free(ptr); } + void Dealloc(void *ptr) { mfem_aligned_free(ptr); } }; /// The aligned 64 host memory space @@ -222,6 +224,7 @@ public: Aligned64HostMemorySpace(): HostMemorySpace() { } void Alloc(void **ptr, size_t bytes) { if (mfem_memalign(ptr, 64, bytes) != 0) { throw ::std::bad_alloc(); } } + void Dealloc(void *ptr) { mfem_aligned_free(ptr); } }; #ifndef _WIN32 diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index ae735c2e57..c225dc1e8e 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -638,7 +638,7 @@ inline void Memory::New(int size, MemoryType mt) if (mt_host) { flags = OWNS_HOST | VALID_HOST; } h_mt = IsHostMemory(mt) ? mt : MemoryManager::GetDualMemoryType_(mt); T *h_tmp = (h_mt == MemoryType::HOST) ? new T[size] : nullptr; - h_ptr = (mt_host) ? h_tmp: (T*)MemoryManager::New_(h_tmp, bytes, mt, flags); + h_ptr = (mt_host) ? h_tmp : (T*)MemoryManager::New_(h_tmp, bytes, mt, flags); } template From 224895adc2ac7a2fb5b879c2e06cb5e3de355362 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 14:43:57 +0200 Subject: [PATCH 139/535] Add mesh info output --- miniapps/nurbs/nurbs_ex1.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index db57375112..4bfcd9059b 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -197,6 +197,7 @@ int main(int argc, char *argv[]) { mesh->UniformRefinement(); } + mesh->PrintInfo(); } // 4. Define a finite element space on the mesh. Here we use continuous From ea59ab0ce9c087bd8f718a9f5bdacf7caedb0a8a Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 14:47:37 +0200 Subject: [PATCH 140/535] Add be2face and face2be mapping to mesh, needs cleaning --- mesh/mesh.cpp | 18 ++++++++++++++++++ mesh/mesh.hpp | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 6262b546a1..846585e597 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -10755,6 +10755,24 @@ Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz) return mesh3d; } + + int Mesh::face2be(int i) + { + if (face2be_array.Size() == 0) + { + face2be_array.SetSize(40000); + face2be_array = -1; + for (int j = 0; j < NumOfBdrElements; j++) + { + face2be_array[be2face(j)] = j; + } + } + + return face2be_array[i]; + } + + + #ifdef MFEM_DEBUG void Mesh::DebugDump(std::ostream &out) const { diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 0bd0b70180..8732039ac7 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -861,6 +861,28 @@ public: } } + /// Returns the indices of the vertices of face i. + int be2face(int i) const + { + if (Dim == 1) + { + return (i==0)? 0:NumOfFaces-1; // NEEDS checking !!! + } + else if (Dim == 2) + { + return be_to_edge[i]; + } + else + { + return be_to_face[i]; + } + + } + + Array face2be_array; + int face2be(int i); + + /// Returns the indices of the vertices of edge i. void GetEdgeVertices(int i, Array &vert) const; From 9e0569c53af72ffddbfe6702451bc04c01547678 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 14:55:15 +0200 Subject: [PATCH 141/535] Add NURBS face integration capability --- fem/fespace.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 3d1467aa4f..9ab25d7977 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1741,6 +1741,17 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const { + + /*if (face_dof) + { + face_dof->GetRow(i, dofs); + }*/ + if (NURBSext) + { + GetBdrElementDofs(mesh->face2be(i),dofs); + } + else + { int j, k, nv, ne, nf, nd, dim = mesh->Dimension(); Array V, E, Eo; const int *ind; @@ -1796,6 +1807,7 @@ void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const dofs[ne+k] = j; } } + } } void FiniteElementSpace::GetEdgeDofs(int i, Array &dofs) const @@ -1925,6 +1937,11 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const // if (NURBSext) // NURBSext->LoadFaceElement(i, fe); + if (NURBSext) + { + NURBSext->LoadBE(mesh->face2be(i), fe); + } + return fe; } From f62a6eee7584966091c30fc3c0edee69409905f3 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 17:05:18 +0200 Subject: [PATCH 142/535] Clean Face2Bdr and Bdr2Face mechanism --- fem/fespace.cpp | 4 ++-- mesh/mesh.cpp | 47 +++++++++++++++++++++++++++++++++-------------- mesh/mesh.hpp | 32 +++++++++----------------------- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 9ab25d7977..6cea6cca44 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1748,7 +1748,7 @@ void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const }*/ if (NURBSext) { - GetBdrElementDofs(mesh->face2be(i),dofs); + GetBdrElementDofs(mesh->GetFaceBdr(i),dofs); } else { @@ -1939,7 +1939,7 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const if (NURBSext) { - NURBSext->LoadBE(mesh->face2be(i), fe); + NURBSext->LoadBE(mesh->GetFaceBdr(i), fe); } return fe; diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 846585e597..67c970e457 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -2294,12 +2294,13 @@ void Mesh::FinalizeTopology(bool generate_bdr) { NumOfEdges = 0; } - if (Dim == 1) { GenerateFaces(); } + if (NURBSext) GenerateFaceBdrMap(); + if (ncmesh) { // tell NCMesh the numbering of edges/faces @@ -2311,6 +2312,7 @@ void Mesh::FinalizeTopology(bool generate_bdr) // generate the arrays 'attributes' and 'bdr_attributes' SetAttributes(); + } void Mesh::Finalize(bool refine, bool fix_orientation) @@ -3784,6 +3786,8 @@ void Mesh::UpdateNURBS() GetElementToFaceTable(); GenerateFaces(); } + + GenerateFaceBdrMap(); } void Mesh::LoadPatchTopo(std::istream &input, Array &edge_to_knot) @@ -4633,6 +4637,34 @@ int Mesh::GetBdrElementEdgeIndex(int i) const return -1; } +int Mesh::GetBdrFace(int i) const +{ + switch (Dim) + { + case 1: return boundary[i]->GetVertices()[0]; + case 2: return be_to_edge[i]; + case 3: return be_to_face[i]; + default: mfem_error("Mesh::GetBdrFace: invalid dimension!"); + } + return -1; +} + +void Mesh::GenerateFaceBdrMap() +{ + int fm = NumOfFaces; + for (int j = 0; j < NumOfBdrElements; j++) + { + fm = std::max(GetBdrFace(j),fm); + } + + face_to_be.SetSize(fm+1); + face_to_be = -1; + for (int j = 0; j < NumOfBdrElements; j++) + { + face_to_be[GetBdrFace(j)] = j; + } +} + void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const { int fid = GetBdrElementEdgeIndex(bdr_el); @@ -10756,20 +10788,7 @@ Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz) } - int Mesh::face2be(int i) - { - if (face2be_array.Size() == 0) - { - face2be_array.SetSize(40000); - face2be_array = -1; - for (int j = 0; j < NumOfBdrElements; j++) - { - face2be_array[be2face(j)] = j; - } - } - return face2be_array[i]; - } diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 8732039ac7..73e0403186 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -147,6 +147,7 @@ protected: Array be_to_edge; // for 2D Table *bel_to_edge; // for 3D Array be_to_face; + Array face_to_be; mutable Table *face_edge; mutable Table *edge_vertex; @@ -861,28 +862,6 @@ public: } } - /// Returns the indices of the vertices of face i. - int be2face(int i) const - { - if (Dim == 1) - { - return (i==0)? 0:NumOfFaces-1; // NEEDS checking !!! - } - else if (Dim == 2) - { - return be_to_edge[i]; - } - else - { - return be_to_face[i]; - } - - } - - Array face2be_array; - int face2be(int i); - - /// Returns the indices of the vertices of edge i. void GetEdgeVertices(int i, Array &vert) const; @@ -901,7 +880,14 @@ public: /** Return the vertex index of boundary element i. (1D) Return the edge index of boundary element i. (2D) Return the face index of boundary element i. (3D) */ - int GetBdrElementEdgeIndex(int i) const; + int GetBdrElementEdgeIndex(int i) const; // Strange name + int GetBdrFace(int i) const; // Does the same as above better name?? + + /// Generates the face to bdr mapping. (-1 if no match). + void GenerateFaceBdrMap(); + + /// Return the bdr indices of a face i. (-1 if no match). + int GetFaceBdr(int i) { return face_to_be[i]; } /** @brief For the given boundary element, bdr_el, return its adjacent element and its info, i.e. 64*local_bdr_index+bdr_orientation. */ From cea889054ec6e981842686cbfdf72a8229e21105 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 17:24:03 +0200 Subject: [PATCH 143/535] Add test cases --- miniapps/nurbs/CMakeLists.txt | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/miniapps/nurbs/CMakeLists.txt b/miniapps/nurbs/CMakeLists.txt index b953b91172..ddcbd3ee10 100644 --- a/miniapps/nurbs/CMakeLists.txt +++ b/miniapps/nurbs/CMakeLists.txt @@ -25,16 +25,31 @@ add_mfem_miniapp(nurbs_ex1 MAIN nurbs_ex1.cpp LIBRARIES mfem) -add_test(NAME nurbs_ex1_ser - COMMAND $ -no-vis) +add_test(NAME nurbs_ex1_r0_o4_ser + COMMAND $ -no-vis -r 0 -o 4) + +add_test(NAME nurbs_ex1_r2_ser + COMMAND $ -no-vis -r 2) add_test(NAME nurbs_ex1_per_ser COMMAND $ -no-vis -m ../../data/beam-hex-nurbs.mesh -pm 1 -ps 2) -add_test(NAME nurbs_ex1_lap_ser +add_test(NAME nurbs_ex1_lap_r0_ser COMMAND $ -no-vis - -m pipe-nurbs-2d.mesh -o 2 -no-ibp) + -m pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0) + +add_test(NAME nurbs_ex1_lap_r2_ser + COMMAND $ -no-vis + -m pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2) + +add_test(NAME nurbs_ex1_weak_r0_ser + COMMAND $ -no-vis + -m pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0) + +add_test(NAME nurbs_ex1_weak_r2_ser + COMMAND $ -no-vis + -m pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2) if (MFEM_USE_MPI) From 0001d33b5bba7de370c65c8889d2552b2c688555 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 17:24:58 +0200 Subject: [PATCH 144/535] undo unnecessary changes --- mesh/mesh.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index eb43766261..e22dd1c1d9 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -2329,6 +2329,7 @@ void Mesh::FinalizeTopology(bool generate_bdr) { NumOfEdges = 0; } + if (Dim == 1) { GenerateFaces(); @@ -2347,7 +2348,6 @@ void Mesh::FinalizeTopology(bool generate_bdr) // generate the arrays 'attributes' and 'bdr_attributes' SetAttributes(); - } void Mesh::Finalize(bool refine, bool fix_orientation) @@ -10961,11 +10961,6 @@ Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz) return mesh3d; } - - - - - #ifdef MFEM_DEBUG void Mesh::DebugDump(std::ostream &out) const { From e089d8a4aff64a3c78cce54d8385d876b9ae4e58 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 17:46:33 +0200 Subject: [PATCH 145/535] make style --- fem/fespace.cpp | 88 ++++++++++++++++++------------------ mesh/mesh.cpp | 2 +- mesh/mesh.hpp | 2 +- miniapps/nurbs/nurbs_ex1.cpp | 6 ++- 4 files changed, 50 insertions(+), 48 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 803d0f64bf..cbe20cb49d 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1751,61 +1751,61 @@ void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const } else { - int j, k, nv, ne, nf, nd, dim = mesh->Dimension(); - Array V, E, Eo; - const int *ind; + int j, k, nv, ne, nf, nd, dim = mesh->Dimension(); + Array V, E, Eo; + const int *ind; - // for 1D, 2D and 3D faces - nv = fec->DofForGeometry(Geometry::POINT); - ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0; - if (nv > 0) - { - mesh->GetFaceVertices(i, V); - } - if (ne > 0) - { - mesh->GetFaceEdges(i, E, Eo); - } - nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0); - nd = V.Size() * nv + E.Size() * ne + nf; - dofs.SetSize(nd); - if (nv > 0) - { - for (k = 0; k < V.Size(); k++) + // for 1D, 2D and 3D faces + nv = fec->DofForGeometry(Geometry::POINT); + ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0; + if (nv > 0) { - for (j = 0; j < nv; j++) - { - dofs[k*nv+j] = V[k]*nv+j; - } + mesh->GetFaceVertices(i, V); } - } - nv *= V.Size(); - if (ne > 0) - { - for (k = 0; k < E.Size(); k++) + if (ne > 0) { - ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]); - for (j = 0; j < ne; j++) + mesh->GetFaceEdges(i, E, Eo); + } + nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0); + nd = V.Size() * nv + E.Size() * ne + nf; + dofs.SetSize(nd); + if (nv > 0) + { + for (k = 0; k < V.Size(); k++) { - if (ind[j] < 0) + for (j = 0; j < nv; j++) { - dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) ); - } - else - { - dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j]; + dofs[k*nv+j] = V[k]*nv+j; } } } - } - ne = nv + ne * E.Size(); - if (nf > 0) - { - for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++) + nv *= V.Size(); + if (ne > 0) { - dofs[ne+k] = j; + for (k = 0; k < E.Size(); k++) + { + ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]); + for (j = 0; j < ne; j++) + { + if (ind[j] < 0) + { + dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) ); + } + else + { + dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j]; + } + } + } + } + ne = nv + ne * E.Size(); + if (nf > 0) + { + for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++) + { + dofs[ne+k] = j; + } } - } } } diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index e22dd1c1d9..d660567aaa 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -2335,7 +2335,7 @@ void Mesh::FinalizeTopology(bool generate_bdr) GenerateFaces(); } - if (NURBSext) GenerateFaceBdrMap(); + if (NURBSext) { GenerateFaceBdrMap(); } if (ncmesh) { diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 51d72697a7..fab8b12452 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -889,7 +889,7 @@ public: Return the edge index of boundary element i. (2D) Return the face index of boundary element i. (3D) */ int GetBdrElementEdgeIndex(int i) const; // Strange name - int GetBdrFace(int i) const; // Does the same as above better name?? + int GetBdrFace(int i)const; // Does the same as above /// Generates the face to bdr mapping. (-1 if no match). void GenerateFaceBdrMap(); diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index 4bfcd9059b..0ff3e67d49 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) if (ref_levels < 0) { ref_levels = - (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); + (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); } for (int l = 0; l < ref_levels; l++) @@ -324,7 +324,7 @@ int main(int argc, char *argv[]) LinearForm *b = new LinearForm(fespace); b->AddDomainIntegrator(new DomainLFIntegrator(one)); if (!strongBC) - b->AddBdrFaceIntegrator( + b->AddBdrFaceIntegrator( new DGDirichletLFIntegrator(zero, one, -1.0, kappa)); b->Assemble(); @@ -348,7 +348,9 @@ int main(int argc, char *argv[]) } if (!strongBC) + { a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa)); + } // 9. Assemble the bilinear form and the corresponding linear system, // applying any necessary transformations such as: eliminating boundary From 40d9185c8b47bc607ee4a3a1889d7edcbd65a38c Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 8 Apr 2020 17:53:17 +0200 Subject: [PATCH 146/535] Updating changelog and comments --- CHANGELOG | 4 ++++ miniapps/nurbs/nurbs_ex1.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index e00a8f7575..54231b708a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,10 +24,14 @@ New and updated examples and miniapps stitching together opposite surfaces of a mesh to create a topologically periodic mesh. +- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp + Discretization improvements --------------------------- - Added support for simplices in GSLIB-FindPoints. +- Added support face integrals on the boundaries of NURBS meshes. + Improved testing ---------------- - Added a GitLab pipeline that automates PR testing on supercomputing systems diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index 0ff3e67d49..d590bab128 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -14,6 +14,7 @@ // Description: This example code demonstrates the use of MFEM to define a // simple finite element discretization of the Laplace problem // -Delta u = 1 with homogeneous Dirichlet boundary conditions. +// The boundary conditions can be enforced either strongly or weakly. // Specifically, we discretize using a FE space of the specified // order, or if order < 1 using an isoparametric/isogeometric // space (i.e. quadratic for quadratic curvilinear mesh, NURBS for From 52405412dbca0741bd409ce53b61f614d032c3c3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 09:56:50 -0700 Subject: [PATCH 147/535] Make FaceGeom a reference and add @deprecated comments. --- fem/eltrans.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index b91f90fad2..c5f50cdd81 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -376,11 +376,15 @@ private: int side; public: - int Elem1No, Elem2No, FaceGeom; - ElementTransformation *Elem1, *Elem2, *Face; + int Elem1No, Elem2No; + /// @deprecated Use GetGeometryType instead + Geometry::Type &FaceGeom; + ElementTransformation *Elem1, *Elem2; + /// @deprecated No longer necessary + ElementTransformation *Face; IntegrationPointTransformation Loc1, Loc2; - FaceElementTransformations() : side(2), Face(this) {} + FaceElementTransformations() : side(2), FaceGeom(geom), Face(this) {} /** FaceElementTransformations objects are often used when performing the surface integrals on the interfaces between From bb25ac674c4049d5eeda7a26ec325b5959c73102 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 09:58:01 -0700 Subject: [PATCH 148/535] Move a call to GetBdrElementDofs to avoid unneeded function call in DG context --- fem/gridfunc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 77a831e1b4..63a7c381c4 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -644,7 +644,6 @@ double GridFunction::GetValue(ElementTransformation &T, } else if (T.ElementType == ElementTransformation::BDR_ELEMENT) { - fes->GetBdrElementDofs(T.ElementNo, dofs); fe = fes->GetBE(T.ElementNo); if (fe == NULL) @@ -659,6 +658,11 @@ double GridFunction::GetValue(ElementTransformation &T, } return GetValue(*FET, ip, comp); } + else + { + /// Not a DG field so we can simply grab the DoFs. + fes->GetBdrElementDofs(T.ElementNo, dofs); + } } else if (T.ElementType == ElementTransformation::FACE) { From a8d146622eebd24431b6b88c9ff44d38af0f3e19 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 09:58:33 -0700 Subject: [PATCH 149/535] FaceGeom is a reference so we don't need to set it this way. --- mesh/mesh.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 941d325226..73125ee4a6 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -484,12 +484,6 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr) FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute(); FTr->ElementNo = FaceNo; FTr->ElementType = ElementTransformation::FACE; - FaceElementTransformations * FETr = - dynamic_cast(FTr); - if (FETr) - { - FETr->FaceGeom = GetFaceGeometryType(FaceNo); - } DenseMatrix &pm = FTr->GetPointMat(); if (Nodes == NULL) { From 8436ce39bd25d999a90a585e72d435c90dc41691 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 10:46:27 -0700 Subject: [PATCH 150/535] Reproducing the effect of the mask when setting up the FaceElementTransformation --- mesh/mesh.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 73125ee4a6..b821e9e058 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -898,8 +898,15 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, } // setup the face transformation - GetFaceTransformation(FaceNo, &FaceElemTr); - + if (mask & 16) + { + GetFaceTransformation(FaceNo, &FaceElemTr); + } + else + { + FaceElemTr.FaceGeom = GetFaceGeometryType(FaceNo); + } + // setup Loc1 & Loc2 int face_type = GetFaceElementType(FaceNo); if (mask & 4) From 5f090c9542e7f51733a48e6c25e9b6960b16136c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 10:57:22 -0700 Subject: [PATCH 151/535] Adding `const GridFunction*` from PR #716 to `GridFunctionCoefficient` classes --- fem/coefficient.cpp | 14 +++++++------- fem/coefficient.hpp | 40 ++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 8e814895ae..1cea8b7967 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -160,13 +160,13 @@ void VectorArrayCoefficient::Eval(Vector &V, ElementTransformation &T, } VectorGridFunctionCoefficient::VectorGridFunctionCoefficient ( - GridFunction *gf) + const GridFunction *gf) : VectorCoefficient ((gf) ? gf -> VectorDim() : 0) { GridFunc = gf; } -void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf) +void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) { GridFunc = gf; vdim = (gf) ? gf -> VectorDim() : 0; } @@ -184,14 +184,14 @@ void VectorGridFunctionCoefficient::Eval( } GradientGridFunctionCoefficient::GradientGridFunctionCoefficient ( - GridFunction *gf) + const GridFunction *gf) : VectorCoefficient((gf) ? gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0) { GridFunc = gf; } -void GradientGridFunctionCoefficient::SetGridFunction(GridFunction *gf) +void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) { GridFunc = gf; vdim = (gf) ? gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0; @@ -210,14 +210,14 @@ void GradientGridFunctionCoefficient::Eval( } CurlGridFunctionCoefficient::CurlGridFunctionCoefficient ( - GridFunction *gf) + const GridFunction *gf) : VectorCoefficient ((gf) ? gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0) { GridFunc = gf; } -void CurlGridFunctionCoefficient::SetGridFunction(GridFunction *gf) +void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) { GridFunc = gf; vdim = (gf) ? gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0; @@ -230,7 +230,7 @@ void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, } DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient ( - GridFunction *gf) : Coefficient() + const GridFunction *gf) : Coefficient() { GridFunc = gf; } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 65a4d7e591..bddfe07aac 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -164,18 +164,18 @@ class GridFunction; class GridFunctionCoefficient : public Coefficient { private: - GridFunction *GridF; + const GridFunction *GridF; int Component; public: GridFunctionCoefficient() : GridF(NULL), Component(1) { } /** Construct GridFunctionCoefficient from a given GridFunction, and optionally specify a component to use if it is a vector GridFunction. */ - GridFunctionCoefficient (GridFunction *gf, int comp = 1) + GridFunctionCoefficient (const GridFunction *gf, int comp = 1) { GridF = gf; Component = comp; } - void SetGridFunction(GridFunction *gf) { GridF = gf; } - GridFunction * GetGridFunction() const { return GridF; } + void SetGridFunction(const GridFunction *gf) { GridF = gf; } + const GridFunction * GetGridFunction() const { return GridF; } virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); @@ -400,14 +400,14 @@ public: class VectorGridFunctionCoefficient : public VectorCoefficient { protected: - GridFunction *GridFunc; + const GridFunction *GridFunc; public: VectorGridFunctionCoefficient() : VectorCoefficient(0), GridFunc(NULL) { } - VectorGridFunctionCoefficient(GridFunction *gf); + VectorGridFunctionCoefficient(const GridFunction *gf); - void SetGridFunction(GridFunction *gf); - GridFunction * GetGridFunction() const { return GridFunc; } + void SetGridFunction(const GridFunction *gf); + const GridFunction * GetGridFunction() const { return GridFunc; } virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -422,13 +422,13 @@ public: class GradientGridFunctionCoefficient : public VectorCoefficient { protected: - GridFunction *GridFunc; + const GridFunction *GridFunc; public: - GradientGridFunctionCoefficient(GridFunction *gf); + GradientGridFunctionCoefficient(const GridFunction *gf); - void SetGridFunction(GridFunction *gf); - GridFunction * GetGridFunction() const { return GridFunc; } + void SetGridFunction(const GridFunction *gf); + const GridFunction * GetGridFunction() const { return GridFunc; } virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -443,13 +443,13 @@ public: class CurlGridFunctionCoefficient : public VectorCoefficient { protected: - GridFunction *GridFunc; + const GridFunction *GridFunc; public: - CurlGridFunctionCoefficient(GridFunction *gf); + CurlGridFunctionCoefficient(const GridFunction *gf); - void SetGridFunction(GridFunction *gf); - GridFunction * GetGridFunction() const { return GridFunc; } + void SetGridFunction(const GridFunction *gf); + const GridFunction * GetGridFunction() const { return GridFunc; } using VectorCoefficient::Eval; virtual void Eval(Vector &V, ElementTransformation &T, @@ -462,13 +462,13 @@ public: class DivergenceGridFunctionCoefficient : public Coefficient { protected: - GridFunction *GridFunc; + const GridFunction *GridFunc; public: - DivergenceGridFunctionCoefficient(GridFunction *gf); + DivergenceGridFunctionCoefficient(const GridFunction *gf); - void SetGridFunction(GridFunction *gf) { GridFunc = gf; } - GridFunction * GetGridFunction() const { return GridFunc; } + void SetGridFunction(const GridFunction *gf) { GridFunc = gf; } + const GridFunction * GetGridFunction() const { return GridFunc; } virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); From 5fc741c7316c6e75754f173b65b195578dfeaf65 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 10:57:40 -0700 Subject: [PATCH 152/535] make style --- mesh/mesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index b821e9e058..32440aba4b 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -906,7 +906,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, { FaceElemTr.FaceGeom = GetFaceGeometryType(FaceNo); } - + // setup Loc1 & Loc2 int face_type = GetFaceElementType(FaceNo); if (mask & 4) From b0ddd613fd81762f341c342643662ed1e997d0df Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 8 Apr 2020 11:24:17 -0700 Subject: [PATCH 153/535] Adding doxygen warnings to GetValue(int i,...) methods --- fem/eltrans.hpp | 6 ++---- fem/gridfunc.hpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index c5f50cdd81..a17d98fccc 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -377,11 +377,9 @@ private: public: int Elem1No, Elem2No; - /// @deprecated Use GetGeometryType instead - Geometry::Type &FaceGeom; + Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead ElementTransformation *Elem1, *Elem2; - /// @deprecated No longer necessary - ElementTransformation *Face; + ElementTransformation *Face; ///< @deprecated No longer necessary IntegrationPointTransformation Loc1, Loc2; FaceElementTransformations() : side(2), FaceGeom(geom), Face(this) {} diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 81c007deea..93328392d5 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -146,6 +146,14 @@ public: These methods take an element index and return the interpolated value of the field at a given reference point within the element. + + @warning These methods retrieve and use the + ElementTransformation object from the mfem::Mesh. This can + alter the state of the ElementTransformation object. This can + lead to unexpected results when the ElementTransformation + object is already in use such as when these methods are called + from within an integration loop. Consider using + GetValue(ElementTransformation &T, ...) instead. */ ///@{ /** Return a scalar value from within the given element. */ @@ -163,6 +171,14 @@ public: methods are optimized and should perform better than repeatedly calling GetValue. The GetVectorValues method simply calls GetVectorValue repeatedly. + + @warning These methods retrieve and use the + ElementTransformation object from the mfem::Mesh. This can + alter the state of the ElementTransformation object. This can + lead to unexpected results when the ElementTransformation + object is already in use such as when these methods are called + from within an integration loop. Consider using + GetValues(ElementTransformation &T, ...) instead. */ ///@{ /** Compute a collection of scalar values from within the element @@ -186,6 +202,11 @@ public: ElementTransformation objects coming from either Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation(). + + @note These methods do not reset the ElementTransformation + object so they should be safe to use within integration loops + or other contexts where the ElementTransformation is already in + use. */ ///@{ /** Return a scalar value from within the element indicated by the @@ -209,6 +230,11 @@ public: Mesh::GetFaceElementTransformations(), Mesh::GetInteriorFaceElementTransformations(), or Mesh::GetBdrFaceElementTransformations(). + + @note These methods do not reset the FaceElementTransformations + object so they should be safe to use within integration loops + or other contexts where the FaceElementTransformations is + already in use. */ ///@{ /** Return a scalar value from within the face indicated by the @@ -225,7 +251,7 @@ public: Vector &val, Vector *tr = NULL) const; ///@} - /** ElementTransformation Get Values Methods + /** @name ElementTransformation Get Values Methods These are convenience methods for repeatedly calling GetValue for multiple points within a given element. They work by @@ -233,6 +259,14 @@ public: FaceElementTransformations versions described above. Consequently, these methods should not be expected to run faster than calling the above methods in an external loop. + + @note These methods do not reset the ElementTransformation + object so they should be safe to use within integration loops + or other contexts where the ElementTransformation is already in + use. + + @note These methods can also be used wtih + FaceElementTransformations objects. */ ///@{ /** Compute a collection of scalar values from within the element @@ -256,6 +290,15 @@ public: (automatically chosen). See the FaceElementTransformations documentation in eltrans.hpp for more information on the \a side parameter. + + @warning These methods retrieve and use the + FaceElementTransformations object from the mfem::Mesh. This + can alter the state of the FaceElementTransformations object. + This can lead to unexpected results when the + FaceElementTransformations object is already in use such as + when these methods are called from within an integration loop. + Consider using GetValues(ElementTransformation &T, ...) + instead. */ ///@{ /** Compute a collection of scalar values from within the face From 17d7a117c10f2b1936fa8c16d323d214cdfcdf22 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Wed, 8 Apr 2020 15:19:15 -0700 Subject: [PATCH 154/535] Added to the doc generated files to .gitignore. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8af8173131..855885eb5d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,8 @@ config/sample-runs-build.log doc/CodeDocumentation.conf doc/CodeDocumentation.html doc/CodeDocumentation +doc/undoc.log +doc/warnings.log # Temporary files created by the tests. *.stderr From 07f9bece016892e7bf9ad9e6c917c572f44618ca Mon Sep 17 00:00:00 2001 From: Tomov Date: Wed, 8 Apr 2020 19:49:02 -0700 Subject: [PATCH 155/535] Interpolation of the zeta function after mesh update. --- fem/tmop.cpp | 40 +++++++++++++++++++++++++--- fem/tmop.hpp | 12 ++++++++- fem/tmop_tools.cpp | 2 ++ miniapps/meshing/pmesh-optimizer.cpp | 32 ++++++++++++++++------ 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 18e44327ff..abb8ac4667 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1212,11 +1212,35 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, } } +void TMOP_Integrator::EnableDiscrAdaptiveLimiting(const GridFunction &xi0_gf, + GridFunction &zeta_gf) +{ + xi_0 = &xi0_gf; + zeta = &zeta_gf; + adapt_eval = new AdvectorCG; + adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(), + *zeta->FESpace()->FEColl(), 1); + adapt_eval->SetInitialField + (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); +} + +void TMOP_Integrator::EnableDiscrAdaptiveLimiting(const ParGridFunction &xi0_gf, + ParGridFunction &zeta_gf) +{ + xi_0 = &xi0_gf; + zeta = &zeta_gf; + adapt_eval = new AdvectorCG; + adapt_eval->SetParMetaInfo(*zeta_gf.ParFESpace()->GetParMesh(), + *zeta_gf.ParFESpace()->FEColl(), 1); + adapt_eval->SetInitialField + (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); +} + double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, ElementTransformation &T, const Vector &elfun) { - int dof = el.GetDof(), dim = el.GetDim(); + const int dof = el.GetDof(), dim = el.GetDim(); double energy; DSh.SetSize(dof, dim); @@ -1300,11 +1324,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, lim_func->Eval(p, p0, d_vals(i)) * coeff0->Eval(*Tpr, ip); } - if (xi_0) + if (zeta) { // Adaptive limiting. const double diff = - xi_0->GetValue(T.ElementNo, ip) - xi->Eval(*Tpr, ip); + xi_0->GetValue(T.ElementNo, ip) - zeta->GetValue(T.ElementNo, ip); val += 10.0 * lim_normal * diff * diff; } @@ -1773,6 +1797,16 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x, dx = detv_avg_min / dxscale; } +void TMOP_Integrator::UpdateAfterMeshChange(const Vector &new_x) +{ + std::cout << "Update 1 " << zeta->Norml2() << std::endl; + // Update zeta if adaptive limiting is enabled. + + if (zeta) { adapt_eval->ComputeAtNewPosition(new_x, *zeta); } + + std::cout << "Update 2 " << zeta->Norml2() << std::endl; +} + void TMOP_Integrator::ComputeFDh(const Vector &x, const FiniteElementSpace &fes) { if (!fdflag) { return; } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 56aa9af534..3d0ff8c6bf 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -812,6 +812,8 @@ protected: // Adaptive limiting. const GridFunction *xi_0; + GridFunction *zeta; + AdaptivityEvaluator *adapt_eval; Coefficient *xi; DiscreteAdaptTC *discr_tc; @@ -869,6 +871,8 @@ protected: #endif void ComputeMinJac(const Vector &x, const FiniteElementSpace &fes); + void UpdateAfterMeshChange(const Vector &new_x); + public: /** @param[in] m TMOP_QualityMetric that will be integrated (not owned). @param[in] tc Target-matrix construction algorithm to use (not owned). */ @@ -877,7 +881,7 @@ public: coeff1(NULL), metric_normal(1.0), nodes0(NULL), coeff0(NULL), lim_dist(NULL), lim_func(NULL), lim_normal(1.0), - xi_0(NULL), xi(NULL), + xi_0(NULL), zeta(NULL), xi(NULL), discr_tc(dynamic_cast(tc)), fdflag(false), dxscale(1.0e3) { } @@ -925,6 +929,12 @@ public: xi_0 = &xi0_gf; xi = &xi_coeff; } + void EnableDiscrAdaptiveLimiting(const GridFunction &xi0_gf, + GridFunction &zeta_gf); + #ifdef MFEM_USE_MPI + void EnableDiscrAdaptiveLimiting(const ParGridFunction &xi0_gf, + ParGridFunction &zeta_gf); + #endif /// Update the original/reference nodes used for limiting. void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; } diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index ee5b08f74d..f6f39e7aca 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -424,6 +424,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const TMOP_Integrator *tmopi = dynamic_cast(integs[i]); DiscreteAdaptTC *discrtc = tmopi->GetDiscreteAdaptTC(); tmopi->ComputeFDh(x_loc, *pfesc); + tmopi->UpdateAfterMeshChange(x_loc); if (discrtc) { discrtc->UpdateTargetSpecification(x_loc); @@ -459,6 +460,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const TMOP_Integrator *tmopi = dynamic_cast(integs[i]); DiscreteAdaptTC *discrtc = tmopi->GetDiscreteAdaptTC(); tmopi->ComputeFDh(x_loc, *fesc); + tmopi->UpdateAfterMeshChange(x_loc); if (discrtc) { discrtc->UpdateTargetSpecification(x); diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 1d838d312f..cf44c6353b 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -31,6 +31,9 @@ // // Compile with: make pmesh-optimizer // +// Adaptive limiting test: +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -fd -al +// // Sample runs: // Adapted analytic Hessian: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 @@ -308,6 +311,7 @@ int main (int argc, char *argv[]) bool visualization = true; int verbosity_level = 0; bool fdscheme = false; + bool adapt_lim = false; // 2. Parse command-line options. OptionsParser args(argc, argv); @@ -375,6 +379,8 @@ int main (int argc, char *argv[]) "Make all terms in the optimization functional unitless."); args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", "Enable finite difference based derivative computations."); + args.AddOption(&adapt_lim, "-al", "--adapt-limit", "no-ad", "no-adapt-limit", + "Enable adaptive limiting."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -616,12 +622,17 @@ int main (int argc, char *argv[]) // Adaptive limiting. ParGridFunction xi_0; + ParGridFunction zeta(&ind_fes); xi_0.SetSpace(&ind_fes); FunctionCoefficient alim_coeff(adapt_lim_fun); + zeta.ProjectCoefficient(alim_coeff); xi_0.ProjectCoefficient(alim_coeff); - he_nlf_integ->EnableAnalyticAdaptiveLimiting(xi_0, alim_coeff); - socketstream vis1; - common::VisualizeField(vis1, "localhost", 19916, xi_0, "Xi 0", 300, 600, 300, 300); + if (adapt_lim) + { + he_nlf_integ->EnableDiscrAdaptiveLimiting(xi_0, zeta); + socketstream vis1; + common::VisualizeField(vis1, "localhost", 19916, zeta, "Zeta 0", 300, 600, 300, 300); + } // 15. Setup the final NonlinearForm (which defines the integral of interest, // its first and second derivatives). Here we can use a combination of @@ -851,8 +862,11 @@ int main (int argc, char *argv[]) vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 600); } - socketstream vis0; - common::VisualizeField(vis0, "localhost", 19916, xi_0, "Xi 0", 600, 600, 300, 300); + if (adapt_lim) + { + socketstream vis0; + common::VisualizeField(vis0, "localhost", 19916, xi_0, "Xi 0", 600, 600, 300, 300); + } // 23. Visualize the mesh displacement. if (visualization) @@ -903,9 +917,11 @@ double weight_fun(const Vector &x) double adapt_lim_fun(const Vector &x) { - const double X = x(0), Y = x(1); - double val = std::tanh((10*(Y-0.5) + std::cos(3.0*M_PI*X)) + 1) - - std::tanh((10*(Y-0.5) + std::cos(3.0*M_PI*X)) - 1); + const double xc = x(0) - 0.1, yc = x(1) - 0.2; + const double r = sqrt(xc*xc + yc*yc); + double r1 = 0.45; double r2 = 0.55; double sf=30.0; + double val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); + val = std::max(0.,val); val = std::min(1.,val); return val; From 7a49e839db466fd5e8abf0acd0831b5165d0cc79 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 9 Apr 2020 12:12:06 +0200 Subject: [PATCH 156/535] Modify parallel case to mirror serrial: adding weakbcs a.o. --- miniapps/nurbs/nurbs_ex1p.cpp | 44 ++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1p.cpp b/miniapps/nurbs/nurbs_ex1p.cpp index 8d37e8d2e8..0f32a20a4d 100644 --- a/miniapps/nurbs/nurbs_ex1p.cpp +++ b/miniapps/nurbs/nurbs_ex1p.cpp @@ -143,21 +143,32 @@ int main(int argc, char *argv[]) // 2. Parse command-line options. const char *mesh_file = "../../data/star.mesh"; + int ref_levels = -1; Array order(1); order[0] = 1; bool static_cond = false; bool visualization = 1; bool ibp = 1; + bool strongBC = 1; + double kappa = -1; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); + args.AddOption(&ref_levels, "-r", "--refine", + "Number of times to refine the mesh uniformly, -1 for auto."); args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree) or -1 for" " isoparametric space."); args.AddOption(&ibp, "-ibp", "--ibp", "-no-ibp", "--no-ibp", "Selects the standard weak form (IBP) or the nonstandard (NO-IBP)."); + args.AddOption(&strongBC, "-sbc", "--strong-bc", "-wbc", + "--weak-bc", + "Selects strong or weak enforcement of Dirichlet BCs."); + args.AddOption(&kappa, "-k", "--kappa", + "One of the two DG penalty parameters, should be positive." + " Negative values are replaced with (order+1)^2."); args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", "--no-static-condensation", "Enable static condensation."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", @@ -173,6 +184,10 @@ int main(int argc, char *argv[]) MPI_Finalize(); return 1; } + if (!strongBC & (kappa < 0)) + { + kappa = (order.Max()+1)*(order.Max()+1); + } if (myid == 0) { args.PrintOptions(cout); @@ -189,12 +204,18 @@ int main(int argc, char *argv[]) // 'ref_levels' to be the largest number that gives a final mesh with no // more than 10,000 elements. { - int ref_levels = - (int)floor(log(10000./mesh->GetNE())/log(2.)/dim); + if (ref_levels < 0) + { + ref_levels = + (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); + } + for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); } + + mesh->PrintInfo(); } // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine @@ -299,11 +320,18 @@ int main(int argc, char *argv[]) // 8. Set up the parallel linear form b(.) which corresponds to the // right-hand side of the FEM linear system, which in this case is // (1,phi_i) where phi_i are the basis functions in fespace. - ParLinearForm *b = new ParLinearForm(fespace); ConstantCoefficient one(1.0); - b->AddDomainIntegrator(new DomainLFIntegrator(one)); - b->Assemble(); + ConstantCoefficient zero(0.0); + ParLinearForm *b = new ParLinearForm(fespace); + b->AddDomainIntegrator(new DomainLFIntegrator(one)); + + if (!strongBC) + b->AddBdrFaceIntegrator( + new DGDirichletLFIntegrator(zero, one, -1.0, kappa)); +std::cout<<333<Assemble(); +std::cout<<334<AddDomainIntegrator(new Diffusion2Integrator(one)); } - + if (!strongBC) + { + a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa)); + } +std::cout<<355< Date: Thu, 9 Apr 2020 12:13:06 +0200 Subject: [PATCH 157/535] Corrections to get parallel working: Generate call needs to move to correct location --- fem/fespace.cpp | 1 + fem/pfespace.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index cbe20cb49d..ad8eec0333 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1938,6 +1938,7 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const if (NURBSext) { + mesh->GenerateFaceBdrMap(); NURBSext->LoadBE(mesh->GetFaceBdr(i), fe); } diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp index eee508a2c5..39f3af3493 100644 --- a/fem/pfespace.cpp +++ b/fem/pfespace.cpp @@ -488,7 +488,7 @@ void ParFiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const void ParFiniteElementSpace::GetFaceDofs(int i, Array &dofs) const { FiniteElementSpace::GetFaceDofs(i, dofs); - if (Conforming()) + if (Conforming() & !NURBSext) { ApplyLDofSigns(dofs); } From 1c4155dc7bcecffecdbb96dd0758db3ca7bcc221 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Thu, 9 Apr 2020 08:59:11 -0700 Subject: [PATCH 158/535] minor fix to findpts --- fem/gslib.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 013777c845..2c96bb0b37 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -159,17 +159,19 @@ void FindPointsGSLIB::Interpolate(Array &codes, Vector node_vals; const int ncomp = field_in.FESpace()->GetVDim(), - points_cnt = field_in.Size() / ncomp; + points_fld = field_in.Size() / ncomp, + points_cnt = codes.Size(); for (int i = 0; i < ncomp; i++) { - int dataptr = i*points_cnt; - field_in_scalar.SetData(field_in.GetData()+dataptr); + const int dataptrin = i*points_fld, + dataptrout = i*points_cnt; + field_in_scalar.SetData(field_in.GetData()+dataptrin); GetNodeValues(field_in_scalar, node_vals); if (dim==2) { - findpts_eval_2(field_out.GetData()+dataptr, sizeof(double), + findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double), codes.GetData(), sizeof(unsigned int), proc_ids.GetData(), sizeof(unsigned int), elem_ids.GetData(), sizeof(unsigned int), @@ -178,7 +180,7 @@ void FindPointsGSLIB::Interpolate(Array &codes, } else { - findpts_eval_3(field_out.GetData()+dataptr, sizeof(double), + findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double), codes.GetData(), sizeof(unsigned int), proc_ids.GetData(), sizeof(unsigned int), elem_ids.GetData(), sizeof(unsigned int), From af0fce3d7352f9ac29b2ae2009d8705ee9a03999 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 9 Apr 2020 18:15:02 +0200 Subject: [PATCH 159/535] Remove debug statements --- miniapps/nurbs/nurbs_ex1p.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1p.cpp b/miniapps/nurbs/nurbs_ex1p.cpp index 0f32a20a4d..a5c6808cfd 100644 --- a/miniapps/nurbs/nurbs_ex1p.cpp +++ b/miniapps/nurbs/nurbs_ex1p.cpp @@ -329,9 +329,8 @@ int main(int argc, char *argv[]) if (!strongBC) b->AddBdrFaceIntegrator( new DGDirichletLFIntegrator(zero, one, -1.0, kappa)); -std::cout<<333<Assemble(); -std::cout<<334<AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa)); } -std::cout<<355< Date: Thu, 9 Apr 2020 18:28:27 +0200 Subject: [PATCH 160/535] Small typo --- CHANGELOG | 2 +- mesh/mesh.cpp | 32 -------------------------------- mesh/mesh.hpp | 10 +--------- 3 files changed, 2 insertions(+), 42 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 54231b708a..cf6284f164 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,7 +24,7 @@ New and updated examples and miniapps stitching together opposite surfaces of a mesh to create a topologically periodic mesh. -- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp +- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp. Discretization improvements --------------------------- diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index d660567aaa..475e1eb4e0 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -2335,8 +2335,6 @@ void Mesh::FinalizeTopology(bool generate_bdr) GenerateFaces(); } - if (NURBSext) { GenerateFaceBdrMap(); } - if (ncmesh) { // tell NCMesh the numbering of edges/faces @@ -3826,8 +3824,6 @@ void Mesh::UpdateNURBS() GetElementToFaceTable(); GenerateFaces(); } - - GenerateFaceBdrMap(); } void Mesh::LoadPatchTopo(std::istream &input, Array &edge_to_knot) @@ -4810,34 +4806,6 @@ int Mesh::GetBdrElementEdgeIndex(int i) const return -1; } -int Mesh::GetBdrFace(int i) const -{ - switch (Dim) - { - case 1: return boundary[i]->GetVertices()[0]; - case 2: return be_to_edge[i]; - case 3: return be_to_face[i]; - default: mfem_error("Mesh::GetBdrFace: invalid dimension!"); - } - return -1; -} - -void Mesh::GenerateFaceBdrMap() -{ - int fm = NumOfFaces; - for (int j = 0; j < NumOfBdrElements; j++) - { - fm = std::max(GetBdrFace(j),fm); - } - - face_to_be.SetSize(fm+1); - face_to_be = -1; - for (int j = 0; j < NumOfBdrElements; j++) - { - face_to_be[GetBdrFace(j)] = j; - } -} - void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const { int fid = GetBdrElementEdgeIndex(bdr_el); diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index fab8b12452..436c493ac4 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -147,7 +147,6 @@ protected: Array be_to_edge; // for 2D Table *bel_to_edge; // for 3D Array be_to_face; - Array face_to_be; mutable Table *face_edge; mutable Table *edge_vertex; @@ -888,14 +887,7 @@ public: /** Return the vertex index of boundary element i. (1D) Return the edge index of boundary element i. (2D) Return the face index of boundary element i. (3D) */ - int GetBdrElementEdgeIndex(int i) const; // Strange name - int GetBdrFace(int i)const; // Does the same as above - - /// Generates the face to bdr mapping. (-1 if no match). - void GenerateFaceBdrMap(); - - /// Return the bdr indices of a face i. (-1 if no match). - int GetFaceBdr(int i) { return face_to_be[i]; } + int GetBdrElementEdgeIndex(int i) const; /** @brief For the given boundary element, bdr_el, return its adjacent element and its info, i.e. 64*local_bdr_index+bdr_orientation. */ From d30214149689443c4838fe8041c54616f136e465 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 9 Apr 2020 18:29:42 +0200 Subject: [PATCH 161/535] Adding face dofs --- fem/fespace.cpp | 50 +++++++++++++++++++++++++++++++++++++------------ fem/fespace.hpp | 8 +++++++- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index ad8eec0333..51d31be554 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -6,7 +6,7 @@ // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file +// terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. // Implementation of FiniteElementSpace @@ -60,7 +60,7 @@ FiniteElementSpace::FiniteElementSpace() : mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES), ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0), fdofs(NULL), bdofs(NULL), - elem_dof(NULL), bdrElem_dof(NULL), + elem_dof(NULL), bdrElem_dof(NULL), face_dof(NULL), NURBSext(NULL), own_ext(false), cP(NULL), cR(NULL), cP_is_set(false), Th(Operator::ANY_TYPE), @@ -1469,6 +1469,31 @@ void FiniteElementSpace::UpdateNURBS() ndofs = NURBSext->GetNDof(); elem_dof = NURBSext->GetElementDofTable(); bdrElem_dof = NURBSext->GetBdrElementDofTable(); + face_dof = NULL;// NURBSext->GetFaceDofTable(); +} + +void FiniteElementSpace::GenerateFaceDofs() +{ + if (face_dof) return; + + Array face_dof_list; + Array row; + face_to_be.SetSize(mesh->GetNumFaces()); + for (int b = 0; b < bdrElem_dof->Size(); b++) + { + bdrElem_dof->GetRow(b, row); + int f = mesh->GetBdrElementEdgeIndex(b); + face_to_be[f] = b; + Connection conn(f,0); + for (int i = 0; i < row.Size(); i++) + { + conn.to = row[i]; + face_dof_list.Append(conn); + } + } + face_dof_list.Sort(); + face_dof_list.Unique(); + face_dof = new Table(mesh->GetNumFaces(), face_dof_list); } void FiniteElementSpace::Construct() @@ -1478,6 +1503,7 @@ void FiniteElementSpace::Construct() elem_dof = NULL; bdrElem_dof = NULL; + face_dof = NULL; ndofs = 0; nedofs = nfdofs = nbdofs = 0; @@ -1741,13 +1767,14 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const { - /*if (face_dof) - { - face_dof->GetRow(i, dofs); - }*/ if (NURBSext) { - GetBdrElementDofs(mesh->GetFaceBdr(i),dofs); + const_cast(this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT + } + + if (face_dof) + { + face_dof->GetRow(i, dofs); } else { @@ -1933,13 +1960,10 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i)); } - // if (NURBSext) - // NURBSext->LoadFaceElement(i, fe); - if (NURBSext) { - mesh->GenerateFaceBdrMap(); - NURBSext->LoadBE(mesh->GetFaceBdr(i), fe); + const_cast(this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT + NURBSext->LoadBE(face_to_be[i], fe); } return fe; @@ -1994,11 +2018,13 @@ void FiniteElementSpace::Destroy() if (NURBSext) { if (own_ext) { delete NURBSext; } + delete face_dof; } else { delete elem_dof; delete bdrElem_dof; + delete face_dof; delete [] bdofs; delete [] fdofs; diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 27ef1335f6..2b11a6cecc 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -6,7 +6,7 @@ // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file +// terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. #ifndef MFEM_FESPACE @@ -111,6 +111,8 @@ protected: mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned. Table *bdrElem_dof; // used only with NURBS FE spaces; not owned. + Table *face_dof; // used only with NURBS FE spaces; + Array face_to_be; // used only with NURBS FE spaces; Array dof_elem_array, dof_ldof_array; @@ -523,6 +525,8 @@ public: const Table &GetElementToDofTable() const { return *elem_dof; } const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; } + const Table &GetFaceToDofTable() const { return *face_dof; } + int GetElementForDof(int i) const { return dof_elem_array[i]; } int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; } @@ -669,6 +673,8 @@ public: FiniteElementCollection *Load(Mesh *m, std::istream &input); virtual ~FiniteElementSpace(); + + void GenerateFaceDofs(); }; From c88f75bbfc44a5befa760af415119b04c57b9a8e Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 9 Apr 2020 18:33:07 +0200 Subject: [PATCH 162/535] Symmetrice the pfespace code --- fem/pfespace.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp index 39f3af3493..b642dbab66 100644 --- a/fem/pfespace.cpp +++ b/fem/pfespace.cpp @@ -487,8 +487,13 @@ void ParFiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const void ParFiniteElementSpace::GetFaceDofs(int i, Array &dofs) const { + if (face_dof) + { + face_dof->GetRow(i, dofs); + return; + } FiniteElementSpace::GetFaceDofs(i, dofs); - if (Conforming() & !NURBSext) + if (Conforming()) { ApplyLDofSigns(dofs); } From c8b773712ddb8239b3eaa12f41bc25f821a087e0 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 9 Apr 2020 18:35:01 +0200 Subject: [PATCH 163/535] make style --- fem/fespace.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 51d31be554..b47de11199 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1474,22 +1474,22 @@ void FiniteElementSpace::UpdateNURBS() void FiniteElementSpace::GenerateFaceDofs() { - if (face_dof) return; + if (face_dof) { return; } Array face_dof_list; Array row; face_to_be.SetSize(mesh->GetNumFaces()); for (int b = 0; b < bdrElem_dof->Size(); b++) { - bdrElem_dof->GetRow(b, row); - int f = mesh->GetBdrElementEdgeIndex(b); - face_to_be[f] = b; - Connection conn(f,0); - for (int i = 0; i < row.Size(); i++) - { - conn.to = row[i]; - face_dof_list.Append(conn); - } + bdrElem_dof->GetRow(b, row); + int f = mesh->GetBdrElementEdgeIndex(b); + face_to_be[f] = b; + Connection conn(f,0); + for (int i = 0; i < row.Size(); i++) + { + conn.to = row[i]; + face_dof_list.Append(conn); + } } face_dof_list.Sort(); face_dof_list.Unique(); @@ -1769,7 +1769,8 @@ void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const if (NURBSext) { - const_cast(this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT + const_cast + (this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT } if (face_dof) @@ -1962,7 +1963,8 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const if (NURBSext) { - const_cast(this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT + const_cast + (this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT NURBSext->LoadBE(face_to_be[i], fe); } From e262fcf98818672e3bb3c56e0a23bb9f8f5e1429 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Thu, 9 Apr 2020 13:33:24 -0700 Subject: [PATCH 164/535] Added Andrew's documentation for the templated code. --- fem/tbilinearform.hpp | 39 ++++-- fem/tbilininteg.hpp | 267 +++++++++++++++++++++--------------------- fem/tcoefficient.hpp | 21 ++-- fem/teltrans.hpp | 35 +++--- fem/tevaluator.hpp | 170 ++++++++++++++------------- fem/tfe.hpp | 25 ++++ 6 files changed, 313 insertions(+), 244 deletions(-) diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 7f31a57fbd..91f1c96c99 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -23,10 +23,22 @@ namespace mfem { -// Templated bilinear form class, cf. bilinearform.?pp +/** @brief Templated bilinear form class, cf. bilinearform.?pp // complex_t - sol dof data type + @tparam meshType typically TMesh, which is templated on FE type // real_t - mesh nodes, sol basis, mesh basis data type + @tparam solFESpace eg. H1_FiniteElementSpace + @tparam IR integration rule, typically TIntegrationRule, which is further + templated on element geometry + @tparam IntegratorType typically a TIntegrator, which is templated on a + kernel, eg. TDiffusionKernel or TMassKernel. This + describes what actual problem you solve. + @tparam solVecLayout_t describes how degrees of freedom are laid out, + scalar or vector, column/row major, etc. + @tparam complex_t data type for solution dofs + @tparam real_t data type for mesh nodes, solution basis, and mesh basis +*/ template ::type kernel_t; + /// p_assembled_t is something like a TTensor or TMatrix for partial assembly typedef typename kernel_t::template p_asm_data::type p_assembled_t; + /// f_assembled_t is something like a TTensor or TMatrix for full assembly typedef typename kernel_t::template f_asm_data::type f_assembled_t; + ///@} typedef TElementTransformation Trans_t; template struct T_result @@ -65,6 +84,10 @@ protected: typedef FieldEvaluator solFieldEval; + + /** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated on + a kernel, eg. ElementMatrix::Compute may be AssembleGradGrad()). + @tparam BE batch size of elements */ template struct S_spec { typedef typename solFieldEval::template Spec Spec; @@ -174,7 +197,7 @@ public: } } - // Partial assembly of quadrature point data + /// Partial assembly of quadrature point data void Assemble() { const int BE = 1; // batch-size of elements @@ -280,7 +303,7 @@ public: } } - // partial assembly from "serialized" nodes + /// Partial assembly from "serialized" nodes // real_t = double void AssembleFromSerializedNodes(const Vector &sNodes) { @@ -326,7 +349,7 @@ public: } } - // serialized vector sx --> serialized vector 'sy' + /// serialized vector sx --> serialized vector 'sy' // complex_t = double void MultAssembledSerialized(const Vector &sx, Vector &sy) const { @@ -350,7 +373,7 @@ public: } #endif // MFEM_TEMPLATE_ENABLE_SERIALIZE - // Assemble the operator in a SparseMatrix. + /// Assemble the operator in a SparseMatrix. // complex_t = double void AssembleMatrix(SparseMatrix &M) const { @@ -392,7 +415,7 @@ public: } } - // Assemble element matrices and store them as a DenseTensor object. + /// Assemble element matrices and store them as a DenseTensor object. // complex_t = double void AssembleMatrix(DenseTensor &M) const { @@ -430,7 +453,7 @@ public: } } - // Assemble element matrices and add them to the bilinear form + /// Assemble element matrices and add them to the bilinear form // complex_t = double void AssembleBilinearForm(BilinearForm &a) const { @@ -502,7 +525,7 @@ public: } } - // Multiplication using assembled element matrices stored as a DenseTensor. + /// Multiplication using assembled element matrices stored as a DenseTensor. // complex_t = double void AddMult(DenseTensor &M, const Vector &x, Vector &y) const { diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index 4901ac25cf..c3f4e5c1fe 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -21,8 +21,7 @@ namespace mfem // Templated local bilinear form integrator kernels, cf. bilininteg.?pp -// The Integrator class combines a kernel and a coefficient - +/// The Integrator class combines a kernel and a coefficient template class kernel_t> class TIntegrator { @@ -38,30 +37,31 @@ public: }; -// Mass kernel - +/// Mass kernel template struct TMassKernel { typedef complex_t complex_type; - // needed for the TElementTransformation::Result class + /// Needed for the TElementTransformation::Result class static const bool uses_Jacobians = true; - // needed for the FieldEvaluator::Data class + /// @name Needed for the FieldEvaluator::Data class + ///@{ static const bool in_values = true; static const bool in_gradients = false; static const bool out_values = true; static const bool out_gradients = false; + ///@} - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in partial assembly, and partially - // assembled action. + /** Partially assembled data type for one element with the given number of + quadrature points. This type is used in partial assembly, and partially + assembled action. */ template struct p_asm_data { typedef TVector type; }; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in full element matrix assembly. + /** Partially assembled data type for one element with the given number of + quadrature points. This type is used in full element matrix assembly. */ template struct f_asm_data { typedef TVector type; }; @@ -71,13 +71,12 @@ struct TMassKernel typedef typename IntRuleCoefficient::Type Type; }; - // Method used for un-assembled (matrix free) action. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // val_qpts [M x NC x NE] - in/out data member in R - // - // val_qpts *= w det(J) + /** @brief Method used for un-assembled (matrix free) action. + @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + @param Q CoefficientEval<>::Type + @param q CoefficientEval<>::Type::result_t + @param R val_qpts [M x NC x NE] - in/out data member in R + val_qpts *= w det(J) */ template static inline MFEM_ALWAYS_INLINE @@ -101,13 +100,15 @@ struct TMassKernel } } - // Method defining partial assembly. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // A [M] - partially assembled scalars - // - // A = w det(J) + /** @brief Method defining partial assembly. + Result in A is the quadrature-point dependent part of element matrix + assembly (as opposed to part that is same for all elements), + A = w det(J) + @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + @param Q CoefficientEval<>::Type + @param q CoefficientEval<>::Type::result_t + @param A [M] - partially assembled scalars + */ template static inline MFEM_ALWAYS_INLINE void Assemble(const int k, const T_result_t &F, @@ -124,11 +125,11 @@ struct TMassKernel } } - // Method for partially assembled action. - // A [M] - partially assembled scalars - // val_qpts [M x NC x NE] - in/out data member in R - // - // val_qpts *= A + /** @brief Method for partially assembled action. + @param A [M] - partially assembled scalars + @param R val_qpts [M x NC x NE] - in/out data member in R + val_qpts *= A + */ template static inline MFEM_ALWAYS_INLINE void MultAssembled(const int k, const TVector &A, S_data_t &R) @@ -148,35 +149,36 @@ struct TMassKernel }; -// Diffusion kernel - -// complex_t - type for the assembled data +/** @brief Diffusion kernel + @tparam complex_t - type for the assembled data +*/ template struct TDiffusionKernel; -// Diffusion kernel in 1D +/// Diffusion kernel in 1D template struct TDiffusionKernel<1,1,complex_t> { typedef complex_t complex_type; - // needed for the TElementTransformation::Result class + /// Needed for the TElementTransformation::Result class static const bool uses_Jacobians = true; - // needed for the FieldEvaluator::Data class + /// Needed for the FieldEvaluator::Data class static const bool in_values = false; static const bool in_gradients = true; static const bool out_values = false; static const bool out_gradients = true; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in partial assembly, and partially - // assembled action. + /** Partially assembled data type for one element with the given number of + quadrature points. This type is used in partial assembly, and partially + assembled action. */ template struct p_asm_data { typedef TMatrix type; }; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in full element matrix assembly. + + /// Partially assembled data type for one element with the given number of + /// quadrature points. This type is used in full element matrix assembly. template struct f_asm_data { typedef TTensor3 type; }; @@ -186,13 +188,12 @@ struct TDiffusionKernel<1,1,complex_t> typedef typename IntRuleCoefficient::Type Type; }; - // Method used for un-assembled (matrix free) action. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // grad_qpts [M x SDim x NC x NE] - in/out data member in R - // - // grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts + /** @brief Method used for un-assembled (matrix free) action. + @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + @param Q - CoefficientEval<>::Type + @param q - CoefficientEval<>::Type::result_t + @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R + grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts */ template static inline MFEM_ALWAYS_INLINE @@ -214,17 +215,19 @@ struct TDiffusionKernel<1,1,complex_t> } } - // Method defining partial assembly. The pointwise Dim x Dim matrices are - // stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2) - // or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3) - // matrices. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices - // A [M x Dim x Dim] - partially assembled Dim x Dim matrices - // - // A = (w/det(J)) adj(J) adj(J)^t + + /** @brief Method defining partial assembly. + The pointwise Dim x Dim matrices are stored as symmetric (when + asm_type == p_asm_data, i.e. A.layout.rank == 2) or + non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank + == 3) matrices. + @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + @param Q CoefficientEval<>::Type + @param q CoefficientEval<>::Type::result_t + @param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices + A [M x Dim x Dim] - partially assembled Dim x Dim matrices + A = (w/det(J)) adj(J) adj(J)^t + */ template static inline MFEM_ALWAYS_INLINE void Assemble(const int k, const T_result_t &F, @@ -240,13 +243,12 @@ struct TDiffusionKernel<1,1,complex_t> A[i] = Q.get(q,i,k) / F.Jt(i,0,0,k); } } - - // Method for partially assembled action. - // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric - // matrices - // grad_qpts [M x SDim x NC x NE] - in/out data member in R - // - // grad_qpts = A grad_qpts + /** @brief Method for partially assembled action. + @param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symmetric + matrices + @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R + grad_qpts = A grad_qpts + */ template static inline MFEM_ALWAYS_INLINE void MultAssembled(const int k, const TMatrix &A, @@ -266,30 +268,30 @@ struct TDiffusionKernel<1,1,complex_t> } }; -// Diffusion kernel in 2D +/// Diffusion kernel in 2D template struct TDiffusionKernel<2,2,complex_t> { typedef complex_t complex_type; - // needed for the TElementTransformation::Result class + /// Needed for the TElementTransformation::Result class static const bool uses_Jacobians = true; - // needed for the FieldEvaluator::Data class + /// Needed for the FieldEvaluator::Data class static const bool in_values = false; static const bool in_gradients = true; static const bool out_values = false; static const bool out_gradients = true; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in partial assembly, and partially - // assembled action. Stores one symmetric 2 x 2 matrix per point. + /// Partially assembled data type for one element with the given number of + /// quadrature points. This type is used in partial assembly, and partially + /// assembled action. Stores one symmetric 2 x 2 matrix per point. template struct p_asm_data { typedef TMatrix type; }; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in full element matrix assembly. - // Stores one general (non-symmetric) 2 x 2 matrix per point. + /// Partially assembled data type for one element with the given number of + /// quadrature points. This type is used in full element matrix assembly. + /// Stores one general (non-symmetric) 2 x 2 matrix per point. template struct f_asm_data { typedef TTensor3 type; }; @@ -299,13 +301,13 @@ struct TDiffusionKernel<2,2,complex_t> typedef typename IntRuleCoefficient::Type Type; }; - // Method used for un-assembled (matrix free) action. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // grad_qpts [M x SDim x NC x NE] - in/out data member in R - // - // grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts + /** @brief Method used for un-assembled (matrix free) action. + @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + @param Q CoefficientEval<>::Type + @param q CoefficientEval<>::Type::result_t + @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R + grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts + */ template static inline MFEM_ALWAYS_INLINE @@ -338,17 +340,17 @@ struct TDiffusionKernel<2,2,complex_t> } } - // Method defining partial assembly. The pointwise Dim x Dim matrices are - // stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2) - // or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3) - // matrices. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices - // A [M x Dim x Dim] - partially assembled Dim x Dim matrices - // - // A = (w/det(J)) adj(J) adj(J)^t + /** @brief Method defining partial assembly. + The pointwise Dim x Dim matrices are stored as symmetric (when + asm_type == p_asm_data, i.e. A.layout.rank == 2) or non-symmetric + (when asm_type == f_asm_data, i.e. A.layout.rank == 3) matrices. + A = (w/det(J)) adj(J) adj(J)^t + @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + @param Q CoefficientEval<>::Type + @param q CoefficientEval<>::Type::result_t + @param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symm. matrices + @param A [M x Dim x Dim] partially assembled Dim x Dim matrices + */ template static inline MFEM_ALWAYS_INLINE void Assemble(const int k, const T_result_t &F, @@ -376,12 +378,12 @@ struct TDiffusionKernel<2,2,complex_t> } } - // Method for partially assembled action. - // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric - // matrices - // grad_qpts [M x SDim x NC x NE] - in/out data member in R - // - // grad_qpts = A grad_qpts + /** @brief Method for partially assembled action. + @param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric + matrices + @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R + grad_qpts = A grad_qpts + */ template static inline MFEM_ALWAYS_INLINE void MultAssembled(const int k, const TMatrix &A, @@ -407,30 +409,30 @@ struct TDiffusionKernel<2,2,complex_t> } }; -// Diffusion kernel in 3D +/// Diffusion kernel in 3D template struct TDiffusionKernel<3,3,complex_t> { typedef complex_t complex_type; - // needed for the TElementTransformation::Result class + /// Needed for the TElementTransformation::Result class static const bool uses_Jacobians = true; - // needed for the FieldEvaluator::Data class + /// Needed for the FieldEvaluator::Data class static const bool in_values = false; static const bool in_gradients = true; static const bool out_values = false; static const bool out_gradients = true; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in partial assembly, and partially - // assembled action. Stores one symmetric 3 x 3 matrix per point. + /// Partially assembled data type for one element with the given number of + /// quadrature points. This type is used in partial assembly, and partially + /// assembled action. Stores one symmetric 3 x 3 matrix per point. template struct p_asm_data { typedef TMatrix type; }; - // Partially assembled data type for one element with the given number of - // quadrature points. This type is used in full element matrix assembly. - // Stores one general (non-symmetric) 3 x 3 matrix per point. + /// Partially assembled data type for one element with the given number of + /// quadrature points. This type is used in full element matrix assembly. + /// Stores one general (non-symmetric) 3 x 3 matrix per point. template struct f_asm_data { typedef TTensor3 type; }; @@ -440,13 +442,13 @@ struct TDiffusionKernel<3,3,complex_t> typedef typename IntRuleCoefficient::Type Type; }; - // Method used for un-assembled (matrix free) action. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // grad_qpts [M x SDim x NC x NE] - in/out data member in R - // - // grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts + /** @brief Method used for un-assembled (matrix free) action. + grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts + Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + Q - CoefficientEval<>::Type + q - CoefficientEval<>::Type::result_t + grad_qpts [M x SDim x NC x NE] - in/out data member in R + */ template static inline MFEM_ALWAYS_INLINE @@ -477,17 +479,18 @@ struct TDiffusionKernel<3,3,complex_t> } } - // Method defining partial assembly. The pointwise Dim x Dim matrices are - // stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2) - // or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3) - // matrices. - // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F - // Q - CoefficientEval<>::Type - // q - CoefficientEval<>::Type::result_t - // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices - // A [M x Dim x Dim] - partially assembled Dim x Dim matrices - // - // A = (w/det(J)) adj(J) adj(J)^t + /** @brief Method defining partial assembly. + The pointwise Dim x Dim matrices are stored as symmetric (when + asm_type == p_asm_data, i.e. A.layout.rank == 2) or + non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank + == 3) matrices. + A = (w/det(J)) adj(J) adj(J)^t + Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F + Q - CoefficientEval<>::Type + q - CoefficientEval<>::Type::result_t + A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices + A [M x Dim x Dim] - partially assembled Dim x Dim matrices + */ template static inline MFEM_ALWAYS_INLINE void Assemble(const int k, const T_result_t &F, @@ -518,12 +521,12 @@ struct TDiffusionKernel<3,3,complex_t> } } - // Method for partially assembled action. - // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric - // matrices - // grad_qpts [M x SDim x NC x NE] - in/out data member in R - // - // grad_qpts = A grad_qpts + /** @brief Method for partially assembled action. + A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric + matrices + grad_qpts [M x SDim x NC x NE] - in/out data member in R + grad_qpts = A grad_qpts + */ template static inline MFEM_ALWAYS_INLINE void MultAssembled(const int k, const TMatrix &A, diff --git a/fem/tcoefficient.hpp b/fem/tcoefficient.hpp index 19c14cb054..04947e7211 100644 --- a/fem/tcoefficient.hpp +++ b/fem/tcoefficient.hpp @@ -21,7 +21,7 @@ namespace mfem { -// Templated coefficient classes, cf. coefficient.?pp +/// Templated coefficient classes, cf. coefficient.?pp class TCoefficient { @@ -56,12 +56,13 @@ public: }; -// Function coefficient. The template class 'Func' has to implement at least one -// of the following methods, depending on the dimension that will be used: -// complex_t Eval1D(real_t); -// complex_t Eval2D(real_t,real_t); -// complex_t Eval3D(real_t,real_t,real_t); -// Use MFEM_FLOPS_ADD() to count flops inside Eval*D. +/** @brief Function coefficient. + @tparam Func has to implement at least one of the following methods, + depending on the dimension that will be used: + complex_t Eval1D(real_t); + complex_t Eval2D(real_t,real_t); + complex_t Eval3D(real_t,real_t,real_t); + Use MFEM_FLOPS_ADD() to count flops inside Eval*D. */ template class TFunctionCoefficient : public TCoefficient { @@ -126,9 +127,9 @@ protected: }; public: - // Constructor for the case when Func has no data members. + /// Constructor for the case when Func has no data members. TFunctionCoefficient() : F() { } - // Constructor for the case when Func has data members. + /// Constructor for the case when Func has data members. TFunctionCoefficient(Func &F_) : F(F_) { } // Default copy constructor, Func has to have copy constructor. @@ -177,7 +178,7 @@ public: } }; - +/// GridFunction coefficient class. template class TGridFunctionCoefficient : public TCoefficient { diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp index 5cdfb9e86f..9ebe23b280 100644 --- a/fem/teltrans.hpp +++ b/fem/teltrans.hpp @@ -21,12 +21,14 @@ namespace mfem // Templated element transformation classes, cf. eltrans.?pp -// Element transformation class, templated on a mesh type and an integration -// rule. It is constructed from a mesh (e.g. class TMesh) and shape evaluator -// (e.g. class ShapeEvaluator) objects. Allows computation of physical -// coordinates and Jacobian matrices corresponding to the reference integration -// points. The desired result is specified through the template subclass Result -// and stored in an object of the same type. +/** @brief Element transformation class, templated on a mesh type and an + integration rule. + It is constructed from a mesh (e.g. class TMesh) and shape evaluator + (e.g. class ShapeEvaluator) objects. Allows computation of physical + coordinates and Jacobian matrices corresponding to the reference integration + points. The desired result is specified through the template subclass Result + and stored in an object of the same type. +*/ template class TElementTransformation { @@ -39,9 +41,9 @@ public: typedef TElementTransformation T_type; - // Enumeration for the result type of the TElementTransformation::Eval() - // method. The types can obtained by summing constants from this enumeration - // and used as a template parameter in struct Result. + /// Enumeration for the result type of the TElementTransformation::Eval() + /// method. The types can obtained by summing constants from this enumeration + /// and used as a template parameter in struct Result. enum EvalOperations { EvalNone = 0, @@ -51,6 +53,8 @@ public: LoadElementIdxs = 8 }; + /// Determines at compile-time the operations needed for given coefficient and + /// kernel template struct Get { static const int EvalOps = @@ -61,11 +65,12 @@ public: (EvalJacobians * kernel_t::uses_Jacobians); }; - // Templated struct Result, used to specify the type result that is computed - // by the TElementTransformation::Eval() method and stored in this structure. - // The template parameter EvalOps is a sum (bitwise or) of constants from - // the enum EvalOperations. The parameter NE is the number of elements to be - // processed in the Eval() method. + /** @brief Templated struct Result, used to specify the type result that is + computed by the TElementTransformation::Eval() method and stored in this + structure. + @tparam EvalOps is a sum (bitwise or) of constants from the enum EvalOperations + @tparam NE is the number of elements to be processed in the Eval() method. + */ template struct Result; static const int dim = Mesh_t::dim; @@ -105,7 +110,7 @@ public: elements(mesh.m_mesh.GetElementsArray()) { } - // Evaluate coordinates and/or Jacobian matrices at quadrature points. + /// Evaluate coordinates and/or Jacobian matrices at quadrature points. template inline MFEM_ALWAYS_INLINE void Eval(int el, Result &F) diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 50e00782c2..7c18498084 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -23,12 +23,16 @@ namespace mfem // Templated classes for transitioning between degrees of freedom and quadrature // points values. -// Shape evaluators -- values of basis functions on the reference element - +/** @brief Shape evaluators -- values of basis functions on the reference element + @tparam FE some form of TFiniteElement, probably got from TMesh::FE_type + @tparam IR some form of TIntegrationRule + @tparam TP tensor product or not + @tparam real_t data type for mesh nodes, solution basis, mesh basis +*/ template class ShapeEvaluator_base; -// ShapeEvaluator without tensor-product structure +/// ShapeEvaluator without tensor-product structure template class ShapeEvaluator_base { @@ -54,8 +58,8 @@ public: // default copy constructor - // Multi-component shape evaluation from DOFs to quadrature points. - // dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). + /** Multi-component shape evaluation from DOFs to quadrature points. + dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */ template MFEM_ALWAYS_INLINE @@ -76,8 +80,8 @@ public: qpt_layout, qpt_data); } - // Multi-component shape evaluation transpose from quadrature points to DOFs. - // qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). + /** Multi-component shape evaluation transpose from quadrature points to DOFs. + qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */ template @@ -99,8 +103,8 @@ public: dof_layout, dof_data); } - // Multi-component gradient evaluation from DOFs to quadrature points. - // dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). + /** Multi-component gradient evaluation from DOFs to quadrature points. + dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). */ template MFEM_ALWAYS_INLINE @@ -124,8 +128,8 @@ public: grad_layout.merge_12(), grad_data); } - // Multi-component gradient evaluation transpose from quadrature points to - // DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). + /** Multi-component gradient evaluation transpose from quadrature points to + DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */ template @@ -150,8 +154,9 @@ public: dof_layout, dof_data); } - // Multi-component assemble. - // qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) + /** Multi-component assemble. + qpt_layout is (NIP x NumComp), + M_layout is (DOF x DOF x NumComp) */ template MFEM_ALWAYS_INLINE @@ -207,7 +212,7 @@ public: template class TProductShapeEvaluator; -// ShapeEvaluator with 1D tensor-product structure +/// ShapeEvaluator with 1D tensor-product structure template class TProductShapeEvaluator<1, DOF, NIP, real_t> { @@ -220,8 +225,8 @@ protected: public: TProductShapeEvaluator() { } - // Multi-component shape evaluation from DOFs to quadrature points. - // dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). + /** Multi-component shape evaluation from DOFs to quadrature points. + dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */ template MFEM_ALWAYS_INLINE @@ -233,8 +238,8 @@ public: qpt_layout, qpt_data); } - // Multi-component shape evaluation transpose from quadrature points to DOFs. - // qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). + /** Multi-component shape evaluation transpose from quadrature points to DOFs. + qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */ template @@ -247,8 +252,8 @@ public: dof_layout, dof_data); } - // Multi-component gradient evaluation from DOFs to quadrature points. - // dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). + /** Multi-component gradient evaluation from DOFs to quadrature points. + dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). */ template MFEM_ALWAYS_INLINE @@ -263,8 +268,8 @@ public: grad_layout.merge_12(), grad_data); } - // Multi-component gradient evaluation transpose from quadrature points to - // DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). + /** Multi-component gradient evaluation transpose from quadrature points to + DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */ template @@ -281,8 +286,8 @@ public: dof_layout, dof_data); } - // Multi-component assemble. - // qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) + /** Multi-component assemble. + qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) */ template MFEM_ALWAYS_INLINE @@ -304,9 +309,9 @@ public: #endif } - // Multi-component assemble of grad-grad element matrices. - // qpt_layout is (NIP x DIM x DIM x NumComp), and - // D_layout is (DOF x DOF x NumComp). + /** Multi-component assemble of grad-grad element matrices. + qpt_layout is (NIP x DIM x DIM x NumComp), and + D_layout is (DOF x DOF x NumComp). */ template MFEM_ALWAYS_INLINE @@ -331,7 +336,7 @@ public: } }; -// ShapeEvaluator with 2D tensor-product structure +/// ShapeEvaluator with 2D tensor-product structure template class TProductShapeEvaluator<2, DOF, NIP, real_t> { @@ -366,8 +371,8 @@ public: qpt_layout.template split_1(), qpt_data); } - // Multi-component shape evaluation from DOFs to quadrature points. - // dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). + /** Multi-component shape evaluation from DOFs to quadrature points. + dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */ template MFEM_ALWAYS_INLINE @@ -398,8 +403,8 @@ public: dof_layout.template split_1(), dof_data); } - // Multi-component shape evaluation transpose from quadrature points to DOFs. - // qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). + /** Multi-component shape evaluation transpose from quadrature points to DOFs. + qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */ template @@ -410,8 +415,8 @@ public: CalcT(qpt_layout, qpt_data, dof_layout, dof_data); } - // Multi-component gradient evaluation from DOFs to quadrature points. - // dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). + /** Multi-component gradient evaluation from DOFs to quadrature points. + dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). */ template MFEM_ALWAYS_INLINE @@ -426,9 +431,9 @@ public: grad_layout.ind2(1), grad_data); } - // Multi-component gradient evaluation transpose from quadrature points to - // DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is - // (TDOF x NumComp). + /** Multi-component gradient evaluation transpose from quadrature points to + DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is + (TDOF x NumComp). */ template @@ -444,8 +449,8 @@ public: dof_layout, dof_data); } - // Multi-component assemble. - // qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) + /** Multi-component assemble. + qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) */ template MFEM_ALWAYS_INLINE @@ -607,7 +612,7 @@ public: } }; -// ShapeEvaluator with 3D tensor-product structure +/// ShapeEvaluator with 3D tensor-product structure template class TProductShapeEvaluator<3, DOF, NIP, real_t> { @@ -646,8 +651,8 @@ public: qpt_layout.template split_1(), qpt_data); } - // Multi-component shape evaluation from DOFs to quadrature points. - // dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). + /** Multi-component shape evaluation from DOFs to quadrature points. + dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */ template MFEM_ALWAYS_INLINE @@ -682,8 +687,8 @@ public: dof_layout.template split_1(), dof_data); } - // Multi-component shape evaluation transpose from quadrature points to DOFs. - // qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). + /** Multi-component shape evaluation transpose from quadrature points to DOFs. + qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */ template @@ -694,8 +699,8 @@ public: CalcT(qpt_layout, qpt_data, dof_layout, dof_data); } - // Multi-component gradient evaluation from DOFs to quadrature points. - // dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). + /** Multi-component gradient evaluation from DOFs to quadrature points. + dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). */ template MFEM_ALWAYS_INLINE @@ -714,9 +719,9 @@ public: // y-derivatives and second time for the z-derivatives. } - // Multi-component gradient evaluation transpose from quadrature points to - // DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is - // (TDOF x NumComp). + /** Multi-component gradient evaluation transpose from quadrature points to + DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is + (TDOF x NumComp). */ template @@ -734,8 +739,8 @@ public: dof_layout, dof_data); } - // Multi-component assemble. - // qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) + /** Multi-component assemble. + qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) */ template MFEM_ALWAYS_INLINE @@ -895,7 +900,7 @@ public: } }; -// ShapeEvaluator with tensor-product structure in any dimension +/// ShapeEvaluator with tensor-product structure in any dimension template class ShapeEvaluator_base : public TProductShapeEvaluator @@ -921,7 +926,7 @@ public: // default copy constructor }; -// General ShapeEvaluator for any scalar FE type (L2 or H1) +/// General ShapeEvaluator for any scalar FE type (L2 or H1) template class ShapeEvaluator : public ShapeEvaluator_base @@ -946,8 +951,9 @@ public: }; -// Field evaluators -- values of a given global FE grid function - +/** Field evaluators -- values of a given global FE grid function + This is roughly speaking a templated version of GridFunction +*/ template class FieldEvaluator_base @@ -960,7 +966,7 @@ protected: ShapeEval_type shapeEval; VecLayout_t vec_layout; - // With this constructor, fespace is a shallow copy. + /// With this constructor, fespace is a shallow copy. inline MFEM_ALWAYS_INLINE FieldEvaluator_base(const FESpace_t &tfes, const ShapeEval_type &shape_eval, const VecLayout_t &vec_layout) @@ -969,14 +975,14 @@ protected: vec_layout(vec_layout) { } - // This constructor creates new fespace, not a shallow copy. + /// This constructor creates new fespace, not a shallow copy. inline MFEM_ALWAYS_INLINE FieldEvaluator_base(const FE_type &fe, const FiniteElementSpace &fes) : fespace(fe, fes), shapeEval(fe), vec_layout(fes) { } }; -// complex_t - dof/qpt data type, real_t - ShapeEvaluator (FE basis) data type +/// complex_t - dof/qpt data type, real_t - ShapeEvaluator (FE basis) data type template class FieldEvaluator @@ -1009,7 +1015,7 @@ protected: complex_t *data_out; public: - // With this constructor, fespace is a shallow copy of tfes. + /// With this constructor, fespace is a shallow copy of tfes. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FESpace_t &tfes, const ShapeEval_type &shape_eval, const VecLayout_type &vec_layout, @@ -1019,7 +1025,7 @@ public: data_out(global_data_out) { } - // With this constructor, fespace is a shallow copy of f.fespace. + /// With this constructor, fespace is a shallow copy of f.fespace. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FieldEvaluator &f, const complex_t *global_data_in, complex_t *global_data_out) @@ -1028,7 +1034,7 @@ public: data_out(global_data_out) { } - // This constructor creates a new fespace, not a shallow copy. + /// This constructor creates a new fespace, not a shallow copy. inline MFEM_ALWAYS_INLINE FieldEvaluator(const FiniteElementSpace &fes, const complex_t *global_data_in, complex_t *global_data_out) @@ -1049,7 +1055,7 @@ public: fespace.SetElement(el); } - // val_layout_t is (qpts x vdim x NE) + /// val_layout_t is (qpts x vdim x NE) template inline MFEM_ALWAYS_INLINE void GetValues(int el, const val_layout_t &l, val_data_t &vals) @@ -1061,7 +1067,7 @@ public: shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, l.merge_23(), vals); } - // grad_layout_t is (qpts x dim x vdim x NE) + /// grad_layout_t is (qpts x dim x vdim x NE) template inline MFEM_ALWAYS_INLINE void GetGradients(int el, const grad_layout_t &l, grad_data_t &grad) @@ -1126,9 +1132,9 @@ public: } #endif - // Enumeration for the data type used by the Eval() and Assemble() methods. - // The types can obtained by summing constants from this enumeration and used - // as a template parameter in struct Data. + /** Enumeration for the data type used by the Eval() and Assemble() methods. + The types can obtained by summing constants from this enumeration and used + as a template parameter in struct Data. */ enum InOutData { None = 0, @@ -1136,10 +1142,12 @@ public: Gradients = 2 }; - // Auxiliary templated struct AData, used by the Eval() and Assemble() - // methods. The template parameter IOData is "bitwise or" of constants from - // the enum InOutData. The parameter NE is the number of elements to be - // processed in the Eval() and Assemble() methods. + /** @brief Auxiliary templated struct AData, used by the Eval() and Assemble() + methods. + + The template parameter IOData is "bitwise or" of constants from + the enum InOutData. The parameter NE is the number of elements to be + processed in the Eval() and Assemble() methods. */ template struct AData; template struct AData<0,NE> // 0 = None @@ -1181,8 +1189,8 @@ public: TTensor4 grad_qpts; }; - // This struct is similar to struct AData, adding separate static data - // members for the input (InData) and output (OutData) data types. + /** This struct is similar to struct AData, adding separate static data + members for the input (InData) and output (OutData) data types. */ template struct BData : public AData { @@ -1192,9 +1200,9 @@ public: static const int OutData = OData; }; - // This struct implements the input (Eval, EvalSerialized) and output - // (Assemble, AssembleSerialized) operations for the given Ops. - // Ops is "bitwise or" of constants from the enum InOutData. + /** This struct implements the input (Eval, EvalSerialized) and output + (Assemble, AssembleSerialized) operations for the given Ops. + Ops is "bitwise or" of constants from the enum InOutData. */ template struct Action; template struct Action<0,dummy> // 0 = None @@ -1371,8 +1379,8 @@ public: #endif }; - // This struct implements element matrix computation for some combinations - // of input (InOps) and output (OutOps) operations. + /** This struct implements element matrix computation for some combinations + of input (InOps) and output (OutOps) operations. */ template struct TElementMatrix; template struct TElementMatrix<1,1,NE> // 1,1 = Values,Values @@ -1392,8 +1400,12 @@ public: template struct TElementMatrix<2,2,NE> // 2,2 = Gradients,Gradients { - // qpt_layout_t is (nip x dim x dim), M_layout_t is (dof x dof) - // NE = 1 is assumed + /** @brief Assemble element mass matrix + @param A given quadrature point data for element (incl. coefficient, + geometry) + @param M the resulting element mass matrix + qpt_layout_t is (nip), M_layout_t is (dof x dof) + NE = 1 is assumed */ template static inline MFEM_ALWAYS_INLINE diff --git a/fem/tfe.hpp b/fem/tfe.hpp index 8a71866062..9b01aed797 100644 --- a/fem/tfe.hpp +++ b/fem/tfe.hpp @@ -20,6 +20,16 @@ namespace mfem // Templated finite element classes, cf. fe.?pp +/** @brief Store mass-like matrix B for each integration point on the reference + element. + For tensor product evaluation, this is only called on the 1D reference + element, and higher dimensions are put together from that. + The element mass matrix can be written \f$ M_E = B^T D_E B \f$ where the B + built here is the B, and is unchanging across the mesh. The diagonal matrix + \f$ D_E \f$ then contains all the element-specific geometry and physics data. + @param B must be (nip x dof) with column major storage + @param dof_map the inverse of dof_map is applied to reorder local dofs. +*/ template void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir, real_t *B, const Array *dof_map = NULL) @@ -41,6 +51,21 @@ void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir, } } +/** @brief store gradient matrix G for each integration point on the reference + element. + For tensor product evaluation, this is only called on the 1D reference + element, and higher dimensions are put together from that. + The element stiffness matrix can be written + \f[ + S_E = \sum_{k=1}^{nq} G_{k,i}^T (D_E^G)_{k,k} G_{k,j} + \f] + where \f$ nq \f$ is the number of quadrature points, \f$ D_E^G \f$ contains + all the information about the element geometry and coefficients (Jacobians + etc.), and \f$ G \f$ is the matrix built in this routine, which is the same + for all elements in a mesh. + @param[out] G must be (nip x dim x dof) with column major storage + @param[in] dof_map the inverse of dof_map is applied to reorder local dofs. +*/ template void CalcGradTensor(const FiniteElement &fe, const IntegrationRule &ir, real_t *G, const Array *dof_map = NULL) From 2dcae3ac056660fb47ae4f52f3ddbf2ee995624f Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Thu, 9 Apr 2020 14:06:34 -0700 Subject: [PATCH 165/535] make style --- fem/bilinearform.hpp | 26 +++++----- fem/coefficient.hpp | 90 +++++++++++++++++----------------- fem/eltrans.hpp | 26 +++++----- fem/estimators.hpp | 8 +-- fem/fe.hpp | 102 ++++++++++++++++++++------------------- fem/fe_coll.hpp | 12 ++--- fem/tbilinearform.hpp | 2 +- fem/tbilininteg.hpp | 2 +- fem/tcoefficient.hpp | 2 +- fem/tevaluator.hpp | 2 +- general/array.hpp | 2 +- general/mem_manager.hpp | 2 +- general/optparser.hpp | 2 +- general/sets.hpp | 2 +- general/socketstream.hpp | 6 +-- general/stable3d.hpp | 16 +++--- 16 files changed, 152 insertions(+), 150 deletions(-) diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index bc7cf2ee6e..501b4dfac9 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -45,7 +45,7 @@ enum class AssemblyLevel /** Class for bilinear form - "Matrix" with associated FE space and - BLFIntegrators. The sum of all the BLFIntegrators will be used + BLFIntegrators. The sum of all the BLFIntegrators will be used form the matrix/operator M. */ class BilinearForm : public Matrix { @@ -53,7 +53,7 @@ protected: /// Sparse matrix \f$ M \f$ to be associated with the form. Owned. SparseMatrix *mat; - /** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations + /** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations from the b.c. Owned. \f$ M + M_e = M_{original} \f$ */ SparseMatrix *mat_e; @@ -150,7 +150,7 @@ public: /// Get the size of the BilinearForm as a square matrix. int Size() const { return height; } - /// Set the desired assembly level. + /// Set the desired assembly level. /** Valid choices are: - AssemblyLevel::FULL (default) @@ -171,7 +171,7 @@ public: condensation is not reduced, it is not enabled. */ void EnableStaticCondensation(); - /** @brief Check if static condensation was actually enabled by a previous + /** @brief Check if static condensation was actually enabled by a previous call to EnableStaticCondensation(). */ bool StaticCondensationIsEnabled() const { return static_cond; } @@ -207,7 +207,7 @@ public: void UseSparsity(SparseMatrix &A); /// Pre-allocate the internal SparseMatrix before assembly. - /** If the flag 'precompute sparsity' + /** If the flag 'precompute sparsity' is set, the matrix is allocated in CSR format (i.e. finalized) and the entries are initialized with zeros. */ void AllocateMatrix() { if (mat == NULL) { AllocMat(); } } @@ -244,8 +244,8 @@ public: /// Matrix vector multiplication: \f$ y = M x \f$ virtual void Mult(const Vector &x, Vector &y) const; - /** @brief Matrix vector multiplication with the original uneliminated - matrix. The original matrix is \f$ M + M_e \f$ so we have: + /** @brief Matrix vector multiplication with the original uneliminated + matrix. The original matrix is \f$ M + M_e \f$ so we have: \f$ y = M x + M_e x \f$ */ void FullMult(const Vector &x, Vector &y) const { mat->Mult(x, y); mat_e->AddMult(x, y); } @@ -254,8 +254,8 @@ public: virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const { mat -> AddMult (x, y, a); } - /** @brief Add the original uneliminated matrix vector multiple to a vector. - The original matrix is \f$ M + Me \f$ so we have: + /** @brief Add the original uneliminated matrix vector multiple to a vector. + The original matrix is \f$ M + Me \f$ so we have: \f$ y += M x + M_e x \f$ */ void FullAddMult(const Vector &x, Vector &y) const { mat->AddMult(x, y); mat_e->AddMult(x, y); } @@ -265,8 +265,8 @@ public: const double a = 1.0) const { mat->AddMultTranspose(x, y, a); } - /** @brief Add the original uneliminated matrix transpose vector - multiple to a vector. The original matrix is \f$ M + M_e \f$ + /** @brief Add the original uneliminated matrix transpose vector + multiple to a vector. The original matrix is \f$ M + M_e \f$ so we have: \f$ y += M^T x + {M_e}^T x \f$ */ void FullAddMultTranspose(const Vector & x, Vector & y) const { mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); } @@ -299,7 +299,7 @@ public: return *mat; } - /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer + /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer to it. Used for transfering ownership. */ SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; } @@ -706,7 +706,7 @@ public: /// Returns a reference to the sparse matrix: \f$ M \f$ SparseMatrix &SpMat() { return *mat; } - /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer + /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer to it. Used for transfering ownership. */ SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index d15e129205..810d3a073a 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -81,7 +81,7 @@ public: { return (constant); } }; -/** @brief A piecewise constant coefficient with the constants keyed +/** @brief A piecewise constant coefficient with the constants keyed off the element attribute numbers. */ class PWConstCoefficient : public Coefficient { @@ -191,12 +191,12 @@ public: }; -/** @brief A coefficient that depends on 1 or 2 parent coefficients and a - transformation rule represented by a c-function. +/** @brief A coefficient that depends on 1 or 2 parent coefficients and a + transformation rule represented by a c-function. - \f$ C(x,t) = T(Q1(x,t)) \f$ or \f$ C(x,t) = T(Q1(x,t), Q2(x,t)) \f$ + \f$ C(x,t) = T(Q1(x,t)) \f$ or \f$ C(x,t) = T(Q1(x,t), Q2(x,t)) \f$ - where T is the transformation rule, and Q1/Q2 are the parent coefficients.*/ + where T is the transformation rule, and Q1/Q2 are the parent coefficients.*/ class TransformedCoefficient : public Coefficient { private: @@ -216,13 +216,13 @@ public: virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; -/** @brief Delta function coefficient optionally multiplied by a weight +/** @brief Delta function coefficient optionally multiplied by a weight coefficient and a scaled time dependent c-function. \f$ F(x,t) = w(x,t) s T(t) d(x - xc) \f$ where w is the optional weight coefficient, @a s is a scale factor - T is an optional time-dependent function and d is a delta function. + T is an optional time-dependent function and d is a delta function. WARNING this cannot be used as a normal coefficient. The usual Eval method is disabled. */ @@ -316,7 +316,7 @@ private: public: /** @brief Construct with a parent coefficient and an array of zeros and - ones representing which attributes this coefficient should be active. */ + ones representing which attributes this coefficient should be active. */ RestrictedCoefficient(Coefficient &_c, Array &attr) { c = &_c; attr.Copy(active_attr); } @@ -425,9 +425,9 @@ public: virtual ~VectorFunctionCoefficient() { } }; -/** @brief Vector coefficient defined by an array of scalar coefficients. +/** @brief Vector coefficient defined by an array of scalar coefficients. Coefficients that are not set will evaluate to zero in the vector. - This object takes ownership of the array of coefficients inside it and + This object takes ownership of the array of coefficients inside it and deletes them at object destruction. */ class VectorArrayCoefficient : public VectorCoefficient { @@ -436,7 +436,7 @@ private: Array ownCoeff; public: - /** @brief Construct vector of dim coefficients. The actual coefficients + /** @brief Construct vector of dim coefficients. The actual coefficients still need to be added with Set(). */ explicit VectorArrayCoefficient(int dim); @@ -449,12 +449,12 @@ public: /// Sets coefficient in the vector. void Set(int i, Coefficient *c, bool own=true); - /// Evaluates i'th component of the vector of coefficients. Returns + /// Evaluates i'th component of the vector of coefficients. Returns double Eval(int i, ElementTransformation &T, const IntegrationPoint &ip) { return Coeff[i] ? Coeff[i]->Eval(T, ip, GetTime()) : 0.0; } using VectorCoefficient::Eval; - /** @brief Evaluate the coefficient. Each element of vector V comes from the + /** @brief Evaluate the coefficient. Each element of vector V comes from the associated array of scalar coefficients. */ virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -474,8 +474,8 @@ public: function is set with cause a segfault. */ VectorGridFunctionCoefficient() : VectorCoefficient(0), GridFunc(NULL) { } - /** @brief Construct the coefficient with grid function @a gf. The - grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with grid function @a gf. The + grid function is not owned by the coefficient. */ VectorGridFunctionCoefficient(GridFunction *gf); /// Set the grid function @@ -486,7 +486,7 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - /** @brief Evaluate the vector coefficient at all of the locations in the + /** @brief Evaluate the vector coefficient at all of the locations in the integration rule and write the vectors into matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -501,8 +501,8 @@ protected: GridFunction *GridFunc; public: - /** @brief Construct the coefficient with a scalar grid function - @a gf. The grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with a scalar grid function + @a gf. The grid function is not owned by the coefficient. */ GradientGridFunctionCoefficient(GridFunction *gf); ///Set the scalar grid function. @@ -515,8 +515,8 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - /** @brief Evaluate the gradient vector coefficient at all of the - locations in the integration rule and write the vectors into + /** @brief Evaluate the gradient vector coefficient at all of the + locations in the integration rule and write the vectors into matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -531,8 +531,8 @@ protected: GridFunction *GridFunc; public: - /** @brief Construct the coefficient with a vector grid function - @a gf. The grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with a vector grid function + @a gf. The grid function is not owned by the coefficient. */ CurlGridFunctionCoefficient(GridFunction *gf); /// Set the vector grid function. @@ -556,8 +556,8 @@ protected: GridFunction *GridFunc; public: - /** @brief Construct the coefficient with a vector grid function - @a gf. The grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with a vector grid function + @a gf. The grid function is not owned by the coefficient. */ DivergenceGridFunctionCoefficient(GridFunction *gf); // /Set the vector grid function. @@ -573,7 +573,7 @@ public: virtual ~DivergenceGridFunctionCoefficient() { } }; -/** @brief Vector coefficient defined by a scalar DeltaCoefficient and a +/** @brief Vector coefficient defined by a scalar DeltaCoefficient and a constant vector direction. WARNING this cannot be used as a normal coefficient. The usual Eval @@ -589,23 +589,23 @@ public: VectorDeltaCoefficient(int _vdim) : VectorCoefficient(_vdim), dir(_vdim), d() { } - /** @brief Construct with a Vector object representing the direction and + /** @brief Construct with a Vector object representing the direction and a unit delta function centered at (0.0,0.0,0.0) */ VectorDeltaCoefficient(const Vector& _dir) : VectorCoefficient(_dir.Size()), dir(_dir), d() { } - /** @brief Construct with a Vector object representing the direction and - a delta function scaled by @a s and centered at (x,0.0,0.0) */ + /** @brief Construct with a Vector object representing the direction and + a delta function scaled by @a s and centered at (x,0.0,0.0) */ VectorDeltaCoefficient(const Vector& _dir, double x, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,s) { } - /** @brief Construct with a Vector object representing the direction and - a delta function scaled by @a s and centered at (x,y,0.0) */ + /** @brief Construct with a Vector object representing the direction and + a delta function scaled by @a s and centered at (x,y,0.0) */ VectorDeltaCoefficient(const Vector& _dir, double x, double y, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,s) { } - /** @brief Construct with a Vector object representing the direction and - a delta function scaled by @a s and centered at (x,y,z) */ + /** @brief Construct with a Vector object representing the direction and + a delta function scaled by @a s and centered at (x,y,z) */ VectorDeltaCoefficient(const Vector& _dir, double x, double y, double z, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,z,s) { } @@ -649,7 +649,7 @@ private: public: /** @brief Construct with a parent vector coefficient and an array of zeros and - ones representing the attributes for which this coefficient should be active. */ + ones representing the attributes for which this coefficient should be active. */ VectorRestrictedCoefficient(VectorCoefficient &vc, Array &attr) : VectorCoefficient(vc.GetVDim()) { c = &vc; attr.Copy(active_attr); } @@ -658,8 +658,8 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - /** @brief Evaluate the vector coefficient at all of the - locations in the integration rule and write the vectors into + /** @brief Evaluate the vector coefficient at all of the + locations in the integration rule and write the vectors into matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -723,9 +723,9 @@ public: }; -/** @brief A matrix coefficient with an optional scalar coefficient +/** @brief A matrix coefficient with an optional scalar coefficient multiplier \a q. The matrix function can either be represented by a - C-function or a constant matrix provided when constructiong this + C-function or a constant matrix provided when constructiong this object. */ class MatrixFunctionCoefficient : public MatrixCoefficient { @@ -775,10 +775,10 @@ public: -/** @brief Matrix coefficient defined by an matrix of scalar coefficients. +/** @brief Matrix coefficient defined by an matrix of scalar coefficients. Coefficients that are not set will evaluate to zero in the vector. The - of coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. - This object takes ownership of the array of coefficients inside it and + of coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. + This object takes ownership of the array of coefficients inside it and deletes them at object destruction. */ class MatrixArrayCoefficient : public MatrixCoefficient @@ -788,7 +788,7 @@ private: Array ownCoeff; public: - /** @brief Construct matrix of dim = height*width coefficients. + /** @brief Construct matrix of dim = height*width coefficients. The actual coefficients still need to be added with Set(). */ explicit MatrixArrayCoefficient (int dim); @@ -810,7 +810,7 @@ public: }; -/** @brief Derived matrix coefficient that takes the value of the parent +/** @brief Derived matrix coefficient that takes the value of the parent matrix coefficient for the active attrs and is zero otherwise. */ class MatrixRestrictedCoefficient : public MatrixCoefficient { @@ -820,7 +820,7 @@ private: public: /** @brief Construct with a parent matrix coefficient and an array of zeros and - ones representing the attributes for which this coefficient should be active. */ + ones representing the attributes for which this coefficient should be active. */ MatrixRestrictedCoefficient(MatrixCoefficient &mc, Array &attr) : MatrixCoefficient(mc.GetHeight(), mc.GetWidth()) { c = &mc; attr.Copy(active_attr); } @@ -1006,7 +1006,7 @@ public: using VectorCoefficient::Eval; }; -/** @brief Vector coefficient defined as a product of a matrix coeffiecient and +/** @brief Vector coefficient defined as a product of a matrix coeffiecient and a vector coefficient. */ class MatVecCoefficient : public VectorCoefficient { @@ -1065,7 +1065,7 @@ public: const IntegrationPoint &ip); }; -/** @brief Matrix coefficient defined as a product of a scalar +/** @brief Matrix coefficient defined as a product of a scalar coefficient and a matrix coefficient.*/ class ScalarMatrixProductCoefficient : public MatrixCoefficient { diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index e5bea4fd7e..911dec9d29 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -39,7 +39,7 @@ protected: Geometry::Type geom; int space_dim; - /** @brief Evaluate the Jacobian of the transformation at the IntPoint and + /** @brief Evaluate the Jacobian of the transformation at the IntPoint and store it in dFdx. */ virtual const DenseMatrix &EvalJacobian() = 0; virtual const DenseMatrix &EvalHessian() = 0; @@ -53,7 +53,7 @@ public: ElementTransformation(); - /** @brief Set the integration point @a ip that weights and jacobians will + /** @brief Set the integration point @a ip that weights and jacobians will be evaluated at. */ void SetIntPoint(const IntegrationPoint *ip) { IntPoint = ip; EvalState = 0; } @@ -61,7 +61,7 @@ public: /// Get a const reference to the currently set integration point. const IntegrationPoint &GetIntPoint() { return *IntPoint; } - /** @brief Transform integration point from reference coordinates to + /** @brief Transform integration point from reference coordinates to physical coordinates and store them in the vector. */ virtual void Transform(const IntegrationPoint &, Vector &) = 0; @@ -90,7 +90,7 @@ public: { return (EvalState & HESSIAN_MASK) ? d2Fdx2 : EvalHessian(); } /** @brief Return the weight of the Jacobian matrix of the transformation - at the currently set IntegrationPoint, using the metion SetIntPoint(). + at the currently set IntegrationPoint, using the metion SetIntPoint(). The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */ double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); } @@ -321,7 +321,7 @@ private: const FiniteElement *FElem; DenseMatrix PointMat; // dim x dof - /** @brief Evaluate the Jacobian of the transformation at the IntPoint and + /** @brief Evaluate the Jacobian of the transformation at the IntPoint and store it in dFdx. */ virtual const DenseMatrix &EvalJacobian(); // Evaluate the Hessian of the transformation at the IntPoint and store it @@ -341,22 +341,22 @@ public: \f$ x = F( \hat x ) = P \phi( \hat x ) \f$ - where \f$ \hat x \f$ is the reference point, @a x is the corresponding - physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is - the column-vector of all basis functions evaluated at xh. The columns of - @a P represent the control points in physical space defining the + where \f$ \hat x \f$ is the reference point, @a x is the corresponding + physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is + the column-vector of all basis functions evaluated at xh. The columns of + @a P represent the control points in physical space defining the transformation. */ DenseMatrix &GetPointMat() { return PointMat; } - /** @brief Sets up the correct dimensions for the Jacobian computations. This - must be called after SetIdentityTransformation(), but before and calls to + /** @brief Sets up the correct dimensions for the Jacobian computations. This + must be called after SetIdentityTransformation(), but before and calls to EvalJacobian(). */ void FinalizeTransformation() { space_dim = PointMat.Height(); } /// Set the FiniteElement Geometry for the reference elements being used. void SetIdentityTransformation(Geometry::Type GeomType); - /** @brief Transform integration point from reference coordinates to + /** @brief Transform integration point from reference coordinates to physical coordinates and store them in the vector. */ virtual void Transform(const IntegrationPoint &, Vector &); @@ -367,7 +367,7 @@ public: /** @brief Transform all the integration points from the column vectors of @a matrix from reference coordinates to physical - coordinates and store them as column vectors in @a result. */ + coordinates and store them as column vectors in @a result. */ virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); virtual int Order() { return FElem->GetOrder(); } diff --git a/fem/estimators.hpp b/fem/estimators.hpp index 82fef128f0..a276819245 100644 --- a/fem/estimators.hpp +++ b/fem/estimators.hpp @@ -67,12 +67,12 @@ public: /** @brief The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu error estimation procedure. - Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery - and a posteriori error estimates. Part 1: The recovery technique. + Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery + and a posteriori error estimates. Part 1: The recovery technique. Int. J. Num. Meth. Engng. 33, 1331-1364 (1992). - Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery - and a posteriori error estimates. Part 2: Error estimates and adaptivity. + Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery + and a posteriori error estimates. Part 2: Error estimates and adaptivity. Int. J. Num. Meth. Engng. 33, 1365-1382 (1992). The required BilinearFormIntegrator must implement the methods diff --git a/fem/fe.hpp b/fem/fe.hpp index ed52f68247..b068fd5a4e 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -256,25 +256,26 @@ public: /** @brief Enumeration for MapType: defines how reference functions are mapped to physical space. - A reference function \f$ \hat u(\hat x) \f$ can be mapped to a function + A reference function \f$ \hat u(\hat x) \f$ can be mapped to a function \f$ u(x) \f$ on a general physical element in following where: - \f$ x = T(\hat x) \f$ is the image of the reference point \f$ \hat x \f$ - \f$ J = J(\hat x) \f$ is the Jacobian matrix of the transformation T - \f$ w = w(\hat x) = det(J) \f$ is the transformation weight factor for square J - \f$ w = w(\hat x) = det(J^t J)^{1/2} \f$ is the transformation weight factor in general */ - enum MapT { - VALUE, /**< For scalar fields; preserves point values + enum MapT + { + VALUE, /**< For scalar fields; preserves point values \f$ u(x) = \hat u(\hat x) \f$ */ - INTEGRAL, /**< For scalar fields; preserves volume integrals + INTEGRAL, /**< For scalar fields; preserves volume integrals \f$ u(x) = (1/w) \hat u(\hat x) \f$ */ - H_DIV, /**< For vector fields; preserves surface integrals of the + H_DIV, /**< For vector fields; preserves surface integrals of the normal component \f$ u(x) = (J/w) \hat u(\hat x) \f$ */ - H_CURL /**< For vector fields; preserves line integrals of the - tangential component - \f$ u(x) = J^{-t} \hat u(\hat x) \f$ (square J), + H_CURL /**< For vector fields; preserves line integrals of the + tangential component + \f$ u(x) = J^{-t} \hat u(\hat x) \f$ (square J), \f$ u(x) = J(J^t J)^{-1} \hat u(\hat x) \f$ (general J) */ - }; + }; /** @brief Enumeration for DerivType: defines which derivative method is implemented. @@ -283,12 +284,13 @@ public: value returned by GetDerivType() indicates which derivative method is implemented. */ - enum DerivT { - NONE, ///< No derivatives implemented - GRAD, ///< Implements CalcDShape methods - DIV, ///< Implements CalcDivShape methods - CURL ///< Implements CalcCurlShape methods - }; + enum DerivT + { + NONE, ///< No derivatives implemented + GRAD, ///< Implements CalcDShape methods + DIV, ///< Implements CalcDivShape methods + CURL ///< Implements CalcCurlShape methods + }; /** @brief Construct FiniteElement with given @param D Reference space dimension @@ -326,23 +328,23 @@ public: /// Returns the FiniteElement::RangeT of the element, one of {SCALAR, VECTOR}. int GetRangeType() const { return RangeType; } - /** @brief Returns the FiniteElement::RangeT of the element derivative, either + /** @brief Returns the FiniteElement::RangeT of the element derivative, either SCALAR or VECTOR. */ int GetDerivRangeType() const { return DerivRangeType; } - /** @brief Returns the FiniteElement::MapT of the element describing how reference - functions are mapped to physical space, one of {VALUE, INTEGRAL + /** @brief Returns the FiniteElement::MapT of the element describing how reference + functions are mapped to physical space, one of {VALUE, INTEGRAL H_DIV, H_CURL}. */ int GetMapType() const { return MapType; } - /** @brief Returns the FiniteElement::MapT of the element describing how reference - functions are mapped to physical space, one of {VALUE, INTEGRAL + /** @brief Returns the FiniteElement::MapT of the element describing how reference + functions are mapped to physical space, one of {VALUE, INTEGRAL H_DIV, H_CURL}. */ int GetDerivType() const { return DerivType; } - /** @brief Returns the FiniteElement::MapT of the element describing how reference - function derivatives are mapped to physical space, one of {VALUE, + /** @brief Returns the FiniteElement::MapT of the element describing how reference + function derivatives are mapped to physical space, one of {VALUE, INTEGRAL, H_DIV, H_CURL}. */ int GetDerivMapType() const { return DerivMapType; } @@ -430,8 +432,8 @@ public: void CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape) const; - /** @brief Get the dofs associated with the given @a face. - @a *dofs is set to an internal array of the local dofc on the + /** @brief Get the dofs associated with the given @a face. + @a *dofs is set to an internal array of the local dofc on the face, while *ndofs is set to the number of dofs on that face. */ virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const; @@ -554,7 +556,7 @@ public: /// Deconstruct the FiniteElement virtual ~FiniteElement(); - /** @brief Return true if the BasisType of @a b_type is closed + /** @brief Return true if the BasisType of @a b_type is closed (has Quadrature1D points on the boundary). */ static bool IsClosedType(int b_type) { @@ -563,7 +565,7 @@ public: (Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid)); } - /** @brief Return true if the BasisType of @a b_type is open + /** @brief Return true if the BasisType of @a b_type is open (doesn't have Quadrature1D points on the boundary). */ static bool IsOpenType(int b_type) { @@ -572,7 +574,7 @@ public: (Quadrature1D::CheckOpen(q_type) != Quadrature1D::Invalid)); } - /** @brief Ensure that the BasisType of @a b_type is closed + /** @brief Ensure that the BasisType of @a b_type is closed (has Quadrature1D points on the boundary). */ static int VerifyClosed(int b_type) { @@ -581,16 +583,16 @@ public: return b_type; } - /** @brief Ensure that the BasisType of @a b_type is open - (doesn't have Quadrature1D points on the boundary). */ + /** @brief Ensure that the BasisType of @a b_type is open + (doesn't have Quadrature1D points on the boundary). */ static int VerifyOpen(int b_type) { MFEM_VERIFY(IsOpenType(b_type), "invalid open basis type: " << b_type); return b_type; } - /** @brief Ensure that the BasisType of @a b_type nodal - (satisfies the interpolation property). */ + /** @brief Ensure that the BasisType of @a b_type nodal + (satisfies the interpolation property). */ static int VerifyNodal(int b_type) { return BasisType::CheckNodal(b_type); @@ -622,7 +624,7 @@ public: @param Do Number of degrees of freedom in the FiniteElement @param O Order/degree of the FiniteElement @param F FunctionSpace type of the FiniteElement - */ + */ ScalarFiniteElement(int D, Geometry::Type G, int Do, int O, int F = FunctionSpace::Pk) #ifdef MFEM_THREAD_SAFE @@ -643,13 +645,13 @@ public: } - /** @brief Get the matrix @a I that defines nodal interpolation + /** @brief Get the matrix @a I that defines nodal interpolation @a between this element and the refined element @a fine_fe. */ void NodalLocalInterpolation(ElementTransformation &Trans, DenseMatrix &I, const ScalarFiniteElement &fine_fe) const; - /** @brief Get matrix @a I "Interpolation" defined through local + /** @brief Get matrix @a I "Interpolation" defined through local L2-projection in the space defined by the @a fine_fe. */ /** If the "fine" elements cannot represent all basis functions of the "coarse" element, then boundary values from different sub-elements are @@ -725,7 +727,7 @@ public: @param Do Number of degrees of freedom in the FiniteElement @param O Order/degree of the FiniteElement @param F FunctionSpace type of the FiniteElement - */ + */ PositiveFiniteElement(int D, Geometry::Type G, int Do, int O, int F = FunctionSpace::Pk) : ScalarFiniteElement(D, G, Do, O, F) @@ -969,7 +971,7 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; -/** @brief A 2D linear element on a square with 3 nodes at the +/** @brief A 2D linear element on a square with 3 nodes at the vertices of the lower left triangle */ class P1OnQuadFiniteElement : public NodalFiniteElement { @@ -1007,7 +1009,7 @@ public: class QuadPos1DFiniteElement : public PositiveFiniteElement { public: - /// Construct the FiniteElement + /// Construct the FiniteElement QuadPos1DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1200,7 +1202,7 @@ public: }; -/** @brief A 3D linear element on a tetrahedron with nodes at the +/** @brief A 3D linear element on a tetrahedron with nodes at the vertices of the tetrahedron */ class Linear3DFiniteElement : public NodalFiniteElement { @@ -1223,8 +1225,8 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const { dofs = 0.0; dofs(vertex) = 1.0; } - /** @brief Get the dofs associated with the given @a face. - @a *dofs is set to an internal array of the local dofc on the + /** @brief Get the dofs associated with the given @a face. + @a *dofs is set to an internal array of the local dofc on the face, while *ndofs is set to the number of dofs on that face. */ virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const; @@ -1543,7 +1545,7 @@ public: { dofs(0) = 1.0; } }; -/** @brief Tensor products of 1D Lagrange1DFiniteElement +/** @brief Tensor products of 1D Lagrange1DFiniteElement (only degree 2 is functional) */ class LagrangeHexFiniteElement : public NodalFiniteElement { @@ -1745,7 +1747,7 @@ private: static const double nk[36][3]; public: - /// Construct the FiniteElement + /// Construct the FiniteElement RT1HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1929,12 +1931,12 @@ public: and store them in the allready allocated @a u array. */ static void CalcBinomTerms(const int p, const double x, const double y, double *u); - /** @brief Compute the terms in the expansion of the binomial (x + y)^p and + /** @brief Compute the terms in the expansion of the binomial (x + y)^p and their derivatives with respect to x assuming that dy/dx = -1. Store the results in the already allocated @a u and @a d arrays.*/ static void CalcBinomTerms(const int p, const double x, const double y, double *u, double *d); - /** @brief Compute the derivatives (w.r.t. x) of the terms in the expansion + /** @brief Compute the derivatives (w.r.t. x) of the terms in the expansion of the binomial (x + y)^p assuming that dy/dx = -1. Store the results in the already allocated @a d array.*/ static void CalcDBinomTerms(const int p, const double x, const double y, @@ -1946,9 +1948,9 @@ public: static void CalcBernstein(const int p, const double x, double *u) { CalcBinomTerms(p, x, 1. - x, u); } - /** @brief Compute the values and derivatives of the Bernstein basis functions + /** @brief Compute the values and derivatives of the Bernstein basis functions of order @a p at coordinate @a x and store the results in the already allocated - @a u and @a d arrays. */ + @a u and @a d arrays. */ static void CalcBernstein(const int p, const double x, double *u, double *d) { CalcBinomTerms(p, x, 1. - x, u, d); } @@ -2689,7 +2691,7 @@ class RT_HexahedronElement : public VectorFiniteElement public: /** @brief Construct the FiniteElement of order @a p and closed and open - BasisType @a cb_type and @a ob_type */ + BasisType @a cb_type and @a ob_type */ RT_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2916,7 +2918,7 @@ class ND_QuadrilateralElement : public VectorTensorFiniteElement public: /** @brief Construct the FiniteElement of order @a p and closed and open - BasisType @a cb_type and @a ob_type */ + BasisType @a cb_type and @a ob_type */ ND_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -3072,7 +3074,7 @@ class ND_SegmentElement : public VectorFiniteElement public: /** @brief Construct the FiniteElement of order @a p and open - BasisType @a ob_type */ + BasisType @a ob_type */ ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const { obasis1d.Eval(ip.x, shape); } @@ -3127,7 +3129,7 @@ public: @param Do Number of degrees of freedom in the FiniteElement @param O Order/degree of the FiniteElement @param F FunctionSpace type of the FiniteElement - */ + */ NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F) : ScalarFiniteElement(D, G, Do, O, F) { diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index c0c16bb266..33fb35a74e 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -71,7 +71,7 @@ public: | :------: | :---: | :---: | :-------: | :-----: | :---: | | H1_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements | | H1@[BTYPE]_[DIM]_[ORDER] | H1 | * | * | VALUE | H1 nodal elements | - | H1Pos_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements | + | H1Pos_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements | | H1Pos_Trace_[DIM]_[ORDER] | H^{1/2} | * | 2 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) | | H1_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) | | H1_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) | @@ -95,7 +95,7 @@ public: | DG_IntIface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) | | NURBS[ORDER] | - | * | - | VALUE | Non-Uniform Rational B-Splines (NURBS) elements | | LinearNonConf3D | - | 1 | 1 | VALUE | Piecewise-linear nonconforming finite elements in 3D | - | CrouzeixRaviart | - | - | - | - | Crouzeix-Raviart nonconforming elements in 2D | + | CrouzeixRaviart | - | - | - | - | Crouzeix-Raviart nonconforming elements in 2D | | Local_[FENAME] | - | - | - | - | Special collection that builds a local version out of the FENAME collection | |-|-|-|-|-|-| | Linear | H1 | 1 | 1 | VALUE | Left in for backward compatibility, consider using H1_ | @@ -103,13 +103,13 @@ public: | QuadraticPos | H1 | 2 | 2 | VALUE | Left in for backward compatibility, consider using H1_ | | Cubic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ | | Const2D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | - | Const3D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | Const3D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | | LinearDiscont2D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | | GaussLinearDiscont2D | L2 | 1 | 0 | VALUE | Left in for backward compatibility, consider using L2_ | | P1OnQuad | H1 | 1 | 1 | VALUE | Linear P1 element with 3 nodes on a square | - | QuadraticDiscont2D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | + | QuadraticDiscont2D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | | QuadraticPosDiscont2D | L2 | 2 | 2 | VALUE | Left in for backward compatibility, consider using L2_ | - | GaussQuadraticDiscont2D | L2 | 2 | 0 | VALUE | Left in for backward compatibility, consider using L2_ | + | GaussQuadraticDiscont2D | L2 | 2 | 0 | VALUE | Left in for backward compatibility, consider using L2_ | | CubicDiscont2D | L2 | 3 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | | LinearDiscont3D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | | QuadraticDiscont3D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ | @@ -129,7 +129,7 @@ public: | [CBTYPE] | Closed BasisType of the element for elements which have both types | [FENAME] Is a special case for the Local FEC which generates a local version of a given - FEC. It is selected from one of (BiCubic2DFiniteElement, Quad_Q3, Nedelec1HexFiniteElement, + FEC. It is selected from one of (BiCubic2DFiniteElement, Quad_Q3, Nedelec1HexFiniteElement, Hex_ND1, H1_[DIM]_[ORDER],H1Pos_[DIM]_[ORDER], L2_[DIM]_[ORDER] ) */ static FiniteElementCollection *New(const char *name); diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 91f1c96c99..06ae83e873 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -87,7 +87,7 @@ protected: /** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated on a kernel, eg. ElementMatrix::Compute may be AssembleGradGrad()). - @tparam BE batch size of elements */ + @tparam BE batch size of elements */ template struct S_spec { typedef typename solFieldEval::template Spec Spec; diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index c3f4e5c1fe..c3d8068dd2 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -52,7 +52,7 @@ struct TMassKernel static const bool in_gradients = false; static const bool out_values = true; static const bool out_gradients = false; - ///@} + ///@} /** Partially assembled data type for one element with the given number of quadrature points. This type is used in partial assembly, and partially diff --git a/fem/tcoefficient.hpp b/fem/tcoefficient.hpp index 04947e7211..9b1b619aac 100644 --- a/fem/tcoefficient.hpp +++ b/fem/tcoefficient.hpp @@ -178,7 +178,7 @@ public: } }; -/// GridFunction coefficient class. +/// GridFunction coefficient class. template class TGridFunctionCoefficient : public TCoefficient { diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 7c18498084..0557669933 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -1143,7 +1143,7 @@ public: }; /** @brief Auxiliary templated struct AData, used by the Eval() and Assemble() - methods. + methods. The template parameter IOData is "bitwise or" of constants from the enum InOutData. The parameter NE is the number of elements to be diff --git a/general/array.hpp b/general/array.hpp index 90bbf60d5c..28115dd18d 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -239,7 +239,7 @@ public: template void Sort(Compare cmp) { std::sort((T*)data, data + size, cmp); } - /** @brief Removes duplicities from a sorted array. This requires + /** @brief Removes duplicities from a sorted array. This requires operator== to be defined for T. */ void Unique() { diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index 2937da4224..63e7ff501c 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -416,7 +416,7 @@ public: }; -/** The memory manager class. Host side pointers are inserted into this +/** The memory manager class. Host side pointers are inserted into this manager which keeps track of the associated device pointer, and where the data currently resides. */ class MemoryManager diff --git a/general/optparser.hpp b/general/optparser.hpp index 3d0ea98f6b..1d24052f4b 100644 --- a/general/optparser.hpp +++ b/general/optparser.hpp @@ -132,7 +132,7 @@ public: required)); } - /** @brief Parse the command-line options. + /** @brief Parse the command-line options. Note that this function expects all the options provided through the command line to have a corresponding diff --git a/general/sets.hpp b/general/sets.hpp index cad531b2a6..2495c6dfe2 100644 --- a/general/sets.hpp +++ b/general/sets.hpp @@ -72,7 +72,7 @@ public: /// Return a random value from the ith set in the list. int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); } - /** @brief Check to see if set 's' is in the list. If not append it to the end of the + /** @brief Check to see if set 's' is in the list. If not append it to the end of the list. Returns the index of the list where set 's' can be found. */ int Insert(IntegerSet &s); diff --git a/general/socketstream.hpp b/general/socketstream.hpp index 8f0fdf22b4..72b38c40ce 100644 --- a/general/socketstream.hpp +++ b/general/socketstream.hpp @@ -61,8 +61,8 @@ public: /// Detatch the current socket descriptor from the socketbuf. int detach() { return attach(-1); } - /** @brief Open a socket on the 'port' at 'hostname' and store the - socket descriptor. Returns 0 if there is no error, + /** @brief Open a socket on the 'port' at 'hostname' and store the + socket descriptor. Returns 0 if there is no error, otherwise returns -1. */ virtual int open(const char hostname[], int port); @@ -72,7 +72,7 @@ public: /// Returns the attached socket descriptor. int getsocketdescriptor() { return socket_descriptor; } - /** @brief Returns true of the socket is open and has a valid + /** @brief Returns true of the socket is open and has a valid socket descriptor. Otherwise returns false. */ bool is_open() { return (socket_descriptor >= 0); } diff --git a/general/stable3d.hpp b/general/stable3d.hpp index fc623af9b5..1a1421df4b 100644 --- a/general/stable3d.hpp +++ b/general/stable3d.hpp @@ -25,12 +25,12 @@ public: int Column, Floor, Number; }; -/** @brief Symmetric 3D Table stored an array of rows each of which has +/** @brief Symmetric 3D Table stored an array of rows each of which has a stack of column, floor, number nodes. The number of the node - is assigned by counting the nodes from zero as they are pushed + is assigned by counting the nodes from zero as they are pushed into the table. Diagonals of any kind are not so the row, column - and floor must all be different for each node. Only one node is - stored for all 6 symmetric entries that are indexable by unique + and floor must all be different for each node. Only one node is + stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor. */ class STable3D @@ -47,7 +47,7 @@ public: /// Construct the table with a total of 'nr' rows. explicit STable3D (int nr); - /** @brief Check to see if this entry is in the table and add it to + /** @brief Check to see if this entry is in the table and add it to the table if it is not there. Returns the number assigned to the table entry. */ int Push (int r, int c, int f); @@ -58,13 +58,13 @@ public: /// Return the number assigned to the table entry. Return -1 if it's not there. int Index (int r, int c, int f) const; - /** @brief Check to see if this entry is in the table and add it to - the table if it is not there. The entry is addressed by the three + /** @brief Check to see if this entry is in the table and add it to + the table if it is not there. The entry is addressed by the three smallest values of (r,c,f,t). Returns the number assigned to the table entry. */ int Push4 (int r, int c, int f, int t); - /** Return the number assigned to the table entry. The entry is + /** Return the number assigned to the table entry. The entry is addressed by the three smallest values of (r,c,f,t). Return -1 if it is not there. */ int operator() (int r, int c, int f, int t) const; From 9b0641f472668fae60974f7b23cb3b4f1285dc3f Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 9 Apr 2020 19:48:05 -0700 Subject: [PATCH 166/535] First derivative of the new limiting term. --- fem/tmop.cpp | 36 +++++++++++++++++++++++----- general/error.cpp | 2 ++ miniapps/meshing/pmesh-optimizer.cpp | 2 +- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index abb8ac4667..4f82dbfcfb 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1284,7 +1284,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, // Define ref->physical transformation, when a Coefficient is specified. IsoparametricTransformation *Tpr = NULL; - if (coeff1 || coeff0 || xi_0) + if (coeff1 || coeff0 || zeta) { Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); @@ -1417,7 +1417,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, // Define ref->physical transformation, when a Coefficient is specified. IsoparametricTransformation *Tpr = NULL; - if (coeff1 || coeff0) + if (coeff1 || coeff0 || zeta) { Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); @@ -1426,6 +1426,23 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T } + Vector z_e_vals, z_q_vals, grad_z_vec; + DenseMatrix grad_phys, grad_z; + Array dofs; + if (zeta) + { + shape.SetSize(dof); + z_q_vals.SetSize(ir->GetNPoints()); + zeta->GetValues(T.ElementNo, *ir, z_q_vals); + + zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); + zeta->GetSubVector(dofs, z_e_vals); + el.ProjectGrad(el, *Tpr, grad_phys); + grad_z_vec.SetSize(dof*dim); + grad_phys.Mult(z_e_vals, grad_z_vec); + grad_z.UseExternalData(grad_z_vec.GetData(), dof, dim); + } + for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); @@ -1457,6 +1474,17 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, grad *= weight * lim_normal * coeff0->Eval(*Tpr, ip); AddMultVWt(shape, grad, PMatO); } + + if (zeta) + { + // Adaptive limiting. + grad.SetSize(dim); + grad_z.MultTranspose(z_e_vals, grad); + el.CalcShape(ip, shape); + grad *= 2.0 * (xi_0->GetValue(T.ElementNo, ip) - z_q_vals(i)); + grad *= 10.0 * weight * lim_normal; + AddMultVWt(shape, grad, PMatO); + } } delete Tpr; } @@ -1799,12 +1827,8 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x, void TMOP_Integrator::UpdateAfterMeshChange(const Vector &new_x) { - std::cout << "Update 1 " << zeta->Norml2() << std::endl; // Update zeta if adaptive limiting is enabled. - if (zeta) { adapt_eval->ComputeAtNewPosition(new_x, *zeta); } - - std::cout << "Update 2 " << zeta->Norml2() << std::endl; } void TMOP_Integrator::ComputeFDh(const Vector &x, const FiniteElementSpace &fes) diff --git a/general/error.cpp b/general/error.cpp index 0e74fc2527..9a5800dc97 100644 --- a/general/error.cpp +++ b/general/error.cpp @@ -161,6 +161,8 @@ void mfem_error(const char *msg) merr << "\n\n" << msg << "\n"; } + std::abort(); // force crash by calling abort + #ifdef MFEM_USE_LIBUNWIND merr << "Backtrace:" << std::endl; mfem_backtrace(1, -1); diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index cf44c6353b..e8b0d7fda2 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,7 +32,7 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting test: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -fd -al +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -al // // Sample runs: // Adapted analytic Hessian: From e6ebf97a219beb69a0f5f2a309f7bfd2353e53b9 Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 10 Apr 2020 18:28:38 -0700 Subject: [PATCH 167/535] First and second (approximate) derivatives of the adaptive limiting term. --- fem/tmop.cpp | 138 ++++++++++++++++++++------- fem/tmop.hpp | 22 ++--- miniapps/meshing/pmesh-optimizer.cpp | 18 ++-- 3 files changed, 119 insertions(+), 59 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 4f82dbfcfb..becb0afd27 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1212,11 +1212,12 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, } } -void TMOP_Integrator::EnableDiscrAdaptiveLimiting(const GridFunction &xi0_gf, - GridFunction &zeta_gf) +void TMOP_Integrator::EnableDiscrAdaptiveLimiting( + const GridFunction &zeta0_gf, GridFunction &zeta_gf, Coefficient &coeff) { - xi_0 = &xi0_gf; + zeta_0 = &zeta0_gf; zeta = &zeta_gf; + coeff_zeta = &coeff; adapt_eval = new AdvectorCG; adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(), *zeta->FESpace()->FEColl(), 1); @@ -1224,11 +1225,12 @@ void TMOP_Integrator::EnableDiscrAdaptiveLimiting(const GridFunction &xi0_gf, (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } -void TMOP_Integrator::EnableDiscrAdaptiveLimiting(const ParGridFunction &xi0_gf, - ParGridFunction &zeta_gf) +void TMOP_Integrator::EnableDiscrAdaptiveLimiting( + const ParGridFunction &zeta0_gf, ParGridFunction &zeta_gf, Coefficient &coeff) { - xi_0 = &xi0_gf; + zeta_0 = &zeta0_gf; zeta = &zeta_gf; + coeff_zeta = &coeff; adapt_eval = new AdvectorCG; adapt_eval->SetParMetaInfo(*zeta_gf.ParFESpace()->GetParMesh(), *zeta_gf.ParFESpace()->FEColl(), 1); @@ -1328,8 +1330,8 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, { // Adaptive limiting. const double diff = - xi_0->GetValue(T.ElementNo, ip) - zeta->GetValue(T.ElementNo, ip); - val += 10.0 * lim_normal * diff * diff; + zeta->GetValue(T.ElementNo, ip) - zeta_0->GetValue(T.ElementNo, ip); + val += coeff_zeta->Eval(*Tpr, ip) * lim_normal * diff * diff; } energy += weight * val; @@ -1426,27 +1428,32 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T } - Vector z_e_vals, z_q_vals, grad_z_vec; - DenseMatrix grad_phys, grad_z; - Array dofs; + Vector zeta_e, zeta_q; + DenseMatrix zeta_grad_e; + Vector zeta_grad_q; if (zeta) { shape.SetSize(dof); - z_q_vals.SetSize(ir->GetNPoints()); - zeta->GetValues(T.ElementNo, *ir, z_q_vals); - + Array dofs; zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); - zeta->GetSubVector(dofs, z_e_vals); + zeta->GetSubVector(dofs, zeta_e); + zeta->GetValues(T.ElementNo, *ir, zeta_q); + + // Project the gradient of zeta in the same space. + // The FE coefficients of the gradient go in zeta_grad_e. + DenseMatrix grad_phys; // This will be (dof x dim, dof). el.ProjectGrad(el, *Tpr, grad_phys); - grad_z_vec.SetSize(dof*dim); - grad_phys.Mult(z_e_vals, grad_z_vec); - grad_z.UseExternalData(grad_z_vec.GetData(), dof, dim); + zeta_grad_e.SetSize(dof, dim); + Vector grad_ptr(zeta_grad_e.GetData(), dof*dim); + grad_phys.Mult(zeta_e, grad_ptr); + + zeta_grad_q.SetSize(dim); } - for (int i = 0; i < ir->GetNPoints(); i++) + for (int q = 0; q < ir->GetNPoints(); q++) { - const IntegrationPoint &ip = ir->IntPoint(i); - const DenseMatrix &Jtr_i = Jtr(i); + const IntegrationPoint &ip = ir->IntPoint(q); + const DenseMatrix &Jtr_i = Jtr(q); metric->SetTargetJacobian(Jtr_i); CalcInverse(Jtr_i, Jrt); const double weight = ip.weight * Jtr_i.Det(); @@ -1470,20 +1477,18 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, el.CalcShape(ip, shape); PMatI.MultTranspose(shape, p); pos0.MultTranspose(shape, p0); - lim_func->Eval_d1(p, p0, d_vals(i), grad); + lim_func->Eval_d1(p, p0, d_vals(q), grad); grad *= weight * lim_normal * coeff0->Eval(*Tpr, ip); AddMultVWt(shape, grad, PMatO); } if (zeta) { - // Adaptive limiting. - grad.SetSize(dim); - grad_z.MultTranspose(z_e_vals, grad); el.CalcShape(ip, shape); - grad *= 2.0 * (xi_0->GetValue(T.ElementNo, ip) - z_q_vals(i)); - grad *= 10.0 * weight * lim_normal; - AddMultVWt(shape, grad, PMatO); + zeta_grad_e.MultTranspose(shape, zeta_grad_q); + zeta_grad_q *= 2.0 * (zeta_q(q) - zeta_0->GetValue(T.ElementNo, ip)); + zeta_grad_q *= coeff_zeta->Eval(*Tpr, ip) * weight * lim_normal; + AddMultVWt(shape, zeta_grad_q, PMatO); } } delete Tpr; @@ -1494,7 +1499,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, const Vector &elfun, DenseMatrix &elmat) { - int dof = el.GetDof(), dim = el.GetDim(); + const int dof = el.GetDof(), dim = el.GetDim(); DSh.SetSize(dof, dim); DS.SetSize(dof, dim); @@ -1538,7 +1543,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, // Define ref->physical transformation, when a Coefficient is specified. IsoparametricTransformation *Tpr = NULL; - if (coeff1 || coeff0) + if (coeff1 || coeff0 || zeta) { Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); @@ -1547,13 +1552,44 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); } - for (int i = 0; i < ir->GetNPoints(); i++) + Vector zeta_e, zeta_q; + DenseMatrix zeta_grad_e, zeta_grad_grad_e; + Vector zeta_grad_q; + DenseMatrix zeta_grad_grad_q; + if (zeta) { - const IntegrationPoint &ip = ir->IntPoint(i); - const DenseMatrix &Jtr_i = Jtr(i); - metric->SetTargetJacobian(Jtr_i); - CalcInverse(Jtr_i, Jrt); - const double weight = ip.weight * Jtr_i.Det(); + shape.SetSize(dof); + Array dofs; + zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); + zeta->GetSubVector(dofs, zeta_e); + zeta->GetValues(T.ElementNo, *ir, zeta_q); + + // Project the gradient of zeta in the same space. + // The FE coefficients of the gradient go in zeta_grad_e. + DenseMatrix grad_phys; // This will be (dof x dim, dof). + el.ProjectGrad(el, *Tpr, grad_phys); + zeta_grad_e.SetSize(dof, dim); + Vector grad_ptr(zeta_grad_e.GetData(), dof*dim); + grad_phys.Mult(zeta_e, grad_ptr); + + // Project the gradient of each gradient of zeta in the same space. + // The FE coefficients of the second derivatives go in zeta_grad_grad_e. + zeta_grad_grad_e.SetSize(dof*dim, dim); + Mult(grad_phys, zeta_grad_e, zeta_grad_grad_e); + // Reshape to be more convenient later (no change in the data). + zeta_grad_grad_e.SetSize(dof, dim*dim); + + zeta_grad_q.SetSize(dim); + zeta_grad_grad_q.SetSize(dim, dim); + } + + for (int q = 0; q < ir->GetNPoints(); q++) + { + const IntegrationPoint &ip = ir->IntPoint(q); + const DenseMatrix &Jtr_q = Jtr(q); + metric->SetTargetJacobian(Jtr_q); + CalcInverse(Jtr_q, Jrt); + const double weight = ip.weight * Jtr_q.Det(); double weight_m = weight * metric_normal; el.CalcDShape(ip, DSh); @@ -1566,13 +1602,14 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, // TODO: derivatives of adaptivity-based targets. + // TODO optimize by symmetry. if (coeff0) { el.CalcShape(ip, shape); PMatI.MultTranspose(shape, p); pos0.MultTranspose(shape, p0); weight_m = weight * lim_normal * coeff0->Eval(*Tpr, ip); - lim_func->Eval_d2(p, p0, d_vals(i), grad_grad); + lim_func->Eval_d2(p, p0, d_vals(q), grad_grad); for (int i = 0; i < dof; i++) { const double w_shape_i = weight_m * shape(i); @@ -1589,6 +1626,33 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, } } } + + if (zeta) + { + el.CalcShape(ip, shape); + zeta_grad_e.MultTranspose(shape, zeta_grad_q); + Vector gg_ptr(zeta_grad_grad_q.GetData(), dim*dim); + zeta_grad_grad_e.MultTranspose(shape, gg_ptr); + + weight_m = coeff_zeta->Eval(*Tpr, ip) * weight * lim_normal; + for (int i = 0; i < dof; i++) + { + for (int j = 0; j < dof; j++) + { + for (int d1 = 0; d1 < dim; d1++) + { + for (int d2 = 0; d2 < dim; d2++) + { + elmat(d1*dof + i, d2*dof + j) += weight_m * + ( 2.0 * zeta_grad_q(d1) * shape(i) * + zeta_grad_q(d2) * shape(j) + + 2.0 * (zeta_q(q) - zeta_0->GetValue(T.ElementNo, ip)) * + zeta_grad_grad_q(d1, d2) * shape(i) * shape(j)); + } + } + } + } + } } delete Tpr; } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 3d0ff8c6bf..8a3a1f2adc 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -811,10 +811,10 @@ protected: double lim_normal; // Adaptive limiting. - const GridFunction *xi_0; + const GridFunction *zeta_0; GridFunction *zeta; + Coefficient *coeff_zeta; AdaptivityEvaluator *adapt_eval; - Coefficient *xi; DiscreteAdaptTC *discr_tc; @@ -881,7 +881,7 @@ public: coeff1(NULL), metric_normal(1.0), nodes0(NULL), coeff0(NULL), lim_dist(NULL), lim_func(NULL), lim_normal(1.0), - xi_0(NULL), zeta(NULL), xi(NULL), + zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL), discr_tc(dynamic_cast(tc)), fdflag(false), dxscale(1.0e3) { } @@ -923,17 +923,13 @@ public: void EnableLimiting(const GridFunction &n0, Coefficient &w0, TMOP_LimiterFunction *lfunc = NULL); - void EnableAnalyticAdaptiveLimiting(const GridFunction &xi0_gf, - Coefficient &xi_coeff) - { - xi_0 = &xi0_gf; - xi = &xi_coeff; - } - void EnableDiscrAdaptiveLimiting(const GridFunction &xi0_gf, - GridFunction &zeta_gf); + void EnableDiscrAdaptiveLimiting(const GridFunction &zeta0_gf, + GridFunction &zeta_gf, + Coefficient &coeff); #ifdef MFEM_USE_MPI - void EnableDiscrAdaptiveLimiting(const ParGridFunction &xi0_gf, - ParGridFunction &zeta_gf); + void EnableDiscrAdaptiveLimiting(const ParGridFunction &zeta0_gf, + ParGridFunction &zeta_gf, + Coefficient &coeff); #endif /// Update the original/reference nodes used for limiting. diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index e8b0d7fda2..7910e3e767 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -621,17 +621,17 @@ int main (int argc, char *argv[]) if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); } // Adaptive limiting. - ParGridFunction xi_0; - ParGridFunction zeta(&ind_fes); - xi_0.SetSpace(&ind_fes); - FunctionCoefficient alim_coeff(adapt_lim_fun); - zeta.ProjectCoefficient(alim_coeff); - xi_0.ProjectCoefficient(alim_coeff); + ParGridFunction zeta_0(&ind_fes), zeta(&ind_fes); + ConstantCoefficient coeff_zeta(10.0); if (adapt_lim) { - he_nlf_integ->EnableDiscrAdaptiveLimiting(xi_0, zeta); + FunctionCoefficient alim_coeff(adapt_lim_fun); + zeta.ProjectCoefficient(alim_coeff); + zeta_0.ProjectCoefficient(alim_coeff); + he_nlf_integ->EnableDiscrAdaptiveLimiting(zeta_0, zeta, coeff_zeta); socketstream vis1; - common::VisualizeField(vis1, "localhost", 19916, zeta, "Zeta 0", 300, 600, 300, 300); + common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", + 300, 600, 300, 300); } // 15. Setup the final NonlinearForm (which defines the integral of interest, @@ -865,7 +865,7 @@ int main (int argc, char *argv[]) if (adapt_lim) { socketstream vis0; - common::VisualizeField(vis0, "localhost", 19916, xi_0, "Xi 0", 600, 600, 300, 300); + common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0", 600, 600, 300, 300); } // 23. Visualize the mesh displacement. From 3c404a6b27d5c563227424e4b4a1645fae1ef02b Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 10 Apr 2020 19:09:21 -0700 Subject: [PATCH 168/535] Optimized using the symmetry of the Hessians. --- fem/tmop.cpp | 28 +++++++++++++--------------- fem/tmop.hpp | 4 ++-- miniapps/meshing/pmesh-optimizer.cpp | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index becb0afd27..77c0c4f1bc 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1212,7 +1212,7 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, } } -void TMOP_Integrator::EnableDiscrAdaptiveLimiting( +void TMOP_Integrator::EnableAdaptiveLimiting( const GridFunction &zeta0_gf, GridFunction &zeta_gf, Coefficient &coeff) { zeta_0 = &zeta0_gf; @@ -1225,7 +1225,7 @@ void TMOP_Integrator::EnableDiscrAdaptiveLimiting( (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } -void TMOP_Integrator::EnableDiscrAdaptiveLimiting( +void TMOP_Integrator::EnableAdaptiveLimiting( const ParGridFunction &zeta0_gf, ParGridFunction &zeta_gf, Coefficient &coeff) { zeta_0 = &zeta0_gf; @@ -1635,21 +1635,19 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, zeta_grad_grad_e.MultTranspose(shape, gg_ptr); weight_m = coeff_zeta->Eval(*Tpr, ip) * weight * lim_normal; - for (int i = 0; i < dof; i++) + for (int i = 0; i < dof * dim; i++) { - for (int j = 0; j < dof; j++) + const int idof = i % dof, idim = i / dof; + for (int j = 0; j <= i; j++) { - for (int d1 = 0; d1 < dim; d1++) - { - for (int d2 = 0; d2 < dim; d2++) - { - elmat(d1*dof + i, d2*dof + j) += weight_m * - ( 2.0 * zeta_grad_q(d1) * shape(i) * - zeta_grad_q(d2) * shape(j) + - 2.0 * (zeta_q(q) - zeta_0->GetValue(T.ElementNo, ip)) * - zeta_grad_grad_q(d1, d2) * shape(i) * shape(j)); - } - } + const int jdof = j % dof, jdim = j / dof; + const double entry = weight_m * + ( 2.0 * zeta_grad_q(idim) * shape(idof) * + zeta_grad_q(jdim) * shape(jdof) + + 2.0 * (zeta_q(q) - zeta_0->GetValue(T.ElementNo, ip)) * + zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof)); + elmat(i, j) += entry; + if (i != j) { elmat(j, i) += entry; } } } } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 8a3a1f2adc..039f68af25 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -923,11 +923,11 @@ public: void EnableLimiting(const GridFunction &n0, Coefficient &w0, TMOP_LimiterFunction *lfunc = NULL); - void EnableDiscrAdaptiveLimiting(const GridFunction &zeta0_gf, + void EnableAdaptiveLimiting(const GridFunction &zeta0_gf, GridFunction &zeta_gf, Coefficient &coeff); #ifdef MFEM_USE_MPI - void EnableDiscrAdaptiveLimiting(const ParGridFunction &zeta0_gf, + void EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, ParGridFunction &zeta_gf, Coefficient &coeff); #endif diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 7910e3e767..a507779f28 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -628,7 +628,7 @@ int main (int argc, char *argv[]) FunctionCoefficient alim_coeff(adapt_lim_fun); zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); - he_nlf_integ->EnableDiscrAdaptiveLimiting(zeta_0, zeta, coeff_zeta); + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coeff_zeta); socketstream vis1; common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", 300, 600, 300, 300); From f8dd9bd06cec874af98e7b3d0a50eebf479e7e3e Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 10 Apr 2020 19:28:02 -0700 Subject: [PATCH 169/535] More optimizations. --- fem/tmop.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 77c0c4f1bc..c577ed9322 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1302,6 +1302,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, // the physical coordinates (i.e. changes in 'elfun'), e.g. when the // coefficient is a ConstantCoefficient or a GridFunctionCoefficient. + Vector zeta_q, zeta0_q; + if (zeta) + { + zeta->GetValues(T.ElementNo, *ir, zeta_q); + zeta_0->GetValues(T.ElementNo, *ir, zeta0_q); + } + for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); @@ -1328,9 +1335,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, if (zeta) { - // Adaptive limiting. - const double diff = - zeta->GetValue(T.ElementNo, ip) - zeta_0->GetValue(T.ElementNo, ip); + const double diff = zeta_q(i) - zeta0_q(i); val += coeff_zeta->Eval(*Tpr, ip) * lim_normal * diff * diff; } @@ -1428,7 +1433,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T } - Vector zeta_e, zeta_q; + Vector zeta_e, zeta_q, zeta0_q; DenseMatrix zeta_grad_e; Vector zeta_grad_q; if (zeta) @@ -1438,6 +1443,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); zeta->GetSubVector(dofs, zeta_e); zeta->GetValues(T.ElementNo, *ir, zeta_q); + zeta_0->GetValues(T.ElementNo, *ir, zeta0_q); // Project the gradient of zeta in the same space. // The FE coefficients of the gradient go in zeta_grad_e. @@ -1486,7 +1492,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, { el.CalcShape(ip, shape); zeta_grad_e.MultTranspose(shape, zeta_grad_q); - zeta_grad_q *= 2.0 * (zeta_q(q) - zeta_0->GetValue(T.ElementNo, ip)); + zeta_grad_q *= 2.0 * (zeta_q(q) - zeta0_q(q)); zeta_grad_q *= coeff_zeta->Eval(*Tpr, ip) * weight * lim_normal; AddMultVWt(shape, zeta_grad_q, PMatO); } @@ -1552,7 +1558,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); } - Vector zeta_e, zeta_q; + Vector zeta_e, zeta_q, zeta0_q; DenseMatrix zeta_grad_e, zeta_grad_grad_e; Vector zeta_grad_q; DenseMatrix zeta_grad_grad_q; @@ -1563,6 +1569,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); zeta->GetSubVector(dofs, zeta_e); zeta->GetValues(T.ElementNo, *ir, zeta_q); + zeta_0->GetValues(T.ElementNo, *ir, zeta0_q); // Project the gradient of zeta in the same space. // The FE coefficients of the gradient go in zeta_grad_e. @@ -1644,7 +1651,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, const double entry = weight_m * ( 2.0 * zeta_grad_q(idim) * shape(idof) * zeta_grad_q(jdim) * shape(jdof) + - 2.0 * (zeta_q(q) - zeta_0->GetValue(T.ElementNo, ip)) * + 2.0 * (zeta_q(q) - zeta0_q(q)) * zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof)); elmat(i, j) += entry; if (i != j) { elmat(j, i) += entry; } From c2a80e493ceefd2d84083c4429dd43c92983cebb Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 14 Apr 2020 12:37:01 +0200 Subject: [PATCH 170/535] Rename and relocate face generation function --- fem/fespace.cpp | 15 ++++----------- fem/fespace.hpp | 8 ++++++-- mesh/mesh.cpp | 1 + 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index b47de11199..c0ef4ea439 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1432,6 +1432,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext, own_ext = 1; } UpdateNURBS(); + GenerateFaceDofsFromBdr(); cP = cR = NULL; cP_is_set = false; } @@ -1469,10 +1470,11 @@ void FiniteElementSpace::UpdateNURBS() ndofs = NURBSext->GetNDof(); elem_dof = NURBSext->GetElementDofTable(); bdrElem_dof = NURBSext->GetBdrElementDofTable(); - face_dof = NULL;// NURBSext->GetFaceDofTable(); + face_dof = NULL; + } -void FiniteElementSpace::GenerateFaceDofs() +void FiniteElementSpace::GenerateFaceDofsFromBdr() { if (face_dof) { return; } @@ -1766,13 +1768,6 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const { - - if (NURBSext) - { - const_cast - (this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT - } - if (face_dof) { face_dof->GetRow(i, dofs); @@ -1963,8 +1958,6 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const if (NURBSext) { - const_cast - (this)->GenerateFaceDofs(); // NEED_BETTER_PLACEMENT NURBSext->LoadBE(face_to_be[i], fe); } diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 2b11a6cecc..2776d1efc8 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -521,13 +521,18 @@ public: is preserved. */ void ReorderElementToDofTable(); + /** @brief Generates partial face_dof table. + + Table only defined for face on boundary. Uses bdrElem_dof table + and the mesh boundary information.*/ + void GenerateFaceDofsFromBdr(); + void BuildDofToArrays(); const Table &GetElementToDofTable() const { return *elem_dof; } const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; } const Table &GetFaceToDofTable() const { return *face_dof; } - int GetElementForDof(int i) const { return dof_elem_array[i]; } int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; } @@ -674,7 +679,6 @@ public: virtual ~FiniteElementSpace(); - void GenerateFaceDofs(); }; diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index cef74d7252..7e40f3a336 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -3824,6 +3824,7 @@ void Mesh::UpdateNURBS() GetElementToFaceTable(); GenerateFaces(); } + Nodes->FESpace()->GenerateFaceDofsFromBdr(); } void Mesh::LoadPatchTopo(std::istream &input, Array &edge_to_knot) From a9496f3c5816896a594261a907047811662b6ae4 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 14 Apr 2020 17:10:33 +0200 Subject: [PATCH 171/535] No strong BCs if switch is set. Increased penalty --- miniapps/nurbs/nurbs_ex1.cpp | 2 +- miniapps/nurbs/nurbs_ex1p.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index d590bab128..0d3e75a823 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -173,7 +173,7 @@ int main(int argc, char *argv[]) } if (!strongBC & (kappa < 0)) { - kappa = (order.Max()+1)*(order.Max()+1); + kappa = 4*(order.Max()+1)*(order.Max()+1); } args.PrintOptions(cout); diff --git a/miniapps/nurbs/nurbs_ex1p.cpp b/miniapps/nurbs/nurbs_ex1p.cpp index a5c6808cfd..4a5a679183 100644 --- a/miniapps/nurbs/nurbs_ex1p.cpp +++ b/miniapps/nurbs/nurbs_ex1p.cpp @@ -186,7 +186,7 @@ int main(int argc, char *argv[]) } if (!strongBC & (kappa < 0)) { - kappa = (order.Max()+1)*(order.Max()+1); + kappa = 4*(order.Max()+1)*(order.Max()+1); } if (myid == 0) { @@ -313,7 +313,14 @@ int main(int argc, char *argv[]) if (pmesh->bdr_attributes.Size()) { Array ess_bdr(pmesh->bdr_attributes.Max()); - ess_bdr = 1; + if (strongBC) + { + ess_bdr = 1; + } + else + { + ess_bdr = 0; + } fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); } From 52ccf07bdbe58fce618a61fd482684583261a698 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 14 Apr 2020 17:11:33 +0200 Subject: [PATCH 172/535] Default mapping value to indicate failure -1 --- fem/fespace.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index c0ef4ea439..302ef4395e 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1481,6 +1481,7 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() Array face_dof_list; Array row; face_to_be.SetSize(mesh->GetNumFaces()); + face_to_be = -1; for (int b = 0; b < bdrElem_dof->Size(); b++) { bdrElem_dof->GetRow(b, row); From 7e10b0a7eeb1d827101fed4f47fc0a52d754844d Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 14 Apr 2020 17:59:49 +0200 Subject: [PATCH 173/535] Only pritn mehs info once --- miniapps/nurbs/nurbs_ex1p.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1p.cpp b/miniapps/nurbs/nurbs_ex1p.cpp index 4a5a679183..8248962eef 100644 --- a/miniapps/nurbs/nurbs_ex1p.cpp +++ b/miniapps/nurbs/nurbs_ex1p.cpp @@ -214,8 +214,10 @@ int main(int argc, char *argv[]) { mesh->UniformRefinement(); } - - mesh->PrintInfo(); + if (myid == 0) + { + mesh->PrintInfo(); + } } // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine From 8eff49047cd02f77bd87c8e8f2d5ea5a72285bf9 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 14 Apr 2020 18:01:14 +0200 Subject: [PATCH 174/535] Add 3d tests, no data copy. Moved meshes to data --- data/cube-nurbs.mesh | 73 +++++++++++++++++++++++++++++++++++ data/pipe-nurbs-2d.mesh | 70 +++++++++++++++++++++++++++++++++ data/square-nurbs.mesh | 57 +++++++++++++++++++++++++++ miniapps/nurbs/CMakeLists.txt | 38 +++++++++++------- 4 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 data/cube-nurbs.mesh create mode 100644 data/pipe-nurbs-2d.mesh create mode 100644 data/square-nurbs.mesh diff --git a/data/cube-nurbs.mesh b/data/cube-nurbs.mesh new file mode 100644 index 0000000000..513b58982b --- /dev/null +++ b/data/cube-nurbs.mesh @@ -0,0 +1,73 @@ +MFEM NURBS mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# SEGMENT = 1 +# SQUARE = 3 +# CUBE = 5 +# + +dimension +3 + +elements +1 +1 5 0 1 2 3 4 5 6 7 + +boundary +6 +1 3 0 1 2 3 +1 3 4 5 6 7 +1 3 0 1 5 4 +1 3 1 2 6 5 +1 3 2 3 7 6 +1 3 3 0 4 7 + +edges +12 +0 0 1 +0 3 2 +0 4 5 +0 7 6 +1 0 3 +1 1 2 +1 4 7 +1 5 6 +2 0 4 +2 1 5 +2 2 6 +2 3 7 + +vertices +8 + +knotvectors +3 +1 2 0 0 1 1 +1 2 0 0 1 1 +1 2 0 0 1 1 + +weights +1 +1 +1 +1 +1 +1 +1 +1 + +FiniteElementSpace +FiniteElementCollection: NURBS1 +VDim: 3 +Ordering: 1 + +0 0 0 +1 0 0 +1 1 0 +0 1 0 +0 0 1 +1 0 1 +1 1 1 +0 1 1 diff --git a/data/pipe-nurbs-2d.mesh b/data/pipe-nurbs-2d.mesh new file mode 100644 index 0000000000..b02c040635 --- /dev/null +++ b/data/pipe-nurbs-2d.mesh @@ -0,0 +1,70 @@ +MFEM NURBS mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# SEGMENT = 1 +# SQUARE = 3 +# CUBE = 5 +# + +dimension +2 + +elements +1 +1 3 0 1 2 3 + +boundary +4 +1 1 0 1 +1 1 2 3 +1 1 3 0 +1 1 1 2 + +edges +4 +0 0 1 +0 3 2 +1 0 3 +1 1 2 + +vertices +4 + +knotvectors +2 +2 3 0 0 0 1 1 1 +2 3 0 0 0 1 1 1 + +weights +1 +1 +1 +1 + +0.7071067811865475244 +0.7071067811865475244 + +1 +1 + +0.7071067811865475244 + +FiniteElementSpace +FiniteElementCollection: NURBS2 +VDim: 2 +Ordering: 1 + +0 0 +2 2 +1 2 +0 1 + +2 0 +1 1 + +0 0.5 +1.5 2 + +1.5 0.5 diff --git a/data/square-nurbs.mesh b/data/square-nurbs.mesh new file mode 100644 index 0000000000..282818ff41 --- /dev/null +++ b/data/square-nurbs.mesh @@ -0,0 +1,57 @@ +MFEM NURBS mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# SEGMENT = 1 +# SQUARE = 3 +# CUBE = 5 +# + +dimension +2 + +elements +1 +1 3 0 1 2 3 + +boundary +4 +1 1 0 1 +1 1 2 3 +1 1 3 0 +1 1 1 2 + + + +edges +4 +0 0 1 +0 3 2 +1 0 3 +1 1 2 + +vertices +4 + +knotvectors +2 +1 2 0 0 1 1 +1 2 0 0 1 1 + +weights +1 +1 +1 +1 + +FiniteElementSpace +FiniteElementCollection: NURBS1 +VDim: 2 +Ordering: 1 + +0 0 +1 0 +1 1 +0 1 + diff --git a/miniapps/nurbs/CMakeLists.txt b/miniapps/nurbs/CMakeLists.txt index ddcbd3ee10..03815da6ea 100644 --- a/miniapps/nurbs/CMakeLists.txt +++ b/miniapps/nurbs/CMakeLists.txt @@ -9,17 +9,17 @@ # terms of the BSD-3 license. We welcome feedback and contributions, see file # CONTRIBUTING.md for details. -configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/square-nurbs.mesh - ${PROJECT_BINARY_DIR}/miniapps/nurbs/square-nurbs.mesh - COPYONLY) +#configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/square-nurbs.mesh +# ${PROJECT_BINARY_DIR}/miniapps/nurbs/square-nurbs.mesh +# COPYONLY) -configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/cube-nurbs.mesh - ${PROJECT_BINARY_DIR}/miniapps/nurbs/cube-nurbs.mesh - COPYONLY) +#configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/cube-nurbs.mesh +# ${PROJECT_BINARY_DIR}/miniapps/nurbs/cube-nurbs.mesh +# COPYONLY) -configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/pipe-nurbs-2d.mesh - ${PROJECT_BINARY_DIR}/miniapps/nurbs/pipe-nurbs-2d.mesh - COPYONLY) +#configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/pipe-nurbs-2d.mesh +# ${PROJECT_BINARY_DIR}/miniapps/nurbs/pipe-nurbs-2d.mesh +# COPYONLY) add_mfem_miniapp(nurbs_ex1 MAIN nurbs_ex1.cpp @@ -33,23 +33,27 @@ add_test(NAME nurbs_ex1_r2_ser add_test(NAME nurbs_ex1_per_ser COMMAND $ -no-vis - -m ../../data/beam-hex-nurbs.mesh -pm 1 -ps 2) + -m ${PROJECT_SOURCE_DIR}/data/beam-hex-nurbs.mesh -pm 1 -ps 2) add_test(NAME nurbs_ex1_lap_r0_ser COMMAND $ -no-vis - -m pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0) + -m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0) add_test(NAME nurbs_ex1_lap_r2_ser COMMAND $ -no-vis - -m pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2) + -m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2) add_test(NAME nurbs_ex1_weak_r0_ser COMMAND $ -no-vis - -m pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0) + -m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0) add_test(NAME nurbs_ex1_weak_r2_ser COMMAND $ -no-vis - -m pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2) + -m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2) + +add_test(NAME nurbs_ex1_weak_mp_ser + COMMAND $ -no-vis + -m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0) if (MFEM_USE_MPI) @@ -67,6 +71,12 @@ if (MFEM_USE_MPI) ${MPIEXEC_PREFLAGS} $ -no-vis -m pipe-nurbs-2d.mesh -o 2 -no-ibp ${MPIEXEC_POSTFLAGS}) + add_test(NAME nurbs_ex1p_weak_mp_np=4 + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} + ${MPIEXEC_PREFLAGS} $ -no-vis + -m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0 + ${MPIEXEC_POSTFLAGS}) + add_mfem_miniapp(nurbs_ex11p MAIN nurbs_ex11p.cpp LIBRARIES mfem) From da31bce5953cd1a1cbe6284976539a5383726b9c Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 14 Apr 2020 18:03:00 +0200 Subject: [PATCH 175/535] Make empty partition check a while loop. --- mesh/mesh.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 7e40f3a336..8af13ca5e3 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -5762,6 +5762,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method) // Check for empty partitionings (a "feature" in METIS) { Array< Pair > psize(nparts); + int empty_parts; for (i = 0; i < nparts; i++) { psize[i].one = 0; @@ -5773,7 +5774,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method) psize[partitioning[i]].one++; } - int empty_parts = 0; + empty_parts = 0; for (i = 0; i < nparts; i++) { if (psize[i].one == 0) { empty_parts++; } @@ -5781,7 +5782,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method) // This code just split the largest partitionings in two. // Do we need to replace it with something better? - if (empty_parts) + while (empty_parts) { if (print_messages) { @@ -5812,6 +5813,24 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method) } } } + + // Check for empty partitionings again + for (i = 0; i < nparts; i++) + { + psize[i].one = 0; + } + + for (i = 0; i < NumOfElements; i++) + { + psize[partitioning[i]].one++; + } + + empty_parts = 0; + for (i = 0; i < nparts; i++) + { + if (psize[i].one == 0) { empty_parts++; } + } + } } From a407734872e57f968e9657d07af5478c8466a861 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 14 Apr 2020 10:11:50 -0700 Subject: [PATCH 176/535] Reverting lambda and mu evaluations to use volume element transformations --- fem/lininteg.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 9a0eaf0e10..93cfeadf56 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -688,8 +688,8 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( double wL, wM, jcoef; { const double w = ip.weight / Tr.Elem1->Weight(); - wL = w * lambda->Eval(Tr, ip); - wM = w * mu->Eval(Tr, ip); + wL = w * lambda->Eval(*Tr.Elem1, eip); + wM = w * mu->Eval(*Tr.Elem1, eip); jcoef = kappa * (wL + 2.0*wM) * (nor*nor); dshape_ps.Mult(nor, dshape_dn); dshape_ps.Mult(u_dir, dshape_du); From c20a680439be816cd1c77ee307feaadfba1e3dca Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 14 Apr 2020 10:24:08 -0700 Subject: [PATCH 177/535] Revert u coefficient to use volume element transformation --- fem/lininteg.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 93cfeadf56..10ce318ce9 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -503,8 +503,10 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( Tr.SetIntPoint(&ip); Tr.SetActiveSide(0); - // Use Tr transformation in case u or f depends on boundary attribute - u->Eval(vu, Tr, ip); + // Use Tr.Elem1 transformation for u so that it matches the + // coefficient used with the ConvectionIntegrator and/or the + // DGTraceIntegrator. + u->Eval(vu, *Tr.Elem1, eip); if (dim == 1) { From a39c7cb7530b426f5e79cd1d72d511430787c027 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 14 Apr 2020 10:33:53 -0700 Subject: [PATCH 178/535] Fixing return type on ParMesh::GetGhostFaceTransformation --- mesh/pmesh.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index ee25264881..a5a183600f 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -103,7 +103,7 @@ protected: void GetFaceNbrElementTransformation( int i, IsoparametricTransformation *ElTr); - void GetGhostFaceTransformation( + ElementTransformation* GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom); From 9ab36ea05760f142c4b2834d91e55581d1faa75f Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Apr 2020 11:14:49 -0700 Subject: [PATCH 179/535] Small updates to VQFC and QFC classes to address some of the comments --- fem/coefficient.cpp | 29 ++++++++++---------------- fem/coefficient.hpp | 33 +++++++++--------------------- tests/unit/fem/test_quadf_coef.cpp | 22 ++++++++------------ 3 files changed, 30 insertions(+), 54 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 690892d0c0..8b1eee4d86 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -766,14 +766,21 @@ VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient( void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) { + MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); + index = 0; length = qf->GetVDim(); vdim = length; QuadF = qf; } -void VectorQuadratureFunctionCoefficient::SetLength(int _length) +void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length) { + MFEM_VERIFY(_index >= 0, "Index must be >= 0"); + MFEM_VERIFY(_index < QuadF->GetVDim(), + "Index must be < QuadratureFunction length"); + index = _index; + MFEM_VERIFY(_length > 0, "Length must be > 0"); int diff = QuadF->GetVDim() - index; @@ -784,21 +791,6 @@ void VectorQuadratureFunctionCoefficient::SetLength(int _length) vdim = length; } -void VectorQuadratureFunctionCoefficient::SetIndex(int _index) -{ - MFEM_VERIFY(_index >= 0, "Index must be >= 0"); - MFEM_VERIFY(_index < QuadF->GetVDim(), - "Index must be < the QuadratureFunction length"); - index = _index; - // check to see if length needs to be modified - int diff = QuadF->GetVDim() - index; - if (length > diff) - { - length = diff; - vdim = length; - } -} - void VectorQuadratureFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) @@ -824,15 +816,16 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, } QuadratureFunctionCoefficient::QuadratureFunctionCoefficient( - QuadratureFunction *qf) + QuadratureFunction *qf) : QuadF(qf) { MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); - QuadF = qf; } void QuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) { + MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); + MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); QuadF = qf; } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index de6a1b5e77..825d708573 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -948,7 +948,8 @@ public: class QuadratureFunction; -/// Quadrature function vector coefficient +/// Vector quadrature function coefficient which requires that the quadrature rules used for this +/// vector coefficient be the same as those that live within the supplied QuadratureFunction. class VectorQuadratureFunctionCoefficient : public VectorCoefficient { private: @@ -957,27 +958,16 @@ private: int length; public: - /// constructor with a quadrature function as input + /// Constructor with a quadrature function as input VectorQuadratureFunctionCoefficient(QuadratureFunction *qf); - /// constructor with a null qf - VectorQuadratureFunctionCoefficient() : VectorCoefficient(0), QuadF(NULL), - index(-1), length(0) {} - void SetQuadratureFunction(QuadratureFunction *qf); - /// set the starting index within the QuadFunc that'll be used to project outwards - /// if length is set to a value which will go out of bounds after this is changed than - /// it will be changed so that things still work. You should always change length right - /// after this is changed. - void SetIndex(int _index); + /// Set the starting index within the QuadFunc that'll be used to project outwards as well + /// as the corresponding length. The projected length should have the bounds of + /// 1 <= length <= (length QuadFunc - index). + void SetComponent(int _index, int _length); - /// set the length of the function that you want to project - /// the projected length should have the bounds of 1 <= len <= (length QuadFunc - index) - /// where index is the starting location within the QuadFunc that you want projected - void SetLength(int _length); - - /// getter function for the internal quadrature function QuadratureFunction *GetQuadFunction() const { return QuadF; } using VectorCoefficient::Eval; @@ -987,20 +977,17 @@ public: virtual ~VectorQuadratureFunctionCoefficient() { }; }; -/// Generic quadrature function coefficient class for using -/// coefficients which only live at integration points +/// Quadrature function coefficient which requires that the quadrature rules used for this +/// coefficient be the same as those that live within the supplied QuadratureFunction. class QuadratureFunctionCoefficient : public Coefficient { private: QuadratureFunction *QuadF; public: - /// constructor with a quadrature function as input + /// Constructor with a quadrature function as input QuadratureFunctionCoefficient(QuadratureFunction *qf); - /// constructor with a null qf - QuadratureFunctionCoefficient() : Coefficient() { QuadF = NULL; } - void SetQuadratureFunction(QuadratureFunction *qf); QuadratureFunction *GetQuadFunction() const { return QuadF; } diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 76bd45e5d2..918f7a80fa 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -71,20 +71,16 @@ TEST_CASE("Quadrature Function Coefficients", { std::cout << "Testing VecQuadFuncCoeff: " << std::endl; #ifdef MFEM_USE_EXCEPTIONS - std::cout << " Setting Index" << std::endl; - REQUIRE_THROWS(qfvc.SetIndex(3)); - REQUIRE_THROWS(qfvc.SetIndex(-1)); - REQUIRE_NOTHROW(qfvc.SetIndex(1)); - qfvc.SetIndex(0); - std::cout << " Setting Length" << std::endl; - REQUIRE_THROWS(qfvc.SetLength(4)); - qfvc.SetIndex(1); - REQUIRE_THROWS(qfvc.SetLength(3)); - REQUIRE_NOTHROW(qfvc.SetLength(2)); - REQUIRE_THROWS(qfvc.SetLength(0)); + std::cout << " Setting Component" << std::endl; + REQUIRE_THROWS(qfvc.SetComponent(3, 1)); + REQUIRE_THROWS(qfvc.SetComponent(-1, 1)); + REQUIRE_NOTHROW(qfvc.SetComponent(1, 2)); + REQUIRE_THROWS(qfvc.SetComponent(0, 4)); + REQUIRE_THROWS(qfvc.SetComponent(1, 3)); + REQUIRE_NOTHROW(qfvc.SetComponent(0, 2)); + REQUIRE_THROWS(qfvc.SetComponent(0, 0)); #endif - qfvc.SetIndex(0); - qfvc.SetLength(3); + qfvc.SetComponent(0, 3); SECTION("Gridfunction L2 tests") { From eefde7fc9d5a46230abbe6a44d7a0f93f90ac38f Mon Sep 17 00:00:00 2001 From: Andreas Schafelner <35033720+aschaf@users.noreply.github.com> Date: Wed, 15 Apr 2020 15:08:06 +0200 Subject: [PATCH 180/535] Added variable eig_est_cg_iter to HypreSmoother. Behaves as before if eig_est_cg_iter != 0, and uses hypre_ParCSRMaxEigEstimate to estimate the maximum eigenvalue otherwise. --- linalg/hypre.cpp | 30 ++++++++++++++++++++++++------ linalg/hypre.hpp | 6 ++++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index b5b5a447e1..b9d5f393c6 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1899,7 +1899,7 @@ HypreSmoother::HypreSmoother() : Solver() HypreSmoother::HypreSmoother(HypreParMatrix &_A, int _type, int _relax_times, double _relax_weight, double _omega, - int _poly_order, double _poly_fraction) + int _poly_order, double _poly_fraction, int _eig_est_cg_iter) { type = _type; relax_times = _relax_times; @@ -1907,6 +1907,7 @@ HypreSmoother::HypreSmoother(HypreParMatrix &_A, int _type, omega = _omega; poly_order = _poly_order; poly_fraction = _poly_fraction; + eig_est_cg_iter = _eig_est_cg_iter; l1_norms = NULL; pos_l1_norms = false; @@ -1929,10 +1930,11 @@ void HypreSmoother::SetSOROptions(double _relax_weight, double _omega) omega = _omega; } -void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction) +void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction, int _eig_est_cg_iter) { poly_order = _poly_order; poly_fraction = _poly_fraction; + eig_est_cg_iter = _eig_est_cg_iter; } void HypreSmoother::SetTaubinOptions(double _lambda, double _mu, @@ -2016,15 +2018,31 @@ void HypreSmoother::SetOperator(const Operator &op) if (type == 16) { poly_scale = 1; - hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, 10, - &max_eig_est, &min_eig_est); + if (eig_est_cg_iter > 0) + { + hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter, + &max_eig_est, &min_eig_est); + } + else + { + min_eig_est = 0; + hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est); + } Z = new HypreParVector(*A); } else if (type == 1001 || type == 1002) { poly_scale = 0; - hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, 10, - &max_eig_est, &min_eig_est); + if (eig_est_cg_iter > 0) + { + hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter, + &max_eig_est, &min_eig_est); + } + else + { + min_eig_est = 0; + hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est); + } // The Taubin and FIR polynomials are defined on [0, 2] max_eig_est /= 2; diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp index d8041232c4..bf0ff73266 100644 --- a/linalg/hypre.hpp +++ b/linalg/hypre.hpp @@ -615,6 +615,8 @@ protected: double *l1_norms; /// If set, take absolute values of the computed l1_norms bool pos_l1_norms; + /// Number of CG iterations to determine eigenvalue estimates + int eig_est_cg_iter; /// Maximal eigenvalue estimate for polynomial smoothing double max_eig_est; /// Minimal eigenvalue estimate for polynomial smoothing @@ -645,14 +647,14 @@ public: HypreSmoother(HypreParMatrix &_A, int type = l1GS, int relax_times = 1, double relax_weight = 1.0, double omega = 1.0, int poly_order = 2, - double poly_fraction = .3); + double poly_fraction = .3, int eig_est_cg_iter = 10); /// Set the relaxation type and number of sweeps void SetType(HypreSmoother::Type type, int relax_times = 1); /// Set SOR-related parameters void SetSOROptions(double relax_weight, double omega); /// Set parameters for polynomial smoothing - void SetPolyOptions(int poly_order, double poly_fraction); + void SetPolyOptions(int poly_order, double poly_fraction, int eig_est_cg_iter = 10); /// Set parameters for Taubin's lambda-mu method void SetTaubinOptions(double lambda, double mu, int iter); From 59901ecddc3f10a965f43b9b680bc810ab58ffa2 Mon Sep 17 00:00:00 2001 From: Andreas Schafelner <35033720+aschaf@users.noreply.github.com> Date: Wed, 15 Apr 2020 17:09:23 +0200 Subject: [PATCH 181/535] Default value in default constructor. --- linalg/hypre.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index b9d5f393c6..f53ccf6118 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1892,6 +1892,7 @@ HypreSmoother::HypreSmoother() : Solver() l1_norms = NULL; pos_l1_norms = false; + eig_est_cg_iter = 10; B = X = V = Z = NULL; X0 = X1 = NULL; fir_coeffs = NULL; From 03b50176d9e68d540dc12083a782607c79625e4d Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Apr 2020 09:13:50 -0700 Subject: [PATCH 182/535] Should fix issues with eval passing back the underlying quadrature data --- fem/coefficient.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 8b1eee4d86..caaffce72c 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -801,15 +801,19 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, int elem_no = T.ElementNo; if (index == 0 && length == QuadF->GetVDim()) { - QuadF->GetElementValues(elem_no, ip.index, V); + Vector temp; + QuadF->GetElementValues(elem_no, ip.index, temp); + V = temp; } else { - // This will need to be improved upon... Vector temp; QuadF->GetElementValues(elem_no, ip.index, temp); double *data = temp.HostReadWrite(); - V.NewDataAndSize(data + index, length); + V.SetSize(length); + for(int i = 0; i < length; i++) { + V(i) = data[index + i]; + } } return; From a8abcac9387520980abe184272745ca6571e324b Mon Sep 17 00:00:00 2001 From: Tomov Date: Wed, 15 Apr 2020 15:51:27 -0700 Subject: [PATCH 183/535] Adaptive limiting contributions in FD regime. --- fem/tmop.cpp | 281 +++++++++++++++++---------- fem/tmop.hpp | 9 +- miniapps/meshing/pmesh-optimizer.cpp | 4 +- 3 files changed, 191 insertions(+), 103 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index c577ed9322..5530653a0a 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1376,9 +1376,10 @@ void TMOP_Integrator::AssembleElementGrad(const FiniteElement &el, void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, ElementTransformation &T, - const Vector &elfun, Vector &elvect) + const Vector &elfun, + Vector &elvect) { - int dof = el.GetDof(), dim = el.GetDim(); + const int dof = el.GetDof(), dim = el.GetDim(); DSh.SetSize(dof, dim); DS.SetSize(dof, dim); @@ -1394,9 +1395,11 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, { ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- } + const int nqp = ir->GetNPoints(); elvect = 0.0; - DenseTensor Jtr(dim, dim, ir->GetNPoints()); + Vector weights(nqp); + DenseTensor Jtr(dim, dim, nqp); targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr); // Limited case. @@ -1418,7 +1421,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, } else { - d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0; + d_vals.SetSize(nqp); d_vals = 1.0; } } @@ -1433,37 +1436,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T } - Vector zeta_e, zeta_q, zeta0_q; - DenseMatrix zeta_grad_e; - Vector zeta_grad_q; - if (zeta) - { - shape.SetSize(dof); - Array dofs; - zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); - zeta->GetSubVector(dofs, zeta_e); - zeta->GetValues(T.ElementNo, *ir, zeta_q); - zeta_0->GetValues(T.ElementNo, *ir, zeta0_q); - - // Project the gradient of zeta in the same space. - // The FE coefficients of the gradient go in zeta_grad_e. - DenseMatrix grad_phys; // This will be (dof x dim, dof). - el.ProjectGrad(el, *Tpr, grad_phys); - zeta_grad_e.SetSize(dof, dim); - Vector grad_ptr(zeta_grad_e.GetData(), dof*dim); - grad_phys.Mult(zeta_e, grad_ptr); - - zeta_grad_q.SetSize(dim); - } - - for (int q = 0; q < ir->GetNPoints(); q++) + for (int q = 0; q < nqp; q++) { const IntegrationPoint &ip = ir->IntPoint(q); - const DenseMatrix &Jtr_i = Jtr(q); - metric->SetTargetJacobian(Jtr_i); - CalcInverse(Jtr_i, Jrt); - const double weight = ip.weight * Jtr_i.Det(); - double weight_m = weight * metric_normal; + const DenseMatrix &Jtr_q = Jtr(q); + metric->SetTargetJacobian(Jtr_q); + CalcInverse(Jtr_q, Jrt); + weights(q) = ip.weight * Jtr_q.Det(); + double weight_m = weights(q) * metric_normal; el.CalcDShape(ip, DSh); Mult(DSh, Jrt, DS); @@ -1484,19 +1464,13 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, PMatI.MultTranspose(shape, p); pos0.MultTranspose(shape, p0); lim_func->Eval_d1(p, p0, d_vals(q), grad); - grad *= weight * lim_normal * coeff0->Eval(*Tpr, ip); + grad *= weights(q) * lim_normal * coeff0->Eval(*Tpr, ip); AddMultVWt(shape, grad, PMatO); } - - if (zeta) - { - el.CalcShape(ip, shape); - zeta_grad_e.MultTranspose(shape, zeta_grad_q); - zeta_grad_q *= 2.0 * (zeta_q(q) - zeta0_q(q)); - zeta_grad_q *= coeff_zeta->Eval(*Tpr, ip) * weight * lim_normal; - AddMultVWt(shape, zeta_grad_q, PMatO); - } } + + AssembleElemVecAdaptLim(el, weights, *Tpr, *ir, PMatO); + delete Tpr; } @@ -1519,9 +1493,11 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, { ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- } + const int nqp = ir->GetNPoints(); elmat = 0.0; - DenseTensor Jtr(dim, dim, ir->GetNPoints()); + Vector weights(nqp); + DenseTensor Jtr(dim, dim, nqp); targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr); // Limited case. @@ -1543,7 +1519,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, } else { - d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0; + d_vals.SetSize(nqp); d_vals = 1.0; } } @@ -1558,45 +1534,14 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, Tpr->GetPointMat().Transpose(PMatI); } - Vector zeta_e, zeta_q, zeta0_q; - DenseMatrix zeta_grad_e, zeta_grad_grad_e; - Vector zeta_grad_q; - DenseMatrix zeta_grad_grad_q; - if (zeta) - { - shape.SetSize(dof); - Array dofs; - zeta->FESpace()->GetElementDofs(T.ElementNo, dofs); - zeta->GetSubVector(dofs, zeta_e); - zeta->GetValues(T.ElementNo, *ir, zeta_q); - zeta_0->GetValues(T.ElementNo, *ir, zeta0_q); - - // Project the gradient of zeta in the same space. - // The FE coefficients of the gradient go in zeta_grad_e. - DenseMatrix grad_phys; // This will be (dof x dim, dof). - el.ProjectGrad(el, *Tpr, grad_phys); - zeta_grad_e.SetSize(dof, dim); - Vector grad_ptr(zeta_grad_e.GetData(), dof*dim); - grad_phys.Mult(zeta_e, grad_ptr); - - // Project the gradient of each gradient of zeta in the same space. - // The FE coefficients of the second derivatives go in zeta_grad_grad_e. - zeta_grad_grad_e.SetSize(dof*dim, dim); - Mult(grad_phys, zeta_grad_e, zeta_grad_grad_e); - // Reshape to be more convenient later (no change in the data). - zeta_grad_grad_e.SetSize(dof, dim*dim); - - zeta_grad_q.SetSize(dim); - zeta_grad_grad_q.SetSize(dim, dim); - } - - for (int q = 0; q < ir->GetNPoints(); q++) + for (int q = 0; q < nqp; q++) { const IntegrationPoint &ip = ir->IntPoint(q); const DenseMatrix &Jtr_q = Jtr(q); metric->SetTargetJacobian(Jtr_q); CalcInverse(Jtr_q, Jrt); const double weight = ip.weight * Jtr_q.Det(); + weights(q) = ip.weight * Jtr_q.Det(); double weight_m = weight * metric_normal; el.CalcDShape(ip, DSh); @@ -1615,7 +1560,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, el.CalcShape(ip, shape); PMatI.MultTranspose(shape, p); pos0.MultTranspose(shape, p0); - weight_m = weight * lim_normal * coeff0->Eval(*Tpr, ip); + weight_m = weights(q) * lim_normal * coeff0->Eval(*Tpr, ip); lim_func->Eval_d2(p, p0, d_vals(q), grad_grad); for (int i = 0; i < dof; i++) { @@ -1633,33 +1578,110 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, } } } + } - if (zeta) + AssembleElemGradAdaptLim(el, weights, *Tpr, *ir, elmat); + + delete Tpr; +} + +void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el, + const Vector &weights, IsoparametricTransformation &Tpr, + const IntegrationRule &ir, DenseMatrix &mat) +{ + if (zeta == NULL) { return; } + + const int dof = el.GetDof(), dim = el.GetDim(); + Vector shape(dof), zeta_e, zeta_q, zeta0_q; + + Array dofs; + zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs); + zeta->GetSubVector(dofs, zeta_e); + zeta->GetValues(Tpr.ElementNo, ir, zeta_q); + zeta_0->GetValues(Tpr.ElementNo, ir, zeta0_q); + + // Project the gradient of zeta in the same space. + // The FE coefficients of the gradient go in zeta_grad_e. + DenseMatrix zeta_grad_e(dof, dim); + DenseMatrix grad_phys; // This will be (dof x dim, dof). + el.ProjectGrad(el, Tpr, grad_phys); + Vector grad_ptr(zeta_grad_e.GetData(), dof*dim); + grad_phys.Mult(zeta_e, grad_ptr); + + Vector zeta_grad_q(dim); + + const int nqp = weights.Size(); + for (int q = 0; q < nqp; q++) + { + const IntegrationPoint &ip = ir.IntPoint(q); + el.CalcShape(ip, shape); + zeta_grad_e.MultTranspose(shape, zeta_grad_q); + zeta_grad_q *= 2.0 * (zeta_q(q) - zeta0_q(q)); + zeta_grad_q *= weights(q) * lim_normal * coeff_zeta->Eval(Tpr, ip); + AddMultVWt(shape, zeta_grad_q, mat); + } +} + +void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el, + const Vector &weights, IsoparametricTransformation &Tpr, + const IntegrationRule &ir, DenseMatrix &mat) +{ + if (zeta == NULL) { return; } + + const int dof = el.GetDof(), dim = el.GetDim(); + Vector shape(dof), zeta_e, zeta_q, zeta0_q; + + Array dofs; + zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs); + zeta->GetSubVector(dofs, zeta_e); + zeta->GetValues(Tpr.ElementNo, ir, zeta_q); + zeta_0->GetValues(Tpr.ElementNo, ir, zeta0_q); + + // Project the gradient of zeta in the same space. + // The FE coefficients of the gradient go in zeta_grad_e. + DenseMatrix zeta_grad_e(dof, dim); + DenseMatrix grad_phys; // This will be (dof x dim, dof). + el.ProjectGrad(el, Tpr, grad_phys); + Vector grad_ptr(zeta_grad_e.GetData(), dof*dim); + grad_phys.Mult(zeta_e, grad_ptr); + + // Project the gradient of each gradient of zeta in the same space. + // The FE coefficients of the second derivatives go in zeta_grad_grad_e. + DenseMatrix zeta_grad_grad_e(dof*dim, dim); + Mult(grad_phys, zeta_grad_e, zeta_grad_grad_e); + // Reshape to be more convenient later (no change in the data). + zeta_grad_grad_e.SetSize(dof, dim*dim); + + Vector zeta_grad_q(dim); + DenseMatrix zeta_grad_grad_q(dim, dim); + + const int nqp = weights.Size(); + for (int q = 0; q < nqp; q++) + { + const IntegrationPoint &ip = ir.IntPoint(q); + el.CalcShape(ip, shape); + + zeta_grad_e.MultTranspose(shape, zeta_grad_q); + Vector gg_ptr(zeta_grad_grad_q.GetData(), dim*dim); + zeta_grad_grad_e.MultTranspose(shape, gg_ptr); + + const double w = weights(q) * lim_normal * coeff_zeta->Eval(Tpr, ip); + for (int i = 0; i < dof * dim; i++) { - el.CalcShape(ip, shape); - zeta_grad_e.MultTranspose(shape, zeta_grad_q); - Vector gg_ptr(zeta_grad_grad_q.GetData(), dim*dim); - zeta_grad_grad_e.MultTranspose(shape, gg_ptr); - - weight_m = coeff_zeta->Eval(*Tpr, ip) * weight * lim_normal; - for (int i = 0; i < dof * dim; i++) + const int idof = i % dof, idim = i / dof; + for (int j = 0; j <= i; j++) { - const int idof = i % dof, idim = i / dof; - for (int j = 0; j <= i; j++) - { - const int jdof = j % dof, jdim = j / dof; - const double entry = weight_m * - ( 2.0 * zeta_grad_q(idim) * shape(idof) * - zeta_grad_q(jdim) * shape(jdof) + - 2.0 * (zeta_q(q) - zeta0_q(q)) * - zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof)); - elmat(i, j) += entry; - if (i != j) { elmat(j, i) += entry; } - } + const int jdof = j % dof, jdim = j / dof; + const double entry = w * + ( 2.0 * zeta_grad_q(idim) * shape(idof) * + zeta_grad_q(jdim) * shape(jdof) + + 2.0 * (zeta_q(q) - zeta0_q(q)) * + zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof)); + mat(i, j) += entry; + if (i != j) { mat(j, i) += entry; } } } } - delete Tpr; } double TMOP_Integrator::GetFDDerivative(const FiniteElement &el, @@ -1701,7 +1723,7 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, elvect.SetSize(dof*dim); Vector elfunmod(elfun); - // Energy for unperturbed configuration + // Energy for unperturbed configuration. double e_fx = GetElementEnergy(el, T, elfun); for (int j = 0; j < dim; j++) @@ -1717,6 +1739,35 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, if (discr_tc) { discr_tc->RestoreTargetSpecificationAtNode(T, i); } } } + + // Contributions from adaptive limiting. + if (zeta) + { + const IntegrationRule *ir = IntRule; + if (!ir) + { + ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- + } + const int nqp = ir->GetNPoints(); + DenseTensor Jtr(dim, dim, nqp); + targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr); + + IsoparametricTransformation Tpr; + Tpr.SetFE(&el); + Tpr.ElementNo = T.ElementNo; + Tpr.Attribute = T.Attribute; + PMatI.UseExternalData(elfun.GetData(), dof, dim); + Tpr.GetPointMat().Transpose(PMatI); // PointMat = PMatI^T + + Vector weights(nqp); + for (int q = 0; q < nqp; q++) + { + weights(q) = ir->IntPoint(q).weight * Jtr(q).Det(); + } + + PMatO.UseExternalData(elvect.GetData(), dof, dim); + AssembleElemVecAdaptLim(el, weights, Tpr, *ir, PMatO); + } } void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, @@ -1785,6 +1836,34 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, } } } + + // Contributions from adaptive limiting. + if (zeta) + { + const IntegrationRule *ir = IntRule; + if (!ir) + { + ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- + } + const int nqp = ir->GetNPoints(); + DenseTensor Jtr(dim, dim, nqp); + targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr); + + IsoparametricTransformation Tpr; + Tpr.SetFE(&el); + Tpr.ElementNo = T.ElementNo; + Tpr.Attribute = T.Attribute; + PMatI.UseExternalData(elfun.GetData(), dof, dim); + Tpr.GetPointMat().Transpose(PMatI); // PointMat = PMatI^T + + Vector weights(nqp); + for (int q = 0; q < nqp; q++) + { + weights(q) = ir->IntPoint(q).weight * Jtr(q).Det(); + } + + AssembleElemGradAdaptLim(el, weights, Tpr, *ir, elmat); + } } void TMOP_Integrator::EnableNormalization(const GridFunction &x) diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 039f68af25..cb5107ea40 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -854,11 +854,18 @@ protected: ElementTransformation &T, const Vector &elfun, Vector &elvect); - /** Assumes that AssembleElementVectorFD has been called. */ + // Assumes that AssembleElementVectorFD has been called. void AssembleElementGradFD(const FiniteElement &el, ElementTransformation &T, const Vector &elfun, DenseMatrix &elmat); + void AssembleElemVecAdaptLim(const FiniteElement &el, const Vector &weights, + IsoparametricTransformation &Tpr, + const IntegrationRule &ir, DenseMatrix &m); + void AssembleElemGradAdaptLim(const FiniteElement &el, const Vector &weights, + IsoparametricTransformation &Tpr, + const IntegrationRule &ir, DenseMatrix &m); + double GetFDDerivative(const FiniteElement &el, ElementTransformation &T, Vector &elfun, const int nodenum,const int idir, diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index a507779f28..579fb87a36 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -31,8 +31,10 @@ // // Compile with: make pmesh-optimizer // -// Adaptive limiting test: +// Adaptive limiting: // mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -al +// Adaptive limiting through FD: +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -al -fd // // Sample runs: // Adapted analytic Hessian: From da531c446029cd81561f72fd89ea2fb65c274e42 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Thu, 16 Apr 2020 13:06:21 -0700 Subject: [PATCH 184/535] minor --- fem/tmop.cpp | 17 +++++++++++++++-- fem/tmop.hpp | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index e5b00f0bc8..6b5f262770 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -982,7 +982,7 @@ void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) ncomp += vdim; - if (ncomp == vdim) + if (tspec_fes == NULL) { tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), tspec_.FESpace()->FEColl(), @@ -1039,6 +1039,12 @@ void DiscreteAdaptTC::SetParDiscreteTargetOrientation(ParGridFunction &tspec_) orientationidx = ncomp; SetParDiscreteTargetBase(tspec_); } + +void DiscreteAdaptTC::SetParDiscreteTargetSpec(ParGridFunction &tspec_) +{ + SetParDiscreteTargetSize(tspec_); + FinalizeParDiscreteTargetSpec(); +} #endif void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) @@ -1048,7 +1054,7 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) ncomp += vdim; - if (ncomp == vdim) + if (tspec_fes == NULL) { tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), tspec_.FESpace()->FEColl(), @@ -1122,6 +1128,13 @@ void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() ncomp); } +void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(GridFunction &tspec_) +{ + SetSerialDiscreteTargetSize(tspec_); + FinalizeSerialDiscreteTargetSpec(); +} + + void DiscreteAdaptTC::UpdateTargetSpecification(const Vector &new_x) { MFEM_VERIFY(tspec.Size() > 0, "Target specification is not set!"); diff --git a/fem/tmop.hpp b/fem/tmop.hpp index c28559f3bd..6e8b26f196 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -750,12 +750,14 @@ public: delete tspec_fesv; } + virtual void SetSerialDiscreteTargetSpec(GridFunction &tspec_); virtual void SetSerialDiscreteTargetSize(GridFunction &tspec_); virtual void SetSerialDiscreteTargetSkew(GridFunction &tspec_); virtual void SetSerialDiscreteTargetAspectRatio(GridFunction &tspec_); virtual void SetSerialDiscreteTargetOrientation(GridFunction &tspec_); virtual void FinalizeSerialDiscreteTargetSpec(); #ifdef MFEM_USE_MPI + virtual void SetParDiscreteTargetSpec(ParGridFunction &tspec_); virtual void SetParDiscreteTargetSize(ParGridFunction &tspec_); virtual void SetParDiscreteTargetSkew(ParGridFunction &tspec_); virtual void SetParDiscreteTargetAspectRatio(ParGridFunction &tspec_); From 4cf82c950ef5f00733f6a379212870f6d842d07b Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 16 Apr 2020 19:18:34 -0700 Subject: [PATCH 185/535] Comments / alignments / unused variables. --- fem/tmop.cpp | 23 ++++++++++------------- fem/tmop_tools.cpp | 15 +++++---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 6b5f262770..c8c64ae326 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -959,15 +959,13 @@ void AnalyticAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, #ifdef MFEM_USE_MPI void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() { - if (!adapt_eval) {MFEM_ABORT("Set adaptivity evaluator\n");} - - MFEM_VERIFY(ncomp>0," Must set atleast 1 discrete target spec"); + MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!") + MFEM_VERIFY(ncomp > 0, "No target specifications have been set!"); adapt_eval->SetParMetaInfo(*ptspec_fes->GetParMesh(), *ptspec_fes->FEColl(), ncomp); - adapt_eval->SetInitialField - (*tspec_fes->GetMesh()->GetNodes(), tspec); + adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec); tspec_sav = tspec; tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), @@ -1049,8 +1047,8 @@ void DiscreteAdaptTC::SetParDiscreteTargetSpec(ParGridFunction &tspec_) void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) { - const int vdim = tspec_.FESpace()->GetVDim(), - cnt = tspec_.Size()/vdim; + const int vdim = tspec_.FESpace()->GetVDim(), + dof_cnt = tspec_.Size()/vdim; ncomp += vdim; @@ -1071,16 +1069,16 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) // make a copy of tspec->tspec_temp, increase its size, and // copy data from tspec_temp -> tspec, then add new entries Vector tspec_temp = tspec; - tspec.SetSize(ncomp*cnt); + tspec.SetSize(ncomp*dof_cnt); for (int i = 0; i < tspec_temp.Size(); i++) { tspec(i) = tspec_temp(i); } - for (int i = 0; i < cnt*vdim; i++) + for (int i = 0; i < dof_cnt*vdim; i++) { - tspec(i+(ncomp-vdim)*cnt) = tspec_(i); + tspec(i+(ncomp-vdim)*dof_cnt) = tspec_(i); } } @@ -1111,9 +1109,8 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(GridFunction &tspec_) void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() { - if (!adapt_eval) {MFEM_ABORT("Set adaptivity evaluator\n");} - - MFEM_VERIFY(ncomp > 0," Must set atleast 1 discrete target spec"); + MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!") + MFEM_VERIFY(ncomp > 0, "No target specifications have been set!"); adapt_eval->SetSerialMetaInfo(*tspec_fes->GetMesh(), *tspec_fes->FEColl(), diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index e6aaa640e6..daec70bda9 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -65,27 +65,22 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, GridFunction u(mesh_nodes->FESpace()); subtract(new_nodes, nodes0, u); + // Define a scalar FE space for the solution, and the advection operator. TimeDependentOperator *oper = NULL; FiniteElementSpace *fess = NULL; #ifdef MFEM_USE_MPI ParFiniteElementSpace *pfess = NULL; #endif - // This must be the fes of the ind, associated with the object's mesh. - if (fes) { - fess = new FiniteElementSpace(fes->GetMesh(), - fes->FEColl(), - 1); + fess = new FiniteElementSpace(fes->GetMesh(), fes->FEColl(), 1); oper = new SerialAdvectorCGOper(nodes0, u, *fess); } #ifdef MFEM_USE_MPI else if (pfes) { - pfess = new ParFiniteElementSpace(pfes->GetParMesh(), - pfes->FEColl(), - 1); - oper = new ParAdvectorCGOper(nodes0, u, *pfess); + pfess = new ParFiniteElementSpace(pfes->GetParMesh(), pfes->FEColl(), 1); + oper = new ParAdvectorCGOper(nodes0, u, *pfess); } #endif MFEM_VERIFY(oper != NULL, @@ -98,7 +93,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, { h_min = std::min(h_min, m->GetElementSize(i)); } - double v_max = 0.0, v_max_glob = 0.0; + double v_max = 0.0; const int dim = fes->GetFE(0)->GetDim(), s = new_field.Size() ; From 671923f0418bb786e53b6b39299a993c26878d19 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Fri, 17 Apr 2020 11:06:32 -0700 Subject: [PATCH 186/535] addressing reviewer comments --- fem/tmop_tools.cpp | 14 +++++++------- fem/tmop_tools.hpp | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index daec70bda9..1f3991239e 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -29,10 +29,10 @@ void AdvectorCG::SetInitialField(const Vector &init_nodes, void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, Vector &new_field) { - // This function will not work for AMR meshes in the current state. + // TODO: Implement for AMR meshes. const int dim = fes->GetFE(0)->GetDim(), ncomp = fes->GetVDim(), - pnt_cnt = new_nodes.Size()/dim; + pnt_cnt = new_field.Size()/ncomp; new_field = field0; @@ -42,8 +42,8 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, ComputeAtNewPositionScalar(new_nodes, new_field_temp); } - //field0 = new_field; - //nodes0 = new_nodes; + field0 = new_field; + nodes0 = new_nodes; } void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, @@ -141,8 +141,8 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, ode_solver.Step(new_field, t, dt); } - double glob_minv = minv; - double glob_maxv = maxv; + double glob_minv = minv, + glob_maxv = maxv; #ifdef MFEM_USE_MPI if (pfes) { @@ -425,7 +425,7 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0) { if (print_level >= 0) - { mfem::out << "Scale = " << scale << " " << energy_out << " " << "Increasing energy.\n"; } + { mfem::out << "Scale = " << scale << " Increasing energy.\n"; } scale *= 0.5; continue; } diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index 997a473301..766cc6028d 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -29,8 +29,7 @@ private: Vector field0; const double dt_scale; - virtual void ComputeAtNewPositionScalar(const Vector &new_nodes, - Vector &new_field); + void ComputeAtNewPositionScalar(const Vector &new_nodes, Vector &new_field); public: AdvectorCG(double timestep_scale = 0.5) : AdaptivityEvaluator(), From 4114098c86ccea73da7151cc6c83227917b35f72 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Sat, 18 Apr 2020 00:46:06 -0700 Subject: [PATCH 187/535] Fixed a bunch of typos and errors that Mark found. --- fem/bilinearform.hpp | 16 +-- fem/bilinearform_ext.hpp | 23 ++-- fem/coefficient.hpp | 58 +++++----- fem/eltrans.hpp | 25 ++++- fem/fe.hpp | 229 ++++++++++++++++++++------------------- fem/tbilininteg.hpp | 49 ++++++--- fem/tevaluator.hpp | 79 +++++++------- fem/tfe.hpp | 4 + 8 files changed, 272 insertions(+), 211 deletions(-) diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index 501b4dfac9..b6188d438f 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -44,9 +44,10 @@ enum class AssemblyLevel }; -/** Class for bilinear form - "Matrix" with associated FE space and - BLFIntegrators. The sum of all the BLFIntegrators will be used - form the matrix/operator M. */ +/** Class for bilinear form - Used to form a matrix given the + associated FE space and BLFIntegrators. The + sum of all the BLFIntegrators will be used + form the matrix M. */ class BilinearForm : public Matrix { protected: @@ -506,7 +507,6 @@ public: are returned in @a vdofs. The flag @a skip_zeros skips the zero elements of the matrix, unless they are breaking the symmetry of the system matrix. */ - void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, Array &vdofs, int skip_zeros = 1); @@ -532,7 +532,7 @@ public: void EliminateVDofs(const Array &vdofs, const Vector &sol, Vector &rhs, DiagonalPolicy dpolicy = DIAG_ONE); - /// Eliminate the given @a vdofs, storing the eliminated part internall in \f$ M_e \f$. + /// Eliminate the given @a vdofs, storing the eliminated part internally in \f$ M_e \f$. /** This method works in conjunction with EliminateVDofsInRHS() and allows elimination of boundary conditions in multiple right-hand sides. In this method, @a vdofs is a list of DOFs. */ @@ -580,9 +580,9 @@ public: /// Sets diagonal policy used upon construction of the linear system. /** Policies include: - - DIAG_ZERO (Set the diagonal value to zero) - - DIAG_ONE (Set the diagonal value to one) - - DIAG_KEEP (Keep the diagonal value) + - DIAG_ZERO (Set the diagonal values to zero) + - DIAG_ONE (Set the diagonal values to one) + - DIAG_KEEP (Keep the diagonal values) */ void SetDiagonalPolicy(DiagonalPolicy policy); diff --git a/fem/bilinearform_ext.hpp b/fem/bilinearform_ext.hpp index 446b0e4b5f..0045684fa8 100644 --- a/fem/bilinearform_ext.hpp +++ b/fem/bilinearform_ext.hpp @@ -22,8 +22,12 @@ namespace mfem class BilinearForm; class MixedBilinearForm; -/** @brief Class extending the BilinearForm class to support the different - AssemblyLevel%s. */ +/// Class extending the BilinearForm class to support different AssemblyLevels. +/** FA - Full Assembly + PA - Partial Assembly + EA - Element Assembly + MF - Matrix Free +*/ class BilinearFormExtension : public Operator { protected: @@ -58,7 +62,8 @@ public: virtual void Update() = 0; }; -/// Data and methods for fully-assembled bilinear forms NOT IMPLEMENTED HERE +/** @brief Data and methods for fully-assembled bilinear forms. + Not yet implemented! Use the BilinearForm Class instead. */ class FABilinearFormExtension : public BilinearFormExtension { public: @@ -78,7 +83,7 @@ public: ~FABilinearFormExtension() {} }; -/// Data and methods for element-assembled bilinear forms NOT IMPLEMENTED HERE +/// Data and methods for element-assembled bilinear forms NOT YET IMPLIMENTED class EABilinearFormExtension : public BilinearFormExtension { public: @@ -128,7 +133,7 @@ public: }; -/// Data and methods for matrix-free bilinear forms +/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED. class MFBilinearFormExtension : public BilinearFormExtension { public: @@ -148,8 +153,12 @@ public: ~MFBilinearFormExtension() {} }; -/** @brief Class extending the MixedBilinearForm class to support the different - AssemblyLevel%s. */ +/// Class extending the MixedBilinearForm class to support different AssemblyLevels. +/** FA - Full Assembly + PA - Partial Assembly + EA - Element Assembly + MF - Matrix Free +*/ class MixedBilinearFormExtension : public Operator { protected: diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 810d3a073a..8377edacd7 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -285,10 +285,12 @@ public: /// Return a pointer to a c-array representing the center of the delta function. const double *Center() { return center; } - /** @brief Return the value of the time */ + /** @brief Return the scale factor times the optional time dependent + function. Returns \f$ s T(t) \f$ with \f$ T(t) = 1 \f$ when + not set by the user. */ double Scale() { return tdf ? (*tdf)(GetTime())*scale : scale; } - /// Return the tolerance used to identify the mesh vertex + /// Return the tolerance used to identify the mesh vertices double Tol() { return tol; } /// See SetWeight() for description of the weight Coefficient. @@ -307,7 +309,7 @@ public: }; /** @brief Derived coefficient that takes the value of the parent coefficient - for the active attrs and is zero otherwise. */ + for the active attributes and is zero otherwise. */ class RestrictedCoefficient : public Coefficient { private: @@ -315,8 +317,9 @@ private: Array active_attr; public: - /** @brief Construct with a parent coefficient and an array of zeros and - ones representing which attributes this coefficient should be active. */ + /** @brief Construct with a parent coefficient and an array with + ones marking the attributes on which this coefficient should be + active. */ RestrictedCoefficient(Coefficient &_c, Array &attr) { c = &_c; attr.Copy(active_attr); } @@ -449,7 +452,7 @@ public: /// Sets coefficient in the vector. void Set(int i, Coefficient *c, bool own=true); - /// Evaluates i'th component of the vector of coefficients. Returns + /// Evaluates i'th component of the vector of coefficients and returns the value. double Eval(int i, ElementTransformation &T, const IntegrationPoint &ip) { return Coeff[i] ? Coeff[i]->Eval(T, ip, GetTime()) : 0.0; } @@ -471,7 +474,7 @@ protected: public: /** @brief Construct an empty coefficient. Calling Eval() before the grid - function is set with cause a segfault. */ + function is set will cause a segfault. */ VectorGridFunctionCoefficient() : VectorCoefficient(0), GridFunc(NULL) { } /** @brief Construct the coefficient with grid function @a gf. The @@ -486,8 +489,9 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - /** @brief Evaluate the vector coefficient at all of the locations in the - integration rule and write the vectors into matrix @a M. */ + /** @brief Evaluate the vector coefficients at all of the locations in the + integration rule and write the vectors into the + columns of matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -517,7 +521,7 @@ public: /** @brief Evaluate the gradient vector coefficient at all of the locations in the integration rule and write the vectors into - matrix @a M. */ + columns of matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -560,7 +564,7 @@ public: @a gf. The grid function is not owned by the coefficient. */ DivergenceGridFunctionCoefficient(GridFunction *gf); - // /Set the vector grid function. + /// Set the vector grid function. void SetGridFunction(GridFunction *gf) { GridFunc = gf; } /// Get the vector grid function. @@ -610,9 +614,9 @@ public: double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,z,s) { } - /// Replace the associated DeltaCoefficient with a new DeltaCoeficient. - /** The new DeltaCoeficient cannot have a specified weight Coefficient, i.e. - DeltaCoeficient::Weight() should return NULL. */ + /// Replace the associated DeltaCoefficient with a new DeltaCoefficient. + /** The new DeltaCoefficient cannot have a specified weight Coefficient, i.e. + DeltaCoefficient::Weight() should return NULL. */ void SetDeltaCoefficient(const DeltaCoefficient& _d) { d = _d; } /// Return the associated scalar DeltaCoefficient. @@ -660,13 +664,13 @@ public: /** @brief Evaluate the vector coefficient at all of the locations in the integration rule and write the vectors into - matrix @a M. */ + the columns of matrix @a M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); }; -/// Base class forMatrix Coefficients that optionally depend on time and space. +/// Base class for Matrix Coefficients that optionally depend on time and space. class MatrixCoefficient { protected: @@ -677,7 +681,7 @@ public: /// Construct a dim x dim matrix coefficient. explicit MatrixCoefficient(int dim) { height = width = dim; time = 0.; } - /// Construct a h x b matrix coefficient. + /// Construct a h x w matrix coefficient. MatrixCoefficient(int h, int w) : height(h), width(w), time(0.) { } /// Set the time for time dependent coefficients @@ -692,7 +696,7 @@ public: /// Get the width of the matrix. int GetWidth() const { return width; } - // For backward compatibility get the width of the matrix. + /// For backward compatibility get the width of the matrix. int GetVDim() const { return width; } /** @brief Evaluate the matrix coefficient in the element described by @a T @@ -775,11 +779,9 @@ public: -/** @brief Matrix coefficient defined by an matrix of scalar coefficients. +/** @brief Matrix coefficient defined by a matrix of scalar coefficients. Coefficients that are not set will evaluate to zero in the vector. The - of coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. - This object takes ownership of the array of coefficients inside it and - deletes them at object destruction. + coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. */ class MatrixArrayCoefficient : public MatrixCoefficient { @@ -788,14 +790,16 @@ private: Array ownCoeff; public: - /** @brief Construct matrix of dim = height*width coefficients. + /** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. The actual coefficients still need to be added with Set(). */ explicit MatrixArrayCoefficient (int dim); /// Get the coefficient located at (i,j) in the matrix. Coefficient* GetCoeff (int i, int j) { return Coeff[i*width+j]; } - /// Set the coefficient located at (i,j) in the matrix. + /** @brief Set the coefficient located at (i,j) in the matrix. By default + by default this will take ownership of the Coefficient passed in, but this + can be overrided with the @a own parameter. */ void Set(int i, int j, Coefficient * c, bool own=true); /// Evaluate coefficient located at (i,j) in the matrix using integration point @a ip. @@ -902,7 +906,7 @@ private: mutable Vector va; mutable Vector vb; public: - /// Construxt with the two vector coefficients. Result is \f$ A \cdot B \f$. + /// Construct with the two vector coefficients. Result is \f$ A \cdot B \f$. InnerProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); /// Evaluate the coefficient at @a ip. @@ -921,7 +925,7 @@ private: mutable Vector vb; public: - /// Construxt with the two vector coefficients. Result is \f$ A_x B_y - A_y * B_x; \f$. + /// Construct with the two vector coefficients. Result is \f$ A_x B_y - A_y * B_x; \f$. VectorRotProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); /// Evaluate the coefficient at @a ip. @@ -938,7 +942,7 @@ private: mutable DenseMatrix ma; public: - /// Construxt with the matrix. + /// Construct with the matrix. DeterminantCoefficient(MatrixCoefficient &A); /// Evaluate the determinant coefficient at @a ip. diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 911dec9d29..7780755aaa 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -42,6 +42,9 @@ protected: /** @brief Evaluate the Jacobian of the transformation at the IntPoint and store it in dFdx. */ virtual const DenseMatrix &EvalJacobian() = 0; + + /** @brief Evaluate the Hessian of the transformation at the IntPoint and + store it in d2Fdx2. */ virtual const DenseMatrix &EvalHessian() = 0; double EvalWeight(); @@ -58,7 +61,8 @@ public: void SetIntPoint(const IntegrationPoint *ip) { IntPoint = ip; EvalState = 0; } - /// Get a const reference to the currently set integration point. + /** @brief Get a const reference to the currently set integration point. This + will return NULL if no integration point is set. */ const IntegrationPoint &GetIntPoint() { return *IntPoint; } /** @brief Transform integration point from reference coordinates to @@ -104,9 +108,14 @@ public: const DenseMatrix &InverseJacobian() { return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); } - + /// Return the order of the current element we are using for the transformation. virtual int Order() = 0; + + /// Return the order of the elements of the Jacobian of the transformation. virtual int OrderJ() = 0; + + /** @brief Return the order of the determinant of the Jacobian (weight) + of the transformation. */ virtual int OrderW() = 0; /// Return the order of \f$ adj(J)^T \nabla fi \f$ @@ -343,9 +352,9 @@ public: where \f$ \hat x \f$ is the reference point, @a x is the corresponding physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is - the column-vector of all basis functions evaluated at xh. The columns of - @a P represent the control points in physical space defining the - transformation. */ + the column-vector of all basis functions evaluated at \f$ \hat x \f$ . + The columns of @a P represent the control points in physical space + defining the transformation. */ DenseMatrix &GetPointMat() { return PointMat; } /** @brief Sets up the correct dimensions for the Jacobian computations. This @@ -370,8 +379,14 @@ public: coordinates and store them as column vectors in @a result. */ virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); + /// Return the order of the current element we are using for the transformation. virtual int Order() { return FElem->GetOrder(); } + + /// Return the order of the elements of the Jacobian of the transformation. virtual int OrderJ(); + + /** @brief Return the order of the determinant of the Jacobian (weight) + of the transformation. */ virtual int OrderW(); /// Return the order of \f$ adj(J)^T \nabla fi \f$ diff --git a/fem/fe.hpp b/fem/fe.hpp index b068fd5a4e..8560503c48 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -228,7 +228,7 @@ class KnotVector; // Base and derived classes for finite elements -/// Abstract class for Finite Elements +/// Abstract class for all finite elements. class FiniteElement { protected: @@ -338,13 +338,13 @@ public: int GetMapType() const { return MapType; } - /** @brief Returns the FiniteElement::MapT of the element describing how reference - functions are mapped to physical space, one of {VALUE, INTEGRAL - H_DIV, H_CURL}. */ + /** @brief Returns the FiniteElement::DerivT of the element describing the + spatial derivative method implemented, one of {NONE, GRAD, + DIV, CURL}. */ int GetDerivType() const { return DerivType; } - /** @brief Returns the FiniteElement::MapT of the element describing how reference - function derivatives are mapped to physical space, one of {VALUE, + /** @brief Returns the FiniteElement::DerivT of the element describing how + reference function derivatives are mapped to physical space, one of {VALUE, INTEGRAL, H_DIV, H_CURL}. */ int GetDerivMapType() const { return DerivMapType; } @@ -548,7 +548,7 @@ public: ElementTransformation &Trans, DenseMatrix &div) const; - /** Return a DofToQuad structure corresponding to the given IntegrationRule + /** @brief Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mode. */ /** See the documentation for DofToQuad for more details. */ virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir, @@ -599,6 +599,9 @@ public: } }; + +/** @brief Class for finite elements with basis functions + that take scalar values. */ class ScalarFiniteElement : public FiniteElement { protected: @@ -618,7 +621,7 @@ protected: DofToQuad::Mode mode) const; public: - /** @brief Construct FiniteElement with given + /** @brief Construct ScalarFiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @param Do Number of degrees of freedom in the FiniteElement @@ -664,6 +667,8 @@ public: DofToQuad::Mode mode) const; }; + +/// Class for standard nodal finite elements. class NodalFiniteElement : public ScalarFiniteElement { protected: @@ -672,7 +677,7 @@ protected: DenseMatrix &curl) const; public: - /** @brief Construct FiniteElement with given + /** @brief Construct NodalFiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @param Do Number of degrees of freedom in the FiniteElement @@ -717,11 +722,12 @@ public: DenseMatrix &div) const; }; - +/** @brief Class for finite elements utilizing the + always positive Bernstein basis. */ class PositiveFiniteElement : public ScalarFiniteElement { public: - /** @brief Construct FiniteElement with given + /** @brief Construct PositiveFiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @param Do Number of degrees of freedom in the FiniteElement @@ -756,8 +762,8 @@ public: DenseMatrix &I) const; }; -/** Abstract base clase for finite elements whose basis functions are - vector valued. */ +/** @brief Intermediate class for finite elements whose basis functions take + vector values. */ class VectorFiniteElement : public FiniteElement { // Hide the scalar functions CalcShape and CalcDShape. @@ -869,7 +875,7 @@ public: class PointFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the PointFiniteElement PointFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -882,7 +888,7 @@ public: class Linear1DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Linear1DFiniteElement Linear1DFiniteElement(); /** virtual function which evaluates the values of all @@ -902,7 +908,7 @@ public: class Linear2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Linear2DFiniteElement Linear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -924,7 +930,7 @@ public: class BiLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the BiLinear2DFiniteElement BiLinear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -948,7 +954,7 @@ public: class GaussLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the GaussLinear2DFiniteElement GaussLinear2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -971,12 +977,12 @@ public: virtual void ProjectDelta(int vertex, Vector &dofs) const; }; -/** @brief A 2D linear element on a square with 3 nodes at the +/** @brief A 2D linear element on a square with 3 nodes at the vertices of the lower left triangle */ class P1OnQuadFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P1OnQuadFiniteElement P1OnQuadFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -989,7 +995,7 @@ public: class Quad1DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Quad1DFiniteElement Quad1DFiniteElement(); /** virtual function which evaluates the values of all @@ -1009,7 +1015,7 @@ public: class QuadPos1DFiniteElement : public PositiveFiniteElement { public: - /// Construct the FiniteElement + /// Construct the QuadPos1DFiniteElement QuadPos1DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1021,7 +1027,7 @@ public: class Quad2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Quad2DFiniteElement Quad2DFiniteElement(); /** virtual function which evaluates the values of all @@ -1050,7 +1056,7 @@ private: mutable DenseMatrix D; mutable Vector pol; public: - /// Construct the FiniteElement + /// Construct the GaussQuad2DFiniteElement GaussQuad2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1062,7 +1068,7 @@ public: class BiQuad2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the BiQuad2DFiniteElement BiQuad2DFiniteElement(); /** virtual function which evaluates the values of all @@ -1084,7 +1090,7 @@ public: class BiQuadPos2DFiniteElement : public PositiveFiniteElement { public: - /// Construct the FiniteElement + /// Construct the BiQuadPos2DFiniteElement BiQuadPos2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1104,7 +1110,7 @@ public: class GaussBiQuad2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the GaussBiQuad2DFiniteElement GaussBiQuad2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1117,7 +1123,7 @@ public: class BiCubic2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the BiCubic2DFiniteElement BiCubic2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1132,7 +1138,7 @@ public: class Cubic1DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Cubic1DFiniteElement Cubic1DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1145,7 +1151,7 @@ public: class Cubic2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Cubic2DFiniteElement Cubic2DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1161,7 +1167,7 @@ public: class Cubic3DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Cubic3DFiniteElement Cubic3DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1174,7 +1180,7 @@ public: class P0TriangleFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P0TriangleFiniteElement P0TriangleFiniteElement(); /// evaluate shape function - constant 1 @@ -1192,7 +1198,7 @@ public: class P0QuadFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P0QuadFiniteElement P0QuadFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1207,7 +1213,7 @@ public: class Linear3DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Linear3DFiniteElement Linear3DFiniteElement(); /** @brief virtual function which evaluates the values of all @@ -1236,7 +1242,7 @@ public: class Quadratic3DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the Quadratic3DFiniteElement Quadratic3DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1249,7 +1255,7 @@ public: class TriLinear3DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the TriLinear3DFiniteElement TriLinear3DFiniteElement(); /** virtual function which evaluates the values of all @@ -1273,7 +1279,7 @@ public: class CrouzeixRaviartFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the CrouzeixRaviartFiniteElement CrouzeixRaviartFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1286,31 +1292,33 @@ public: class CrouzeixRaviartQuadFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the CrouzeixRaviartQuadFiniteElement CrouzeixRaviartQuadFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; + +/// A 1D constant element on a segment class P0SegmentFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement with dummy order @a Ord + /// Construct the P0SegmentFiniteElement with dummy order @a Ord P0SegmentFiniteElement(int Ord = 0); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; -/** @brief A 2D 1st Raviart-Thomas vector element on a triangle */ +/** @brief A 2D 1st order Raviart-Thomas vector element on a triangle */ class RT0TriangleFiniteElement : public VectorFiniteElement { private: static const double nk[3][2]; public: - /// Construct the FiniteElement + /// Construct the RT0TriangleFiniteElement RT0TriangleFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1332,14 +1340,14 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 1st Raviart-Thomas vector element on a square*/ +/** @brief A 2D 1st order Raviart-Thomas vector element on a square*/ class RT0QuadFiniteElement : public VectorFiniteElement { private: static const double nk[4][2]; public: - /// Construct the FiniteElement + /// Construct the RT0QuadFiniteElement RT0QuadFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1361,14 +1369,14 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 2nd Raviart-Thomas vector element on a triangle */ +/** @brief A 2D 2nd order Raviart-Thomas vector element on a triangle */ class RT1TriangleFiniteElement : public VectorFiniteElement { private: static const double nk[8][2]; public: - /// Construct the FiniteElement + /// Construct the RT1TriangleFiniteElement RT1TriangleFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1390,14 +1398,14 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 2nd Raviart-Thomas vector element on a square */ +/** @brief A 2D 2nd order Raviart-Thomas vector element on a square */ class RT1QuadFiniteElement : public VectorFiniteElement { private: static const double nk[12][2]; public: - /// Construct the FiniteElement + /// Construct the RT1QuadFiniteElement RT1QuadFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1419,13 +1427,13 @@ public: ElementTransformation &Trans, Vector &dofs) const; }; -/** @brief A 2D 3rd Raviart-Thomas vector element on a triangle */ +/** @brief A 2D 3rd order Raviart-Thomas vector element on a triangle */ class RT2TriangleFiniteElement : public VectorFiniteElement { private: static const double M[15][15]; public: - /// Construct the FiniteElement + /// Construct the RT2TriangleFiniteElement RT2TriangleFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1439,7 +1447,7 @@ public: Vector &divshape) const; }; -/** @brief A 2D 3rd Raviart-Thomas vector element on a square */ +/** @brief A 2D 3rd order Raviart-Thomas vector element on a square */ class RT2QuadFiniteElement : public VectorFiniteElement { private: @@ -1448,7 +1456,7 @@ private: static const double dpt[3]; public: - /// Construct the FiniteElement + /// Construct the RT2QuadFiniteElement RT2QuadFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1474,7 +1482,7 @@ public: class P1SegmentFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P1SegmentFiniteElement P1SegmentFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1485,7 +1493,7 @@ public: class P2SegmentFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P2SegmentFiniteElement P2SegmentFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1501,18 +1509,18 @@ private: mutable Vector rxxk; #endif public: - /// Construct the FiniteElement with the provided @a degree + /// Construct the Lagrange1DFiniteElement with the provided @a degree Lagrange1DFiniteElement (int degree); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; }; - +/// A 3D linear tetrahedron with nodes at thirds??? class P1TetNonConfFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P1TetNonConfFiniteElement P1TetNonConfFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1523,7 +1531,7 @@ public: class P0TetFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P0TetFiniteElement P0TetFiniteElement (); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1536,7 +1544,7 @@ public: class P0HexFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the P0HexFiniteElement P0HexFiniteElement (); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1559,7 +1567,7 @@ private: #endif public: - /// Construct the FiniteElement with the provided @a degree + /// Construct the LagrangeHexFiniteElement with the provided @a degree LagrangeHexFiniteElement (int degree); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1572,7 +1580,7 @@ public: class RefinedLinear1DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the RefinedLinear1DFiniteElement RefinedLinear1DFiniteElement(); /** virtual function which evaluates the values of all @@ -1592,7 +1600,7 @@ public: class RefinedLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the RefinedLinear2DFiniteElement RefinedLinear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -1612,7 +1620,7 @@ public: class RefinedLinear3DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the RefinedLinear3DFiniteElement RefinedLinear3DFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1625,7 +1633,7 @@ public: class RefinedBiLinear2DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the RefinedBiLinear2DFiniteElement RefinedBiLinear2DFiniteElement(); /** virtual function which evaluates the values of all @@ -1645,7 +1653,7 @@ public: class RefinedTriLinear3DFiniteElement : public NodalFiniteElement { public: - /// Construct the FiniteElement + /// Construct the RefinedTriLinear3DFiniteElement RefinedTriLinear3DFiniteElement(); /** virtual function which evaluates the values of all @@ -1669,7 +1677,7 @@ private: static const double tk[12][3]; public: - /// Construct the FiniteElement + /// Construct the Nedelec1HexFiniteElement Nedelec1HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1693,7 +1701,7 @@ private: static const double tk[6][3]; public: - /// Construct the FiniteElement + /// Construct the Nedelec1TetFiniteElement Nedelec1TetFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1717,7 +1725,7 @@ private: static const double nk[6][3]; public: - /// Construct the FiniteElement + /// Construct the RT0HexFiniteElement RT0HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1747,7 +1755,7 @@ private: static const double nk[36][3]; public: - /// Construct the FiniteElement + /// Construct the RT1HexFiniteElement RT1HexFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1777,7 +1785,7 @@ private: static const double nk[4][3]; public: - /// Construct the FiniteElement + /// Construct the RT0TetFiniteElement RT0TetFiniteElement(); virtual void CalcVShape(const IntegrationPoint &ip, @@ -1803,6 +1811,7 @@ public: class RotTriLinearHexFiniteElement : public NodalFiniteElement { public: + /// Construct the RotTriLinearHexFiniteElement RotTriLinearHexFiniteElement(); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1928,7 +1937,7 @@ public: static void ChebyshevPoints(const int p, double *x); /** @brief Compute the @a p terms in the expansion of the binomial (x + y)^p - and store them in the allready allocated @a u array. */ + and store them in the already allocated @a u array. */ static void CalcBinomTerms(const int p, const double x, const double y, double *u); /** @brief Compute the terms in the expansion of the binomial (x + y)^p and @@ -2085,7 +2094,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the H1_SegmentElement of order @a p and BasisType @a btype H1_SegmentElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2103,7 +2112,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the H1_QuadrilateralElement of order @a p and BasisType @a btype H1_QuadrilateralElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2122,7 +2131,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the H1_HexahedronElement of order @a p and BasisType @a btype H1_HexahedronElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2144,7 +2153,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the H1Pos_SegmentElement of order @a p H1Pos_SegmentElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2163,7 +2172,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the H1Pos_QuadrilateralElement of order @a p H1Pos_QuadrilateralElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2176,6 +2185,7 @@ public: class H1Ser_QuadrilateralElement : public ScalarFiniteElement { public: + /// Construct the H1Ser_QuadrilateralElement of order @a p H1Ser_QuadrilateralElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2195,7 +2205,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the H1Pos_HexahedronElement of order @a p H1Pos_HexahedronElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2216,7 +2226,7 @@ private: DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the H1_TriangleElement of order @a p and BasisType @a btype H1_TriangleElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2239,7 +2249,7 @@ private: DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the H1_TetrahedronElement of order @a p and BasisType @a btype H1_TetrahedronElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2261,7 +2271,7 @@ protected: Array dof_map; public: - /// Construct the FiniteElement of order @a p + /// Construct the H1Pos_TriangleElement of order @a p H1Pos_TriangleElement(const int p); // The size of shape is (p+1)(p+2)/2 (dof). @@ -2289,7 +2299,7 @@ protected: Array dof_map; public: - /// Construct the FiniteElement of order @a p + /// Construct the H1Pos_TetrahedronElement of order @a p H1Pos_TetrahedronElement(const int p); // The size of shape is (p+1)(p+2)(p+3)/6 (dof). @@ -2320,7 +2330,7 @@ private: H1_SegmentElement SegmentFE; public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the H1_WedgeElement of order @a p and BasisType @a btype H1_WedgeElement(const int p, const int btype = BasisType::GaussLobatto); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2366,7 +2376,7 @@ protected: H1Pos_SegmentElement SegmentFE; public: - /// Construct the FiniteElement of order @a p + /// Construct the H1Pos_WedgeElement of order @a p H1Pos_WedgeElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2384,7 +2394,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the L2_SegmentElement of order @a p and BasisType @a btype L2_SegmentElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2401,7 +2411,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the L2Pos_SegmentElement of order @a p L2Pos_SegmentElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2419,7 +2429,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the L2_QuadrilateralElement of order @a p and BasisType @a btype L2_QuadrilateralElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2441,7 +2451,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the L2Pos_QuadrilateralElement of order @a p L2Pos_QuadrilateralElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2458,7 +2468,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the L2_HexahedronElement of order @a p and BasisType @a btype L2_HexahedronElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2477,7 +2487,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the L2Pos_HexahedronElement of order @a p L2Pos_HexahedronElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2497,7 +2507,7 @@ private: DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the L2_TriangleElement of order @a p and BasisType @a btype L2_TriangleElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2519,7 +2529,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the L2Pos_TriangleElement of order @a p L2Pos_TriangleElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2540,7 +2550,7 @@ private: DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the L2_TetrahedronElement of order @a p and BasisType @a btype L2_TetrahedronElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2559,7 +2569,7 @@ private: #endif public: - /// Construct the FiniteElement of order @a p + /// Construct the L2Pos_TetrahedronElement of order @a p L2Pos_TetrahedronElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -2582,7 +2592,7 @@ private: L2_SegmentElement SegmentFE; public: - /// Construct the FiniteElement of order @a p and BasisType @a btype + /// Construct the L2_WedgeElement of order @a p and BasisType @a btype L2_WedgeElement(const int p, const int btype = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2594,6 +2604,7 @@ public: class P0WedgeFiniteElement : public L2_WedgeElement { public: + /// Construct the P0WedgeFiniteElement P0WedgeFiniteElement () : L2_WedgeElement(0) {} }; @@ -2611,7 +2622,7 @@ protected: L2Pos_SegmentElement SegmentFE; public: - /// Construct the FiniteElement of order @a p + /// Construct the L2Pos_WedgeElement of order @a p L2Pos_WedgeElement(const int p); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -2633,7 +2644,7 @@ private: Array dof_map, dof2nk; public: - /** @brief Construct the FiniteElement of order @a p and closed and open + /** @brief Construct the RT_QuadrilateralElement of order @a p and closed and open BasisType @a cb_type and @a ob_type */ RT_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, @@ -2690,7 +2701,7 @@ class RT_HexahedronElement : public VectorFiniteElement Array dof_map, dof2nk; public: - /** @brief Construct the FiniteElement of order @a p and closed and open + /** @brief Construct the RT_HexahedronElement of order @a p and closed and open BasisType @a cb_type and @a ob_type */ RT_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, @@ -2745,7 +2756,7 @@ class RT_TriangleElement : public VectorFiniteElement DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p + /// Construct the RT_TriangleElement of order @a p RT_TriangleElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2802,7 +2813,7 @@ class RT_TetrahedronElement : public VectorFiniteElement DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p + /// Construct the RT_TetrahedronElement of order @a p RT_TetrahedronElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2849,7 +2860,7 @@ class ND_HexahedronElement : public VectorTensorFiniteElement Array dof2tk; public: - /** @brief Construct the FiniteElement of order @a p and closed and open + /** @brief Construct the ND_HexahedronElement of order @a p and closed and open BasisType @a cb_type and @a ob_type */ ND_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, @@ -2917,7 +2928,7 @@ class ND_QuadrilateralElement : public VectorTensorFiniteElement Array dof2tk; public: - /** @brief Construct the FiniteElement of order @a p and closed and open + /** @brief Construct the ND_QuadrilateralElement of order @a p and closed and open BasisType @a cb_type and @a ob_type */ ND_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, @@ -2971,7 +2982,7 @@ class ND_TetrahedronElement : public VectorFiniteElement DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p + /// Construct the ND_TetrahedronElement of order @a p ND_TetrahedronElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -3027,7 +3038,7 @@ class ND_TriangleElement : public VectorFiniteElement DenseMatrixInverse Ti; public: - /// Construct the FiniteElement of order @a p + /// Construct the ND_TriangleElement of order @a p ND_TriangleElement(const int p); virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -3073,7 +3084,7 @@ class ND_SegmentElement : public VectorFiniteElement Array dof2tk; public: - /** @brief Construct the FiniteElement of order @a p and open + /** @brief Construct the ND_SegmentElement of order @a p and open BasisType @a ob_type */ ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre); virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const @@ -3123,7 +3134,7 @@ protected: mutable Vector weights; public: - /** @brief Construct FiniteElement with given + /** @brief Construct NURBSFiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @param Do Number of degrees of freedom in the FiniteElement @@ -3160,7 +3171,7 @@ protected: mutable Vector shape_x; public: - /// Construct the FiniteElement of order @a p + /// Construct the NURBS1DFiniteElement of order @a p NURBS1DFiniteElement(int p) : NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk), shape_x(p + 1) { } @@ -3181,7 +3192,7 @@ protected: mutable DenseMatrix du; public: - /// Construct the FiniteElement of order @a p + /// Construct the NURBS2DFiniteElement of order @a p NURBS2DFiniteElement(int p) : NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p, FunctionSpace::Qk), @@ -3189,7 +3200,7 @@ public: dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(Dof,2) { Orders[0] = Orders[1] = p; } - /// Construct the FiniteElement with x-order @a px and y-order @a py + /// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py NURBS2DFiniteElement(int px, int py) : NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1), std::max(px, py), FunctionSpace::Qk), @@ -3215,7 +3226,7 @@ protected: mutable DenseMatrix du; public: - /// Construct the FiniteElement of order @a p + /// Construct the NURBS3DFiniteElement of order @a p NURBS3DFiniteElement(int p) : NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p, FunctionSpace::Qk), @@ -3224,7 +3235,7 @@ public: d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(Dof,3) { Orders[0] = Orders[1] = Orders[2] = p; } - /// Construct the FiniteElement with x-order @a px and y-order @a py and z-order @a pz + /// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py and z-order @a pz NURBS3DFiniteElement(int px, int py, int pz) : NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1), std::max(std::max(px,py),pz), FunctionSpace::Qk), diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index c3d8068dd2..95ce907dfb 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -54,13 +54,13 @@ struct TMassKernel static const bool out_gradients = false; ///@} - /** Partially assembled data type for one element with the given number of + /** @brief Partially assembled data type for one element with the given number of quadrature points. This type is used in partial assembly, and partially assembled action. */ template struct p_asm_data { typedef TVector type; }; - /** Partially assembled data type for one element with the given number of + /** @brief Partially assembled data type for one element with the given number of quadrature points. This type is used in full element matrix assembly. */ template struct f_asm_data { typedef TVector type; }; @@ -72,6 +72,7 @@ struct TMassKernel }; /** @brief Method used for un-assembled (matrix free) action. + @param k the element number @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F @param Q CoefficientEval<>::Type @param q CoefficientEval<>::Type::result_t @@ -104,6 +105,7 @@ struct TMassKernel Result in A is the quadrature-point dependent part of element matrix assembly (as opposed to part that is same for all elements), A = w det(J) + @param k the element number @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F @param Q CoefficientEval<>::Type @param q CoefficientEval<>::Type::result_t @@ -126,6 +128,7 @@ struct TMassKernel } /** @brief Method for partially assembled action. + @param k the element number @param A [M] - partially assembled scalars @param R val_qpts [M x NC x NE] - in/out data member in R val_qpts *= A @@ -165,20 +168,22 @@ struct TDiffusionKernel<1,1,complex_t> static const bool uses_Jacobians = true; /// Needed for the FieldEvaluator::Data class + ///@{ static const bool in_values = false; static const bool in_gradients = true; static const bool out_values = false; static const bool out_gradients = true; + ///@} - /** Partially assembled data type for one element with the given number of + /** @brief Partially assembled data type for one element with the given number of quadrature points. This type is used in partial assembly, and partially assembled action. */ template struct p_asm_data { typedef TMatrix type; }; - /// Partially assembled data type for one element with the given number of - /// quadrature points. This type is used in full element matrix assembly. + /** @brief Partially assembled data type for one element with the given number of + quadrature points. This type is used in full element matrix assembly. */ template struct f_asm_data { typedef TTensor3 type; }; @@ -189,6 +194,7 @@ struct TDiffusionKernel<1,1,complex_t> }; /** @brief Method used for un-assembled (matrix free) action. + @param k the element number @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F @param Q - CoefficientEval<>::Type @param q - CoefficientEval<>::Type::result_t @@ -221,6 +227,7 @@ struct TDiffusionKernel<1,1,complex_t> asm_type == p_asm_data, i.e. A.layout.rank == 2) or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3) matrices. + @param k the element number @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F @param Q CoefficientEval<>::Type @param q CoefficientEval<>::Type::result_t @@ -244,6 +251,7 @@ struct TDiffusionKernel<1,1,complex_t> } } /** @brief Method for partially assembled action. + @param k the element number @param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symmetric matrices @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R @@ -278,20 +286,22 @@ struct TDiffusionKernel<2,2,complex_t> static const bool uses_Jacobians = true; /// Needed for the FieldEvaluator::Data class + ///@{ static const bool in_values = false; static const bool in_gradients = true; static const bool out_values = false; static const bool out_gradients = true; + ///@} - /// Partially assembled data type for one element with the given number of - /// quadrature points. This type is used in partial assembly, and partially - /// assembled action. Stores one symmetric 2 x 2 matrix per point. + /** @brief Partially assembled data type for one element with the given number of + quadrature points. This type is used in partial assembly, and partially + assembled action. Stores one symmetric 2 x 2 matrix per point. */ template struct p_asm_data { typedef TMatrix type; }; - /// Partially assembled data type for one element with the given number of - /// quadrature points. This type is used in full element matrix assembly. - /// Stores one general (non-symmetric) 2 x 2 matrix per point. + /** @brief Partially assembled data type for one element with the given number of + quadrature points. This type is used in full element matrix assembly. + Stores one general (non-symmetric) 2 x 2 matrix per point. */ template struct f_asm_data { typedef TTensor3 type; }; @@ -302,6 +312,7 @@ struct TDiffusionKernel<2,2,complex_t> }; /** @brief Method used for un-assembled (matrix free) action. + @param k the element number @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F @param Q CoefficientEval<>::Type @param q CoefficientEval<>::Type::result_t @@ -345,6 +356,7 @@ struct TDiffusionKernel<2,2,complex_t> asm_type == p_asm_data, i.e. A.layout.rank == 2) or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3) matrices. A = (w/det(J)) adj(J) adj(J)^t + @param k the element number @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F @param Q CoefficientEval<>::Type @param q CoefficientEval<>::Type::result_t @@ -379,6 +391,7 @@ struct TDiffusionKernel<2,2,complex_t> } /** @brief Method for partially assembled action. + @param k the element number @param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric matrices @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R @@ -419,20 +432,22 @@ struct TDiffusionKernel<3,3,complex_t> static const bool uses_Jacobians = true; /// Needed for the FieldEvaluator::Data class + ///@{ static const bool in_values = false; static const bool in_gradients = true; static const bool out_values = false; static const bool out_gradients = true; + ///@} - /// Partially assembled data type for one element with the given number of - /// quadrature points. This type is used in partial assembly, and partially - /// assembled action. Stores one symmetric 3 x 3 matrix per point. + /** @brief Partially assembled data type for one element with the given number of + quadrature points. This type is used in partial assembly, and partially + assembled action. Stores one symmetric 3 x 3 matrix per point. */ template struct p_asm_data { typedef TMatrix type; }; - /// Partially assembled data type for one element with the given number of - /// quadrature points. This type is used in full element matrix assembly. - /// Stores one general (non-symmetric) 3 x 3 matrix per point. + /** @brief Partially assembled data type for one element with the given number of + quadrature points. This type is used in full element matrix assembly. + Stores one general (non-symmetric) 3 x 3 matrix per point. */ template struct f_asm_data { typedef TTensor3 type; }; diff --git a/fem/tevaluator.hpp b/fem/tevaluator.hpp index 0557669933..dbcba9a5df 100644 --- a/fem/tevaluator.hpp +++ b/fem/tevaluator.hpp @@ -58,7 +58,7 @@ public: // default copy constructor - /** Multi-component shape evaluation from DOFs to quadrature points. + /** @brief Multi-component shape evaluation from DOFs to quadrature points. dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */ template @@ -80,8 +80,8 @@ public: qpt_layout, qpt_data); } - /** Multi-component shape evaluation transpose from quadrature points to DOFs. - qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */ + /** @brief Multi-component shape evaluation transpose from quadrature points to + DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */ template @@ -103,7 +103,7 @@ public: dof_layout, dof_data); } - /** Multi-component gradient evaluation from DOFs to quadrature points. + /** @brief Multi-component gradient evaluation from DOFs to quadrature points. dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). */ template @@ -128,7 +128,7 @@ public: grad_layout.merge_12(), grad_data); } - /** Multi-component gradient evaluation transpose from quadrature points to + /** @brief Multi-component gradient evaluation transpose from quadrature points to DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */ template MFEM_ALWAYS_INLINE @@ -225,7 +225,7 @@ protected: public: TProductShapeEvaluator() { } - /** Multi-component shape evaluation from DOFs to quadrature points. + /** @brief Multi-component shape evaluation from DOFs to quadrature points. dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */ template @@ -238,8 +238,8 @@ public: qpt_layout, qpt_data); } - /** Multi-component shape evaluation transpose from quadrature points to DOFs. - qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */ + /** @brief Multi-component shape evaluation transpose from quadrature points + to DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */ template @@ -252,7 +252,7 @@ public: dof_layout, dof_data); } - /** Multi-component gradient evaluation from DOFs to quadrature points. + /** @brief Multi-component gradient evaluation from DOFs to quadrature points. dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). */ template @@ -268,7 +268,7 @@ public: grad_layout.merge_12(), grad_data); } - /** Multi-component gradient evaluation transpose from quadrature points to + /** @brief Multi-component gradient evaluation transpose from quadrature points to DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */ template @@ -309,7 +309,7 @@ public: #endif } - /** Multi-component assemble of grad-grad element matrices. + /** @brief Multi-component assemble of grad-grad element matrices. qpt_layout is (NIP x DIM x DIM x NumComp), and D_layout is (DOF x DOF x NumComp). */ template (), qpt_data); } - /** Multi-component shape evaluation from DOFs to quadrature points. + /** @brief Multi-component shape evaluation from DOFs to quadrature points. dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */ template @@ -403,7 +403,7 @@ public: dof_layout.template split_1(), dof_data); } - /** Multi-component shape evaluation transpose from quadrature points to DOFs. + /** @brief Multi-component shape evaluation transpose from quadrature points to DOFs. qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */ template (qpt_layout, qpt_data, dof_layout, dof_data); } - /** Multi-component gradient evaluation from DOFs to quadrature points. + /** @brief Multi-component gradient evaluation from DOFs to quadrature points. dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). */ template @@ -431,7 +431,7 @@ public: grad_layout.ind2(1), grad_data); } - /** Multi-component gradient evaluation transpose from quadrature points to + /** @brief Multi-component gradient evaluation transpose from quadrature points to DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is (TDOF x NumComp). */ template @@ -540,9 +540,9 @@ public: D_layout.merge_23().template split_12(), D_data); } - // Multi-component assemble of grad-grad element matrices. - // qpt_layout is (TNIP x DIM x DIM x NumComp), and - // D_layout is (TDOF x TDOF x NumComp). + /** @brief Multi-component assemble of grad-grad element matrices. + qpt_layout is (TNIP x DIM x DIM x NumComp), and + D_layout is (TDOF x TDOF x NumComp). */ template MFEM_ALWAYS_INLINE @@ -651,7 +651,7 @@ public: qpt_layout.template split_1(), qpt_data); } - /** Multi-component shape evaluation from DOFs to quadrature points. + /** @brief Multi-component shape evaluation from DOFs to quadrature points. dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */ template @@ -687,7 +687,7 @@ public: dof_layout.template split_1(), dof_data); } - /** Multi-component shape evaluation transpose from quadrature points to DOFs. + /** @brief Multi-component shape evaluation transpose from quadrature points to DOFs. qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */ template (qpt_layout, qpt_data, dof_layout, dof_data); } - /** Multi-component gradient evaluation from DOFs to quadrature points. + /** @brief Multi-component gradient evaluation from DOFs to quadrature points. dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). */ template @@ -719,7 +719,7 @@ public: // y-derivatives and second time for the z-derivatives. } - /** Multi-component gradient evaluation transpose from quadrature points to + /** @brief Multi-component gradient evaluation transpose from quadrature points to DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is (TDOF x NumComp). */ template @@ -864,9 +864,9 @@ public: } #endif - // Multi-component assemble of grad-grad element matrices. - // qpt_layout is (TNIP x DIM x DIM x NumComp), and - // D_layout is (TDOF x TDOF x NumComp). + /** @brief Multi-component assemble of grad-grad element matrices. + qpt_layout is (TNIP x DIM x DIM x NumComp), and + D_layout is (TDOF x TDOF x NumComp). */ template MFEM_ALWAYS_INLINE @@ -951,7 +951,7 @@ public: }; -/** Field evaluators -- values of a given global FE grid function +/** @brief Field evaluators -- values of a given global FE grid function This is roughly speaking a templated version of GridFunction */ template grad_qpts; }; - /** This struct is similar to struct AData, adding separate static data + /** @brief This struct is similar to struct AData, adding separate static data members for the input (InData) and output (OutData) data types. */ template struct BData : public AData @@ -1200,7 +1200,7 @@ public: static const int OutData = OData; }; - /** This struct implements the input (Eval, EvalSerialized) and output + /** @brief This struct implements the input (Eval, EvalSerialized) and output (Assemble, AssembleSerialized) operations for the given Ops. Ops is "bitwise or" of constants from the enum InOutData. */ template struct Action; @@ -1379,7 +1379,7 @@ public: #endif }; - /** This struct implements element matrix computation for some combinations + /** @brief This struct implements element matrix computation for some combinations of input (InOps) and output (OutOps) operations. */ template struct TElementMatrix; @@ -1401,9 +1401,12 @@ public: template struct TElementMatrix<2,2,NE> // 2,2 = Gradients,Gradients { /** @brief Assemble element mass matrix + @param a the layout for the quadrature point data @param A given quadrature point data for element (incl. coefficient, geometry) + @param m the layout for the resulting element mass matrix @param M the resulting element mass matrix + @param ev the shape evaluator qpt_layout_t is (nip), M_layout_t is (dof x dof) NE = 1 is assumed */ template Date: Sun, 19 Apr 2020 18:17:09 -0700 Subject: [PATCH 188/535] WIP: Initial shot at L2 projection for VQFC and QFC This compiles but no idea if it actually runs like it should yet... --- fem/CMakeLists.txt | 2 + fem/field_interpolant.cpp | 212 ++++++++++++++++++++++++++++++++++++++ fem/field_interpolant.hpp | 68 ++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 fem/field_interpolant.cpp create mode 100644 fem/field_interpolant.hpp diff --git a/fem/CMakeLists.txt b/fem/CMakeLists.txt index 8308f8ed0f..4d6429bf39 100644 --- a/fem/CMakeLists.txt +++ b/fem/CMakeLists.txt @@ -30,6 +30,7 @@ set(SRCS fe.cpp fe_coll.cpp fespace.cpp + field_interpolant.cpp geom.cpp gridfunc.cpp hybridization.cpp @@ -62,6 +63,7 @@ set(HDRS fe_coll.hpp fem.hpp fespace.hpp + field_interpolant.hpp geom.hpp gridfunc.hpp hybridization.hpp diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp new file mode 100644 index 0000000000..3885db5c3e --- /dev/null +++ b/fem/field_interpolant.cpp @@ -0,0 +1,212 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +// Implementation of Field Interpolants and necessary (Vector)QuadratorIntegrators + +#include "field_interpolant.hpp" +#include "../linalg/densemat.hpp" + +namespace mfem{ + +void VectorQuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect) +{ + const int nqp = IntRule->GetNPoints(); + const int vdim = vqfc.GetVDim(); + const int ndofs = fe.GetDof(); + Vector shape(ndofs); + Vector temp(vdim); + elvect.SetSize(vdim * ndofs); + elvect = 0.0; + for (int q = 0; q < nqp; q++) + { + const IntegrationPoint &ip = IntRule->IntPoint(q); + const double w = Tr.Weight() * ip.weight; + vqfc.Eval(temp, Tr, ip); + fe.CalcShape(ip, shape); + for (int ind = 0; ind < vdim; ind++) { + for(int nd = 0; nd < ndofs; nd++){ + elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind); + } + } + } +} + +void QuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect) +{ + const int nqp = IntRule->GetNPoints(); + const int ndofs = fe.GetDof(); + Vector shape(ndofs); + elvect.SetSize(ndofs); + elvect = 0.0; + for (int q = 0; q < nqp; q++) + { + const IntegrationPoint &ip = IntRule->IntPoint(q); + const double w = Tr.Weight() * ip.weight; + double temp = qfc.Eval(Tr, ip); + fe.CalcShape(ip, shape); + shape *= (w * temp); + elvect += shape; + } +} + +//As a change to this we should have a setup phase where all the inverse matrices are stored off. +//If we do that we don't need to do the inverse and assemble step constantly. We can store the value in a vec +//and then just just use the DenseMatrix UseExternalData function. +//We can therefore provide a set-up phase that is run at the start of this if the vector this is all stored in is null. +//We should also provide a function that clears this. +//We'll need to assume that this is already an L2 space. +//One of the assumptions that we make down below is that our integration scheme is the same across all elements. +//If that isn't the case we might be able to still do things but things will most likely be slower. +void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &fes) +{ + int ndofs; + DenseMatrix mi; + DenseMatrixInverse inv(&mi); + const IntegrationRule* ir; + NE = fes.GetMesh()->GetNE(); + { + // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + // and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes.GetFE(0); + ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const QuadratureFunction* qf = vqfc.GetQuadFunction(); + const IntegrationRule *ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + // This should be the number of nodes available + ndofs = el.GetDof(); + } + int vdim = vqfc.GetVDim(); + + Vector rhs(ndofs * vdim), rhs_sub(ndofs); + Vector qfv(ndofs * vdim), qfv_sub(ndofs); + Array dofs(ndofs); + + VectorQuadratureIntegrator qi(vqfc); + qi.SetIntRule(ir); + + if(!setup) { + m_all_data.SetSize(ndofs * ndofs * NE); + double* data = m_all_data.HostReadWrite(); + for(int e = 0; e < NE; e++) + { + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); + mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); + mass_int.AssembleElementMatrix(fe, eltr, mi); + } + setup = true; + } + + double* data = m_all_data.HostReadWrite(); + if(fes.GetOrdering() == Ordering::byNODES){ + for(int e = 0; e < NE; e++){ + mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); + inv.Factor(); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); + qi.AssembleRHSElementVect(fe, eltr, rhs); + for(int ind = 0; ind < vdim; ind++){ + qfv_sub.MakeRef(qfv, ndofs * ind); + rhs_sub.MakeRef(rhs, ndofs * ind); + inv.Mult(rhs_sub, qfv_sub); + } + fes.GetElementDofs(e, dofs); + gf.SetSubVector(dofs, qfv); + } + } else { + Vector tmp(qfv); + for(int e = 0; e < NE; e++){ + mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); + inv.Factor(); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); + qi.AssembleRHSElementVect(fe, eltr, rhs); + for(int ind = 0; ind < vdim; ind++){ + qfv_sub.MakeRef(qfv, ndofs * ind); + rhs_sub.MakeRef(rhs, ndofs * ind); + inv.Mult(rhs_sub, qfv_sub); + } + + //Now to reorder the vec from byNodes order to byVec + tmp = qfv; + for(int ind = 0; ind < vdim; ind++){ + for(int nd = 0; nd < ndofs; nd++){ + qfv((nd * vdim) + ind) = tmp(nd + ind * ndofs); + } + } + fes.GetElementDofs(e, dofs); + gf.SetSubVector(dofs, qfv); + } + } +} + +void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &fes) +{ + int ndofs; + DenseMatrix mi; + DenseMatrixInverse inv(&mi); + const IntegrationRule* ir; + { + // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + // and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes.GetFE(0); + ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const QuadratureFunction* qf = qfc.GetQuadFunction(); + const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + // This should be the number of nodes available + ndofs = el.GetDof(); + } + + Vector rhs(ndofs); + Vector qfv(ndofs); + Array dofs(ndofs); + + QuadratureIntegrator qi(qfc); + qi.SetIntRule(ir); + + if(!setup) { + m_all_data.SetSize(ndofs * ndofs * NE); + double* data = m_all_data.HostReadWrite(); + for(int e = 0; e < NE; e++) + { + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); + mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); + mass_int.AssembleElementMatrix(fe, eltr, mi); + } + setup = true; + } + + double* data = m_all_data.HostReadWrite(); + for(int e = 0; e < NE; e++){ + mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); + inv.Factor(); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); + qi.AssembleRHSElementVect(fe, eltr, rhs); + inv.Mult(rhs, qfv); + fes.GetElementDofs(e, dofs); + gf.SetSubVector(dofs, qfv); + } +} + +} \ No newline at end of file diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp new file mode 100644 index 0000000000..b6f20b7c07 --- /dev/null +++ b/fem/field_interpolant.hpp @@ -0,0 +1,68 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +// Implementation of Field Interpolants + +#ifndef MFEM_FIELD_INTERPOLANT +#define MFEM_FIELD_INTERPOLANT + +#include "../config/config.hpp" +#include "../linalg/linalg.hpp" +#include "intrules.hpp" +#include "eltrans.hpp" +#include "coefficient.hpp" +#include "bilininteg.cpp" +#include "lininteg.hpp" + +namespace mfem{ + +class FieldInterpolant { + private: + bool setup; + Vector m_all_data; + MassIntegrator mass_int; + int NE; + public: + FieldInterpolant() {} + void ProjectQuadratureDiscCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &fes); + void ProjectQuadratureDiscCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &fes); + void SetupReset() { setup = false; } +}; + +class VectorQuadratureIntegrator : public LinearFormIntegrator { + private: + VectorQuadratureFunctionCoefficient &vqfc; + public: + VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc(vqfc) { } + using LinearFormIntegrator::AssembleRHSElementVect; + void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect); +}; + +class QuadratureIntegrator : public LinearFormIntegrator { + private: + QuadratureFunctionCoefficient &qfc; + public: + QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } + using LinearFormIntegrator::AssembleRHSElementVect; + void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect); +}; + +} + +#endif \ No newline at end of file From 1478efc4b08b3bb5cf07a855606294d31bdb2032 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Apr 2020 11:15:16 -0700 Subject: [PATCH 189/535] Fixes to FieldInterpolant class and update tests --- fem/fem.hpp | 1 + fem/field_interpolant.cpp | 12 +++++++----- fem/field_interpolant.hpp | 4 ++-- tests/unit/fem/test_quadf_coef.cpp | 11 +++++++++-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/fem/fem.hpp b/fem/fem.hpp index d6c5c1f73e..10acb5b075 100644 --- a/fem/fem.hpp +++ b/fem/fem.hpp @@ -23,6 +23,7 @@ #include "nonlininteg.hpp" #include "bilininteg.hpp" #include "fespace.hpp" +#include "field_interpolant.hpp" #include "gridfunc.hpp" #include "linearform.hpp" #include "nonlinearform.hpp" diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 3885db5c3e..782aa895ae 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -13,6 +13,7 @@ #include "field_interpolant.hpp" #include "../linalg/densemat.hpp" +#include "gridfunc.hpp" namespace mfem{ @@ -115,24 +116,25 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, double* data = m_all_data.HostReadWrite(); if(fes.GetOrdering() == Ordering::byNODES){ for(int e = 0; e < NE; e++){ + qfv = 0.0; mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(); + inv.Factor(mi); const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); for(int ind = 0; ind < vdim; ind++){ qfv_sub.MakeRef(qfv, ndofs * ind); rhs_sub.MakeRef(rhs, ndofs * ind); - inv.Mult(rhs_sub, qfv_sub); + inv.Mult(rhs_sub, qfv_sub); } - fes.GetElementDofs(e, dofs); + fes.GetElementVDofs(e, dofs); gf.SetSubVector(dofs, qfv); } } else { Vector tmp(qfv); for(int e = 0; e < NE; e++){ mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(); + inv.Factor(mi); const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); @@ -199,7 +201,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, double* data = m_all_data.HostReadWrite(); for(int e = 0; e < NE; e++){ mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(); + inv.Factor(mi); const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index b6f20b7c07..e77042ffac 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -19,7 +19,7 @@ #include "intrules.hpp" #include "eltrans.hpp" #include "coefficient.hpp" -#include "bilininteg.cpp" +#include "bilininteg.hpp" #include "lininteg.hpp" namespace mfem{ @@ -31,7 +31,7 @@ class FieldInterpolant { MassIntegrator mass_int; int NE; public: - FieldInterpolant() {} + FieldInterpolant(const IntegrationRule* ir) { mass_int.SetIntRule(ir); } void ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, FiniteElementSpace &fes); diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 918f7a80fa..62ab08ecbb 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -67,6 +67,8 @@ TEST_CASE("Quadrature Function Coefficients", QuadratureFunctionCoefficient qfc(&quadf_coeff); VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); + FieldInterpolant fi(&ir); + SECTION("Operators on VecQuadFuncCoeff") { std::cout << "Testing VecQuadFuncCoeff: " << std::endl; @@ -104,7 +106,8 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - g0.ProjectDiscCoefficient(qfvc, GridFunction::ARITHMETIC); + // g0.ProjectDiscCoefficient(qfvc, GridFunction::ARITHMETIC); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -147,6 +150,8 @@ TEST_CASE("Quadrature Function Coefficients", FiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); + // This line is necessary for the test suite. + fi.SetupReset(); // When using an L2 FE space of the same order as the mesh, the below highlights // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. @@ -165,7 +170,9 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - g0.ProjectDiscCoefficient(qfc, GridFunction::ARITHMETIC); + // These two methods result in the same answer at least for hex meshes + // g0.ProjectDiscCoefficient(qfc, GridFunction::ARITHMETIC); + fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } From 1e8f50bcd656227db3ea96ba9f8808b40bb48eee Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Apr 2020 11:16:44 -0700 Subject: [PATCH 190/535] make style --- fem/coefficient.cpp | 5 +-- fem/coefficient.hpp | 2 +- fem/field_interpolant.cpp | 73 ++++++++++++++++++++++++--------------- fem/field_interpolant.hpp | 73 +++++++++++++++++++++------------------ 4 files changed, 88 insertions(+), 65 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index caaffce72c..8c53fc2279 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -780,7 +780,7 @@ void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length) MFEM_VERIFY(_index < QuadF->GetVDim(), "Index must be < QuadratureFunction length"); index = _index; - + MFEM_VERIFY(_length > 0, "Length must be > 0"); int diff = QuadF->GetVDim() - index; @@ -811,7 +811,8 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, QuadF->GetElementValues(elem_no, ip.index, temp); double *data = temp.HostReadWrite(); V.SetSize(length); - for(int i = 0; i < length; i++) { + for (int i = 0; i < length; i++) + { V(i) = data[index + i]; } } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 825d708573..a93ffbaa27 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -964,7 +964,7 @@ public: void SetQuadratureFunction(QuadratureFunction *qf); /// Set the starting index within the QuadFunc that'll be used to project outwards as well - /// as the corresponding length. The projected length should have the bounds of + /// as the corresponding length. The projected length should have the bounds of /// 1 <= length <= (length QuadFunc - index). void SetComponent(int _index, int _length); diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 782aa895ae..4ca0cc6321 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -15,7 +15,8 @@ #include "../linalg/densemat.hpp" #include "gridfunc.hpp" -namespace mfem{ +namespace mfem +{ void VectorQuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, @@ -34,9 +35,11 @@ void VectorQuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, const double w = Tr.Weight() * ip.weight; vqfc.Eval(temp, Tr, ip); fe.CalcShape(ip, shape); - for (int ind = 0; ind < vdim; ind++) { - for(int nd = 0; nd < ndofs; nd++){ - elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind); + for (int ind = 0; ind < vdim; ind++) + { + for (int nd = 0; nd < ndofs; nd++) + { + elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind); } } } @@ -70,7 +73,7 @@ void QuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, //We'll need to assume that this is already an L2 space. //One of the assumptions that we make down below is that our integration scheme is the same across all elements. //If that isn't the case we might be able to still do things but things will most likely be slower. -void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, +void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, FiniteElementSpace &fes) { @@ -81,13 +84,14 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, NE = fes.GetMesh()->GetNE(); { // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same + // and the QuadratureSpace correspond to the same const FiniteElement &el = *fes.GetFE(0); ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule *ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && + (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); // This should be the number of nodes available ndofs = el.GetDof(); } @@ -100,10 +104,11 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureIntegrator qi(vqfc); qi.SetIntRule(ir); - if(!setup) { + if (!setup) + { m_all_data.SetSize(ndofs * ndofs * NE); double* data = m_all_data.HostReadWrite(); - for(int e = 0; e < NE; e++) + for (int e = 0; e < NE; e++) { const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); @@ -114,15 +119,18 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } double* data = m_all_data.HostReadWrite(); - if(fes.GetOrdering() == Ordering::byNODES){ - for(int e = 0; e < NE; e++){ + if (fes.GetOrdering() == Ordering::byNODES) + { + for (int e = 0; e < NE; e++) + { qfv = 0.0; mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); - for(int ind = 0; ind < vdim; ind++){ + for (int ind = 0; ind < vdim; ind++) + { qfv_sub.MakeRef(qfv, ndofs * ind); rhs_sub.MakeRef(rhs, ndofs * ind); inv.Mult(rhs_sub, qfv_sub); @@ -130,24 +138,30 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, fes.GetElementVDofs(e, dofs); gf.SetSubVector(dofs, qfv); } - } else { + } + else + { Vector tmp(qfv); - for(int e = 0; e < NE; e++){ + for (int e = 0; e < NE; e++) + { mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); - for(int ind = 0; ind < vdim; ind++){ + for (int ind = 0; ind < vdim; ind++) + { qfv_sub.MakeRef(qfv, ndofs * ind); rhs_sub.MakeRef(rhs, ndofs * ind); - inv.Mult(rhs_sub, qfv_sub); + inv.Mult(rhs_sub, qfv_sub); } - //Now to reorder the vec from byNodes order to byVec + //Now to reorder the vec from byNodes order to byVec tmp = qfv; - for(int ind = 0; ind < vdim; ind++){ - for(int nd = 0; nd < ndofs; nd++){ + for (int ind = 0; ind < vdim; ind++) + { + for (int nd = 0; nd < ndofs; nd++) + { qfv((nd * vdim) + ind) = tmp(nd + ind * ndofs); } } @@ -157,7 +171,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } } -void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, +void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, FiniteElementSpace &fes) { @@ -167,13 +181,14 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, const IntegrationRule* ir; { // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same + // and the QuadratureSpace correspond to the same const FiniteElement &el = *fes.GetFE(0); ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && + (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); // This should be the number of nodes available ndofs = el.GetDof(); } @@ -185,10 +200,11 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureIntegrator qi(qfc); qi.SetIntRule(ir); - if(!setup) { + if (!setup) + { m_all_data.SetSize(ndofs * ndofs * NE); double* data = m_all_data.HostReadWrite(); - for(int e = 0; e < NE; e++) + for (int e = 0; e < NE; e++) { const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); @@ -199,13 +215,14 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } double* data = m_all_data.HostReadWrite(); - for(int e = 0; e < NE; e++){ + for (int e = 0; e < NE; e++) + { mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); const FiniteElement &fe = *fes.GetFE(e); ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); - inv.Mult(rhs, qfv); + inv.Mult(rhs, qfv); fes.GetElementDofs(e, dofs); gf.SetSubVector(dofs, qfv); } diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index e77042ffac..457fce0d7d 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -22,45 +22,50 @@ #include "bilininteg.hpp" #include "lininteg.hpp" -namespace mfem{ +namespace mfem +{ -class FieldInterpolant { - private: - bool setup; - Vector m_all_data; - MassIntegrator mass_int; - int NE; - public: - FieldInterpolant(const IntegrationRule* ir) { mass_int.SetIntRule(ir); } - void ProjectQuadratureDiscCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &fes); - void ProjectQuadratureDiscCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &fes); - void SetupReset() { setup = false; } +class FieldInterpolant +{ +private: + bool setup; + Vector m_all_data; + MassIntegrator mass_int; + int NE; +public: + FieldInterpolant(const IntegrationRule* ir) { mass_int.SetIntRule(ir); } + void ProjectQuadratureDiscCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &fes); + void ProjectQuadratureDiscCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &fes); + void SetupReset() { setup = false; } }; -class VectorQuadratureIntegrator : public LinearFormIntegrator { - private: - VectorQuadratureFunctionCoefficient &vqfc; - public: - VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc(vqfc) { } - using LinearFormIntegrator::AssembleRHSElementVect; - void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect); +class VectorQuadratureIntegrator : public LinearFormIntegrator +{ +private: + VectorQuadratureFunctionCoefficient &vqfc; +public: + VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc( + vqfc) { } + using LinearFormIntegrator::AssembleRHSElementVect; + void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect); }; -class QuadratureIntegrator : public LinearFormIntegrator { - private: - QuadratureFunctionCoefficient &qfc; - public: - QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } - using LinearFormIntegrator::AssembleRHSElementVect; - void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect); +class QuadratureIntegrator : public LinearFormIntegrator +{ +private: + QuadratureFunctionCoefficient &qfc; +public: + QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } + using LinearFormIntegrator::AssembleRHSElementVect; + void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect); }; } From 02caf2cdf017c69d229c55b4f515c31b1f13a9f9 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Apr 2020 15:01:29 -0700 Subject: [PATCH 191/535] All L2 projection methods now work but still missing parallel implementations --- fem/field_interpolant.cpp | 135 +++++++++++++++++++++++++---- fem/field_interpolant.hpp | 29 ++++++- tests/unit/fem/test_quadf_coef.cpp | 40 +++++---- 3 files changed, 168 insertions(+), 36 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 4ca0cc6321..507b1312d8 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -13,7 +13,7 @@ #include "field_interpolant.hpp" #include "../linalg/densemat.hpp" -#include "gridfunc.hpp" +#include "fem.hpp" namespace mfem { @@ -75,6 +75,7 @@ void QuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, //If that isn't the case we might be able to still do things but things will most likely be slower. void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &tr_fes, FiniteElementSpace &fes) { int ndofs; @@ -104,18 +105,18 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureIntegrator qi(vqfc); qi.SetIntRule(ir); - if (!setup) + if (!setup_disc) { m_all_data.SetSize(ndofs * ndofs * NE); double* data = m_all_data.HostReadWrite(); for (int e = 0; e < NE; e++) { - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); + const FiniteElement &fe = *tr_fes.GetFE(e); + ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); mass_int.AssembleElementMatrix(fe, eltr, mi); } - setup = true; + setup_disc = true; } double* data = m_all_data.HostReadWrite(); @@ -126,8 +127,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, qfv = 0.0; mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); + const FiniteElement &fe = *tr_fes.GetFE(e); + ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); for (int ind = 0; ind < vdim; ind++) { @@ -146,8 +147,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, { mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); + const FiniteElement &fe = *tr_fes.GetFE(e); + ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); for (int ind = 0; ind < vdim; ind++) { @@ -165,7 +166,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, qfv((nd * vdim) + ind) = tmp(nd + ind * ndofs); } } - fes.GetElementDofs(e, dofs); + fes.GetElementVDofs(e, dofs); gf.SetSubVector(dofs, qfv); } } @@ -173,6 +174,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &tr_fes, FiniteElementSpace &fes) { int ndofs; @@ -200,27 +202,29 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureIntegrator qi(qfc); qi.SetIntRule(ir); - if (!setup) + if (!setup_disc) { m_all_data.SetSize(ndofs * ndofs * NE); double* data = m_all_data.HostReadWrite(); for (int e = 0; e < NE; e++) { - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); + const FiniteElement &fe = *tr_fes.GetFE(e); + ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); mass_int.AssembleElementMatrix(fe, eltr, mi); } - setup = true; + setup_disc = true; } + + double* data = m_all_data.HostReadWrite(); for (int e = 0; e < NE; e++) { mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); + const FiniteElement &fe = *tr_fes.GetFE(e); + ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); inv.Mult(rhs, qfv); fes.GetElementDofs(e, dofs); @@ -228,4 +232,103 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } } +void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &fes) +{ + const IntegrationRule* ir; + { + // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + // and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes.GetFE(0); + ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const QuadratureFunction* qf = vqfc.GetQuadFunction(); + const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && + (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + } + + LinearForm *b = new LinearForm(&fes); + b->AddDomainIntegrator(new VectorQuadratureIntegrator(vqfc, ir)); + b->Assemble(); + + // We need this fes to only have a vdim of 1 which is not the case here so we need to make a new fespace + // Potential fix me with a better implementation + const FiniteElementCollection *fec = fes.FEColl(); + Mesh *mesh = fes.GetMesh(); + FiniteElementSpace fes_v1(mesh, fec, 1); + + BilinearForm *L2 = new BilinearForm(&fes_v1); + L2->AddDomainIntegrator(new MassIntegrator(ir)); + L2->Assemble(); + + GridFunction x(&fes); + x = 0.0; + OperatorPtr A; + Vector B, b_sub, X_sub, X; + + Array ess_tdof_list; + + int vdim = vqfc.GetVDim(); + int size = b->Size() / vdim; + + for(int ind = 0; ind < vdim; ind++) { + int offset = ind * size; + b_sub.MakeRef(*b, offset, size); + X_sub.MakeRef(x, offset, size); + L2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); + // Fix this to be more efficient + // OperatorJacobiSmoother M(*L2, ess_tdof_list); + CG(*A, B, X, 0, 2000, 1e-25, 0.0); + // Recover the solution as a finite element grid function. + L2->RecoverFEMSolution(X, *b, X_sub); + } + gf = x; + + delete L2; + delete b; +} +void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &fes) +{ + const IntegrationRule* ir; + { + // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + // and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes.GetFE(0); + ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const QuadratureFunction* qf = qfc.GetQuadFunction(); + const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && + (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + } + LinearForm *b = new LinearForm(&fes); + b->AddDomainIntegrator(new QuadratureIntegrator(qfc, ir)); + b->Assemble(); + + BilinearForm *L2 = new BilinearForm(&fes); + L2->AddDomainIntegrator(new MassIntegrator(ir)); + L2->Assemble(); + + GridFunction x(&fes); + x = 0.0; + OperatorPtr A; + Vector B, X; + Array ess_tdof_list; + + L2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + // Fix this to be more efficient + // OperatorJacobiSmoother M(*L2, ess_tdof_list); + CG(*A, B, X, 0, 2000, 1e-25, 0.0); + // Recover the solution as a finite element grid function. + L2->RecoverFEMSolution(X, *b, x); + gf = x; + + delete L2; + delete b; +} + } \ No newline at end of file diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 457fce0d7d..a4f4ae1b5d 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -28,19 +28,41 @@ namespace mfem class FieldInterpolant { private: - bool setup; + bool setup_disc; Vector m_all_data; MassIntegrator mass_int; int NE; public: FieldInterpolant(const IntegrationRule* ir) { mass_int.SetIntRule(ir); } + // This function takes a vector quadrature function coefficient and projects it onto a GridFunction that lives + // in L2 space. This function requires tr_fes to be the finite element space that the VectorQuadratureFunctionCoefficient lives on + // and fes is the L2 finite element space that we're projecting onto. void ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &tr_fes, FiniteElementSpace &fes); + // This function takes a quadrature function coefficient and projects it onto a GridFunction that lives + // in L2 space. This function requires tr_fes to be the finite element space that the QuadratureFunctionCoefficient lives on + // and fes is the L2 finite element space that we're projecting onto. void ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &tr_fes, FiniteElementSpace &fes); - void SetupReset() { setup = false; } + //Parallel versions of the ProjectQuadratureCoefficient will need to be created once the serial version works + + // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector + // quadrature function coefficient. + void ProjectQuadratureCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + FiniteElementSpace &fes); + // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as + // quadrature function coefficient. + void ProjectQuadratureCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc, + FiniteElementSpace &fes); + //Tells the ProjectQuadratureDiscCoefficient that they need to recalculate the data. + void SetupDiscReset() { setup_disc = false; } + ~FieldInterpolant() {} }; class VectorQuadratureIntegrator : public LinearFormIntegrator @@ -50,6 +72,8 @@ private: public: VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc( vqfc) { } + VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc, const IntegrationRule *ir) : vqfc( + vqfc), LinearFormIntegrator(ir) { } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, @@ -62,6 +86,7 @@ private: QuadratureFunctionCoefficient &qfc; public: QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } + QuadratureIntegrator(QuadratureFunctionCoefficient &qfc, const IntegrationRule *ir) : qfc(qfc), LinearFormIntegrator(ir) { } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 62ab08ecbb..00beb51cde 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -89,6 +89,8 @@ TEST_CASE("Quadrature Function Coefficients", std::cout << " Testing GridFunc L2 projection" << std::endl; L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); @@ -106,8 +108,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - // g0.ProjectDiscCoefficient(qfvc, GridFunction::ARITHMETIC); - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -134,7 +135,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - g0.ProjectCoefficient(qfvc); + fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -148,31 +149,35 @@ TEST_CASE("Quadrature Function Coefficients", std::cout << " Testing GridFunc L2 projection" << std::endl; L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); - // This line is necessary for the test suite. - fi.SetupReset(); + + fi.SetupDiscReset(); // When using an L2 FE space of the same order as the mesh, the below highlights // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. { int ne = mesh.GetNE(); - int int_points = ir.GetNPoints(); - for (int i = 0; i < ne; i++) - { - for (int j = 0; j < int_points; j++) - { - gtrue((i * int_points) + j) = geom_facts->X((i * int_points * dim) + - (2 * int_points) + j); + GridFunction nodes(&fespace_h1); + Vector el_x; + Array vdofs; + mesh.GetNodes(nodes); + for(int i = 0; i < ne; i++){ + fespace_h1.GetElementVDofs(i, vdofs); + nodes.GetSubVector(vdofs, el_x); + // Should be constant across all elements + int enodes = el_x.Size() / dim; + for(int j = 0; j < enodes; j++){ + gtrue(j + i * enodes) = el_x(enodes * 2 + j); } } } g0 = 0.0; - // These two methods result in the same answer at least for hex meshes - // g0.ProjectDiscCoefficient(qfc, GridFunction::ARITHMETIC); - fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_h1, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -196,11 +201,10 @@ TEST_CASE("Quadrature Function Coefficients", gtrue(i) = nodes(i * dim + 2); } } - //If this was actually doing something akin to an L2 projection these values would be fairly close. + g0 = 0.0; - g0.ProjectCoefficient(qfc); + fi.ProjectQuadratureCoefficient(g0, qfc, fespace_h1); gtrue -= g0; - //This currently fails... REQUIRE(gtrue.Norml2() < tol); } } From 881539dfb5e79c90089554a8a48aa62ece6152a4 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Apr 2020 15:03:46 -0700 Subject: [PATCH 192/535] make style --- fem/field_interpolant.cpp | 3 ++- fem/field_interpolant.hpp | 12 +++++++----- tests/unit/fem/test_quadf_coef.cpp | 6 ++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 507b1312d8..c66318f03e 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -273,7 +273,8 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, int vdim = vqfc.GetVDim(); int size = b->Size() / vdim; - for(int ind = 0; ind < vdim; ind++) { + for (int ind = 0; ind < vdim; ind++) + { int offset = ind * size; b_sub.MakeRef(*b, offset, size); X_sub.MakeRef(x, offset, size); diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index a4f4ae1b5d..14bc42f866 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -49,13 +49,13 @@ public: FiniteElementSpace &tr_fes, FiniteElementSpace &fes); //Parallel versions of the ProjectQuadratureCoefficient will need to be created once the serial version works - + // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector // quadrature function coefficient. void ProjectQuadratureCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, FiniteElementSpace &fes); - // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as + // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as // quadrature function coefficient. void ProjectQuadratureCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, @@ -72,8 +72,9 @@ private: public: VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc( vqfc) { } - VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc, const IntegrationRule *ir) : vqfc( - vqfc), LinearFormIntegrator(ir) { } + VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc, + const IntegrationRule *ir) : vqfc( + vqfc), LinearFormIntegrator(ir) { } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, @@ -86,7 +87,8 @@ private: QuadratureFunctionCoefficient &qfc; public: QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } - QuadratureIntegrator(QuadratureFunctionCoefficient &qfc, const IntegrationRule *ir) : qfc(qfc), LinearFormIntegrator(ir) { } + QuadratureIntegrator(QuadratureFunctionCoefficient &qfc, + const IntegrationRule *ir) : qfc(qfc), LinearFormIntegrator(ir) { } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 00beb51cde..624806537d 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -165,12 +165,14 @@ TEST_CASE("Quadrature Function Coefficients", Vector el_x; Array vdofs; mesh.GetNodes(nodes); - for(int i = 0; i < ne; i++){ + for (int i = 0; i < ne; i++) + { fespace_h1.GetElementVDofs(i, vdofs); nodes.GetSubVector(vdofs, el_x); // Should be constant across all elements int enodes = el_x.Size() / dim; - for(int j = 0; j < enodes; j++){ + for (int j = 0; j < enodes; j++) + { gtrue(j + i * enodes) = el_x(enodes * 2 + j); } } From 0119774c0f5a9f330c3a41cf8c6bd3b6fe4446d3 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Mon, 20 Apr 2020 15:10:28 -0700 Subject: [PATCH 193/535] Changed the names of the basically typed member variables in the FiniteElement class to snake_case. --- fem/fe.cpp | 998 ++++++++++++++++++++++++++--------------------------- fem/fe.hpp | 144 ++++---- 2 files changed, 571 insertions(+), 571 deletions(-) diff --git a/fem/fe.cpp b/fem/fe.cpp index 196762eb40..4dd44c6aff 100644 --- a/fem/fe.cpp +++ b/fem/fe.cpp @@ -25,15 +25,15 @@ using namespace std; FiniteElement::FiniteElement(int D, Geometry::Type G, int Do, int O, int F) : Nodes(Do) { - Dim = D ; GeomType = G ; Dof = Do ; Order = O ; FuncSpace = F; - RangeType = SCALAR; - MapType = VALUE; - DerivType = NONE; - DerivRangeType = SCALAR; - DerivMapType = VALUE; - for (int i = 0; i < Geometry::MaxDim; i++) { Orders[i] = -1; } + dim = D ; geom_type = G ; dof = Do ; order = O ; func_space = F; + range_type = SCALAR; + map_type = VALUE; + deriv_type = NONE; + deriv_range_type = SCALAR; + deriv_map_type = VALUE; + for (int i = 0; i < Geometry::MaxDim; i++) { orders[i] = -1; } #ifndef MFEM_THREAD_SAFE - vshape.SetSize(Dof, Dim); + vshape.SetSize(dof, dim); #endif } @@ -75,12 +75,12 @@ void FiniteElement::CalcCurlShape(const IntegrationPoint &ip, void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape) const { - switch (Dim) + switch (dim) { case 3: { #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif CalcCurlShape(Trans.GetIntPoint(), vshape); MultABt(vshape, Trans.Jacobian(), curl_shape); @@ -93,7 +93,7 @@ void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans, curl_shape *= (1.0 / Trans.Weight()); break; default: - MFEM_ABORT("Invalid dimension, Dim = " << Dim); + MFEM_ABORT("Invalid dimension, Dim = " << dim); } } @@ -186,7 +186,7 @@ void FiniteElement::CalcPhysShape(ElementTransformation &Trans, Vector &shape) const { CalcShape(Trans.GetIntPoint(), shape); - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { shape /= Trans.Weight(); } @@ -195,9 +195,9 @@ void FiniteElement::CalcPhysShape(ElementTransformation &Trans, void FiniteElement::CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const { - MFEM_ASSERT(MapType == VALUE, ""); + MFEM_ASSERT(map_type == VALUE, ""); #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif CalcDShape(Trans.GetIntPoint(), vshape); Mult(vshape, Trans.InverseJacobian(), dshape); @@ -206,7 +206,7 @@ void FiniteElement::CalcPhysDShape(ElementTransformation &Trans, void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans, Vector &Laplacian) const { - MFEM_ASSERT(MapType == VALUE, ""); + MFEM_ASSERT(map_type == VALUE, ""); // Simpler routine if mapping is affine if (Trans.Hessian().FNorm2() < 1e-20) @@ -216,27 +216,27 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans, } // Compute full Hessian first if non-affine - int size = (Dim*(Dim+1))/2; - DenseMatrix hess(Dof, size); + int size = (dim*(dim+1))/2; + DenseMatrix hess(dof, size); CalcPhysHessian(Trans,hess); - if (Dim == 3) + if (dim == 3) { - for (int nd = 0; nd < Dof; nd++) + for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5); } } - else if (Dim == 2) + else if (dim == 2) { - for (int nd = 0; nd < Dof; nd++) + for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = hess(nd,0) + hess(nd,2); } } else { - for (int nd = 0; nd < Dof; nd++) + for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = hess(nd,0); } @@ -248,16 +248,16 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans, void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans, Vector &Laplacian) const { - MFEM_ASSERT(MapType == VALUE, ""); - int size = (Dim*(Dim+1))/2; - DenseMatrix hess(Dof, size); - DenseMatrix Gij(Dim,Dim); + MFEM_ASSERT(map_type == VALUE, ""); + int size = (dim*(dim+1))/2; + DenseMatrix hess(dof, size); + DenseMatrix Gij(dim,dim); Vector scale(size); CalcHessian (Trans.GetIntPoint(), hess); MultAAt(Trans.InverseJacobian(), Gij); - if (Dim == 3) + if (dim == 3) { scale[0] = Gij(0,0); scale[1] = 2*Gij(0,1); @@ -268,7 +268,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans, scale[5] = Gij(1,1); } - else if (Dim == 2) + else if (dim == 2) { scale[0] = Gij(0,0); scale[1] = 2*Gij(0,1); @@ -279,7 +279,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans, scale[0] = Gij(0,0); } - for (int nd = 0; nd < Dof; nd++) + for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = 0.0; for (int ii = 0; ii < size; ii++) @@ -293,11 +293,11 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans, void FiniteElement::CalcPhysHessian(ElementTransformation &Trans, DenseMatrix& Hessian) const { - MFEM_ASSERT(MapType == VALUE, ""); + MFEM_ASSERT(map_type == VALUE, ""); // Roll 2-Tensors in vectors and 4-Tensor in Matrix, exploiting symmetry - Array map(Dim*Dim); - if (Dim == 3) + Array map(dim*dim); + if (dim == 3) { map[0] = 0; map[1] = 1; @@ -311,7 +311,7 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans, map[7] = 3; map[8] = 4; } - else if (Dim == 2) + else if (dim == 2) { map[0] = 0; map[1] = 1; @@ -325,16 +325,16 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans, } // Hessian in ref coords - int size = (Dim*(Dim+1))/2; - DenseMatrix hess(Dof, size); + int size = (dim*(dim+1))/2; + DenseMatrix hess(dof, size); CalcHessian(Trans.GetIntPoint(), hess); // Gradient in physical coords if (Trans.Hessian().FNorm2() > 1e-10) { - DenseMatrix grad(Dof, Dim); + DenseMatrix grad(dof, dim); CalcPhysDShape(Trans, grad); - DenseMatrix gmap(Dof, size); + DenseMatrix gmap(dof, size); Mult(grad,Trans.Hessian(),gmap); hess -= gmap; } @@ -343,15 +343,15 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans, DenseMatrix lhm(size,size); DenseMatrix invJ = Trans.Jacobian(); lhm = 0.0; - for (int i = 0; i < Dim; i++) + for (int i = 0; i < dim; i++) { - for (int j = 0; j < Dim; j++) + for (int j = 0; j < dim; j++) { - for (int k = 0; k < Dim; k++) + for (int k = 0; k < dim; k++) { - for (int l = 0; l < Dim; l++) + for (int l = 0; l < dim; l++) { - lhm(map[i*Dim+j],map[k*Dim+l]) += invJ(i,k)*invJ(j,l); + lhm(map[i*dim+j],map[k*dim+l]) += invJ(i,k)*invJ(j,l); } } } @@ -359,7 +359,7 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans, // Correct multiplicity Vector mult(size); mult = 0.0; - for (int i = 0; i < Dim*Dim; i++) { mult[map[i]]++; } + for (int i = 0; i < dim*dim; i++) { mult[map[i]]++; } lhm.InvRightScaling(mult); // Hessian in physical coords @@ -389,31 +389,31 @@ void ScalarFiniteElement::NodalLocalInterpolation ( const ScalarFiniteElement &fine_fe) const { double v[Geometry::MaxDim]; - Vector vv (v, Dim); + Vector vv (v, dim); IntegrationPoint f_ip; #ifdef MFEM_THREAD_SAFE - Vector c_shape(Dof); + Vector c_shape(dof); #endif - MFEM_ASSERT(MapType == fine_fe.GetMapType(), ""); + MFEM_ASSERT(map_type == fine_fe.GetMapType(), ""); - I.SetSize(fine_fe.Dof, Dof); - for (int i = 0; i < fine_fe.Dof; i++) + I.SetSize(fine_fe.dof, dof); + for (int i = 0; i < fine_fe.dof; i++) { Trans.Transform(fine_fe.Nodes.IntPoint(i), vv); - f_ip.Set(v, Dim); + f_ip.Set(v, dim); CalcShape(f_ip, c_shape); - for (int j = 0; j < Dof; j++) + for (int j = 0; j < dof; j++) if (fabs(I(i,j) = c_shape(j)) < 1.0e-12) { I(i,j) = 0.0; } } - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { // assuming Trans is linear; this should be ok for all refinement types - Trans.SetIntPoint(&Geometries.GetCenter(GeomType)); + Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); I *= Trans.Weight(); } } @@ -425,7 +425,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation( // General "interpolation", defined by L2 projection double v[Geometry::MaxDim]; - Vector vv (v, Dim); + Vector vv (v, dim); IntegrationPoint f_ip; const int fs = fine_fe.GetDof(), cs = this->GetDof(); @@ -440,7 +440,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation( const IntegrationPoint &ip = ir.IntPoint(i); fine_fe.CalcShape(ip, fine_shape); Trans.Transform(ip, vv); - f_ip.Set(v, Dim); + f_ip.Set(v, dim); this->CalcShape(f_ip, coarse_shape); AddMult_a_VVt(ip.weight, fine_shape, fine_mass); @@ -450,10 +450,10 @@ void ScalarFiniteElement::ScalarLocalInterpolation( DenseMatrixInverse fine_mass_inv(fine_mass); fine_mass_inv.Mult(fine_coarse_mass, I); - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { // assuming Trans is linear; this should be ok for all refinement types - Trans.SetIntPoint(&Geometries.GetCenter(GeomType)); + Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); I *= Trans.Weight(); } } @@ -474,30 +474,30 @@ const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir, d2q->FE = this; d2q->IntRule = &ir; d2q->mode = mode; - d2q->ndof = Dof; + d2q->ndof = dof; d2q->nqpt = nqpt; - d2q->B.SetSize(nqpt*Dof); - d2q->Bt.SetSize(Dof*nqpt); - d2q->G.SetSize(nqpt*Dim*Dof); - d2q->Gt.SetSize(Dof*nqpt*Dim); + d2q->B.SetSize(nqpt*dof); + d2q->Bt.SetSize(dof*nqpt); + d2q->G.SetSize(nqpt*dim*dof); + d2q->Gt.SetSize(dof*nqpt*dim); #ifdef MFEM_THREAD_SAFE - Vector c_shape(Dof); - DenseMatrix vshape(Dof, Dim); + Vector c_shape(dof); + DenseMatrix vshape(dof, dim); #endif for (int i = 0; i < nqpt; i++) { const IntegrationPoint &ip = ir.IntPoint(i); CalcShape(ip, c_shape); - for (int j = 0; j < Dof; j++) + for (int j = 0; j < dof; j++) { - d2q->B[i+nqpt*j] = d2q->Bt[j+Dof*i] = c_shape(j); + d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = c_shape(j); } CalcDShape(ip, vshape); - for (int d = 0; d < Dim; d++) + for (int d = 0; d < dim; d++) { - for (int j = 0; j < Dof; j++) + for (int j = 0; j < dof; j++) { - d2q->G[i+nqpt*(d+Dim*j)] = d2q->Gt[j+Dof*(i+nqpt*d)] = vshape(j,d); + d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j,d); } } } @@ -520,8 +520,8 @@ const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad( DofToQuad *d2q = new DofToQuad; const Poly_1D::Basis &basis_1d = tb.GetBasis1D(); - const int ndof = Order + 1; - const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/Dim) + 0.5); + const int ndof = order + 1; + const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5); d2q->FE = this; d2q->IntRule = &ir; d2q->mode = mode; @@ -556,8 +556,8 @@ void NodalFiniteElement::ProjectCurl_2D( DenseMatrix curl_shape(fe.GetDof(), 1); - curl.SetSize(Dof, fe.GetDof()); - for (int i = 0; i < Dof; i++) + curl.SetSize(dof, fe.GetDof()); + for (int i = 0; i < dof; i++) { fe.CalcCurlShape(Nodes.IntPoint(i), curl_shape); for (int j = 0; j < fe.GetDof(); j++) @@ -587,18 +587,18 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans, DenseMatrix &R) const { IntegrationPoint ipt; - Vector pt(&ipt.x, Dim); + Vector pt(&ipt.x, dim); #ifdef MFEM_THREAD_SAFE - Vector c_shape(Dof); + Vector c_shape(dof); #endif Trans.SetIntPoint(&Nodes[0]); - for (int j = 0; j < Dof; j++) + for (int j = 0; j < dof; j++) { InvertLinearTrans(Trans, Nodes[j], pt); - if (Geometries.CheckPoint(GeomType, ipt)) // do we need an epsilon here? + if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here? { CalcShape(ipt, c_shape); R.SetRow(j, c_shape); @@ -615,14 +615,14 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans, void NodalFiniteElement::Project ( Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const { - for (int i = 0; i < Dof; i++) + for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); // some coefficients expect that Trans.IntPoint is the same // as the second argument of Eval Trans.SetIntPoint(&ip); dofs(i) = coeff.Eval (Trans, ip); - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { dofs(i) *= Trans.Weight(); } @@ -632,21 +632,21 @@ void NodalFiniteElement::Project ( void NodalFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { - MFEM_ASSERT(dofs.Size() == vc.GetVDim()*Dof, ""); + MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, ""); Vector x(vc.GetVDim()); - for (int i = 0; i < Dof; i++) + for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); vc.Eval (x, Trans, ip); - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { x *= Trans.Weight(); } for (int j = 0; j < x.Size(); j++) { - dofs(Dof*j+i) = x(j); + dofs(dof*j+i) = x(j); } } } @@ -654,20 +654,20 @@ void NodalFiniteElement::Project ( void NodalFiniteElement::ProjectMatrixCoefficient( MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const { - // (mc.height x mc.width) @ DOFs -> (Dof x mc.width x mc.height) in dofs - MFEM_ASSERT(dofs.Size() == mc.GetHeight()*mc.GetWidth()*Dof, ""); + // (mc.height x mc.width) @ DOFs -> (dof x mc.width x mc.height) in dofs + MFEM_ASSERT(dofs.Size() == mc.GetHeight()*mc.GetWidth()*dof, ""); DenseMatrix MQ(mc.GetHeight(), mc.GetWidth()); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { T.SetIntPoint(&Nodes.IntPoint(k)); mc.Eval(MQ, T, Nodes.IntPoint(k)); - if (MapType == INTEGRAL) { MQ *= T.Weight(); } + if (map_type == INTEGRAL) { MQ *= T.Weight(); } for (int r = 0; r < MQ.Height(); r++) { for (int d = 0; d < MQ.Width(); d++) { - dofs(k+Dof*(d+MQ.Width()*r)) = MQ(r,d); + dofs(k+dof*(d+MQ.Width()*r)) = MQ(r,d); } } } @@ -678,12 +678,12 @@ void NodalFiniteElement::Project( { if (fe.GetRangeType() == SCALAR) { - MFEM_ASSERT(MapType == fe.GetMapType(), ""); + MFEM_ASSERT(map_type == fe.GetMapType(), ""); Vector shape(fe.GetDof()); - I.SetSize(Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + I.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { fe.CalcShape(Nodes.IntPoint(k), shape); for (int j = 0; j < shape.Size(); j++) @@ -696,19 +696,19 @@ void NodalFiniteElement::Project( { DenseMatrix vshape(fe.GetDof(), Trans.GetSpaceDim()); - I.SetSize(vshape.Width()*Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + I.SetSize(vshape.Width()*dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { Trans.SetIntPoint(&Nodes.IntPoint(k)); fe.CalcVShape(Trans, vshape); - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { vshape *= Trans.Weight(); } for (int j = 0; j < vshape.Height(); j++) for (int d = 0; d < vshape.Width(); d++) { - I(k+d*Dof,j) = vshape(j,d); + I(k+d*dof,j) = vshape(j,d); } } } @@ -719,26 +719,26 @@ void NodalFiniteElement::ProjectGrad( DenseMatrix &grad) const { MFEM_ASSERT(fe.GetMapType() == VALUE, ""); - MFEM_ASSERT(Trans.GetSpaceDim() == Dim, "") + MFEM_ASSERT(Trans.GetSpaceDim() == dim, "") - DenseMatrix dshape(fe.GetDof(), Dim), grad_k(fe.GetDof(), Dim), Jinv(Dim); + DenseMatrix dshape(fe.GetDof(), dim), grad_k(fe.GetDof(), dim), Jinv(dim); - grad.SetSize(Dim*Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + grad.SetSize(dim*dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcDShape(ip, dshape); Trans.SetIntPoint(&ip); CalcInverse(Trans.Jacobian(), Jinv); Mult(dshape, Jinv, grad_k); - if (MapType == INTEGRAL) + if (map_type == INTEGRAL) { grad_k *= Trans.Weight(); } for (int j = 0; j < grad_k.Height(); j++) - for (int d = 0; d < Dim; d++) + for (int d = 0; d < dim; d++) { - grad(k+d*Dof,j) = grad_k(j,d); + grad(k+d*dof,j) = grad_k(j,d); } } } @@ -750,12 +750,12 @@ void NodalFiniteElement::ProjectDiv( double detJ; Vector div_shape(fe.GetDof()); - div.SetSize(Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + div.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcDivShape(ip, div_shape); - if (MapType == VALUE) + if (map_type == VALUE) { Trans.SetIntPoint(&ip); detJ = Trans.Weight(); @@ -778,7 +778,7 @@ void NodalFiniteElement::ProjectDiv( void PositiveFiniteElement::Project( Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const { - for (int i = 0; i < Dof; i++) + for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); @@ -789,17 +789,17 @@ void PositiveFiniteElement::Project( void PositiveFiniteElement::Project( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { - MFEM_ASSERT(dofs.Size() == vc.GetVDim()*Dof, ""); + MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, ""); Vector x(vc.GetVDim()); - for (int i = 0; i < Dof; i++) + for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); vc.Eval (x, Trans, ip); for (int j = 0; j < x.Size(); j++) { - dofs(Dof*j+i) = x(j); + dofs(dof*j+i) = x(j); } } } @@ -810,7 +810,7 @@ void PositiveFiniteElement::Project( const NodalFiniteElement *nfe = dynamic_cast(&fe); - if (nfe && Dof == nfe->GetDof()) + if (nfe && dof == nfe->GetDof()) { nfe->Project(*this, Trans, I); I.Invert(); @@ -825,7 +825,7 @@ void PositiveFiniteElement::Project( mass_integ.AssembleElementMatrix2(fe, *this, Trans, mixed_mass); DenseMatrixInverse pos_mass_inv(pos_mass); - I.SetSize(Dof, fe.GetDof()); + I.SetSize(dof, fe.GetDof()); pos_mass_inv.Mult(mixed_mass, I); } } @@ -847,47 +847,47 @@ void VectorFiniteElement::CalcDShape ( void VectorFiniteElement::SetDerivMembers() { - switch (MapType) + switch (map_type) { case H_DIV: - DerivType = DIV; - DerivRangeType = SCALAR; - DerivMapType = INTEGRAL; + deriv_type = DIV; + deriv_range_type = SCALAR; + deriv_map_type = INTEGRAL; break; case H_CURL: - switch (Dim) + switch (dim) { case 3: // curl: 3D H_CURL -> 3D H_DIV - DerivType = CURL; - DerivRangeType = VECTOR; - DerivMapType = H_DIV; + deriv_type = CURL; + deriv_range_type = VECTOR; + deriv_map_type = H_DIV; break; case 2: // curl: 2D H_CURL -> INTEGRAL - DerivType = CURL; - DerivRangeType = SCALAR; - DerivMapType = INTEGRAL; + deriv_type = CURL; + deriv_range_type = SCALAR; + deriv_map_type = INTEGRAL; break; case 1: - DerivType = NONE; - DerivRangeType = SCALAR; - DerivMapType = INTEGRAL; + deriv_type = NONE; + deriv_range_type = SCALAR; + deriv_map_type = INTEGRAL; break; default: - MFEM_ABORT("Invalid dimension, Dim = " << Dim); + MFEM_ABORT("Invalid dimension, Dim = " << dim); } break; default: - MFEM_ABORT("Invalid MapType = " << MapType); + MFEM_ABORT("Invalid MapType = " << map_type); } } void VectorFiniteElement::CalcVShape_RT ( ElementTransformation &Trans, DenseMatrix &shape) const { - MFEM_ASSERT(MapType == H_DIV, ""); + MFEM_ASSERT(map_type == H_DIV, ""); #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif CalcVShape(Trans.GetIntPoint(), vshape); MultABt(vshape, Trans.Jacobian(), shape); @@ -897,9 +897,9 @@ void VectorFiniteElement::CalcVShape_RT ( void VectorFiniteElement::CalcVShape_ND ( ElementTransformation &Trans, DenseMatrix &shape) const { - MFEM_ASSERT(MapType == H_CURL, ""); + MFEM_ASSERT(map_type == H_CURL, ""); #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif CalcVShape(Trans.GetIntPoint(), vshape); Mult(vshape, Trans.InverseJacobian(), shape); @@ -913,14 +913,14 @@ void VectorFiniteElement::Project_RT( const int sdim = Trans.GetSpaceDim(); MFEM_ASSERT(vc.GetVDim() == sdim, ""); Vector xk(vk, sdim); - const bool square_J = (Dim == sdim); + const bool square_J = (dim == sdim); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { Trans.SetIntPoint(&Nodes.IntPoint(k)); vc.Eval(xk, Trans, Nodes.IntPoint(k)); // dof_k = nk^t adj(J) xk - dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*Dim); + dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim); if (!square_J) { dofs(k) /= Trans.Weight(); } } } @@ -933,22 +933,22 @@ void VectorFiniteElement::ProjectMatrixCoefficient_RT( const int sdim = T.GetSpaceDim(); MFEM_ASSERT(mc.GetWidth() == sdim, ""); - const bool square_J = (Dim == sdim); + const bool square_J = (dim == sdim); DenseMatrix MQ(mc.GetHeight(), mc.GetWidth()); Vector nk_phys(sdim), dofs_k(MQ.Height()); - MFEM_ASSERT(dofs.Size() == Dof*MQ.Height(), ""); + MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), ""); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { T.SetIntPoint(&Nodes.IntPoint(k)); mc.Eval(MQ, T, Nodes.IntPoint(k)); // nk_phys = adj(J)^t nk - T.AdjugateJacobian().MultTranspose(nk + d2n[k]*Dim, nk_phys); + T.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, nk_phys); if (!square_J) { nk_phys /= T.Weight(); } MQ.Mult(nk_phys, dofs_k); for (int r = 0; r < MQ.Height(); r++) { - dofs(k+Dof*r) = dofs_k(r); + dofs(k+dof*r) = dofs_k(r); } } } @@ -963,18 +963,18 @@ void VectorFiniteElement::Project_RT( Vector shape(fe.GetDof()); int sdim = Trans.GetSpaceDim(); - I.SetSize(Dof, sdim*fe.GetDof()); - for (int k = 0; k < Dof; k++) + I.SetSize(dof, sdim*fe.GetDof()); + for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcShape(ip, shape); Trans.SetIntPoint(&ip); - Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*Dim, vk); + Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk); if (fe.GetMapType() == INTEGRAL) { double w = 1.0/Trans.Weight(); - for (int d = 0; d < Dim; d++) + for (int d = 0; d < dim; d++) { vk[d] *= w; } @@ -1004,7 +1004,7 @@ void VectorFiniteElement::ProjectGrad_RT( const double *nk, const Array &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const { - if (Dim != 2) + if (dim != 2) { mfem_error("VectorFiniteElement::ProjectGrad_RT works only in 2D!"); } @@ -1013,12 +1013,12 @@ void VectorFiniteElement::ProjectGrad_RT( Vector grad_k(fe.GetDof()); double tk[2]; - grad.SetSize(Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + grad.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { fe.CalcDShape(Nodes.IntPoint(k), dshape); - tk[0] = nk[d2n[k]*Dim+1]; - tk[1] = -nk[d2n[k]*Dim]; + tk[0] = nk[d2n[k]*dim+1]; + tk[1] = -nk[d2n[k]*dim]; dshape.Mult(tk, grad_k); for (int j = 0; j < grad_k.Size(); j++) { @@ -1032,19 +1032,19 @@ void VectorFiniteElement::ProjectCurl_ND( ElementTransformation &Trans, DenseMatrix &curl) const { #ifdef MFEM_THREAD_SAFE - DenseMatrix curlshape(fe.GetDof(), Dim); - DenseMatrix curlshape_J(fe.GetDof(), Dim); - DenseMatrix J(Dim, Dim); + DenseMatrix curlshape(fe.GetDof(), dim); + DenseMatrix curlshape_J(fe.GetDof(), dim); + DenseMatrix J(dim, dim); #else - curlshape.SetSize(fe.GetDof(), Dim); - curlshape_J.SetSize(fe.GetDof(), Dim); - J.SetSize(Dim, Dim); + curlshape.SetSize(fe.GetDof(), dim); + curlshape_J.SetSize(fe.GetDof(), dim); + J.SetSize(dim, dim); #endif Vector curl_k(fe.GetDof()); - curl.SetSize(Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + curl.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); @@ -1057,7 +1057,7 @@ void VectorFiniteElement::ProjectCurl_ND( fe.CalcCurlShape(ip, curlshape); Mult(curlshape, J, curlshape_J); - curlshape_J.Mult(tk + d2t[k]*Dim, curl_k); + curlshape_J.Mult(tk + d2t[k]*dim, curl_k); for (int j = 0; j < curl_k.Size(); j++) { curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j); @@ -1069,14 +1069,14 @@ void VectorFiniteElement::ProjectCurl_RT( const double *nk, const Array &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const { - DenseMatrix curl_shape(fe.GetDof(), Dim); + DenseMatrix curl_shape(fe.GetDof(), dim); Vector curl_k(fe.GetDof()); - curl.SetSize(Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + curl.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { fe.CalcCurlShape(Nodes.IntPoint(k), curl_shape); - curl_shape.Mult(nk + d2n[k]*Dim, curl_k); + curl_shape.Mult(nk + d2n[k]*dim, curl_k); for (int j = 0; j < curl_k.Size(); j++) { curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j); @@ -1091,13 +1091,13 @@ void VectorFiniteElement::Project_ND( double vk[Geometry::MaxDim]; Vector xk(vk, vc.GetVDim()); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { Trans.SetIntPoint(&Nodes.IntPoint(k)); vc.Eval(xk, Trans, Nodes.IntPoint(k)); // dof_k = xk^t J tk - dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*Dim, vk); + dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk); } } @@ -1111,18 +1111,18 @@ void VectorFiniteElement::ProjectMatrixCoefficient_ND( MFEM_ASSERT(mc.GetWidth() == sdim, ""); DenseMatrix MQ(mc.GetHeight(), mc.GetWidth()); Vector tk_phys(sdim), dofs_k(MQ.Height()); - MFEM_ASSERT(dofs.Size() == Dof*MQ.Height(), ""); + MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), ""); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { T.SetIntPoint(&Nodes.IntPoint(k)); mc.Eval(MQ, T, Nodes.IntPoint(k)); // tk_phys = J tk - T.Jacobian().Mult(tk + d2t[k]*Dim, tk_phys); + T.Jacobian().Mult(tk + d2t[k]*dim, tk_phys); MQ.Mult(tk_phys, dofs_k); for (int r = 0; r < MQ.Height(); r++) { - dofs(k+Dof*r) = dofs_k(r); + dofs(k+dof*r) = dofs_k(r); } } } @@ -1137,14 +1137,14 @@ void VectorFiniteElement::Project_ND( double vk[Geometry::MaxDim]; Vector shape(fe.GetDof()); - I.SetSize(Dof, sdim*fe.GetDof()); - for (int k = 0; k < Dof; k++) + I.SetSize(dof, sdim*fe.GetDof()); + for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcShape(ip, shape); Trans.SetIntPoint(&ip); - Trans.Jacobian().Mult(tk + d2t[k]*Dim, vk); + Trans.Jacobian().Mult(tk + d2t[k]*dim, vk); if (fe.GetMapType() == INTEGRAL) { double w = 1.0/Trans.Weight(); @@ -1183,11 +1183,11 @@ void VectorFiniteElement::ProjectGrad_ND( DenseMatrix dshape(fe.GetDof(), fe.GetDim()); Vector grad_k(fe.GetDof()); - grad.SetSize(Dof, fe.GetDof()); - for (int k = 0; k < Dof; k++) + grad.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) { fe.CalcDShape(Nodes.IntPoint(k), dshape); - dshape.Mult(tk + d2t[k]*Dim, grad_k); + dshape.Mult(tk + d2t[k]*dim, grad_k); for (int j = 0; j < grad_k.Size(); j++) { grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j); @@ -1199,33 +1199,33 @@ void VectorFiniteElement::LocalInterpolation_RT( const VectorFiniteElement &cfe, const double *nk, const Array &d2n, ElementTransformation &Trans, DenseMatrix &I) const { - MFEM_ASSERT(MapType == cfe.GetMapType(), ""); + MFEM_ASSERT(map_type == cfe.GetMapType(), ""); double vk[Geometry::MaxDim]; - Vector xk(vk, Dim); + Vector xk(vk, dim); IntegrationPoint ip; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(cfe.GetDof(), cfe.GetDim()); #else DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim()); #endif - I.SetSize(Dof, vshape.Height()); + I.SetSize(dof, vshape.Height()); // assuming Trans is linear; this should be ok for all refinement types - Trans.SetIntPoint(&Geometries.GetCenter(GeomType)); + Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &adjJ = Trans.AdjugateJacobian(); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { Trans.Transform(Nodes.IntPoint(k), xk); ip.Set3(vk); cfe.CalcVShape(ip, vshape); // xk = |J| J^{-t} n_k - adjJ.MultTranspose(nk + d2n[k]*Dim, vk); - // I_k = vshape_k.adj(J)^t.n_k, k=1,...,Dof + adjJ.MultTranspose(nk + d2n[k]*dim, vk); + // I_k = vshape_k.adj(J)^t.n_k, k=1,...,dof for (int j = 0; j < vshape.Height(); j++) { double Ikj = 0.; - for (int i = 0; i < Dim; i++) + for (int i = 0; i < dim; i++) { Ikj += vshape(j, i) * vk[i]; } @@ -1239,30 +1239,30 @@ void VectorFiniteElement::LocalInterpolation_ND( ElementTransformation &Trans, DenseMatrix &I) const { double vk[Geometry::MaxDim]; - Vector xk(vk, Dim); + Vector xk(vk, dim); IntegrationPoint ip; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(cfe.GetDof(), cfe.GetDim()); #else DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim()); #endif - I.SetSize(Dof, vshape.Height()); + I.SetSize(dof, vshape.Height()); // assuming Trans is linear; this should be ok for all refinement types - Trans.SetIntPoint(&Geometries.GetCenter(GeomType)); + Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &J = Trans.Jacobian(); - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { Trans.Transform(Nodes.IntPoint(k), xk); ip.Set3(vk); cfe.CalcVShape(ip, vshape); // xk = J t_k - J.Mult(tk + d2t[k]*Dim, vk); + J.Mult(tk + d2t[k]*dim, vk); // I_k = vshape_k.J.t_k, k=1,...,Dof for (int j = 0; j < vshape.Height(); j++) { double Ikj = 0.; - for (int i = 0; i < Dim; i++) + for (int i = 0; i < dim; i++) { Ikj += vshape(j, i) * vk[i]; } @@ -1277,28 +1277,28 @@ void VectorFiniteElement::LocalRestriction_RT( { double pt_data[Geometry::MaxDim]; IntegrationPoint ip; - Vector pt(pt_data, Dim); + Vector pt(pt_data, dim); #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif - Trans.SetIntPoint(&Geometries.GetCenter(GeomType)); + Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &J = Trans.Jacobian(); const double weight = Trans.Weight(); - for (int j = 0; j < Dof; j++) + for (int j = 0; j < dof; j++) { InvertLinearTrans(Trans, Nodes.IntPoint(j), pt); - ip.Set(pt_data, Dim); - if (Geometries.CheckPoint(GeomType, ip)) // do we need an epsilon here? + ip.Set(pt_data, dim); + if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here? { CalcVShape(ip, vshape); - J.MultTranspose(nk+Dim*d2n[j], pt_data); + J.MultTranspose(nk+dim*d2n[j], pt_data); pt /= weight; - for (int k = 0; k < Dof; k++) + for (int k = 0; k < dof; k++) { double R_jk = 0.0; - for (int d = 0; d < Dim; d++) + for (int d = 0; d < dim; d++) { R_jk += vshape(k,d)*pt_data[d]; } @@ -1320,26 +1320,26 @@ void VectorFiniteElement::LocalRestriction_ND( { double pt_data[Geometry::MaxDim]; IntegrationPoint ip; - Vector pt(pt_data, Dim); + Vector pt(pt_data, dim); #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif - Trans.SetIntPoint(&Geometries.GetCenter(GeomType)); + Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &Jinv = Trans.InverseJacobian(); - for (int j = 0; j < Dof; j++) + for (int j = 0; j < dof; j++) { InvertLinearTrans(Trans, Nodes.IntPoint(j), pt); - ip.Set(pt_data, Dim); - if (Geometries.CheckPoint(GeomType, ip)) // do we need an epsilon here? + ip.Set(pt_data, dim); + if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here? { CalcVShape(ip, vshape); - Jinv.Mult(tk+Dim*d2t[j], pt_data); - for (int k = 0; k < Dof; k++) + Jinv.Mult(tk+dim*d2t[j], pt_data); + for (int k = 0; k < dof; k++) { double R_jk = 0.0; - for (int d = 0; d < Dim; d++) + for (int d = 0; d < dim; d++) { R_jk += vshape(k,d)*pt_data[d]; } @@ -2130,7 +2130,7 @@ void H1Ser_QuadrilateralElement::GetLocalInterpolation(ElementTransformation { // For p<=4, the basis is nodal; for p>4, the quad-interior functions are // non-nodal. - if (Order <= 4) + if (order <= 4) { NodalLocalInterpolation(Trans, I, *this); } @@ -3323,8 +3323,8 @@ void RT0TriangleFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -3377,7 +3377,7 @@ void RT0TriangleFiniteElement::Project ( double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 3; k++) @@ -3438,8 +3438,8 @@ void RT0QuadFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -3492,7 +3492,7 @@ void RT0QuadFiniteElement::Project ( double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 4; k++) @@ -3580,8 +3580,8 @@ void RT1TriangleFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -3633,7 +3633,7 @@ void RT1TriangleFiniteElement::Project ( double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 8; k++) @@ -3762,8 +3762,8 @@ void RT1QuadFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -3815,7 +3815,7 @@ void RT1QuadFiniteElement::Project ( double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 12; k++) @@ -4214,8 +4214,8 @@ void RT2QuadFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -4267,7 +4267,7 @@ void RT2QuadFiniteElement::Project ( double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 24; k++) @@ -4574,9 +4574,9 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) { if (degree == 2) { - I = new int[Dof]; - J = new int[Dof]; - K = new int[Dof]; + I = new int[dof]; + J = new int[dof]; + K = new int[dof]; // nodes I[ 0] = 0; J[ 0] = 0; K[ 0] = 0; I[ 1] = 1; J[ 1] = 0; K[ 1] = 0; @@ -4611,9 +4611,9 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) } else if (degree == 3) { - I = new int[Dof]; - J = new int[Dof]; - K = new int[Dof]; + I = new int[dof]; + J = new int[dof]; + K = new int[dof]; // nodes I[ 0] = 0; J[ 0] = 0; K[ 0] = 0; I[ 1] = 1; J[ 1] = 0; K[ 1] = 0; @@ -4701,7 +4701,7 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) dshape1dz.SetSize(dof1d,1); #endif - for (int n = 0; n < Dof; n++) + for (int n = 0; n < dof; n++) { Nodes.IntPoint(n).x = fe1d -> GetNodes().IntPoint(I[n]).x; Nodes.IntPoint(n).y = fe1d -> GetNodes().IntPoint(J[n]).x; @@ -4724,7 +4724,7 @@ void LagrangeHexFiniteElement::CalcShape(const IntegrationPoint &ip, fe1d -> CalcShape(ipy, shape1dy); fe1d -> CalcShape(ipz, shape1dz); - for (int n = 0; n < Dof; n++) + for (int n = 0; n < dof; n++) { shape(n) = shape1dx(I[n]) * shape1dy(J[n]) * shape1dz(K[n]); } @@ -4750,7 +4750,7 @@ void LagrangeHexFiniteElement::CalcDShape(const IntegrationPoint &ip, fe1d -> CalcDShape(ipy, dshape1dy); fe1d -> CalcDShape(ipz, dshape1dz); - for (int n = 0; n < Dof; n++) + for (int n = 0; n < dof; n++) { dshape(n,0) = dshape1dx(I[n],0) * shape1dy(J[n]) * shape1dz(K[n]); dshape(n,1) = shape1dx(I[n]) * dshape1dy(J[n],0) * shape1dz(K[n]); @@ -5849,7 +5849,7 @@ void Nedelec1HexFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif #ifdef MFEM_DEBUG @@ -6015,7 +6015,7 @@ void Nedelec1TetFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); + DenseMatrix vshape(dof, dim); #endif #ifdef MFEM_DEBUG @@ -6163,8 +6163,8 @@ void RT0HexFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -6220,7 +6220,7 @@ void RT0HexFiniteElement::Project ( double vk[3]; Vector xk (vk, 3); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 6; k++) @@ -6552,8 +6552,8 @@ void RT1HexFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -6609,7 +6609,7 @@ void RT1HexFiniteElement::Project ( double vk[3]; Vector xk (vk, 3); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 36; k++) @@ -6687,8 +6687,8 @@ void RT0TetFiniteElement::GetLocalInterpolation ( { int k, j; #ifdef MFEM_THREAD_SAFE - DenseMatrix vshape(Dof, Dim); - DenseMatrix Jinv(Dim); + DenseMatrix vshape(dof, dim); + DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG @@ -6744,7 +6744,7 @@ void RT0TetFiniteElement::Project ( double vk[3]; Vector xk (vk, 3); #ifdef MFEM_THREAD_SAFE - DenseMatrix Jinv(Dim); + DenseMatrix Jinv(dim); #endif for (int k = 0; k < 4; k++) @@ -7602,7 +7602,7 @@ H1_SegmentElement::H1_SegmentElement(const int p, const int btype) void H1_SegmentElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1); @@ -7621,7 +7621,7 @@ void H1_SegmentElement::CalcShape(const IntegrationPoint &ip, void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), dshape_x(p+1); @@ -7639,7 +7639,7 @@ void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip, void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const { - const int p = Order; + const int p = order; const double *cp = poly1d.ClosedPoints(p, b_type); switch (vertex) @@ -7692,7 +7692,7 @@ H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype) void H1_QuadrilateralElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1); @@ -7711,7 +7711,7 @@ void H1_QuadrilateralElement::CalcShape(const IntegrationPoint &ip, void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1); @@ -7732,7 +7732,7 @@ void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip, void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const { - const int p = Order; + const int p = order; const double *cp = poly1d.ClosedPoints(p, b_type); #ifdef MFEM_THREAD_SAFE @@ -7807,7 +7807,7 @@ H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype) void H1_HexahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); @@ -7828,7 +7828,7 @@ void H1_HexahedronElement::CalcShape(const IntegrationPoint &ip, void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); @@ -7851,7 +7851,7 @@ void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip, void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const { - const int p = Order; + const int p = order; const double *cp = poly1d.ClosedPoints(p,b_type); #ifdef MFEM_THREAD_SAFE @@ -7955,7 +7955,7 @@ H1Pos_SegmentElement::H1Pos_SegmentElement(const int p) void H1Pos_SegmentElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1); @@ -7975,7 +7975,7 @@ void H1Pos_SegmentElement::CalcShape(const IntegrationPoint &ip, void H1Pos_SegmentElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), dshape_x(p+1); @@ -8022,7 +8022,7 @@ H1Pos_QuadrilateralElement::H1Pos_QuadrilateralElement(const int p) void H1Pos_QuadrilateralElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1); @@ -8042,7 +8042,7 @@ void H1Pos_QuadrilateralElement::CalcShape(const IntegrationPoint &ip, void H1Pos_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1); @@ -8092,7 +8092,7 @@ H1Pos_HexahedronElement::H1Pos_HexahedronElement(const int p) void H1Pos_HexahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); @@ -8113,7 +8113,7 @@ void H1Pos_HexahedronElement::CalcShape(const IntegrationPoint &ip, void H1Pos_HexahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); @@ -8157,9 +8157,9 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype) ddshape_x.SetSize(p + 1); ddshape_y.SetSize(p + 1); ddshape_l.SetSize(p + 1); - u.SetSize(Dof); - du.SetSize(Dof, Dim); - ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2 ); + u.SetSize(dof); + du.SetSize(dof, dim); + ddu.SetSize(dof, (dim * (dim + 1)) / 2 ); #else Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); #endif @@ -8192,8 +8192,8 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype) Nodes.IntPoint(o++).Set2(cp[i]/w, cp[j]/w); } - DenseMatrix T(Dof); - for (int k = 0; k < Dof; k++) + DenseMatrix T(dof); + for (int k = 0; k < dof; k++) { IntegrationPoint &ip = Nodes.IntPoint(k); poly1d.CalcBasis(p, ip.x, shape_x); @@ -8215,10 +8215,10 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype) void H1_TriangleElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE - Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1), u(Dof); + Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1), u(dof); #endif poly1d.CalcBasis(p, ip.x, shape_x); @@ -8237,12 +8237,12 @@ void H1_TriangleElement::CalcShape(const IntegrationPoint &ip, void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1); - DenseMatrix du(Dof, Dim); + DenseMatrix du(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x); @@ -8266,12 +8266,12 @@ void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip, void H1_TriangleElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &ddshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1); Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_l(p + 1); - DenseMatrix ddu(Dof, Dim); + DenseMatrix ddu(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x); @@ -8315,9 +8315,9 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) ddshape_y.SetSize(p + 1); ddshape_z.SetSize(p + 1); ddshape_l.SetSize(p + 1); - u.SetSize(Dof); - du.SetSize(Dof, Dim); - ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2); + u.SetSize(dof); + du.SetSize(dof, dim); + ddu.SetSize(dof, (dim * (dim + 1)) / 2); #else Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); #endif @@ -8390,8 +8390,8 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) Nodes.IntPoint(o++).Set3(cp[i]/w, cp[j]/w, cp[k]/w); } - DenseMatrix T(Dof); - for (int m = 0; m < Dof; m++) + DenseMatrix T(dof); + for (int m = 0; m < dof; m++) { IntegrationPoint &ip = Nodes.IntPoint(m); poly1d.CalcBasis(p, ip.x, shape_x); @@ -8415,11 +8415,11 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) void H1_TetrahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); - Vector u(Dof); + Vector u(dof); #endif poly1d.CalcBasis(p, ip.x, shape_x); @@ -8440,12 +8440,12 @@ void H1_TetrahedronElement::CalcShape(const IntegrationPoint &ip, void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1); - DenseMatrix du(Dof, Dim); + DenseMatrix du(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x); @@ -8473,13 +8473,13 @@ void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip, void H1_TetrahedronElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &ddshape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1); Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_l(p + 1); - DenseMatrix ddu(Dof, ((Dim + 1) * Dim) / 2); + DenseMatrix ddu(dof, ((dim + 1) * dim) / 2); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x); @@ -8521,11 +8521,11 @@ H1Pos_TriangleElement::H1Pos_TriangleElement(const int p) FunctionSpace::Pk) { #ifndef MFEM_THREAD_SAFE - m_shape.SetSize(Dof); + m_shape.SetSize(dof); dshape_1d.SetSize(p + 1); - m_dshape.SetSize(Dof, Dim); + m_dshape.SetSize(dof, dim); #endif - dof_map.SetSize(Dof); + dof_map.SetSize(dof); struct Index { @@ -8634,10 +8634,10 @@ void H1Pos_TriangleElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { #ifdef MFEM_THREAD_SAFE - Vector m_shape(Dof); + Vector m_shape(dof); #endif - CalcShape(Order, ip.x, ip.y, m_shape.GetData()); - for (int i = 0; i < Dof; i++) + CalcShape(order, ip.x, ip.y, m_shape.GetData()); + for (int i = 0; i < dof; i++) { shape(dof_map[i]) = m_shape(i); } @@ -8647,13 +8647,13 @@ void H1Pos_TriangleElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { #ifdef MFEM_THREAD_SAFE - Vector dshape_1d(Order + 1); - DenseMatrix m_dshape(Dof, Dim); + Vector dshape_1d(order + 1); + DenseMatrix m_dshape(dof, dim); #endif - CalcDShape(Order, ip.x, ip.y, dshape_1d.GetData(), m_dshape.Data()); + CalcDShape(order, ip.x, ip.y, dshape_1d.GetData(), m_dshape.Data()); for (int d = 0; d < 2; d++) { - for (int i = 0; i < Dof; i++) + for (int i = 0; i < dof; i++) { dshape(dof_map[i],d) = m_dshape(i,d); } @@ -8666,11 +8666,11 @@ H1Pos_TetrahedronElement::H1Pos_TetrahedronElement(const int p) ((p + 1)*(p + 2)*(p + 3))/6, p, FunctionSpace::Pk) { #ifndef MFEM_THREAD_SAFE - m_shape.SetSize(Dof); + m_shape.SetSize(dof); dshape_1d.SetSize(p + 1); - m_dshape.SetSize(Dof, Dim); + m_dshape.SetSize(dof, dim); #endif - dof_map.SetSize(Dof); + dof_map.SetSize(dof); struct Index { @@ -8886,10 +8886,10 @@ void H1Pos_TetrahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { #ifdef MFEM_THREAD_SAFE - Vector m_shape(Dof); + Vector m_shape(dof); #endif - CalcShape(Order, ip.x, ip.y, ip.z, m_shape.GetData()); - for (int i = 0; i < Dof; i++) + CalcShape(order, ip.x, ip.y, ip.z, m_shape.GetData()); + for (int i = 0; i < dof; i++) { shape(dof_map[i]) = m_shape(i); } @@ -8899,13 +8899,13 @@ void H1Pos_TetrahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { #ifdef MFEM_THREAD_SAFE - Vector dshape_1d(Order + 1); - DenseMatrix m_dshape(Dof, Dim); + Vector dshape_1d(order + 1); + DenseMatrix m_dshape(dof, dim); #endif - CalcDShape(Order, ip.x, ip.y, ip.z, dshape_1d.GetData(), m_dshape.Data()); + CalcDShape(order, ip.x, ip.y, ip.z, dshape_1d.GetData(), m_dshape.Data()); for (int d = 0; d < 3; d++) { - for (int i = 0; i < Dof; i++) + for (int i = 0; i < dof; i++) { dshape(dof_map[i],d) = m_dshape(i,d); } @@ -8927,8 +8927,8 @@ H1_WedgeElement::H1_WedgeElement(const int p, s_dshape.SetSize(SegmentFE.GetDof(), 1); #endif - t_dof.SetSize(Dof); - s_dof.SetSize(Dof); + t_dof.SetSize(dof); + s_dof.SetSize(dof); // Nodal DoFs t_dof[0] = 0; s_dof[0] = 0; @@ -9005,7 +9005,7 @@ H1_WedgeElement::H1_WedgeElement(const int p, // Define Nodes const IntegrationRule & t_Nodes = TriangleFE.GetNodes(); const IntegrationRule & s_Nodes = SegmentFE.GetNodes(); - for (int i=0; i 0) ? poly1d.OpenPoints(p - 1) : NULL; const double *bop = poly1d.OpenPoints(p); @@ -10823,8 +10823,8 @@ RT_TriangleElement::RT_TriangleElement(const int p) dshape_x.SetSize(p + 1); dshape_y.SetSize(p + 1); dshape_l.SetSize(p + 1); - u.SetSize(Dof, Dim); - divu.SetSize(Dof); + u.SetSize(dof, dim); + divu.SetSize(dof); #else Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); #endif @@ -10858,8 +10858,8 @@ RT_TriangleElement::RT_TriangleElement(const int p) dof2nk[o++] = 2; } - DenseMatrix T(Dof); - for (int k = 0; k < Dof; k++) + DenseMatrix T(dof); + for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); poly1d.CalcBasis(p, ip.x, shape_x); @@ -10889,11 +10889,11 @@ RT_TriangleElement::RT_TriangleElement(const int p) void RT_TriangleElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - const int p = Order - 1; + const int p = order - 1; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); - DenseMatrix u(Dof, Dim); + DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x); @@ -10922,12 +10922,12 @@ void RT_TriangleElement::CalcVShape(const IntegrationPoint &ip, void RT_TriangleElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { - const int p = Order - 1; + const int p = order - 1; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1); - Vector divu(Dof); + Vector divu(dof); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x); @@ -10964,7 +10964,7 @@ const double RT_TetrahedronElement::c = 1./4.; RT_TetrahedronElement::RT_TetrahedronElement(const int p) : VectorFiniteElement(3, Geometry::TETRAHEDRON, (p + 1)*(p + 2)*(p + 4)/2, p + 1, H_DIV, FunctionSpace::Pk), - dof2nk(Dof) + dof2nk(dof) { const double *iop = (p > 0) ? poly1d.OpenPoints(p - 1) : NULL; const double *bop = poly1d.OpenPoints(p); @@ -10978,8 +10978,8 @@ RT_TetrahedronElement::RT_TetrahedronElement(const int p) dshape_y.SetSize(p + 1); dshape_z.SetSize(p + 1); dshape_l.SetSize(p + 1); - u.SetSize(Dof, Dim); - divu.SetSize(Dof); + u.SetSize(dof, dim); + divu.SetSize(dof); #else Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); #endif @@ -11030,8 +11030,8 @@ RT_TetrahedronElement::RT_TetrahedronElement(const int p) dof2nk[o++] = 3; } - DenseMatrix T(Dof); - for (int m = 0; m < Dof; m++) + DenseMatrix T(dof); + for (int m = 0; m < dof; m++) { const IntegrationPoint &ip = Nodes.IntPoint(m); poly1d.CalcBasis(p, ip.x, shape_x); @@ -11066,11 +11066,11 @@ RT_TetrahedronElement::RT_TetrahedronElement(const int p) void RT_TetrahedronElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - const int p = Order - 1; + const int p = order - 1; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); - DenseMatrix u(Dof, Dim); + DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x); @@ -11102,12 +11102,12 @@ void RT_TetrahedronElement::CalcVShape(const IntegrationPoint &ip, void RT_TetrahedronElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { - const int p = Order - 1; + const int p = order - 1; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1); - Vector divu(Dof); + Vector divu(dof); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x); @@ -11149,13 +11149,13 @@ ND_HexahedronElement::ND_HexahedronElement(const int p, const int cb_type, const int ob_type) : VectorTensorFiniteElement(3, 3*p*(p + 1)*(p + 1), p, cb_type, ob_type, H_CURL, DofMapType::L2_DOF_MAP), - dof2tk(Dof) + dof2tk(dof) { - dof_map.SetSize(Dof); + dof_map.SetSize(dof); const double *cp = poly1d.ClosedPoints(p, cb_type); const double *op = poly1d.OpenPoints(p - 1, ob_type); - const int dof3 = Dof/3; + const int dof3 = dof/3; #ifndef MFEM_THREAD_SAFE shape_cx.SetSize(p + 1); @@ -11366,7 +11366,7 @@ ND_HexahedronElement::ND_HexahedronElement(const int p, void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); @@ -11440,7 +11440,7 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip, void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); @@ -11545,8 +11545,8 @@ const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad( } DofToQuad *d2q = new DofToQuad; - const int ndof = closed ? Order + 1 : Order; - const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/Dim) + 0.5); + const int ndof = closed ? order + 1 : order; + const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5); d2q->FE = this; d2q->IntRule = &ir; d2q->mode = mode; @@ -11598,13 +11598,13 @@ ND_QuadrilateralElement::ND_QuadrilateralElement(const int p, const int ob_type) : VectorTensorFiniteElement(2, 2*p*(p + 1), p, cb_type, ob_type, H_CURL, DofMapType::L2_DOF_MAP), - dof2tk(Dof) + dof2tk(dof) { - dof_map.SetSize(Dof); + dof_map.SetSize(dof); const double *cp = poly1d.ClosedPoints(p, cb_type); const double *op = poly1d.OpenPoints(p - 1, ob_type); - const int dof2 = Dof/2; + const int dof2 = dof/2; #ifndef MFEM_THREAD_SAFE shape_cx.SetSize(p + 1); @@ -11685,7 +11685,7 @@ ND_QuadrilateralElement::ND_QuadrilateralElement(const int p, void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); @@ -11734,7 +11734,7 @@ void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip, void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { - const int p = Order; + const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); @@ -11787,7 +11787,7 @@ const double ND_TetrahedronElement::c = 1./4.; ND_TetrahedronElement::ND_TetrahedronElement(const int p) : VectorFiniteElement(3, Geometry::TETRAHEDRON, p*(p + 2)*(p + 3)/2, p, - H_CURL, FunctionSpace::Pk), dof2tk(Dof) + H_CURL, FunctionSpace::Pk), dof2tk(dof) { const double *eop = poly1d.OpenPoints(p - 1); const double *fop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL; @@ -11804,7 +11804,7 @@ ND_TetrahedronElement::ND_TetrahedronElement(const int p) dshape_y.SetSize(p); dshape_z.SetSize(p); dshape_l.SetSize(p); - u.SetSize(Dof, Dim); + u.SetSize(dof, dim); #else Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p); #endif @@ -11894,8 +11894,8 @@ ND_TetrahedronElement::ND_TetrahedronElement(const int p) dof2tk[o++] = 2; } - DenseMatrix T(Dof); - for (int m = 0; m < Dof; m++) + DenseMatrix T(dof); + for (int m = 0; m < dof; m++) { const IntegrationPoint &ip = Nodes.IntPoint(m); const double *tm = tk + 3*dof2tk[m]; @@ -11936,12 +11936,12 @@ ND_TetrahedronElement::ND_TetrahedronElement(const int p) void ND_TetrahedronElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - const int pm1 = Order - 1; + const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE - const int p = Order; + const int p = order; Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p); - DenseMatrix u(Dof, Dim); + DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(pm1, ip.x, shape_x); @@ -11978,13 +11978,13 @@ void ND_TetrahedronElement::CalcVShape(const IntegrationPoint &ip, void ND_TetrahedronElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { - const int pm1 = Order - 1; + const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE - const int p = Order; + const int p = order; Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p); Vector dshape_x(p), dshape_y(p), dshape_z(p), dshape_l(p); - DenseMatrix u(Dof, Dim); + DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(pm1, ip.x, shape_x, dshape_x); @@ -12050,7 +12050,7 @@ const double ND_TriangleElement::c = 1./3.; ND_TriangleElement::ND_TriangleElement(const int p) : VectorFiniteElement(2, Geometry::TRIANGLE, p*(p + 2), p, H_CURL, FunctionSpace::Pk), - dof2tk(Dof) + dof2tk(dof) { const double *eop = poly1d.OpenPoints(p - 1); const double *iop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL; @@ -12064,8 +12064,8 @@ ND_TriangleElement::ND_TriangleElement(const int p) dshape_x.SetSize(p); dshape_y.SetSize(p); dshape_l.SetSize(p); - u.SetSize(Dof, Dim); - curlu.SetSize(Dof); + u.SetSize(dof, dim); + curlu.SetSize(dof); #else Vector shape_x(p), shape_y(p), shape_l(p); #endif @@ -12099,8 +12099,8 @@ ND_TriangleElement::ND_TriangleElement(const int p) dof2tk[n++] = 3; } - DenseMatrix T(Dof); - for (int m = 0; m < Dof; m++) + DenseMatrix T(dof); + for (int m = 0; m < dof; m++) { const IntegrationPoint &ip = Nodes.IntPoint(m); const double *tm = tk + 2*dof2tk[m]; @@ -12131,12 +12131,12 @@ ND_TriangleElement::ND_TriangleElement(const int p) void ND_TriangleElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - const int pm1 = Order - 1; + const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE - const int p = Order; + const int p = order; Vector shape_x(p), shape_y(p), shape_l(p); - DenseMatrix u(Dof, Dim); + DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(pm1, ip.x, shape_x); @@ -12165,13 +12165,13 @@ void ND_TriangleElement::CalcVShape(const IntegrationPoint &ip, void ND_TriangleElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { - const int pm1 = Order - 1; + const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE - const int p = Order; + const int p = order; Vector shape_x(p), shape_y(p), shape_l(p); Vector dshape_x(p), dshape_y(p), dshape_l(p); - Vector curlu(Dof); + Vector curlu(dof); #endif poly1d.CalcBasis(pm1, ip.x, shape_x, dshape_x); @@ -12200,7 +12200,7 @@ void ND_TriangleElement::CalcCurlShape(const IntegrationPoint &ip, (dshape_y(j)*(ip.y - c) + shape_y(j)) * shape_x(i)); } - Vector curl2d(curl_shape.Data(),Dof); + Vector curl2d(curl_shape.Data(),dof); Ti.Mult(curlu, curl2d); } @@ -12211,7 +12211,7 @@ ND_SegmentElement::ND_SegmentElement(const int p, const int ob_type) : VectorFiniteElement(1, Geometry::SEGMENT, p, p - 1, H_CURL, FunctionSpace::Pk), obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type))), - dof2tk(Dof) + dof2tk(dof) { const double *op = poly1d.OpenPoints(p - 1, ob_type); @@ -12226,18 +12226,18 @@ ND_SegmentElement::ND_SegmentElement(const int p, const int ob_type) void ND_SegmentElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { - Vector vshape(shape.Data(), Dof); + Vector vshape(shape.Data(), dof); obasis1d.Eval(ip.x, vshape); } void NURBS1DFiniteElement::SetOrder() const { - Order = kv[0]->GetOrder(); - Dof = Order + 1; + order = kv[0]->GetOrder(); + dof = order + 1; - weights.SetSize(Dof); - shape_x.SetSize(Dof); + weights.SetSize(dof); + shape_x.SetSize(dof); } void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip, @@ -12246,7 +12246,7 @@ void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip, kv[0]->CalcShape(shape, ijk[0], ip.x); double sum = 0.0; - for (int i = 0; i <= Order; i++) + for (int i = 0; i <= order; i++) { sum += (shape(i) *= weights(i)); } @@ -12257,13 +12257,13 @@ void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip, void NURBS1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { - Vector grad(dshape.Data(), Dof); + Vector grad(dshape.Data(), dof); kv[0]->CalcShape (shape_x, ijk[0], ip.x); kv[0]->CalcDShape(grad, ijk[0], ip.x); double sum = 0.0, dsum = 0.0; - for (int i = 0; i <= Order; i++) + for (int i = 0; i <= order; i++) { sum += (shape_x(i) *= weights(i)); dsum += ( grad(i) *= weights(i)); @@ -12276,15 +12276,15 @@ void NURBS1DFiniteElement::CalcDShape(const IntegrationPoint &ip, void NURBS1DFiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &hessian) const { - Vector grad(Dof); - Vector hess(hessian.Data(), Dof); + Vector grad(dof); + Vector hess(hessian.Data(), dof); kv[0]->CalcShape (shape_x, ijk[0], ip.x); kv[0]->CalcDShape(grad, ijk[0], ip.x); kv[0]->CalcD2Shape(hess, ijk[0], ip.x); double sum = 0.0, dsum = 0.0, d2sum = 0.0; - for (int i = 0; i <= Order; i++) + for (int i = 0; i <= order; i++) { sum += (shape_x(i) *= weights(i)); dsum += ( grad(i) *= weights(i)); @@ -12299,20 +12299,20 @@ void NURBS1DFiniteElement::CalcHessian (const IntegrationPoint &ip, void NURBS2DFiniteElement::SetOrder() const { - Orders[0] = kv[0]->GetOrder(); - Orders[1] = kv[1]->GetOrder(); - shape_x.SetSize(Orders[0]+1); - shape_y.SetSize(Orders[1]+1); - dshape_x.SetSize(Orders[0]+1); - dshape_y.SetSize(Orders[1]+1); - d2shape_x.SetSize(Orders[0]+1); - d2shape_y.SetSize(Orders[1]+1); + orders[0] = kv[0]->GetOrder(); + orders[1] = kv[1]->GetOrder(); + shape_x.SetSize(orders[0]+1); + shape_y.SetSize(orders[1]+1); + dshape_x.SetSize(orders[0]+1); + dshape_y.SetSize(orders[1]+1); + d2shape_x.SetSize(orders[0]+1); + d2shape_y.SetSize(orders[1]+1); - Order = max(Orders[0], Orders[1]); - Dof = (Orders[0] + 1)*(Orders[1] + 1); - u.SetSize(Dof); - du.SetSize(Dof); - weights.SetSize(Dof); + order = max(orders[0], orders[1]); + dof = (orders[0] + 1)*(orders[1] + 1); + u.SetSize(dof); + du.SetSize(dof); + weights.SetSize(dof); } void NURBS2DFiniteElement::CalcShape(const IntegrationPoint &ip, @@ -12322,10 +12322,10 @@ void NURBS2DFiniteElement::CalcShape(const IntegrationPoint &ip, kv[1]->CalcShape(shape_y, ijk[1], ip.y); double sum = 0.0; - for (int o = 0, j = 0; j <= Orders[1]; j++) + for (int o = 0, j = 0; j <= orders[1]; j++) { const double sy = shape_y(j); - for (int i = 0; i <= Orders[0]; i++, o++) + for (int i = 0; i <= orders[0]; i++, o++) { sum += ( shape(o) = shape_x(i)*sy*weights(o) ); } @@ -12346,10 +12346,10 @@ void NURBS2DFiniteElement::CalcDShape(const IntegrationPoint &ip, kv[1]->CalcDShape(dshape_y, ijk[1], ip.y); sum = dsum[0] = dsum[1] = 0.0; - for (int o = 0, j = 0; j <= Orders[1]; j++) + for (int o = 0, j = 0; j <= orders[1]; j++) { const double sy = shape_y(j), dsy = dshape_y(j); - for (int i = 0; i <= Orders[0]; i++, o++) + for (int i = 0; i <= orders[0]; i++, o++) { sum += ( u(o) = shape_x(i)*sy*weights(o) ); @@ -12362,7 +12362,7 @@ void NURBS2DFiniteElement::CalcDShape(const IntegrationPoint &ip, dsum[0] *= sum*sum; dsum[1] *= sum*sum; - for (int o = 0; o < Dof; o++) + for (int o = 0; o < dof; o++) { dshape(o,0) = dshape(o,0)*sum - u(o)*dsum[0]; dshape(o,1) = dshape(o,1)*sum - u(o)*dsum[1]; @@ -12385,10 +12385,10 @@ void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip, sum = dsum[0] = dsum[1] = 0.0; d2sum[0] = d2sum[1] = d2sum[2] = 0.0; - for (int o = 0, j = 0; j <= Orders[1]; j++) + for (int o = 0, j = 0; j <= orders[1]; j++) { const double sy = shape_y(j), dsy = dshape_y(j), d2sy = d2shape_y(j); - for (int i = 0; i <= Orders[0]; i++, o++) + for (int i = 0; i <= orders[0]; i++, o++) { const double sx = shape_x(i), dsx = dshape_x(i), d2sx = d2shape_x(i); sum += ( u(o) = sx*sy*weights(o) ); @@ -12410,7 +12410,7 @@ void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip, d2sum[1] *= sum; d2sum[2] *= sum; - for (int o = 0; o < Dof; o++) + for (int o = 0; o < dof; o++) { hessian(o,0) = hessian(o,0)*sum - 2*du(o,0)*sum*dsum[0] @@ -12430,26 +12430,26 @@ void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip, void NURBS3DFiniteElement::SetOrder() const { - Orders[0] = kv[0]->GetOrder(); - Orders[1] = kv[1]->GetOrder(); - Orders[2] = kv[2]->GetOrder(); - shape_x.SetSize(Orders[0]+1); - shape_y.SetSize(Orders[1]+1); - shape_z.SetSize(Orders[2]+1); + orders[0] = kv[0]->GetOrder(); + orders[1] = kv[1]->GetOrder(); + orders[2] = kv[2]->GetOrder(); + shape_x.SetSize(orders[0]+1); + shape_y.SetSize(orders[1]+1); + shape_z.SetSize(orders[2]+1); - dshape_x.SetSize(Orders[0]+1); - dshape_y.SetSize(Orders[1]+1); - dshape_z.SetSize(Orders[2]+1); + dshape_x.SetSize(orders[0]+1); + dshape_y.SetSize(orders[1]+1); + dshape_z.SetSize(orders[2]+1); - d2shape_x.SetSize(Orders[0]+1); - d2shape_y.SetSize(Orders[1]+1); - d2shape_z.SetSize(Orders[2]+1); + d2shape_x.SetSize(orders[0]+1); + d2shape_y.SetSize(orders[1]+1); + d2shape_z.SetSize(orders[2]+1); - Order = max(max(Orders[0], Orders[1]), Orders[2]); - Dof = (Orders[0] + 1)*(Orders[1] + 1)*(Orders[2] + 1); - u.SetSize(Dof); - du.SetSize(Dof); - weights.SetSize(Dof); + order = max(max(orders[0], orders[1]), orders[2]); + dof = (orders[0] + 1)*(orders[1] + 1)*(orders[2] + 1); + u.SetSize(dof); + du.SetSize(dof); + weights.SetSize(dof); } void NURBS3DFiniteElement::CalcShape(const IntegrationPoint &ip, @@ -12460,13 +12460,13 @@ void NURBS3DFiniteElement::CalcShape(const IntegrationPoint &ip, kv[2]->CalcShape(shape_z, ijk[2], ip.z); double sum = 0.0; - for (int o = 0, k = 0; k <= Orders[2]; k++) + for (int o = 0, k = 0; k <= orders[2]; k++) { const double sz = shape_z(k); - for (int j = 0; j <= Orders[1]; j++) + for (int j = 0; j <= orders[1]; j++) { const double sy_sz = shape_y(j)*sz; - for (int i = 0; i <= Orders[0]; i++, o++) + for (int i = 0; i <= orders[0]; i++, o++) { sum += ( shape(o) = shape_x(i)*sy_sz*weights(o) ); } @@ -12490,15 +12490,15 @@ void NURBS3DFiniteElement::CalcDShape(const IntegrationPoint &ip, kv[2]->CalcDShape(dshape_z, ijk[2], ip.z); sum = dsum[0] = dsum[1] = dsum[2] = 0.0; - for (int o = 0, k = 0; k <= Orders[2]; k++) + for (int o = 0, k = 0; k <= orders[2]; k++) { const double sz = shape_z(k), dsz = dshape_z(k); - for (int j = 0; j <= Orders[1]; j++) + for (int j = 0; j <= orders[1]; j++) { const double sy_sz = shape_y(j)* sz; const double dsy_sz = dshape_y(j)* sz; const double sy_dsz = shape_y(j)*dsz; - for (int i = 0; i <= Orders[0]; i++, o++) + for (int i = 0; i <= orders[0]; i++, o++) { sum += ( u(o) = shape_x(i)*sy_sz*weights(o) ); @@ -12514,7 +12514,7 @@ void NURBS3DFiniteElement::CalcDShape(const IntegrationPoint &ip, dsum[1] *= sum*sum; dsum[2] *= sum*sum; - for (int o = 0; o < Dof; o++) + for (int o = 0; o < dof; o++) { dshape(o,0) = dshape(o,0)*sum - u(o)*dsum[0]; dshape(o,1) = dshape(o,1)*sum - u(o)*dsum[1]; @@ -12542,13 +12542,13 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip, sum = dsum[0] = dsum[1] = dsum[2] = 0.0; d2sum[0] = d2sum[1] = d2sum[2] = d2sum[3] = d2sum[4] = d2sum[5] = 0.0; - for (int o = 0, k = 0; k <= Orders[2]; k++) + for (int o = 0, k = 0; k <= orders[2]; k++) { const double sz = shape_z(k), dsz = dshape_z(k), d2sz = d2shape_z(k); - for (int j = 0; j <= Orders[1]; j++) + for (int j = 0; j <= orders[1]; j++) { const double sy = shape_y(j), dsy = dshape_y(j), d2sy = d2shape_y(j); - for (int i = 0; i <= Orders[0]; i++, o++) + for (int i = 0; i <= orders[0]; i++, o++) { const double sx = shape_x(i), dsx = dshape_x(i), d2sx = d2shape_x(i); sum += ( u(o) = sx*sy*sz*weights(o) ); @@ -12582,7 +12582,7 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip, d2sum[4] *= sum; d2sum[5] *= sum; - for (int o = 0; o < Dof; o++) + for (int o = 0; o < dof; o++) { hessian(o,0) = hessian(o,0)*sum - 2*du(o,0)*sum*dsum[0] diff --git a/fem/fe.hpp b/fem/fe.hpp index 8560503c48..87f7ee0bc2 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -232,14 +232,14 @@ class KnotVector; class FiniteElement { protected: - int Dim; ///< Dimension of reference space - Geometry::Type GeomType; ///< Geometry::Type of the reference element - int FuncSpace, RangeType, MapType, - DerivType, DerivRangeType, DerivMapType; + int dim; ///< Dimension of reference space + Geometry::Type geom_type; ///< Geometry::Type of the reference element + int func_space, range_type, map_type, + deriv_type, deriv_range_type, deriv_map_type; mutable - int Dof, ///< Number of degrees of freedom - Order; ///< Order/degree of the shape functions - mutable int Orders[Geometry::MaxDim]; ///< Anisotropic orders + int dof, ///< Number of degrees of freedom + order; ///< Order/degree of the shape functions + mutable int orders[Geometry::MaxDim]; ///< Anisotropic orders IntegrationRule Nodes; #ifndef MFEM_THREAD_SAFE mutable DenseMatrix vshape; // Dof x Dim @@ -250,8 +250,8 @@ protected: mutable Array dof2quad_array; public: - /// Enumeration for RangeType and DerivRangeType - enum RangeT { SCALAR, VECTOR }; + /// Enumeration for range_type and deriv_range_type + enum RangeType { SCALAR, VECTOR }; /** @brief Enumeration for MapType: defines how reference functions are mapped to physical space. @@ -263,7 +263,7 @@ public: - \f$ w = w(\hat x) = det(J) \f$ is the transformation weight factor for square J - \f$ w = w(\hat x) = det(J^t J)^{1/2} \f$ is the transformation weight factor in general */ - enum MapT + enum MapType { VALUE, /**< For scalar fields; preserves point values \f$ u(x) = \hat u(\hat x) \f$ */ @@ -284,7 +284,7 @@ public: value returned by GetDerivType() indicates which derivative method is implemented. */ - enum DerivT + enum DerivType { NONE, ///< No derivatives implemented GRAD, ///< Implements CalcDShape methods @@ -303,66 +303,66 @@ public: int F = FunctionSpace::Pk); /// Returns the reference space dimension for the finite element - int GetDim() const { return Dim; } + int GetDim() const { return dim; } /// Returns the Geometry::Type of the reference element - Geometry::Type GetGeomType() const { return GeomType; } + Geometry::Type GetGeomType() const { return geom_type; } /// Returns the number of degrees of freedom in the finite element - int GetDof() const { return Dof; } + int GetDof() const { return dof; } /** @brief Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order. */ - int GetOrder() const { return Order; } + int GetOrder() const { return order; } /** @brief Returns true if the FiniteElement basis *may be using* different orders/degrees in different spatial directions. */ - bool HasAnisotropicOrders() const { return Orders[0] != -1; } + bool HasAnisotropicOrders() const { return orders[0] != -1; } /// Returns an array containing the anisotropic orders/degrees. - const int *GetAnisotropicOrders() const { return Orders; } + const int *GetAnisotropicOrders() const { return orders; } /// Returns the type of FunctionSpace on the element. - int Space() const { return FuncSpace; } + int Space() const { return func_space; } - /// Returns the FiniteElement::RangeT of the element, one of {SCALAR, VECTOR}. - int GetRangeType() const { return RangeType; } + /// Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}. + int GetRangeType() const { return range_type; } - /** @brief Returns the FiniteElement::RangeT of the element derivative, either + /** @brief Returns the FiniteElement::RangeType of the element derivative, either SCALAR or VECTOR. */ - int GetDerivRangeType() const { return DerivRangeType; } + int GetDerivRangeType() const { return deriv_range_type; } - /** @brief Returns the FiniteElement::MapT of the element describing how reference + /** @brief Returns the FiniteElement::MapType of the element describing how reference functions are mapped to physical space, one of {VALUE, INTEGRAL H_DIV, H_CURL}. */ - int GetMapType() const { return MapType; } + int GetMapType() const { return map_type; } - /** @brief Returns the FiniteElement::DerivT of the element describing the + /** @brief Returns the FiniteElement::DerivType of the element describing the spatial derivative method implemented, one of {NONE, GRAD, DIV, CURL}. */ - int GetDerivType() const { return DerivType; } + int GetDerivType() const { return deriv_type; } - /** @brief Returns the FiniteElement::DerivT of the element describing how + /** @brief Returns the FiniteElement::DerivType of the element describing how reference function derivatives are mapped to physical space, one of {VALUE, INTEGRAL, H_DIV, H_CURL}. */ - int GetDerivMapType() const { return DerivMapType; } + int GetDerivMapType() const { return deriv_map_type; } /** @brief Evaluate the values of all shape functions of a scalar finite element in reference space at the given point @a ip. */ - /** The size (#Dof) of the result Vector @a shape must be set in advance. */ + /** The size (#dof) of the result Vector @a shape must be set in advance. */ virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const = 0; /** @brief Evaluate the values of all shape functions of a scalar finite element in physical space at the point described by @a Trans. */ - /** The size (#Dof) of the result Vector @a shape must be set in advance. */ + /** The size (#dof) of the result Vector @a shape must be set in advance. */ void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const; /** @brief Evaluate the gradients of all shape functions of a scalar finite element in reference space at the given point @a ip. */ /** Each row of the result DenseMatrix @a dshape contains the derivatives of - one shape function. The size (#Dof x #Dim) of @a dshape must be set in + one shape function. The size (#dof x #dim) of @a dshape must be set in advance. */ virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const = 0; @@ -370,8 +370,8 @@ public: /** @brief Evaluate the gradients of all shape functions of a scalar finite element in physical space at the point described by @a Trans. */ /** Each row of the result DenseMatrix @a dshape contains the derivatives of - one shape function. The size (#Dof x SDim) of @a dshape must be set in - advance, where SDim >= #Dim is the physical space dimension as described + one shape function. The size (#dof x SDim) of @a dshape must be set in + advance, where SDim >= #dim is the physical space dimension as described by @a Trans. */ void CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const; @@ -383,7 +383,7 @@ public: /** @brief Evaluate the values of all shape functions of a *vector* finite element in reference space at the given point @a ip. */ /** Each row of the result DenseMatrix @a shape contains the components of - one vector shape function. The size (#Dof x #Dim) of @a shape must be set + one vector shape function. The size (#dof x #dim) of @a shape must be set in advance. */ virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -391,8 +391,8 @@ public: /** @brief Evaluate the values of all shape functions of a *vector* finite element in physical space at the point described by @a Trans. */ /** Each row of the result DenseMatrix @a shape contains the components of - one vector shape function. The size (#Dof x SDim) of @a shape must be set - in advance, where SDim >= #Dim is the physical space dimension as + one vector shape function. The size (#dof x SDim) of @a shape must be set + in advance, where SDim >= #dim is the physical space dimension as described by @a Trans. */ virtual void CalcVShape(ElementTransformation &Trans, DenseMatrix &shape) const; @@ -403,32 +403,32 @@ public: /** @brief Evaluate the divergence of all shape functions of a *vector* finite element in reference space at the given point @a ip. */ - /** The size (#Dof) of the result Vector @a divshape must be set in advance. + /** The size (#dof) of the result Vector @a divshape must be set in advance. */ virtual void CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const; /** @brief Evaluate the divergence of all shape functions of a *vector* finite element in physical space at the point described by @a Trans. */ - /** The size (#Dof) of the result Vector @a divshape must be set in advance. + /** The size (#dof) of the result Vector @a divshape must be set in advance. */ void CalcPhysDivShape(ElementTransformation &Trans, Vector &divshape) const; /** @brief Evaluate the curl of all shape functions of a *vector* finite element in reference space at the given point @a ip. */ /** Each row of the result DenseMatrix @a curl_shape contains the components - of the curl of one vector shape function. The size (#Dof x CDim) of - @a curl_shape must be set in advance, where CDim = 3 for #Dim = 3 and - CDim = 1 for #Dim = 2. */ + of the curl of one vector shape function. The size (#dof x CDim) of + @a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and + CDim = 1 for #dim = 2. */ virtual void CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const; /** @brief Evaluate the curl of all shape functions of a *vector* finite element in physical space at the point described by @a Trans. */ /** Each row of the result DenseMatrix @a curl_shape contains the components - of the curl of one vector shape function. The size (#Dof x CDim) of - @a curl_shape must be set in advance, where CDim = 3 for #Dim = 3 and - CDim = 1 for #Dim = 2. */ + of the curl of one vector shape function. The size (#dof x CDim) of + @a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and + CDim = 1 for #dim = 2. */ void CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape) const; @@ -443,19 +443,19 @@ public: /** Each row of the result DenseMatrix @a Hessian contains upper triangular part of the Hessian of one shape function. The order in 2D is {u_xx, u_xy, u_yy}. - The size (#Dof x (#Dim (#Dim-1)/2) of @a Hessian must be set in advance.*/ + The size (#dof x (#dim (#dim-1)/2) of @a Hessian must be set in advance.*/ virtual void CalcHessian (const IntegrationPoint &ip, DenseMatrix &Hessian) const; /** @brief Evaluate the Hessian of all shape functions of a scalar finite element in reference space at the given point @a ip. */ - /** The size (#Dof, #Dim*(#Dim+1)/2) of @a Hessian must be set in advance. */ + /** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */ virtual void CalcPhysHessian(ElementTransformation &Trans, DenseMatrix& Hessian) const; /** @brief Evaluate the Laplacian of all shape functions of a scalar finite element in reference space at the given point @a ip. */ - /** The size (#Dof) of @a Laplacian must be set in advance. */ + /** The size (#dof) of @a Laplacian must be set in advance. */ virtual void CalcPhysLaplacian(ElementTransformation &Trans, Vector& Laplacian) const; @@ -493,7 +493,7 @@ public: allowing the "coarse" FiniteElement to be different from the "fine" FiniteElement as when h-refinement is combined with p-refinement or p-derefinement. It is assumed that both finite elements use the same - FiniteElement::MapT. */ + FiniteElement::MapType. */ virtual void GetTransferMatrix(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const; @@ -632,19 +632,19 @@ public: int F = FunctionSpace::Pk) #ifdef MFEM_THREAD_SAFE : FiniteElement(D, G, Do, O, F) - { DerivType = GRAD; DerivRangeType = VECTOR; DerivMapType = H_CURL; } + { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; } #else - : FiniteElement(D, G, Do, O, F), c_shape(Dof) - { DerivType = GRAD; DerivRangeType = VECTOR; DerivMapType = H_CURL; } + : FiniteElement(D, G, Do, O, F), c_shape(dof) + { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; } #endif - /** @brief Set the FiniteElement::MapT of the element to either VALUE or INTEGRAL. - Also sets the FiniteElement::DerivT to GRAD if the FiniteElement::MapT is VALUE. */ + /** @brief Set the FiniteElement::MapType of the element to either VALUE or INTEGRAL. + Also sets the FiniteElement::DerivType to GRAD if the FiniteElement::MapType is VALUE. */ void SetMapType(int M) { MFEM_VERIFY(M == VALUE || M == INTEGRAL, "unknown MapType"); - MapType = M; - DerivType = (M == VALUE) ? GRAD : NONE; + map_type = M; + deriv_type = (M == VALUE) ? GRAD : NONE; } @@ -864,10 +864,10 @@ public: int F = FunctionSpace::Pk) : #ifdef MFEM_THREAD_SAFE FiniteElement(D, G, Do, O, F) - { RangeType = VECTOR; MapType = M; SetDerivMembers(); } + { range_type = VECTOR; map_type = M; SetDerivMembers(); } #else FiniteElement(D, G, Do, O, F), Jinv(D) - { RangeType = VECTOR; MapType = M; SetDerivMembers(); } + { range_type = VECTOR; map_type = M; SetDerivMembers(); } #endif }; @@ -1516,7 +1516,7 @@ public: DenseMatrix &dshape) const; }; -/// A 3D linear tetrahedron with nodes at thirds??? +/// A 3D Crouzeix-Raviart element on the tetrahedron. class P1TetNonConfFiniteElement : public NodalFiniteElement { public: @@ -3146,8 +3146,8 @@ public: { ijk = NULL; patch = elem = -1; - kv.SetSize(Dim); - weights.SetSize(Dof); + kv.SetSize(dim); + weights.SetSize(dof); weights = 1.0; } @@ -3196,17 +3196,17 @@ public: NURBS2DFiniteElement(int p) : NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p, FunctionSpace::Qk), - u(Dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1), - dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(Dof,2) - { Orders[0] = Orders[1] = p; } + u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1), + dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2) + { orders[0] = orders[1] = p; } /// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py NURBS2DFiniteElement(int px, int py) : NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1), std::max(px, py), FunctionSpace::Qk), - u(Dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1), - dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(Dof,2) - { Orders[0] = px; Orders[1] = py; } + u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1), + dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2) + { orders[0] = px; orders[1] = py; } virtual void SetOrder() const; virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -3230,19 +3230,19 @@ public: NURBS3DFiniteElement(int p) : NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p, FunctionSpace::Qk), - u(Dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), + u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), - d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(Dof,3) - { Orders[0] = Orders[1] = Orders[2] = p; } + d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3) + { orders[0] = orders[1] = orders[2] = p; } /// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py and z-order @a pz NURBS3DFiniteElement(int px, int py, int pz) : NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1), std::max(std::max(px,py),pz), FunctionSpace::Qk), - u(Dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1), + u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1), dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1), - d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(Dof,3) - { Orders[0] = px; Orders[1] = py; Orders[2] = pz; } + d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3) + { orders[0] = px; orders[1] = py; orders[2] = pz; } virtual void SetOrder() const; virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; From add2e8a3f2952eaf610cc16696deb6b5f65aa83d Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Mon, 20 Apr 2020 16:51:30 -0700 Subject: [PATCH 194/535] Fixed the remainder of the issues that Mark caught. --- fem/coefficient.hpp | 12 +++++++++++- general/array.hpp | 9 +++++---- general/communication.hpp | 25 ++++++++++++++++--------- general/mem_alloc.hpp | 2 ++ general/optparser.hpp | 15 ++++++++++++--- general/sets.hpp | 2 +- general/socketstream.hpp | 2 +- general/stable3d.hpp | 12 ++++++------ general/tic_toc.hpp | 2 +- linalg/vector.hpp | 34 ++++++++++++++++++++++++++++++---- 10 files changed, 85 insertions(+), 30 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 6c0a56b36c..e446b1fe84 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -263,7 +263,11 @@ public: center[0] = x; center[1] = y; center[2] = z; scale = s; tol = 1e-12; weight = NULL; sdim = 3; tdf = NULL; } + + /// Set the center location of the delta function. void SetDeltaCenter(const Vector& center); + + /// Set the scale value multiplying the delta function. void SetScale(double _s) { scale = _s; } /// Set a time-dependent function that multiplies the Scale(). @@ -337,6 +341,7 @@ protected: double time; public: + /// Initilize the a VectorCoefficient with vector dimension @a vd. VectorCoefficient(int vd) { vdim = vd; time = 0.; } /// Set the time for time dependent coefficients @@ -389,6 +394,8 @@ public: /// Evaluate the vector coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { V = vec; } + + /// Return a reference to the constant vector in this class. const Vector& GetVec() { return vec; } }; @@ -481,8 +488,11 @@ public: grid function is not owned by the coefficient. */ VectorGridFunctionCoefficient(GridFunction *gf); - /// Set the grid function + /** @brief Set the grid function for this coefficient. Also sets the Vector + dimension to match that of the @a gf. */ void SetGridFunction(GridFunction *gf); + + /// Returns a pointer to the grid function in this Coefficient GridFunction * GetGridFunction() const { return GridFunc; } /// Evaluate the vector coefficient at @a ip. diff --git a/general/array.hpp b/general/array.hpp index 28115dd18d..c81d3ac5ab 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -62,7 +62,6 @@ public: /// Creates array of @a asize elements explicit inline Array(int asize) - : size(asize) { asize > 0 ? data.New(asize) : data.Reset(); } /** @brief Creates array using an existing c-array of asize elements; @@ -71,7 +70,6 @@ public: inline Array(T *_data, int asize) { data.Wrap(_data, asize, false); size = asize; } - /// Copy constructor: deep copy from @a src /** This method supports source arrays using any MemoryType. */ inline Array(const Array &src); @@ -259,18 +257,21 @@ public: /// Set all entries of the array to the provided constant. inline void operator=(const T &a); - /// Copy data from a pointer. 'Size()'' elements are copied. + /// Copy data from a pointer. 'Size()' elements are copied. inline void Assign(const T *); /// STL-like copyTo @a dest from begin to end. template inline void CopyTo(U *dest) { std::copy(begin(), end(), dest); } + /** @brief Copy from @a src into this array. Copies enough entries to + fill the Capacity size of this array. Careful this does not update + the Size to match this Capacity after this.*/ template inline void CopyFrom(const U *src) { std::memcpy(begin(), src, MemoryUsage()); } - // STL-like begin. Returns poiner to the first element of the array. + /// STL-like begin. Returns poiner to the first element of the array. inline T* begin() { return data; } /// STL-like end. Returns pointer after the last element of the array. diff --git a/general/communication.hpp b/general/communication.hpp index 01b2763074..5aec850647 100644 --- a/general/communication.hpp +++ b/general/communication.hpp @@ -59,8 +59,6 @@ class GroupTopology private: MPI_Comm MyComm; - - /// Neighbor ids (lproc) in each group. Table group_lproc; /// Master neighbor id for each group. @@ -94,6 +92,7 @@ public: /// Return the number of MPI ranks within this object's communicator. int NRanks() const { int s; MPI_Comm_size(MyComm, &s); return s; } + /// Set up the group topology given the list of sets of shared entities. void Create(ListOfIntegerSets &groups, int mpitag); /// Return the number of groups. @@ -104,16 +103,21 @@ public: /// Return the MPI rank of neighbor 'i'. int GetNeighborRank(int i) const { return lproc_proc[i]; } + /// Return true if I am master for group 'g'. bool IAmMaster(int g) const { return (groupmaster_lproc[g] == 0); } - /** Return the neighbor index of the group master for a given group. + + /** @brief Return the neighbor index of the group master for a given group. * Neighbor 0 is the local processor. */ int GetGroupMaster(int g) const { return groupmaster_lproc[g]; } + /// Return the rank of the group master for group 'g'. int GetGroupMasterRank(int g) const { return lproc_proc[groupmaster_lproc[g]]; } + /// Return the group number in the master for group 'g'. int GetGroupMasterGroup(int g) const { return group_mgroup[g]; } + /// Get the number of processors in a group int GetGroupSize(int g) const { return group_lproc.RowSize(g); } @@ -123,6 +127,7 @@ public: /// Save the data in a stream. void Save(std::ostream &out) const; + /// Load the data from a stream. void Load(std::istream &in); @@ -339,7 +344,7 @@ struct VarMessage std::string data; MPI_Request send_request; - /** Non-blocking send to processor 'rank'. Returns immediately. Completion + /** @brief Non-blocking send to processor 'rank'. Returns immediately. Completion (as tested by MPI_Wait/Test) does not mean the message was received -- it may be on its way or just buffered locally. */ void Isend(int rank, MPI_Comm comm) @@ -349,7 +354,7 @@ struct VarMessage &send_request); } - /** Non-blocking synchronous send to processor 'rank'. Returns immediately. + /** @brief Non-blocking synchronous send to processor 'rank'. Returns immediately. Completion (MPI_Wait/Test) means that the message was received. */ void Issend(int rank, MPI_Comm comm) { @@ -379,8 +384,8 @@ struct VarMessage } } - /** Return true if all messages in the map container were sent, otherwise - return false, without waiting. */ + /** @brief Return true if all messages in the map container were sent, + otherwise return false, without waiting. */ template static bool TestAllSent(MapT& rank_msg) { @@ -398,7 +403,7 @@ struct VarMessage return true; } - /** Blocking probe for incoming message of this type from any rank. + /** @brief Blocking probe for incoming message of this type from any rank. Returns the rank and message size. */ static void Probe(int &rank, int &size, MPI_Comm comm) { @@ -408,7 +413,7 @@ struct VarMessage MPI_Get_count(&status, MPI_BYTE, &size); } - /** Non-blocking probe for incoming message of this type from any rank. + /** @briefNon-blocking probe for incoming message of this type from any rank. If there is an incoming message, returns true and sets 'rank' and 'size'. Otherwise returns false. */ static bool IProbe(int &rank, int &size, MPI_Comm comm) @@ -465,6 +470,8 @@ struct VarMessage } VarMessage() : send_request(MPI_REQUEST_NULL) {} + + /// Clear the message and associated request. void Clear() { data.clear(); send_request = MPI_REQUEST_NULL; } virtual ~VarMessage() diff --git a/general/mem_alloc.hpp b/general/mem_alloc.hpp index 91dc209c89..19c66b509a 100644 --- a/general/mem_alloc.hpp +++ b/general/mem_alloc.hpp @@ -44,7 +44,9 @@ public: /// Clear the elements off the stack. void Clear(); + /// Swap the data in this stack with the data in @a other. void Swap(Stack &other); + /// Return the number of bytes used by the stack. size_t MemoryUsage() const; ~Stack() { Clear(); } diff --git a/general/optparser.hpp b/general/optparser.hpp index 1d24052f4b..ab0d35b51d 100644 --- a/general/optparser.hpp +++ b/general/optparser.hpp @@ -69,15 +69,15 @@ private: public: - /// Comstruct a command line option parser with '_argc' and '_argv'. + /// Construct a command line option parser with '_argc' and '_argv'. OptionsParser(int _argc, char *_argv[]) : argc(_argc), argv(_argv) { error_type = error_idx = 0; } - /** Add a boolean option and set 'var' to recieve the value. Enable/disable - tags are used to set the bool to true/false respectively. */ + /** @brief Add a boolean option and set 'var' to recieve the value. + Enable/disable tags are used to set the bool to true/false respectively. */ void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, @@ -143,10 +143,19 @@ public: /// Return true if the command line options were parsed sucessfully. bool Good() const { return (error_type == 0); } + /// Return true if we are flagged to print the help message. bool Help() const { return (error_type == 1); } + + /// Print the options void PrintOptions(std::ostream &out) const; + + /// Print the error message void PrintError(std::ostream &out) const; + + /// Print the help message void PrintHelp(std::ostream &out) const; + + /// Print the usage message void PrintUsage(std::ostream &out) const; }; diff --git a/general/sets.hpp b/general/sets.hpp index 2495c6dfe2..33f5ee7874 100644 --- a/general/sets.hpp +++ b/general/sets.hpp @@ -50,7 +50,7 @@ public: /// Return 1 if the sets are equal and 0 otherwise. int operator==(IntegerSet &s); - /** Create an integer set from C-array 'p' of 'n' integers. + /** @brief Create an integer set from C-array 'p' of 'n' integers. Overwrites any existing set data. */ void Recreate(const int n, const int *p); }; diff --git a/general/socketstream.hpp b/general/socketstream.hpp index 72b38c40ce..f0bbd55029 100644 --- a/general/socketstream.hpp +++ b/general/socketstream.hpp @@ -72,7 +72,7 @@ public: /// Returns the attached socket descriptor. int getsocketdescriptor() { return socket_descriptor; } - /** @brief Returns true of the socket is open and has a valid + /** @brief Returns true if the socket is open and has a valid socket descriptor. Otherwise returns false. */ bool is_open() { return (socket_descriptor >= 0); } diff --git a/general/stable3d.hpp b/general/stable3d.hpp index 1a1421df4b..54a4d3e197 100644 --- a/general/stable3d.hpp +++ b/general/stable3d.hpp @@ -25,13 +25,13 @@ public: int Column, Floor, Number; }; -/** @brief Symmetric 3D Table stored an array of rows each of which has +/** @brief Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed - into the table. Diagonals of any kind are not so the row, column - and floor must all be different for each node. Only one node is - stored for all 6 symmetric entries that are indexable by unique - triplets of row, column, and floor. + into the table. Diagonals of any kind are not allowed so the row, + column and floor must all be different for each node. Only one + node is stored for all 6 symmetric entries that are indexable by + unique triplets of row, column, and floor. */ class STable3D { @@ -64,7 +64,7 @@ public: table entry. */ int Push4 (int r, int c, int f, int t); - /** Return the number assigned to the table entry. The entry is + /** @brief Return the number assigned to the table entry. The entry is addressed by the three smallest values of (r,c,f,t). Return -1 if it is not there. */ int operator() (int r, int c, int f, int t) const; diff --git a/general/tic_toc.hpp b/general/tic_toc.hpp index fc854ee08a..110b945c96 100644 --- a/general/tic_toc.hpp +++ b/general/tic_toc.hpp @@ -48,7 +48,7 @@ public: /// Stop the stopwatch. void Stop(); - ///Return the time resolution available to the stopwatch. + /// Return the time resolution available to the stopwatch. double Resolution(); /// Return the number of real seconds elapsed since the stopwatch was started. diff --git a/linalg/vector.hpp b/linalg/vector.hpp index 9fa3be189f..318a62f949 100644 --- a/linalg/vector.hpp +++ b/linalg/vector.hpp @@ -281,22 +281,48 @@ public: /// v = median(v,lo,hi) entrywise. Implementation assumes lo <= hi. void median(const Vector &lo, const Vector &hi); - /// Extract entries listed in `dofs` to the output `elemvect` + /** @brief Extract entries listed in @a dofs to the output Vector @a elemvect. + Negative dof values cause the -dof-1 position in @a elemvect to recieve + the -val in from this Vector. */ void GetSubVector(const Array &dofs, Vector &elemvect) const; + + /** @brief Extract entries listed in @a dofs to the output array @a elem_data. + Negative dof values cause the -dof-1 position in @a elem_data to recieve + the -val in from this Vector. */ void GetSubVector(const Array &dofs, double *elem_data) const; - /// Set the entries listed in `dofs` to the given `value`. + /** @brief Set the entries listed in @a dofs to the given @a value. + Negative dof values cause the -dof-1 position in this Vector to recieve + the -value. */ void SetSubVector(const Array &dofs, const double value); + + /** @brief Set the entries listed in @a dofs to the values given in the @a elemvect Vector. + Negative dof values cause the -dof-1 position in this Vector to recieve + the -val from @a elemvect. */ void SetSubVector(const Array &dofs, const Vector &elemvect); + + /** @brief Set the entries listed in @a dofs to the values given the @a elem_data array. + Negative dof values cause the -dof-1 position in this Vector to recieve + the -val from @a elem_data. */ void SetSubVector(const Array &dofs, double *elem_data); - /// Add (element) subvector to the vector. + /** @brief Add elements of the @a elemvect Vector to the entries listed in @a dofs. + Negative dof values cause the -dof-1 position in this Vector to add + the -val from @a elemvect. */ void AddElementVector(const Array & dofs, const Vector & elemvect); + + /** @brief Add elements of the @a elem_data array to the entries listed in @a dofs. + Negative dof values cause the -dof-1 position in this Vector to add + the -val from @a elem_data. */ void AddElementVector(const Array & dofs, double *elem_data); + + /** @brief Add @a times the elements of the @a elemvect Vector to the entries listed in + @a dofs. Negative dof values cause the -dof-1 position in this Vector to add + the -a*val from @a elemvect. */ void AddElementVector(const Array & dofs, const double a, const Vector & elemvect); - /// Set all vector entries NOT in the 'dofs' array to the given 'val'. + /// Set all vector entries NOT in the @a dofs Array to the given @a val. void SetSubVectorComplement(const Array &dofs, const double val); /// Prints vector to stream out. From 662ffefdb8e78ade20601cd51a2a599372af9e19 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 21 Apr 2020 11:26:19 -0700 Subject: [PATCH 195/535] reviewer comments --- fem/tmop.cpp | 70 +++++++++++++++++++++------------------------- fem/tmop.hpp | 7 ++++- fem/tmop_tools.cpp | 7 ++--- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index c8c64ae326..e2d503003c 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -975,65 +975,37 @@ void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) { - const int vdim = tspec_.FESpace()->GetVDim(), - cnt = tspec_.Size()/vdim; - - ncomp += vdim; - if (tspec_fes == NULL) { - tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), - tspec_.FESpace()->FEColl(), - 1); ptspec_fes = tspec_.ParFESpace(); - tspec = tspec_; - - return; - } - - // need to append data to tspec - // make a copy of tspec->tspec_temp, increase its size, and - // copy data from tspec_temp -> tspec, then add new entries - Vector tspec_temp = tspec; - tspec.SetSize(ncomp*cnt); - - for (int i = 0; i < tspec_temp.Size(); i++) - { - tspec(i) = tspec_temp(i); - } - - for (int i = 0; i < cnt*vdim; i++) - { - tspec(i+(ncomp-vdim)*cnt) = tspec_(i); } + SetSerialDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetSize(ParGridFunction &tspec_) { - MFEM_VERIFY(sizeidx == -1, " Size discrete function already specified") + if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; } sizeidx = ncomp; SetParDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetSkew(ParGridFunction &tspec_) { - MFEM_VERIFY(skewidx == -1, " Skew discrete function already specified") + if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; } skewidx = ncomp; SetParDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(ParGridFunction &tspec_) { - MFEM_VERIFY(aspectratioidx == -1, - " AspectRatio discrete function already specified") + if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; } aspectratioidx = ncomp; SetParDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetOrientation(ParGridFunction &tspec_) { - MFEM_VERIFY(orientationidx == -1, - " Orientation discrete function already specified") + if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; } orientationidx = ncomp; SetParDiscreteTargetBase(tspec_); } @@ -1041,7 +1013,7 @@ void DiscreteAdaptTC::SetParDiscreteTargetOrientation(ParGridFunction &tspec_) void DiscreteAdaptTC::SetParDiscreteTargetSpec(ParGridFunction &tspec_) { SetParDiscreteTargetSize(tspec_); - FinalizeParDiscreteTargetSpec(); + if (tspec_fesv == NULL) { FinalizeParDiscreteTargetSpec(); } } #endif @@ -1082,27 +1054,45 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) } } +void DiscreteAdaptTC::SetTspecAtIndex(int idx, GridFunction &tspec_) +{ + const int vdim = tspec_.FESpace()->GetVDim(), + dof_cnt = tspec_.Size()/vdim; + for (int i = 0; i < dof_cnt*vdim; i++) + { + tspec(i+idx*dof_cnt) = tspec_(i); + } + for (int i = 0; i < dof_cnt*vdim; i++) + { + tspec_sav(i+idx*dof_cnt) = tspec_(i); + } +} void DiscreteAdaptTC::SetSerialDiscreteTargetSize(GridFunction &tspec_) { + + if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; } sizeidx = ncomp; SetSerialDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(GridFunction &tspec_) { + if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; } skewidx = ncomp; SetSerialDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(GridFunction &tspec_) { + if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; } aspectratioidx = ncomp; SetSerialDiscreteTargetBase(tspec_); } void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(GridFunction &tspec_) { + if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; } orientationidx = ncomp; SetSerialDiscreteTargetBase(tspec_); } @@ -1128,7 +1118,7 @@ void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(GridFunction &tspec_) { SetSerialDiscreteTargetSize(tspec_); - FinalizeSerialDiscreteTargetSpec(); + if (tspec_fesv == NULL) { FinalizeSerialDiscreteTargetSpec(); } } @@ -1365,7 +1355,7 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x, tspec_perth.SetSize(x.Size()*ncomp); Vector TSpecTemp(ncomp*cnt); - Vector xtemp(x.GetData(), x.Size()); + Vector xtemp = x; for (int j = 0; j < dim; j++) { for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) += dx; } @@ -1387,7 +1377,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, tspec_pertmix.SetSize(cnt*totmix*ncomp); Vector TSpecTemp(cnt*ncomp); - Vector xtemp(x.GetData(), x.Size()); + Vector xtemp = x; // T(x+2h) for (int j = 0; j < dim; j++) @@ -1433,6 +1423,8 @@ void AdaptivityEvaluator::SetSerialMetaInfo(const Mesh &m, delete mesh; mesh = new Mesh(m, true); fes = new FiniteElementSpace(mesh, &fec, num_comp); + dim = fes->GetFE(0)->GetDim(); + ncomp = num_comp; } #ifdef MFEM_USE_MPI @@ -1444,7 +1436,8 @@ void AdaptivityEvaluator::SetParMetaInfo(const ParMesh &m, delete pmesh; pmesh = new ParMesh(m, true); pfes = new ParFiniteElementSpace(pmesh, &fec, num_comp); - fes = pfes; + dim = pfes->GetFE(0)->GetDim(); + ncomp = num_comp; } #endif @@ -1453,6 +1446,7 @@ AdaptivityEvaluator::~AdaptivityEvaluator() delete fes; delete mesh; #ifdef MFEM_USE_MPI + delete pfes; delete pmesh; #endif } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 6e8b26f196..4a23c3a420 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -560,6 +560,8 @@ protected: ParFiniteElementSpace *pfes; #endif + int dim, ncomp; + public: AdaptivityEvaluator() : mesh(NULL), fes(NULL) { @@ -735,13 +737,16 @@ protected: #ifdef MFEM_USE_MPI void SetParDiscreteTargetBase(ParGridFunction &tspec_); #endif + void SetTspecAtIndex(int idx, GridFunction &tspec_); public: DiscreteAdaptTC(TargetType ttype) : TargetConstructor(ttype), ncomp(0), sizeidx(-1), skewidx(-1), aspectratioidx(-1), orientationidx(-1), - tspec(), tspec_fes(NULL), adapt_eval(NULL) { } + tspec(), tspec_sav(), tspec_perth(), tspec_pert2h(), tspec_pertmix(), + ptspec_fes(NULL), tspec_fes(NULL), tspec_fesv(NULL), + adapt_eval(NULL) { } virtual ~DiscreteAdaptTC() { diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 1f3991239e..cad1fbb581 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -30,9 +30,7 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes, Vector &new_field) { // TODO: Implement for AMR meshes. - const int dim = fes->GetFE(0)->GetDim(), - ncomp = fes->GetVDim(), - pnt_cnt = new_field.Size()/ncomp; + const int pnt_cnt = new_field.Size()/ncomp; new_field = field0; @@ -94,8 +92,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes, h_min = std::min(h_min, m->GetElementSize(i)); } double v_max = 0.0; - const int dim = fes->GetFE(0)->GetDim(), - s = new_field.Size() ; + const int s = new_field.Size(); for (int i = 0; i < s; i++) { From fdae3b1f19d6b3bee42e39805c33652aba1931e3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 21 Apr 2020 15:00:21 -0700 Subject: [PATCH 196/535] Adding a "Set" method to replace the deprecated public FaceGeom member data --- fem/eltrans.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 53c276c1ab..c7a3b89849 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -391,6 +391,15 @@ public: FaceElementTransformations() : side(2), FaceGeom(geom), Face(this) {} + /** @brief Method to set the geometry type of the face. + + @note This method should only be used when + [Par]Mesh::GetFaceTransformation will not be called i.e. when the + face transformation will not be needed but the neighboring + element transformations will be. + */ + void SetGeometryType(Geometry::Type g) { geom = g; } + /** FaceElementTransformations objects are often used when performing the surface integrals on the interfaces between elements needed by Discontinuous Galerkin methods. Since the From 41e0872d792ccf452d2d7e1e963752b236dc2725 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 21 Apr 2020 15:01:23 -0700 Subject: [PATCH 197/535] Removing uses of deprecated FaceElementTransformations features --- examples/ex18.hpp | 6 +++--- mesh/mesh.cpp | 2 +- mesh/pmesh.cpp | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/ex18.hpp b/examples/ex18.hpp index fe0e38ffc2..75fa5e885b 100644 --- a/examples/ex18.hpp +++ b/examples/ex18.hpp @@ -418,7 +418,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, { intorder++; } - const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder); + const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder); for (int i = 0; i < ir->GetNPoints(); i++) { @@ -435,10 +435,10 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, elfun1_mat.MultTranspose(shape1, funval1); elfun2_mat.MultTranspose(shape2, funval2); - Tr.Face->SetIntPoint(&ip); + Tr.SetIntPoint(&ip); // Get the normal vector and the flux on the face - CalcOrtho(Tr.Face->Jacobian(), nor); + CalcOrtho(Tr.Jacobian(), nor); const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN); // Update max char speed diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 09049c5edb..2691cedd9a 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -890,7 +890,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, } else { - FaceElemTr.FaceGeom = GetFaceGeometryType(FaceNo); + FaceElemTr.SetGeometryType(GetFaceGeometryType(FaceNo)); } // setup Loc1 & Loc2 diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 2377880112..8772778066 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2392,12 +2392,15 @@ GetSharedFaceTransformations(int sf, bool fill2) } // setup the face transformation if the face is not a ghost - FaceElemTr.FaceGeom = face_geom; if (!is_ghost) { - FaceElemTr.Face = GetFaceTransformation(FaceNo); + GetFaceTransformation(FaceNo, &FaceElemTr); // NOTE: The above call overwrites FaceElemTr.Loc1 } + else + { + FaceElemTr.SetGeometryType(face_geom); + } // setup Loc1 & Loc2 int elem_type = GetElementType(face_info.Elem1No); @@ -2436,8 +2439,7 @@ GetSharedFaceTransformations(int sf, bool fill2) // for ghost faces we need a special version of GetFaceTransformation if (is_ghost) { - FaceElemTr.Face = - GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); + GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); } return &FaceElemTr; From c658d4ead049e5af9b38f616c0598bfaaea87bdd Mon Sep 17 00:00:00 2001 From: Tomov Date: Tue, 21 Apr 2020 16:49:08 -0700 Subject: [PATCH 198/535] Added some comments, const qualifiers. --- fem/tmop.cpp | 47 ++++++++++++++++++++--------------------------- fem/tmop.hpp | 49 +++++++++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 9e3d684664..2aeb092c25 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -963,61 +963,59 @@ void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() MFEM_VERIFY(ncomp > 0, "No target specifications have been set!"); adapt_eval->SetParMetaInfo(*ptspec_fes->GetParMesh(), - *ptspec_fes->FEColl(), - ncomp); + *ptspec_fes->FEColl(), ncomp); adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec); tspec_sav = tspec; tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), - tspec_fes->FEColl(), - ncomp); + tspec_fes->FEColl(), ncomp); } -void DiscreteAdaptTC::SetParDiscreteTargetBase(ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetBase(const ParGridFunction &tspec_) { - if (tspec_fes == NULL) + if (ptspec_fes == NULL) { ptspec_fes = tspec_.ParFESpace(); } SetSerialDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetSize(ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetSize(const ParGridFunction &tspec_) { if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; } sizeidx = ncomp; SetParDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetSkew(ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetSkew(const ParGridFunction &tspec_) { if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; } skewidx = ncomp; SetParDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(const ParGridFunction &tspec_) { if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; } aspectratioidx = ncomp; SetParDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetOrientation(ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetOrientation(const ParGridFunction &tspec_) { if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; } orientationidx = ncomp; SetParDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetSpec(ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetSpec(const ParGridFunction &tspec_) { SetParDiscreteTargetSize(tspec_); if (tspec_fesv == NULL) { FinalizeParDiscreteTargetSpec(); } } #endif -void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetBase(const GridFunction &tspec_) { const int vdim = tspec_.FESpace()->GetVDim(), dof_cnt = tspec_.Size()/vdim; @@ -1054,7 +1052,7 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetBase(GridFunction &tspec_) } } -void DiscreteAdaptTC::SetTspecAtIndex(int idx, GridFunction &tspec_) +void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_) { const int vdim = tspec_.FESpace()->GetVDim(), dof_cnt = tspec_.Size()/vdim; @@ -1068,7 +1066,7 @@ void DiscreteAdaptTC::SetTspecAtIndex(int idx, GridFunction &tspec_) } } -void DiscreteAdaptTC::SetSerialDiscreteTargetSize(GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetSize(const GridFunction &tspec_) { if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; } @@ -1076,21 +1074,21 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetSize(GridFunction &tspec_) SetSerialDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(const GridFunction &tspec_) { if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; } skewidx = ncomp; SetSerialDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(const GridFunction &tspec_) { if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; } aspectratioidx = ncomp; SetSerialDiscreteTargetBase(tspec_); } -void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(const GridFunction &tspec_) { if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; } orientationidx = ncomp; @@ -1103,19 +1101,15 @@ void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() MFEM_VERIFY(ncomp > 0, "No target specifications have been set!"); adapt_eval->SetSerialMetaInfo(*tspec_fes->GetMesh(), - *tspec_fes->FEColl(), - ncomp); - - adapt_eval->SetInitialField - (*tspec_fes->GetMesh()->GetNodes(), tspec); + *tspec_fes->FEColl(), ncomp); + adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec); tspec_sav = tspec; tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), - tspec_fes->FEColl(), - ncomp); + tspec_fes->FEColl(), ncomp); } -void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(const GridFunction &tspec_) { SetSerialDiscreteTargetSize(tspec_); if (tspec_fesv == NULL) { FinalizeSerialDiscreteTargetSpec(); } @@ -1176,7 +1170,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, const Vector &elfun, DenseTensor &Jtr) const { - MFEM_VERIFY(tspec_fes, "A call to SetDiscreteTargerSpec() is needed."); + MFEM_VERIFY(tspec_fesv, "A call to FinalizeDiscreteTargetSpec() is needed."); switch (target_type) { @@ -1189,7 +1183,6 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, ndofs = tspec_fes->GetFE(0)->GetDof(), ntspec_dofs = ndofs*ncomp; - Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals, par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs); diff --git a/fem/tmop.hpp b/fem/tmop.hpp index fd3616c0d7..536f8b3986 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -710,15 +710,14 @@ class DiscreteAdaptTC : public TargetConstructor protected: // Discrete target specification. // Data is owned, updated by UpdateTargetSpecification. - int ncomp; - int sizeidx, skewidx, aspectratioidx, orientationidx; - Vector tspec; //eta(x) + int ncomp, sizeidx, skewidx, aspectratioidx, orientationidx; + Vector tspec; //eta(x) Vector tspec_sav; Vector tspec_pert1h; //eta(x+h) Vector tspec_pert2h; //eta(x+2*h) Vector tspec_pertmix; //eta(x+h,y+h) - // The new order for these vectors is - // eta1(x+h),eta2(x+h)...etan(x+h),eta1(y+h),eta2(y+h)...etan(y+h). + // The order inside these perturbation vectors (e.g. in 2D) is + // eta1(x+h,y), eta2(x+h,y) ... etan(x+h,y), eta1(x,y+h), eta2(x,y+h) ... // same for tspec_pert2h and tspec_pertmix. // Note: do not use the Nodes of this space as they may not be on the @@ -737,11 +736,11 @@ protected: // Owned. AdaptivityEvaluator *adapt_eval; - void SetSerialDiscreteTargetBase(GridFunction &tspec_); + void SetSerialDiscreteTargetBase(const GridFunction &tspec_); #ifdef MFEM_USE_MPI - void SetParDiscreteTargetBase(ParGridFunction &tspec_); + void SetParDiscreteTargetBase(const ParGridFunction &tspec_); #endif - void SetTspecAtIndex(int idx, GridFunction &tspec_); + void SetTspecAtIndex(int idx, const GridFunction &tspec_); public: DiscreteAdaptTC(TargetType ttype) @@ -760,20 +759,34 @@ public: delete tspec_fesv; } - virtual void SetSerialDiscreteTargetSpec(GridFunction &tspec_); - virtual void SetSerialDiscreteTargetSize(GridFunction &tspec_); - virtual void SetSerialDiscreteTargetSkew(GridFunction &tspec_); - virtual void SetSerialDiscreteTargetAspectRatio(GridFunction &tspec_); - virtual void SetSerialDiscreteTargetOrientation(GridFunction &tspec_); + /** @name Target specification methods. + The following methods are used to specify geometric parameters of the + targets when these parameters are given by discrete FE functions. + Note that every GridFunction given to the Set methods must use a + H1_FECollection of the same order. The number of components must + correspond to the type of geometric parameter and dimension. + Once the calls to the Set methods are complete, users are expected to + call a Finalize method. + + @param[in] tspec_ Input values of a geometric parameter. Note that + the methods in this class support only functions that + use H1_FECollection collection of the same order. */ + ///@{ + virtual void SetSerialDiscreteTargetSpec(const GridFunction &tspec_); + virtual void SetSerialDiscreteTargetSize(const GridFunction &tspec_); + virtual void SetSerialDiscreteTargetSkew(const GridFunction &tspec_); + virtual void SetSerialDiscreteTargetAspectRatio(const GridFunction &tspec_); + virtual void SetSerialDiscreteTargetOrientation(const GridFunction &tspec_); virtual void FinalizeSerialDiscreteTargetSpec(); #ifdef MFEM_USE_MPI - virtual void SetParDiscreteTargetSpec(ParGridFunction &tspec_); - virtual void SetParDiscreteTargetSize(ParGridFunction &tspec_); - virtual void SetParDiscreteTargetSkew(ParGridFunction &tspec_); - virtual void SetParDiscreteTargetAspectRatio(ParGridFunction &tspec_); - virtual void SetParDiscreteTargetOrientation(ParGridFunction &tspec_); + virtual void SetParDiscreteTargetSpec(const ParGridFunction &tspec_); + virtual void SetParDiscreteTargetSize(const ParGridFunction &tspec_); + virtual void SetParDiscreteTargetSkew(const ParGridFunction &tspec_); + virtual void SetParDiscreteTargetAspectRatio(const ParGridFunction &tspec_); + virtual void SetParDiscreteTargetOrientation(const ParGridFunction &tspec_); virtual void FinalizeParDiscreteTargetSpec(); #endif + ///@} /// Used in combination with the Update methods to avoid extra computations. void ResetUpdateFlags() From f10f165b712bc733c2636bdf62ea3f2d8c0768d0 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 22 Apr 2020 13:52:36 +0200 Subject: [PATCH 199/535] Fix mem leak --- fem/fespace.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 516c5cd467..34220b648f 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1402,6 +1402,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext, this->ordering = (Ordering::Type) ordering; elem_dof = NULL; + face_dof = NULL; sequence = mesh->GetSequence(); Th.SetType(Operator::ANY_TYPE); @@ -1464,6 +1465,7 @@ void FiniteElementSpace::UpdateNURBS() ndofs = NURBSext->GetNDof(); elem_dof = NURBSext->GetElementDofTable(); bdrElem_dof = NURBSext->GetBdrElementDofTable(); + delete face_dof; face_dof = NULL; } From b1bacf9b3f7a5039c7969b3637c268f308806a91 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Apr 2020 11:33:25 -0700 Subject: [PATCH 200/535] fix uninitialized value --- fem/field_interpolant.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 14bc42f866..71a019d488 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -33,7 +33,7 @@ private: MassIntegrator mass_int; int NE; public: - FieldInterpolant(const IntegrationRule* ir) { mass_int.SetIntRule(ir); } + FieldInterpolant(const IntegrationRule* ir) : setup_disc(false) { mass_int.SetIntRule(ir); } // This function takes a vector quadrature function coefficient and projects it onto a GridFunction that lives // in L2 space. This function requires tr_fes to be the finite element space that the VectorQuadratureFunctionCoefficient lives on // and fes is the L2 finite element space that we're projecting onto. From aea7ed60693d7d60f49782e1f5dc4f4ea63b1045 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Wed, 22 Apr 2020 14:00:29 -0700 Subject: [PATCH 201/535] changes to discrete adaptivity --- fem/gslib.cpp | 4 +- fem/tmop.cpp | 84 +++++----- fem/tmop.hpp | 17 +- miniapps/meshing/mesh-optimizer.cpp | 215 +------------------------ miniapps/meshing/mesh-optimizer.hpp | 228 +++++++++++++++++++++++++++ miniapps/meshing/pmesh-optimizer.cpp | 214 +------------------------ 6 files changed, 300 insertions(+), 462 deletions(-) create mode 100644 miniapps/meshing/mesh-optimizer.hpp diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 2c96bb0b37..d58ed4bb50 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -34,7 +34,9 @@ FindPointsGSLIB::FindPointsGSLIB() { gsl_comm = new comm; #ifdef MFEM_USE_MPI - MPI_Init(NULL, NULL); + int initialized; + MPI_Initialized(&initialized); + if (!initialized) { MPI_Init(NULL, NULL); } MPI_Comm comm = MPI_COMM_WORLD;; comm_init(gsl_comm, comm); #else diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 2aeb092c25..e8384c458d 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -957,83 +957,89 @@ void AnalyticAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, } #ifdef MFEM_USE_MPI -void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec() +void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec(const ParGridFunction + &tspec_) { MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!") MFEM_VERIFY(ncomp > 0, "No target specifications have been set!"); + ParFiniteElementSpace *ptspec_fes = tspec_.ParFESpace(); + adapt_eval->SetParMetaInfo(*ptspec_fes->GetParMesh(), *ptspec_fes->FEColl(), ncomp); adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec); tspec_sav = tspec; + + delete tspec_fesv; tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), tspec_fes->FEColl(), ncomp); } -void DiscreteAdaptTC::SetParDiscreteTargetBase(const ParGridFunction &tspec_) +void DiscreteAdaptTC::SetTspecAtIndex(int idx, const ParGridFunction &tspec_) { - if (ptspec_fes == NULL) + const int vdim = tspec_.FESpace()->GetVDim(), + dof_cnt = tspec_.Size()/vdim; + for (int i = 0; i < dof_cnt*vdim; i++) { - ptspec_fes = tspec_.ParFESpace(); + tspec(i+idx*dof_cnt) = tspec_(i); } - SetSerialDiscreteTargetBase(tspec_); + + FinalizeParDiscreteTargetSpec(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetSize(const ParGridFunction &tspec_) { if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; } sizeidx = ncomp; - SetParDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeParDiscreteTargetSpec(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetSkew(const ParGridFunction &tspec_) { if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; } skewidx = ncomp; - SetParDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeParDiscreteTargetSpec(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(const ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(const ParGridFunction + &tspec_) { if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; } aspectratioidx = ncomp; - SetParDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeParDiscreteTargetSpec(tspec_); } -void DiscreteAdaptTC::SetParDiscreteTargetOrientation(const ParGridFunction &tspec_) +void DiscreteAdaptTC::SetParDiscreteTargetOrientation(const ParGridFunction + &tspec_) { if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; } orientationidx = ncomp; - SetParDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeParDiscreteTargetSpec(tspec_); } void DiscreteAdaptTC::SetParDiscreteTargetSpec(const ParGridFunction &tspec_) { SetParDiscreteTargetSize(tspec_); - if (tspec_fesv == NULL) { FinalizeParDiscreteTargetSpec(); } + FinalizeParDiscreteTargetSpec(tspec_); } #endif -void DiscreteAdaptTC::SetSerialDiscreteTargetBase(const GridFunction &tspec_) +void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_) { const int vdim = tspec_.FESpace()->GetVDim(), dof_cnt = tspec_.Size()/vdim; ncomp += vdim; - if (tspec_fes == NULL) - { - tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), - tspec_.FESpace()->FEColl(), - 1); - // we don't do tspec_.FESpace() here because it can be a vector FESpace - // for 3D cases (e.g., aspect ratio has 3 components in 3D). - - tspec = tspec_; - - return; - } + delete tspec_fes; + tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), + tspec_.FESpace()->FEColl(), + 1); // need to append data to tspec // make a copy of tspec->tspec_temp, increase its size, and @@ -1060,10 +1066,8 @@ void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_) { tspec(i+idx*dof_cnt) = tspec_(i); } - for (int i = 0; i < dof_cnt*vdim; i++) - { - tspec_sav(i+idx*dof_cnt) = tspec_(i); - } + + FinalizeSerialDiscreteTargetSpec(); } void DiscreteAdaptTC::SetSerialDiscreteTargetSize(const GridFunction &tspec_) @@ -1071,28 +1075,34 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetSize(const GridFunction &tspec_) if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; } sizeidx = ncomp; - SetSerialDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeSerialDiscreteTargetSpec(); } void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(const GridFunction &tspec_) { if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; } skewidx = ncomp; - SetSerialDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeSerialDiscreteTargetSpec(); } -void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(const GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio( + const GridFunction &tspec_) { if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; } aspectratioidx = ncomp; - SetSerialDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeSerialDiscreteTargetSpec(); } -void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(const GridFunction &tspec_) +void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation( + const GridFunction &tspec_) { if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; } orientationidx = ncomp; - SetSerialDiscreteTargetBase(tspec_); + SetDiscreteTargetBase(tspec_); + FinalizeSerialDiscreteTargetSpec(); } void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() @@ -1105,6 +1115,8 @@ void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec); tspec_sav = tspec; + + delete tspec_fesv; tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(), tspec_fes->FEColl(), ncomp); } @@ -1112,7 +1124,7 @@ void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec() void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(const GridFunction &tspec_) { SetSerialDiscreteTargetSize(tspec_); - if (tspec_fesv == NULL) { FinalizeSerialDiscreteTargetSpec(); } + FinalizeSerialDiscreteTargetSpec(); } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 536f8b3986..3b223123f0 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -722,9 +722,6 @@ protected: // Note: do not use the Nodes of this space as they may not be on the // positions corresponding to the values of tspec. -#ifdef MFEM_USE_MPI - ParFiniteElementSpace *ptspec_fes; -#endif const FiniteElementSpace *tspec_fes; const FiniteElementSpace *tspec_fesv; @@ -736,11 +733,13 @@ protected: // Owned. AdaptivityEvaluator *adapt_eval; - void SetSerialDiscreteTargetBase(const GridFunction &tspec_); -#ifdef MFEM_USE_MPI - void SetParDiscreteTargetBase(const ParGridFunction &tspec_); -#endif + void SetDiscreteTargetBase(const GridFunction &tspec_); void SetTspecAtIndex(int idx, const GridFunction &tspec_); + void FinalizeSerialDiscreteTargetSpec(); +#ifdef MFEM_USE_MPI + void SetTspecAtIndex(int idx, const ParGridFunction &tspec_); + void FinalizeParDiscreteTargetSpec(const ParGridFunction &tspec_); +#endif public: DiscreteAdaptTC(TargetType ttype) @@ -748,7 +747,7 @@ public: ncomp(0), sizeidx(-1), skewidx(-1), aspectratioidx(-1), orientationidx(-1), tspec(), tspec_sav(), tspec_pert1h(), tspec_pert2h(), tspec_pertmix(), - ptspec_fes(NULL), tspec_fes(NULL), tspec_fesv(NULL), + tspec_fes(NULL), tspec_fesv(NULL), good_tspec(false), good_tspec_grad(false), good_tspec_hess(false), adapt_eval(NULL) { } @@ -777,14 +776,12 @@ public: virtual void SetSerialDiscreteTargetSkew(const GridFunction &tspec_); virtual void SetSerialDiscreteTargetAspectRatio(const GridFunction &tspec_); virtual void SetSerialDiscreteTargetOrientation(const GridFunction &tspec_); - virtual void FinalizeSerialDiscreteTargetSpec(); #ifdef MFEM_USE_MPI virtual void SetParDiscreteTargetSpec(const ParGridFunction &tspec_); virtual void SetParDiscreteTargetSize(const ParGridFunction &tspec_); virtual void SetParDiscreteTargetSkew(const ParGridFunction &tspec_); virtual void SetParDiscreteTargetAspectRatio(const ParGridFunction &tspec_); virtual void SetParDiscreteTargetOrientation(const ParGridFunction &tspec_); - virtual void FinalizeParDiscreteTargetSpec(); #endif ///@} diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index bf090794e2..b3f66ef87f 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -78,172 +78,7 @@ using namespace mfem; using namespace std; -double weight_fun(const Vector &x); -void DiffuseField(GridFunction &field, int smooth_steps); - -double discrete_size_2d(const Vector &x) -{ - int opt = 2; - const double small = 0.001, big = 0.01; - double val = 0.; - - if (opt == 1) // sine wave. - { - const double X = x(0), Y = x(1); - val = std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) + 1) - - std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) - 1); - } - else if (opt == 2) // semi-circle - { - const double xc = x(0) - 0.0, yc = x(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.45; double r2 = 0.55; double sf=30.0; - val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); - } - - val = std::max(0.,val); - val = std::min(1.,val); - - return val * small + (1.0 - val) * big; -} - -double material_indicator_2d(const Vector &x) -{ - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; - double tfac = 20; - double s1 = 3; - double s2 = 3; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } - return wgt; -} - -double discrete_ori_2d(const Vector &x) -{ - return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); -} - -double discrete_aspr_2d(const Vector &x) -{ - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn; yc = yn; - - double tfac = 20; - double s1 = 3; - double s2 = 2; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) - - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } - return 0.1 + 1*(1-wgt)*(1-wgt); -} - -void discrete_aspr_3d(const Vector &x, Vector &v) -{ - int dim = x.Size(); - v.SetSize(dim); - double l1, l2, l3; - l1 = 1.; - l2 = 1. + 5*x(1); - l3 = 1. + 10*x(2); - v[0] = l1/pow(l2*l3,0.5); - v[1] = l2/pow(l1*l3,0.5); - v[2] = l3/pow(l2*l1,0.5); -} - -class HessianCoefficient : public MatrixCoefficient -{ -private: - int metric; - -public: - HessianCoefficient(int dim, int metric_id) - : MatrixCoefficient(dim), metric(metric_id) { } - - virtual void Eval(DenseMatrix &K, ElementTransformation &T, - const IntegrationPoint &ip) - { - Vector pos(3); - T.Transform(ip, pos); - if (metric != 14 && metric != 87) - { - const double xc = pos(0) - 0.5, yc = pos(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.15; double r2 = 0.35; double sf=30.0; - const double eps = 0.5; - - const double tan1 = std::tanh(sf*(r-r1)), - tan2 = std::tanh(sf*(r-r2)); - - K(0, 0) = eps + 1.0 * (tan1 - tan2); - K(0, 1) = 0.0; - K(1, 0) = 0.0; - K(1, 1) = 1.0; - } - else if (metric == 14) // Size + Alignment - { - const double xc = pos(0), yc = pos(1); - double theta = M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); - double alpha_bar = 0.1; - - K(0, 0) = cos(theta); - K(1, 0) = sin(theta); - K(0, 1) = -sin(theta); - K(1, 1) = cos(theta); - - K *= alpha_bar; - } - else if (metric == 87) // Shape + Alignment - { - Vector x = pos; - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - xc = xn; yc=yn; - - double tfac = 20; - double s1 = 3; - double s2 = 2; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) - - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); - if (wgt > 1) { wgt = 1; } - if (wgt < 0) { wgt = 0; } - - xc = pos(0), yc = pos(1); - double theta = M_PI * (yc) * (1.0 - yc) * cos(2 * M_PI * xc); - - K(0, 0) = cos(theta); - K(1, 0) = sin(theta); - K(0, 1) = -sin(theta); - K(1, 1) = cos(theta); - - double asp_ratio_tar = 0.1 + 1*(1-wgt)*(1-wgt); - - K(0, 0) *= 1/pow(asp_ratio_tar,0.5); - K(1, 0) *= 1/pow(asp_ratio_tar,0.5); - K(0, 1) *= pow(asp_ratio_tar,0.5); - K(1, 1) *= pow(asp_ratio_tar,0.5); - } - } -}; - -// Additional IntegrationRules that can be used with the --quad-type option. -IntegrationRules IntRulesLo(0, Quadrature1D::GaussLobatto); -IntegrationRules IntRulesCU(0, Quadrature1D::ClosedUniform); - +#include "mesh-optimizer.hpp" int main(int argc, char *argv[]) { @@ -518,7 +353,6 @@ int main(int argc, char *argv[]) FunctionCoefficient ind_coeff(discrete_size_2d); size.ProjectCoefficient(ind_coeff); tc->SetSerialDiscreteTargetSize(size); - tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; break; } @@ -561,16 +395,16 @@ int main(int argc, char *argv[]) d_y(i) = std::abs(d_y(i)); } const double eps = 0.01; - const double ratio = 20.0; - const double big_small_ratio = 40.0; + const double aspr_ratio = 20.0; + const double size_ratio = 40.0; for (int i = 0; i < size.Size(); i++) { size(i) = (size(i)/max); aspr(i) = (d_x(i)+eps)/(d_y(i)+eps); aspr(i) = 0.1 + 0.9*(1-size(i))*(1-size(i)); - if (aspr(i) > ratio) {aspr(i) = ratio;} - if (aspr(i) < 1.0/ratio) {aspr(i) = 1.0/ratio;} + if (aspr(i) > aspr_ratio) {aspr(i) = aspr_ratio;} + if (aspr(i) < 1.0/aspr_ratio) {aspr(i) = 1.0/aspr_ratio;} } Vector vals; const int NE = mesh->GetNE(); @@ -594,11 +428,11 @@ int main(int argc, char *argv[]) const double avg_zone_size = volume / NE; const double small_avg_ratio = (volume_ind + (volume - volume_ind) / - big_small_ratio) / + size_ratio) / volume; const double small_zone_size = small_avg_ratio * avg_zone_size; - const double big_zone_size = big_small_ratio * small_zone_size; + const double big_zone_size = size_ratio * small_zone_size; for (int i = 0; i < size.Size(); i++) { @@ -607,13 +441,11 @@ int main(int argc, char *argv[]) size(i) = big_zone_size / (1.0+a*val); } - DiffuseField(size, 2); DiffuseField(aspr, 2); tc->SetSerialDiscreteTargetSize(size); tc->SetSerialDiscreteTargetAspectRatio(aspr); - tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; break; } @@ -635,7 +467,6 @@ int main(int argc, char *argv[]) aspr3d.ProjectCoefficient(fd_aspr3d); tc->SetSerialDiscreteTargetAspectRatio(aspr3d); - tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; break; } @@ -672,7 +503,6 @@ int main(int argc, char *argv[]) FunctionCoefficient ori_coeff(discrete_ori_2d); ori.ProjectCoefficient(ori_coeff); tc->SetSerialDiscreteTargetOrientation(ori); - tc->FinalizeSerialDiscreteTargetSpec(); target_c = tc; break; } @@ -959,34 +789,3 @@ int main(int argc, char *argv[]) return 0; } - -// Defined with respect to the icf mesh. -double weight_fun(const Vector &x) -{ - const double r = sqrt(x(0)*x(0) + x(1)*x(1) + 1e-12); - const double den = 0.002; - double l2 = 0.2 + 0.5*std::tanh((r-0.16)/den) - 0.5*std::tanh((r-0.17)/den) - + 0.5*std::tanh((r-0.23)/den) - 0.5*std::tanh((r-0.24)/den); - return l2; -} - -void DiffuseField(GridFunction &field, int smooth_steps) -{ - //Setup the Laplacian operator - BilinearForm *Lap = new BilinearForm(field.FESpace()); - Lap->AddDomainIntegrator(new DiffusionIntegrator()); - Lap->Assemble(); - Lap->Finalize(); - - //Setup the smoothing operator - DSmoother *S = new DSmoother(0,1.0,smooth_steps); - S->iterative_mode = true; - S->SetOperator(Lap->SpMat()); - - Vector tmp(field.Size()); - tmp = 0.0; - S->Mult(tmp, field); - - delete S; - delete Lap; -} diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp new file mode 100644 index 0000000000..d859cfe13a --- /dev/null +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -0,0 +1,228 @@ +// MFEM Mesh Optimizer Miniapp - Serial/Parallel Shared Code + +#include "mfem.hpp" +#include +#include + +using namespace mfem; +using namespace std; + +double discrete_size_2d(const Vector &x) +{ + int opt = 2; + const double small = 0.001, big = 0.01; + double val = 0.; + + if (opt == 1) // sine wave. + { + const double X = x(0), Y = x(1); + val = std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) + 1) - + std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) - 1); + } + else if (opt == 2) // semi-circle + { + const double xc = x(0) - 0.0, yc = x(1) - 0.5; + const double r = sqrt(xc*xc + yc*yc); + double r1 = 0.45; double r2 = 0.55; double sf=30.0; + val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); + } + + val = std::max(0.,val); + val = std::min(1.,val); + + return val * small + (1.0 - val) * big; +} + +double material_indicator_2d(const Vector &x) +{ + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc = xn/stretch; yc = yn/stretch; + double tfac = 20; + double s1 = 3; + double s2 = 3; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + return wgt; +} + +double discrete_ori_2d(const Vector &x) +{ + return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); +} + +double discrete_aspr_2d(const Vector &x) +{ + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + double stretch = 1/cos(th2); + xc = xn; yc = yn; + + double tfac = 20; + double s1 = 3; + double s2 = 2; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) + - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + return 0.1 + 1*(1-wgt)*(1-wgt); +} + +void discrete_aspr_3d(const Vector &x, Vector &v) +{ + int dim = x.Size(); + v.SetSize(dim); + double l1, l2, l3; + l1 = 1.; + l2 = 1. + 5*x(1); + l3 = 1. + 10*x(2); + v[0] = l1/pow(l2*l3,0.5); + v[1] = l2/pow(l1*l3,0.5); + v[2] = l3/pow(l2*l1,0.5); +} + +class HessianCoefficient : public MatrixCoefficient +{ +private: + int metric; + +public: + HessianCoefficient(int dim, int metric_id) + : MatrixCoefficient(dim), metric(metric_id) { } + + virtual void Eval(DenseMatrix &K, ElementTransformation &T, + const IntegrationPoint &ip) + { + Vector pos(3); + T.Transform(ip, pos); + if (metric != 14 && metric != 87) + { + const double xc = pos(0) - 0.5, yc = pos(1) - 0.5; + const double r = sqrt(xc*xc + yc*yc); + double r1 = 0.15; double r2 = 0.35; double sf=30.0; + const double eps = 0.5; + + const double tan1 = std::tanh(sf*(r-r1)), + tan2 = std::tanh(sf*(r-r2)); + + K(0, 0) = eps + 1.0 * (tan1 - tan2); + K(0, 1) = 0.0; + K(1, 0) = 0.0; + K(1, 1) = 1.0; + } + else if (metric == 14) // Size + Alignment + { + const double xc = pos(0), yc = pos(1); + double theta = M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); + double alpha_bar = 0.1; + + K(0, 0) = cos(theta); + K(1, 0) = sin(theta); + K(0, 1) = -sin(theta); + K(1, 1) = cos(theta); + + K *= alpha_bar; + } + else if (metric == 87) // Shape + Alignment + { + Vector x = pos; + double xc = x(0)-0.5, yc = x(1)-0.5; + double th = 22.5*M_PI/180.; + double xn = cos(th)*xc + sin(th)*yc; + double yn = -sin(th)*xc + cos(th)*yc; + xc = xn; yc=yn; + + double tfac = 20; + double s1 = 3; + double s2 = 2; + double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) + - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); + if (wgt > 1) { wgt = 1; } + if (wgt < 0) { wgt = 0; } + + xc = pos(0), yc = pos(1); + double theta = M_PI * (yc) * (1.0 - yc) * cos(2 * M_PI * xc); + + K(0, 0) = cos(theta); + K(1, 0) = sin(theta); + K(0, 1) = -sin(theta); + K(1, 1) = cos(theta); + + double asp_ratio_tar = 0.1 + 1*(1-wgt)*(1-wgt); + + K(0, 0) *= 1/pow(asp_ratio_tar,0.5); + K(1, 0) *= 1/pow(asp_ratio_tar,0.5); + K(0, 1) *= pow(asp_ratio_tar,0.5); + K(1, 1) *= pow(asp_ratio_tar,0.5); + } + } +}; + +// Additional IntegrationRules that can be used with the --quad-type option. +IntegrationRules IntRulesLo(0, Quadrature1D::GaussLobatto); +IntegrationRules IntRulesCU(0, Quadrature1D::ClosedUniform); + +// Defined with respect to the icf mesh. +double weight_fun(const Vector &x) +{ + const double r = sqrt(x(0)*x(0) + x(1)*x(1) + 1e-12); + const double den = 0.002; + double l2 = 0.2 + 0.5*std::tanh((r-0.16)/den) - 0.5*std::tanh((r-0.17)/den) + + 0.5*std::tanh((r-0.23)/den) - 0.5*std::tanh((r-0.24)/den); + return l2; +} + +void DiffuseField(GridFunction &field, int smooth_steps) +{ + //Setup the Laplacian operator + BilinearForm *Lap = new BilinearForm(field.FESpace()); + Lap->AddDomainIntegrator(new DiffusionIntegrator()); + Lap->Assemble(); + Lap->Finalize(); + + //Setup the smoothing operator + DSmoother *S = new DSmoother(0,1.0,smooth_steps); + S->iterative_mode = true; + S->SetOperator(Lap->SpMat()); + + Vector tmp(field.Size()); + tmp = 0.0; + S->Mult(tmp, field); + + delete S; + delete Lap; +} + +#ifdef MFEM_USE_MPI +void DiffuseField(ParGridFunction &field, int smooth_steps) +{ + //Setup the Laplacian operator + ParBilinearForm *Lap = new ParBilinearForm(field.ParFESpace()); + Lap->AddDomainIntegrator(new DiffusionIntegrator()); + Lap->Assemble(); + Lap->Finalize(); + HypreParMatrix *A = Lap->ParallelAssemble(); + + HypreSmoother *S = new HypreSmoother(*A,0,smooth_steps); + S->iterative_mode = true; + + Vector tmp(A->Width()); + field.SetTrueVector(); + Vector fieldtrue = field.GetTrueVector(); + tmp = 0.0; + S->Mult(tmp, fieldtrue); + + field.SetFromTrueDofs(fieldtrue); + + delete S; + delete Lap; +} +#endif diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index c0ca24ec67..abcc66df30 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -77,168 +77,7 @@ using namespace mfem; using namespace std; -double weight_fun(const Vector &x); -void DiffuseField(ParGridFunction &field, int smooth_steps); - -double discrete_size_2d(const Vector &x) -{ - int opt = 2; - const double small = 0.001, big = 0.01; - double val = 0.; - - if (opt == 1) // sine wave - { - const double X = x(0), Y = x(1); - val = std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) + 1) - - std::tanh((10*(Y-0.5) + std::sin(4.0*M_PI*X)) - 1); - } - else if (opt == 2) // semi-circle - { - const double xc = x(0) - 0.0, yc = x(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.45; double r2 = 0.55; double sf=30.0; - val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); - } - - val = std::max(0.,val); - val = std::min(1.,val); - - return val * small + (1.0 - val) * big; -} - -double material_indicator_2d(const Vector &x) -{ - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); - xc = xn/stretch; yc = yn/stretch; - double tfac = 20; - double s1 = 3; - double s2 = 3; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1); - wgt = std::max(0., wgt); - wgt = std::min(1., wgt); - return wgt; -} - -double discrete_ori_2d(const Vector &x) -{ - return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0)); -} - -double discrete_aspr_2d(const Vector &x) -{ - double xc = x(0)-0.5, yc = x(1)-0.5; - double th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - xc = xn; yc = yn; - - double tfac = 20; - double s1 = 3; - double s2 = 2; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) - - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); - wgt = std::max(0., wgt); - wgt = std::min(1., wgt); - return 0.1 + 1*(1-wgt)*(1-wgt); -} - -void discrete_aspr_3d(const Vector &x, Vector &v) -{ - int dim = x.Size(); - v.SetSize(dim); - double l1, l2, l3; - l1 = 1.; - l2 = 1. + 5*x(1); - l3 = 1. + 10*x(2); - v[0] = l1/pow(l2*l3,0.5); - v[1] = l2/pow(l1*l3,0.5); - v[2] = l3/pow(l2*l1,0.5); -} - -class HessianCoefficient : public MatrixCoefficient -{ -private: - int metric; - -public: - HessianCoefficient(int dim, int metric_id) - : MatrixCoefficient(dim), metric(metric_id) { } - - virtual void Eval(DenseMatrix &K, ElementTransformation &T, - const IntegrationPoint &ip) - { - Vector pos(3); - T.Transform(ip, pos); - if (metric != 14 && metric != 87) - { - const double xc = pos(0) - 0.5, yc = pos(1) - 0.5; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.15; double r2 = 0.35; double sf=30.0; - const double eps = 0.5; - - const double tan1 = std::tanh(sf*(r-r1)), - tan2 = std::tanh(sf*(r-r2)); - - K(0, 0) = eps + 1.0 * (tan1 - tan2); - K(0, 1) = 0.0; - K(1, 0) = 0.0; - K(1, 1) = 1.0; - } - else if (metric == 14) // Size + Alignment - { - const double xc = pos(0), yc = pos(1); - double theta = M_PI * yc * (1.0 - yc) * cos(2 * M_PI * xc); - double alpha_bar = 0.1; - - K(0, 0) = cos(theta); - K(1, 0) = sin(theta); - K(0, 1) = -sin(theta); - K(1, 1) = cos(theta); - - K *= alpha_bar; - } - else if (metric == 87) // Shape + Size + Alignment - { - Vector x = pos; - double xc = x(0)-0.5, yc = x(1)-0.5, - th = 22.5*M_PI/180.; - double xn = cos(th)*xc + sin(th)*yc; - double yn = -sin(th)*xc + cos(th)*yc; - xc = xn; yc=yn; - - double tfac = 20, s1 = 3, s2 = 2; - double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1) - - std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1); - wgt = std::max(0., wgt); - wgt = std::min(1., wgt); - - xc = pos(0), yc = pos(1); - double theta = M_PI * (yc) * (1.0 - yc) * cos(2 * M_PI * xc); - - K(0, 0) = cos(theta); - K(1, 0) = sin(theta); - K(0, 1) = -sin(theta); - K(1, 1) = cos(theta); - - double asp_ratio_tar = 0.1 + 1*(1-wgt)*(1-wgt); - - K(0, 0) *= 1/pow(asp_ratio_tar,0.5); - K(1, 0) *= 1/pow(asp_ratio_tar,0.5); - K(0, 1) *= pow(asp_ratio_tar,0.5); - K(1, 1) *= pow(asp_ratio_tar,0.5); - } - } -}; - - -// Additional IntegrationRules that can be used with the --quad-type option. -IntegrationRules IntRulesLo(0, Quadrature1D::GaussLobatto); -IntegrationRules IntRulesCU(0, Quadrature1D::ClosedUniform); +#include "mesh-optimizer.hpp" int main (int argc, char *argv[]) { @@ -544,7 +383,6 @@ int main (int argc, char *argv[]) FunctionCoefficient ind_coeff(discrete_size_2d); size.ProjectCoefficient(ind_coeff); tc->SetParDiscreteTargetSize(size); - tc->FinalizeParDiscreteTargetSpec(); target_c = tc; break; } @@ -588,16 +426,16 @@ int main (int argc, char *argv[]) d_y(i) = std::abs(d_y(i)); } const double eps = 0.01; - const double ratio = 20.0; - const double big_small_ratio = 40.0; + const double aspr_ratio = 20.0; + const double size_ratio = 40.0; for (int i = 0; i < size.Size(); i++) { size(i) = (size(i)/max_all); aspr(i) = (d_x(i)+eps)/(d_y(i)+eps); aspr(i) = 0.1 + 0.9*(1-size(i))*(1-size(i)); - if (aspr(i) > ratio) {aspr(i) = ratio;} - if (aspr(i) < 1.0/ratio) {aspr(i) = 1.0/ratio;} + if (aspr(i) > aspr_ratio) {aspr(i) = aspr_ratio;} + if (aspr(i) < 1.0/aspr_ratio) {aspr(i) = 1.0/aspr_ratio;} } Vector vals; const int NE = pmesh->GetNE(); @@ -627,11 +465,11 @@ int main (int argc, char *argv[]) const double avg_zone_size = volume_all / NE_ALL; const double small_avg_ratio = - (volume_ind_all + (volume_all - volume_ind_all) / big_small_ratio) + (volume_ind_all + (volume_all - volume_ind_all) / size_ratio) / volume_all; const double small_zone_size = small_avg_ratio * avg_zone_size; - const double big_zone_size = big_small_ratio * small_zone_size; + const double big_zone_size = size_ratio * small_zone_size; for (int i = 0; i < size.Size(); i++) { @@ -645,7 +483,6 @@ int main (int argc, char *argv[]) tc->SetParDiscreteTargetSize(size); tc->SetParDiscreteTargetAspectRatio(aspr); - tc->FinalizeParDiscreteTargetSpec(); target_c = tc; break; } @@ -666,8 +503,6 @@ int main (int argc, char *argv[]) VectorFunctionCoefficient fd_aspr3d(dim, discrete_aspr_3d); aspr3d.ProjectCoefficient(fd_aspr3d); tc->SetParDiscreteTargetAspectRatio(aspr3d); - - tc->FinalizeParDiscreteTargetSpec(); target_c = tc; break; } @@ -704,7 +539,6 @@ int main (int argc, char *argv[]) FunctionCoefficient ori_coeff(discrete_ori_2d); ori.ProjectCoefficient(ori_coeff); tc->SetParDiscreteTargetOrientation(ori); - tc->FinalizeParDiscreteTargetSpec(); target_c = tc; break; } @@ -1016,37 +850,3 @@ int main (int argc, char *argv[]) MPI_Finalize(); return 0; } - -// Defined with respect to the icf mesh. -double weight_fun(const Vector &x) -{ - const double r = sqrt(x(0)*x(0) + x(1)*x(1) + 1e-12); - const double den = 0.002; - double l2 = 0.2 + 0.5 * (std::tanh((r-0.16)/den) - std::tanh((r-0.17)/den) - + std::tanh((r-0.23)/den) - std::tanh((r-0.24)/den)); - return l2; -} - -void DiffuseField(ParGridFunction &field, int smooth_steps) -{ - //Setup the Laplacian operator - ParBilinearForm *Lap = new ParBilinearForm(field.ParFESpace()); - Lap->AddDomainIntegrator(new DiffusionIntegrator()); - Lap->Assemble(); - Lap->Finalize(); - HypreParMatrix *A = Lap->ParallelAssemble(); - - HypreSmoother *S = new HypreSmoother(*A,0,smooth_steps); - S->iterative_mode = true; - - Vector tmp(A->Width()); - field.SetTrueVector(); - Vector fieldtrue = field.GetTrueVector(); - tmp = 0.0; - S->Mult(tmp, fieldtrue); - - field.SetFromTrueDofs(fieldtrue); - - delete S; - delete Lap; -} From 57fbb7e7ab10611c2aec04e8b633b247e389f5bd Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Apr 2020 15:34:57 -0700 Subject: [PATCH 202/535] Bug fix and parallel implementation is now added along with relevant bug fixes --- fem/field_interpolant.cpp | 123 +++++++++++++++ fem/field_interpolant.hpp | 16 ++ tests/unit/fem/test_quadf_coef.cpp | 232 ++++++++++++++++++++++++++++- 3 files changed, 369 insertions(+), 2 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index c66318f03e..85ab009d59 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -32,6 +32,7 @@ void VectorQuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, for (int q = 0; q < nqp; q++) { const IntegrationPoint &ip = IntRule->IntPoint(q); + Tr.SetIntPoint(&ip); const double w = Tr.Weight() * ip.weight; vqfc.Eval(temp, Tr, ip); fe.CalcShape(ip, shape); @@ -57,6 +58,7 @@ void QuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, for (int q = 0; q < nqp; q++) { const IntegrationPoint &ip = IntRule->IntPoint(q); + Tr.SetIntPoint (&ip); const double w = Tr.Weight() * ip.weight; double temp = qfc.Eval(Tr, ip); fe.CalcShape(ip, shape); @@ -332,4 +334,125 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, delete b; } +#ifdef MFEM_USE_MPI +// This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector +// quadrature function coefficient. +void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + ParFiniteElementSpace &fes) +{ + const IntegrationRule* ir; + { + // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + // and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes.GetFE(0); + ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const QuadratureFunction* qf = vqfc.GetQuadFunction(); + const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && + (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + } + + ParLinearForm *b = new ParLinearForm(&fes); + b->AddDomainIntegrator(new VectorQuadratureIntegrator(vqfc, ir)); + b->Assemble(); + + // We need this fes to only have a vdim of 1 which is not the case here so we need to make a new fespace + // Potential fix me with a better implementation + const FiniteElementCollection *fec = fes.FEColl(); + ParMesh *mesh = fes.GetParMesh(); + ParFiniteElementSpace fes_v1(mesh, fec, 1); + + ParBilinearForm *L2 = new ParBilinearForm(&fes_v1); + L2->AddDomainIntegrator(new MassIntegrator(ir)); + L2->Assemble(); + + ParGridFunction x(&fes); + x = 0.0; + OperatorPtr A; + Vector B, b_sub, X_sub, X; + + Array ess_tdof_list; + + int vdim = vqfc.GetVDim(); + int size = b->Size() / vdim; + + CGSolver cg(MPI_COMM_WORLD); + cg.SetPrintLevel(0); + cg.SetMaxIter(2000); + cg.SetRelTol(sqrt(1e-25)); + cg.SetAbsTol(sqrt(0.0)); + + for (int ind = 0; ind < vdim; ind++) + { + int offset = ind * size; + b_sub.MakeRef(*b, offset, size); + X_sub.MakeRef(x, offset, size); + L2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); + // Fix this to be more efficient + // OperatorJacobiSmoother M(*L2, ess_tdof_list); + // CG(*A, B, X, 0, 2000, 1e-25, 0.0); + cg.SetOperator(*A); + cg.Mult(B, X); + // Recover the solution as a finite element grid function. + L2->RecoverFEMSolution(X, *b, X_sub); + } + gf = x; + + delete L2; + delete b; +} +// This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as +// quadrature function coefficient. +void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, + QuadratureFunctionCoefficient &qfc, + ParFiniteElementSpace &fes) +{ + const IntegrationRule* ir; + { + // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + // and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes.GetFE(0); + ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const QuadratureFunction* qf = qfc.GetQuadFunction(); + const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && + (ir->GetNPoints() == ir_qf->GetNPoints()), + "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + } + ParLinearForm *b = new ParLinearForm(&fes); + b->AddDomainIntegrator(new QuadratureIntegrator(qfc, ir)); + b->Assemble(); + + ParBilinearForm *L2 = new ParBilinearForm(&fes); + L2->AddDomainIntegrator(new MassIntegrator(ir)); + L2->Assemble(); + + ParGridFunction x(&fes); + x = 0.0; + OperatorPtr A; + Vector B, X; + Array ess_tdof_list; + + L2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + // Fix this to be more efficient + // OperatorJacobiSmoother M(*L2, ess_tdof_list); + // CG(*A, B, X, 0, 2000, 1e-25, 0.0); + CGSolver cg(MPI_COMM_WORLD); + cg.SetPrintLevel(0); + cg.SetMaxIter(2000); + cg.SetRelTol(sqrt(1e-25)); + cg.SetAbsTol(sqrt(0.0)); + cg.SetOperator(*A); + cg.Mult(B, X); + // Recover the solution as a finite element grid function. + L2->RecoverFEMSolution(X, *b, x); + gf = x; + + delete L2; + delete b; +} +#endif + } \ No newline at end of file diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 71a019d488..218b9ea9cc 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -21,6 +21,10 @@ #include "coefficient.hpp" #include "bilininteg.hpp" #include "lininteg.hpp" +#include "gridfunc.hpp" +#ifdef MFEM_USE_MPI +#include "pgridfunc.hpp" +#endif namespace mfem { @@ -60,6 +64,18 @@ public: void ProjectQuadratureCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, FiniteElementSpace &fes); +#ifdef MFEM_USE_MPI + // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector + // quadrature function coefficient. + void ProjectQuadratureCoefficient(ParGridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + ParFiniteElementSpace &fes); + // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as + // quadrature function coefficient. + void ProjectQuadratureCoefficient(ParGridFunction &gf, + QuadratureFunctionCoefficient &qfc, + ParFiniteElementSpace &fes); +#endif //Tells the ProjectQuadratureDiscCoefficient that they need to recalculate the data. void SetupDiscReset() { setup_disc = false; } ~FieldInterpolant() {} diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 624806537d..a03561f36d 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -20,10 +20,11 @@ namespace qf_coeff TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients]") { - int order_h1 = 1, n = 3, dim = 3; + int order_h1 = 2, n = 4, dim = 3; double tol = 1e-9; Mesh mesh(n, n, n, Element::HEXAHEDRON, false, 1.0, 1.0, 1.0); + mesh.SetCurvature(order_h1); int intOrder = 2 * order_h1 + 1; @@ -90,7 +91,7 @@ TEST_CASE("Quadrature Function Coefficients", L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); @@ -212,5 +213,232 @@ TEST_CASE("Quadrature Function Coefficients", } } +#ifdef MFEM_USE_MPI + +TEST_CASE("Parallel Quadrature Function Coefficients", + "[Parallel] , [Parallel Quadrature Function Coefficients]") +{ + int order_h1 = 2, n = 4, dim = 3; + double tol = 1e-9; + + Mesh *tmesh = new Mesh(n, n, n, Element::HEXAHEDRON, false, 1.0, 1.0, 1.0); + tmesh->SetCurvature(order_h1); + ParMesh mesh(MPI_COMM_WORLD, *tmesh); + + delete tmesh; + + int intOrder = 2 * order_h1 + 1; + + QuadratureSpace qspace(&mesh, intOrder); + QuadratureFunction quadf_coeff(&qspace, 1); + QuadratureFunction quadf_vcoeff(&qspace, dim); + + const IntegrationRule ir = qspace.GetElementIntRule(0); + + const GeometricFactors *geom_facts = mesh.GetGeometricFactors(ir, + GeometricFactors::COORDINATES); + + { + int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim() / ir.GetNPoints(); + int vdim = ir.GetNPoints(); + + for (int i = 0; i < nelems; i++) + { + for (int j = 0; j < vdim; j++) + { + //X has dims nqpts x sdim x ne + quadf_coeff((i * vdim) + j) = geom_facts->X((i * vdim * dim) + (vdim * 2) + j ); + } + } + } + + { + //More like nelems * nqpts + int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim(); + int vdim = quadf_vcoeff.GetVDim(); + + for (int i = 0; i < nelems; i++) + { + for (int j = 0; j < vdim; j++) + { + quadf_vcoeff((i * vdim) + j) = j; + } + } + } + + QuadratureFunctionCoefficient qfc(&quadf_coeff); + VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); + + FieldInterpolant fi(&ir); + + SECTION("Operators on VecQuadFuncCoeff") + { + std::cout << "Testing VecQuadFuncCoeff: " << std::endl; +#ifdef MFEM_USE_EXCEPTIONS + std::cout << " Setting Component" << std::endl; + REQUIRE_THROWS(qfvc.SetComponent(3, 1)); + REQUIRE_THROWS(qfvc.SetComponent(-1, 1)); + REQUIRE_NOTHROW(qfvc.SetComponent(1, 2)); + REQUIRE_THROWS(qfvc.SetComponent(0, 4)); + REQUIRE_THROWS(qfvc.SetComponent(1, 3)); + REQUIRE_NOTHROW(qfvc.SetComponent(0, 2)); + REQUIRE_THROWS(qfvc.SetComponent(0, 0)); +#endif + qfvc.SetComponent(0, 3); + + SECTION("Gridfunction L2 tests") + { + std::cout << " Testing GridFunc L2 projection" << std::endl; + L2_FECollection fec_l2(order_h1, dim); + ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); + ParGridFunction g0(&fespace_l2); + ParGridFunction gtrue(&fespace_l2); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { + gtrue((i * nnodes) + j) = i; + } + } + } + + g0 = 0.0; + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + gtrue -= g0; + + double lerr = gtrue.Norml2(); + double error = 0; + + MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + REQUIRE(error < tol); + } + + SECTION("Gridfunction H1 tests") + { + std::cout << " Testing GridFunc H1 projection" << std::endl; + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); + ParGridFunction g0(&fespace_h1); + ParGridFunction gtrue(&fespace_h1); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { + gtrue((i * nnodes) + j) = i; + } + } + } + + g0 = 0.0; + fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + gtrue -= g0; + + double lerr = gtrue.Norml2(); + double error = 0; + + MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + REQUIRE(error < tol); + } + } + + SECTION("Operators on QuadFuncCoeff") + { + SECTION("Gridfunction L2 tests") + { + std::cout << "Testing QuadFuncCoeff:"; + std::cout << " Testing GridFunc L2 projection" << std::endl; + L2_FECollection fec_l2(order_h1, dim); + ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); + ParGridFunction g0(&fespace_l2); + ParGridFunction gtrue(&fespace_l2); + + fi.SetupDiscReset(); + + // When using an L2 FE space of the same order as the mesh, the below highlights + // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. + { + int ne = mesh.GetNE(); + + ParGridFunction nodes(&fespace_h1); + Vector el_x; + Array vdofs; + mesh.GetNodes(nodes); + for (int i = 0; i < ne; i++) + { + fespace_h1.GetElementVDofs(i, vdofs); + nodes.GetSubVector(vdofs, el_x); + // Should be constant across all elements + int enodes = el_x.Size() / dim; + for (int j = 0; j < enodes; j++) + { + gtrue(j + i * enodes) = el_x(enodes * 2 + j); + } + } + } + + g0 = 0.0; + fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_h1, fespace_l2); + gtrue -= g0; + + double lerr = gtrue.Norml2(); + double error = 0; + + MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + REQUIRE(error < tol); + } + + SECTION("Gridfunction H1 tests") + { + std::cout << " Testing GridFunc H1 projection" << std::endl; + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); + ParGridFunction g0(&fespace_h1); + ParGridFunction gtrue(&fespace_h1); + + { + int nnodes = gtrue.Size(); + int vdim = 1; + + Vector nodes; + mesh.GetNodes(nodes); + for (int i = 0; i < nnodes; i++) + { + gtrue(i) = nodes(i * dim + 2); + } + } + + g0 = 0.0; + fi.ProjectQuadratureCoefficient(g0, qfc, fespace_h1); + gtrue -= g0; + + double lerr = gtrue.Norml2(); + double error = 0; + + MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + REQUIRE(error < tol); + } + } + +#endif +} + } // namespace qf_coeff From 75dab15fc8c7405280bba8434957d42f2033f891 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Apr 2020 16:49:41 -0700 Subject: [PATCH 203/535] Fixed bracket in wrong place for ifdef --- tests/unit/fem/test_quadf_coef.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index a03561f36d..ce56479c15 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -436,9 +436,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", REQUIRE(error < tol); } } - -#endif } - +#endif } // namespace qf_coeff From 18b488d14db596708e52d181edf6ba0ac4593245 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Apr 2020 16:50:20 -0700 Subject: [PATCH 204/535] Get rid of reorder warning --- fem/field_interpolant.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 218b9ea9cc..d1c1bcb4de 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -89,8 +89,8 @@ public: VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc( vqfc) { } VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc, - const IntegrationRule *ir) : vqfc( - vqfc), LinearFormIntegrator(ir) { } + const IntegrationRule *ir) : LinearFormIntegrator(ir), vqfc( + vqfc) { } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, @@ -104,7 +104,7 @@ private: public: QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } QuadratureIntegrator(QuadratureFunctionCoefficient &qfc, - const IntegrationRule *ir) : qfc(qfc), LinearFormIntegrator(ir) { } + const IntegrationRule *ir) : LinearFormIntegrator(ir), qfc(qfc) { } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, From e38ae35cebb756d34031028139f9e03f5ca35a52 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Apr 2020 17:45:47 -0700 Subject: [PATCH 205/535] Add tests for FiniteElementSpace Ordering::ByVDIM and bug fixes to have it work correctly --- fem/field_interpolant.cpp | 132 +++++++++++++++++------------ tests/unit/fem/test_quadf_coef.cpp | 123 +++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 54 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 85ab009d59..0832e5ff0b 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -122,55 +122,22 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } double* data = m_all_data.HostReadWrite(); - if (fes.GetOrdering() == Ordering::byNODES) + for (int e = 0; e < NE; e++) { - for (int e = 0; e < NE; e++) + qfv = 0.0; + mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); + inv.Factor(mi); + const FiniteElement &fe = *tr_fes.GetFE(e); + ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); + qi.AssembleRHSElementVect(fe, eltr, rhs); + for (int ind = 0; ind < vdim; ind++) { - qfv = 0.0; - mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(mi); - const FiniteElement &fe = *tr_fes.GetFE(e); - ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); - qi.AssembleRHSElementVect(fe, eltr, rhs); - for (int ind = 0; ind < vdim; ind++) - { - qfv_sub.MakeRef(qfv, ndofs * ind); - rhs_sub.MakeRef(rhs, ndofs * ind); - inv.Mult(rhs_sub, qfv_sub); - } - fes.GetElementVDofs(e, dofs); - gf.SetSubVector(dofs, qfv); - } - } - else - { - Vector tmp(qfv); - for (int e = 0; e < NE; e++) - { - mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(mi); - const FiniteElement &fe = *tr_fes.GetFE(e); - ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); - qi.AssembleRHSElementVect(fe, eltr, rhs); - for (int ind = 0; ind < vdim; ind++) - { - qfv_sub.MakeRef(qfv, ndofs * ind); - rhs_sub.MakeRef(rhs, ndofs * ind); - inv.Mult(rhs_sub, qfv_sub); - } - - //Now to reorder the vec from byNodes order to byVec - tmp = qfv; - for (int ind = 0; ind < vdim; ind++) - { - for (int nd = 0; nd < ndofs; nd++) - { - qfv((nd * vdim) + ind) = tmp(nd + ind * ndofs); - } - } - fes.GetElementVDofs(e, dofs); - gf.SetSubVector(dofs, qfv); + qfv_sub.MakeRef(qfv, ndofs * ind); + rhs_sub.MakeRef(rhs, ndofs * ind); + inv.Mult(rhs_sub, qfv_sub); } + fes.GetElementVDofs(e, dofs); + gf.SetSubVector(dofs, qfv); } } @@ -251,10 +218,28 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); } + int vdim = vqfc.GetVDim(); + int size = gf.Size() / vdim; + LinearForm *b = new LinearForm(&fes); b->AddDomainIntegrator(new VectorQuadratureIntegrator(vqfc, ir)); b->Assemble(); + // If our FES is byVDIM then we're going to rearrange b to be in byNodes order + if (fes.GetOrdering() == Ordering::byVDIM) + { + Vector tmp = *b; + double* data = b->HostReadWrite(); + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < size; j++) + { + data[j + i * size] = tmp(i + j * vdim); + } + } + } + + // We need this fes to only have a vdim of 1 which is not the case here so we need to make a new fespace // Potential fix me with a better implementation const FiniteElementCollection *fec = fes.FEColl(); @@ -272,9 +257,6 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, Array ess_tdof_list; - int vdim = vqfc.GetVDim(); - int size = b->Size() / vdim; - for (int ind = 0; ind < vdim; ind++) { int offset = ind * size; @@ -287,7 +269,21 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, // Recover the solution as a finite element grid function. L2->RecoverFEMSolution(X, *b, X_sub); } - gf = x; + + if (fes.GetOrdering() == Ordering::byNODES) + { + gf = x; + } + else + { + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < size; j++) + { + gf(i + j * vdim) = x(i * size + j); + } + } + } delete L2; delete b; @@ -354,10 +350,27 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); } + int vdim = vqfc.GetVDim(); + int size = gf.Size() / vdim; + ParLinearForm *b = new ParLinearForm(&fes); b->AddDomainIntegrator(new VectorQuadratureIntegrator(vqfc, ir)); b->Assemble(); + // If our FES is byVDIM then we're going to rearrange b to be in byNodes order + if (fes.GetOrdering() == Ordering::byVDIM) + { + Vector tmp = *b; + double* data = b->HostReadWrite(); + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < size; j++) + { + data[j + i * size] = tmp(i + j * vdim); + } + } + } + // We need this fes to only have a vdim of 1 which is not the case here so we need to make a new fespace // Potential fix me with a better implementation const FiniteElementCollection *fec = fes.FEColl(); @@ -375,9 +388,6 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, Array ess_tdof_list; - int vdim = vqfc.GetVDim(); - int size = b->Size() / vdim; - CGSolver cg(MPI_COMM_WORLD); cg.SetPrintLevel(0); cg.SetMaxIter(2000); @@ -398,7 +408,21 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, // Recover the solution as a finite element grid function. L2->RecoverFEMSolution(X, *b, X_sub); } - gf = x; + + if (fes.GetOrdering() == Ordering::byNODES) + { + gf = x; + } + else + { + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < size; j++) + { + gf(i + j * vdim) = x(i * size + j); + } + } + } delete L2; delete b; diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index ce56479c15..c2c4c64be9 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -114,6 +114,35 @@ TEST_CASE("Quadrature Function Coefficients", REQUIRE(gtrue.Norml2() < tol); } + SECTION("Gridfunction L2 tests byVDIM") + { + std::cout << " Testing GridFunc L2 projection byVDIM" << std::endl; + L2_FECollection fec_l2(order_h1, dim); + FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim, Ordering::byVDIM); + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1, Ordering::byVDIM); + GridFunction g0(&fespace_l2); + GridFunction gtrue(&fespace_l2); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { + gtrue(i + (vdim * j)) = i; + } + } + } + + g0 = 0.0; + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + gtrue -= g0; + REQUIRE(gtrue.Norml2() < tol); + } + SECTION("Gridfunction H1 tests") { std::cout << " Testing GridFunc H1 projection" << std::endl; @@ -135,6 +164,32 @@ TEST_CASE("Quadrature Function Coefficients", } } + g0 = 0.0; + fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + gtrue -= g0; + REQUIRE(gtrue.Norml2() < tol); + } + SECTION("Gridfunction H1 tests byVDIM") + { + std::cout << " Testing GridFunc H1 projection byVDIM" << std::endl; + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); + GridFunction g0(&fespace_h1); + GridFunction gtrue(&fespace_h1); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { + gtrue(i + j * vdim) = i; + } + } + } + g0 = 0.0; fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); gtrue -= g0; @@ -321,6 +376,41 @@ TEST_CASE("Parallel Quadrature Function Coefficients", REQUIRE(error < tol); } + SECTION("Gridfunction L2 tests byVDIM") + { + std::cout << " Testing GridFunc L2 projection byVDIM" << std::endl; + L2_FECollection fec_l2(order_h1, dim); + ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, dim, Ordering::byVDIM); + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, 1, Ordering::byVDIM); + ParGridFunction g0(&fespace_l2); + ParGridFunction gtrue(&fespace_l2); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { + gtrue(i + (vdim * j)) = i; + } + } + } + + g0 = 0.0; + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + gtrue -= g0; + + double lerr = gtrue.Norml2(); + double error = 0; + + MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + REQUIRE(error < tol); + } + SECTION("Gridfunction H1 tests") { std::cout << " Testing GridFunc H1 projection" << std::endl; @@ -353,6 +443,39 @@ TEST_CASE("Parallel Quadrature Function Coefficients", REQUIRE(error < tol); } + + SECTION("Gridfunction H1 tests byVDIM") + { + std::cout << " Testing GridFunc H1 projection byVDIM" << std::endl; + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); + ParGridFunction g0(&fespace_h1); + ParGridFunction gtrue(&fespace_h1); + + { + int nnodes = gtrue.Size() / dim; + int vdim = dim; + + for (int i = 0; i < vdim; i++) + { + for (int j = 0; j < nnodes; j++) + { + gtrue(i + j * vdim) = i; + } + } + } + + g0 = 0.0; + fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + gtrue -= g0; + + double lerr = gtrue.Norml2(); + double error = 0; + + MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + REQUIRE(error < tol); + } } SECTION("Operators on QuadFuncCoeff") From bd424d6a89bbe4067ed6ee58f2953b3fe0c5b40d Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 23 Apr 2020 11:03:49 +0200 Subject: [PATCH 206/535] Debug init for Nmesh --- fem/fespace.cpp | 1 + mesh/mesh.cpp | 18 ++++++++++++++++++ mesh/mesh.hpp | 3 +++ miniapps/nurbs/CMakeLists.txt | 17 +++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 34220b648f..faf84927ef 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1473,6 +1473,7 @@ void FiniteElementSpace::UpdateNURBS() void FiniteElementSpace::GenerateFaceDofsFromBdr() { if (face_dof) { return; } + if (!mesh->BdrInfoAvailable()) { return; } Array face_dof_list; Array row; diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index e69e70a060..fd4c7258c8 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -3341,6 +3341,12 @@ void Mesh::Loader(std::istream &input, int generate_edges, } } } + else if (NURBSext) + { + { + Nodes->FESpace()->GenerateFaceDofsFromBdr(); + } + } // If a parse tag was supplied, keep reading the stream until the tag is // encountered. @@ -4782,6 +4788,18 @@ void Mesh::GetBdrElementFace(int i, int *f, int *o) const } } +bool Mesh::BdrInfoAvailable() const +{ + switch (Dim) + { + case 1: return (boundary != NULL); + case 2: return (be_to_edge != NULL); + case 3: return (be_to_face != NULL); + default: mfem_error("Mesh::GetBdrElementEdgeIndex: invalid dimension!"); + } + return false; +} + int Mesh::GetBdrElementEdgeIndex(int i) const { switch (Dim) diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index c67c9982fe..8c97f8da2c 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -896,6 +896,9 @@ public: Return the face index of boundary element i. (3D) */ int GetBdrElementEdgeIndex(int i) const; + // Checks if the info required for the above function is available. + bool BdrInfoAvailable() const; + /** @brief For the given boundary element, bdr_el, return its adjacent element and its info, i.e. 64*local_bdr_index+bdr_orientation. */ void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const; diff --git a/miniapps/nurbs/CMakeLists.txt b/miniapps/nurbs/CMakeLists.txt index 03815da6ea..b3bbf9c994 100644 --- a/miniapps/nurbs/CMakeLists.txt +++ b/miniapps/nurbs/CMakeLists.txt @@ -55,6 +55,13 @@ add_test(NAME nurbs_ex1_weak_mp_ser COMMAND $ -no-vis -m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0) +add_test(NAME nurbs_ex1_weak_patch_format_ser + COMMAND $ -no-vis + -m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0) + +add_test(NAME nurbs_ex1_weak_patch_format_r1_ser + COMMAND $ -no-vis + -m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1) if (MFEM_USE_MPI) add_mfem_miniapp(nurbs_ex1p @@ -77,6 +84,16 @@ if (MFEM_USE_MPI) -m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0 ${MPIEXEC_POSTFLAGS}) +add_test(NAME nurbs_ex1_weak_patch_format_np=4 + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} + ${MPIEXEC_PREFLAGS} $ -no-vis + -m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0) + +add_test(NAME nurbs_ex1_weak_patch_format_r1_np=4 + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} + ${MPIEXEC_PREFLAGS} $ -no-vis + -m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1) + add_mfem_miniapp(nurbs_ex11p MAIN nurbs_ex11p.cpp LIBRARIES mfem) From e95687faaa07e909c7d230a5856fde2c1fa6fcc1 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 23 Apr 2020 14:18:48 +0200 Subject: [PATCH 207/535] Adding multi patch mesh in patch format to data --- data/square-disc-nurbs-patch.mesh | 155 ++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 data/square-disc-nurbs-patch.mesh diff --git a/data/square-disc-nurbs-patch.mesh b/data/square-disc-nurbs-patch.mesh new file mode 100644 index 0000000000..4e9668a6c8 --- /dev/null +++ b/data/square-disc-nurbs-patch.mesh @@ -0,0 +1,155 @@ +MFEM NURBS mesh v1.0 + +dimension +2 + +elements +5 +1 3 0 3 7 4 +1 3 3 2 6 7 +1 3 2 1 5 6 +1 3 1 0 4 5 +1 3 2 8 9 1 + +boundary +10 +1 1 0 3 +2 1 3 2 +2 1 1 0 +2 1 2 8 +2 1 9 1 +3 1 7 4 +3 1 6 7 +3 1 5 6 +3 1 4 5 +4 1 8 9 + +edges +15 +0 0 4 +0 3 7 +0 1 5 +0 2 6 +1 0 3 +1 4 7 +2 3 2 +2 7 6 +2 1 0 +2 5 4 +1 2 1 +1 6 5 +1 8 9 +3 2 8 +3 1 9 + +vertices +10 + +patches + +knotvectors +2 +2 3 0 0 0 1 1 1 +2 4 0 0 0 0.5 1 1 1 + +dimension +2 + +controlpoints_cartesian +-5 5 1 +-5 3.92523e-16 1 +-5 -5 1 +-2.47593 2.47593 1 +-4.95187 6.06429e-16 0.707107 +-2.47593 -2.47593 1 +-0.424264 0.424264 1 +-0.848528 1.03915e-16 0.707107 +-0.424264 -0.424264 1 +-0.353553 0.353553 1 +-0.707107 8.65956e-17 0.707107 +-0.353553 -0.353553 1 + +knotvectors +2 +2 3 0 0 0 1 1 1 +2 4 0 0 0 0.5 1 1 1 + +dimension +2 + +controlpoints_cartesian +-5 -5 1 +-1.17757e-15 -5 1 +5 -5 1 +-2.47593 -2.47593 1 +-9.09644e-16 -4.95187 0.707107 +2.47593 -2.47593 1 +-0.424264 -0.424264 1 +-1.55872e-16 -0.848528 0.707107 +0.424264 -0.424264 1 +-0.353553 -0.353553 1 +-1.29893e-16 -0.707107 0.707107 +0.353553 -0.353553 1 + +knotvectors +2 +2 3 0 0 0 1 1 1 +2 4 0 0 0 0.5 1 1 1 + +dimension +2 + +controlpoints_cartesian +5 -5 1 +5 -1.17757e-15 1 +5 5 1 +2.47593 -2.47593 1 +4.95187 -1.21286e-15 0.707107 +2.47593 2.47593 1 +0.424264 -0.424264 1 +0.848528 -2.07829e-16 0.707107 +0.424264 0.424264 1 +0.353553 -0.353553 1 +0.707107 -1.73191e-16 0.707107 +0.353553 0.353553 1 + +knotvectors +2 +2 3 0 0 0 1 1 1 +2 4 0 0 0 0.5 1 1 1 + +dimension +2 + +controlpoints_cartesian +5 5 1 +3.92523e-16 5 1 +-5 5 1 +2.47593 2.47593 1 +3.03215e-16 4.95187 0.707107 +-2.47593 2.47593 1 +0.424264 0.424264 1 +5.19574e-17 0.848528 0.707107 +-0.424264 0.424264 1 +0.353553 0.353553 1 +4.32978e-17 0.707107 0.707107 +-0.353553 0.353553 1 + +knotvectors +2 +2 3 0 0 0 1 1 1 +2 3 0 0 0 1 1 1 + +dimension +2 + +controlpoints_cartesian +5 -5 1 +10 -5 1 +15 -5 1 +5 0 1 +10 0 1 +15 0 1 +5 5 1 +10 5 1 +15 5 1 From a5ef20ee9aaff8caa74fb2129f566458771d46e8 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 23 Apr 2020 14:52:38 +0200 Subject: [PATCH 208/535] Correct mesh file in test --- miniapps/nurbs/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miniapps/nurbs/CMakeLists.txt b/miniapps/nurbs/CMakeLists.txt index b3bbf9c994..06cfd66bd0 100644 --- a/miniapps/nurbs/CMakeLists.txt +++ b/miniapps/nurbs/CMakeLists.txt @@ -75,7 +75,8 @@ if (MFEM_USE_MPI) add_test(NAME nurbs_ex1p_lap_np=4 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} - ${MPIEXEC_PREFLAGS} $ -no-vis -m pipe-nurbs-2d.mesh -o 2 -no-ibp + ${MPIEXEC_PREFLAGS} $ -no-vis -m + ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -no-ibp ${MPIEXEC_POSTFLAGS}) add_test(NAME nurbs_ex1p_weak_mp_np=4 From 08bff51ce88e0c2acde6582ae1e5cfc539a350d6 Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 23 Apr 2020 11:30:11 -0700 Subject: [PATCH 209/535] Updated comments. --- fem/tmop.cpp | 2 +- fem/tmop.hpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index e8384c458d..e71c3539fa 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1182,7 +1182,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, const Vector &elfun, DenseTensor &Jtr) const { - MFEM_VERIFY(tspec_fesv, "A call to FinalizeDiscreteTargetSpec() is needed."); + MFEM_VERIFY(tspec_fesv, "No target specifications have been set."); switch (target_type) { diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 3b223123f0..210ec0ca3a 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -764,8 +764,6 @@ public: Note that every GridFunction given to the Set methods must use a H1_FECollection of the same order. The number of components must correspond to the type of geometric parameter and dimension. - Once the calls to the Set methods are complete, users are expected to - call a Finalize method. @param[in] tspec_ Input values of a geometric parameter. Note that the methods in this class support only functions that From 7102e5f53e56bf209bad5d265d58746de09f986b Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Thu, 23 Apr 2020 12:13:08 -0700 Subject: [PATCH 210/535] ading cube.mesh --- miniapps/meshing/cube.mesh | 439 +++++++++++++++++++++++++++++++++++++ 1 file changed, 439 insertions(+) create mode 100644 miniapps/meshing/cube.mesh diff --git a/miniapps/meshing/cube.mesh b/miniapps/meshing/cube.mesh new file mode 100644 index 0000000000..6b3a3e28ca --- /dev/null +++ b/miniapps/meshing/cube.mesh @@ -0,0 +1,439 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# PRISM = 6 +# + +dimension +3 + +elements +8 +1 5 0 1 4 3 9 10 13 12 +1 5 3 4 7 6 12 13 16 15 +1 5 12 13 16 15 21 22 25 24 +1 5 9 10 13 12 18 19 22 21 +1 5 10 11 14 13 19 20 23 22 +1 5 13 14 17 16 22 23 26 25 +1 5 4 5 8 7 13 14 17 16 +1 5 1 2 5 4 10 11 14 13 + +boundary +24 +3 3 0 3 4 1 +3 3 1 4 5 2 +3 3 3 6 7 4 +3 3 4 7 8 5 +3 3 18 19 22 21 +3 3 19 20 23 22 +3 3 21 22 25 24 +3 3 22 23 26 25 +1 3 0 9 12 3 +1 3 3 12 15 6 +1 3 9 18 21 12 +1 3 12 21 24 15 +1 3 2 5 14 11 +1 3 5 8 17 14 +1 3 11 14 23 20 +1 3 14 17 26 23 +2 3 0 1 10 9 +2 3 9 10 19 18 +2 3 1 2 11 10 +2 3 10 11 20 19 +2 3 6 15 16 7 +2 3 15 24 25 16 +2 3 7 16 17 8 +2 3 16 25 26 17 + +vertices +27 + +nodes +FiniteElementSpace +FiniteElementCollection: H1_3D_P2 +VDim: 3 +Ordering: 0 + +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0 +0.5 +1 +0.25 +0.5 +0.25 +0 +0.25 +0.5 +0.25 +0 +0 +0.5 +0.5 +0 +0.5 +0.25 +0 +0.5 +0.25 +0 +0.5 +0 +0.25 +0.5 +0.25 +0 +0 +0.5 +0.5 +0 +0.25 +0.5 +0 +0 +0.5 +0.75 +1 +0.75 +0.75 +1 +0.75 +1 +1 +1 +0.75 +1 +0.75 +1 +0.75 +1 +0.75 +1 +1 +0.75 +1 +1 +0.25 +0.25 +0.5 +0.25 +0 +0.25 +0.25 +0.5 +0.25 +0 +0.25 +0.25 +0.5 +0.25 +0 +0.25 +0.25 +0.5 +0 +0.25 +0.75 +0.75 +1 +0.75 +0.75 +0.75 +1 +0.75 +0.75 +0.75 +0.75 +1 +0.75 +0.75 +0.75 +1 +0.25 +0.25 +0.25 +0.25 +0.75 +0.75 +0.75 +0.75 +0 +0 +0 +0.5 +0.5 +0.5 +1 +1 +1 +0 +0 +0 +0.5 +0.5 +0.5 +1 +1 +1 +0 +0 +0 +0.5 +0.5 +0.5 +1 +1 +1 +0 +0.25 +0.5 +0.25 +0 +0.25 +0.5 +0.25 +0 +0 +0.5 +0.5 +0.75 +1 +0.75 +0.75 +1 +0.75 +1 +1 +0.5 +0.75 +1 +0.75 +0.5 +0.5 +1 +1 +0 +0.25 +0.25 +0 +0 +0 +0.25 +0.5 +0 +0.25 +0.5 +0 +0.5 +0.75 +1 +0.75 +1 +1 +0.5 +0.75 +1 +0.5 +1 +0 +0.25 +0 +0.25 +0 +0.25 +0.5 +0.25 +0.25 +0.75 +0.75 +1 +0.75 +0.75 +0.5 +0.75 +1 +0.75 +0.75 +0 +0.25 +0.25 +0.25 +0.25 +0 +0.25 +0.5 +0.25 +0.75 +0.75 +1 +0.75 +0.75 +0.5 +0.75 +1 +0.25 +0 +0.25 +0.25 +0.75 +0.75 +0.25 +0.25 +0.75 +0.75 +0.25 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0.5 +0.5 +0.5 +0.5 +0.5 +0.5 +0.5 +0.5 +0.5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +0 +0.5 +0.5 +0.5 +0.5 +0.25 +0.25 +0.25 +0.25 +0 +0 +0 +0.5 +0.5 +0.5 +0.25 +0.25 +1 +1 +1 +1 +0.75 +0.75 +0.75 +0.75 +1 +1 +1 +0.75 +0.75 +0.5 +0.5 +0.5 +1 +1 +1 +0.75 +0.75 +0.5 +0.5 +1 +1 +0.75 +0 +0 +0 +0.25 +0.25 +0 +0 +0.25 +0 +0.25 +0.25 +0.25 +0.25 +0.5 +0 +0.25 +0.25 +0.25 +0.5 +0.75 +0.75 +0.75 +0.75 +1 +0.75 +0.75 +0.75 +1 +0.5 +0.75 +0.75 +0.75 +1 +0.5 +0.75 +0.75 +1 +0 +0.25 +0.25 +0.25 +0 +0.25 +0.25 +0.25 +0.25 +0.75 +0.75 +0.75 +0.75 +0.25 +0.25 From 4252b22632ac41174537781e250ed438a9943e33 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Apr 2020 13:01:07 -0700 Subject: [PATCH 211/535] Refactor class FieldInterpolant to seperate out parallel implementation and not require the formation of bilinearform and cg objects to be repeatedly created each time a function is called. --- fem/field_interpolant.cpp | 95 ++++++++---------------- fem/field_interpolant.hpp | 112 ++++++++++++++++++++++++----- tests/unit/fem/test_quadf_coef.cpp | 14 +++- 3 files changed, 133 insertions(+), 88 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 0832e5ff0b..82f7328062 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -107,6 +107,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureIntegrator qi(vqfc); qi.SetIntRule(ir); + Array dbfi = *L2->GetDBFI(); + if (!setup_disc) { m_all_data.SetSize(ndofs * ndofs * NE); @@ -116,7 +118,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, const FiniteElement &fe = *tr_fes.GetFE(e); ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - mass_int.AssembleElementMatrix(fe, eltr, mi); + dbfi[0]->AssembleElementMatrix(fe, eltr, mi); } setup_disc = true; } @@ -170,6 +172,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureIntegrator qi(qfc); qi.SetIntRule(ir); + Array dbfi = *L2->GetDBFI(); if (!setup_disc) { @@ -180,7 +183,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, const FiniteElement &fe = *tr_fes.GetFE(e); ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - mass_int.AssembleElementMatrix(fe, eltr, mi); + dbfi[0]->AssembleElementMatrix(fe, eltr, mi); } setup_disc = true; } @@ -239,16 +242,7 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, } } - - // We need this fes to only have a vdim of 1 which is not the case here so we need to make a new fespace - // Potential fix me with a better implementation - const FiniteElementCollection *fec = fes.FEColl(); - Mesh *mesh = fes.GetMesh(); - FiniteElementSpace fes_v1(mesh, fec, 1); - - BilinearForm *L2 = new BilinearForm(&fes_v1); - L2->AddDomainIntegrator(new MassIntegrator(ir)); - L2->Assemble(); + // L2->Assemble(); GridFunction x(&fes); x = 0.0; @@ -263,9 +257,9 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, b_sub.MakeRef(*b, offset, size); X_sub.MakeRef(x, offset, size); L2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); - // Fix this to be more efficient - // OperatorJacobiSmoother M(*L2, ess_tdof_list); - CG(*A, B, X, 0, 2000, 1e-25, 0.0); + // Fix this to be more efficient; + cg->SetOperator(*A); + cg->Mult(B, X); // Recover the solution as a finite element grid function. L2->RecoverFEMSolution(X, *b, X_sub); } @@ -285,7 +279,6 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, } } - delete L2; delete b; } void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, @@ -308,9 +301,7 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, b->AddDomainIntegrator(new QuadratureIntegrator(qfc, ir)); b->Assemble(); - BilinearForm *L2 = new BilinearForm(&fes); - L2->AddDomainIntegrator(new MassIntegrator(ir)); - L2->Assemble(); + // L2->Assemble(); GridFunction x(&fes); x = 0.0; @@ -319,23 +310,21 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, Array ess_tdof_list; L2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - // Fix this to be more efficient - // OperatorJacobiSmoother M(*L2, ess_tdof_list); - CG(*A, B, X, 0, 2000, 1e-25, 0.0); + cg->SetOperator(*A); + cg->Mult(B, X); // Recover the solution as a finite element grid function. L2->RecoverFEMSolution(X, *b, x); gf = x; - delete L2; delete b; } #ifdef MFEM_USE_MPI // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector // quadrature function coefficient. -void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - ParFiniteElementSpace &fes) +void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + ParFiniteElementSpace &fes) { const IntegrationRule* ir; { @@ -371,15 +360,7 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, } } - // We need this fes to only have a vdim of 1 which is not the case here so we need to make a new fespace - // Potential fix me with a better implementation - const FiniteElementCollection *fec = fes.FEColl(); - ParMesh *mesh = fes.GetParMesh(); - ParFiniteElementSpace fes_v1(mesh, fec, 1); - - ParBilinearForm *L2 = new ParBilinearForm(&fes_v1); - L2->AddDomainIntegrator(new MassIntegrator(ir)); - L2->Assemble(); + // ParL2->Assemble(); ParGridFunction x(&fes); x = 0.0; @@ -388,25 +369,16 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, Array ess_tdof_list; - CGSolver cg(MPI_COMM_WORLD); - cg.SetPrintLevel(0); - cg.SetMaxIter(2000); - cg.SetRelTol(sqrt(1e-25)); - cg.SetAbsTol(sqrt(0.0)); - for (int ind = 0; ind < vdim; ind++) { int offset = ind * size; b_sub.MakeRef(*b, offset, size); X_sub.MakeRef(x, offset, size); - L2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); - // Fix this to be more efficient - // OperatorJacobiSmoother M(*L2, ess_tdof_list); - // CG(*A, B, X, 0, 2000, 1e-25, 0.0); - cg.SetOperator(*A); - cg.Mult(B, X); + ParL2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); // Recover the solution as a finite element grid function. - L2->RecoverFEMSolution(X, *b, X_sub); + cg->SetOperator(*A); + cg->Mult(B, X); + ParL2->RecoverFEMSolution(X, *b, X_sub); } if (fes.GetOrdering() == Ordering::byNODES) @@ -424,14 +396,13 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, } } - delete L2; delete b; } // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as // quadrature function coefficient. -void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc, - ParFiniteElementSpace &fes) +void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, + QuadratureFunctionCoefficient &qfc, + ParFiniteElementSpace &fes) { const IntegrationRule* ir; { @@ -449,9 +420,7 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, b->AddDomainIntegrator(new QuadratureIntegrator(qfc, ir)); b->Assemble(); - ParBilinearForm *L2 = new ParBilinearForm(&fes); - L2->AddDomainIntegrator(new MassIntegrator(ir)); - L2->Assemble(); + // ParL2->Assemble(); ParGridFunction x(&fes); x = 0.0; @@ -459,22 +428,14 @@ void FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, Vector B, X; Array ess_tdof_list; - L2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); + ParL2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); // Fix this to be more efficient - // OperatorJacobiSmoother M(*L2, ess_tdof_list); - // CG(*A, B, X, 0, 2000, 1e-25, 0.0); - CGSolver cg(MPI_COMM_WORLD); - cg.SetPrintLevel(0); - cg.SetMaxIter(2000); - cg.SetRelTol(sqrt(1e-25)); - cg.SetAbsTol(sqrt(0.0)); - cg.SetOperator(*A); - cg.Mult(B, X); + cg->SetOperator(*A); + cg->Mult(B, X); // Recover the solution as a finite element grid function. - L2->RecoverFEMSolution(X, *b, x); + ParL2->RecoverFEMSolution(X, *b, x); gf = x; - delete L2; delete b; } #endif diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index d1c1bcb4de..0d57391d3f 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -20,10 +20,12 @@ #include "eltrans.hpp" #include "coefficient.hpp" #include "bilininteg.hpp" +#include "bilinearform.hpp" #include "lininteg.hpp" #include "gridfunc.hpp" #ifdef MFEM_USE_MPI #include "pgridfunc.hpp" +#include "pbilinearform.hpp" #endif namespace mfem @@ -31,13 +33,28 @@ namespace mfem class FieldInterpolant { -private: +protected: bool setup_disc; + bool setup_full; Vector m_all_data; - MassIntegrator mass_int; + BilinearForm *L2; + CGSolver *cg; int NE; public: - FieldInterpolant(const IntegrationRule* ir) : setup_disc(false) { mass_int.SetIntRule(ir); } + // The FiniteElementSpace passed into here should have a vdim set to 1 in order for the + // MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with + // a VectorQuadratureFunctionCoefficient. + FieldInterpolant(FiniteElementSpace *fes) : setup_disc(false), setup_full(false) + { + L2 = new BilinearForm(fes); + + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule *ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); + + L2->AddDomainIntegrator(new MassIntegrator(ir)); + L2->Assemble(); + } // This function takes a vector quadrature function coefficient and projects it onto a GridFunction that lives // in L2 space. This function requires tr_fes to be the finite element space that the VectorQuadratureFunctionCoefficient lives on // and fes is the L2 finite element space that we're projecting onto. @@ -52,8 +69,6 @@ public: QuadratureFunctionCoefficient &qfc, FiniteElementSpace &tr_fes, FiniteElementSpace &fes); - //Parallel versions of the ProjectQuadratureCoefficient will need to be created once the serial version works - // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector // quadrature function coefficient. void ProjectQuadratureCoefficient(GridFunction &gf, @@ -64,21 +79,80 @@ public: void ProjectQuadratureCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, FiniteElementSpace &fes); -#ifdef MFEM_USE_MPI - // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector - // quadrature function coefficient. - void ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - ParFiniteElementSpace &fes); - // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as - // quadrature function coefficient. - void ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc, - ParFiniteElementSpace &fes); -#endif - //Tells the ProjectQuadratureDiscCoefficient that they need to recalculate the data. + // Tells the ProjectQuadratureDiscCoefficient that they need to recalculate the data. void SetupDiscReset() { setup_disc = false; } - ~FieldInterpolant() {} + // Tells the ProjectQuadratureCoefficient that they need to recalculate the data. + virtual void FullReset() + { + L2->Update(); + L2->Assemble(); + } + virtual void SetupCG() + { + cg = new CGSolver(); + cg->SetPrintLevel(0); + cg->SetMaxIter(2000); + cg->SetRelTol(sqrt(1e-30)); + cg->SetAbsTol(sqrt(0.0)); + } + ~FieldInterpolant() + { + delete L2; + delete cg; + } +}; + +class ParFieldInterpolant : public FieldInterpolant +{ +protected: + ParBilinearForm *ParL2; +public: + // The ParFiniteElementSpace passed into here should have a vdim set to 1 in order for the + // MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with + // a VectorQuadratureFunctionCoefficient. + ParFieldInterpolant(ParFiniteElementSpace *pfes) : FieldInterpolant(pfes) + { + ParL2 = new ParBilinearForm(pfes); + + const FiniteElement &el = *pfes->GetFE(0); + const IntegrationRule *ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); + + ParL2->AddDomainIntegrator(new MassIntegrator(ir)); + ParL2->Assemble(); + } + // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector + // quadrature function coefficient. + void ProjectQuadratureCoefficient(ParGridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc, + ParFiniteElementSpace &fes); + // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as + // quadrature function coefficient. + void ProjectQuadratureCoefficient(ParGridFunction &gf, + QuadratureFunctionCoefficient &qfc, + ParFiniteElementSpace &fes); + // Tells the internal bilinearform needs to be reset in order to reset the sparse matrix + virtual void FullReset() override + { + FieldInterpolant::FullReset(); + ParL2->Update(); + ParL2->Assemble(); + } + using FieldInterpolant::SetupCG; + // Setup the CG solver with an MPI communicator + virtual void SetupCG(MPI_Comm _comm) + { + cg = new CGSolver(_comm); + cg->SetPrintLevel(0); + cg->SetMaxIter(2000); + cg->SetRelTol(sqrt(1e-30)); + cg->SetAbsTol(sqrt(0.0)); + } + + ~ParFieldInterpolant() + { + delete ParL2; + } }; class VectorQuadratureIntegrator : public LinearFormIntegrator diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index c2c4c64be9..06f2b9768b 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -68,7 +68,10 @@ TEST_CASE("Quadrature Function Coefficients", QuadratureFunctionCoefficient qfc(&quadf_coeff); VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); - FieldInterpolant fi(&ir); + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_hv1(&mesh, &fec_h1, 1); + FieldInterpolant fi(&fespace_hv1); + fi.SetupCG(); SECTION("Operators on VecQuadFuncCoeff") { @@ -248,6 +251,8 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction g0(&fespace_h1); GridFunction gtrue(&fespace_h1); + fi.FullReset(); + { int nnodes = gtrue.Size(); int vdim = 1; @@ -324,7 +329,10 @@ TEST_CASE("Parallel Quadrature Function Coefficients", QuadratureFunctionCoefficient qfc(&quadf_coeff); VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); - FieldInterpolant fi(&ir); + H1_FECollection fec_h1(order_h1, dim); + ParFiniteElementSpace fespace_hv1(&mesh, &fec_h1, 1); + ParFieldInterpolant fi(&fespace_hv1); + fi.SetupCG(MPI_COMM_WORLD); SECTION("Operators on VecQuadFuncCoeff") { @@ -452,6 +460,8 @@ TEST_CASE("Parallel Quadrature Function Coefficients", ParGridFunction g0(&fespace_h1); ParGridFunction gtrue(&fespace_h1); + fi.FullReset(); + { int nnodes = gtrue.Size() / dim; int vdim = dim; From e87905396d4582f996503b8c17cc28e8c9af26ff Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Apr 2020 13:36:42 -0700 Subject: [PATCH 212/535] Left out a set of ifdef to guard against parallel portions of the header file... --- fem/field_interpolant.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 0d57391d3f..9455d9b753 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -102,6 +102,7 @@ public: } }; +#ifdef MFEM_USE_MPI class ParFieldInterpolant : public FieldInterpolant { protected: @@ -154,6 +155,7 @@ public: delete ParL2; } }; +#endif class VectorQuadratureIntegrator : public LinearFormIntegrator { From 7bea8ddf8b3699398ddc71294140bc6281318a5c Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Apr 2020 20:21:36 -0700 Subject: [PATCH 213/535] Update unit tests to have vector coefficients be based on the projection of the mesh nodes to quadrature points and back to nodes --- fem/field_interpolant.cpp | 4 +- tests/unit/fem/test_quadf_coef.cpp | 161 +++++++++++++++-------------- 2 files changed, 83 insertions(+), 82 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 82f7328062..f00aa0ec63 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -102,7 +102,6 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, Vector rhs(ndofs * vdim), rhs_sub(ndofs); Vector qfv(ndofs * vdim), qfv_sub(ndofs); - Array dofs(ndofs); VectorQuadratureIntegrator qi(vqfc); qi.SetIntRule(ir); @@ -124,6 +123,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } double* data = m_all_data.HostReadWrite(); + Array dofs; for (int e = 0; e < NE; e++) { qfv = 0.0; @@ -168,7 +168,7 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, Vector rhs(ndofs); Vector qfv(ndofs); - Array dofs(ndofs); + Array dofs; QuadratureIntegrator qi(qfc); qi.SetIntRule(ir); diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 06f2b9768b..af9352c9f6 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -52,15 +52,20 @@ TEST_CASE("Quadrature Function Coefficients", } { - //More like nelems * nqpts - int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim(); + int nqpts = ir.GetNPoints(); + int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim() / nqpts; int vdim = quadf_vcoeff.GetVDim(); for (int i = 0; i < nelems; i++) { for (int j = 0; j < vdim; j++) { - quadf_vcoeff((i * vdim) + j) = j; + for (int k = 0; k < nqpts; k++) + { + //X has dims nqpts x sdim x ne + quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( + i * nqpts * vdim) + (j * nqpts) + k ); + } } } } @@ -94,20 +99,26 @@ TEST_CASE("Quadrature Function Coefficients", L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); + GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; + int ne = mesh.GetNE(); - for (int i = 0; i < vdim; i++) + GridFunction nodes(&fespace_h1); + Vector el_x; + Array vdofs; + mesh.GetNodes(nodes); + int vdim = quadf_vcoeff.GetVDim(); + + for (int i = 0; i < ne; i++) { - for (int j = 0; j < nnodes; j++) - { - gtrue((i * nnodes) + j) = i; - } + fespace_h1.GetElementVDofs(i, vdofs); + nodes.GetSubVector(vdofs, el_x); + fespace_l2.GetElementVDofs(i, vdofs); + gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); } } @@ -123,20 +134,25 @@ TEST_CASE("Quadrature Function Coefficients", L2_FECollection fec_l2(order_h1, dim); FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim, Ordering::byVDIM); H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1, Ordering::byVDIM); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; + int ne = mesh.GetNE(); - for (int i = 0; i < vdim; i++) + GridFunction nodes(&fespace_h1); + Vector el_x; + Array vdofs; + mesh.GetNodes(nodes); + int vdim = quadf_vcoeff.GetVDim(); + + for (int i = 0; i < ne; i++) { - for (int j = 0; j < nnodes; j++) - { - gtrue(i + (vdim * j)) = i; - } + fespace_h1.GetElementVDofs(i, vdofs); + nodes.GetSubVector(vdofs, el_x); + fespace_l2.GetElementVDofs(i, vdofs); + gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); } } @@ -155,16 +171,9 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction gtrue(&fespace_h1); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; - - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < nnodes; j++) - { - gtrue((i * nnodes) + j) = i; - } - } + GridFunction nodes(&fespace_h1); + mesh.GetNodes(nodes); + gtrue = nodes; } g0 = 0.0; @@ -181,16 +190,9 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction gtrue(&fespace_h1); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; - - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < nnodes; j++) - { - gtrue(i + j * vdim) = i; - } - } + GridFunction nodes(&fespace_h1); + mesh.GetNodes(nodes); + gtrue = nodes; } g0 = 0.0; @@ -228,7 +230,6 @@ TEST_CASE("Quadrature Function Coefficients", { fespace_h1.GetElementVDofs(i, vdofs); nodes.GetSubVector(vdofs, el_x); - // Should be constant across all elements int enodes = el_x.Size() / dim; for (int j = 0; j < enodes; j++) { @@ -313,15 +314,20 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } { - //More like nelems * nqpts - int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim(); + int nqpts = ir.GetNPoints(); + int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim() / nqpts; int vdim = quadf_vcoeff.GetVDim(); for (int i = 0; i < nelems; i++) { for (int j = 0; j < vdim; j++) { - quadf_vcoeff((i * vdim) + j) = j; + for (int k = 0; k < nqpts; k++) + { + //X has dims nqpts x sdim x ne + quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( + i * nqpts * vdim) + (j * nqpts) + k ); + } } } } @@ -355,20 +361,25 @@ TEST_CASE("Parallel Quadrature Function Coefficients", L2_FECollection fec_l2(order_h1, dim); ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); ParGridFunction g0(&fespace_l2); ParGridFunction gtrue(&fespace_l2); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; + int ne = mesh.GetNE(); - for (int i = 0; i < vdim; i++) + ParGridFunction nodes(&fespace_h1); + Vector el_x; + Array vdofs; + mesh.GetNodes(nodes); + int vdim = quadf_vcoeff.GetVDim(); + + for (int i = 0; i < ne; i++) { - for (int j = 0; j < nnodes; j++) - { - gtrue((i * nnodes) + j) = i; - } + fespace_h1.GetElementVDofs(i, vdofs); + nodes.GetSubVector(vdofs, el_x); + fespace_l2.GetElementVDofs(i, vdofs); + gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); } } @@ -390,20 +401,25 @@ TEST_CASE("Parallel Quadrature Function Coefficients", L2_FECollection fec_l2(order_h1, dim); ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, dim, Ordering::byVDIM); H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, 1, Ordering::byVDIM); + ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); ParGridFunction g0(&fespace_l2); ParGridFunction gtrue(&fespace_l2); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; + int ne = mesh.GetNE(); - for (int i = 0; i < vdim; i++) + ParGridFunction nodes(&fespace_h1); + Vector el_x; + Array vdofs; + mesh.GetNodes(nodes); + int vdim = quadf_vcoeff.GetVDim(); + + for (int i = 0; i < ne; i++) { - for (int j = 0; j < nnodes; j++) - { - gtrue(i + (vdim * j)) = i; - } + fespace_h1.GetElementVDofs(i, vdofs); + nodes.GetSubVector(vdofs, el_x); + fespace_l2.GetElementVDofs(i, vdofs); + gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); } } @@ -428,16 +444,9 @@ TEST_CASE("Parallel Quadrature Function Coefficients", ParGridFunction gtrue(&fespace_h1); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; - - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < nnodes; j++) - { - gtrue((i * nnodes) + j) = i; - } - } + ParGridFunction nodes(&fespace_h1); + mesh.GetNodes(nodes); + gtrue = nodes; } g0 = 0.0; @@ -463,16 +472,9 @@ TEST_CASE("Parallel Quadrature Function Coefficients", fi.FullReset(); { - int nnodes = gtrue.Size() / dim; - int vdim = dim; - - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < nnodes; j++) - { - gtrue(i + j * vdim) = i; - } - } + ParGridFunction nodes(&fespace_h1); + mesh.GetNodes(nodes); + gtrue = nodes; } g0 = 0.0; @@ -516,7 +518,6 @@ TEST_CASE("Parallel Quadrature Function Coefficients", { fespace_h1.GetElementVDofs(i, vdofs); nodes.GetSubVector(vdofs, el_x); - // Should be constant across all elements int enodes = el_x.Size() / dim; for (int j = 0; j < enodes; j++) { From ca10dca105c2ed7c94b1a42dbd4dae6644476716 Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 23 Apr 2020 22:33:30 -0700 Subject: [PATCH 214/535] Minor edits in mesh-optimizer. --- fem/tmop.cpp | 3 +-- miniapps/meshing/mesh-optimizer.cpp | 10 +++++++++- miniapps/meshing/pmesh-optimizer.cpp | 10 +++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index e71c3539fa..adc4d6e574 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1038,8 +1038,7 @@ void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_) delete tspec_fes; tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(), - tspec_.FESpace()->FEColl(), - 1); + tspec_.FESpace()->FEColl(), 1); // need to append data to tspec // make a copy of tspec->tspec_temp, increase its size, and diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index b3f66ef87f..6f07a480eb 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -48,7 +48,7 @@ // Adapted discrete aspect-ratio+orientation // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 // Adapted discrete aspect ratio (3D) -// mesh-optimizer -m cube.mesh -o 2 -rs 0 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape: // mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: @@ -348,6 +348,8 @@ int main(int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } FunctionCoefficient ind_coeff(discrete_size_2d); @@ -372,6 +374,8 @@ int main(int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } @@ -461,6 +465,8 @@ int main(int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } VectorFunctionCoefficient fd_aspr3d(dim, discrete_aspr_3d); @@ -482,6 +488,8 @@ int main(int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index abcc66df30..4f443a1a28 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -48,7 +48,7 @@ // Adapted discrete aspect-ratio+orientation // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 // Adapted discrete aspect ratio (3D) -// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 0 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape: // mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: @@ -378,6 +378,8 @@ int main (int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } FunctionCoefficient ind_coeff(discrete_size_2d); @@ -402,6 +404,8 @@ int main (int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } //Diffuse the interface @@ -498,6 +502,8 @@ int main (int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } VectorFunctionCoefficient fd_aspr3d(dim, discrete_aspr_3d); @@ -518,6 +524,8 @@ int main (int argc, char *argv[]) { #ifdef MFEM_USE_GSLIB tc->SetAdaptivityEvaluator(new InterpolatorFP); +#else + MFEM_ABORT("MFEM is not built with GSLIB."); #endif } From 33b9f0441225d9781abcde17b6131e58fd13324a Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 23 Apr 2020 23:59:14 -0700 Subject: [PATCH 215/535] Modified some of the sample runs to use GSLIB as they don't work well with the advection. Fixed some debug build warnings. --- fem/gslib.cpp | 3 ++- miniapps/meshing/mesh-optimizer.cpp | 10 ++++++---- miniapps/meshing/mesh-optimizer.hpp | 4 ++-- miniapps/meshing/pmesh-optimizer.cpp | 10 ++++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index d58ed4bb50..a227ae5cc7 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -304,7 +304,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates() const GridFunction *nodes = mesh->GetNodes(); Mesh *meshsplit = NULL; const int NE = mesh->GetNE(); - int NEsplit; + int NEsplit = -1; // Split the reference element into a reference submesh of quads or hexes. if (gt == Geometry::TRIANGLE) @@ -398,6 +398,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates() } meshsplit->FinalizeHexMesh(1, 1, true); } + else { MFEM_ABORT("Unsupported geometry type."); } // Curve the reference submesh. H1_FECollection fec(fe->GetOrder(), dim); diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 6f07a480eb..89d6c8bac4 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -41,14 +41,16 @@ // Adapted discrete size: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor + // Adapted size+aspect ratio to discrete material indicator // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -// Adapted discrete size+orientation -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -// Adapted discrete aspect-ratio+orientation -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// Adapted discrete size+orientation (requires GSLIB) +// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 +// Adapted discrete aspect-ratio+orientation (requires GSLIB) +// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 // Adapted discrete aspect ratio (3D) // mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 + // Blade shape: // mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index d859cfe13a..b907897d4f 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -62,8 +62,8 @@ double discrete_aspr_2d(const Vector &x) double th = 22.5*M_PI/180.; double xn = cos(th)*xc + sin(th)*yc; double yn = -sin(th)*xc + cos(th)*yc; - double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; - double stretch = 1/cos(th2); + //double th2 = (th > 45.*M_PI/180) ? M_PI/2 - th : th; + //double stretch = 1/cos(th2); xc = xn; yc = yn; double tfac = 20; diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 4f443a1a28..d64932238c 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -41,14 +41,16 @@ // Adapted discrete size: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor + // Adapted size+aspect ratio to discrete material indicator // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -// Adapted discrete size+orientation -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -// Adapted discrete aspect-ratio+orientation -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// Adapted discrete size+orientation (requires GSLIB) +// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 +// Adapted discrete aspect-ratio+orientation (requires GSLIB) +// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 // Adapted discrete aspect ratio (3D) // mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 + // Blade shape: // mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: From dc18fc27a0ed1c5c78d6e52bf6dfabb2649c8f4c Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 24 Apr 2020 00:19:42 -0700 Subject: [PATCH 216/535] Valgrind errors. --- fem/gslib.cpp | 2 +- fem/tmop_tools.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index a227ae5cc7..e8f0e01a8a 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -168,7 +168,7 @@ void FindPointsGSLIB::Interpolate(Array &codes, { const int dataptrin = i*points_fld, dataptrout = i*points_cnt; - field_in_scalar.SetData(field_in.GetData()+dataptrin); + field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld); GetNodeValues(field_in_scalar, node_vals); if (dim==2) diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 4c8bd72e77..03fb596176 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -275,6 +275,12 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes, const double newton_tol = 1.0e-12; const int npts_at_once = 256; + if (finder) + { + finder->FreeData(); + delete finder; + } + FiniteElementSpace *f = fes; #ifdef MFEM_USE_MPI if (pfes) From e3d0907234d849cbffb8e8ecd8b85246f523917b Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 24 Apr 2020 00:26:56 -0700 Subject: [PATCH 217/535] Valgrind. --- fem/tmop.cpp | 10 +++++----- fem/tmop_tools.hpp | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index adc4d6e574..de70b82224 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1365,13 +1365,13 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x, tspec_pert1h.SetSize(x.Size()*ncomp); - Vector TSpecTemp(ncomp*cnt); + Vector TSpecTemp; Vector xtemp = x; for (int j = 0; j < dim; j++) { for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) += dx; } - TSpecTemp.SetDataAndSize(tspec_pert1h.GetData() + j*cnt*ncomp, cnt*ncomp); + TSpecTemp.NewDataAndSize(tspec_pert1h.GetData() + j*cnt*ncomp, cnt*ncomp); UpdateTargetSpecification(xtemp, TSpecTemp); for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) -= dx; } @@ -1393,7 +1393,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, tspec_pert2h.SetSize(cnt*dim*ncomp); tspec_pertmix.SetSize(cnt*totmix*ncomp); - Vector TSpecTemp(cnt*ncomp); + Vector TSpecTemp; Vector xtemp = x; // T(x+2h) @@ -1401,7 +1401,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, { for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) += 2*dx; } - TSpecTemp.SetDataAndSize(tspec_pert2h.GetData() + j*cnt*ncomp, cnt*ncomp); + TSpecTemp.NewDataAndSize(tspec_pert2h.GetData() + j*cnt*ncomp, cnt*ncomp); UpdateTargetSpecification(xtemp, TSpecTemp); for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) -= 2*dx; } @@ -1419,7 +1419,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x, xtemp(k2*cnt+i) += dx; } - TSpecTemp.SetDataAndSize(tspec_pertmix.GetData() + j*cnt*ncomp, cnt*ncomp); + TSpecTemp.NewDataAndSize(tspec_pertmix.GetData() + j*cnt*ncomp, cnt*ncomp); UpdateTargetSpecification(xtemp, TSpecTemp); for (int i = 0; i < cnt; i++) diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index 4cc83b148d..e77e23c7e9 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -53,6 +53,8 @@ private: Vector pos_r_out, dist_p_out; int dim; public: + InterpolatorFP() : finder(NULL) { } + virtual void SetInitialField(const Vector &init_nodes, const Vector &init_field); From 9900068b7a9321aa60c6ab7a257e55042757739f Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 24 Apr 2020 15:16:33 -0700 Subject: [PATCH 218/535] Adding error checking to FaceElementTransformations --- fem/eltrans.cpp | 28 ++++++++++++++++++++++++++++ fem/eltrans.hpp | 19 +++++++++++++++++++ mesh/mesh.cpp | 3 +++ 3 files changed, 50 insertions(+) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index 12cf10d6dd..017f7acf00 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -619,10 +619,14 @@ FaceElementTransformations::GetActivePointTransformation() { if (side == 0) { + MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation " + "for side 1 has not been configured."); return &Loc1; } else if (side == 1) { + MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation " + "for side 2 has not been configured."); return &Loc2; } @@ -631,4 +635,28 @@ FaceElementTransformations::GetActivePointTransformation() } } +void FaceElementTransformations::Transform(const IntegrationPoint &ip, + Vector &trans) +{ + MFEM_VERIFY(mask & 16, "The ElementTransformation " + "for the face has not been configured."); + IsoparametricTransformation::Transform(ip, trans); +} + +void FaceElementTransformations::Transform(const IntegrationRule &ir, + DenseMatrix &tr) +{ + MFEM_VERIFY(mask & 16, "The ElementTransformation " + "for the face has not been configured."); + IsoparametricTransformation::Transform(ir, tr); +} + +void FaceElementTransformations::Transform(const DenseMatrix &matrix, + DenseMatrix &result) +{ + MFEM_VERIFY(mask & 16, "The ElementTransformation " + "for the face has not been configured."); + IsoparametricTransformation::Transform(matrix, result); +} + } diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index c7a3b89849..daedbfbca1 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -381,6 +381,7 @@ class FaceElementTransformations : public IsoparametricTransformation { private: int side; + int mask; public: int Elem1No, Elem2No; @@ -418,6 +419,24 @@ public: int SetActiveSide(int s); int GetActiveSide() const { return side; } + /// Set the mask indicating which portions of the object have been setup + /** The argument @a m is a bitmask used in + Mesh::GetFaceElementTransformations to indicate which portions + of the FaceElement Transformations object have been configured. + + mask & 1: Elem1 is configured + mask & 2: Elem2 is configured + mask & 4: Loc1 is configured + mask & 8: Loc2 is configured + mask & 16: The Face transformation itself is configured + */ + void SetConfigurationMask(int m) { mask = m; } + int GetConfigurationMask() const { return mask; } + + virtual void Transform(const IntegrationPoint &, Vector &); + virtual void Transform(const IntegrationRule &, DenseMatrix &); + virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); + ElementTransformation * GetActiveElementTransformation(); IntegrationPointTransformation * GetActivePointTransformation(); }; diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 2691cedd9a..5e483fb7cf 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -859,6 +859,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, { FaceInfo &face_info = faces_info[FaceNo]; + FaceElemTr.SetConfigurationMask(0); FaceElemTr.Elem1 = NULL; FaceElemTr.Elem2 = NULL; @@ -922,6 +923,8 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, } } + FaceElemTr.SetConfigurationMask(mask); + return &FaceElemTr; } From 68a58b2188d69903c84068f866012e396eea3a98 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 24 Apr 2020 20:27:04 -0700 Subject: [PATCH 219/535] Fixing ProjectQuadratureDiscCoefficient methods and unit tests based on GitHub comments related to L2 My understanding of where L2 FiniteElementSpace values was off. I thought they were at the element nodes, but it turns out they are just at the quadrature points instead. --- fem/field_interpolant.cpp | 18 +++--- fem/field_interpolant.hpp | 8 +-- tests/unit/fem/test_quadf_coef.cpp | 94 ++++++------------------------ 3 files changed, 28 insertions(+), 92 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index f00aa0ec63..84506c4f39 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -77,7 +77,6 @@ void QuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, //If that isn't the case we might be able to still do things but things will most likely be slower. void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &tr_fes, FiniteElementSpace &fes) { int ndofs; @@ -114,8 +113,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, double* data = m_all_data.HostReadWrite(); for (int e = 0; e < NE; e++) { - const FiniteElement &fe = *tr_fes.GetFE(e); - ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); dbfi[0]->AssembleElementMatrix(fe, eltr, mi); } @@ -129,8 +128,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, qfv = 0.0; mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); - const FiniteElement &fe = *tr_fes.GetFE(e); - ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); for (int ind = 0; ind < vdim; ind++) { @@ -145,7 +144,6 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &tr_fes, FiniteElementSpace &fes) { int ndofs; @@ -180,8 +178,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, double* data = m_all_data.HostReadWrite(); for (int e = 0; e < NE; e++) { - const FiniteElement &fe = *tr_fes.GetFE(e); - ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); dbfi[0]->AssembleElementMatrix(fe, eltr, mi); } @@ -195,8 +193,8 @@ void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, { mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); inv.Factor(mi); - const FiniteElement &fe = *tr_fes.GetFE(e); - ElementTransformation &eltr = *tr_fes.GetElementTransformation(e); + const FiniteElement &fe = *fes.GetFE(e); + ElementTransformation &eltr = *fes.GetElementTransformation(e); qi.AssembleRHSElementVect(fe, eltr, rhs); inv.Mult(rhs, qfv); fes.GetElementDofs(e, dofs); diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 9455d9b753..ebed793df1 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -56,18 +56,14 @@ public: L2->Assemble(); } // This function takes a vector quadrature function coefficient and projects it onto a GridFunction that lives - // in L2 space. This function requires tr_fes to be the finite element space that the VectorQuadratureFunctionCoefficient lives on - // and fes is the L2 finite element space that we're projecting onto. + // in L2 space. This function requires fes to be L2 finite element space that we're projecting onto. void ProjectQuadratureDiscCoefficient(GridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &tr_fes, FiniteElementSpace &fes); // This function takes a quadrature function coefficient and projects it onto a GridFunction that lives - // in L2 space. This function requires tr_fes to be the finite element space that the QuadratureFunctionCoefficient lives on - // and fes is the L2 finite element space that we're projecting onto. + // in L2 space. This function requires fes to be L2 finite element space that we're projecting onto. void ProjectQuadratureDiscCoefficient(GridFunction &gf, QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &tr_fes, FiniteElementSpace &fes); // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector // quadrature function coefficient. diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index af9352c9f6..8cca7aa65c 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -105,25 +105,15 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction gtrue(&fespace_l2); { - int ne = mesh.GetNE(); GridFunction nodes(&fespace_h1); - Vector el_x; - Array vdofs; mesh.GetNodes(nodes); - int vdim = quadf_vcoeff.GetVDim(); + gtrue.ProjectGridFunction(nodes); - for (int i = 0; i < ne; i++) - { - fespace_h1.GetElementVDofs(i, vdofs); - nodes.GetSubVector(vdofs, el_x); - fespace_l2.GetElementVDofs(i, vdofs); - gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); - } } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -139,25 +129,15 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction gtrue(&fespace_l2); { - int ne = mesh.GetNE(); GridFunction nodes(&fespace_h1); - Vector el_x; - Array vdofs; mesh.GetNodes(nodes); - int vdim = quadf_vcoeff.GetVDim(); + gtrue.ProjectGridFunction(nodes); - for (int i = 0; i < ne; i++) - { - fespace_h1.GetElementVDofs(i, vdofs); - nodes.GetSubVector(vdofs, el_x); - fespace_l2.GetElementVDofs(i, vdofs); - gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); - } } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -220,26 +200,17 @@ TEST_CASE("Quadrature Function Coefficients", // When using an L2 FE space of the same order as the mesh, the below highlights // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. { - int ne = mesh.GetNE(); + GridFunction nodes_z(&fespace_hv1); GridFunction nodes(&fespace_h1); - Vector el_x; - Array vdofs; mesh.GetNodes(nodes); - for (int i = 0; i < ne; i++) - { - fespace_h1.GetElementVDofs(i, vdofs); - nodes.GetSubVector(vdofs, el_x); - int enodes = el_x.Size() / dim; - for (int j = 0; j < enodes; j++) - { - gtrue(j + i * enodes) = el_x(enodes * 2 + j); - } - } + nodes_z.MakeRef(nodes, nodes_z.Size() * 2); + gtrue.ProjectGridFunction(nodes_z); + } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_h1, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_l2); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -366,25 +337,15 @@ TEST_CASE("Parallel Quadrature Function Coefficients", ParGridFunction gtrue(&fespace_l2); { - int ne = mesh.GetNE(); ParGridFunction nodes(&fespace_h1); - Vector el_x; - Array vdofs; mesh.GetNodes(nodes); - int vdim = quadf_vcoeff.GetVDim(); + gtrue.ProjectGridFunction(nodes); - for (int i = 0; i < ne; i++) - { - fespace_h1.GetElementVDofs(i, vdofs); - nodes.GetSubVector(vdofs, el_x); - fespace_l2.GetElementVDofs(i, vdofs); - gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); - } } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -406,25 +367,15 @@ TEST_CASE("Parallel Quadrature Function Coefficients", ParGridFunction gtrue(&fespace_l2); { - int ne = mesh.GetNE(); ParGridFunction nodes(&fespace_h1); - Vector el_x; - Array vdofs; mesh.GetNodes(nodes); - int vdim = quadf_vcoeff.GetVDim(); + gtrue.ProjectGridFunction(nodes); - for (int i = 0; i < ne; i++) - { - fespace_h1.GetElementVDofs(i, vdofs); - nodes.GetSubVector(vdofs, el_x); - fespace_l2.GetElementVDofs(i, vdofs); - gtrue.SetSubVector(vdofs, el_x.HostReadWrite()); - } } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_h1, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -508,26 +459,17 @@ TEST_CASE("Parallel Quadrature Function Coefficients", // When using an L2 FE space of the same order as the mesh, the below highlights // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. { - int ne = mesh.GetNE(); + ParGridFunction nodes_z(&fespace_hv1); ParGridFunction nodes(&fespace_h1); - Vector el_x; - Array vdofs; mesh.GetNodes(nodes); - for (int i = 0; i < ne; i++) - { - fespace_h1.GetElementVDofs(i, vdofs); - nodes.GetSubVector(vdofs, el_x); - int enodes = el_x.Size() / dim; - for (int j = 0; j < enodes; j++) - { - gtrue(j + i * enodes) = el_x(enodes * 2 + j); - } - } + nodes_z.MakeRef(nodes, nodes_z.Size() * 2); + gtrue.ProjectGridFunction(nodes_z); + } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_h1, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_l2); gtrue -= g0; double lerr = gtrue.Norml2(); From 3e98c0b5527cfdfc918df189936a94dd2ce393f7 Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 27 Apr 2020 11:03:04 -0700 Subject: [PATCH 220/535] Address reviewer's comments --- config/simd/auto.hpp | 69 +++++++++++++++++----------------- config/simd/m128.hpp | 71 +++++++++++++++++------------------ config/simd/m256.hpp | 67 +++++++++++++++------------------ config/simd/m512.hpp | 71 +++++++++++++++++------------------ config/simd/m64.hpp | 63 ++++++++++++++----------------- config/simd/qpx256.hpp | 71 +++++++++++++++++------------------ config/simd/qpx64.hpp | 67 ++++++++++++++------------------- config/simd/vsx128.hpp | 71 +++++++++++++++++------------------ config/simd/vsx64.hpp | 63 ++++++++++++++----------------- config/tconfig.hpp | 9 +++++ fem/tbilinearform.hpp | 6 ++- miniapps/performance/makefile | 1 - 12 files changed, 302 insertions(+), 327 deletions(-) diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index b0815d19ab..22b8ef6876 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -14,21 +14,20 @@ #include "../tconfig.hpp" -template -struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD +template +struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD { - typedef scalar_t scalar_type; static const int size = S; static const int align_size = align_S; - scalar_t vec[size]; + double vec[size]; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + inline MFEM_ALWAYS_INLINE double &operator[](int i) { return vec[i]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + inline MFEM_ALWAYS_INLINE const double &operator[](int i) const { return vec[i]; } @@ -40,7 +39,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e; } @@ -54,7 +53,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e; } @@ -68,7 +67,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] -= e; } @@ -82,7 +81,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] *= e; } @@ -96,7 +95,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] /= e; } @@ -119,7 +118,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -135,7 +134,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -151,7 +150,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -167,7 +166,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -182,14 +181,14 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e * v[i]; } @@ -203,14 +202,14 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e * v[i]; } @@ -218,45 +217,45 @@ struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD } }; -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e + v[i]; } return r; } -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e - v[i]; } return r; } -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e * v[i]; } return r; } -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e / v[i]; } return r; diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 5b8c66a6c6..7976300685 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -14,24 +14,23 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 2; static constexpr int align_size = 16; union { __m128d m128d; - scalar_t vec[size]; + double vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + inline MFEM_ALWAYS_INLINE double &operator[](int i) { return vec[i]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + inline MFEM_ALWAYS_INLINE const double &operator[](int i) const { return vec[i]; } @@ -42,7 +41,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { m128d = _mm_set1_pd(e); return *this; @@ -50,11 +49,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { - m128d = _mm_add_pd(m128d,v); + m128d = _mm_add_pd(m128d,v.m128d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { m128d = _mm_add_pd(m128d,_mm_set1_pd(e)); return *this; @@ -62,11 +61,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { - m128d = _mm_sub_pd(m128d,v); + m128d = _mm_sub_pd(m128d,v.m128d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { m128d = _mm_sub_pd(m128d,_mm_set1_pd(e)); return *this; @@ -78,7 +77,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { m128d = _mm_mul_pd(m128d,_mm_set1_pd(e)); return *this; @@ -90,7 +89,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { m128d = _mm_div_pd(m128d,_mm_set1_pd(e)); return *this; @@ -98,7 +97,9 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { - return _mm_xor_pd(_mm_set1_pd(-0.0), m128d); + AutoSIMD r; + r.m128d = _mm_xor_pd(_mm_set1_pd(-0.0), m128d); + return r; } inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const @@ -109,7 +110,7 @@ template struct AutoSIMD } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; r.m128d = _mm_add_pd(m128d, _mm_set1_pd(e)); @@ -123,7 +124,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; r.m128d = _mm_sub_pd(m128d, _mm_set1_pd(e)); @@ -137,7 +138,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; r.m128d = _mm_mul_pd(m128d, _mm_set1_pd(e)); @@ -151,7 +152,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; r.m128d = _mm_div_pd(m128d, _mm_set1_pd(e)); @@ -165,13 +166,13 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { m128d = _mm_add_pd(_mm_mul_pd(_mm_set1_pd(e),v.m128d),m128d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { m128d = _mm_add_pd(_mm_mul_pd(v.m128d,_mm_set1_pd(e)),m128d); return *this; @@ -183,55 +184,51 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { m128d = _mm_mul_pd(v.m128d,_mm_set1_pd(e)); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d); return *this; } }; -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_add_pd(_mm_set1_pd(e),v.m128d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_sub_pd(_mm_set1_pd(e),v.m128d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_div_pd(_mm_set1_pd(e),v.m128d); return r; } diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 9bbc5036da..2018921c11 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -14,24 +14,23 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 4; static constexpr int align_size = 32; union { __m256d m256d; - scalar_t vec[size]; + double vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + inline MFEM_ALWAYS_INLINE double &operator[](int i) { return vec[i]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + inline MFEM_ALWAYS_INLINE const double &operator[](int i) const { return vec[i]; } @@ -42,7 +41,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { m256d = _mm256_set1_pd(e); return *this; @@ -50,11 +49,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { - m256d = _mm256_add_pd(m256d,v); + m256d = _mm256_add_pd(m256d,v.m256d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { m256d = _mm256_add_pd(m256d,_mm256_set1_pd(e)); return *this; @@ -62,11 +61,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { - m256d = _mm256_sub_pd(m256d,v); + m256d = _mm256_sub_pd(m256d,v.m256d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { m256d = _mm256_sub_pd(m256d,_mm256_set1_pd(e)); return *this; @@ -78,7 +77,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { m256d = _mm256_mul_pd(m256d,_mm256_set1_pd(e)); return *this; @@ -90,7 +89,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { m256d = _mm256_div_pd(m256d,_mm256_set1_pd(e)); return *this; @@ -110,7 +109,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; r.m256d = _mm256_add_pd(m256d, _mm256_set1_pd(e)); @@ -124,7 +123,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; r.m256d = _mm256_sub_pd(m256d, _mm256_set1_pd(e)); @@ -138,7 +137,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; r.m256d = _mm256_mul_pd(m256d, _mm256_set1_pd(e)); @@ -152,7 +151,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; r.m256d = _mm256_div_pd(m256d, _mm256_set1_pd(e)); @@ -169,7 +168,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { #ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(_mm256_set1_pd(e),v.m256d),m256d); @@ -179,7 +178,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { #ifndef __AVX2__ m256d = _mm256_add_pd(_mm256_mul_pd(v.m256d,_mm256_set1_pd(e)),m256d); @@ -195,55 +194,51 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { m256d = _mm256_mul_pd(v.m256d,_mm256_set1_pd(e)); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); return *this; } }; -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_add_pd(_mm256_set1_pd(e),v.m256d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_sub_pd(_mm256_set1_pd(e),v.m256d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_div_pd(_mm256_set1_pd(e),v.m256d); return r; } diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 2a06b3b10e..511fa67bb3 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -14,24 +14,23 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 8; static constexpr int align_size = 64; union { __m512d m512d; - scalar_t vec[size]; + double vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + inline MFEM_ALWAYS_INLINE double &operator[](int i) { return vec[i]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + inline MFEM_ALWAYS_INLINE const double &operator[](int i) const { return vec[i]; } @@ -42,7 +41,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { m512d = _mm512_set1_pd(e); return *this; @@ -50,11 +49,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { - m512d = _mm512_add_pd(m512d,v); + m512d = _mm512_add_pd(m512d,v.m512d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { m512d = _mm512_add_pd(m512d,_mm512_set1_pd(e)); return *this; @@ -62,11 +61,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { - m512d = _mm512_sub_pd(m512d,v); + m512d = _mm512_sub_pd(m512d,v.m512d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { m512d = _mm512_sub_pd(m512d,_mm512_set1_pd(e)); return *this; @@ -78,7 +77,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { m512d = _mm512_mul_pd(m512d,_mm512_set1_pd(e)); return *this; @@ -90,7 +89,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { m512d = _mm512_div_pd(m512d,_mm512_set1_pd(e)); return *this; @@ -98,7 +97,9 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { - return _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); + AutoSIMD r; + r.m512d = _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); + return r; } inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const @@ -108,7 +109,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; r.m512d = _mm512_add_pd(m512d, _mm512_set1_pd(e)); @@ -122,7 +123,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; r.m512d = _mm512_sub_pd(m512d, _mm512_set1_pd(e)); @@ -136,7 +137,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; r.m512d = _mm512_mul_pd(m512d, _mm512_set1_pd(e)); @@ -150,7 +151,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; r.m512d = _mm512_div_pd(m512d, _mm512_set1_pd(e)); @@ -163,13 +164,13 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { m512d = _mm512_fmadd_pd(_mm512_set1_pd(e),v.m512d,m512d); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { m512d = _mm512_fmadd_pd(v.m512d,_mm512_set1_pd(e),m512d); return *this; @@ -181,55 +182,51 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { m512d = _mm512_mul_pd(v.m512d,_mm512_set1_pd(e)); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); return *this; } }; -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_add_pd(_mm512_set1_pd(e),v.m512d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_sub_pd(_mm512_set1_pd(e),v.m512d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_div_pd(_mm512_set1_pd(e),v.m512d); return r; } diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp index 95837972ca..c30bb44fda 100644 --- a/config/simd/m64.hpp +++ b/config/simd/m64.hpp @@ -14,20 +14,19 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 1; static constexpr int align_size = 8; - scalar_t vec[size]; + double vec[size]; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int) + inline MFEM_ALWAYS_INLINE double &operator[](int) { return vec[0]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int) const + inline MFEM_ALWAYS_INLINE const double &operator[](int) const { return vec[0]; } @@ -38,7 +37,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { vec[0] = e; return *this; @@ -50,7 +49,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { vec[0] += e; return *this; @@ -62,7 +61,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { vec[0] -= e; return *this; @@ -74,7 +73,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { vec[0] *= e; return *this; @@ -86,7 +85,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { vec[0] /= e; return *this; @@ -106,7 +105,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; r[0] = vec[0] + e; @@ -120,7 +119,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; r[0] = vec[0] - e; @@ -134,7 +133,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; r[0] = vec[0] * e; @@ -148,7 +147,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; r[0] = vec[0] / e; @@ -161,13 +160,13 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { vec[0] += v[0] * e; return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { vec[0] += e * v[0]; return *this; @@ -179,55 +178,51 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { vec[0] = v[0] * e; return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { vec[0] = e * v[0]; return *this; } }; -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e + v[0]; return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e - v[0]; return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e * v[0]; return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e / v[0]; return r; } diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index fffa8621b9..328140162f 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -14,21 +14,20 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 4; static constexpr int align_size = 32; union { vector4double vd; - scalar_t vec[size]; + double vec[size]; }; - inline __ATTRS_ai scalar_t &operator[](int i) { return vec[i]; } + inline __ATTRS_ai double &operator[](int i) { return vec[i]; } - inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[i]; } + inline __ATTRS_ai const double &operator[](int i) const { return vec[i]; } inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) { @@ -36,7 +35,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator=(const double &e) { vd = vec_splats(e); return *this; @@ -44,11 +43,11 @@ template struct AutoSIMD inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) { - vd = vec_add(vd,v); + vd = vec_add(vd,v.vd); return *this; } - inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator+=(const double &e) { vd = vec_add(vd,vec_splats(e)); return *this; @@ -56,11 +55,11 @@ template struct AutoSIMD inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) { - vd = vec_sub(vd,v); + vd = vec_sub(vd,v.vd); return *this; } - inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator-=(const double &e) { vd = vec_sub(vd,vec_splats(e)); return *this; @@ -72,7 +71,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator*=(const double &e) { vd = vec_mul(vd,vec_splats(e)); return *this; @@ -84,7 +83,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator/=(const double &e) { vd = vec_swdiv(vd,vec_splats(e)); return *this; @@ -92,7 +91,9 @@ template struct AutoSIMD inline __ATTRS_ai AutoSIMD operator-() const { - return vec_neg(vd); + AutoSIMD r; + r.vd = vec_neg(vd); + return r; } inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const @@ -102,7 +103,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator+(const double &e) const { AutoSIMD r; r.vd = vec_add(vd, vec_splats(e)); @@ -116,7 +117,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator-(const double &e) const { AutoSIMD r; r.vd = vec_sub(vd, vec_splats(e)); @@ -130,7 +131,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator*(const double &e) const { AutoSIMD r; r.vd = vec_mul(vd, vec_splats(e)); @@ -144,7 +145,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator/(const double &e) const { AutoSIMD r; r.vd = vec_swdiv(vd, vec_splats(e)); @@ -157,13 +158,13 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const double &e) { vd = vec_madd(v.vd,vec_splats(e),vd); return *this; } - inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline __ATTRS_ai AutoSIMD &fma(const double &e, const AutoSIMD &v) { vd = vec_madd(vec_splats(e),v.vd,vd); return *this; @@ -175,55 +176,51 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const double &e) { vd = vec_mul(v.vd,vec_splats(e)); return *this; } - inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline __ATTRS_ai AutoSIMD &mul(const double &e, const AutoSIMD &v) { vd = vec_mul(vec_splats(e),v.vd); return *this; } }; -template inline __ATTRS_ai -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_add(vec_splats(e),v.vd); return r; } -template inline __ATTRS_ai -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_sub(vec_splats(e),v.vd); return r; } -template inline __ATTRS_ai -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_mul(vec_splats(e),v.vd); return r; } -template inline __ATTRS_ai -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_swdiv(vec_splats(e),v.vd); return r; } diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp index b4c0f39e6f..0b8444ec4a 100644 --- a/config/simd/qpx64.hpp +++ b/config/simd/qpx64.hpp @@ -14,17 +14,16 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 1; static constexpr int align_size = 8; - scalar_t vec[size]; + double vec[size]; - inline __ATTRS_ai scalar_t &operator[](int i) { return vec[0]; } + inline __ATTRS_ai double &operator[](int i) { return vec[0]; } - inline __ATTRS_ai const scalar_t &operator[](int i) const { return vec[0]; } + inline __ATTRS_ai const double &operator[](int i) const { return vec[0]; } inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) { @@ -32,7 +31,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator=(const double &e) { vec[0] = e; return *this; @@ -44,7 +43,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator+=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator+=(const double &e) { vec[0] += e; return *this; @@ -56,7 +55,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator-=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator-=(const double &e) { vec[0] -= e; return *this; @@ -68,7 +67,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator*=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator*=(const double &e) { vec[0] *= e; return *this; @@ -80,7 +79,7 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &operator/=(const scalar_t &e) + inline __ATTRS_ai AutoSIMD &operator/=(const double &e) { vec[0] /= e; return *this; @@ -100,7 +99,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator+(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator+(const double &e) const { AutoSIMD r; r[0] = vec[0] + e; @@ -114,7 +113,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator-(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator-(const double &e) const { AutoSIMD r; r[0] = vec[0] - e; @@ -128,7 +127,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator*(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator*(const double &e) const { AutoSIMD r; r[0] = vec[0] * e; @@ -142,7 +141,7 @@ template struct AutoSIMD return r; } - inline __ATTRS_ai AutoSIMD operator/(const scalar_t &e) const + inline __ATTRS_ai AutoSIMD operator/(const double &e) const { AutoSIMD r; r[0] = vec[0] / e; @@ -155,13 +154,13 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const double &e) { vec[0] += v[0] * e; return *this; } - inline __ATTRS_ai AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline __ATTRS_ai AutoSIMD &fma(const double &e, const AutoSIMD &v) { vec[0] += e * v[0]; return *this; @@ -173,59 +172,51 @@ template struct AutoSIMD return *this; } - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const double &e) { vec[0] = v[0] * e; return *this; } - inline __ATTRS_ai AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline __ATTRS_ai AutoSIMD &mul(const double &e, const AutoSIMD &v) { vec[0] = e * v[0]; return *this; } }; -// ***************************************************************************** -template inline __ATTRS_ai -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e + v[0]; return r; } -// ***************************************************************************** -template inline __ATTRS_ai -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e - v[0]; return r; } -// ***************************************************************************** -template inline __ATTRS_ai -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e * v[0]; return r; } -// ***************************************************************************** -template inline __ATTRS_ai -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e / v[0]; return r; } diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp index 5397ba6571..0ed0072a91 100644 --- a/config/simd/vsx128.hpp +++ b/config/simd/vsx128.hpp @@ -14,24 +14,23 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 2; static constexpr int align_size = 16; union { vector double vd; - scalar_t vec[size]; + double vec[size]; }; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + inline MFEM_ALWAYS_INLINE double &operator[](int i) { return vec[i]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + inline MFEM_ALWAYS_INLINE const double &operator[](int i) const { return vec[i]; } @@ -42,7 +41,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { vd = vec_splats(e); return *this; @@ -50,11 +49,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) { - vd = vec_add(vd,v); + vd = vec_add(vd,v.vd); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { vd = vec_add(vd,vec_splats(e)); return *this; @@ -62,11 +61,11 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) { - vd = vec_sub(vd,v); + vd = vec_sub(vd,v.vd); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { vd = vec_sub(vd,vec_splats(e)); return *this; @@ -78,7 +77,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { vd = vec_mul(vd,vec_splats(e)); return *this; @@ -90,7 +89,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { vd = vec_div(vd,vec_splats(e)); return *this; @@ -98,7 +97,9 @@ template struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { - return vec_neg(vd); + AutoSIMD r; + r.vd = vec_neg(vd); + return r; } inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const @@ -108,7 +109,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; r.vd = vec_add(vd, vec_splats(e)); @@ -122,7 +123,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; r.vd = vec_sub(vd, vec_splats(e)); @@ -136,7 +137,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; r.vd = vec_mul(vd, vec_splats(e)); @@ -150,7 +151,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; r.vd = vec_div(vd, vec_splats(e)); @@ -163,13 +164,13 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { vd = vec_madd(v.vd,vec_splats(e),vd); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { vd = vec_madd(vec_splats(e),v.vd,vd); return *this; @@ -181,55 +182,51 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { vd = vec_mul(v.vd,vec_splats(e)); return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { vd = vec_mul(vec_splats(e),v.vd); return *this; } }; -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_add(vec_splats(e),v.vd); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_sub(vec_splats(e),v.vd); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_mul(vec_splats(e),v.vd); return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_div(vec_splats(e),v.vd); return r; } diff --git a/config/simd/vsx64.hpp b/config/simd/vsx64.hpp index ae5b705feb..e5d208711d 100644 --- a/config/simd/vsx64.hpp +++ b/config/simd/vsx64.hpp @@ -14,20 +14,19 @@ #include "../tconfig.hpp" -template struct AutoSIMD +template <> struct AutoSIMD { - typedef scalar_t scalar_type; static constexpr int size = 1; static constexpr int align_size = 8; - scalar_t vec[size]; + double vec[size]; - inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) + inline MFEM_ALWAYS_INLINE double &operator[](int i) { return vec[0]; } - inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const + inline MFEM_ALWAYS_INLINE const double &operator[](int i) const { return vec[0]; } @@ -38,7 +37,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) { vec[0] = e; return *this; @@ -50,7 +49,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) { vec[0] += e; return *this; @@ -62,7 +61,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) { vec[0] -= e; return *this; @@ -74,7 +73,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) { vec[0] *= e; return *this; @@ -86,7 +85,7 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) { vec[0] /= e; return *this; @@ -106,7 +105,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const { AutoSIMD r; r[0] = vec[0] + e; @@ -120,7 +119,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const { AutoSIMD r; r[0] = vec[0] - e; @@ -134,7 +133,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const { AutoSIMD r; r[0] = vec[0] * e; @@ -148,7 +147,7 @@ template struct AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const { AutoSIMD r; r[0] = vec[0] / e; @@ -161,13 +160,13 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) { vec[0] += v[0] * e; return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) { vec[0] += e * v[0]; return *this; @@ -179,55 +178,51 @@ template struct AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) { vec[0] = v[0] * e; return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) { vec[0] = e * v[0]; return *this; } }; -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e + v[0]; return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e - v[0]; return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e * v[0]; return r; } -template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const scalar_t &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r[0] = e / v[0]; return r; } diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 19b59f80cd..3ad2a9afbc 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -68,13 +68,20 @@ #elif defined(__VSX__) #define MFEM_SIMD_SIZE 16 #define MFEM_TEMPLATE_BLOCK_SIZE 2 +#elif defined(__MIC__) || defined(__AVX512F__) +#define MFEM_SIMD_SIZE 64 +#define MFEM_TEMPLATE_BLOCK_SIZE 8 #elif defined(__x86_64__) #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 #else +#warning No SIMD #error Unknown SIMD architecture #endif +namespace mfem +{ + template struct AutoImplTraits { @@ -95,6 +102,8 @@ struct AutoImplTraits #endif // MFEM_USE_SIMD }; +} // mfem namespace + #define MFEM_TEMPLATE_ENABLE_SERIALIZE // #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 68c3f7040b..85843590ee 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -117,7 +117,11 @@ public: coeff(integ.coeff), assembled_data(), in_fes(sol_fes) - { assembled_data.Reset(MemoryType::HOST_32); } + { + assembled_data.Reset(SS == 64 ? MemoryType::HOST_64 : + SS == 32 ? MemoryType::HOST_32 : + MemoryType::HOST); + } virtual ~TBilinearForm() { diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 571d99c324..7713a8d88f 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -65,7 +65,6 @@ MFEM_PERF_CXXFLAGS_clang += -pedantic -Wall MFEM_PERF_CXXFLAGS_clang += -fcolor-diagnostics MFEM_PERF_CXXFLAGS_clang += -fvectorize MFEM_PERF_CXXFLAGS_clang += -fslp-vectorize -MFEM_PERF_CXXFLAGS_clang += -fslp-vectorize-aggressive MFEM_PERF_CXXFLAGS_clang += -ffp-contract=fast # - Intel C++ compiler extra options: From cd0c6e6a0cfdb0aa2e2660d21385a367a3bec22f Mon Sep 17 00:00:00 2001 From: camierjs Date: Mon, 27 Apr 2020 11:44:07 -0700 Subject: [PATCH 221/535] Revert auto.hpp and cleanup --- config/simd/auto.hpp | 69 ++++++++++++++++++++++---------------------- config/simd/qpx.hpp | 2 +- config/tconfig.hpp | 14 ++++----- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index 22b8ef6876..b0815d19ab 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -14,20 +14,21 @@ #include "../tconfig.hpp" -template -struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD +template +struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD { + typedef scalar_t scalar_type; static const int size = S; static const int align_size = align_S; - double vec[size]; + scalar_t vec[size]; - inline MFEM_ALWAYS_INLINE double &operator[](int i) + inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i) { return vec[i]; } - inline MFEM_ALWAYS_INLINE const double &operator[](int i) const + inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const { return vec[i]; } @@ -39,7 +40,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e; } @@ -53,7 +54,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e; } @@ -67,7 +68,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] -= e; } @@ -81,7 +82,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] *= e; } @@ -95,7 +96,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] /= e; } @@ -118,7 +119,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -134,7 +135,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -150,7 +151,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -166,7 +167,7 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return r; } - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const + inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const { AutoSIMD r; MFEM_VECTORIZE_LOOP @@ -181,14 +182,14 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += v[i] * e; } return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] += e * v[i]; } @@ -202,14 +203,14 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = v[i] * e; } return *this; } - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) + inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v) { MFEM_VECTORIZE_LOOP for (int i = 0; i < size; i++) { vec[i] = e * v[i]; } @@ -217,45 +218,45 @@ struct MFEM_ALIGN_AS(align_S*sizeof(double)) AutoSIMD } }; -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) +AutoSIMD operator+(const scalar_t &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e + v[i]; } return r; } -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) +AutoSIMD operator-(const scalar_t &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e - v[i]; } return r; } -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) +AutoSIMD operator*(const scalar_t &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e * v[i]; } return r; } -template +template inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) +AutoSIMD operator/(const scalar_t &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; MFEM_VECTORIZE_LOOP for (int i = 0; i < S; i++) { r[i] = e / v[i]; } return r; diff --git a/config/simd/qpx.hpp b/config/simd/qpx.hpp index 54797fd761..254504bfde 100644 --- a/config/simd/qpx.hpp +++ b/config/simd/qpx.hpp @@ -14,7 +14,7 @@ #include "builtins.h" -//template struct AutoSIMD; +template struct AutoSIMD; #include "qpx64.hpp" diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 3ad2a9afbc..27f9af0c7b 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -65,18 +65,18 @@ #if defined(_WIN32) #define MFEM_SIMD_SIZE 8 #define MFEM_TEMPLATE_BLOCK_SIZE 1 -#elif defined(__VSX__) -#define MFEM_SIMD_SIZE 16 -#define MFEM_TEMPLATE_BLOCK_SIZE 2 -#elif defined(__MIC__) || defined(__AVX512F__) +#elif defined(__AVX512F__) #define MFEM_SIMD_SIZE 64 #define MFEM_TEMPLATE_BLOCK_SIZE 8 -#elif defined(__x86_64__) +#elif defined(__AVX__) || defined(__VECTOR4DOUBLE__) #define MFEM_SIMD_SIZE 32 #define MFEM_TEMPLATE_BLOCK_SIZE 4 +#elif defined(__SSE2__) || defined(__VSX__) +#define MFEM_SIMD_SIZE 16 +#define MFEM_TEMPLATE_BLOCK_SIZE 2 #else -#warning No SIMD -#error Unknown SIMD architecture +#define MFEM_SIMD_SIZE 8 +#define MFEM_TEMPLATE_BLOCK_SIZE 1 #endif namespace mfem From 1c9bdb456be9c5c83abf904af59d015535438d68 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 27 Apr 2020 13:40:47 -0700 Subject: [PATCH 222/535] Adding FaceElementTransformation::SetIntPoint method --- fem/eltrans.cpp | 16 ++++++++++++++++ fem/eltrans.hpp | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index 017f7acf00..df8f9cab3f 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -635,6 +635,22 @@ FaceElementTransformations::GetActivePointTransformation() } } +void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) +{ + IsoparametricTransformation::SetIntPoint(ip); + + if (Elem1) + { + Loc1.Transform(*ip, eip1); + Elem1->SetIntPoint(&eip1); + } + if (Elem2) + { + Loc2.Transform(*ip, eip2); + Elem2->SetIntPoint(&eip2); + } +} + void FaceElementTransformations::Transform(const IntegrationPoint &ip, Vector &trans) { diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index daedbfbca1..47eaceec24 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -383,6 +383,8 @@ private: int side; int mask; + IntegrationPoint eip1, eip2; + public: int Elem1No, Elem2No; Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead @@ -433,6 +435,9 @@ public: void SetConfigurationMask(int m) { mask = m; } int GetConfigurationMask() const { return mask; } + /// Sets integration point on the face and neighboring elements. + void SetIntPoint(const IntegrationPoint *ip); + virtual void Transform(const IntegrationPoint &, Vector &); virtual void Transform(const IntegrationRule &, DenseMatrix &); virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); From 07344159a4f18c72967f59448b66c025624f8377 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 27 Apr 2020 13:41:32 -0700 Subject: [PATCH 223/535] Implementing GridFunction::GetGradient which works on boundary elements --- fem/gridfunc.cpp | 73 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index f68a20622e..6768879baa 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1304,22 +1304,67 @@ void GridFunction::GetCurl(ElementTransformation &tr, Vector &curl) const } } -void GridFunction::GetGradient(ElementTransformation &tr, Vector &grad) const +void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const { - int elNo = tr.ElementNo; - const FiniteElement *fe = fes->GetFE(elNo); - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); - int dim = fe->GetDim(), dof = fe->GetDof(); - DenseMatrix dshape(dof, dim); - Vector lval, gh(dim); - Array dofs; + const FiniteElement * fe = NULL; + if (T.ElementType == ElementTransformation::ELEMENT) + { + fe = fes->GetFE(T.ElementNo); + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + int spaceDim = fes->GetMesh()->SpaceDimension(); + int dim = fe->GetDim(), dof = fe->GetDof(); + DenseMatrix dshape(dof, dim); + Vector lval, gh(dim); + Array dofs; - grad.SetSize(dim); - fes->GetElementDofs(elNo, dofs); - GetSubVector(dofs, lval); - fe->CalcDShape(tr.GetIntPoint(), dshape); - dshape.MultTranspose(lval, gh); - tr.InverseJacobian().MultTranspose(gh, grad); + grad.SetSize(spaceDim); + fes->GetElementDofs(T.ElementNo, dofs); + GetSubVector(dofs, lval); + fe->CalcDShape(T.GetIntPoint(), dshape); + dshape.MultTranspose(lval, gh); + T.InverseJacobian().MultTranspose(gh, grad); + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + FaceElementTransformations * FET = NULL; + + fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field. Check for DG context. + FET = dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } + } + else + { + /// Not a DG field but we will need the neighboring element. + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + FET->SetActiveSide(0); + FET->SetIntPoint(&T.GetIntPoint()); + } + GetGradient(*FET->GetActiveElementTransformation(), grad); + } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + GetGradient(*FET->GetActiveElementTransformation(), grad); + } + } + else + { + MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \"" + << T.ElementType << "\""); + } } void GridFunction::GetGradients(ElementTransformation &tr, From 4b99e0096f04c068ee3120fc6cff81aa4673d03a Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 27 Apr 2020 14:23:11 -0700 Subject: [PATCH 224/535] Generalizing GetDivergence and GetCurl to work on boundary elements --- fem/gridfunc.cpp | 207 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 147 insertions(+), 60 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 6768879baa..6a2180424d 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1219,88 +1219,175 @@ void GridFunction::GetVectorGradientHat( MultAtB(loc_data_mat, dshape, gh); } -double GridFunction::GetDivergence(ElementTransformation &tr) const +double GridFunction::GetDivergence(ElementTransformation &T) const { - double div_v; - int elNo = tr.ElementNo; - const FiniteElement *FElem = fes->GetFE(elNo); - if (FElem->GetRangeType() == FiniteElement::SCALAR) + double div_v = 0.0; + + if (T.ElementType == ElementTransformation::ELEMENT) { - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - DenseMatrix grad_hat; - GetVectorGradientHat(tr, grad_hat); - const DenseMatrix &Jinv = tr.InverseJacobian(); - div_v = 0.0; - for (int i = 0; i < Jinv.Width(); i++) + int elNo = T.ElementNo; + const FiniteElement *fe = fes->GetFE(elNo); + if (fe->GetRangeType() == FiniteElement::SCALAR) { - for (int j = 0; j < Jinv.Height(); j++) + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + DenseMatrix grad_hat; + GetVectorGradientHat(T, grad_hat); + const DenseMatrix &Jinv = T.InverseJacobian(); + div_v = 0.0; + for (int i = 0; i < Jinv.Width(); i++) { - div_v += grad_hat(i, j) * Jinv(j, i); + for (int j = 0; j < Jinv.Height(); j++) + { + div_v += grad_hat(i, j) * Jinv(j, i); + } } } + else + { + // Assuming RT-type space + Array dofs; + fes->GetElementDofs(elNo, dofs); + Vector loc_data, divshape(fe->GetDof()); + GetSubVector(dofs, loc_data); + fe->CalcDivShape(T.GetIntPoint(), divshape); + div_v = (loc_data * divshape) / T.Weight(); + } + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + FaceElementTransformations * FET = NULL; + + const FiniteElement *fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field. Check for DG context. + FET = dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } + } + else + { + /// Not a DG field but we will need the neighboring element. + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + FET->SetActiveSide(0); + FET->SetIntPoint(&T.GetIntPoint()); + } + div_v = GetDivergence(*FET->GetActiveElementTransformation()); + } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + div_v = GetDivergence(*FET->GetActiveElementTransformation()); + } } else { - // Assuming RT-type space - Array dofs; - fes->GetElementDofs(elNo, dofs); - Vector loc_data, divshape(FElem->GetDof()); - GetSubVector(dofs, loc_data); - FElem->CalcDivShape(tr.GetIntPoint(), divshape); - div_v = (loc_data * divshape) / tr.Weight(); + MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \"" + << T.ElementType << "\""); } return div_v; } -void GridFunction::GetCurl(ElementTransformation &tr, Vector &curl) const +void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const { - int elNo = tr.ElementNo; - const FiniteElement *FElem = fes->GetFE(elNo); - if (FElem->GetRangeType() == FiniteElement::SCALAR) + if (T.ElementType == ElementTransformation::ELEMENT) { - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - DenseMatrix grad_hat; - GetVectorGradientHat(tr, grad_hat); - const DenseMatrix &Jinv = tr.InverseJacobian(); - DenseMatrix grad(grad_hat.Height(), Jinv.Width()); // vdim x FElem->Dim - Mult(grad_hat, Jinv, grad); - MFEM_ASSERT(grad.Height() == grad.Width(), ""); - if (grad.Height() == 3) + int elNo = T.ElementNo; + const FiniteElement *fe = fes->GetFE(elNo); + if (fe->GetRangeType() == FiniteElement::SCALAR) { - curl.SetSize(3); - curl(0) = grad(2,1) - grad(1,2); - curl(1) = grad(0,2) - grad(2,0); - curl(2) = grad(1,0) - grad(0,1); + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + DenseMatrix grad_hat; + GetVectorGradientHat(T, grad_hat); + const DenseMatrix &Jinv = T.InverseJacobian(); + DenseMatrix grad(grad_hat.Height(), Jinv.Width()); // vdim x FElem->Dim + Mult(grad_hat, Jinv, grad); + MFEM_ASSERT(grad.Height() == grad.Width(), ""); + if (grad.Height() == 3) + { + curl.SetSize(3); + curl(0) = grad(2,1) - grad(1,2); + curl(1) = grad(0,2) - grad(2,0); + curl(2) = grad(1,0) - grad(0,1); + } + else if (grad.Height() == 2) + { + curl.SetSize(1); + curl(0) = grad(1,0) - grad(0,1); + } } - else if (grad.Height() == 2) + else { - curl.SetSize(1); - curl(0) = grad(1,0) - grad(0,1); + // Assuming ND-type space + Array dofs; + fes->GetElementDofs(elNo, dofs); + Vector loc_data; + GetSubVector(dofs, loc_data); + DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1); + fe->CalcCurlShape(T.GetIntPoint(), curl_shape); + curl.SetSize(curl_shape.Width()); + if (curl_shape.Width() == 3) + { + double curl_hat[3]; + curl_shape.MultTranspose(loc_data, curl_hat); + T.Jacobian().Mult(curl_hat, curl); + } + else + { + curl_shape.MultTranspose(loc_data, curl); + } + curl /= T.Weight(); + } + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + FaceElementTransformations * FET = NULL; + + const FiniteElement *fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field. Check for DG context. + FET = dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } + } + else + { + /// Not a DG field but we will need the neighboring element. + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + FET->SetActiveSide(0); + FET->SetIntPoint(&T.GetIntPoint()); + } + GetCurl(*FET->GetActiveElementTransformation(), curl); + } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + GetCurl(*FET->GetActiveElementTransformation(), curl); } } else { - // Assuming ND-type space - Array dofs; - fes->GetElementDofs(elNo, dofs); - Vector loc_data; - GetSubVector(dofs, loc_data); - DenseMatrix curl_shape(FElem->GetDof(), FElem->GetDim() == 3 ? 3 : 1); - FElem->CalcCurlShape(tr.GetIntPoint(), curl_shape); - curl.SetSize(curl_shape.Width()); - if (curl_shape.Width() == 3) - { - double curl_hat[3]; - curl_shape.MultTranspose(loc_data, curl_hat); - tr.Jacobian().Mult(curl_hat, curl); - } - else - { - curl_shape.MultTranspose(loc_data, curl); - } - curl /= tr.Weight(); + MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \"" + << T.ElementType << "\""); } } From 7c857883ad9deb32c934bd39b7772ff8a6130939 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 27 Apr 2020 14:26:36 -0700 Subject: [PATCH 225/535] Generalizing GetVectorGradient --- fem/gridfunc.cpp | 59 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 6a2180424d..b0d087ffc7 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1480,15 +1480,58 @@ void GridFunction::GetGradients(ElementTransformation &tr, } void GridFunction::GetVectorGradient( - ElementTransformation &tr, DenseMatrix &grad) const + ElementTransformation &T, DenseMatrix &grad) const { - MFEM_ASSERT(fes->GetFE(tr.ElementNo)->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - DenseMatrix grad_hat; - GetVectorGradientHat(tr, grad_hat); - const DenseMatrix &Jinv = tr.InverseJacobian(); - grad.SetSize(grad_hat.Height(), Jinv.Width()); - Mult(grad_hat, Jinv, grad); + if (T.ElementType == ElementTransformation::ELEMENT) + { + MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + DenseMatrix grad_hat; + GetVectorGradientHat(T, grad_hat); + const DenseMatrix &Jinv = T.InverseJacobian(); + grad.SetSize(grad_hat.Height(), Jinv.Width()); + Mult(grad_hat, Jinv, grad); + } + else if (T.ElementType == ElementTransformation::BDR_ELEMENT) + { + FaceElementTransformations * FET = NULL; + + const FiniteElement *fe = fes->GetBE(T.ElementNo); + + if (fe == NULL) + { + // This must be a DG field. Check for DG context. + FET = dynamic_cast(&T); + if (FET == NULL) + { + // non-DG context + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + } + } + else + { + /// Not a DG field but we will need the neighboring element. + FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + FET->SetActiveSide(0); + FET->SetIntPoint(&T.GetIntPoint()); + } + GetVectorGradient(*FET->GetActiveElementTransformation(), grad); + } + else if (T.ElementType == ElementTransformation::FACE) + { + // This must be a DG field called in a DG context. + FaceElementTransformations * FET = + dynamic_cast(&T); + if (FET != NULL) + { + GetVectorGradient(*FET->GetActiveElementTransformation(), grad); + } + } + else + { + MFEM_ABORT("GridFunction::GetVectorGradient: Unsupported element type \"" + << T.ElementType << "\""); + } } void GridFunction::GetElementAverages(GridFunction &avgs) const From b03da60c17340191d8093e9924941d0dfae31ae6 Mon Sep 17 00:00:00 2001 From: Samiullah Malik Date: Mon, 27 Apr 2020 19:41:49 -0400 Subject: [PATCH 226/535] Implements NedelecFieldMFEMtoPUMI --- mesh/pumi.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ mesh/pumi.hpp | 6 +++ 2 files changed, 129 insertions(+) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index d9598bbb9d..2230061b51 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -1493,6 +1493,129 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf_mesh->end(itr); } +static int findIndex(mfem::Array array, int value) +{ + int size = array.Size(); + for (int i = 0; i < size; i++) { + if (value == array[i] ) return i; + } + return -1; +} +void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, + ParGridFunction* gf, + apf::Field* NedelecField) +{ + apf::Numbering* local_vtx_numbering = apf_mesh->getNumbering(0); // TODO + + apf::FieldShape* nedelecFieldShape = NedelecField->getShape(); + int num_nodes = 4 * nedelecFieldShape->countNodesOn(0) + // Vertex + 6 * nedelecFieldShape->countNodesOn(1) + // Edge + 4 * nedelecFieldShape->countNodesOn(2) + // Triangle + nedelecFieldShape->countNodesOn(4); // Tetrahedron + int dim = apf_mesh->getDimension(); + apf::NewArray pumi_nodes (num_nodes); + + size_t elemNo = 0; + apf::MeshEntity* el_ent; + apf::MeshIterator* el_it; + el_it = apf_mesh->begin(dim); + while ( el_ent = apf_mesh->iterate(el_it) ) { + + // TODO use getPumiNodeXis to collect pumi nodes when fixed + // collect pumi nodes + int node_number = 0; + for (int d = 0; d <= dim; d++) { + if (nedelecFieldShape->hasNodesIn(d)) { + apf::Downward a; + int na = apf_mesh->getDownward(el_ent,d,a); + for (int i = 0; i < na; i++) { // loop over downward entities + int type = apf_mesh->getType(a[i]); + int nan = nedelecFieldShape->countNodesOn(type); + for (int n = 0; n < nan; n++) { // loop over entity nodes + apf::Vector3 ent_xi; + nedelecFieldShape->getNodeXi(type, n, ent_xi); // getNodeXi + apf::Vector3 elem_xi = apf::boundaryToElementXi( + apf_mesh, a[i], el_ent, ent_xi); // transform entity nodeXi to parent element nodeXi. + pumi_nodes[node_number++] = elem_xi; + } + } + } + } + + // get downward vertices of PUMI element + apf::Downward v; + int nv = apf_mesh->getDownward(el_ent,0,v); + std::vector pumi_vtx_indices (nv); + for (int i = 0; i < nv; i++) + pumi_vtx_indices[i] = apf::getNumber(local_vtx_numbering, v[i], 0, 0); + + // get downward vertices of MFEM element + mfem::Array mfem_vtx_indices; + this->GetElementVertices(elemNo, mfem_vtx_indices); + + // get rotated indices of PUMI element + int pumi_tetv[nv]; + for (int i = 0; i < nv; i++) + pumi_tetv[i] = findIndex(mfem_vtx_indices, pumi_vtx_indices[i]); + apf::Downward rv; + for (int i = 0; i < nv; i++) + rv[i] = v[ pumi_tetv[i] ]; + int rotation = ma::findTetRotation(apf_mesh, el_ent, rv); + + // map the coordinates computed on the original set of vertices + // to the coordinates computed based on a rotated set of vertices + IntegrationRule mfem_nodes (num_nodes); + for(int i = 0; i < num_nodes; i++) { + ma::rotateTetXi(pumi_nodes[i], rotation); + IntegrationPoint& ip = mfem_nodes.IntPoint(i); + double xi[3]; + pumi_nodes[i].toArray(xi); + ip.Set(xi,3); + } + + // evaluate the vector field on the mfem nodes + ElementTransformation* eltr = this->GetElementTransformation(elemNo); + DenseMatrix mfem_field_vals; + gf->GetVectorValues(*eltr, mfem_nodes, mfem_field_vals); + + // compute and store dofs on ND field + node_number = 0; + for (int d = 0; d <= dim; d++) { + if (nedelecFieldShape->hasNodesIn(d)) { + apf::Downward a; + int na = apf_mesh->getDownward(el_ent,d,a); + for (int i = 0; i < na; i++) { // loop over downward entities + int type = apf_mesh->getType(a[i]); + int nan = nedelecFieldShape->countNodesOn(type); + apf::MeshElement* me = apf::createMeshElement(apf_mesh, a[i]); + for (int n = 0; n < nan; n++) { // loop over entity nodes + apf::Vector3 xi, tangent; + nedelecFieldShape->getNodeXi(type, n, xi); // getNodeXi + nedelecFieldShape->getNodeTangent(type, n, tangent); // getNodeTangent + + apf::Vector3 pumi_field_vector; // getVectorValue in PUMI + pumi_field_vector[0] = mfem_field_vals(0,node_number); + pumi_field_vector[1] = mfem_field_vals(1,node_number); + pumi_field_vector[2] = mfem_field_vals(2,node_number); + + apf::Matrix3x3 J; // get Jacobian + apf::getJacobian(me, xi, J); + + apf::Vector3 temp = J * pumi_field_vector; // compute scalar dof + double dof = temp * tangent; + apf::setScalar(NedelecField, a[i], n, dof); + + node_number++; + } + apf::destroyMeshElement(me); + } + } + } + elemNo++; + } + apf_mesh->end(el_it); // end loop over all elements +} + void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, apf::Field* ScalarField, ParGridFunction* Pr) diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 10aa161ca9..9282cf004f 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -33,8 +33,10 @@ #include #include #include +#include #include #include +#include namespace mfem { @@ -96,6 +98,10 @@ public: apf::Field* VelField, apf::Field* VelMagField); + void NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, + ParGridFunction* gf, + apf::Field* NedelecField); + /// Update the mesh after adaptation. void UpdateMesh(const ParMesh* AdaptedpMesh); From ad4b4c902e33b3984a0a0fd82eed1f13a37692a2 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 28 Apr 2020 09:51:46 -0700 Subject: [PATCH 227/535] Update CGSolver with user options and default values --- fem/field_interpolant.hpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index ebed793df1..efccb1ecda 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -83,13 +83,14 @@ public: L2->Update(); L2->Assemble(); } - virtual void SetupCG() + virtual void SetupCG(int print_level = 0, int max_iter = 2000, + double rel_tol = 1e-15, double abs_tol = 0.0) { cg = new CGSolver(); - cg->SetPrintLevel(0); - cg->SetMaxIter(2000); - cg->SetRelTol(sqrt(1e-30)); - cg->SetAbsTol(sqrt(0.0)); + cg->SetPrintLevel(print_level); + cg->SetMaxIter(max_iter); + cg->SetRelTol(rel_tol); + cg->SetAbsTol(abs_tol); } ~FieldInterpolant() { @@ -137,13 +138,14 @@ public: } using FieldInterpolant::SetupCG; // Setup the CG solver with an MPI communicator - virtual void SetupCG(MPI_Comm _comm) + virtual void SetupCG(MPI_Comm _comm, int print_level = 0, int max_iter = 2000, + double rel_tol = 1e-15, double abs_tol = 0.0) { cg = new CGSolver(_comm); - cg->SetPrintLevel(0); - cg->SetMaxIter(2000); - cg->SetRelTol(sqrt(1e-30)); - cg->SetAbsTol(sqrt(0.0)); + cg->SetPrintLevel(print_level); + cg->SetMaxIter(max_iter); + cg->SetRelTol(rel_tol); + cg->SetAbsTol(abs_tol); } ~ParFieldInterpolant() From ddddb3dab8adaa0b876da219f3e1b043ae129e1f Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 28 Apr 2020 10:50:06 -0700 Subject: [PATCH 228/535] fix ambiguous default parameter issue for the parallel builds Since MPI_Comm is an int type the compiler was getting confused when trying to compile the parallel unit tests. So, I just moved the double parameters before the int CGSolver parameters. --- fem/field_interpolant.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index efccb1ecda..e45f9e22f5 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -39,12 +39,14 @@ protected: Vector m_all_data; BilinearForm *L2; CGSolver *cg; + FiniteElementSpace *fes; int NE; public: // The FiniteElementSpace passed into here should have a vdim set to 1 in order for the // MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with // a VectorQuadratureFunctionCoefficient. - FieldInterpolant(FiniteElementSpace *fes) : setup_disc(false), setup_full(false) + FieldInterpolant(FiniteElementSpace *fes) : setup_disc(false), + setup_full(false), fes(fes) { L2 = new BilinearForm(fes); @@ -83,8 +85,8 @@ public: L2->Update(); L2->Assemble(); } - virtual void SetupCG(int print_level = 0, int max_iter = 2000, - double rel_tol = 1e-15, double abs_tol = 0.0) + virtual void SetupCG(double rel_tol = 1e-15, double abs_tol = 0.0, + int print_level = 0, int max_iter = 2000) { cg = new CGSolver(); cg->SetPrintLevel(print_level); @@ -138,8 +140,9 @@ public: } using FieldInterpolant::SetupCG; // Setup the CG solver with an MPI communicator - virtual void SetupCG(MPI_Comm _comm, int print_level = 0, int max_iter = 2000, - double rel_tol = 1e-15, double abs_tol = 0.0) + virtual void SetupCG(MPI_Comm _comm, double rel_tol = 1e-15, + double abs_tol = 0.0, + int print_level = 0, int max_iter = 2000) { cg = new CGSolver(_comm); cg->SetPrintLevel(print_level); From 3d1082041745440f27d69cb9b3e7ff0740150bf5 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 28 Apr 2020 11:20:07 -0700 Subject: [PATCH 229/535] Accidentally left FES in here when playing around with things --- fem/field_interpolant.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index e45f9e22f5..18385c9a6e 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -39,14 +39,12 @@ protected: Vector m_all_data; BilinearForm *L2; CGSolver *cg; - FiniteElementSpace *fes; int NE; public: // The FiniteElementSpace passed into here should have a vdim set to 1 in order for the // MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with // a VectorQuadratureFunctionCoefficient. - FieldInterpolant(FiniteElementSpace *fes) : setup_disc(false), - setup_full(false), fes(fes) + FieldInterpolant(FiniteElementSpace *fes) : setup_disc(false), setup_full(false) { L2 = new BilinearForm(fes); From 5925b7dfa836f8ddb803beca384cd1ffc551ee9d Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Tue, 28 Apr 2020 13:27:48 -0700 Subject: [PATCH 230/535] init commit of batch lu decomp --- linalg/densemat.cpp | 122 ++++++++++++++++++++++++ linalg/densemat.hpp | 3 + tests/unit/linalg/test_matrix_dense.cpp | 44 +++++++++ 3 files changed, 169 insertions(+) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 710d47727c..57652c713a 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -17,6 +17,8 @@ #include "vector.hpp" #include "matrix.hpp" #include "densemat.hpp" +#include "kernels.hpp" +#include "../general/forall.hpp" #include "../general/table.hpp" #include "../general/globals.hpp" @@ -3503,4 +3505,124 @@ DenseTensor &DenseTensor::operator=(double c) return *this; } +void BatchLUFactor(DenseTensor &Minv, Array &P) +{ + + int m = Minv.SizeI(); + int NE = Minv.SizeK(); + P.SetSize(m*NE); + auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); + auto piv_all = mfem::Reshape(P.Write(), m, NE); + + MFEM_FORALL(e, NE, + { + + double *data = &data_all(0,0,e); + int *ipiv = &piv_all(0,e); + for (int i = 0; i < m; i++) + { + + // pivoting + { + int piv = i; + double a = fabs(data[piv+i*m]); + for (int j = i+1; j < m; j++) + { + const double b = fabs(data[j+i*m]); + if (b > a) + { + a = b; + piv = j; + } + } + ipiv[i] = piv; + if (piv != i) + { + // swap rows i and piv in both L and U parts + for (int j = 0; j < m; j++) + { + //mfem::kernels::internal::Swap(data[i+j*m], data[piv+j*m]); + //Hit a segfault... + double tmp = data[i+j*m]; + data[i+j*m] = data[piv+j*m]; + data[piv+j*m] = tmp; + } + } + }//pivot end + + //Q: How to check for errors? + //if (abs(data[i + i*m]) <= TOL) + //{ + //return false; // failed + //} + + const double a_ii_inv = 1.0 / data[i+i*m]; + for (int j = i+1; j < m; j++) + { + data[j+i*m] *= a_ii_inv; + } + + for (int k = i+1; k < m; k++) + { + const double a_ik = data[i+k*m]; + for (int j = i+1; j < m; j++) + { + data[j+k*m] -= a_ik * data[j+i*m]; + } + } + + }//m loop + + }); + } + +void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X) +{ + + int m = Minv.SizeI(); + int NE = Minv.SizeK(); + auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); + auto piv_all = mfem::Reshape(P.Read(), m, NE); + auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); + + MFEM_FORALL(e, NE, + { + + const double *data = &data_all(0,0,e); + const int *ipiv = &piv_all(0,e); + double *x = &x_all(0,e); + + // X <- P X + for (int i = 0; i < m; i++) + { + //Swap(x[i], x[ipiv[i]-ipiv_base]); //Hit a segfault... + double tmp = x[i]; + x[i] = x[ipiv[i]]; + x[ipiv[i]] = tmp; + } + + // X <- L^{-1} X + for (int j = 0; j < m; j++) + { + const double x_j = x[j]; + for (int i = j+1; i < m; i++) + { + x[i] -= data[i+j*m] * x_j; + } + } + + // X <- U^{-1} X + for (int j = m-1; j >= 0; j--) + { + const double x_j = ( x[j] /= data[j+j*m] ); + for (int i = 0; i < j; i++) + { + x[i] -= data[i+j*m] * x_j; + } + } + }); + +} + +} //namespace diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 3cd4abac12..e376feb244 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -859,6 +859,9 @@ public: ~DenseTensor() { tdata.Delete(); } }; +void BatchLUFactor(DenseTensor &Minv, Array &P); + +void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X); // Inline methods diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index 0f178c0e13..d20d441f6b 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -11,6 +11,7 @@ #include "mfem.hpp" #include "catch.hpp" +#include "../../../linalg/dtensor.hpp" using namespace mfem; @@ -245,3 +246,46 @@ TEST_CASE("LUFactors RightSolve", "[DenseMatrix]") REQUIRE(C.MaxMaxNorm() < tol); } + +TEST_CASE("DenseTensor LinearSolve methods", + "[DenseMatrix]") +{ + + int N = 3; + DenseMatrix A(N); + A(0,0) = 4; A(0,1) = 5; A(0,2) = -2; + A(1,0) = 7; A(1,1) = -1; A(1,2) = 2; + A(2,0) = 3; A(2,1) = 1; A(2,2) = 4; + + double X[3] = { -14, 42, 28 }; + + int NE = 10; + Vector X_batch(N*NE); + DenseTensor A_batch(N, N, NE); + + auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE); + auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE); + //Column major + for(int e=0; e P; + BatchLUFactor(A_batch, P); + BatchLUSolve(A_batch, P, X_batch); + + auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE); + REQUIRE(LinearSolve(A,X)); + for(int e=0; e Date: Tue, 28 Apr 2020 13:36:05 -0700 Subject: [PATCH 231/535] make style --- linalg/densemat.cpp | 188 ++++++++++++------------ tests/unit/linalg/test_matrix_dense.cpp | 71 ++++----- 2 files changed, 132 insertions(+), 127 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 57652c713a..86b3c0e8fc 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3507,121 +3507,121 @@ DenseTensor &DenseTensor::operator=(double c) void BatchLUFactor(DenseTensor &Minv, Array &P) { - - int m = Minv.SizeI(); - int NE = Minv.SizeK(); - P.SetSize(m*NE); - auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); - auto piv_all = mfem::Reshape(P.Write(), m, NE); - MFEM_FORALL(e, NE, - { + int m = Minv.SizeI(); + int NE = Minv.SizeK(); + P.SetSize(m*NE); + auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); + auto piv_all = mfem::Reshape(P.Write(), m, NE); - double *data = &data_all(0,0,e); - int *ipiv = &piv_all(0,e); - for (int i = 0; i < m; i++) - { + MFEM_FORALL(e, NE, + { - // pivoting + double *data = &data_all(0,0,e); + int *ipiv = &piv_all(0,e); + for (int i = 0; i < m; i++) { - int piv = i; - double a = fabs(data[piv+i*m]); + + // pivoting + { + int piv = i; + double a = fabs(data[piv+i*m]); + for (int j = i+1; j < m; j++) + { + const double b = fabs(data[j+i*m]); + if (b > a) + { + a = b; + piv = j; + } + } + ipiv[i] = piv; + if (piv != i) + { + // swap rows i and piv in both L and U parts + for (int j = 0; j < m; j++) + { + //mfem::kernels::internal::Swap(data[i+j*m], data[piv+j*m]); + //Hit a segfault... + double tmp = data[i+j*m]; + data[i+j*m] = data[piv+j*m]; + data[piv+j*m] = tmp; + } + } + }//pivot end + + //Q: How to check for errors? + //if (abs(data[i + i*m]) <= TOL) + //{ + //return false; // failed + //} + + const double a_ii_inv = 1.0 / data[i+i*m]; for (int j = i+1; j < m; j++) { - const double b = fabs(data[j+i*m]); - if (b > a) + data[j+i*m] *= a_ii_inv; + } + + for (int k = i+1; k < m; k++) + { + const double a_ik = data[i+k*m]; + for (int j = i+1; j < m; j++) { - a = b; - piv = j; + data[j+k*m] -= a_ik * data[j+i*m]; } } - ipiv[i] = piv; - if (piv != i) - { - // swap rows i and piv in both L and U parts - for (int j = 0; j < m; j++) - { - //mfem::kernels::internal::Swap(data[i+j*m], data[piv+j*m]); - //Hit a segfault... - double tmp = data[i+j*m]; - data[i+j*m] = data[piv+j*m]; - data[piv+j*m] = tmp; - } - } - }//pivot end - - //Q: How to check for errors? - //if (abs(data[i + i*m]) <= TOL) - //{ - //return false; // failed - //} - - const double a_ii_inv = 1.0 / data[i+i*m]; - for (int j = i+1; j < m; j++) - { - data[j+i*m] *= a_ii_inv; - } - - for (int k = i+1; k < m; k++) - { - const double a_ik = data[i+k*m]; - for (int j = i+1; j < m; j++) - { - data[j+k*m] -= a_ik * data[j+i*m]; - } - } }//m loop - }); + }); } void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X) { - - int m = Minv.SizeI(); - int NE = Minv.SizeK(); - auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); - auto piv_all = mfem::Reshape(P.Read(), m, NE); - auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); - MFEM_FORALL(e, NE, - { + int m = Minv.SizeI(); + int NE = Minv.SizeK(); + auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); + auto piv_all = mfem::Reshape(P.Read(), m, NE); + auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); - const double *data = &data_all(0,0,e); - const int *ipiv = &piv_all(0,e); - double *x = &x_all(0,e); - - // X <- P X - for (int i = 0; i < m; i++) - { - //Swap(x[i], x[ipiv[i]-ipiv_base]); //Hit a segfault... - double tmp = x[i]; - x[i] = x[ipiv[i]]; - x[ipiv[i]] = tmp; - } + MFEM_FORALL(e, NE, + { - // X <- L^{-1} X - for (int j = 0; j < m; j++) - { - const double x_j = x[j]; - for (int i = j+1; i < m; i++) - { - x[i] -= data[i+j*m] * x_j; - } - } + const double *data = &data_all(0,0,e); + const int *ipiv = &piv_all(0,e); + double *x = &x_all(0,e); - // X <- U^{-1} X - for (int j = m-1; j >= 0; j--) - { - const double x_j = ( x[j] /= data[j+j*m] ); - for (int i = 0; i < j; i++) - { - x[i] -= data[i+j*m] * x_j; - } - } - }); + // X <- P X + for (int i = 0; i < m; i++) + { + //Swap(x[i], x[ipiv[i]-ipiv_base]); //Hit a segfault... + double tmp = x[i]; + x[i] = x[ipiv[i]]; + x[ipiv[i]] = tmp; + } + + // X <- L^{-1} X + for (int j = 0; j < m; j++) + { + const double x_j = x[j]; + for (int i = j+1; i < m; i++) + { + x[i] -= data[i+j*m] * x_j; + } + } + + // X <- U^{-1} X + for (int j = m-1; j >= 0; j--) + { + const double x_j = ( x[j] /= data[j+j*m] ); + for (int i = 0; i < j; i++) + { + x[i] -= data[i+j*m] * x_j; + } + } + }); } diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index d20d441f6b..c04c65f2dc 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -251,41 +251,46 @@ TEST_CASE("DenseTensor LinearSolve methods", "[DenseMatrix]") { - int N = 3; - DenseMatrix A(N); - A(0,0) = 4; A(0,1) = 5; A(0,2) = -2; - A(1,0) = 7; A(1,1) = -1; A(1,2) = 2; - A(2,0) = 3; A(2,1) = 1; A(2,2) = 4; - - double X[3] = { -14, 42, 28 }; + int N = 3; + DenseMatrix A(N); + A(0,0) = 4; A(0,1) = 5; A(0,2) = -2; + A(1,0) = 7; A(1,1) = -1; A(1,2) = 2; + A(2,0) = 3; A(2,1) = 1; A(2,2) = 4; - int NE = 10; - Vector X_batch(N*NE); - DenseTensor A_batch(N, N, NE); - - auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE); - auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE); - //Column major - for(int e=0; e P; - BatchLUFactor(A_batch, P); - BatchLUSolve(A_batch, P, X_batch); - - auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE); - REQUIRE(LinearSolve(A,X)); - for(int e=0; e P; + BatchLUFactor(A_batch, P); + BatchLUSolve(A_batch, P, X_batch); + + auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE); + REQUIRE(LinearSolve(A,X)); + for (int e=0; e Date: Tue, 28 Apr 2020 14:00:35 -0700 Subject: [PATCH 232/535] clean up pass --- linalg/densemat.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 86b3c0e8fc..398f1961ee 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3541,11 +3541,7 @@ void BatchLUFactor(DenseTensor &Minv, Array &P) // swap rows i and piv in both L and U parts for (int j = 0; j < m; j++) { - //mfem::kernels::internal::Swap(data[i+j*m], data[piv+j*m]); - //Hit a segfault... - double tmp = data[i+j*m]; - data[i+j*m] = data[piv+j*m]; - data[piv+j*m] = tmp; + mfem::kernels::internal::Swap(data[i+j*m], data[piv+j*m]); } } }//pivot end @@ -3596,10 +3592,7 @@ void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X) // X <- P X for (int i = 0; i < m; i++) { - //Swap(x[i], x[ipiv[i]-ipiv_base]); //Hit a segfault... - double tmp = x[i]; - x[i] = x[ipiv[i]]; - x[ipiv[i]] = tmp; + mfem::kernels::internal::Swap(x[i], x[ipiv[i]]); } // X <- L^{-1} X From 908f689ea5a79e2a612ae81844baa0e854604c17 Mon Sep 17 00:00:00 2001 From: Vargas Date: Tue, 28 Apr 2020 14:40:36 -0700 Subject: [PATCH 233/535] makestyle --- linalg/densemat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 398f1961ee..51a045d783 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3592,7 +3592,7 @@ void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X) // X <- P X for (int i = 0; i < m; i++) { - mfem::kernels::internal::Swap(x[i], x[ipiv[i]]); + mfem::kernels::internal::Swap(x[i], x[ipiv[i]]); } // X <- L^{-1} X From 4f430f0ee4d4734c92f71c7b8fa6cd5914e38a75 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Tue, 28 Apr 2020 18:16:08 -0700 Subject: [PATCH 234/535] DenseTensor->Vector --- linalg/densemat.cpp | 10 +++------- linalg/densemat.hpp | 5 +++-- tests/unit/linalg/test_matrix_dense.cpp | 6 +++--- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 51a045d783..6582858ce5 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3505,11 +3505,8 @@ DenseTensor &DenseTensor::operator=(double c) return *this; } -void BatchLUFactor(DenseTensor &Minv, Array &P) +void BatchLUFactor(Vector &Minv,const int m,const int NE, Array &P) { - - int m = Minv.SizeI(); - int NE = Minv.SizeK(); P.SetSize(m*NE); auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); auto piv_all = mfem::Reshape(P.Write(), m, NE); @@ -3573,11 +3570,10 @@ void BatchLUFactor(DenseTensor &Minv, Array &P) } -void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X) +void BatchLUSolve(Vector &Minv, int m, int NE, + Array &P, Vector &X) { - int m = Minv.SizeI(); - int NE = Minv.SizeK(); auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); auto piv_all = mfem::Reshape(P.Read(), m, NE); auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index e376feb244..3184a77800 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -859,9 +859,10 @@ public: ~DenseTensor() { tdata.Delete(); } }; -void BatchLUFactor(DenseTensor &Minv, Array &P); +void BatchLUFactor(Vector &Minv,int m,int NE, Array &P); -void BatchLUSolve(DenseTensor &Minv, Array &P, Vector &X); +void BatchLUSolve(Vector &Minv, int m, int NE, + Array &P, Vector &X); // Inline methods diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index c04c65f2dc..bba8f08f76 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -261,7 +261,7 @@ TEST_CASE("DenseTensor LinearSolve methods", int NE = 10; Vector X_batch(N*NE); - DenseTensor A_batch(N, N, NE); + Vector A_batch(N*N*NE); auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE); auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE); @@ -280,8 +280,8 @@ TEST_CASE("DenseTensor LinearSolve methods", } Array P; - BatchLUFactor(A_batch, P); - BatchLUSolve(A_batch, P, X_batch); + BatchLUFactor(A_batch, N, NE, P); + BatchLUSolve(A_batch, N, NE, P, X_batch); auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE); REQUIRE(LinearSolve(A,X)); From 0d4b1cb9ff2cc98ddc634d536f00f896ee06ca06 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 29 Apr 2020 11:30:54 +0200 Subject: [PATCH 235/535] Remove need for sort of face dofs --- fem/fespace.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index faf84927ef..757cb50117 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1475,15 +1475,24 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() if (face_dof) { return; } if (!mesh->BdrInfoAvailable()) { return; } - Array face_dof_list; - Array row; + // Find bdr to face mapping face_to_be.SetSize(mesh->GetNumFaces()); face_to_be = -1; for (int b = 0; b < bdrElem_dof->Size(); b++) { - bdrElem_dof->GetRow(b, row); int f = mesh->GetBdrElementEdgeIndex(b); face_to_be[f] = b; + } + + // Loop over faces in correct order, to prevent a sort + // Sort will destroy orientation info in ordering of dofs + Array face_dof_list; + Array row; + for (int f = 0; f < mesh->GetNumFaces(); f++) + { + int b = face_to_be[f]; + if (b == -1) { continue;} + bdrElem_dof->GetRow(b, row); Connection conn(f,0); for (int i = 0; i < row.Size(); i++) { @@ -1491,9 +1500,8 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() face_dof_list.Append(conn); } } - face_dof_list.Sort(); - face_dof_list.Unique(); face_dof = new Table(mesh->GetNumFaces(), face_dof_list); + } void FiniteElementSpace::Construct() From 1000f0118c4bc59da072d29a90d1a31914debe9b Mon Sep 17 00:00:00 2001 From: Tomov Date: Wed, 29 Apr 2020 11:50:44 -0700 Subject: [PATCH 236/535] Option to use gslib for the interpolation. --- fem/tmop.cpp | 38 +++++++++++++++++++++++----- fem/tmop.hpp | 8 +++--- miniapps/meshing/pmesh-optimizer.cpp | 6 ++--- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 5530653a0a..2075377670 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1212,26 +1212,52 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, } } -void TMOP_Integrator::EnableAdaptiveLimiting( - const GridFunction &zeta0_gf, GridFunction &zeta_gf, Coefficient &coeff) +void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &zeta0_gf, + GridFunction &zeta_gf, + Coefficient &coeff, + int interp_type) { zeta_0 = &zeta0_gf; zeta = &zeta_gf; coeff_zeta = &coeff; - adapt_eval = new AdvectorCG; + + if (interp_type == 0) { adapt_eval = new AdvectorCG; } + else if (interp_type == 1) + { +#ifdef MFEM_USE_GSLIB + adapt_eval = new InterpolatorFP; +#elif + MFEM_ABORT("MFEM is not built with GSLIB support!"); +#endif + } + else { MFEM_ABORT("Bad interpolation option."); } + adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(), *zeta->FESpace()->FEColl(), 1); adapt_eval->SetInitialField (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } -void TMOP_Integrator::EnableAdaptiveLimiting( - const ParGridFunction &zeta0_gf, ParGridFunction &zeta_gf, Coefficient &coeff) +void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, + ParGridFunction &zeta_gf, + Coefficient &coeff, + int interp_type) { zeta_0 = &zeta0_gf; zeta = &zeta_gf; coeff_zeta = &coeff; - adapt_eval = new AdvectorCG; + + if (interp_type == 0) { adapt_eval = new AdvectorCG; } + else if (interp_type == 1) + { +#ifdef MFEM_USE_GSLIB + adapt_eval = new InterpolatorFP; +#elif + MFEM_ABORT("MFEM is not built with GSLIB support!"); +#endif + } + else { MFEM_ABORT("Bad interpolation option."); } + adapt_eval->SetParMetaInfo(*zeta_gf.ParFESpace()->GetParMesh(), *zeta_gf.ParFESpace()->FEColl(), 1); adapt_eval->SetInitialField diff --git a/fem/tmop.hpp b/fem/tmop.hpp index cb5107ea40..33f9d26c1d 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -931,12 +931,12 @@ public: Coefficient &w0, TMOP_LimiterFunction *lfunc = NULL); void EnableAdaptiveLimiting(const GridFunction &zeta0_gf, - GridFunction &zeta_gf, - Coefficient &coeff); + GridFunction &zeta_gf, Coefficient &coeff, + int interp_type); #ifdef MFEM_USE_MPI void EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, - ParGridFunction &zeta_gf, - Coefficient &coeff); + ParGridFunction &zeta_gf, Coefficient &coeff, + int interp_type); #endif /// Update the original/reference nodes used for limiting. diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 579fb87a36..a9ed25c2c5 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -al +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al // Adaptive limiting through FD: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -vl 1 -al -fd +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -fd // // Sample runs: // Adapted analytic Hessian: @@ -630,7 +630,7 @@ int main (int argc, char *argv[]) FunctionCoefficient alim_coeff(adapt_lim_fun); zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); - he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coeff_zeta); + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coeff_zeta, 1); socketstream vis1; common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", 300, 600, 300, 300); From 70acff2a18b70bb8ca250ea8d624cf7feb91401e Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:53:39 -0700 Subject: [PATCH 237/535] Adding enumeration and methods to help distinguish continuous fields from limited continuity fields. --- fem/fe.hpp | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ fem/fe_coll.hpp | 46 ++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/fem/fe.hpp b/fem/fe.hpp index b8d1982574..8390fb2ff6 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -294,6 +294,15 @@ public: CURL ///< Implements CalcCurlShape methods }; + /** @brief Enumeration for ContType: defines the continuity of the + field across element interfaces. + */ + enum { CONTINUOUS, ///< Field is continuous across element interfaces + TANGENTIAL, ///< Tangential components of vector field + NORMAL, ///< Normal component of vector field + DISCONTINUOUS ///< Field is discontinuous across element interfaces + }; + /** Construct FiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @@ -337,6 +346,8 @@ public: int GetDerivMapType() const { return DerivMapType; } + virtual int GetContType() const = 0; + /** @brief Evaluate the values of all shape functions of a scalar finite element in reference space at the given point @a ip. */ /** The size (#Dof) of the result Vector @a shape must be set in advance. */ @@ -814,6 +825,8 @@ class PointFiniteElement : public NodalFiniteElement public: PointFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } + virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -827,6 +840,9 @@ public: /// Construct a linear FE on interval Linear1DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (2) */ @@ -847,6 +863,9 @@ public: /// Construct a linear FE on triangle Linear2DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (3) */ @@ -869,6 +888,9 @@ public: /// Construct a bilinear FE on quadrilateral BiLinear2DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (4) */ @@ -891,6 +913,7 @@ class GaussLinear2DFiniteElement : public NodalFiniteElement { public: GaussLinear2DFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -905,6 +928,7 @@ private: public: GaussBiLinear2DFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -915,6 +939,7 @@ class P1OnQuadFiniteElement : public NodalFiniteElement { public: P1OnQuadFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -929,6 +954,9 @@ public: /// Construct a quadratic FE on interval Quad1DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (3) */ @@ -946,6 +974,7 @@ class QuadPos1DFiniteElement : public PositiveFiniteElement { public: QuadPos1DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -958,6 +987,9 @@ public: /// Construct a quadratic FE on triangle Quad2DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (6) */ @@ -985,6 +1017,7 @@ private: mutable Vector pol; public: GaussQuad2DFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -998,6 +1031,9 @@ public: /// Construct a biquadratic FE on quadrilateral BiQuad2DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (9) */ @@ -1016,6 +1052,7 @@ class BiQuadPos2DFiniteElement : public PositiveFiniteElement { public: BiQuadPos2DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1035,6 +1072,7 @@ class GaussBiQuad2DFiniteElement : public NodalFiniteElement { public: GaussBiQuad2DFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1045,6 +1083,7 @@ class BiCubic2DFiniteElement : public NodalFiniteElement { public: BiCubic2DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1057,6 +1096,8 @@ class Cubic1DFiniteElement : public NodalFiniteElement public: Cubic1DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1068,6 +1109,8 @@ class Cubic2DFiniteElement : public NodalFiniteElement public: Cubic2DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1084,6 +1127,8 @@ public: /// Construct a cubic FE on tetrahedron Cubic3DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1097,6 +1142,8 @@ public: /// Construct P0 triangle finite element P0TriangleFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } + /// evaluate shape function - constant 1 virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1112,6 +1159,7 @@ class P0QuadFiniteElement : public NodalFiniteElement { public: P0QuadFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1127,6 +1175,9 @@ public: /// Construct a linear FE on tetrahedron Linear3DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (4) */ @@ -1152,6 +1203,9 @@ public: /// Construct a quadratic FE on tetrahedron Quadratic3DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1165,6 +1219,9 @@ public: /// Construct a tri-linear FE on cube TriLinear3DFiniteElement(); + /// Returns the continuity of the field + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (8) */ @@ -1187,6 +1244,7 @@ class CrouzeixRaviartFiniteElement : public NodalFiniteElement { public: CrouzeixRaviartFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1199,6 +1257,7 @@ class CrouzeixRaviartQuadFiniteElement : public NodalFiniteElement { public: CrouzeixRaviartQuadFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1208,6 +1267,7 @@ class P0SegmentFiniteElement : public NodalFiniteElement { public: P0SegmentFiniteElement(int Ord = 0); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1221,6 +1281,8 @@ private: public: RT0TriangleFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1248,6 +1310,8 @@ private: public: RT0QuadFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1275,6 +1339,8 @@ private: public: RT1TriangleFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1302,6 +1368,8 @@ private: public: RT1QuadFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1328,6 +1396,8 @@ private: public: RT2TriangleFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1349,6 +1419,8 @@ private: public: RT2QuadFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1373,6 +1445,7 @@ class P1SegmentFiniteElement : public NodalFiniteElement { public: P1SegmentFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1383,6 +1456,7 @@ class P2SegmentFiniteElement : public NodalFiniteElement { public: P2SegmentFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1397,6 +1471,7 @@ private: #endif public: Lagrange1DFiniteElement (int degree); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1406,6 +1481,7 @@ class P1TetNonConfFiniteElement : public NodalFiniteElement { public: P1TetNonConfFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1415,6 +1491,7 @@ class P0TetFiniteElement : public NodalFiniteElement { public: P0TetFiniteElement (); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1426,6 +1503,7 @@ class P0HexFiniteElement : public NodalFiniteElement { public: P0HexFiniteElement (); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1447,6 +1525,7 @@ private: public: LagrangeHexFiniteElement (int degree); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1461,6 +1540,8 @@ public: /// Construct a quadratic FE on interval RefinedLinear1DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (3) */ @@ -1481,6 +1562,8 @@ public: /// Construct a quadratic FE on triangle RefinedLinear2DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (6) */ @@ -1501,6 +1584,8 @@ public: /// Construct a quadratic FE on tetrahedron RefinedLinear3DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1514,6 +1599,8 @@ public: /// Construct a biquadratic FE on quadrilateral RefinedBiLinear2DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (9) */ @@ -1534,6 +1621,8 @@ public: /// Construct a biquadratic FE on quadrilateral RefinedTriLinear3DFiniteElement(); + virtual int GetContType() const { return CONTINUOUS; } + /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (9) */ @@ -1555,6 +1644,7 @@ private: public: Nedelec1HexFiniteElement(); + virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -1577,6 +1667,7 @@ private: public: Nedelec1TetFiniteElement(); + virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -1600,6 +1691,8 @@ private: public: RT0HexFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1628,6 +1721,8 @@ private: public: RT1HexFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1656,6 +1751,8 @@ private: public: RT0TetFiniteElement(); + virtual int GetContType() const { return NORMAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1680,6 +1777,7 @@ class RotTriLinearHexFiniteElement : public NodalFiniteElement { public: RotTriLinearHexFiniteElement(); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1941,6 +2039,7 @@ private: public: H1_SegmentElement(const int p, const int btype = BasisType::GaussLobatto); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1958,6 +2057,7 @@ private: public: H1_QuadrilateralElement(const int p, const int btype = BasisType::GaussLobatto); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1974,6 +2074,7 @@ private: public: H1_HexahedronElement(const int p, const int btype = BasisType::GaussLobatto); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1994,6 +2095,7 @@ private: public: H1Pos_SegmentElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2011,6 +2113,7 @@ private: public: H1Pos_QuadrilateralElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2022,6 +2125,7 @@ class H1Ser_QuadrilateralElement : public ScalarFiniteElement { public: H1Ser_QuadrilateralElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2040,6 +2144,7 @@ private: public: H1Pos_HexahedronElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2059,6 +2164,7 @@ private: public: H1_TriangleElement(const int p, const int btype = BasisType::GaussLobatto); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2081,6 +2187,7 @@ private: public: H1_TetrahedronElement(const int p, const int btype = BasisType::GaussLobatto); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2101,6 +2208,8 @@ protected: public: H1Pos_TriangleElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } + // The size of shape is (p+1)(p+2)/2 (dof). static void CalcShape(const int p, const double x, const double y, double *shape); @@ -2127,6 +2236,8 @@ protected: public: H1Pos_TetrahedronElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } + // The size of shape is (p+1)(p+2)(p+3)/6 (dof). static void CalcShape(const int p, const double x, const double y, const double z, double *shape); @@ -2156,6 +2267,7 @@ private: public: H1_WedgeElement(const int p, const int btype = BasisType::GaussLobatto); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2200,6 +2312,7 @@ protected: public: H1Pos_WedgeElement(const int p); + virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2215,6 +2328,7 @@ private: public: L2_SegmentElement(const int p, const int btype = BasisType::GaussLegendre); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2231,6 +2345,7 @@ private: public: L2Pos_SegmentElement(const int p); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2248,6 +2363,7 @@ private: public: L2_QuadrilateralElement(const int p, const int btype = BasisType::GaussLegendre); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2268,6 +2384,7 @@ private: public: L2Pos_QuadrilateralElement(const int p); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2285,6 +2402,7 @@ private: public: L2_HexahedronElement(const int p, const int btype = BasisType::GaussLegendre); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2301,6 +2419,7 @@ private: public: L2Pos_HexahedronElement(const int p); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2320,6 +2439,7 @@ private: public: L2_TriangleElement(const int p, const int btype = BasisType::GaussLegendre); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2340,6 +2460,7 @@ private: public: L2Pos_TriangleElement(const int p); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2360,6 +2481,7 @@ private: public: L2_TetrahedronElement(const int p, const int btype = BasisType::GaussLegendre); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2376,6 +2498,7 @@ private: public: L2Pos_TetrahedronElement(const int p); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2398,6 +2521,7 @@ private: public: L2_WedgeElement(const int p, const int btype = BasisType::GaussLegendre); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2424,6 +2548,7 @@ protected: public: L2Pos_WedgeElement(const int p); + virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2446,6 +2571,7 @@ public: RT_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); + virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2502,6 +2628,7 @@ public: const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); + virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2551,6 +2678,7 @@ class RT_TriangleElement : public VectorFiniteElement public: RT_TriangleElement(const int p); + virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2606,6 +2734,7 @@ class RT_TetrahedronElement : public VectorFiniteElement public: RT_TetrahedronElement(const int p); + virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2654,6 +2783,8 @@ public: const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); + virtual int GetContType() const { return TANGENTIAL; } + virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2718,6 +2849,7 @@ public: ND_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); + virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2767,6 +2899,7 @@ class ND_TetrahedronElement : public VectorFiniteElement public: ND_TetrahedronElement(const int p); + virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2821,6 +2954,7 @@ class ND_TriangleElement : public VectorFiniteElement public: ND_TriangleElement(const int p); + virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2865,6 +2999,7 @@ class ND_SegmentElement : public VectorFiniteElement public: ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre); + virtual int GetContType() const { return TANGENTIAL; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const { obasis1d.Eval(ip.x, shape); } virtual void CalcVShape(const IntegrationPoint &ip, @@ -2921,6 +3056,8 @@ public: weights = 1.0; } + virtual int GetContType() const { return CONTINUOUS; } + void Reset () const { patch = elem = -1; } void SetIJK (const int *IJK) const { ijk = IJK; } int GetPatch () const { return patch; } diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index 7640b8e1db..fd101d98fa 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -52,6 +52,8 @@ public: virtual const char * Name() const { return "Undefined"; } + virtual int GetContType() const = 0; + int HasFaceDofs(Geometry::Type GeomType) const; virtual const FiniteElement *TraceFiniteElementForGeometry( @@ -102,6 +104,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char *Name() const { return h1_name; } + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } FiniteElementCollection *GetTraceCollection() const; int GetBasisType() const { return b_type; } @@ -174,6 +177,8 @@ public: int Or) const; virtual const char *Name() const { return d_name; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual const FiniteElement *TraceFiniteElementForGeometry( Geometry::Type GeomType) const { @@ -221,6 +226,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char *Name() const { return rt_name; } + virtual int GetContType() const { return FiniteElement::NORMAL; } FiniteElementCollection *GetTraceCollection() const; virtual ~RT_FECollection(); @@ -270,6 +276,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char *Name() const { return nd_name; } + virtual int GetContType() const { return FiniteElement::TANGENTIAL; } FiniteElementCollection *GetTraceCollection() const; virtual ~ND_FECollection(); @@ -334,6 +341,8 @@ public: virtual const char *Name() const { return name; } + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + FiniteElementCollection *GetTraceCollection() const; virtual ~NURBSFECollection(); @@ -363,6 +372,8 @@ public: int Or) const; virtual const char * Name() const { return "Linear"; } + + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } }; /// Piecewise-(bi)quadratic continuous finite elements. @@ -389,6 +400,8 @@ public: int Or) const; virtual const char * Name() const { return "Quadratic"; } + + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } }; /// Version of QuadraticFECollection with positive basis functions. @@ -410,6 +423,8 @@ public: int Or) const; virtual const char * Name() const { return "QuadraticPos"; } + + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } }; /// Piecewise-(bi)cubic continuous finite elements. @@ -437,6 +452,8 @@ public: int Or) const; virtual const char * Name() const { return "Cubic"; } + + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } }; /// Crouzeix-Raviart nonconforming elements in 2D. @@ -458,6 +475,8 @@ public: int Or) const; virtual const char * Name() const { return "CrouzeixRaviart"; } + + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /// Piecewise-linear nonconforming finite elements in 3D. @@ -481,6 +500,8 @@ public: int Or) const; virtual const char * Name() const { return "LinearNonConf3D"; } + + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; @@ -504,6 +525,8 @@ public: int Or) const; virtual const char * Name() const { return "RT0_2D"; } + + virtual int GetContType() const { return FiniteElement::NORMAL; } }; /** Second order Raviart-Thomas finite elements in 2D. This class is kept only @@ -526,6 +549,8 @@ public: int Or) const; virtual const char * Name() const { return "RT1_2D"; } + + virtual int GetContType() const { return FiniteElement::NORMAL; } }; /** Third order Raviart-Thomas finite elements in 2D. This class is kept only @@ -548,6 +573,8 @@ public: int Or) const; virtual const char * Name() const { return "RT2_2D"; } + + virtual int GetContType() const { return FiniteElement::NORMAL; } }; /** Piecewise-constant discontinuous finite elements in 2D. This class is kept @@ -569,6 +596,8 @@ public: int Or) const; virtual const char * Name() const { return "Const2D"; } + + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /** Piecewise-linear discontinuous finite elements in 2D. This class is kept @@ -591,6 +620,8 @@ public: int Or) const; virtual const char * Name() const { return "LinearDiscont2D"; } + + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /// Version of LinearDiscont2DFECollection with dofs in the Gaussian points. @@ -613,6 +644,8 @@ public: int Or) const; virtual const char * Name() const { return "GaussLinearDiscont2D"; } + + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /// Linear (P1) finite elements on quadrilaterals. @@ -628,6 +661,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char * Name() const { return "P1OnQuad"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept @@ -650,6 +684,7 @@ public: int Or) const; virtual const char * Name() const { return "QuadraticDiscont2D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /// Version of QuadraticDiscont2DFECollection with positive basis functions. @@ -667,6 +702,7 @@ public: int Or) const { return NULL; } virtual const char * Name() const { return "QuadraticPosDiscont2D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /// Version of QuadraticDiscont2DFECollection with dofs in the Gaussian points. @@ -689,6 +725,7 @@ public: int Or) const; virtual const char * Name() const { return "GaussQuadraticDiscont2D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /** Piecewise-cubic discontinuous finite elements in 2D. This class is kept @@ -711,6 +748,7 @@ public: int Or) const; virtual const char * Name() const { return "CubicDiscont2D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /** Piecewise-constant discontinuous finite elements in 3D. This class is kept @@ -734,6 +772,7 @@ public: int Or) const; virtual const char * Name() const { return "Const3D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /** Piecewise-linear discontinuous finite elements in 3D. This class is kept @@ -756,6 +795,7 @@ public: int Or) const; virtual const char * Name() const { return "LinearDiscont3D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept @@ -778,6 +818,7 @@ public: int Or) const; virtual const char * Name() const { return "QuadraticDiscont3D"; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; /// Finite element collection on a macro-element. @@ -803,6 +844,7 @@ public: int Or) const; virtual const char * Name() const { return "RefinedLinear"; } + virtual int GetContType() const { return FiniteElement::CONTINUOUS; } }; /** Lowest order Nedelec finite elements in 3D. This class is kept only for @@ -825,6 +867,7 @@ public: int Or) const; virtual const char * Name() const { return "ND1_3D"; } + virtual int GetContType() const { return FiniteElement::TANGENTIAL; } }; /** First order Raviart-Thomas finite elements in 3D. This class is kept only @@ -848,6 +891,7 @@ public: int Or) const; virtual const char * Name() const { return "RT0_3D"; } + virtual int GetContType() const { return FiniteElement::NORMAL; } }; /** Second order Raviart-Thomas finite elements in 3D. This class is kept only @@ -870,6 +914,7 @@ public: int Or) const; virtual const char * Name() const { return "RT1_3D"; } + virtual int GetContType() const { return FiniteElement::NORMAL; } }; /// Discontinuous collection defined locally by a given finite element. @@ -894,6 +939,7 @@ public: virtual const char *Name() const { return d_name; } virtual ~Local_FECollection() { delete Local_Element; } + virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } }; } From 8592a79c3d639926d0c8e97410a7b7376dd03448 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:54:19 -0700 Subject: [PATCH 238/535] Removing `ActiveSide` concept from `FaceElementTransformations` --- fem/eltrans.cpp | 110 ++++++++++++++++-------------------------------- fem/eltrans.hpp | 37 ++++++---------- 2 files changed, 51 insertions(+), 96 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index 017f7acf00..f852577a9d 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -551,88 +551,52 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1, } } -int FaceElementTransformations::SetActiveSide(int s) +void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) { - if (s == 2) // automatic choice of side + IsoparametricTransformation::SetIntPoint(ip); + + if (Elem1) { - if (Elem1 && Elem2) - { - side = (Elem1->Attribute <= Elem2->Attribute) ? 0 : 1; - } - else if (Elem1) - { - side = 0; - } - else if (Elem2) - { - side = 1; - } - else - { - MFEM_ABORT("FaceElementTransformation: both Elem1 and Elem2 are NULL. " - "Automatic side selection failed!"); - } + Loc1.Transform(*ip, eip1); + Elem1->SetIntPoint(&eip1); } - else + if (Elem2) { - if (s == 0 && Elem1) - { - side = 0; - } - else if (s == 1 && Elem2) - { - side = 1; - } - else - { - MFEM_ABORT("FaceElementTransformation: the ElementTransformation " - "for the requested side is NULL."); - } - } - - return side; -} - -ElementTransformation * -FaceElementTransformations::GetActiveElementTransformation() -{ - while (1) - { - if (side == 0) - { - return Elem1; - } - else if (side == 1) - { - return Elem2; - } - - // Automatic selection has not yet occured. - SetActiveSide(2); + Loc2.Transform(*ip, eip2); + Elem2->SetIntPoint(&eip2); } } -IntegrationPointTransformation * -FaceElementTransformations::GetActivePointTransformation() +ElementTransformation & +FaceElementTransformations::GetElement1Transformation() { - while (1) - { - if (side == 0) - { - MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation " - "for side 1 has not been configured."); - return &Loc1; - } - else if (side == 1) - { - MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation " - "for side 2 has not been configured."); - return &Loc2; - } + MFEM_VERIFY(mask & 1 && Elem1 != NULL, "The ElementTransformation " + "for the element has not been configured for side 1."); + return *Elem1; +} - // Automatic selection has not yet occured. - SetActiveSide(2); - } +ElementTransformation & +FaceElementTransformations::GetElement2Transformation() +{ + MFEM_VERIFY(mask & 2 && Elem2 != NULL, "The ElementTransformation " + "for the element has not been configured for side 2."); + return *Elem2; +} + +IntegrationPointTransformation & +FaceElementTransformations::GetIntPoint1Transformation() +{ + MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation " + "for the element has not been configured for side 1."); + return Loc1; +} + +IntegrationPointTransformation & +FaceElementTransformations::GetIntPoint2Transformation() +{ + MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation " + "for the element has not been configured for side 2."); + return Loc2; } void FaceElementTransformations::Transform(const IntegrationPoint &ip, diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index daedbfbca1..ac9886b954 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -60,13 +60,15 @@ public: | BDR_ELEMENT | [0, Mesh::GetNBE() ) | EDGE | [0, Mesh::GetNEdges() ) | FACE | [0, Mesh::GetNFaces() ) + | BDR_FACE | [0, Mesh::GetNBE() ) */ enum { ELEMENT = 1, BDR_ELEMENT = 2, EDGE = 3, - FACE = 4 + FACE = 4, + BDR_FACE = 5 }; int Attribute, ElementNo, ElementType; @@ -380,9 +382,10 @@ public: class FaceElementTransformations : public IsoparametricTransformation { private: - int side; int mask; + IntegrationPoint eip1, eip2; + public: int Elem1No, Elem2No; Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead @@ -390,7 +393,7 @@ public: ElementTransformation *Face; ///< @deprecated No longer necessary IntegrationPointTransformation Loc1, Loc2; - FaceElementTransformations() : side(2), FaceGeom(geom), Face(this) {} + FaceElementTransformations() : FaceGeom(geom), Face(this) {} /** @brief Method to set the geometry type of the face. @@ -401,24 +404,6 @@ public: */ void SetGeometryType(Geometry::Type g) { geom = g; } - /** FaceElementTransformations objects are often used when - performing the surface integrals on the interfaces between - elements needed by Discontinuous Galerkin methods. Since the - fields are generally multivalued on such interfaces it is - important to specify which neighboring element should supply - the field values. This is controlled by setting the "active - side" in the FaceElementTransformations object. - - Possible values for s are 0, 1, and 2: - 0 - Set Elem1No as the active side - 1 - Set Elem2No as the active side - 2 - Choose the active side automatically. This selects Elem1No - unless Elem2No exists and has a lower attribute number than - Elem1No. - */ - int SetActiveSide(int s); - int GetActiveSide() const { return side; } - /// Set the mask indicating which portions of the object have been setup /** The argument @a m is a bitmask used in Mesh::GetFaceElementTransformations to indicate which portions @@ -433,12 +418,18 @@ public: void SetConfigurationMask(int m) { mask = m; } int GetConfigurationMask() const { return mask; } + /** @brief Set the integration point in the Face and the two neighboring + elements, if present. */ + void SetIntPoint(const IntegrationPoint *ip); + virtual void Transform(const IntegrationPoint &, Vector &); virtual void Transform(const IntegrationRule &, DenseMatrix &); virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); - ElementTransformation * GetActiveElementTransformation(); - IntegrationPointTransformation * GetActivePointTransformation(); + ElementTransformation & GetElement1Transformation(); + ElementTransformation & GetElement2Transformation(); + IntegrationPointTransformation & GetIntPoint1Transformation(); + IntegrationPointTransformation & GetIntPoint2Transformation(); }; /* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) From c7f3b4049b7489af9383aa66a7627bfd7fc2e437 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:55:06 -0700 Subject: [PATCH 239/535] Adding BDR_FACE element type for `BdrFaceElementTransformations` --- mesh/mesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 5c771ef3b8..d97ba34e9e 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -970,7 +970,7 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) tr = GetFaceElementTransformations(fn); tr->Attribute = boundary[BdrElemNo]->GetAttribute(); tr->ElementNo = BdrElemNo; - tr->ElementType = ElementTransformation::BDR_ELEMENT; + tr->ElementType = ElementTransformation::BDR_FACE; return tr; } From 4619cf228d750fe741727d57ad4e0ef1afebf86f Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:55:57 -0700 Subject: [PATCH 240/535] Using new field continuity information to simplify the logic in the GetValue and GetVectorValue methods --- fem/gridfunc.cpp | 247 +++++++++++++++++++++++++++++------------------ fem/gridfunc.hpp | 29 ------ 2 files changed, 152 insertions(+), 124 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index f68a20622e..197719ba7e 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -236,7 +236,6 @@ void GridFunction::MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset) } } - void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi, GridFunction &flux, Array& count, @@ -626,6 +625,56 @@ void GridFunction::GetVectorValues(int i, const IntegrationRule &ir, GetVectorValues(*Tr, ir, vals); } +void be_to_bfe(Geometry::Type geom, int o, const IntegrationPoint &ip, + IntegrationPoint &fip) +{ + if (geom == Geometry::TRIANGLE) + { + if (o == 2) + { + fip.x = 1.0 - ip.x - ip.y; + fip.y = ip.x; + } + else if (o == 4) + { + fip.x = ip.y; + fip.y = 1.0 - ip.x - ip.y; + } + else + { + fip.x = ip.x; + fip.y = ip.y; + } + fip.z = ip.z; + } + else + { + if (o == 2) + { + fip.x = ip.y; + fip.y = 1.0 - ip.x; + } + else if (o == 4) + { + fip.x = 1.0 - ip.x; + fip.y = 1.0 - ip.y; + } + else if (o == 6) + { + fip.x = 1.0 - ip.y; + fip.y = ip.x; + } + else + { + fip.x = ip.x; + fip.y = ip.y; + } + fip.z = ip.z; + } + fip.weight = ip.weight; + fip.index = ip.index; +} + double GridFunction::GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp, Vector *tr) const @@ -635,50 +684,66 @@ double GridFunction::GetValue(ElementTransformation &T, T.SetIntPoint(&ip); T.Transform(ip, *tr); } - Array dofs; - const FiniteElement * fe = NULL; - if (T.ElementType == ElementTransformation::ELEMENT) - { - fes->GetElementDofs(T.ElementNo, dofs); - fe = fes->GetFE(T.ElementNo); - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - fe = fes->GetBE(T.ElementNo); - if (fe == NULL) + const FiniteElement * fe = NULL; + Array dofs; + + switch (T.ElementType) + { + case ElementTransformation::ELEMENT: + fe = fes->GetFE(T.ElementNo); + fes->GetElementDofs(T.ElementNo, dofs); + break; + case ElementTransformation::BDR_ELEMENT: + { + if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + { + // This is a continuous field so we can evaluate it on the boudnary + fe = fes->GetBE(T.ElementNo); + fes->GetBdrElementDofs(T.ElementNo, dofs); + } + else + { + // This is a discontinuous field which cannot be evaluated on + // the boudary so we'll evaluate it in the neighboring elememt. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + + // Boundary elements and Boundary Faces may have different + // orientations so adjust the integration point if necessary. + int o = 0; + if (fes->GetMesh()->Dimension() == 3) + { + int f; + fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o); + } + + IntegrationPoint fip; + be_to_bfe(FET->GetGeometryType(), o, ip, fip); + + FET->SetIntPoint(&fip); + ElementTransformation & T1 = FET->GetElement1Transformation(); + return GetValue(T1, T1.GetIntPoint(), comp); + } + break; + } + case ElementTransformation::BDR_FACE: { - // This must be a DG field. Check for DG context. FaceElementTransformations * FET = dynamic_cast(&T); - if (FET == NULL) - { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - } - return GetValue(*FET, ip, comp); + + // Evaluate in neighboring element for both continuous and + // discontinuous fields. + ElementTransformation & T1 = FET->GetElement1Transformation(); + return GetValue(T1, T1.GetIntPoint(), comp); } - else + default: { - /// Not a DG field so we can simply grab the DoFs. - fes->GetBdrElementDofs(T.ElementNo, dofs); + MFEM_ABORT("GridFunction::GetValue: Unsupported element type \"" + << T.ElementType << "\""); + return NAN; } } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) - { - return GetValue(*FET, ip, comp); - } - } - else - { - MFEM_ABORT("GridFunction::GetValue: Unsupported element type \"" - << T.ElementType << "\""); - } fes->DofsToVDofs(comp-1, dofs); Vector DofVal(dofs.Size()), LocVec; @@ -715,19 +780,6 @@ void GridFunction::GetValues(ElementTransformation &T, } } -double GridFunction::GetValue(FaceElementTransformations &FET, - const IntegrationPoint &ip, - int comp, Vector *tr) const -{ - ElementTransformation * T = FET.GetActiveElementTransformation(); - - IntegrationPoint eip; - FET.GetActivePointTransformation()->Transform(ip, eip); - T->SetIntPoint(&eip); - - return GetValue(*T, eip, comp, tr); -} - void GridFunction::GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, Vector &val, Vector *tr) const @@ -737,48 +789,67 @@ void GridFunction::GetVectorValue(ElementTransformation &T, T.SetIntPoint(&ip); T.Transform(ip, *tr); } + Array vdofs; const FiniteElement *fe = NULL; - if (T.ElementType == ElementTransformation::ELEMENT) - { - fes->GetElementVDofs(T.ElementNo, vdofs); - fe = fes->GetFE(T.ElementNo); - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - fes->GetBdrElementVDofs(T.ElementNo, vdofs); - fe = fes->GetBE(T.ElementNo); - if (fe == NULL) + switch (T.ElementType) + { + case ElementTransformation::ELEMENT: + fes->GetElementVDofs(T.ElementNo, vdofs); + fe = fes->GetFE(T.ElementNo); + break; + case ElementTransformation::BDR_ELEMENT: + { + if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + { + // This is a continuous field so we can evaluate it on the boudnary + fes->GetBdrElementVDofs(T.ElementNo, vdofs); + fe = fes->GetBE(T.ElementNo); + } + else + { + // This is a discontinuous vector field which cannot be evaluated on + // the boudary so we'll evaluate it in the neighboring elememt. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + + // Boundary elements and Boundary Faces may have different + // orientations so adjust the integration point if necessary. + int o = 0; + if (fes->GetMesh()->Dimension() == 3) + { + int f; + fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o); + } + + IntegrationPoint fip; + be_to_bfe(FET->GetGeometryType(), o, ip, fip); + + FET->SetIntPoint(&fip); + ElementTransformation & T1 = FET->GetElement1Transformation(); + return GetVectorValue(T1, T1.GetIntPoint(), val); + } + break; + } + case ElementTransformation::BDR_FACE: { - // This must be a DG field. Check for DG context. FaceElementTransformations * FET = dynamic_cast(&T); - if (FET == NULL) - { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - } - GetVectorValue(*FET, ip, val); - return; + + // Evaluate in neighboring element for both continuous and + // discontinuous fields. + ElementTransformation & T1 = FET->GetElement1Transformation(); + return GetVectorValue(T1, T1.GetIntPoint(), val); } - } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) + default: { - GetVectorValue(*FET, ip, val); + MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \"" + << T.ElementType << "\""); + if (val.Size() > 0) { val = NAN; } return; } } - else - { - MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \"" - << T.ElementType << "\""); - } int dof = fe->GetDof(); Vector loc_data; @@ -805,26 +876,12 @@ void GridFunction::GetVectorValue(ElementTransformation &T, { int spaceDim = fes->GetMesh()->SpaceDimension(); DenseMatrix vshape(dof, spaceDim); - T.SetIntPoint(&ip); fe->CalcVShape(T, vshape); val.SetSize(spaceDim); vshape.MultTranspose(loc_data, val); } } -void GridFunction::GetVectorValue(FaceElementTransformations &FET, - const IntegrationPoint &ip, - Vector &val, Vector *tr) const -{ - ElementTransformation * T = FET.GetActiveElementTransformation(); - - IntegrationPoint eip; - FET.GetActivePointTransformation()->Transform(ip, eip); - T->SetIntPoint(&eip); - - GetVectorValue(*T, eip, val, tr); -} - void GridFunction::GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals, diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 5e7bff739d..a9e9d8fdc6 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -225,35 +225,6 @@ public: Vector &val, Vector *tr = NULL) const; ///@} - /** @name FaceElementTransformations Get Value Methods - - These member functions are designed for use within - GridFunctionCoefficient objects. These can be used with - FaceElementTransformations objects coming from - Mesh::GetFaceElementTransformations(), - Mesh::GetInteriorFaceElementTransformations(), or - Mesh::GetBdrFaceElementTransformations(). - - @note These methods do not reset the FaceElementTransformations - object so they should be safe to use within integration loops - or other contexts where the FaceElementTransformations is - already in use. - */ - ///@{ - /** Return a scalar value from within the face indicated by the - FaceElementTransformations object. - */ - double GetValue(FaceElementTransformations &T, const IntegrationPoint &ip, - int comp = 0, Vector *tr = NULL) const; - - /** Return a vector value from within the face indicated by the - FaceElementTransformations object. - */ - void GetVectorValue(FaceElementTransformations &T, - const IntegrationPoint &ip, - Vector &val, Vector *tr = NULL) const; - ///@} - /** @name ElementTransformation Get Values Methods These are convenience methods for repeatedly calling GetValue From 5394b3f8e5553b87807a09e93394189236349db3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:56:41 -0700 Subject: [PATCH 241/535] Removing SetActiveSide from integrators --- fem/bilininteg.cpp | 2 -- fem/lininteg.cpp | 4 ---- 2 files changed, 6 deletions(-) diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp index e5d8b26bc7..a3fa6a614e 100644 --- a/fem/bilininteg.cpp +++ b/fem/bilininteg.cpp @@ -878,8 +878,6 @@ void BoundaryMassIntegrator::AssembleFaceMatrix( int nd1 = el1.GetDof(); double w; - Trans.SetActiveSide(0); - #ifdef MFEM_THREAD_SAFE Vector shape; #endif diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index f5e35f3312..1c40bd19c9 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -317,7 +317,6 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect( Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); - Tr.SetActiveSide(0); // Use Tr transformation in case Q depends on boundary attribute Q.Eval(vec, Tr, ip); @@ -528,7 +527,6 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( el.CalcShape(eip, shape); Tr.SetIntPoint(&ip); - Tr.SetActiveSide(0); // Use Tr.Elem1 transformation for u so that it matches the // coefficient used with the ConvectionIntegrator and/or the @@ -599,7 +597,6 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); - Tr.SetActiveSide(0); if (dim == 1) { nor(0) = 2*eip.x - 1.0; @@ -693,7 +690,6 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); - Tr.SetActiveSide(0); Tr.Elem1->SetIntPoint(&eip); // Evaluate the Dirichlet b.c. using the face transformation. From 408d5e411b437c4a862a720e2ee60cfcfc784473 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:57:51 -0700 Subject: [PATCH 242/535] `T->Elem[12]->SetIntPoint` is now handled internally by `FaceElementTransformations::SetIntPoint` --- fem/bilininteg.cpp | 8 -------- fem/lininteg.cpp | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp index a3fa6a614e..b4e5637b4c 100644 --- a/fem/bilininteg.cpp +++ b/fem/bilininteg.cpp @@ -2550,7 +2550,6 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1, el1.CalcShape(eip1, shape1); Trans.SetIntPoint(&ip); - Trans.Elem1->SetIntPoint(&eip1); u->Eval(vu, *Trans.Elem1, eip1); @@ -2575,7 +2574,6 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1, double rho_p; if (un >= 0.0 && ndof2) { - Trans.Elem2->SetIntPoint(&eip2); rho_p = rho->Eval(*Trans.Elem2, eip2); } else @@ -2714,7 +2712,6 @@ void DGDiffusionIntegrator::AssembleFaceMatrix( el1.CalcShape(eip1, shape1); el1.CalcDShape(eip1, dshape1); - Trans.Elem1->SetIntPoint(&eip1); w = ip.weight/Trans.Elem1->Weight(); if (ndof2) { @@ -2763,7 +2760,6 @@ void DGDiffusionIntegrator::AssembleFaceMatrix( Trans.Loc2.Transform(ip, eip2); el2.CalcShape(eip2, shape2); el2.CalcDShape(eip2, dshape2); - Trans.Elem2->SetIntPoint(&eip2); w = ip.weight/2/Trans.Elem2->Weight(); if (!MQ) { @@ -2982,7 +2978,6 @@ void DGElasticityIntegrator::AssembleFaceMatrix( IntegrationPoint eip1, eip2; // integration point in the reference space Trans.Loc1.Transform(ip, eip1); Trans.SetIntPoint(&ip); - Trans.Elem1->SetIntPoint(&eip1); el1.CalcShape(eip1, shape1); el1.CalcDShape(eip1, dshape1); @@ -3003,7 +2998,6 @@ void DGElasticityIntegrator::AssembleFaceMatrix( if (ndofs2) { Trans.Loc2.Transform(ip, eip2); - Trans.Elem2->SetIntPoint(&eip2); el2.CalcShape(eip2, shape2); el2.CalcDShape(eip2, dshape2); CalcAdjugate(Trans.Elem2->Jacobian(), adjJ); @@ -3148,13 +3142,11 @@ void TraceJumpIntegrator::AssembleFaceMatrix( // Side 1 finite element shape function Trans.Loc1.Transform(ip, eip1); test_fe1.CalcShape(eip1, shape1); - Trans.Elem1->SetIntPoint(&eip1); if (ndof2) { // Side 2 finite element shape function Trans.Loc2.Transform(ip, eip2); test_fe2.CalcShape(eip2, shape2); - Trans.Elem2->SetIntPoint(&eip2); } w = ip.weight; if (trial_face_fe.GetMapType() == FiniteElement::VALUE) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 1c40bd19c9..53a84808d4 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -608,7 +608,7 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( el.CalcShape(eip, shape); el.CalcDShape(eip, dshape); - Tr.Elem1->SetIntPoint(&eip); + // compute uD through the face transformation w = ip.weight * uD->Eval(Tr, ip) / Tr.Elem1->Weight(); if (!MQ) @@ -690,7 +690,6 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); - Tr.Elem1->SetIntPoint(&eip); // Evaluate the Dirichlet b.c. using the face transformation. uD.Eval(u_dir, Tr, ip); From 8511c709e3f95305d94326c351122d34316b2d44 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:58:09 -0700 Subject: [PATCH 243/535] Removing active side unit tests --- tests/unit/fem/test_face_elem_trans.cpp | 225 +++++------------------- 1 file changed, 46 insertions(+), 179 deletions(-) diff --git a/tests/unit/fem/test_face_elem_trans.cpp b/tests/unit/fem/test_face_elem_trans.cpp index d3f43910c1..70fc8bed56 100644 --- a/tests/unit/fem/test_face_elem_trans.cpp +++ b/tests/unit/fem/test_face_elem_trans.cpp @@ -27,200 +27,67 @@ TEST_CASE("3D FaceElementTransformations", Mesh mesh(n, n, n, Element::TETRAHEDRON, 1, 2.0, 3.0, 5.0); - SECTION("SetActiveSide 0") - { - int f = 2; - if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } - FaceElementTransformations *T = - mesh.GetInteriorFaceTransformations(2); - - if (T != NULL) - { - int attr1 = mesh.GetElement(T->Elem1No)->GetAttribute(); - int attr2 = (T->Elem2No >= 0) ? - mesh.GetElement(T->Elem2No)->GetAttribute() : -1; - - T->SetActiveSide(0); - REQUIRE(T->GetActiveSide() == 0); - REQUIRE(T->GetActiveElementTransformation() == T->Elem1); - REQUIRE(T->GetActivePointTransformation() == &T->Loc1); - } - } - - SECTION("SetActiveSide 1") - { - int f = 2; - if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } - FaceElementTransformations *T = - mesh.GetInteriorFaceTransformations(2); - - if (T != NULL) - { - int attr1 = mesh.GetElement(T->Elem1No)->GetAttribute(); - int attr2 = (T->Elem2No >= 0) ? - mesh.GetElement(T->Elem2No)->GetAttribute() : -1; - - T->SetActiveSide(1); - REQUIRE(T->GetActiveSide() == 1); - REQUIRE(T->GetActiveElementTransformation() == T->Elem2); - REQUIRE(T->GetActivePointTransformation() == &T->Loc2); - } - } - - SECTION("SetActiveSide 2") - { - int f = 2; - if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } - FaceElementTransformations *T = - mesh.GetInteriorFaceTransformations(2); - - if (T != NULL) - { - int attr1 = mesh.GetElement(T->Elem1No)->GetAttribute(); - int attr2 = (T->Elem2No >= 0) ? - mesh.GetElement(T->Elem2No)->GetAttribute() : -1; - - SECTION("Both Elements present with Elem1.Attr == Elem2.Attr") - { - T->SetActiveSide(2); - REQUIRE(T->GetActiveSide() == 0); - REQUIRE(T->GetActiveElementTransformation() == T->Elem1); - REQUIRE(T->GetActivePointTransformation() == &T->Loc1); - } - SECTION("Both Elements present with Elem1.Attr < Elem2.Attr") - { - T->Elem1->Attribute = 1; - T->Elem2->Attribute = 2; - - T->SetActiveSide(2); - REQUIRE(T->GetActiveSide() == 0); - REQUIRE(T->GetActiveElementTransformation() == T->Elem1); - REQUIRE(T->GetActivePointTransformation() == &T->Loc1); - - T->Elem1->Attribute = 1; - T->Elem2->Attribute = 1; - } - SECTION("Both Elements present with Elem1.Attr > Elem2.Attr") - { - T->Elem1->Attribute = 2; - T->Elem2->Attribute = 1; - - T->SetActiveSide(2); - REQUIRE(T->GetActiveSide() == 1); - REQUIRE(T->GetActiveElementTransformation() == T->Elem2); - REQUIRE(T->GetActivePointTransformation() == &T->Loc2); - - T->Elem1->Attribute = 1; - T->Elem2->Attribute = 1; - } - SECTION("Element 2 absent") - { - ElementTransformation * T2 = T->Elem2; - T->Elem2 = NULL; - - T->SetActiveSide(2); - REQUIRE(T->GetActiveSide() == 0); - REQUIRE(T->GetActiveElementTransformation() == T->Elem1); - REQUIRE(T->GetActivePointTransformation() == &T->Loc1); - - T->Elem2 = T2; - } - SECTION("Element 1 absent") - { - ElementTransformation * T1 = T->Elem1; - T->Elem1 = NULL; - - T->SetActiveSide(2); - REQUIRE(T->GetActiveSide() == 1); - REQUIRE(T->GetActiveElementTransformation() == T->Elem2); - REQUIRE(T->GetActivePointTransformation() == &T->Loc2); - - T->Elem1 = T1; - } - } - } - - SECTION("GetActiveElementTransformation Without Calling SetActiveSide") - { - int f = 2; - if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } - FaceElementTransformations *T = - mesh.GetInteriorFaceTransformations(2); - - if (T != NULL) - { - REQUIRE(T->GetActiveSide() == 2); - REQUIRE(T->GetActiveElementTransformation() == T->Elem1); - } - } - - SECTION("GetActivePointTransformation Without Calling SetActiveSide") - { - int f = 2; - if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } - FaceElementTransformations *T = - mesh.GetInteriorFaceTransformations(2); - - if (T != NULL) - { - REQUIRE(T->GetActiveSide() == 2); - REQUIRE(T->GetActivePointTransformation() == &T->Loc1); - } - } - SECTION("Transform") { int npts = 0; - int f = 2; - if (log > 0) { std::cout << "Getting trans for face " << f << std::endl; } - FaceElementTransformations *T = - mesh.GetInteriorFaceTransformations(f); - - if (T != NULL) + for (int f=0; fGetGeometryType(), - 2*order + 2); if (log > 0) { - std::cout << f << " " << T->Elem1No - << " " << T->Elem2No << std::endl; + std::cout << "Getting trans for face " << f << std::endl; } + FaceElementTransformations *T = + mesh.GetInteriorFaceTransformations(f); - double tip_data[3]; - double tip1_data[3]; - double tip2_data[3]; - Vector tip(tip_data, 3); - Vector tip1(tip1_data, 3); - Vector tip2(tip2_data, 3); - - for (int j=0; jGetGeometryType(), + 2*order + 2); + if (log > 0) + { + std::cout << f << " " << T->Elem1No + << " " << T->Elem2No << std::endl; + } - T->SetIntPoint(&ip); - T->Transform(ip, tip); + double tip_data[3]; + double tip1_data[3]; + double tip2_data[3]; + Vector tip(tip_data, 3); + Vector tip1(tip1_data, 3); + Vector tip2(tip2_data, 3); - T->Loc1.Transform(ip, eip1); - T->Elem1->SetIntPoint(&eip1); - T->Elem1->Transform(eip1, tip1); + for (int j=0; jLoc2.Transform(ip, eip2); - T->Elem2->SetIntPoint(&eip2); - T->Elem2->Transform(eip2, tip2); + T->SetIntPoint(&ip); + T->Transform(ip, tip); - tip1 -= tip; - tip2 -= tip; + T->Loc1.Transform(ip, eip1); + T->Elem1->Transform(eip1, tip1); - REQUIRE(tip1.Norml2() == Approx(0.0)); - REQUIRE(tip2.Norml2() == Approx(0.0)); + tip1 -= tip; + + REQUIRE(tip1.Norml2() == Approx(0.0)); + + if (T->Elem2) + { + T->Loc2.Transform(ip, eip2); + T->Elem2->Transform(eip2, tip2); + + tip2 -= tip; + + REQUIRE(tip2.Norml2() == Approx(0.0)); + } + } + } + if (log > 0) + { + std::cout << "Checked " << npts << " points within face " + << f << std::endl; } - } - if (log > 0) - { - std::cout << "Checked " << npts << " points within face " - << f << std::endl; } } } From 0f0e38283ee23fa2a10318eca313ad6f188b92b5 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 29 Apr 2020 16:59:10 -0700 Subject: [PATCH 244/535] Updating GetValue unit tests and adding 1D and 2D variants. Also adding GetVectorValue tests in 2D and 3D. --- tests/unit/fem/test_get_value.cpp | 2228 +++++++++++++++++++++++++---- 1 file changed, 1934 insertions(+), 294 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 7e85d74179..6862fbfb1a 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -14,13 +14,628 @@ using namespace mfem; +namespace get_value +{ + +double func_1D_lin(const Vector &x) +{ + return x[0]; +} + +double func_2D_lin(const Vector &x) +{ + return x[0] + 2.0 * x[1]; +} + double func_3D_lin(const Vector &x) { return x[0] + 2.0 * x[1] + 3.0 * x[2]; } -namespace get_value +void Func_2D_lin(const Vector &x, Vector &v) { + v.SetSize(2); + v[0] = 1.234 * x[0] - 2.357 * x[1]; + v[1] = 2.537 * x[0] + 4.321 * x[1]; +} + +void Func_3D_lin(const Vector &x, Vector &v) +{ + v.SetSize(3); + v[0] = 1.234 * x[0] - 2.357 * x[1] + 3.572 * x[2]; + v[1] = 2.537 * x[0] + 4.321 * x[1] - 1.234 * x[2]; + v[2] = -2.572 * x[0] + 1.321 * x[1] + 3.234 * x[2]; +} + +TEST_CASE("1D GetValue", + "[GridFunction]" + "[GridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 1; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::SEGMENT; + type <= (int)Element::SEGMENT; type++) + { + Mesh mesh(n, 2.0); + + FunctionCoefficient linCoef(func_1D_lin); + + SECTION("1D GetValue tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + FiniteElementSpace dgi_fespace(&mesh, &dgi_fec); + + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + GridFunction dgi_x(&dgi_fespace); + + GridFunctionCoefficient h1_xCoef(&h1_x); + GridFunctionCoefficient dgv_xCoef(&dgv_x); + GridFunctionCoefficient dgi_xCoef(&dgi_x); + + h1_x.ProjectCoefficient(linCoef); + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + SECTION("Domain Evaluation 1D (H1 Context)") + { + std::cout << "Domain Evaluation 1D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[1]; + Vector tip(tip_data, 1); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_1D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 1D (H1 Context)") + { + std::cout << "Boundary Evaluation 1D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[1]; + Vector tip(tip_data, 1); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_1D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + + SECTION("Domain Evaluation 1D (DG Context)") + { + std::cout << "Domain Evaluation 1D (DG Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[1]; + Vector tip(tip_data, 1); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_1D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 1D (DG Context)") + { + std::cout << "Boundary Evaluation 1D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[1]; + Vector tip(tip_data, 1); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_1D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetValue at " + << npts << " 1D points" << std::endl; +} + +TEST_CASE("2D GetValue", + "[GridFunction]" + "[GridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 2; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + + FunctionCoefficient linCoef(func_2D_lin); + + SECTION("2D GetValue tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + FiniteElementSpace dgi_fespace(&mesh, &dgi_fec); + + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + GridFunction dgi_x(&dgi_fespace); + + GridFunctionCoefficient h1_xCoef(&h1_x); + GridFunctionCoefficient dgv_xCoef(&dgv_x); + GridFunctionCoefficient dgi_xCoef(&dgi_x); + + h1_x.ProjectCoefficient(linCoef); + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + SECTION("Domain Evaluation 2D (H1 Context)") + { + std::cout << "Domain Evaluation 2D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_2D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (H1 Context)") + { + std::cout << "Boundary Evaluation 2D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_2D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + + SECTION("Domain Evaluation 2D (DG Context)") + { + std::cout << "Domain Evaluation 2D (DG Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_2D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 2D (DG Context)") + { + std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_2D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetValue at " + << npts << " 2D points" << std::endl; +} TEST_CASE("3D GetValue", "[GridFunction]" @@ -30,318 +645,1343 @@ TEST_CASE("3D GetValue", int n = 1; int dim = 3; int order = 1; - double tol = 1e-6; - - Mesh mesh(n, n, n, Element::TETRAHEDRON, 1, 2.0, 3.0, 5.0); - - FunctionCoefficient linCoef(func_3D_lin); - - H1_FECollection h1_fec(order, dim); - DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, - FiniteElement::VALUE); - DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, - FiniteElement::INTEGRAL); - - FiniteElementSpace h1_fespace(&mesh, &h1_fec); - FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); - FiniteElementSpace dgi_fespace(&mesh, &dgi_fec); - - GridFunction h1_x(&h1_fespace); - GridFunction dgv_x(&dgv_fespace); - GridFunction dgi_x(&dgi_fespace); - - GridFunctionCoefficient h1_xCoef(&h1_x); - GridFunctionCoefficient dgv_xCoef(&dgv_x); - GridFunctionCoefficient dgi_xCoef(&dgi_x); - - h1_x.ProjectCoefficient(linCoef); - dgv_x.ProjectCoefficient(linCoef); - dgi_x.ProjectCoefficient(linCoef); - int npts = 0; - SECTION("Domain Evaluation (H1 Context)") + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::WEDGE; type++) { - int e = 1; - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = h1_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); + Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + FunctionCoefficient linCoef(func_3D_lin); - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); - double f_val = func_3D_lin(tip); + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + FiniteElementSpace dgi_fespace(&mesh, &dgi_fec); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + GridFunction dgi_x(&dgi_fespace); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + GridFunctionCoefficient h1_xCoef(&h1_x); + GridFunctionCoefficient dgv_xCoef(&dgv_x); + GridFunctionCoefficient dgi_xCoef(&dgi_x); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + h1_x.ProjectCoefficient(linCoef); + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + SECTION("Domain Evaluation 3D (H1 Context)") { - std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; + std::cout << "Domain Evaluation 3D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + + SECTION("Boundary Evaluation 3D (H1 Context)") { - std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; + std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + + SECTION("Domain Evaluation 3D (DG Context)") { - std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; + std::cout << "Domain Evaluation 3D (DG Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 3D (DG Context)") + { + std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } } } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); } - - SECTION("Boundary Evaluation (H1 Context)") - { - int be = 1; - ElementTransformation *T = mesh.GetBdrElementTransformation(be); - const FiniteElement *fe = h1_fespace.GetBE(be); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - - SECTION("Domain Evaluation (DG Context)") - { - int e = 1; - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - - SECTION("Interior Face Evaluation (DG Context)") - { - int be = 2; - FaceElementTransformations *T = mesh.GetInteriorFaceTransformations(be); - const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - - SECTION("Boundary Evaluation (DG Context)") - { - int be = 1; - FaceElementTransformations *T = mesh.GetBdrFaceTransformations(be); - const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << h1_gf_val - << " " << fabs(f_val - h1_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgv_gf_val - << " " << fabs(f_val - dgv_gf_val) << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " " << f_val << " " << dgi_gf_val - << " " << fabs(f_val - dgi_gf_val) << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - std::cout << "Checked GridFunction::GetValue at " - << npts << " points" << std::endl; + << npts << " 3D points" << std::endl; +} + +TEST_CASE("2D GetVectorValue", + "[GridFunction]" + "[VectorGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 2; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + + VectorFunctionCoefficient linCoef(2, Func_2D_lin); + + SECTION("2D GetVectorValue tests for element type " + + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + ND_FECollection nd_fec(order+1, dim); + RT_FECollection rt_fec(order+1, dim); + L2_FECollection l2_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec, dim); + FiniteElementSpace nd_fespace(&mesh, &nd_fec); + FiniteElementSpace rt_fespace(&mesh, &rt_fec); + FiniteElementSpace l2_fespace(&mesh, &l2_fec, dim); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec, dim); + FiniteElementSpace dgi_fespace(&mesh, &dgi_fec, dim); + + GridFunction h1_x( &h1_fespace); + GridFunction nd_x( &nd_fespace); + GridFunction rt_x( &rt_fespace); + GridFunction l2_x( &l2_fespace); + GridFunction dgv_x(&dgv_fespace); + GridFunction dgi_x(&dgi_fespace); + + VectorGridFunctionCoefficient h1_xCoef( &h1_x); + VectorGridFunctionCoefficient nd_xCoef( &nd_x); + VectorGridFunctionCoefficient rt_xCoef( &rt_x); + VectorGridFunctionCoefficient l2_xCoef( &l2_x); + VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); + VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); + + h1_x.ProjectCoefficient(linCoef); + nd_x.ProjectCoefficient(linCoef); + rt_x.ProjectCoefficient(linCoef); + l2_x.ProjectCoefficient(linCoef); + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + Vector f_val(2); f_val = 0.0; + Vector h1_gf_val(2); h1_gf_val = 0.0; + Vector nd_gf_val(2); nd_gf_val = 0.0; + Vector rt_gf_val(2); rt_gf_val = 0.0; + Vector l2_gf_val(2); l2_gf_val = 0.0; + Vector dgv_gf_val(2); dgv_gf_val = 0.0; + Vector dgi_gf_val(2); dgi_gf_val = 0.0; + + SECTION("Domain Evaluation 2D (H1 Context)") + { + std::cout << "Domain Evaluation 2D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_2D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2); + double nd_dist = Distance(f_val, nd_gf_val, 2); + double rt_dist = Distance(f_val, rt_gf_val, 2); + double l2_dist = Distance(f_val, l2_gf_val, 2); + double dgv_dist = Distance(f_val, dgv_gf_val, 2); + double dgi_dist = Distance(f_val, dgi_gf_val, 2); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_dist << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << e << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_dist << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << e << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << e << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 2D (H1 Context)") + { + std::cout << "Boundary Evaluation 2D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_2D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2); + double nd_dist = Distance(f_val, nd_gf_val, 2); + double rt_dist = Distance(f_val, rt_gf_val, 2); + double l2_dist = Distance(f_val, l2_gf_val, 2); + double dgv_dist = Distance(f_val, dgv_gf_val, 2); + double dgi_dist = Distance(f_val, dgi_gf_val, 2); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_dist << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << be << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_dist << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << be << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << be << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Domain Evaluation 2D (DG Context)") + { + std::cout << "Domain Evaluation 2D (DG Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_2D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2); + double nd_dist = Distance(f_val, nd_gf_val, 2); + double rt_dist = Distance(f_val, rt_gf_val, 2); + double l2_dist = Distance(f_val, l2_gf_val, 2); + double dgv_dist = Distance(f_val, dgv_gf_val, 2); + double dgi_dist = Distance(f_val, dgi_gf_val, 2); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_dist << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << e << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_dist << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << e << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << e << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 2D (DG Context)") + { + std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[2]; + Vector tip(tip_data, 2); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_2D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2); + double nd_dist = Distance(f_val, nd_gf_val, 2); + double rt_dist = Distance(f_val, rt_gf_val, 2); + double l2_dist = Distance(f_val, l2_gf_val, 2); + double dgv_dist = Distance(f_val, dgv_gf_val, 2); + double dgi_dist = Distance(f_val, dgi_gf_val, 2); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_dist << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << be << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_dist << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << be << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << be << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetVectorValue at " + << npts << " 2D points" << std::endl; +} + +TEST_CASE("3D GetVectorValue", + "[GridFunction]" + "[VectorGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 3; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::HEXAHEDRON; type++) + { + Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + + VectorFunctionCoefficient linCoef(3, Func_3D_lin); + + SECTION("3D GetVectorValue tests for element type " + + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + ND_FECollection nd_fec(order+1, dim); + RT_FECollection rt_fec(order+1, dim); + L2_FECollection l2_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec, dim); + FiniteElementSpace nd_fespace(&mesh, &nd_fec); + FiniteElementSpace rt_fespace(&mesh, &rt_fec); + FiniteElementSpace l2_fespace(&mesh, &l2_fec, dim); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec, dim); + FiniteElementSpace dgi_fespace(&mesh, &dgi_fec, dim); + + GridFunction h1_x( &h1_fespace); + GridFunction nd_x( &nd_fespace); + GridFunction rt_x( &rt_fespace); + GridFunction l2_x( &l2_fespace); + GridFunction dgv_x(&dgv_fespace); + GridFunction dgi_x(&dgi_fespace); + + VectorGridFunctionCoefficient h1_xCoef( &h1_x); + VectorGridFunctionCoefficient nd_xCoef( &nd_x); + VectorGridFunctionCoefficient rt_xCoef( &rt_x); + VectorGridFunctionCoefficient l2_xCoef( &l2_x); + VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); + VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); + + h1_x.ProjectCoefficient(linCoef); + nd_x.ProjectCoefficient(linCoef); + rt_x.ProjectCoefficient(linCoef); + l2_x.ProjectCoefficient(linCoef); + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + Vector f_val(3); f_val = 0.0; + Vector h1_gf_val(3); h1_gf_val = 0.0; + Vector nd_gf_val(3); nd_gf_val = 0.0; + Vector rt_gf_val(3); rt_gf_val = 0.0; + Vector l2_gf_val(3); l2_gf_val = 0.0; + Vector dgv_gf_val(3); dgv_gf_val = 0.0; + Vector dgi_gf_val(3); dgi_gf_val = 0.0; + + SECTION("Domain Evaluation 3D (H1 Context)") + { + std::cout << "Domain Evaluation 3D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 3); + double nd_dist = Distance(f_val, nd_gf_val, 3); + double rt_dist = Distance(f_val, rt_gf_val, 3); + double l2_dist = Distance(f_val, l2_gf_val, 3); + double dgv_dist = Distance(f_val, dgv_gf_val, 3); + double dgi_dist = Distance(f_val, dgi_gf_val, 3); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << e << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << "," + << rt_gf_val[2] << ") " << rt_dist + << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << e << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << "," + << l2_gf_val[2] << ") " << l2_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << e << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," + << dgi_gf_val[2] << ") " << dgi_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 3D (H1 Context)") + { + std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 3); + double nd_dist = Distance(f_val, nd_gf_val, 3); + double rt_dist = Distance(f_val, rt_gf_val, 3); + double l2_dist = Distance(f_val, l2_gf_val, 3); + double dgv_dist = Distance(f_val, dgv_gf_val, 3); + double dgi_dist = Distance(f_val, dgi_gf_val, 3); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << be << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << "," + << rt_gf_val[2] << ") " << rt_dist + << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << be << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << "," + << l2_gf_val[2] << ") " << l2_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << be << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," + << dgi_gf_val[2] << ") " << dgi_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Domain Evaluation 3D (DG Context)") + { + std::cout << "Domain Evaluation 3D (DG Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 3); + double nd_dist = Distance(f_val, nd_gf_val, 3); + double rt_dist = Distance(f_val, rt_gf_val, 3); + double l2_dist = Distance(f_val, l2_gf_val, 3); + double dgv_dist = Distance(f_val, dgv_gf_val, 3); + double dgi_dist = Distance(f_val, dgi_gf_val, 3); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << e << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << "," + << rt_gf_val[2] << ") " << rt_dist + << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << e << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << "," + << l2_gf_val[2] << ") " << l2_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << e << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," + << dgi_gf_val[2] << ") " << dgi_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + SECTION("Boundary Evaluation 3D (DG Context)") + { + std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 3); + double nd_dist = Distance(f_val, nd_gf_val, 3); + double rt_dist = Distance(f_val, rt_gf_val, 3); + double l2_dist = Distance(f_val, l2_gf_val, 3); + double dgv_dist = Distance(f_val, dgv_gf_val, 3); + double dgi_dist = Distance(f_val, dgi_gf_val, 3); + + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << be << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << "," + << rt_gf_val[2] << ") " << rt_dist + << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << be << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << "," + << l2_gf_val[2] << ") " << l2_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << be << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," + << dgi_gf_val[2] << ") " << dgi_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetVectorValue at " + << npts << " 3D points" << std::endl; } } // namespace get_value From 219c4fa73611a14a808a164eabef34fa9f95e3b5 Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Wed, 29 Apr 2020 20:47:15 -0400 Subject: [PATCH 245/535] Some clean up the Nedelec Field transfer routine a) now used v_num_loc directly b) added a new routine to get the rotated xi values --- mesh/pumi.cpp | 187 +++++++++++++++++++++++++------------------------- mesh/pumi.hpp | 9 ++- 2 files changed, 103 insertions(+), 93 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 2230061b51..9198967614 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -307,11 +307,11 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, // Create local numbering that respects the global ordering apf::Field* apf_field_crd = apf_mesh->getCoordinateField(); apf::FieldShape* crd_shape = apf::getShape(apf_field_crd); - apf::Numbering* v_num_loc = apf::createNumbering(apf_mesh, - "LocalVertexNumbering", - crd_shape, 1); + v_num_loc = apf::createNumbering(apf_mesh, + "LocalVertexNumbering", + crd_shape, 1); - // Construct the numbering v_loc_num and set the coordinates of the vertices. + // Construct the numbering v_num_loc and set the coordinates of the vertices. NumOfVertices = thisVertIds.Size(); vertices.SetSize(NumOfVertices); itr = apf_mesh->begin(0); @@ -691,6 +691,15 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, Finalize(refine, fix_orientation); } +ParPumiMesh::~ParPumiMesh() +{ + // clean ups + + // This is used during some of the field transfers, and therefore + // unlike the PumiMesh class, we cannot destroy this inside the + // constructor of the class. + apf::destroyNumbering(v_num_loc); +} // GridFunctionPumi Implementation needed for high order meshes GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM, @@ -922,6 +931,48 @@ void ParPumiMesh::UpdateMesh(const ParMesh* AdaptedpMesh) } } + +// Convert parent coordinate form a PUMI tet to an MFEM tet +IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, + apf::MeshEntity* tet, + int elemId, + std::vector& pumi_xi) +{ + MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); + std::size_t num_nodes = pumi_xi.size(); + // get downward vertices of PUMI element + apf::Downward vs; + int nv = apf_mesh->getDownward(tet,0,vs); + int pumi_vid[nv]; + for (int i = 0; i < nv; i++) + pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); + + // get downward vertices of MFEM element + mfem::Array mfem_vid; + this->GetElementVertices(elemId, mfem_vid); + + // get rotated indices of PUMI element + int pumi_vid_rot[nv]; + for (int i = 0; i < nv; i++) + pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); + apf::Downward vs_rot; + for (int i = 0; i < nv; i++) + vs_rot[i] = vs[pumi_vid_rot[i]]; + int rotation = ma::findTetRotation(apf_mesh, tet, vs_rot); + + // map the coordinates computed on the original set of vertices + // to the coordinates computed based on a rotated set of vertices + IntegrationRule mfem_xi(num_nodes); + for(int i = 0; i < num_nodes; i++) { + ma::rotateTetXi(pumi_xi[i], rotation); + IntegrationPoint& ip = mfem_xi.IntPoint(i); + double tmp_xi[3]; + pumi_xi[i].toArray(tmp_xi); + ip.Set(tmp_xi,3); + } + return mfem_xi; +} + // Transfer a mixed vector-scalar field (i.e. velocity,pressure) and the // magnitude of the vector field to use for mesh adaptation. void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, @@ -1493,85 +1544,46 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf_mesh->end(itr); } -static int findIndex(mfem::Array array, int value) -{ - int size = array.Size(); - for (int i = 0; i < size; i++) { - if (value == array[i] ) return i; - } - return -1; -} void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* gf, apf::Field* NedelecField) { - apf::Numbering* local_vtx_numbering = apf_mesh->getNumbering(0); // TODO - apf::FieldShape* nedelecFieldShape = NedelecField->getShape(); int num_nodes = 4 * nedelecFieldShape->countNodesOn(0) + // Vertex 6 * nedelecFieldShape->countNodesOn(1) + // Edge 4 * nedelecFieldShape->countNodesOn(2) + // Triangle nedelecFieldShape->countNodesOn(4); // Tetrahedron int dim = apf_mesh->getDimension(); - apf::NewArray pumi_nodes (num_nodes); + std::vector pumi_nodes(num_nodes); size_t elemNo = 0; - apf::MeshEntity* el_ent; - apf::MeshIterator* el_it; - el_it = apf_mesh->begin(dim); - while ( el_ent = apf_mesh->iterate(el_it) ) { + apf::MeshEntity* ent; + apf::MeshIterator* it = apf_mesh->begin(dim); + while ( ent = apf_mesh->iterate(it) ) { // TODO use getPumiNodeXis to collect pumi nodes when fixed // collect pumi nodes - int node_number = 0; + int non = 0; for (int d = 0; d <= dim; d++) { - if (nedelecFieldShape->hasNodesIn(d)) { - apf::Downward a; - int na = apf_mesh->getDownward(el_ent,d,a); - for (int i = 0; i < na; i++) { // loop over downward entities - int type = apf_mesh->getType(a[i]); - int nan = nedelecFieldShape->countNodesOn(type); - for (int n = 0; n < nan; n++) { // loop over entity nodes - apf::Vector3 ent_xi; - nedelecFieldShape->getNodeXi(type, n, ent_xi); // getNodeXi - apf::Vector3 elem_xi = apf::boundaryToElementXi( - apf_mesh, a[i], el_ent, ent_xi); // transform entity nodeXi to parent element nodeXi. - pumi_nodes[node_number++] = elem_xi; - } + if (!nedelecFieldShape->hasNodesIn(d)) continue; + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) { + int type = apf_mesh->getType(a[i]); + int nan = nedelecFieldShape->countNodesOn(type); + for (int n = 0; n < nan; n++) { + apf::Vector3 xi; + nedelecFieldShape->getNodeXi(type, n, xi); + pumi_nodes[non++] = apf::boundaryToElementXi(apf_mesh, a[i], ent, xi); } } } - // get downward vertices of PUMI element - apf::Downward v; - int nv = apf_mesh->getDownward(el_ent,0,v); - std::vector pumi_vtx_indices (nv); - for (int i = 0; i < nv; i++) - pumi_vtx_indices[i] = apf::getNumber(local_vtx_numbering, v[i], 0, 0); - - // get downward vertices of MFEM element - mfem::Array mfem_vtx_indices; - this->GetElementVertices(elemNo, mfem_vtx_indices); - - // get rotated indices of PUMI element - int pumi_tetv[nv]; - for (int i = 0; i < nv; i++) - pumi_tetv[i] = findIndex(mfem_vtx_indices, pumi_vtx_indices[i]); - apf::Downward rv; - for (int i = 0; i < nv; i++) - rv[i] = v[ pumi_tetv[i] ]; - int rotation = ma::findTetRotation(apf_mesh, el_ent, rv); - - // map the coordinates computed on the original set of vertices - // to the coordinates computed based on a rotated set of vertices - IntegrationRule mfem_nodes (num_nodes); - for(int i = 0; i < num_nodes; i++) { - ma::rotateTetXi(pumi_nodes[i], rotation); - IntegrationPoint& ip = mfem_nodes.IntPoint(i); - double xi[3]; - pumi_nodes[i].toArray(xi); - ip.Set(xi,3); - } + // Get the parent coordinates with respect to the MFEM element + IntegrationRule mfem_nodes = ParentXisPUMItoMFEM(apf_mesh, + ent, + elemNo, + pumi_nodes); // evaluate the vector field on the mfem nodes ElementTransformation* eltr = this->GetElementTransformation(elemNo); @@ -1579,41 +1591,32 @@ void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, gf->GetVectorValues(*eltr, mfem_nodes, mfem_field_vals); // compute and store dofs on ND field - node_number = 0; + non = 0; for (int d = 0; d <= dim; d++) { - if (nedelecFieldShape->hasNodesIn(d)) { - apf::Downward a; - int na = apf_mesh->getDownward(el_ent,d,a); - for (int i = 0; i < na; i++) { // loop over downward entities - int type = apf_mesh->getType(a[i]); - int nan = nedelecFieldShape->countNodesOn(type); - apf::MeshElement* me = apf::createMeshElement(apf_mesh, a[i]); - for (int n = 0; n < nan; n++) { // loop over entity nodes - apf::Vector3 xi, tangent; - nedelecFieldShape->getNodeXi(type, n, xi); // getNodeXi - nedelecFieldShape->getNodeTangent(type, n, tangent); // getNodeTangent - - apf::Vector3 pumi_field_vector; // getVectorValue in PUMI - pumi_field_vector[0] = mfem_field_vals(0,node_number); - pumi_field_vector[1] = mfem_field_vals(1,node_number); - pumi_field_vector[2] = mfem_field_vals(2,node_number); - - apf::Matrix3x3 J; // get Jacobian - apf::getJacobian(me, xi, J); - - apf::Vector3 temp = J * pumi_field_vector; // compute scalar dof - double dof = temp * tangent; - apf::setScalar(NedelecField, a[i], n, dof); - - node_number++; - } - apf::destroyMeshElement(me); + if (!nedelecFieldShape->hasNodesIn(d)) continue; + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) { + int type = apf_mesh->getType(a[i]); + int nan = nedelecFieldShape->countNodesOn(type); + apf::MeshElement* me = apf::createMeshElement(apf_mesh, a[i]); + for (int n = 0; n < nan; n++) { + apf::Vector3 xi, tangent; + nedelecFieldShape->getNodeXi(type, n, xi); + nedelecFieldShape->getNodeTangent(type, n, tangent); + apf::Vector3 pumi_field_vector(mfem_field_vals.GetColumn(non)); + apf::Matrix3x3 J; + apf::getJacobian(me, xi, J); + double dof = (J * pumi_field_vector) * tangent; + apf::setScalar(NedelecField, a[i], n, dof); + non++; } + apf::destroyMeshElement(me); } } elemNo++; } - apf_mesh->end(el_it); // end loop over all elements + apf_mesh->end(it); // end loop over all elements } void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 9282cf004f..a54c52de6a 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -78,6 +78,13 @@ public: ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, int refine = 1, bool fix_orientation = true); + /// Convert the parent coordinate from PUMI to MFEM + /// This will only be used for Reoriented tet meshes during + /// field transfer + IntegrationRule ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, + apf::MeshEntity* tet, + int elemId, + std::vector& pumi_xi); /// Transfer field from MFEM mesh to PUMI mesh [Mixed]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* Vel, @@ -110,7 +117,7 @@ public: apf::Field* ScalarField, ParGridFunction* Pr); - virtual ~ParPumiMesh() { } + virtual ~ParPumiMesh(); }; From 049b447ec7b767b093487747e1fc99837c8b9729 Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Thu, 30 Apr 2020 00:06:17 -0400 Subject: [PATCH 246/535] Uses apf::getElementXis instead of a loop Previously this was done in a loop inside each of the field transfer member functions (a lot of code repetition!). Now it is a single function call that can be called by any of the field transfer members. On this commit it is only used for the Nedelec field transfer routine. --- mesh/pumi.cpp | 113 +++++++++++++++++++++++++------------------------- mesh/pumi.hpp | 10 +++-- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 9198967614..077e95a737 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -48,6 +48,22 @@ static void getPumiNodeXis(apf::FieldShape* fs, } } +static void getPumiNodeXis(apf::FieldShape* fs, + apf::Mesh2* m, + apf::MeshEntity* e, + IntegrationRule& xis) +{ + apf::NewArray pumiXis; + apf::getElementNodeXis(fs, m, e, pumiXis); + xis.SetSize(pumiXis.size()); + for (size_t i = 0; i < pumiXis.size(); i++) { + IntegrationPoint& ip = xis.IntPoint(i); + double xi[3]; + pumiXis[i].toArray(xi); + ip.Set(xi, 3); + } +} + static void ReadPumiElement(apf::MeshEntity* Ent, /* ptr to pumi entity */ apf::Downward Verts, @@ -936,35 +952,42 @@ void ParPumiMesh::UpdateMesh(const ParMesh* AdaptedpMesh) IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, apf::MeshEntity* tet, int elemId, - std::vector& pumi_xi) + apf::NewArray& pumi_xi, + bool checkOrientation) { - MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); - std::size_t num_nodes = pumi_xi.size(); - // get downward vertices of PUMI element - apf::Downward vs; - int nv = apf_mesh->getDownward(tet,0,vs); - int pumi_vid[nv]; - for (int i = 0; i < nv; i++) - pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); - - // get downward vertices of MFEM element - mfem::Array mfem_vid; - this->GetElementVertices(elemId, mfem_vid); - - // get rotated indices of PUMI element - int pumi_vid_rot[nv]; - for (int i = 0; i < nv; i++) - pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); - apf::Downward vs_rot; - for (int i = 0; i < nv; i++) - vs_rot[i] = vs[pumi_vid_rot[i]]; - int rotation = ma::findTetRotation(apf_mesh, tet, vs_rot); - - // map the coordinates computed on the original set of vertices - // to the coordinates computed based on a rotated set of vertices + int num_nodes = pumi_xi.size(); IntegrationRule mfem_xi(num_nodes); + int rotation = 0; + + // if check orientation is on then find the rotation + if (checkOrientation) { + // by this point + MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); + // get downward vertices of PUMI element + apf::Downward vs; + int nv = apf_mesh->getDownward(tet,0,vs); + int pumi_vid[nv]; + for (int i = 0; i < nv; i++) + pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); + + // get downward vertices of MFEM element + mfem::Array mfem_vid; + this->GetElementVertices(elemId, mfem_vid); + + // get rotated indices of PUMI element + int pumi_vid_rot[nv]; + for (int i = 0; i < nv; i++) + pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); + apf::Downward vs_rot; + for (int i = 0; i < nv; i++) + vs_rot[i] = vs[pumi_vid_rot[i]]; + rotation = ma::findTetRotation(apf_mesh, tet, vs_rot); + } + for(int i = 0; i < num_nodes; i++) { - ma::rotateTetXi(pumi_xi[i], rotation); + // for non zero "rotation", rotate the xi + if (rotation) + ma::rotateTetXi(pumi_xi[i], rotation); IntegrationPoint& ip = mfem_xi.IntPoint(i); double tmp_xi[3]; pumi_xi[i].toArray(tmp_xi); @@ -1549,49 +1572,25 @@ void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::Field* NedelecField) { apf::FieldShape* nedelecFieldShape = NedelecField->getShape(); - int num_nodes = 4 * nedelecFieldShape->countNodesOn(0) + // Vertex - 6 * nedelecFieldShape->countNodesOn(1) + // Edge - 4 * nedelecFieldShape->countNodesOn(2) + // Triangle - nedelecFieldShape->countNodesOn(4); // Tetrahedron int dim = apf_mesh->getDimension(); - std::vector pumi_nodes(num_nodes); + // loop over all elements size_t elemNo = 0; apf::MeshEntity* ent; apf::MeshIterator* it = apf_mesh->begin(dim); while ( ent = apf_mesh->iterate(it) ) { - - // TODO use getPumiNodeXis to collect pumi nodes when fixed - // collect pumi nodes - int non = 0; - for (int d = 0; d <= dim; d++) { - if (!nedelecFieldShape->hasNodesIn(d)) continue; - apf::Downward a; - int na = apf_mesh->getDownward(ent,d,a); - for (int i = 0; i < na; i++) { - int type = apf_mesh->getType(a[i]); - int nan = nedelecFieldShape->countNodesOn(type); - for (int n = 0; n < nan; n++) { - apf::Vector3 xi; - nedelecFieldShape->getNodeXi(type, n, xi); - pumi_nodes[non++] = apf::boundaryToElementXi(apf_mesh, a[i], ent, xi); - } - } - } - - // Get the parent coordinates with respect to the MFEM element - IntegrationRule mfem_nodes = ParentXisPUMItoMFEM(apf_mesh, - ent, - elemNo, - pumi_nodes); - + // get all the pumi nodes and rotate them + apf::NewArray pumi_nodes; + apf::getElementNodeXis(nedelecFieldShape, apf_mesh, ent, pumi_nodes); + IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( + apf_mesh, ent, elemNo, pumi_nodes, true); // evaluate the vector field on the mfem nodes ElementTransformation* eltr = this->GetElementTransformation(elemNo); DenseMatrix mfem_field_vals; gf->GetVectorValues(*eltr, mfem_nodes, mfem_field_vals); // compute and store dofs on ND field - non = 0; + int non = 0; for (int d = 0; d <= dim; d++) { if (!nedelecFieldShape->hasNodesIn(d)) continue; apf::Downward a; diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index a54c52de6a..87f7c434ed 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -79,12 +79,16 @@ public: int refine = 1, bool fix_orientation = true); /// Convert the parent coordinate from PUMI to MFEM - /// This will only be used for Reoriented tet meshes during - /// field transfer + /// * By default this functions assumes that there is no change + /// in the orientations of elements. + /// * In case there is a change in the orientation (e.g., for + /// higher-order Nedelec shapes, call the functions with last + /// argument = true IntegrationRule ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, apf::MeshEntity* tet, int elemId, - std::vector& pumi_xi); + apf::NewArray& pumi_xi, + bool checkOrientation = false); /// Transfer field from MFEM mesh to PUMI mesh [Mixed]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* Vel, From 6173cb7e4cfa81b22746c9d556c290da2ad97f78 Mon Sep 17 00:00:00 2001 From: camierjs Date: Thu, 30 Apr 2020 10:14:08 -0700 Subject: [PATCH 247/535] MFEM_USE_SIMD defaulted to YES --- CHANGELOG | 2 +- config/defaults.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7062ae2830..107524b157 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -80,7 +80,7 @@ Miscellaneous - x86 (SSE/AVX/AVX2/AVX512), - Power8 & Power9 (VSX), - BG/Q (QPX). - It can be enabled with MFEM_USE_SIMD=YES. + It is now enabled by default, and can be disabled with MFEM_USE_SIMD=NO. - In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the solver can work with non-SPD preconditioner B. diff --git a/config/defaults.mk b/config/defaults.mk index cfb3e904c3..ed5ab20f56 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -137,7 +137,7 @@ MFEM_USE_RAJA = NO MFEM_USE_OCCA = NO MFEM_USE_CEED = NO MFEM_USE_UMPIRE = NO -MFEM_USE_SIMD = NO +MFEM_USE_SIMD = YES MFEM_USE_ADIOS2 = NO # Compile and link options for zlib. From e3665d6cd1308f851e699237138cae4f17684591 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 10:45:57 -0700 Subject: [PATCH 248/535] Removing `ActiveSide` concept and simplifying the logic in GetGrad, GetVecGrad, GetDiv, and GetCurl --- fem/eltrans.cpp | 16 -- fem/gridfunc.cpp | 462 ++++++++++++++++++++++++----------------------- 2 files changed, 241 insertions(+), 237 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index e5021b15bd..f852577a9d 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -599,22 +599,6 @@ FaceElementTransformations::GetIntPoint2Transformation() return Loc2; } -void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) -{ - IsoparametricTransformation::SetIntPoint(ip); - - if (Elem1) - { - Loc1.Transform(*ip, eip1); - Elem1->SetIntPoint(&eip1); - } - if (Elem2) - { - Loc2.Transform(*ip, eip2); - Elem2->SetIntPoint(&eip2); - } -} - void FaceElementTransformations::Transform(const IntegrationPoint &ip, Vector &trans) { diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index e86aacd57b..d4a23c309e 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -725,8 +725,8 @@ double GridFunction::GetValue(ElementTransformation &T, ElementTransformation & T1 = FET->GetElement1Transformation(); return GetValue(T1, T1.GetIntPoint(), comp); } - break; } + break; case ElementTransformation::BDR_FACE: { FaceElementTransformations * FET = @@ -830,8 +830,8 @@ void GridFunction::GetVectorValue(ElementTransformation &T, ElementTransformation & T1 = FET->GetElement1Transformation(); return GetVectorValue(T1, T1.GetIntPoint(), val); } - break; } + break; case ElementTransformation::BDR_FACE: { FaceElementTransformations * FET = @@ -1280,235 +1280,250 @@ double GridFunction::GetDivergence(ElementTransformation &T) const { double div_v = 0.0; - if (T.ElementType == ElementTransformation::ELEMENT) + switch (T.ElementType) { - int elNo = T.ElementNo; - const FiniteElement *fe = fes->GetFE(elNo); - if (fe->GetRangeType() == FiniteElement::SCALAR) + case ElementTransformation::ELEMENT: { - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - DenseMatrix grad_hat; - GetVectorGradientHat(T, grad_hat); - const DenseMatrix &Jinv = T.InverseJacobian(); - div_v = 0.0; - for (int i = 0; i < Jinv.Width(); i++) + int elNo = T.ElementNo; + const FiniteElement *fe = fes->GetFE(elNo); + if (fe->GetRangeType() == FiniteElement::SCALAR) { - for (int j = 0; j < Jinv.Height(); j++) + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + DenseMatrix grad_hat; + GetVectorGradientHat(T, grad_hat); + const DenseMatrix &Jinv = T.InverseJacobian(); + div_v = 0.0; + for (int i = 0; i < Jinv.Width(); i++) { - div_v += grad_hat(i, j) * Jinv(j, i); + for (int j = 0; j < Jinv.Height(); j++) + { + div_v += grad_hat(i, j) * Jinv(j, i); + } } } - } - else - { - // Assuming RT-type space - Array dofs; - fes->GetElementDofs(elNo, dofs); - Vector loc_data, divshape(fe->GetDof()); - GetSubVector(dofs, loc_data); - fe->CalcDivShape(T.GetIntPoint(), divshape); - div_v = (loc_data * divshape) / T.Weight(); - } - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - FaceElementTransformations * FET = NULL; - - const FiniteElement *fe = fes->GetBE(T.ElementNo); - - if (fe == NULL) - { - // This must be a DG field. Check for DG context. - FET = dynamic_cast(&T); - if (FET == NULL) + else { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + // Assuming RT-type space + Array dofs; + fes->GetElementDofs(elNo, dofs); + Vector loc_data, divshape(fe->GetDof()); + GetSubVector(dofs, loc_data); + fe->CalcDivShape(T.GetIntPoint(), divshape); + div_v = (loc_data * divshape) / T.Weight(); } } - else + break; + case ElementTransformation::BDR_ELEMENT: { - /// Not a DG field but we will need the neighboring element. - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - FET->SetActiveSide(0); - FET->SetIntPoint(&T.GetIntPoint()); + // In order to capture the derivative of the normal component of + // the field we must evaluate it in the neighboring element. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + + // Boundary elements and Boundary Faces may have different + // orientations so adjust the integration point if necessary. + int o = 0; + if (fes->GetMesh()->Dimension() == 3) + { + int f; + fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o); + } + + IntegrationPoint fip; + be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); + + FET->SetIntPoint(&fip); + ElementTransformation & T1 = FET->GetElement1Transformation(); + + div_v = GetDivergence(T1); } - div_v = GetDivergence(*FET->GetActiveElementTransformation()); - } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) + break; + case ElementTransformation::BDR_FACE: { - div_v = GetDivergence(*FET->GetActiveElementTransformation()); + // This must be a DG context so this dynamic cast must succeed. + FaceElementTransformations * FET = + dynamic_cast(&T); + + // Evaluate in neighboring element + ElementTransformation & T1 = FET->GetElement1Transformation(); + div_v = GetDivergence(T1); + } + break; + default: + { + MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \"" + << T.ElementType << "\""); } - } - else - { - MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \"" - << T.ElementType << "\""); } return div_v; } void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const { - if (T.ElementType == ElementTransformation::ELEMENT) + switch (T.ElementType) { - int elNo = T.ElementNo; - const FiniteElement *fe = fes->GetFE(elNo); - if (fe->GetRangeType() == FiniteElement::SCALAR) + case ElementTransformation::ELEMENT: { - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - DenseMatrix grad_hat; - GetVectorGradientHat(T, grad_hat); - const DenseMatrix &Jinv = T.InverseJacobian(); - DenseMatrix grad(grad_hat.Height(), Jinv.Width()); // vdim x FElem->Dim - Mult(grad_hat, Jinv, grad); - MFEM_ASSERT(grad.Height() == grad.Width(), ""); - if (grad.Height() == 3) + int elNo = T.ElementNo; + const FiniteElement *fe = fes->GetFE(elNo); + if (fe->GetRangeType() == FiniteElement::SCALAR) { - curl.SetSize(3); - curl(0) = grad(2,1) - grad(1,2); - curl(1) = grad(0,2) - grad(2,0); - curl(2) = grad(1,0) - grad(0,1); - } - else if (grad.Height() == 2) - { - curl.SetSize(1); - curl(0) = grad(1,0) - grad(0,1); - } - } - else - { - // Assuming ND-type space - Array dofs; - fes->GetElementDofs(elNo, dofs); - Vector loc_data; - GetSubVector(dofs, loc_data); - DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1); - fe->CalcCurlShape(T.GetIntPoint(), curl_shape); - curl.SetSize(curl_shape.Width()); - if (curl_shape.Width() == 3) - { - double curl_hat[3]; - curl_shape.MultTranspose(loc_data, curl_hat); - T.Jacobian().Mult(curl_hat, curl); + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + DenseMatrix grad_hat; + GetVectorGradientHat(T, grad_hat); + const DenseMatrix &Jinv = T.InverseJacobian(); + // Dimensions of grad are vdim x FElem->Dim + DenseMatrix grad(grad_hat.Height(), Jinv.Width()); + Mult(grad_hat, Jinv, grad); + MFEM_ASSERT(grad.Height() == grad.Width(), ""); + if (grad.Height() == 3) + { + curl.SetSize(3); + curl(0) = grad(2,1) - grad(1,2); + curl(1) = grad(0,2) - grad(2,0); + curl(2) = grad(1,0) - grad(0,1); + } + else if (grad.Height() == 2) + { + curl.SetSize(1); + curl(0) = grad(1,0) - grad(0,1); + } } else { - curl_shape.MultTranspose(loc_data, curl); + // Assuming ND-type space + Array dofs; + fes->GetElementDofs(elNo, dofs); + Vector loc_data; + GetSubVector(dofs, loc_data); + DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1); + fe->CalcCurlShape(T.GetIntPoint(), curl_shape); + curl.SetSize(curl_shape.Width()); + if (curl_shape.Width() == 3) + { + double curl_hat[3]; + curl_shape.MultTranspose(loc_data, curl_hat); + T.Jacobian().Mult(curl_hat, curl); + } + else + { + curl_shape.MultTranspose(loc_data, curl); + } + curl /= T.Weight(); } - curl /= T.Weight(); } - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - FaceElementTransformations * FET = NULL; - - const FiniteElement *fe = fes->GetBE(T.ElementNo); - - if (fe == NULL) + break; + case ElementTransformation::BDR_ELEMENT: { - // This must be a DG field. Check for DG context. - FET = dynamic_cast(&T); - if (FET == NULL) + // In order to capture the tangential components of the curl we + // must evaluate it in the neighboring element. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + + // Boundary elements and Boundary Faces may have different + // orientations so adjust the integration point if necessary. + int o = 0; + if (fes->GetMesh()->Dimension() == 3) { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + int f; + fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o); } + + IntegrationPoint fip; + be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); + + FET->SetIntPoint(&fip); + ElementTransformation & T1 = FET->GetElement1Transformation(); + + GetCurl(T1, curl); } - else + break; + case ElementTransformation::BDR_FACE: { - /// Not a DG field but we will need the neighboring element. - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - FET->SetActiveSide(0); - FET->SetIntPoint(&T.GetIntPoint()); + // This must be a DG context so this dynamic cast must succeed. + FaceElementTransformations * FET = + dynamic_cast(&T); + + // Evaluate in neighboring element + ElementTransformation & T1 = FET->GetElement1Transformation(); + GetCurl(T1, curl); } - GetCurl(*FET->GetActiveElementTransformation(), curl); - } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) + break; + default: { - GetCurl(*FET->GetActiveElementTransformation(), curl); + MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \"" + << T.ElementType << "\""); } } - else - { - MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \"" - << T.ElementType << "\""); - } } void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const { - const FiniteElement * fe = NULL; - if (T.ElementType == ElementTransformation::ELEMENT) + switch (T.ElementType) { - fe = fes->GetFE(T.ElementNo); - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - int spaceDim = fes->GetMesh()->SpaceDimension(); - int dim = fe->GetDim(), dof = fe->GetDof(); - DenseMatrix dshape(dof, dim); - Vector lval, gh(dim); - Array dofs; - - grad.SetSize(spaceDim); - fes->GetElementDofs(T.ElementNo, dofs); - GetSubVector(dofs, lval); - fe->CalcDShape(T.GetIntPoint(), dshape); - dshape.MultTranspose(lval, gh); - T.InverseJacobian().MultTranspose(gh, grad); - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - FaceElementTransformations * FET = NULL; - - fe = fes->GetBE(T.ElementNo); - - if (fe == NULL) + case ElementTransformation::ELEMENT: { - // This must be a DG field. Check for DG context. - FET = dynamic_cast(&T); - if (FET == NULL) + const FiniteElement * fe = fes->GetFE(T.ElementNo); + MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, + "invalid FE map type"); + int spaceDim = fes->GetMesh()->SpaceDimension(); + int dim = fe->GetDim(), dof = fe->GetDof(); + DenseMatrix dshape(dof, dim); + Vector lval, gh(dim); + Array dofs; + + grad.SetSize(spaceDim); + fes->GetElementDofs(T.ElementNo, dofs); + GetSubVector(dofs, lval); + fe->CalcDShape(T.GetIntPoint(), dshape); + dshape.MultTranspose(lval, gh); + T.InverseJacobian().MultTranspose(gh, grad); + } + break; + case ElementTransformation::BDR_ELEMENT: + { + // In order to capture the normal component of the gradient we + // must evaluate it in the neighboring element. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + + // Boundary elements and Boundary Faces may have different + // orientations so adjust the integration point if necessary. + int o = 0; + if (fes->GetMesh()->Dimension() == 3) { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + int f; + fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o); } + + IntegrationPoint fip; + be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); + + FET->SetIntPoint(&fip); + ElementTransformation & T1 = FET->GetElement1Transformation(); + + GetGradient(T1, grad); } - else + break; + case ElementTransformation::BDR_FACE: { - /// Not a DG field but we will need the neighboring element. - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - FET->SetActiveSide(0); - FET->SetIntPoint(&T.GetIntPoint()); + // This must be a DG context so this dynamic cast must succeed. + FaceElementTransformations * FET = + dynamic_cast(&T); + + // Evaluate in neighboring element + ElementTransformation & T1 = FET->GetElement1Transformation(); + GetGradient(T1, grad); } - GetGradient(*FET->GetActiveElementTransformation(), grad); - } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) + break; + default: { - GetGradient(*FET->GetActiveElementTransformation(), grad); + MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \"" + << T.ElementType << "\""); } } - else - { - MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \"" - << T.ElementType << "\""); - } } void GridFunction::GetGradients(ElementTransformation &tr, @@ -1539,56 +1554,61 @@ void GridFunction::GetGradients(ElementTransformation &tr, void GridFunction::GetVectorGradient( ElementTransformation &T, DenseMatrix &grad) const { - if (T.ElementType == ElementTransformation::ELEMENT) + switch (T.ElementType) { - MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); - DenseMatrix grad_hat; - GetVectorGradientHat(T, grad_hat); - const DenseMatrix &Jinv = T.InverseJacobian(); - grad.SetSize(grad_hat.Height(), Jinv.Width()); - Mult(grad_hat, Jinv, grad); - } - else if (T.ElementType == ElementTransformation::BDR_ELEMENT) - { - FaceElementTransformations * FET = NULL; - - const FiniteElement *fe = fes->GetBE(T.ElementNo); - - if (fe == NULL) + case ElementTransformation::ELEMENT: { - // This must be a DG field. Check for DG context. - FET = dynamic_cast(&T); - if (FET == NULL) + MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() == + FiniteElement::VALUE, "invalid FE map type"); + DenseMatrix grad_hat; + GetVectorGradientHat(T, grad_hat); + const DenseMatrix &Jinv = T.InverseJacobian(); + grad.SetSize(grad_hat.Height(), Jinv.Width()); + Mult(grad_hat, Jinv, grad); + } + break; + case ElementTransformation::BDR_ELEMENT: + { + // In order to capture the normal component of the gradient we + // must evaluate it in the neighboring element. + FaceElementTransformations * FET = + fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + + // Boundary elements and Boundary Faces may have different + // orientations so adjust the integration point if necessary. + int o = 0; + if (fes->GetMesh()->Dimension() == 3) { - // non-DG context - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); + int f; + fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o); } + + IntegrationPoint fip; + be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); + + FET->SetIntPoint(&fip); + ElementTransformation & T1 = FET->GetElement1Transformation(); + + GetVectorGradient(T1, grad); } - else + break; + case ElementTransformation::BDR_FACE: { - /// Not a DG field but we will need the neighboring element. - FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); - FET->SetActiveSide(0); - FET->SetIntPoint(&T.GetIntPoint()); + // This must be a DG context so this dynamic cast must succeed. + FaceElementTransformations * FET = + dynamic_cast(&T); + + // Evaluate in neighboring element + ElementTransformation & T1 = FET->GetElement1Transformation(); + GetVectorGradient(T1, grad); } - GetVectorGradient(*FET->GetActiveElementTransformation(), grad); - } - else if (T.ElementType == ElementTransformation::FACE) - { - // This must be a DG field called in a DG context. - FaceElementTransformations * FET = - dynamic_cast(&T); - if (FET != NULL) + break; + default: { - GetVectorGradient(*FET->GetActiveElementTransformation(), grad); + MFEM_ABORT("GridFunction::GetVectorGradient: " + "Unsupported element type \"" << T.ElementType << "\""); } } - else - { - MFEM_ABORT("GridFunction::GetVectorGradient: Unsupported element type \"" - << T.ElementType << "\""); - } } void GridFunction::GetElementAverages(GridFunction &avgs) const From 8dda4f7441ed520cb5b523954154962444279fa5 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Thu, 30 Apr 2020 10:59:22 -0700 Subject: [PATCH 249/535] Numerous changes suggested by Jakub in the review. --- fem/bilinearform.hpp | 6 ++---- fem/bilinearform_ext.hpp | 2 +- fem/coefficient.hpp | 22 ++++++++++++---------- fem/eltrans.hpp | 8 ++++---- fem/fe.hpp | 6 +++--- fem/fespace.cpp | 1 + fem/fespace.hpp | 36 +++++++++++++++++++++--------------- fem/linearform.hpp | 2 +- fem/nonlininteg.hpp | 2 +- general/array.hpp | 2 +- general/communication.hpp | 2 +- 11 files changed, 48 insertions(+), 41 deletions(-) diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index a480802a67..01b87c783d 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -44,10 +44,8 @@ enum class AssemblyLevel }; -/** Class for bilinear form - Used to form a matrix given the - associated FE space and BLFIntegrators. The - sum of all the BLFIntegrators will be used - form the matrix M. */ +/** @brief Used to form a matrix given the associated FE space and BLFIntegrators + The sum of all the BLFIntegrators will be used form the matrix M. */ class BilinearForm : public Matrix { protected: diff --git a/fem/bilinearform_ext.hpp b/fem/bilinearform_ext.hpp index 0045684fa8..ecae307a2e 100644 --- a/fem/bilinearform_ext.hpp +++ b/fem/bilinearform_ext.hpp @@ -83,7 +83,7 @@ public: ~FABilinearFormExtension() {} }; -/// Data and methods for element-assembled bilinear forms NOT YET IMPLIMENTED +/// Data and methods for element-assembled bilinear forms NOT YET IMPLEMENTED class EABilinearFormExtension : public BilinearFormExtension { public: diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index e446b1fe84..a4a8901536 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -27,7 +27,10 @@ class ParMesh; #endif -/// Base class Coefficients that optionally depend on space and time. +/** @brief Base class Coefficients that optionally depend on space and + time. These are used by the BilinearFormIntegrator, + LinearFormIntegrator, and NonlinearFormIntegrator classes to represent + the physical coeffiencients in the PDEs that are being discretized. */ class Coefficient { protected: @@ -192,7 +195,7 @@ public: /** @brief A coefficient that depends on 1 or 2 parent coefficients and a - transformation rule represented by a c-function. + transformation rule represented by a C-function. \f$ C(x,t) = T(Q1(x,t)) \f$ or \f$ C(x,t) = T(Q1(x,t), Q2(x,t)) \f$ @@ -217,7 +220,7 @@ public: }; /** @brief Delta function coefficient optionally multiplied by a weight - coefficient and a scaled time dependent c-function. + coefficient and a scaled time dependent C-function. \f$ F(x,t) = w(x,t) s T(t) d(x - xc) \f$ @@ -332,8 +335,7 @@ public: { return active_attr[T.Attribute-1] ? c->Eval(T, ip, GetTime()) : 0.0; } }; - -/// Base class for Vector Coefficients that optionally depend on time and space. +/// Base class for vector Coefficients that optionally depend on time and space. class VectorCoefficient { protected: @@ -341,7 +343,7 @@ protected: double time; public: - /// Initilize the a VectorCoefficient with vector dimension @a vd. + /// Initilize the VectorCoefficient with vector dimension @a vd. VectorCoefficient(int vd) { vdim = vd; time = 0.; } /// Set the time for time dependent coefficients @@ -653,8 +655,8 @@ public: virtual ~VectorDeltaCoefficient() { } }; -/** @brief Derived vector coefficient that takes the value of the parent vector - coefficient for the active attrs and is zero otherwise. */ +/** @brief Derived vector coefficient that has the value of the parent vector + where it is active and is zero otherwise. */ class VectorRestrictedCoefficient : public VectorCoefficient { private: @@ -824,8 +826,8 @@ public: }; -/** @brief Derived matrix coefficient that takes the value of the parent - matrix coefficient for the active attrs and is zero otherwise. */ +/** @brief Derived matrix coefficient that has the value of the parent + matrix coefficient where it is active and is zero otherwise. */ class MatrixRestrictedCoefficient : public MatrixCoefficient { private: diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 3e6f07185b..ac11a23abc 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -55,7 +55,7 @@ public: ElementTransformation(); - /** @brief Set the integration point @a ip that weights and jacobians will + /** @brief Set the integration point @a ip that weights and Jacobians will be evaluated at. */ void SetIntPoint(const IntegrationPoint *ip) { IntPoint = ip; EvalState = 0; } @@ -93,17 +93,17 @@ public: { return (EvalState & HESSIAN_MASK) ? d2Fdx2 : EvalHessian(); } /** @brief Return the weight of the Jacobian matrix of the transformation - at the currently set IntegrationPoint, using the metion SetIntPoint(). + at the currently set IntegrationPoint. The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */ double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); } /** @brief Return the adjugate of the Jacobian matrix of the transformation - at the currently set IntegrationPoint, using the method SetIntPoint(). */ + at the currently set IntegrationPoint. */ const DenseMatrix &AdjugateJacobian() { return (EvalState & ADJUGATE_MASK) ? adjJ : EvalAdjugateJ(); } /** @brief Return the inverse of the Jacobian matrix of the transformation - at the currently set IntegrationPoint, using the method SetIntPoint(). */ + at the currently set IntegrationPoint. */ const DenseMatrix &InverseJacobian() { return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); } diff --git a/fem/fe.hpp b/fem/fe.hpp index 87f7ee0bc2..45bcfa9ebc 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -257,7 +257,7 @@ public: mapped to physical space. A reference function \f$ \hat u(\hat x) \f$ can be mapped to a function - \f$ u(x) \f$ on a general physical element in following where: + \f$ u(x) \f$ on a general physical element in following ways: - \f$ x = T(\hat x) \f$ is the image of the reference point \f$ \hat x \f$ - \f$ J = J(\hat x) \f$ is the Jacobian matrix of the transformation T - \f$ w = w(\hat x) = det(J) \f$ is the transformation weight factor for square J @@ -601,7 +601,7 @@ public: /** @brief Class for finite elements with basis functions - that take scalar values. */ + that return scalar values. */ class ScalarFiniteElement : public FiniteElement { protected: @@ -762,7 +762,7 @@ public: DenseMatrix &I) const; }; -/** @brief Intermediate class for finite elements whose basis functions take +/** @brief Intermediate class for finite elements whose basis functions return vector values. */ class VectorFiniteElement : public FiniteElement { diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 4880b6f38f..60c21de348 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1923,6 +1923,7 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const const FiniteElement *FiniteElementSpace::GetEdgeElement(int i) const { + MFEM_ASSERT(mesh->Dimension() > 1, "No edges with a mesh dimension < 2"); return fec->FiniteElementForGeometry(Geometry::SEGMENT); } diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 579ad8ab16..472ee0d8fc 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -462,11 +462,11 @@ public: /// Returns indexes of degrees of freedom for i'th boundary element. virtual void GetBdrElementDofs(int i, Array &dofs) const; - /** Returns the indexes of the degrees of freedom for i'th face + /** @brief eturns the indexes of the degrees of freedom for i'th face including the dofs for the edges and the vertices of the face. */ virtual void GetFaceDofs(int i, Array &dofs) const; - /** Returns the indexes of the degrees of freedom for i'th edge + /** @brief Returns the indexes of the degrees of freedom for i'th edge including the dofs for the vertices of the edge. */ void GetEdgeDofs(int i, Array &dofs) const; @@ -529,22 +529,28 @@ public: int GetElementForDof(int i) const { return dof_elem_array[i]; } int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; } - /// Returns pointer to the FiniteElement associated with i'th element. + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + associated with i'th element in the mesh object. */ const FiniteElement *GetFE(int i) const; - /// Returns pointer to the FiniteElement for the i'th boundary element. + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + associated with i'th boundary face in the mesh object. */ const FiniteElement *GetBE(int i) const; - /// Return pointer for an internal face between elements + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + associated with i'th face in the mesh object. Faces in this case refer + to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are + points.*/ const FiniteElement *GetFaceElement(int i) const; - /// Returns pointer for edge in 3D or face in 2D + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + associated with i'th edge in the mesh object. */ const FiniteElement *GetEdgeElement(int i) const; /// Return the trace element from element 'i' to the given 'geom_type' const FiniteElement *GetTraceElement(int i, Geometry::Type geom_type) const; - /** Mark degrees of freedom associated with boundary elements with + /** @brief Mark degrees of freedom associated with boundary elements with the specified boundary attributes (marked in 'bdr_attr_is_ess'). For spaces with 'vdim' > 1, the 'component' parameter can be used to restricts the marked vDOFs to the specified component. */ @@ -552,7 +558,7 @@ public: Array &ess_vdofs, int component = -1) const; - /** Get a list of essential true dofs, ess_tdof_list, corresponding to the + /** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the boundary attributes marked in the array bdr_attr_is_ess. For spaces with 'vdim' > 1, the 'component' parameter can be used to restricts the marked tDOFs to the specified component. */ @@ -563,19 +569,19 @@ public: /// Convert a Boolean marker array to a list containing all marked indices. static void MarkerToList(const Array &marker, Array &list); - /** Convert an array of indices (list) to a Boolean marker array where all + /** @brief Convert an array of indices (list) to a Boolean marker array where all indices in the list are marked with the given value and the rest are set to zero. */ static void ListToMarker(const Array &list, int marker_size, Array &marker, int mark_val = -1); - /** For a partially conforming FE space, convert a marker array (nonzero + /** @brief For a partially conforming FE space, convert a marker array (nonzero entries are true) on the partially conforming dofs to a marker array on the conforming dofs. A conforming dofs is marked iff at least one of its dependent dofs is marked. */ void ConvertToConformingVDofs(const Array &dofs, Array &cdofs); - /** For a partially conforming FE space, convert a marker array (nonzero + /** @brief For a partially conforming FE space, convert a marker array (nonzero entries are true) on the conforming dofs to a marker array on the (partially conforming) dofs. A dof is marked iff it depends on a marked conforming dofs, where dependency is defined by the ConformingRestriction @@ -583,15 +589,15 @@ public: conforming dof. */ void ConvertFromConformingVDofs(const Array &cdofs, Array &dofs); - /** Generate the global restriction matrix from a discontinuous + /** @brief Generate the global restriction matrix from a discontinuous FE space to the continuous FE space of the same polynomial degree. */ SparseMatrix *D2C_GlobalRestrictionMatrix(FiniteElementSpace *cfes); - /** Generate the global restriction matrix from a discontinuous + /** @brief Generate the global restriction matrix from a discontinuous FE space to the piecewise constant FE space. */ SparseMatrix *D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes); - /** Construct the restriction matrix from the FE space given by + /** @brief Construct the restriction matrix from the FE space given by (*this) to the lower degree FE space given by (*lfes) which is defined on the same mesh. */ SparseMatrix *H2L_GlobalRestrictionMatrix(FiniteElementSpace *lfes); @@ -628,7 +634,7 @@ public: virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes, OperatorHandle &T) const; - /** Reflect changes in the mesh: update number of DOFs, etc. Also, calculate + /** @brief Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation operator (unless want_transform is false). Safe to call multiple times, does nothing if space already up to date. */ virtual void Update(bool want_transform = true); diff --git a/fem/linearform.hpp b/fem/linearform.hpp index f2d050ff29..d12d173efb 100644 --- a/fem/linearform.hpp +++ b/fem/linearform.hpp @@ -19,7 +19,7 @@ namespace mfem { -/// Class for linear form - Vector with associated FE space and LFIntegrators. +///Vector with associated FE space and LinearFormIntegrator. class LinearForm : public Vector { protected: diff --git a/fem/nonlininteg.hpp b/fem/nonlininteg.hpp index b6973ade7a..655affe1e3 100644 --- a/fem/nonlininteg.hpp +++ b/fem/nonlininteg.hpp @@ -20,7 +20,7 @@ namespace mfem { -/** The abstract base class NonlinearFormIntegrator is used to express the +/** @brief This class is used to express the local action of a general nonlinear finite element operator. In addition it may provide the capability to assemble the local gradient operator and to compute the local energy. */ diff --git a/general/array.hpp b/general/array.hpp index c81d3ac5ab..c6dc6b0a28 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -271,7 +271,7 @@ public: inline void CopyFrom(const U *src) { std::memcpy(begin(), src, MemoryUsage()); } - /// STL-like begin. Returns poiner to the first element of the array. + /// STL-like begin. Returns pointer to the first element of the array. inline T* begin() { return data; } /// STL-like end. Returns pointer after the last element of the array. diff --git a/general/communication.hpp b/general/communication.hpp index 5aec850647..2d12100f29 100644 --- a/general/communication.hpp +++ b/general/communication.hpp @@ -413,7 +413,7 @@ struct VarMessage MPI_Get_count(&status, MPI_BYTE, &size); } - /** @briefNon-blocking probe for incoming message of this type from any rank. + /** @brief Non-blocking probe for incoming message of this type from any rank. If there is an incoming message, returns true and sets 'rank' and 'size'. Otherwise returns false. */ static bool IProbe(int &rank, int &size, MPI_Comm comm) From 39d89aa96124bea1787483827db016c7dd51f1df Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Thu, 30 Apr 2020 14:19:51 -0400 Subject: [PATCH 250/535] Adds RotationPUMItoMFEM to ParPumiMesh Also makes the default last argument in ParentXisPUMItoMFEM to be true. This is because there is always rotated tets (due to orientation fix at the boundary). --- mesh/pumi.cpp | 26 ++++++++++++++++++++++++++ mesh/pumi.hpp | 23 +++++++++++++++++------ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 077e95a737..be5bf2475d 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -947,6 +947,32 @@ void ParPumiMesh::UpdateMesh(const ParMesh* AdaptedpMesh) } } +int ParPumiMesh::RotationPUMItoMFEM(apf::Mesh2* apf_mesh, + apf::MeshEntity* tet, + int elemId) +{ + MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); + // get downward vertices of PUMI element + apf::Downward vs; + int nv = apf_mesh->getDownward(tet,0,vs); + int pumi_vid[nv]; + for (int i = 0; i < nv; i++) + pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); + + // get downward vertices of MFEM element + mfem::Array mfem_vid; + this->GetElementVertices(elemId, mfem_vid); + + // get rotated indices of PUMI element + int pumi_vid_rot[nv]; + for (int i = 0; i < nv; i++) + pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); + apf::Downward vs_rot; + for (int i = 0; i < nv; i++) + vs_rot[i] = vs[pumi_vid_rot[i]]; + + return ma::findTetRotation(apf_mesh, tet, vs_rot); +} // Convert parent coordinate form a PUMI tet to an MFEM tet IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 87f7c434ed..a19be12b32 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -78,17 +78,28 @@ public: ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, int refine = 1, bool fix_orientation = true); + + /// Returns the permutation (aka rotation, aka orientation) needed to + /// convert PUMI tet to an MFEM tet. This represents the change in + /// tet-to-vertex connectivity between the PUMI and MFEM meshes. + /// e.g.: + /// PUMI_tet{v0,v1,v2,v3} ---> MFEM_tet{v1,v0,v3,v2} + /// * Note that change in the orientation can be caused by + /// a) fixing wrong boundary element orientations + /// b) a call to ReorientTetMesh() which is required for Nedelec + int RotationPUMItoMFEM(apf::Mesh2* apf_mesh, + apf::MeshEntity* tet, + int elemId); /// Convert the parent coordinate from PUMI to MFEM - /// * By default this functions assumes that there is no change - /// in the orientations of elements. - /// * In case there is a change in the orientation (e.g., for - /// higher-order Nedelec shapes, call the functions with last - /// argument = true + /// * By default this functions assumes that there is always + /// change in the orientations of some of the elements. + /// * In case it is know for sure that there is NO change in + /// the orientation, call the functions with last argument = true IntegrationRule ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, apf::MeshEntity* tet, int elemId, apf::NewArray& pumi_xi, - bool checkOrientation = false); + bool checkOrientation = true); /// Transfer field from MFEM mesh to PUMI mesh [Mixed]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* Vel, From 341023cc34539f5c327bcc5f83632ae49f1783e1 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 11:22:35 -0700 Subject: [PATCH 251/535] Initial draft of GetGradient unit test --- tests/unit/fem/test_get_value.cpp | 308 ++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 6862fbfb1a..693b37d8e7 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -47,6 +47,19 @@ void Func_3D_lin(const Vector &x, Vector &v) v[2] = -2.572 * x[0] + 1.321 * x[1] + 3.234 * x[2]; } +double func_3D_quad(const Vector &x) +{ + return x[0] * x[1] + 2.0 * x[1] * x[2] + 3.0 * x[2] * x[0]; +} + +void dfunc_3D_quad(const Vector &x, Vector &v) +{ + v.SetSize(3); + v[0] = 1.0 * x[1] + 3.0 * x[2]; + v[1] = 2.0 * x[2] + 1.0 * x[0]; + v[2] = 3.0 * x[0] + 2.0 * x[1]; +} + TEST_CASE("1D GetValue", "[GridFunction]" "[GridFunctionCoefficient]") @@ -1984,4 +1997,299 @@ TEST_CASE("3D GetVectorValue", << npts << " 3D points" << std::endl; } +TEST_CASE("3D GetGradient", + "[GridFunction]" + "[GradientGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 3; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::WEDGE; type++) + { + Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + + FunctionCoefficient quadCoef(func_3D_quad); + + SECTION("3D GetGradient tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + + GradientGridFunctionCoefficient h1_xCoef(&h1_x); + GradientGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(quadCoef); + dgv_x.ProjectCoefficient(quadCoef); + + Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + + SECTION("Domain Evaluation 3D (H1 Context)") + { + std::cout << "Domain Evaluation 3D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_3D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + /* + SECTION("Boundary Evaluation 3D (H1 Context)") + { + std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + */ + /* + SECTION("Domain Evaluation 3D (DG Context)") + { + std::cout << "Domain Evaluation 3D (DG Context)" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + */ + /* + SECTION("Boundary Evaluation 3D (DG Context)") + { + std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[3]; + Vector tip(tip_data, 3); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << be << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + */ + } + } + std::cout << "Checked GridFunction::GetGradient at " + << npts << " 3D points" << std::endl; +} + } // namespace get_value From 83c406a0a87d22f04997fb0cd70002346258b20a Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 11:26:52 -0700 Subject: [PATCH 252/535] Removing redundant unit tests --- tests/unit/fem/test_get_value.cpp | 429 +----------------------------- 1 file changed, 12 insertions(+), 417 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 6862fbfb1a..ee224c9de9 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -90,9 +90,9 @@ TEST_CASE("1D GetValue", dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); - SECTION("Domain Evaluation 1D (H1 Context)") + SECTION("Domain Evaluation 1D") { - std::cout << "Domain Evaluation 1D (H1 Context)" << std::endl; + std::cout << "Domain Evaluation 1D" << std::endl; for (int e = 0; e < mesh.GetNE(); e++) { ElementTransformation *T = mesh.GetElementTransformation(e); @@ -213,67 +213,6 @@ TEST_CASE("1D GetValue", } } - SECTION("Domain Evaluation 1D (DG Context)") - { - std::cout << "Domain Evaluation 1D (DG Context)" << std::endl; - for (int e = 0; e < mesh.GetNE(); e++) - { - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[1]; - Vector tip(tip_data, 1); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_1D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) - << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - } SECTION("Boundary Evaluation 1D (DG Context)") { std::cout << "Boundary Evaluation 1D (DG Context)" << std::endl; @@ -385,9 +324,9 @@ TEST_CASE("2D GetValue", dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); - SECTION("Domain Evaluation 2D (H1 Context)") + SECTION("Domain Evaluation 2D") { - std::cout << "Domain Evaluation 2D (H1 Context)" << std::endl; + std::cout << "Domain Evaluation 2D" << std::endl; for (int e = 0; e < mesh.GetNE(); e++) { ElementTransformation *T = mesh.GetElementTransformation(e); @@ -508,67 +447,6 @@ TEST_CASE("2D GetValue", } } - SECTION("Domain Evaluation 2D (DG Context)") - { - std::cout << "Domain Evaluation 2D (DG Context)" << std::endl; - for (int e = 0; e < mesh.GetNE(); e++) - { - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[2]; - Vector tip(tip_data, 2); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_2D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) - << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - } SECTION("Boundary Evaluation 2D (DG Context)") { std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; @@ -680,9 +558,9 @@ TEST_CASE("3D GetValue", dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); - SECTION("Domain Evaluation 3D (H1 Context)") + SECTION("Domain Evaluation 3D") { - std::cout << "Domain Evaluation 3D (H1 Context)" << std::endl; + std::cout << "Domain Evaluation 3D" << std::endl; for (int e = 0; e < mesh.GetNE(); e++) { ElementTransformation *T = mesh.GetElementTransformation(e); @@ -803,67 +681,6 @@ TEST_CASE("3D GetValue", } } - SECTION("Domain Evaluation 3D (DG Context)") - { - std::cout << "Domain Evaluation 3D (DG Context)" << std::endl; - for (int e = 0; e < mesh.GetNE(); e++) - { - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) - << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - } SECTION("Boundary Evaluation 3D (DG Context)") { std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; @@ -999,9 +816,9 @@ TEST_CASE("2D GetVectorValue", Vector dgv_gf_val(2); dgv_gf_val = 0.0; Vector dgi_gf_val(2); dgi_gf_val = 0.0; - SECTION("Domain Evaluation 2D (H1 Context)") + SECTION("Domain Evaluation 2D") { - std::cout << "Domain Evaluation 2D (H1 Context)" << std::endl; + std::cout << "Domain Evaluation 2D" << std::endl; for (int e = 0; e < mesh.GetNE(); e++) { ElementTransformation *T = mesh.GetElementTransformation(e); @@ -1106,6 +923,7 @@ TEST_CASE("2D GetVectorValue", REQUIRE(dgi_err == Approx(0.0)); } } + SECTION("Boundary Evaluation 2D (H1 Context)") { std::cout << "Boundary Evaluation 2D (H1 Context)" << std::endl; @@ -1213,113 +1031,7 @@ TEST_CASE("2D GetVectorValue", REQUIRE(dgi_err == Approx(0.0)); } } - SECTION("Domain Evaluation 2D (DG Context)") - { - std::cout << "Domain Evaluation 2D (DG Context)" << std::endl; - for (int e = 0; e < mesh.GetNE(); e++) - { - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - double h1_err = 0.0; - double nd_err = 0.0; - double rt_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[2]; - Vector tip(tip_data, 2); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_2D_lin(tip, f_val); - - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); - - double h1_dist = Distance(f_val, h1_gf_val, 2); - double nd_dist = Distance(f_val, nd_gf_val, 2); - double rt_dist = Distance(f_val, rt_gf_val, 2); - double l2_dist = Distance(f_val, l2_gf_val, 2); - double dgv_dist = Distance(f_val, dgv_gf_val, 2); - double dgi_dist = Distance(f_val, dgi_gf_val, 2); - - h1_err += h1_dist; - nd_err += nd_dist; - rt_err += rt_dist; - l2_err += l2_dist; - dgv_err += dgv_dist; - dgi_err += dgi_dist; - - if (log > 0 && h1_dist > tol) - { - std::cout << e << ":" << j << " h1 (" - << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " - << h1_dist << std::endl; - } - if (log > 0 && nd_dist > tol) - { - std::cout << e << ":" << j << " nd (" - << f_val[0] << "," << f_val[1] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << ") " - << nd_dist << std::endl; - } - if (log > 0 && rt_dist > tol) - { - std::cout << e << ":" << j << " rt (" - << f_val[0] << "," << f_val[1] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << ") " - << rt_dist << std::endl; - } - if (log > 0 && l2_dist > tol) - { - std::cout << e << ":" << j << " l2 (" - << f_val[0] << "," << f_val[1] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << ") " - << l2_dist << std::endl; - } - if (log > 0 && dgv_dist > tol) - { - std::cout << e << ":" << j << " dgv (" - << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " - << dgv_dist << std::endl; - } - if (log > 0 && dgi_dist > tol) - { - std::cout << e << ":" << j << " dgi (" - << f_val[0] << "," << f_val[1] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " - << dgi_dist << std::endl; - } - } - h1_err /= ir.GetNPoints(); - nd_err /= ir.GetNPoints(); - rt_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( nd_err == Approx(0.0)); - REQUIRE( rt_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - } SECTION("Boundary Evaluation 2D (DG Context)") { std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; @@ -1501,9 +1213,9 @@ TEST_CASE("3D GetVectorValue", Vector dgv_gf_val(3); dgv_gf_val = 0.0; Vector dgi_gf_val(3); dgi_gf_val = 0.0; - SECTION("Domain Evaluation 3D (H1 Context)") + SECTION("Domain Evaluation 3D") { - std::cout << "Domain Evaluation 3D (H1 Context)" << std::endl; + std::cout << "Domain Evaluation 3D" << std::endl; for (int e = 0; e < mesh.GetNE(); e++) { ElementTransformation *T = mesh.GetElementTransformation(e); @@ -1620,6 +1332,7 @@ TEST_CASE("3D GetVectorValue", REQUIRE(dgi_err == Approx(0.0)); } } + SECTION("Boundary Evaluation 3D (H1 Context)") { std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; @@ -1739,125 +1452,7 @@ TEST_CASE("3D GetVectorValue", REQUIRE(dgi_err == Approx(0.0)); } } - SECTION("Domain Evaluation 3D (DG Context)") - { - std::cout << "Domain Evaluation 3D (DG Context)" << std::endl; - for (int e = 0; e < mesh.GetNE(); e++) - { - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - double h1_err = 0.0; - double nd_err = 0.0; - double rt_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); - - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); - - double h1_dist = Distance(f_val, h1_gf_val, 3); - double nd_dist = Distance(f_val, nd_gf_val, 3); - double rt_dist = Distance(f_val, rt_gf_val, 3); - double l2_dist = Distance(f_val, l2_gf_val, 3); - double dgv_dist = Distance(f_val, dgv_gf_val, 3); - double dgi_dist = Distance(f_val, dgi_gf_val, 3); - - h1_err += h1_dist; - nd_err += nd_dist; - rt_err += rt_dist; - l2_err += l2_dist; - dgv_err += dgv_dist; - dgi_err += dgi_dist; - - if (log > 0 && h1_dist > tol) - { - std::cout << e << ":" << j << " h1 (" - << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist - << std::endl; - } - if (log > 0 && nd_dist > tol) - { - std::cout << e << ":" << j << " nd (" - << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist - << std::endl; - } - if (log > 0 && rt_dist > tol) - { - std::cout << e << ":" << j << " rt (" - << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << "," - << rt_gf_val[2] << ") " << rt_dist - << std::endl; - } - if (log > 0 && l2_dist > tol) - { - std::cout << e << ":" << j << " l2 (" - << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << "," - << l2_gf_val[2] << ") " << l2_dist - << std::endl; - } - if (log > 0 && dgv_dist > tol) - { - std::cout << e << ":" << j << " dgv (" - << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist - << std::endl; - } - if (log > 0 && dgi_dist > tol) - { - std::cout << e << ":" << j << " dgi (" - << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," - << dgi_gf_val[2] << ") " << dgi_dist - << std::endl; - } - } - h1_err /= ir.GetNPoints(); - nd_err /= ir.GetNPoints(); - rt_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( nd_err == Approx(0.0)); - REQUIRE( rt_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - } SECTION("Boundary Evaluation 3D (DG Context)") { std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; From 37f64ec487871fba46c70d097bb3081a22d004cc Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Thu, 30 Apr 2020 14:56:58 -0400 Subject: [PATCH 253/535] Cleans the field transfer routines + bug fix This clean up is achieved by using getElementXis to get all the nodes associated with a given tet, as opposed to computing those using loops. Bug fix note: The previous code would ignore the fact that the tet-to-vertex connectivities could change when a PUMI mesh is converted to an MFEM mesh. This means that for some of tets a given parent xi coordinate would not be the same in the PUMI and MFEM meshes. Ignoring this can cause incorrect field transfers. This is fixed now, by explicitly checking the tet rotations and adjusting the xi coordinates accordingly. --- mesh/pumi.cpp | 608 +++++++------------------------------------------- 1 file changed, 75 insertions(+), 533 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index be5bf2475d..19ce6d8111 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -983,33 +983,7 @@ IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, { int num_nodes = pumi_xi.size(); IntegrationRule mfem_xi(num_nodes); - int rotation = 0; - - // if check orientation is on then find the rotation - if (checkOrientation) { - // by this point - MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); - // get downward vertices of PUMI element - apf::Downward vs; - int nv = apf_mesh->getDownward(tet,0,vs); - int pumi_vid[nv]; - for (int i = 0; i < nv; i++) - pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); - - // get downward vertices of MFEM element - mfem::Array mfem_vid; - this->GetElementVertices(elemId, mfem_vid); - - // get rotated indices of PUMI element - int pumi_vid_rot[nv]; - for (int i = 0; i < nv; i++) - pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); - apf::Downward vs_rot; - for (int i = 0; i < nv; i++) - vs_rot[i] = vs[pumi_vid_rot[i]]; - rotation = ma::findTetRotation(apf_mesh, tet, vs_rot); - } - + int rotation = checkOrientation ? RotationPUMItoMFEM(apf_mesh, tet, elemId):0; for(int i = 0; i < num_nodes; i++) { // for non zero "rotation", rotate the xi if (rotation) @@ -1031,156 +1005,43 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::Field* pr_field, apf::Field* vel_mag_field) { - int dim = apf_mesh->getDimension(); // dimension of mesh - int type = apf::Mesh::simplexTypes[dim]; // highest dim entity simplex type apf::FieldShape* field_shape = getShape(vel_field); - apf::EntityShape* es = field_shape->getEntityShape(type); - - IntegrationRule pumi_nodes; - getPumiNodeXis(field_shape, type, pumi_nodes); + int dim = apf_mesh->getDimension(); apf::MeshEntity* ent; apf::MeshIterator* itr = apf_mesh->begin(dim); int iel = 0; while ((ent = apf_mesh->iterate(itr))) { + apf::NewArray pumi_nodes; + apf::getElementNodeXis(field_shape, apf_mesh, ent, pumi_nodes); + IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( + apf_mesh, ent, iel, pumi_nodes, true); // Get the solution - Vector u_vel, v_vel, w_vel; - grid_vel->GetValues(iel, pumi_nodes, u_vel, 1); - grid_vel->GetValues(iel, pumi_nodes, v_vel, 2); - grid_vel->GetValues(iel, pumi_nodes, w_vel, 3); - + ElementTransformation* eltr = this->GetElementTransformation(iel); + DenseMatrix vel; + grid_vel->GetVectorValues(*eltr, mfem_nodes, vel); Vector pr; - grid_pr->GetValues(iel, pumi_nodes, pr, 1); + grid_pr->GetValues(iel, mfem_nodes, pr, 1); - int dof_id = 0; + int non = 0; for (int d = 0; d <= dim; d++) { - int d_type = apf::Mesh::simplexTypes[d]; - if (field_shape->hasNodesIn(d_type)) - { - int non = field_shape->countNodesOn(d_type); - Array order(non); - // initialize to 0 in case alignSharedNodes does not do anything - order = 0; - - apf::Downward down; - int nd = apf_mesh->getDownward(ent, d_type, down); - for (int ii = 0 ; ii < nd; ++ii) - { - es->alignSharedNodes(apf_mesh, ent, down[ii], order); - for (int jj = 0; jj < non; jj++) - { - int cnt = dof_id + order[jj]; - double mag = u_vel[cnt] * u_vel[cnt] + - v_vel[cnt] * v_vel[cnt] + - w_vel[cnt] * w_vel[cnt]; - mag = sqrt(mag); - apf::setScalar(vel_mag_field, down[ii], jj, mag); - - // Set vel - double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(vel_field, down[ii], jj, vels); - - // Set Pr - apf::setScalar(pr_field, down[ii], jj, pr[cnt]); - - } - // Counter - dof_id += non; + if (!field_shape->hasNodesIn(d)) continue; + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) { + int type = apf_mesh->getType(a[i]); + int nan = field_shape->countNodesOn(type); + for (int n = 0; n < nan; n++) { + apf::Vector3 v(vel.GetColumn(non)); + apf::setVector(vel_field, a[i], n, v); + apf::setScalar(pr_field, a[i], n, pr[non]); + apf::setScalar(vel_mag_field, a[i], n, v.getLength()); + non++; } } } - /* // Transfer */ - /* apf::Downward vtxs; */ - /* int num_vts = apf_mesh->getDownward(ent, 0, vtxs); */ - /* for (int kk = 0; kk < num_vts; kk++) */ - /* { */ - /* double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] + */ - /* w_vel[kk] * w_vel[kk]; */ - /* mag = sqrt(mag); */ - /* apf::setScalar(vel_mag_field, vtxs[kk], 0, mag); */ - /* // Set vel */ - /* double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]}; */ - /* apf::setComponents(vel_field, vtxs[kk], 0, vels); */ - - /* // Set Pr */ - /* apf::setScalar(pr_field, vtxs[kk], 0, pr[kk]); */ - /* } */ - - /* int dofId = num_vts; */ - - /* // Edge Dofs */ - /* if (field_shape->hasNodesIn(apf::Mesh::EDGE)) */ - /* { */ - /* int ndOnEdge = field_shape->countNodesOn(apf::Mesh::EDGE); */ - /* Array order(ndOnEdge); */ - - /* apf::Downward edges; */ - /* int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges); */ - /* for (int ii = 0 ; ii < num_edge; ++ii) */ - /* { */ - /* es->alignSharedNodes(apf_mesh, ent, edges[ii], order); */ - /* for (int jj = 0; jj < ndOnEdge; jj++) */ - /* { */ - /* int cnt = dofId + order[jj]; */ - /* double mag = u_vel[cnt] * u_vel[cnt] + */ - /* v_vel[cnt] * v_vel[cnt] + */ - /* w_vel[cnt] * w_vel[cnt]; */ - /* mag = sqrt(mag); */ - /* apf::setScalar(vel_mag_field, edges[ii], jj, mag); */ - - /* // Set vel */ - /* double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; */ - /* apf::setComponents(vel_field, edges[ii], jj, vels); */ - - /* // Set Pr */ - /* apf::setScalar(pr_field, edges[ii], jj, pr[cnt]); */ - - /* } */ - /* // Counter */ - /* dofId += ndOnEdge; */ - /* } */ - /* } */ - /* // Face Dofs */ - /* if (field_shape->hasNodesIn(apf::Mesh::TRIANGLE)) */ - /* { */ - /* int ndOnFace = field_shape->countNodesOn(apf::Mesh::TRIANGLE); */ - /* Array order(ndOnFace); */ - - /* apf::Downward faces; */ - /* int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces); */ - /* for (int ii = 0; ii < num_face; ii++) */ - /* { */ - /* if ( ndOnFace > 1) */ - /* { */ - /* es->alignSharedNodes(apf_mesh, ent, faces[ii], order); */ - /* } */ - /* else */ - /* { */ - /* order[0] = 0; */ - /* } */ - /* for (int jj = 0; jj < ndOnFace; jj++) */ - /* { */ - /* int cnt = dofId + order[jj]; */ - /* double mag = u_vel[cnt] * u_vel[cnt] + */ - /* v_vel[cnt] * v_vel[cnt] + */ - /* w_vel[cnt] * w_vel[cnt]; */ - /* mag = sqrt(mag); */ - /* apf::setScalar(vel_mag_field, faces[ii], jj, mag); */ - - /* // Set vel */ - /* double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; */ - /* apf::setComponents(vel_field, faces[ii], jj, vels); */ - - /* // Set Pr */ - /* apf::setScalar(pr_field, faces[ii], jj, pr[cnt]); */ - /* } */ - /* // Counter */ - /* dofId += ndOnFace; */ - /* } */ - /* } */ - - /* iel++; */ + iel++; } apf_mesh->end(itr); } @@ -1188,197 +1049,42 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, // Transfer a scalar field its magnitude to use for mesh adaptation. void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* grid_pr, - apf::Field* PrField, - apf::Field* PrMagField) + apf::Field* pr_field, + apf::Field* pr_mag_field) { - apf::FieldShape* PrFieldShape = getShape(PrField); - int num_nodes = 4 * PrFieldShape->countNodesOn(0) + // Vertex - 6 * PrFieldShape->countNodesOn(1) + // Edge - 4 * PrFieldShape->countNodesOn(2) + // Triangle - PrFieldShape->countNodesOn(4); // Tetrahedron + apf::FieldShape* field_shape = getShape(pr_field); + int dim = apf_mesh->getDimension(); - // Define integration points - IntegrationRule pumi_nodes(num_nodes); - int ip_cnt = 0; - apf::Vector3 xi_crd(0.,0.,0.); - - // Create a template of dof holders coordinates in parametric coordinates. - // The ordering is taken care of when the field is transferred to PUMI. - - // Dofs on Vertices - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - double pt_crd[3] = {0., 0., 0.}; - ip.Set(pt_crd, 3); - for (int kk = 0; kk < 3; kk++) - { - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - double pt_crd[3] = {0.,0.,0.}; - pt_crd[kk] = 1.0; - ip.Set(pt_crd, 3); - } - // Dofs on Edges - if (PrFieldShape->hasNodesIn(apf::Mesh::EDGE)) - { - const int nn = PrFieldShape->countNodesOn(apf::Mesh::EDGE); - for (int ii = 0; ii < 6; ii++) - { - for (int jj = 0; jj < nn; jj++) - { - PrFieldShape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd); - xi_crd[0] = 0.5 * (xi_crd[0] + 1.); // from (-1,1) to (0,1) - double pt_crd[3] = {0., 0., 0.}; - switch (ii) - { - case 0: - pt_crd[0] = xi_crd[0]; - break; - case 1: - pt_crd[0] = 1. - xi_crd[0]; - pt_crd[1] = xi_crd[0]; - break; - case 2: - pt_crd[1] = xi_crd[0]; - break; - case 3: - pt_crd[2] = xi_crd[0]; - break; - case 4: - pt_crd[0] = 1. - xi_crd[0]; - pt_crd[2] = xi_crd[0]; - break; - case 5: - pt_crd[1] = 1. - xi_crd[0]; - pt_crd[2] = xi_crd[0]; - break; - } - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - ip.Set(pt_crd, 3); - } - } - } - // Dofs on Faces - if (PrFieldShape->hasNodesIn(apf::Mesh::TRIANGLE)) - { - const int nn = PrFieldShape->countNodesOn(apf::Mesh::TRIANGLE); - for (int ii = 0; ii < 4; ii++) - { - for (int jj = 0; jj < nn; jj++) - { - PrFieldShape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd); - double pt_crd[3] = {0., 0., 0.}; - switch (ii) - { - case 0: - pt_crd[0] = xi_crd[0]; - pt_crd[1] = xi_crd[1]; - break; - case 1: - pt_crd[0] = xi_crd[0]; - pt_crd[2] = xi_crd[2]; - break; - case 2: - pt_crd[0] = xi_crd[0]; - pt_crd[1] = xi_crd[1]; - pt_crd[2] = xi_crd[2]; - break; - case 3: - pt_crd[1] = xi_crd[0]; - pt_crd[2] = xi_crd[1]; - break; - } - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - ip.Set(pt_crd, 3); - } - } - } - MFEM_ASSERT(ip_cnt == num_nodes, ""); - - // Other dofs apf::MeshEntity* ent; - apf::MeshIterator* itr = apf_mesh->begin(3); + apf::MeshIterator* itr = apf_mesh->begin(dim); int iel = 0; while ((ent = apf_mesh->iterate(itr))) { + apf::NewArray pumi_nodes; + apf::getElementNodeXis(field_shape, apf_mesh, ent, pumi_nodes); + IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( + apf_mesh, ent, iel, pumi_nodes, true); // Get the solution - Vector pr; - grid_pr->GetValues(iel, pumi_nodes, pr, 1); + Vector vals; + grid_pr->GetValues(iel, mfem_nodes, vals, 1); - // Transfer - apf::Downward vtxs; - int num_vts = apf_mesh->getDownward(ent, 0, vtxs); - for (int kk = 0; kk < num_vts; kk++) - { - double mag; - (pr[kk] >= 0. ? mag = pr[kk] : mag = -pr[kk]); - apf::setScalar(PrMagField, vtxs[kk], 0, mag); - - // Set Pr - apf::setScalar(PrField, vtxs[kk], 0, pr[kk]); + int non = 0; + for (int d = 0; d <= dim; d++) { + if (!field_shape->hasNodesIn(d)) continue; + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) { + int type = apf_mesh->getType(a[i]); + int nan = field_shape->countNodesOn(type); + for (int n = 0; n < nan; n++) { + double pr = vals[non]; + double pr_mag = pr >= 0 ? pr : -pr; + apf::setScalar(pr_field, a[i], n, pr); + apf::setScalar(pr_mag_field, a[i], n, pr_mag); + non++; + } + } } - - int dofId = num_vts; - - apf::EntityShape* es = PrFieldShape->getEntityShape(apf::Mesh::TET); - // Edge Dofs - if (PrFieldShape->hasNodesIn(apf::Mesh::EDGE)) - { - int ndOnEdge = PrFieldShape->countNodesOn(apf::Mesh::EDGE); - Array order(ndOnEdge); - - apf::Downward edges; - int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges); - for (int ii = 0 ; ii < num_edge; ++ii) - { - es->alignSharedNodes(apf_mesh, ent, edges[ii], order); - for (int jj = 0; jj < ndOnEdge; jj++) - { - int cnt = dofId + order[jj]; - double mag; - (pr[cnt] >= 0. ? mag = pr[cnt] : mag = -pr[cnt]); - apf::setScalar(PrMagField, edges[ii], jj, mag); - - // Set Pr - apf::setScalar(PrField, edges[ii], jj, pr[cnt]); - - } - // Counter - dofId += ndOnEdge; - } - } - - // Face Dofs - if (PrFieldShape->hasNodesIn(apf::Mesh::TRIANGLE)) - { - int ndOnFace = PrFieldShape->countNodesOn(apf::Mesh::TRIANGLE); - Array order(ndOnFace); - - apf::Downward faces; - int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces); - for (int ii = 0; ii < num_face; ii++) - { - if ( ndOnFace > 1) - { - es->alignSharedNodes(apf_mesh, ent, faces[ii], order); - } - else - { - order[0] = 0; - } - for (int jj = 0; jj < ndOnFace; jj++) - { - int cnt = dofId + order[jj]; - double mag; - (pr[cnt] >= 0. ? mag = pr[cnt] : mag = -pr[cnt]); - apf::setScalar(PrMagField, faces[ii], jj, mag); - - // Set Pr - apf::setScalar(PrField, faces[ii], jj, pr[cnt]); - } - // Counter - dofId += ndOnFace; - } - } - iel++; } apf_mesh->end(itr); @@ -1392,202 +1098,38 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::Field* vel_mag_field) { apf::FieldShape* field_shape = getShape(vel_field); + int dim = apf_mesh->getDimension(); - int num_nodes = 4 * field_shape->countNodesOn(0) + // Vertex - 6 * field_shape->countNodesOn(1) + // Edge - 4 * field_shape->countNodesOn(2) + // Triangle - field_shape->countNodesOn(4);// Tetrahedron - - // Define integration points - IntegrationRule pumi_nodes(num_nodes); - int ip_cnt = 0; - apf::Vector3 xi_crd(0.,0.,0.); - - // Create a template of dof holders coordinates in parametric coordinates. - // The ordering is taken care of when the field is transferred to PUMI. - - // Dofs on Vertices - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - double pt_crd[3] = {0., 0., 0.}; - ip.Set(pt_crd, 3); - for (int kk = 0; kk < 3; kk++) - { - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - double pt_crd[3] = {0.,0.,0.}; - pt_crd[kk] = 1.0; - ip.Set(pt_crd, 3); - } - // Dofs on Edges - if (field_shape->hasNodesIn(apf::Mesh::EDGE)) - { - const int nn = field_shape->countNodesOn(apf::Mesh::EDGE); - for (int ii = 0; ii < 6; ii++) - { - for (int jj = 0; jj < nn; jj++) - { - field_shape->getNodeXi(apf::Mesh::EDGE, jj, xi_crd); - xi_crd[0] = 0.5 * (xi_crd[0] + 1.); // from (-1,1) to (0,1) - double pt_crd[3] = {0., 0., 0.}; - switch (ii) - { - case 0: - pt_crd[0] = xi_crd[0]; - break; - case 1: - pt_crd[0] = 1. - xi_crd[0]; - pt_crd[1] = xi_crd[0]; - break; - case 2: - pt_crd[1] = xi_crd[0]; - break; - case 3: - pt_crd[2] = xi_crd[0]; - break; - case 4: - pt_crd[0] = 1. - xi_crd[0]; - pt_crd[2] = xi_crd[0]; - break; - case 5: - pt_crd[1] = 1. - xi_crd[0]; - pt_crd[2] = xi_crd[0]; - break; - } - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - ip.Set(pt_crd, 3); - } - } - } - // Dofs on Faces - if (field_shape->hasNodesIn(apf::Mesh::TRIANGLE)) - { - const int nn = field_shape->countNodesOn(apf::Mesh::TRIANGLE); - for (int ii = 0; ii < 4; ii++) - { - for (int jj = 0; jj < nn; jj++) - { - field_shape->getNodeXi(apf::Mesh::TRIANGLE, jj, xi_crd); - double pt_crd[3] = {0., 0., 0.}; - switch (ii) - { - case 0: - pt_crd[0] = xi_crd[0]; - pt_crd[1] = xi_crd[1]; - break; - case 1: - pt_crd[0] = xi_crd[0]; - pt_crd[2] = xi_crd[2]; - break; - case 2: - pt_crd[0] = xi_crd[0]; - pt_crd[1] = xi_crd[1]; - pt_crd[2] = xi_crd[2]; - break; - case 3: - pt_crd[1] = xi_crd[0]; - pt_crd[2] = xi_crd[1]; - break; - } - IntegrationPoint& ip = pumi_nodes.IntPoint(ip_cnt++); - ip.Set(pt_crd, 3); - } - } - } - MFEM_ASSERT(ip_cnt == num_nodes, ""); - - // Other dofs apf::MeshEntity* ent; - apf::MeshIterator* itr = apf_mesh->begin(3); + apf::MeshIterator* itr = apf_mesh->begin(dim); int iel = 0; while ((ent = apf_mesh->iterate(itr))) { + apf::NewArray pumi_nodes; + apf::getElementNodeXis(field_shape, apf_mesh, ent, pumi_nodes); + IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( + apf_mesh, ent, iel, pumi_nodes, true); // Get the solution - Vector u_vel, v_vel, w_vel; - grid_vel->GetValues(iel, pumi_nodes, u_vel, 1); - grid_vel->GetValues(iel, pumi_nodes, v_vel, 2); - grid_vel->GetValues(iel, pumi_nodes, w_vel, 3); + ElementTransformation* eltr = this->GetElementTransformation(iel); + DenseMatrix vel; + grid_vel->GetVectorValues(*eltr, mfem_nodes, vel); - // Transfer - apf::Downward vtxs; - int num_vts = apf_mesh->getDownward(ent, 0, vtxs); - for (int kk = 0; kk < num_vts; kk++) - { - double mag = u_vel[kk] * u_vel[kk] + v_vel[kk] * v_vel[kk] + - w_vel[kk] * w_vel[kk]; - mag = sqrt(mag); - apf::setScalar(vel_mag_field, vtxs[kk], 0, mag); - // Set vel - double vels[3] = {u_vel[kk], v_vel[kk], w_vel[kk]}; - apf::setComponents(vel_field, vtxs[kk], 0, vels); + int non = 0; + for (int d = 0; d <= dim; d++) { + if (!field_shape->hasNodesIn(d)) continue; + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) { + int type = apf_mesh->getType(a[i]); + int nan = field_shape->countNodesOn(type); + for (int n = 0; n < nan; n++) { + apf::Vector3 v(vel.GetColumn(non)); + apf::setScalar(vel_mag_field, a[i], n, v.getLength()); + apf::setVector(vel_field, a[i], n, v); + non++; + } + } } - - int dofId = num_vts; - - apf::EntityShape* es = field_shape->getEntityShape(apf::Mesh::TET); - // Edge Dofs - if (field_shape->hasNodesIn(apf::Mesh::EDGE)) - { - int ndOnEdge = field_shape->countNodesOn(apf::Mesh::EDGE); - Array order(ndOnEdge); - - apf::Downward edges; - int num_edge = apf_mesh->getDownward(ent, apf::Mesh::EDGE, edges); - for (int ii = 0 ; ii < num_edge; ++ii) - { - es->alignSharedNodes(apf_mesh, ent, edges[ii], order); - for (int jj = 0; jj < ndOnEdge; jj++) - { - int cnt = dofId + order[jj]; - double mag = u_vel[cnt] * u_vel[cnt] + - v_vel[cnt] * v_vel[cnt] + - w_vel[cnt] * w_vel[cnt]; - mag = sqrt(mag); - apf::setScalar(vel_mag_field, edges[ii], jj, mag); - - // Set vel - double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(vel_field, edges[ii], jj, vels); - } - // Counter - dofId += ndOnEdge; - } - } - - // Face Dofs - if (field_shape->hasNodesIn(apf::Mesh::TRIANGLE)) - { - int ndOnFace = field_shape->countNodesOn(apf::Mesh::TRIANGLE); - Array order(ndOnFace); - - apf::Downward faces; - int num_face = apf_mesh->getDownward(ent, apf::Mesh::TRIANGLE, faces); - for (int ii = 0; ii < num_face; ii++) - { - if ( ndOnFace > 1) - { - es->alignSharedNodes(apf_mesh, ent, faces[ii], order); - } - else - { - order[0] = 0; - } - for (int jj = 0; jj < ndOnFace; jj++) - { - int cnt = dofId + order[jj]; - double mag = u_vel[cnt] * u_vel[cnt] + - v_vel[cnt] * v_vel[cnt] + - w_vel[cnt] * w_vel[cnt]; - mag = sqrt(mag); - apf::setScalar(vel_mag_field, faces[ii], jj, mag); - - // Set vel - double vels[3] = {u_vel[cnt], v_vel[cnt], w_vel[cnt]}; - apf::setComponents(vel_field, faces[ii], jj, vels); - } - // Counter - dofId += ndOnFace; - } - } - iel++; } apf_mesh->end(itr); From ac033e440655fae6eed0a20a617815c916a808fb Mon Sep 17 00:00:00 2001 From: Tucker Babcock Date: Thu, 30 Apr 2020 15:44:14 -0400 Subject: [PATCH 254/535] added PA support to ParBilinearForm::TrueAddMult --- fem/pbilinearform.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fem/pbilinearform.cpp b/fem/pbilinearform.cpp index 88bf107fa3..386c1bb930 100644 --- a/fem/pbilinearform.cpp +++ b/fem/pbilinearform.cpp @@ -283,7 +283,14 @@ const } X.Distribute(&x); - mat->Mult(X, Y); + if (ext) + { + ext->Mult(X, Y); + } + else + { + mat->Mult(X, Y); + } pfes->Dof_TrueDof_Matrix()->MultTranspose(a, Y, 1.0, y); } From 8b183d8f1b199c25842143de85a7bedb89b98f80 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 15:05:58 -0700 Subject: [PATCH 255/535] Adding `GetGradient` unit tests --- tests/unit/fem/test_get_value.cpp | 627 ++++++++++++++++++++++++------ 1 file changed, 506 insertions(+), 121 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 722590a176..fa315cf012 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -47,6 +47,29 @@ void Func_3D_lin(const Vector &x, Vector &v) v[2] = -2.572 * x[0] + 1.321 * x[1] + 3.234 * x[2]; } +double func_1D_quad(const Vector &x) +{ + return 2.0 * x[0] + x[0] * x[0]; +} + +void dfunc_1D_quad(const Vector &x, Vector &v) +{ + v.SetSize(1); + v[0] = 2.0 + 2.0 * x[0]; +} + +double func_2D_quad(const Vector &x) +{ + return x[0] * x[0] + 2.0 * x[1] * x[1] + 3.0 * x[0] * x[1]; +} + +void dfunc_2D_quad(const Vector &x, Vector &v) +{ + v.SetSize(2); + v[0] = 2.0 * x[0] + 3.0 * x[1]; + v[1] = 4.0 * x[1] + 3.0 * x[0]; +} + double func_3D_quad(const Vector &x) { return x[0] * x[1] + 2.0 * x[1] * x[2] + 3.0 * x[2] * x[0]; @@ -1592,6 +1615,436 @@ TEST_CASE("3D GetVectorValue", << npts << " 3D points" << std::endl; } +TEST_CASE("1D GetGradient", + "[GridFunction]" + "[GradientGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 1; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::SEGMENT; + type <= (int)Element::SEGMENT; type++) + { + Mesh mesh(n, 2.0); + + FunctionCoefficient quadCoef(func_1D_quad); + + SECTION("1D GetGradient tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + + GradientGridFunctionCoefficient h1_xCoef(&h1_x); + GradientGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(quadCoef); + dgv_x.ProjectCoefficient(quadCoef); + + Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + + SECTION("Domain Evaluation 1D") + { + std::cout << "Domain Evaluation 1D" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_1D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << ") vs. (" + << h1_gf_val[0] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << ") vs. (" + << dgv_gf_val[0] << ") " + << dgv_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 1D (H1 Context)") + { + std::cout << "Boundary Evaluation 1D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_1D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << ") vs. (" + << h1_gf_val[0] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << ") vs. (" + << dgv_gf_val[0] << ") " + << dgv_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 1D (DG Context)") + { + std::cout << "Boundary Evaluation 1D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_1D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << ") vs. (" + << h1_gf_val[0] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << ") vs. (" + << dgv_gf_val[0] << ") " + << dgv_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetGradient at " + << npts << " 1D points" << std::endl; +} + +TEST_CASE("2D GetGradient", + "[GridFunction]" + "[GradientGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 2; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + + FunctionCoefficient quadCoef(func_2D_quad); + + SECTION("2D GetGradient tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec); + + GridFunction h1_x(&h1_fespace); + GridFunction dgv_x(&dgv_fespace); + + GradientGridFunctionCoefficient h1_xCoef(&h1_x); + GradientGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(quadCoef); + dgv_x.ProjectCoefficient(quadCoef); + + Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + + SECTION("Domain Evaluation 2D") + { + std::cout << "Domain Evaluation 2D" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_2D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (H1 Context)") + { + std::cout << "Boundary Evaluation 2D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_2D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (DG Context)") + { + std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + dfunc_2D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetGradient at " + << npts << " 2D points" << std::endl; +} + TEST_CASE("3D GetGradient", "[GridFunction]" "[GradientGridFunctionCoefficient]") @@ -1633,9 +2086,9 @@ TEST_CASE("3D GetGradient", Vector h1_gf_val(dim); h1_gf_val = 0.0; Vector dgv_gf_val(dim); dgv_gf_val = 0.0; - SECTION("Domain Evaluation 3D (H1 Context)") + SECTION("Domain Evaluation 3D") { - std::cout << "Domain Evaluation 3D (H1 Context)" << std::endl; + std::cout << "Domain Evaluation 3D" << std::endl; for (int e = 0; e < mesh.GetNE(); e++) { ElementTransformation *T = mesh.GetElementTransformation(e); @@ -1663,16 +2116,16 @@ TEST_CASE("3D GetGradient", double h1_dist = Distance(f_val, h1_gf_val, dim); double dgv_dist = Distance(f_val, dgv_gf_val, dim); - h1_err += h1_dist; + h1_err += h1_dist; dgv_err += dgv_dist; if (log > 0 && h1_dist > tol) { std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," - << f_val[2] << ") vs. (" + << f_val[2] << ") vs. (" << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " + << h1_gf_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -1692,7 +2145,7 @@ TEST_CASE("3D GetGradient", REQUIRE(dgv_err == Approx(0.0)); } } - /* + SECTION("Boundary Evaluation 3D (H1 Context)") { std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; @@ -1705,10 +2158,9 @@ TEST_CASE("3D GetGradient", double h1_err = 0.0; double dgv_err = 0.0; - double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); + double tip_data[dim]; + Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); T->Transform(ip, tip); - double f_val = func_3D_lin(tip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + dfunc_3D_quad(tip, f_val); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) { - std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) - << std::endl; + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " + << h1_dist << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && dgv_dist > tol) { - std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist << std::endl; } } h1_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); REQUIRE(h1_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); } } - */ - /* - SECTION("Domain Evaluation 3D (DG Context)") - { - std::cout << "Domain Evaluation 3D (DG Context)" << std::endl; - for (int e = 0; e < mesh.GetNE(); e++) - { - ElementTransformation *T = mesh.GetElementTransformation(e); - const FiniteElement *fe = dgv_fespace.GetFE(e); - const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), - 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; - - double tip_data[3]; - Vector tip(tip_data, 3); - for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); - - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); - - if (log > 0 && fabs(f_val - h1_gf_val) > tol) - { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) - { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) - << std::endl; - } - } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); - } - } - */ - /* SECTION("Boundary Evaluation 3D (DG Context)") { std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; @@ -1830,10 +2218,9 @@ TEST_CASE("3D GetGradient", double h1_err = 0.0; double dgv_err = 0.0; - double dgi_err = 0.0; - double tip_data[3]; - Vector tip(tip_data, 3); + double tip_data[dim]; + Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + dfunc_3D_quad(tip, f_val); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + h1_xCoef.Eval(h1_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_dist = Distance(f_val, h1_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + h1_err += h1_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) { - std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) - << std::endl; + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " + << h1_dist << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && dgv_dist > tol) { - std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) - << std::endl; - } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) - { - std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist << std::endl; } } h1_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); REQUIRE(h1_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); } } - */ } } std::cout << "Checked GridFunction::GetGradient at " From 1e8cf0ff3f405d01300f0921e90ea0fdbfb765aa Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 15:06:46 -0700 Subject: [PATCH 256/535] Replacing explicit integers with `dim` where appropriate in `GetValue` unit tests --- tests/unit/fem/test_get_value.cpp | 142 +++++++++++++++--------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index fa315cf012..e091cb3875 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -77,12 +77,12 @@ double func_3D_quad(const Vector &x) void dfunc_3D_quad(const Vector &x, Vector &v) { - v.SetSize(3); - v[0] = 1.0 * x[1] + 3.0 * x[2]; - v[1] = 2.0 * x[2] + 1.0 * x[0]; - v[2] = 3.0 * x[0] + 2.0 * x[1]; + v.SetSize(3); + v[0] = 1.0 * x[1] + 3.0 * x[2]; + v[1] = 2.0 * x[2] + 1.0 * x[0]; + v[2] = 3.0 * x[0] + 2.0 * x[1]; } - + TEST_CASE("1D GetValue", "[GridFunction]" "[GridFunctionCoefficient]") @@ -140,8 +140,8 @@ TEST_CASE("1D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[1]; - Vector tip(tip_data, 1); + double tip_data[dim]; + Vector tip(tip_data, dim); for (int j=0; j Date: Thu, 30 Apr 2020 16:36:52 -0700 Subject: [PATCH 257/535] Option to use gslib or advection. --- miniapps/meshing/pmesh-optimizer.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index f4d7144911..dbbbc20603 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -// Adaptive limiting through FD: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -fd +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -ae 0 +// Adaptive limiting through FD (required GSLIB): +// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: @@ -285,6 +285,7 @@ int main (int argc, char *argv[]) bool visualization = true; int verbosity_level = 0; bool fdscheme = false; + int adapt_eval = 0; bool adapt_lim = false; // 2. Parse command-line options. @@ -363,6 +364,8 @@ int main (int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); + args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluatior", + "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) { @@ -599,13 +602,13 @@ int main (int argc, char *argv[]) // Adaptive limiting. ParGridFunction zeta_0(&ind_fes), zeta(&ind_fes); - ConstantCoefficient coeff_zeta(10.0); + ConstantCoefficient coef_zeta(10.0); if (adapt_lim) { FunctionCoefficient alim_coeff(adapt_lim_fun); zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); - he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coeff_zeta, 1); + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, adapt_eval); socketstream vis1; common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", 300, 600, 300, 300); From 29f9e6cb90f7a10fb9d71e6b787496ae88c2ce8b Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 30 Apr 2020 17:10:23 -0700 Subject: [PATCH 258/535] Moved together all integration rule initializations. --- fem/tmop.cpp | 49 ++++++---------------------- fem/tmop.hpp | 16 +++++++++ miniapps/meshing/pmesh-optimizer.cpp | 4 +-- 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 3d6089d5d4..9d35e292d9 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1279,11 +1279,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, Jpt.SetSize(dim); PMatI.UseExternalData(elfun.GetData(), dof, dim); - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- - } + const IntegrationRule *ir = EnergyIntegrationRule(el); energy = 0.0; DenseTensor Jtr(dim, dim, ir->GetNPoints()); @@ -1418,11 +1414,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el, elvect.SetSize(dof*dim); PMatO.UseExternalData(elvect.GetData(), dof, dim); - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- - } + const IntegrationRule *ir = ActionIntegrationRule(el); const int nqp = ir->GetNPoints(); elvect = 0.0; @@ -1516,11 +1508,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, PMatI.UseExternalData(elfun.GetData(), dof, dim); elmat.SetSize(dof*dim); - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- - } + const IntegrationRule *ir = GradientIntegrationRule(el); const int nqp = ir->GetNPoints(); elmat = 0.0; @@ -1771,11 +1759,7 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, // Contributions from adaptive limiting. if (zeta) { - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- - } + const IntegrationRule *ir = ActionIntegrationRule(el); const int nqp = ir->GetNPoints(); DenseTensor Jtr(dim, dim, nqp); targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr); @@ -1868,11 +1852,7 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, // Contributions from adaptive limiting. if (zeta) { - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <--- - } + const IntegrationRule *ir = GradientIntegrationRule(el); const int nqp = ir->GetNPoints(); DenseTensor Jtr(dim, dim, nqp); targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr); @@ -1928,12 +1908,7 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x, Jpr.SetSize(dim); Jpt.SetSize(dim); - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(fe->GetGeomType(), 2*fe->GetOrder() + 3)); // <--- - } - + const IntegrationRule *ir = EnergyIntegrationRule(*fe); DenseTensor Jtr(dim, dim, ir->GetNPoints()); metric_energy = 0.0; @@ -1967,14 +1942,10 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x, void TMOP_Integrator::ComputeMinJac(const Vector &x, const FiniteElementSpace &fes) { - const IntegrationRule *ir = IntRule; - if (!ir) - { - ir = &(IntRules.Get(fes.GetFE(0)->GetGeomType(), - 2*fes.GetFE(0)->GetOrder() + 3)); // <--- - } - const int NE = fes.GetMesh()->GetNE(), dim = fes.GetFE(0)->GetDim(), - dof = fes.GetFE(0)->GetDof(), nsp = ir->GetNPoints(); + const FiniteElement *fe = fes.GetFE(0); + const IntegrationRule *ir = EnergyIntegrationRule(*fe); + const int NE = fes.GetMesh()->GetNE(), dim = fe->GetDim(), + dof = fe->GetDof(), nsp = ir->GetNPoints(); Array xdofs(dof * dim); DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim); diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 75f3134f39..3e70ae8358 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -902,6 +902,22 @@ protected: nodes0 = NULL; coeff0 = NULL; lim_dist = NULL; lim_func = NULL; } + const IntegrationRule *EnergyIntegrationRule(const FiniteElement &el) const + { + return (IntRule) ? IntRule + /* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); + } + const IntegrationRule *ActionIntegrationRule(const FiniteElement &el) const + { + // TODO the energy most likely needs less integration points. + return EnergyIntegrationRule(el); + } + const IntegrationRule *GradientIntegrationRule(const FiniteElement &el) const + { + // TODO the action and energy most likely need less integration points. + return EnergyIntegrationRule(el); + } + public: /** @param[in] m TMOP_QualityMetric that will be integrated (not owned). @param[in] tc Target-matrix construction algorithm to use (not owned). */ diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index dbbbc20603..6d63dccff1 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -ae 0 +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -nor -vl 1 -al -ae 0 // Adaptive limiting through FD (required GSLIB): -// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -vl 1 -al -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -nor -vl 1 -al -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: From 4b76903cf10afed3a67215107f21029d7571c047 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 21:00:24 -0700 Subject: [PATCH 259/535] Correcting dimension of 2D CurlGridFunctionCoefficient --- fem/coefficient.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 1cea8b7967..4734b7d7dd 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -212,15 +212,16 @@ void GradientGridFunctionCoefficient::Eval( CurlGridFunctionCoefficient::CurlGridFunctionCoefficient ( const GridFunction *gf) : VectorCoefficient ((gf) ? - gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0) + (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() + - 3) : 0) { GridFunc = gf; } void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) { - GridFunc = gf; vdim = (gf) ? - gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0; + GridFunc = gf; + vdim = (gf) ? (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() - 3) : 0; } void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, From beed1277640f103ed43c07427bed8d49508fb86c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 30 Apr 2020 21:01:00 -0700 Subject: [PATCH 260/535] Adding unit tests for GetCurl and GetDivergence in 2D and 3D --- tests/unit/fem/test_get_value.cpp | 1145 +++++++++++++++++++++++++++-- 1 file changed, 1096 insertions(+), 49 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index e091cb3875..f0c1816633 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -70,6 +70,24 @@ void dfunc_2D_quad(const Vector &x, Vector &v) v[1] = 4.0 * x[1] + 3.0 * x[0]; } +void Func_2D_quad(const Vector &x, Vector &v) +{ + v.SetSize(2); + v[0] = 1.0 * x[0] * x[0] + 2.0 * x[1] * x[1] + 3.0 * x[0] * x[1]; + v[1] = 2.0 * x[1] * x[1] + 3.0 * x[0] * x[0] + 1.0 * x[0] * x[1]; +} + +void RotFunc_2D_quad(const Vector &x, Vector &v) +{ + v.SetSize(1); + v[0] = 6.0 * x[0] + 1.0 * x[1] - 4.0 * x[1] - 3.0 * x[0]; +} + +double DivFunc_2D_quad(const Vector &x) +{ + return 3.0 * x[0] + 7.0 * x[1]; +} + double func_3D_quad(const Vector &x) { return x[0] * x[1] + 2.0 * x[1] * x[2] + 3.0 * x[2] * x[0]; @@ -83,6 +101,27 @@ void dfunc_3D_quad(const Vector &x, Vector &v) v[2] = 3.0 * x[0] + 2.0 * x[1]; } +void Func_3D_quad(const Vector &x, Vector &v) +{ + v.SetSize(3); + v[0] = 1.0 * x[0] * x[1] + 2.0 * x[1] * x[2] + 3.0 * x[2] * x[0]; + v[1] = 2.0 * x[1] * x[2] + 3.0 * x[2] * x[0] + 1.0 * x[0] * x[1]; + v[2] = 3.0 * x[2] * x[0] + 1.0 * x[0] * x[1] + 2.0 * x[1] * x[2]; +} + +void CurlFunc_3D_quad(const Vector &x, Vector &v) +{ + v.SetSize(3); + v[0] = 1.0 * x[0] + 2.0 * x[2] - 2.0 * x[1] - 3.0 * x[0]; + v[1] = 2.0 * x[1] + 3.0 * x[0] - 3.0 * x[2] - 1.0 * x[1]; + v[2] = 3.0 * x[2] + 1.0 * x[1] - 1.0 * x[0] - 2.0 * x[2]; +} + +double DivFunc_3D_quad(const Vector &x) +{ + return 4.0 * x[0] + 3.0 * x[1] + 5.0 * x[2]; +} + TEST_CASE("1D GetValue", "[GridFunction]" "[GridFunctionCoefficient]") @@ -100,7 +139,7 @@ TEST_CASE("1D GetValue", { Mesh mesh(n, 2.0); - FunctionCoefficient linCoef(func_1D_lin); + FunctionCoefficient funcCoef(func_1D_lin); SECTION("1D GetValue tests for element type " + std::to_string(type)) { @@ -122,9 +161,9 @@ TEST_CASE("1D GetValue", GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); - h1_x.ProjectCoefficient(linCoef); - dgv_x.ProjectCoefficient(linCoef); - dgi_x.ProjectCoefficient(linCoef); + h1_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + dgi_x.ProjectCoefficient(funcCoef); SECTION("Domain Evaluation 1D") { @@ -334,7 +373,7 @@ TEST_CASE("2D GetValue", { Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); - FunctionCoefficient linCoef(func_2D_lin); + FunctionCoefficient funcCoef(func_2D_lin); SECTION("2D GetValue tests for element type " + std::to_string(type)) { @@ -356,9 +395,9 @@ TEST_CASE("2D GetValue", GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); - h1_x.ProjectCoefficient(linCoef); - dgv_x.ProjectCoefficient(linCoef); - dgi_x.ProjectCoefficient(linCoef); + h1_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + dgi_x.ProjectCoefficient(funcCoef); SECTION("Domain Evaluation 2D") { @@ -568,7 +607,7 @@ TEST_CASE("3D GetValue", { Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); - FunctionCoefficient linCoef(func_3D_lin); + FunctionCoefficient funcCoef(func_3D_lin); SECTION("3D GetValue tests for element type " + std::to_string(type)) { @@ -590,9 +629,9 @@ TEST_CASE("3D GetValue", GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); - h1_x.ProjectCoefficient(linCoef); - dgv_x.ProjectCoefficient(linCoef); - dgi_x.ProjectCoefficient(linCoef); + h1_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + dgi_x.ProjectCoefficient(funcCoef); SECTION("Domain Evaluation 3D") { @@ -802,7 +841,7 @@ TEST_CASE("2D GetVectorValue", { Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); - VectorFunctionCoefficient linCoef(2, Func_2D_lin); + VectorFunctionCoefficient funcCoef(2, Func_2D_lin); SECTION("2D GetVectorValue tests for element type " + std::to_string(type)) @@ -837,20 +876,20 @@ TEST_CASE("2D GetVectorValue", VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); - h1_x.ProjectCoefficient(linCoef); - nd_x.ProjectCoefficient(linCoef); - rt_x.ProjectCoefficient(linCoef); - l2_x.ProjectCoefficient(linCoef); - dgv_x.ProjectCoefficient(linCoef); - dgi_x.ProjectCoefficient(linCoef); + h1_x.ProjectCoefficient(funcCoef); + nd_x.ProjectCoefficient(funcCoef); + rt_x.ProjectCoefficient(funcCoef); + l2_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + dgi_x.ProjectCoefficient(funcCoef); - Vector f_val(2); f_val = 0.0; - Vector h1_gf_val(2); h1_gf_val = 0.0; - Vector nd_gf_val(2); nd_gf_val = 0.0; - Vector rt_gf_val(2); rt_gf_val = 0.0; - Vector l2_gf_val(2); l2_gf_val = 0.0; - Vector dgv_gf_val(2); dgv_gf_val = 0.0; - Vector dgi_gf_val(2); dgi_gf_val = 0.0; + Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector nd_gf_val(dim); nd_gf_val = 0.0; + Vector rt_gf_val(dim); rt_gf_val = 0.0; + Vector l2_gf_val(dim); l2_gf_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector dgi_gf_val(dim); dgi_gf_val = 0.0; SECTION("Domain Evaluation 2D") { @@ -1199,7 +1238,7 @@ TEST_CASE("3D GetVectorValue", { Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); - VectorFunctionCoefficient linCoef(3, Func_3D_lin); + VectorFunctionCoefficient funcCoef(3, Func_3D_lin); SECTION("3D GetVectorValue tests for element type " + std::to_string(type)) @@ -1234,20 +1273,20 @@ TEST_CASE("3D GetVectorValue", VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); - h1_x.ProjectCoefficient(linCoef); - nd_x.ProjectCoefficient(linCoef); - rt_x.ProjectCoefficient(linCoef); - l2_x.ProjectCoefficient(linCoef); - dgv_x.ProjectCoefficient(linCoef); - dgi_x.ProjectCoefficient(linCoef); + h1_x.ProjectCoefficient(funcCoef); + nd_x.ProjectCoefficient(funcCoef); + rt_x.ProjectCoefficient(funcCoef); + l2_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + dgi_x.ProjectCoefficient(funcCoef); - Vector f_val(3); f_val = 0.0; - Vector h1_gf_val(3); h1_gf_val = 0.0; - Vector nd_gf_val(3); nd_gf_val = 0.0; - Vector rt_gf_val(3); rt_gf_val = 0.0; - Vector l2_gf_val(3); l2_gf_val = 0.0; - Vector dgv_gf_val(3); dgv_gf_val = 0.0; - Vector dgi_gf_val(3); dgi_gf_val = 0.0; + Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector nd_gf_val(dim); nd_gf_val = 0.0; + Vector rt_gf_val(dim); rt_gf_val = 0.0; + Vector l2_gf_val(dim); l2_gf_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector dgi_gf_val(dim); dgi_gf_val = 0.0; SECTION("Domain Evaluation 3D") { @@ -1632,7 +1671,7 @@ TEST_CASE("1D GetGradient", { Mesh mesh(n, 2.0); - FunctionCoefficient quadCoef(func_1D_quad); + FunctionCoefficient funcCoef(func_1D_quad); SECTION("1D GetGradient tests for element type " + std::to_string(type)) { @@ -1649,8 +1688,8 @@ TEST_CASE("1D GetGradient", GradientGridFunctionCoefficient h1_xCoef(&h1_x); GradientGridFunctionCoefficient dgv_xCoef(&dgv_x); - h1_x.ProjectCoefficient(quadCoef); - dgv_x.ProjectCoefficient(quadCoef); + h1_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; Vector h1_gf_val(dim); h1_gf_val = 0.0; @@ -1847,7 +1886,7 @@ TEST_CASE("2D GetGradient", { Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); - FunctionCoefficient quadCoef(func_2D_quad); + FunctionCoefficient funcCoef(func_2D_quad); SECTION("2D GetGradient tests for element type " + std::to_string(type)) { @@ -1864,8 +1903,8 @@ TEST_CASE("2D GetGradient", GradientGridFunctionCoefficient h1_xCoef(&h1_x); GradientGridFunctionCoefficient dgv_xCoef(&dgv_x); - h1_x.ProjectCoefficient(quadCoef); - dgv_x.ProjectCoefficient(quadCoef); + h1_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; Vector h1_gf_val(dim); h1_gf_val = 0.0; @@ -2062,7 +2101,7 @@ TEST_CASE("3D GetGradient", { Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); - FunctionCoefficient quadCoef(func_3D_quad); + FunctionCoefficient funcCoef(func_3D_quad); SECTION("3D GetGradient tests for element type " + std::to_string(type)) { @@ -2079,8 +2118,8 @@ TEST_CASE("3D GetGradient", GradientGridFunctionCoefficient h1_xCoef(&h1_x); GradientGridFunctionCoefficient dgv_xCoef(&dgv_x); - h1_x.ProjectCoefficient(quadCoef); - dgv_x.ProjectCoefficient(quadCoef); + h1_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; Vector h1_gf_val(dim); h1_gf_val = 0.0; @@ -2272,4 +2311,1012 @@ TEST_CASE("3D GetGradient", << npts << " 3D points" << std::endl; } +TEST_CASE("2D GetCurl", + "[GridFunction]" + "[CurlGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 2; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + + VectorFunctionCoefficient funcCoef(2, Func_2D_quad); + + SECTION("2D GetCurl tests for element type " + + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + ND_FECollection nd_fec(order+1, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec, dim); + FiniteElementSpace nd_fespace(&mesh, &nd_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec, dim); + + GridFunction h1_x( &h1_fespace); + GridFunction nd_x( &nd_fespace); + GridFunction dgv_x(&dgv_fespace); + + CurlGridFunctionCoefficient h1_xCoef( &h1_x); + CurlGridFunctionCoefficient nd_xCoef( &nd_x); + CurlGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(funcCoef); + nd_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + + Vector f_val(2*dim-3); f_val = 0.0; + Vector h1_gf_val(2*dim-3); h1_gf_val = 0.0; + Vector nd_gf_val(2*dim-3); nd_gf_val = 0.0; + Vector dgv_gf_val(2*dim-3); dgv_gf_val = 0.0; + + SECTION("Domain Evaluation 2D") + { + std::cout << "Domain Evaluation 2D" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + RotFunc_2D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + + h1_err += h1_dist; + nd_err += nd_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << ") vs. (" + << h1_gf_val[0] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << ") vs. (" + << nd_gf_val[0] << ") " << nd_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << ") vs. (" + << dgv_gf_val[0] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (H1 Context)") + { + std::cout << "Boundary Evaluation 2D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + RotFunc_2D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + + h1_err += h1_dist; + nd_err += nd_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << ") vs. (" + << h1_gf_val[0] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << ") vs. (" + << nd_gf_val[0] << ") " << nd_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << ") vs. (" + << dgv_gf_val[0] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (DG Context)") + { + std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + RotFunc_2D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + + h1_err += h1_dist; + nd_err += nd_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << ") vs. (" + << h1_gf_val[0] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << ") vs. (" + << nd_gf_val[0] << ") " << nd_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << ") vs. (" + << dgv_gf_val[0] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetCurl at " + << npts << " 2D points" << std::endl; +} + +TEST_CASE("3D GetCurl", + "[GridFunction]" + "[CurlGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 3; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::HEXAHEDRON; type++) + { + Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + + VectorFunctionCoefficient funcCoef(3, Func_3D_quad); + + SECTION("3D GetCurl tests for element type " + + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + ND_FECollection nd_fec(order+1, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec, dim); + FiniteElementSpace nd_fespace(&mesh, &nd_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec, dim); + + GridFunction h1_x( &h1_fespace); + GridFunction nd_x( &nd_fespace); + GridFunction dgv_x(&dgv_fespace); + + CurlGridFunctionCoefficient h1_xCoef( &h1_x); + CurlGridFunctionCoefficient nd_xCoef( &nd_x); + CurlGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(funcCoef); + nd_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + + Vector f_val(2*dim-3); f_val = 0.0; + Vector h1_gf_val(2*dim-3); h1_gf_val = 0.0; + Vector nd_gf_val(2*dim-3); nd_gf_val = 0.0; + Vector dgv_gf_val(2*dim-3); dgv_gf_val = 0.0; + + SECTION("Domain Evaluation 3D") + { + std::cout << "Domain Evaluation 3D" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + CurlFunc_3D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + + h1_err += h1_dist; + nd_err += nd_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 3D (H1 Context)") + { + std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + CurlFunc_3D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + + h1_err += h1_dist; + nd_err += nd_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 3D (DG Context)") + { + std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double nd_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + CurlFunc_3D_quad(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + + h1_err += h1_dist; + nd_err += nd_dist; + dgv_err += dgv_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << be << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << be << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && dgv_dist > tol) + { + std::cout << be << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetCurl at " + << npts << " 3D points" << std::endl; +} + +TEST_CASE("2D GetDivergence", + "[GridFunction]" + "[DivergenceGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 2; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + + VectorFunctionCoefficient funcCoef(dim, Func_2D_quad); + + SECTION("2D GetValue tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + RT_FECollection rt_fec(order+1, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec, dim); + FiniteElementSpace rt_fespace(&mesh, &rt_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec, dim); + + GridFunction h1_x(&h1_fespace); + GridFunction rt_x(&rt_fespace); + GridFunction dgv_x(&dgv_fespace); + + DivergenceGridFunctionCoefficient h1_xCoef(&h1_x); + DivergenceGridFunctionCoefficient rt_xCoef(&rt_x); + DivergenceGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(funcCoef); + rt_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + + SECTION("Domain Evaluation 2D") + { + std::cout << "Domain Evaluation 2D" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double rt_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = DivFunc_2D_quad(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double rt_gf_val = rt_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + rt_err += fabs(f_val - rt_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - rt_gf_val) > tol) + { + std::cout << e << ":" << j << " rt " << f_val << " " + << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(rt_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (H1 Context)") + { + std::cout << "Boundary Evaluation 2D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double rt_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = DivFunc_2D_quad(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double rt_gf_val = rt_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + rt_err += fabs(f_val - rt_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - rt_gf_val) > tol) + { + std::cout << be << ":" << j << " rt " << f_val << " " + << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(rt_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 2D (DG Context)") + { + std::cout << "Boundary Evaluation 2D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double rt_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = DivFunc_2D_quad(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double rt_gf_val = rt_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + rt_err += fabs(f_val - rt_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - rt_gf_val) > tol) + { + std::cout << be << ":" << j << " rt " << f_val << " " + << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(rt_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetDivergence at " + << npts << " 2D points" << std::endl; +} + +TEST_CASE("3D GetDivergence", + "[GridFunction]" + "[DivergenceGridFunctionCoefficient]") +{ + int log = 1; + int n = 1; + int dim = 3; + int order = 2; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::HEXAHEDRON; type++) + { + Mesh mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + + VectorFunctionCoefficient funcCoef(dim, Func_3D_quad); + + SECTION("3D GetValue tests for element type " + std::to_string(type)) + { + H1_FECollection h1_fec(order, dim); + RT_FECollection rt_fec(order+1, dim); + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + + FiniteElementSpace h1_fespace(&mesh, &h1_fec, dim); + FiniteElementSpace rt_fespace(&mesh, &rt_fec); + FiniteElementSpace dgv_fespace(&mesh, &dgv_fec, dim); + + GridFunction h1_x(&h1_fespace); + GridFunction rt_x(&rt_fespace); + GridFunction dgv_x(&dgv_fespace); + + DivergenceGridFunctionCoefficient h1_xCoef(&h1_x); + DivergenceGridFunctionCoefficient rt_xCoef(&rt_x); + DivergenceGridFunctionCoefficient dgv_xCoef(&dgv_x); + + h1_x.ProjectCoefficient(funcCoef); + rt_x.ProjectCoefficient(funcCoef); + dgv_x.ProjectCoefficient(funcCoef); + + SECTION("Domain Evaluation 3D") + { + std::cout << "Domain Evaluation 3D" << std::endl; + for (int e = 0; e < mesh.GetNE(); e++) + { + ElementTransformation *T = mesh.GetElementTransformation(e); + const FiniteElement *fe = h1_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double rt_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = DivFunc_3D_quad(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double rt_gf_val = rt_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + rt_err += fabs(f_val - rt_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - rt_gf_val) > tol) + { + std::cout << e << ":" << j << " rt " << f_val << " " + << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(rt_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 3D (H1 Context)") + { + std::cout << "Boundary Evaluation 3D (H1 Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + ElementTransformation *T = mesh.GetBdrElementTransformation(be); + const FiniteElement *fe = h1_fespace.GetBE(be); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double rt_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = DivFunc_3D_quad(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double rt_gf_val = rt_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + rt_err += fabs(f_val - rt_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - rt_gf_val) > tol) + { + std::cout << be << ":" << j << " rt " << f_val << " " + << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(rt_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + + SECTION("Boundary Evaluation 3D (DG Context)") + { + std::cout << "Boundary Evaluation 3D (DG Context)" << std::endl; + for (int be = 0; be < mesh.GetNBE(); be++) + { + FaceElementTransformations *T = + mesh.GetBdrFaceTransformations(be); + const IntegrationRule &ir = IntRules.Get(T->GetGeometryType(), + 2*order + 2); + + double h1_err = 0.0; + double rt_err = 0.0; + double dgv_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = DivFunc_3D_quad(tip); + + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double rt_gf_val = rt_xCoef.Eval(*T, ip); + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + rt_err += fabs(f_val - rt_gf_val); + dgv_err += fabs(f_val - dgv_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << be << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - rt_gf_val) > tol) + { + std::cout << be << ":" << j << " rt " << f_val << " " + << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << be << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + dgv_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + REQUIRE(rt_err == Approx(0.0)); + REQUIRE(dgv_err == Approx(0.0)); + } + } + } + } + std::cout << "Checked GridFunction::GetDivergence at " + << npts << " 3D points" << std::endl; +} + } // namespace get_value From 62bf39a011446ea1d930c62cbb2dd2604f41f653 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Fri, 1 May 2020 02:13:22 -0400 Subject: [PATCH 261/535] Fixes style --- mesh/pumi.cpp | 340 +++++++++++++++++++++++++++----------------------- 1 file changed, 182 insertions(+), 158 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 19ce6d8111..b7366dc852 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -37,15 +37,16 @@ static void getPumiNodeXis(apf::FieldShape* fs, int type, IntegrationRule& xis) { - apf::NewArray pumiXis; - apf::getElementNodeXis(fs, type, pumiXis); - xis.SetSize(pumiXis.size()); - for (size_t i = 0; i < pumiXis.size(); i++) { - IntegrationPoint& ip = xis.IntPoint(i); - double xi[3]; - pumiXis[i].toArray(xi); - ip.Set(xi, 3); - } + apf::NewArray pumiXis; + apf::getElementNodeXis(fs, type, pumiXis); + xis.SetSize(pumiXis.size()); + for (size_t i = 0; i < pumiXis.size(); i++) + { + IntegrationPoint& ip = xis.IntPoint(i); + double xi[3]; + pumiXis[i].toArray(xi); + ip.Set(xi, 3); + } } static void getPumiNodeXis(apf::FieldShape* fs, @@ -53,23 +54,24 @@ static void getPumiNodeXis(apf::FieldShape* fs, apf::MeshEntity* e, IntegrationRule& xis) { - apf::NewArray pumiXis; - apf::getElementNodeXis(fs, m, e, pumiXis); - xis.SetSize(pumiXis.size()); - for (size_t i = 0; i < pumiXis.size(); i++) { - IntegrationPoint& ip = xis.IntPoint(i); - double xi[3]; - pumiXis[i].toArray(xi); - ip.Set(xi, 3); - } + apf::NewArray pumiXis; + apf::getElementNodeXis(fs, m, e, pumiXis); + xis.SetSize(pumiXis.size()); + for (size_t i = 0; i < pumiXis.size(); i++) + { + IntegrationPoint& ip = xis.IntPoint(i); + double xi[3]; + pumiXis[i].toArray(xi); + ip.Set(xi, 3); + } } static void ReadPumiElement(apf::MeshEntity* Ent, /* ptr to pumi entity */ - apf::Downward Verts, - const int Attr, apf::Numbering* vert_num, - Element* el /* ptr to mfem entity being created */ - ) + apf::Downward Verts, + const int Attr, apf::Numbering* vert_num, + Element* el /* ptr to mfem entity being created */ + ) { int nv, *v; @@ -244,8 +246,8 @@ void PumiMesh::ReadSCORECMesh(apf::Mesh2* apf_mesh, apf::Numbering* v_num_loc, apf_mesh->getDownward(ent, 0, verts); int attr = 1; int geom_type = apf_mesh->getType(ent); - boundary[j] = NewElement(geom_type); - ReadPumiElement(ent, verts, attr, v_num_loc, boundary[j]); + boundary[j] = NewElement(geom_type); + ReadPumiElement(ent, verts, attr, v_num_loc, boundary[j]); j++; } } @@ -396,9 +398,9 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, apf_mesh->getDownward(ent, 0, verts); int attr = 1 ; int geom_type = apf_mesh->getType(ent); - boundary[bdr_ctr] = NewElement(geom_type); - ReadPumiElement(ent, verts, attr, v_num_loc, boundary[bdr_ctr]); - bdr_ctr++; + boundary[bdr_ctr] = NewElement(geom_type); + ReadPumiElement(ent, verts, attr, v_num_loc, boundary[bdr_ctr]); + bdr_ctr++; } } apf_mesh->end(itr); @@ -709,12 +711,12 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, ParPumiMesh::~ParPumiMesh() { - // clean ups + // clean ups - // This is used during some of the field transfers, and therefore - // unlike the PumiMesh class, we cannot destroy this inside the - // constructor of the class. - apf::destroyNumbering(v_num_loc); + // This is used during some of the field transfers, and therefore + // unlike the PumiMesh class, we cannot destroy this inside the + // constructor of the class. + apf::destroyNumbering(v_num_loc); } // GridFunctionPumi Implementation needed for high order meshes @@ -951,49 +953,58 @@ int ParPumiMesh::RotationPUMItoMFEM(apf::Mesh2* apf_mesh, apf::MeshEntity* tet, int elemId) { - MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); - // get downward vertices of PUMI element - apf::Downward vs; - int nv = apf_mesh->getDownward(tet,0,vs); - int pumi_vid[nv]; - for (int i = 0; i < nv; i++) - pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); + MFEM_ASSERT(apf_mesh->getType(tet) == apf::Mesh::TET, ""); + // get downward vertices of PUMI element + apf::Downward vs; + int nv = apf_mesh->getDownward(tet,0,vs); + int pumi_vid[nv]; + for (int i = 0; i < nv; i++) + { + pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); + } - // get downward vertices of MFEM element - mfem::Array mfem_vid; - this->GetElementVertices(elemId, mfem_vid); + // get downward vertices of MFEM element + mfem::Array mfem_vid; + this->GetElementVertices(elemId, mfem_vid); - // get rotated indices of PUMI element - int pumi_vid_rot[nv]; - for (int i = 0; i < nv; i++) - pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); - apf::Downward vs_rot; - for (int i = 0; i < nv; i++) - vs_rot[i] = vs[pumi_vid_rot[i]]; + // get rotated indices of PUMI element + int pumi_vid_rot[nv]; + for (int i = 0; i < nv; i++) + { + pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); + } + apf::Downward vs_rot; + for (int i = 0; i < nv; i++) + { + vs_rot[i] = vs[pumi_vid_rot[i]]; + } - return ma::findTetRotation(apf_mesh, tet, vs_rot); + return ma::findTetRotation(apf_mesh, tet, vs_rot); } // Convert parent coordinate form a PUMI tet to an MFEM tet IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, - apf::MeshEntity* tet, - int elemId, - apf::NewArray& pumi_xi, - bool checkOrientation) + apf::MeshEntity* tet, + int elemId, + apf::NewArray& pumi_xi, + bool checkOrientation) { - int num_nodes = pumi_xi.size(); - IntegrationRule mfem_xi(num_nodes); - int rotation = checkOrientation ? RotationPUMItoMFEM(apf_mesh, tet, elemId):0; - for(int i = 0; i < num_nodes; i++) { - // for non zero "rotation", rotate the xi - if (rotation) - ma::rotateTetXi(pumi_xi[i], rotation); - IntegrationPoint& ip = mfem_xi.IntPoint(i); - double tmp_xi[3]; - pumi_xi[i].toArray(tmp_xi); - ip.Set(tmp_xi,3); - } - return mfem_xi; + int num_nodes = pumi_xi.size(); + IntegrationRule mfem_xi(num_nodes); + int rotation = checkOrientation ? RotationPUMItoMFEM(apf_mesh, tet, elemId):0; + for (int i = 0; i < num_nodes; i++) + { + // for non zero "rotation", rotate the xi + if (rotation) + { + ma::rotateTetXi(pumi_xi[i], rotation); + } + IntegrationPoint& ip = mfem_xi.IntPoint(i); + double tmp_xi[3]; + pumi_xi[i].toArray(tmp_xi); + ip.Set(tmp_xi,3); + } + return mfem_xi; } // Transfer a mixed vector-scalar field (i.e. velocity,pressure) and the @@ -1016,7 +1027,7 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::NewArray pumi_nodes; apf::getElementNodeXis(field_shape, apf_mesh, ent, pumi_nodes); IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( - apf_mesh, ent, iel, pumi_nodes, true); + apf_mesh, ent, iel, pumi_nodes, true); // Get the solution ElementTransformation* eltr = this->GetElementTransformation(iel); DenseMatrix vel; @@ -1025,21 +1036,24 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, grid_pr->GetValues(iel, mfem_nodes, pr, 1); int non = 0; - for (int d = 0; d <= dim; d++) { - if (!field_shape->hasNodesIn(d)) continue; - apf::Downward a; - int na = apf_mesh->getDownward(ent,d,a); - for (int i = 0; i < na; i++) { - int type = apf_mesh->getType(a[i]); - int nan = field_shape->countNodesOn(type); - for (int n = 0; n < nan; n++) { - apf::Vector3 v(vel.GetColumn(non)); - apf::setVector(vel_field, a[i], n, v); - apf::setScalar(pr_field, a[i], n, pr[non]); - apf::setScalar(vel_mag_field, a[i], n, v.getLength()); - non++; - } - } + for (int d = 0; d <= dim; d++) + { + if (!field_shape->hasNodesIn(d)) { continue; } + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) + { + int type = apf_mesh->getType(a[i]); + int nan = field_shape->countNodesOn(type); + for (int n = 0; n < nan; n++) + { + apf::Vector3 v(vel.GetColumn(non)); + apf::setVector(vel_field, a[i], n, v); + apf::setScalar(pr_field, a[i], n, pr[non]); + apf::setScalar(vel_mag_field, a[i], n, v.getLength()); + non++; + } + } } iel++; } @@ -1063,27 +1077,30 @@ void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::NewArray pumi_nodes; apf::getElementNodeXis(field_shape, apf_mesh, ent, pumi_nodes); IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( - apf_mesh, ent, iel, pumi_nodes, true); + apf_mesh, ent, iel, pumi_nodes, true); // Get the solution Vector vals; grid_pr->GetValues(iel, mfem_nodes, vals, 1); int non = 0; - for (int d = 0; d <= dim; d++) { - if (!field_shape->hasNodesIn(d)) continue; - apf::Downward a; - int na = apf_mesh->getDownward(ent,d,a); - for (int i = 0; i < na; i++) { - int type = apf_mesh->getType(a[i]); - int nan = field_shape->countNodesOn(type); - for (int n = 0; n < nan; n++) { - double pr = vals[non]; - double pr_mag = pr >= 0 ? pr : -pr; - apf::setScalar(pr_field, a[i], n, pr); - apf::setScalar(pr_mag_field, a[i], n, pr_mag); - non++; - } - } + for (int d = 0; d <= dim; d++) + { + if (!field_shape->hasNodesIn(d)) { continue; } + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) + { + int type = apf_mesh->getType(a[i]); + int nan = field_shape->countNodesOn(type); + for (int n = 0; n < nan; n++) + { + double pr = vals[non]; + double pr_mag = pr >= 0 ? pr : -pr; + apf::setScalar(pr_field, a[i], n, pr); + apf::setScalar(pr_mag_field, a[i], n, pr_mag); + non++; + } + } } iel++; } @@ -1108,27 +1125,30 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::NewArray pumi_nodes; apf::getElementNodeXis(field_shape, apf_mesh, ent, pumi_nodes); IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( - apf_mesh, ent, iel, pumi_nodes, true); + apf_mesh, ent, iel, pumi_nodes, true); // Get the solution ElementTransformation* eltr = this->GetElementTransformation(iel); DenseMatrix vel; grid_vel->GetVectorValues(*eltr, mfem_nodes, vel); int non = 0; - for (int d = 0; d <= dim; d++) { - if (!field_shape->hasNodesIn(d)) continue; - apf::Downward a; - int na = apf_mesh->getDownward(ent,d,a); - for (int i = 0; i < na; i++) { - int type = apf_mesh->getType(a[i]); - int nan = field_shape->countNodesOn(type); - for (int n = 0; n < nan; n++) { - apf::Vector3 v(vel.GetColumn(non)); - apf::setScalar(vel_mag_field, a[i], n, v.getLength()); - apf::setVector(vel_field, a[i], n, v); - non++; - } - } + for (int d = 0; d <= dim; d++) + { + if (!field_shape->hasNodesIn(d)) { continue; } + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) + { + int type = apf_mesh->getType(a[i]); + int nan = field_shape->countNodesOn(type); + for (int n = 0; n < nan; n++) + { + apf::Vector3 v(vel.GetColumn(non)); + apf::setScalar(vel_mag_field, a[i], n, v.getLength()); + apf::setVector(vel_field, a[i], n, v); + non++; + } + } } iel++; } @@ -1136,54 +1156,58 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, } void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, - ParGridFunction* gf, - apf::Field* NedelecField) + ParGridFunction* gf, + apf::Field* NedelecField) { - apf::FieldShape* nedelecFieldShape = NedelecField->getShape(); - int dim = apf_mesh->getDimension(); + apf::FieldShape* nedelecFieldShape = NedelecField->getShape(); + int dim = apf_mesh->getDimension(); - // loop over all elements - size_t elemNo = 0; - apf::MeshEntity* ent; - apf::MeshIterator* it = apf_mesh->begin(dim); - while ( ent = apf_mesh->iterate(it) ) { - // get all the pumi nodes and rotate them - apf::NewArray pumi_nodes; - apf::getElementNodeXis(nedelecFieldShape, apf_mesh, ent, pumi_nodes); - IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( - apf_mesh, ent, elemNo, pumi_nodes, true); - // evaluate the vector field on the mfem nodes - ElementTransformation* eltr = this->GetElementTransformation(elemNo); - DenseMatrix mfem_field_vals; - gf->GetVectorValues(*eltr, mfem_nodes, mfem_field_vals); + // loop over all elements + size_t elemNo = 0; + apf::MeshEntity* ent; + apf::MeshIterator* it = apf_mesh->begin(dim); + while ( ent = apf_mesh->iterate(it) ) + { + // get all the pumi nodes and rotate them + apf::NewArray pumi_nodes; + apf::getElementNodeXis(nedelecFieldShape, apf_mesh, ent, pumi_nodes); + IntegrationRule mfem_nodes = ParentXisPUMItoMFEM( + apf_mesh, ent, elemNo, pumi_nodes, true); + // evaluate the vector field on the mfem nodes + ElementTransformation* eltr = this->GetElementTransformation(elemNo); + DenseMatrix mfem_field_vals; + gf->GetVectorValues(*eltr, mfem_nodes, mfem_field_vals); - // compute and store dofs on ND field - int non = 0; - for (int d = 0; d <= dim; d++) { - if (!nedelecFieldShape->hasNodesIn(d)) continue; - apf::Downward a; - int na = apf_mesh->getDownward(ent,d,a); - for (int i = 0; i < na; i++) { - int type = apf_mesh->getType(a[i]); - int nan = nedelecFieldShape->countNodesOn(type); - apf::MeshElement* me = apf::createMeshElement(apf_mesh, a[i]); - for (int n = 0; n < nan; n++) { - apf::Vector3 xi, tangent; - nedelecFieldShape->getNodeXi(type, n, xi); - nedelecFieldShape->getNodeTangent(type, n, tangent); - apf::Vector3 pumi_field_vector(mfem_field_vals.GetColumn(non)); - apf::Matrix3x3 J; - apf::getJacobian(me, xi, J); - double dof = (J * pumi_field_vector) * tangent; - apf::setScalar(NedelecField, a[i], n, dof); - non++; - } - apf::destroyMeshElement(me); + // compute and store dofs on ND field + int non = 0; + for (int d = 0; d <= dim; d++) + { + if (!nedelecFieldShape->hasNodesIn(d)) { continue; } + apf::Downward a; + int na = apf_mesh->getDownward(ent,d,a); + for (int i = 0; i < na; i++) + { + int type = apf_mesh->getType(a[i]); + int nan = nedelecFieldShape->countNodesOn(type); + apf::MeshElement* me = apf::createMeshElement(apf_mesh, a[i]); + for (int n = 0; n < nan; n++) + { + apf::Vector3 xi, tangent; + nedelecFieldShape->getNodeXi(type, n, xi); + nedelecFieldShape->getNodeTangent(type, n, tangent); + apf::Vector3 pumi_field_vector(mfem_field_vals.GetColumn(non)); + apf::Matrix3x3 J; + apf::getJacobian(me, xi, J); + double dof = (J * pumi_field_vector) * tangent; + apf::setScalar(NedelecField, a[i], n, dof); + non++; + } + apf::destroyMeshElement(me); + } } - } - elemNo++; - } - apf_mesh->end(it); // end loop over all elements + elemNo++; + } + apf_mesh->end(it); // end loop over all elements } void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, From 90a6df62c28896484f83f5d56ca46c31367f80ed Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 1 May 2020 00:55:44 -0700 Subject: [PATCH 262/535] Adding mesh trimmer miniapp --- miniapps/meshing/makefile | 4 +- miniapps/meshing/trimmer.cpp | 162 +++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 miniapps/meshing/trimmer.cpp diff --git a/miniapps/meshing/makefile b/miniapps/meshing/makefile index fc811ba9d6..8248dcf16f 100644 --- a/miniapps/meshing/makefile +++ b/miniapps/meshing/makefile @@ -91,13 +91,13 @@ clean: clean-build clean-exec clean-build: rm -f *.o *~ mobius-strip klein-bottle toroid twist - rm -f mesh-explorer shaper extruder + rm -f mesh-explorer shaper extruder trimmer rm -f mesh-optimizer pmesh-optimizer rm -f minimal-surface pminimal-surface rm -rf *.dSYM *.TVD.*breakpoints clean-exec: @rm -f mobius-strip.mesh klein-bottle.mesh mesh-explorer.mesh - @rm -f toroid-*.mesh twist-*.mesh + @rm -f toroid-*.mesh twist-*.mesh trimmed.mesh @rm -f partitioning.txt shaper.mesh extruder.mesh @rm -f optimized* perturbed* diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp new file mode 100644 index 0000000000..e1061b6090 --- /dev/null +++ b/miniapps/meshing/trimmer.cpp @@ -0,0 +1,162 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. +// +#include "mfem.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +int main(int argc, char *argv[]) +{ + // Parse command-line options. + const char *mesh_file = "../../data/beam-tet.vtk"; + int offset = -1; + Array attr; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&offset, "-o", "--attr-offset", + "Offset is added to the element attribute to generate " + "the boundary offset."); + args.AddOption(&attr, "-a", "-attr", "Set of attributes to remove from " + "the mesh."); + args.Parse(); + if (!args.Good()) + { + args.PrintUsage(cout); + return 1; + } + if (attr.Size() == 0) + { + attr.SetSize(1); + attr[0] = 2; + } + + Mesh mesh(mesh_file, 0, 0); + + int max_attr = mesh.attributes.Max(); + int max_bdr_attr = (offset == -1) ? mesh.bdr_attributes.Max() : offset; + + Array marker(max_attr); + marker = 0; + for (int i=0; iGetAttribute(); + if (!marker[elem_attr-1]) { num_elements++; } + } + + // Count the number of boundary elements in the final mesh + int num_bdr_elements = 0; + for (int f=0; f= 0) { a1 = mesh.GetElement(e1)->GetAttribute(); } + if (e2 >= 0) { a2 = mesh.GetElement(e2)->GetAttribute(); } + + if (a1 == 0 || a2 == 0) + { + if (a1 == 0 && !marker[a2-1]) { num_bdr_elements++; } + else if (a2 == 0 && !marker[a1-1]) { num_bdr_elements++; } + } + else + { + if (marker[a1-1] && !marker[a2-1]) { num_bdr_elements++; } + else if (!marker[a1-1] && marker[a2-1]) { num_bdr_elements++; } + } + } + + cout << "Number of Elements: " << mesh.GetNE() << " -> " + << num_elements << endl; + cout << "Number of Boundary Elements: " << mesh.GetNBE() << " -> " + << num_bdr_elements << endl; + + Mesh trimmed_mesh(mesh.Dimension(), mesh.GetNV(), + num_elements, num_bdr_elements, mesh.SpaceDimension()); + + // Copy vertices + for (int v=0; vGetAttribute(); + if (!marker[elem_attr-1]) + { + Element * nel = mesh.NewElement(el->GetGeometryType()); + nel->SetAttribute(elem_attr); + nel->SetVertices(el->GetVertices()); + trimmed_mesh.AddElement(nel); + } + } + + // Create boundary elements + for (int f=0; f= 0) { a1 = mesh.GetElement(e1)->GetAttribute(); } + if (e2 >= 0) { a2 = mesh.GetElement(e2)->GetAttribute(); } + + if (a1 == 0 || a2 == 0) + { + if ((a1 == 0 && !marker[a2-1]) || (a2 == 0 && !marker[a1-1])) + { + Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); + trimmed_mesh.AddBdrElement(bel); + } + } + else + { + if (marker[a1-1] && !marker[a2-1]) + { + Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); + bel->SetAttribute(max_bdr_attr + a1); + trimmed_mesh.AddBdrElement(bel); + } + else if (!marker[a1-1] && marker[a2-1]) + { + Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); + bel->SetAttribute(max_bdr_attr + a2); + trimmed_mesh.AddBdrElement(bel); + } + } + } + + trimmed_mesh.FinalizeTopology(); + trimmed_mesh.Finalize(); + trimmed_mesh.RemoveUnusedVertices(); + + ofstream ofs("trimmed.mesh"); + trimmed_mesh.Print(ofs); + ofs.close(); +} From 6ec8be76f1491440bdfbf07d2efbcdba61af771d Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 1 May 2020 15:13:00 -0700 Subject: [PATCH 263/535] Return const reference in combo::getintegrators. --- fem/tmop.hpp | 2 +- miniapps/meshing/pmesh-optimizer.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 3e70ae8358..1022122669 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -1033,7 +1033,7 @@ public: /// Adds a new TMOP_Integrator to the combination. void AddTMOPIntegrator(TMOP_Integrator *ti) { tmopi.Append(ti); } - Array GetTMOPIntegrators() const { return tmopi; } + const Array &GetTMOPIntegrators() const { return tmopi; } /// Adds the limiting term to the first integrator. Disables it for the rest. void EnableLimiting(const GridFunction &n0, const GridFunction &dist, diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 6d63dccff1..dcbdd9de26 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -609,9 +609,12 @@ int main (int argc, char *argv[]) zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, adapt_eval); - socketstream vis1; - common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", - 300, 600, 300, 300); + if (visualization) + { + socketstream vis1; + common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", + 300, 600, 300, 300); + } } // 15. Setup the final NonlinearForm (which defines the integral of interest, @@ -846,7 +849,7 @@ int main (int argc, char *argv[]) vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 600); } - if (adapt_lim) + if (adapt_lim && visualization) { socketstream vis0; common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0", From aa80429c54c1a54ec4d25e8c6da2b61224bdd8a6 Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 1 May 2020 23:33:14 -0700 Subject: [PATCH 264/535] Restructuring to avoid a segfault. --- fem/tmop.cpp | 31 +++++----------------------- fem/tmop.hpp | 12 +++++------ miniapps/meshing/pmesh-optimizer.cpp | 23 +++++++++++++++++---- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 9d35e292d9..0403e3ed2c 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1217,22 +1217,12 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &zeta0_gf, GridFunction &zeta_gf, Coefficient &coeff, - int interp_type) + AdaptivityEvaluator &ad) { zeta_0 = &zeta0_gf; zeta = &zeta_gf; coeff_zeta = &coeff; - - if (interp_type == 0) { adapt_eval = new AdvectorCG; } - else if (interp_type == 1) - { -#ifdef MFEM_USE_GSLIB - adapt_eval = new InterpolatorFP; -#elif - MFEM_ABORT("MFEM is not built with GSLIB support!"); -#endif - } - else { MFEM_ABORT("Bad interpolation option."); } + adapt_eval = &ad; adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(), *zeta->FESpace()->FEColl(), 1); @@ -1243,22 +1233,12 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &zeta0_gf, void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, ParGridFunction &zeta_gf, Coefficient &coeff, - int interp_type) + AdaptivityEvaluator &ad) { zeta_0 = &zeta0_gf; zeta = &zeta_gf; coeff_zeta = &coeff; - - if (interp_type == 0) { adapt_eval = new AdvectorCG; } - else if (interp_type == 1) - { -#ifdef MFEM_USE_GSLIB - adapt_eval = new InterpolatorFP; -#elif - MFEM_ABORT("MFEM is not built with GSLIB support!"); -#endif - } - else { MFEM_ABORT("Bad interpolation option."); } + adapt_eval = &ad; adapt_eval->SetParMetaInfo(*zeta_gf.ParFESpace()->GetParMesh(), *zeta_gf.ParFESpace()->FEColl(), 1); @@ -1556,9 +1536,8 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, const DenseMatrix &Jtr_q = Jtr(q); metric->SetTargetJacobian(Jtr_q); CalcInverse(Jtr_q, Jrt); - const double weight = ip.weight * Jtr_q.Det(); weights(q) = ip.weight * Jtr_q.Det(); - double weight_m = weight * metric_normal; + double weight_m = weights(q) * metric_normal; el.CalcDShape(ip, DSh); Mult(DSh, Jrt, DS); diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 1022122669..87640c1c3f 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -828,10 +828,10 @@ protected: double lim_normal; // Adaptive limiting. - const GridFunction *zeta_0; - GridFunction *zeta; - Coefficient *coeff_zeta; - AdaptivityEvaluator *adapt_eval; + const GridFunction *zeta_0; // Not owned. + GridFunction *zeta; // Not owned. + Coefficient *coeff_zeta; // Not owned. + AdaptivityEvaluator *adapt_eval; // Not owned. DiscreteAdaptTC *discr_tc; @@ -970,11 +970,11 @@ public: void EnableAdaptiveLimiting(const GridFunction &zeta0_gf, GridFunction &zeta_gf, Coefficient &coeff, - int interp_type); + AdaptivityEvaluator &ad); #ifdef MFEM_USE_MPI void EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, ParGridFunction &zeta_gf, Coefficient &coeff, - int interp_type); + AdaptivityEvaluator &ad); #endif /// Update the original/reference nodes used for limiting. diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index dcbdd9de26..acb9515f61 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -nor -vl 1 -al -ae 0 +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 8 -nor -vl 1 -al -ae 0 // Adaptive limiting through FD (required GSLIB): -// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -rs 0 -mid 2 -tid 1 -ni 50 -ls 2 -bnd -qt 1 -qo 8 -nor -vl 1 -al -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 8 -nor -vl 1 -al -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: @@ -602,13 +602,27 @@ int main (int argc, char *argv[]) // Adaptive limiting. ParGridFunction zeta_0(&ind_fes), zeta(&ind_fes); - ConstantCoefficient coef_zeta(10.0); + ConstantCoefficient coef_zeta(5.0); + AdaptivityEvaluator *adapt_evaluator = NULL; if (adapt_lim) { FunctionCoefficient alim_coeff(adapt_lim_fun); zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); - he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, adapt_eval); + + if (adapt_eval == 0) { adapt_evaluator = new AdvectorCG; } + else if (adapt_eval == 1) + { +#ifdef MFEM_USE_GSLIB + adapt_evaluator = new InterpolatorFP; +#else + MFEM_ABORT("MFEM is not built with GSLIB support!"); +#endif + } + else { MFEM_ABORT("Bad interpolation option."); } + + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, + *adapt_evaluator); if (visualization) { socketstream vis1; @@ -882,6 +896,7 @@ int main (int argc, char *argv[]) delete target_c2; delete metric2; delete coeff1; + delete adapt_evaluator; delete target_c; delete adapt_coeff; delete metric; From 2856c64994678f325ec0edc77f7129d700e3f367 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sat, 2 May 2020 00:21:24 -0700 Subject: [PATCH 265/535] Fixed the normalization constant of the limiting term, for the case when the target matrices don't contain volumetric information. --- fem/tmop.cpp | 23 +++++++++++++++++++++-- fem/tmop.hpp | 3 +++ miniapps/meshing/pmesh-optimizer.cpp | 4 ++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 0403e3ed2c..87c43cceff 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -843,7 +843,20 @@ void TargetConstructor::ComputeAvgVolume() const #endif } -// virtual method +bool TargetConstructor::ContainsVolumeInfo() const +{ + switch(target_type) + { + case IDEAL_SHAPE_UNIT_SIZE: return false; + case IDEAL_SHAPE_EQUAL_SIZE: + case IDEAL_SHAPE_GIVEN_SIZE: + case GIVEN_SHAPE_AND_SIZE: + case GIVEN_FULL: return true; + default: MFEM_ABORT("TargetType not added to ContainsVolumeInfo."); + /* */ return false; + } +} + void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe, const IntegrationRule &ir, const Vector &elfun, @@ -1867,7 +1880,8 @@ void TMOP_Integrator::ParEnableNormalization(const ParGridFunction &x) ComputeNormalizationEnergies(x, loc[0], loc[1]); double rdc[2]; MPI_Allreduce(loc, rdc, 2, MPI_DOUBLE, MPI_SUM, x.ParFESpace()->GetComm()); - metric_normal = 1.0 / rdc[0]; lim_normal = 1.0 / rdc[1]; + metric_normal = 1.0 / rdc[0]; + lim_normal = 1.0 / rdc[1]; } #endif @@ -1916,6 +1930,11 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x, lim_energy += weight; } } + if (targetC->ContainsVolumeInfo() == false) + { + // Special case when the targets don't contain volumetric information. + lim_energy = fes->GetNE(); + } } void TMOP_Integrator::ComputeMinJac(const Vector &x, diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 87640c1c3f..ab71505380 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -664,6 +664,9 @@ public: /// Used by target type IDEAL_SHAPE_EQUAL_SIZE. The default volume scale is 1. void SetVolumeScale(double vol_scale) { volume_scale = vol_scale; } + /// Checks if the target matrices contain non-trivial size specification. + bool ContainsVolumeInfo() const; + /** @brief Given an element and quadrature rule, computes ref->target transformation Jacobians for each quadrature point in the element. The physical positions of the element's nodes are given by @a elfun. */ diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index acb9515f61..7f077fd885 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,7 +32,7 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 8 -nor -vl 1 -al -ae 0 +// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 // Adaptive limiting through FD (required GSLIB): // * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 8 -nor -vl 1 -al -fd -ae 1 // @@ -602,7 +602,7 @@ int main (int argc, char *argv[]) // Adaptive limiting. ParGridFunction zeta_0(&ind_fes), zeta(&ind_fes); - ConstantCoefficient coef_zeta(5.0); + ConstantCoefficient coef_zeta(0.5); AdaptivityEvaluator *adapt_evaluator = NULL; if (adapt_lim) { From 1fbad9f62d920924d7b14f192488570f2151a3a7 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sat, 2 May 2020 00:45:44 -0700 Subject: [PATCH 266/535] Avoids double counting of the adaptive limiting terms for FD. --- fem/tmop.cpp | 20 +++++++++++++++----- fem/tmop.hpp | 5 ++++- miniapps/meshing/pmesh-optimizer.cpp | 2 +- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 87c43cceff..aacb5e8864 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1266,6 +1266,9 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, const int dof = el.GetDof(), dim = el.GetDim(); double energy; + // No adaptive limiting terms if this is a FD computation. + const bool adaptive_limiting = (zeta && fd_call_flag == false); + DSh.SetSize(dof, dim); Jrt.SetSize(dim); Jpr.SetSize(dim); @@ -1303,7 +1306,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, // Define ref->physical transformation, when a Coefficient is specified. IsoparametricTransformation *Tpr = NULL; - if (coeff1 || coeff0 || zeta) + if (coeff1 || coeff0 || adaptive_limiting) { Tpr = new IsoparametricTransformation; Tpr->SetFE(&el); @@ -1320,7 +1323,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, // coefficient is a ConstantCoefficient or a GridFunctionCoefficient. Vector zeta_q, zeta0_q; - if (zeta) + if (adaptive_limiting) { zeta->GetValues(T.ElementNo, *ir, zeta_q); zeta_0->GetValues(T.ElementNo, *ir, zeta0_q); @@ -1350,7 +1353,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, lim_func->Eval(p, p0, d_vals(i)) * coeff0->Eval(*Tpr, ip); } - if (zeta) + if (adaptive_limiting) { const double diff = zeta_q(i) - zeta0_q(i); val += coeff_zeta->Eval(*Tpr, ip) * lim_normal * diff * diff; @@ -1731,8 +1734,11 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, elvect.SetSize(dof*dim); Vector elfunmod(elfun); + // In GetElementEnergy(), skip terms that have exact derivative calculations. + fd_call_flag = true; + // Energy for unperturbed configuration. - double e_fx = GetElementEnergy(el, T, elfun); + const double e_fx = GetElementEnergy(el, T, elfun); for (int j = 0; j < dim; j++) { @@ -1747,8 +1753,9 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el, if (discr_tc) { discr_tc->RestoreTargetSpecificationAtNode(T, i); } } } + fd_call_flag = false; - // Contributions from adaptive limiting. + // Contributions from adaptive limiting (exact derivatives). if (zeta) { const IntegrationRule *ir = ActionIntegrationRule(el); @@ -1787,6 +1794,8 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, const Vector &ElemDerLoc = *(ElemDer[T.ElementNo]); const Vector &ElemPertLoc = *(ElemPertEnergy[T.ElementNo]); + // In GetElementEnergy(), skip terms that have exact derivative calculations. + fd_call_flag = true; for (int i = 0; i < dof; i++) { for (int j = 0; j < i+1; j++) @@ -1840,6 +1849,7 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el, } } } + fd_call_flag = false; // Contributions from adaptive limiting. if (zeta) diff --git a/fem/tmop.hpp b/fem/tmop.hpp index ab71505380..e0c654fb40 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -840,6 +840,9 @@ protected: // Parameters for FD-based Gradient & Hessian calculation. bool fdflag; + // Specifies that ComputeElementTargets is being called by a FD function. + // It's used to skip terms that have exact derivative calculations. + bool fd_call_flag; double dx; double dxscale; @@ -931,7 +934,7 @@ public: lim_dist(NULL), lim_func(NULL), lim_normal(1.0), zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL), discr_tc(dynamic_cast(tc)), - fdflag(false), dxscale(1.0e3) + fdflag(false), fd_call_flag(false), dxscale(1.0e3) { } ~TMOP_Integrator() diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 7f077fd885..9b4e7d1729 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -34,7 +34,7 @@ // Adaptive limiting: // mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 // Adaptive limiting through FD (required GSLIB): -// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 8 -nor -vl 1 -al -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: From 18f90a2bce62f5d1f841412732fda5adf89d8a95 Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Sat, 2 May 2020 11:01:51 -0400 Subject: [PATCH 267/535] Updates declarations in pumi.hpp to match w/ .cpp --- mesh/pumi.cpp | 6 +++--- mesh/pumi.hpp | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index b7366dc852..2c3117c89f 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -1157,9 +1157,9 @@ void ParPumiMesh::VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* gf, - apf::Field* NedelecField) + apf::Field* nedelec_field) { - apf::FieldShape* nedelecFieldShape = NedelecField->getShape(); + apf::FieldShape* nedelecFieldShape = nedelec_field->getShape(); int dim = apf_mesh->getDimension(); // loop over all elements @@ -1199,7 +1199,7 @@ void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, apf::Matrix3x3 J; apf::getJacobian(me, xi, J); double dof = (J * pumi_field_vector) * tangent; - apf::setScalar(NedelecField, a[i], n, dof); + apf::setScalar(nedelec_field, a[i], n, dof); non++; } apf::destroyMeshElement(me); diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index a19be12b32..c842a723a6 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -79,22 +79,21 @@ public: int refine = 1, bool fix_orientation = true); - /// Returns the permutation (aka rotation, aka orientation) needed to - /// convert PUMI tet to an MFEM tet. This represents the change in - /// tet-to-vertex connectivity between the PUMI and MFEM meshes. - /// e.g.: - /// PUMI_tet{v0,v1,v2,v3} ---> MFEM_tet{v1,v0,v3,v2} - /// * Note that change in the orientation can be caused by - /// a) fixing wrong boundary element orientations - /// b) a call to ReorientTetMesh() which is required for Nedelec + /// Returns the PUMI-to-MFEM permutation (aka rotation, aka orientation) + /** This represents the change in tet-to-vertex connectivity between + the PUMI and MFEM meshes. E.g., + PUMI_tet{v0,v1,v2,v3} ---> MFEM_tet{v1,v0,v3,v2} + * Note that change in the orientation can be caused by + a) fixing wrong boundary element orientations + b) a call to ReorientTetMesh() which is required for Nedelec */ int RotationPUMItoMFEM(apf::Mesh2* apf_mesh, apf::MeshEntity* tet, int elemId); /// Convert the parent coordinate from PUMI to MFEM - /// * By default this functions assumes that there is always - /// change in the orientations of some of the elements. - /// * In case it is know for sure that there is NO change in - /// the orientation, call the functions with last argument = true + /** By default this functions assumes that there is always + change in the orientations of some of the elements. In case it + is known for sure that there is NO change in the orientation, + call the functions with last argument = false */ IntegrationRule ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, apf::MeshEntity* tet, int elemId, @@ -102,27 +101,28 @@ public: bool checkOrientation = true); /// Transfer field from MFEM mesh to PUMI mesh [Mixed]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, - ParGridFunction* Vel, - ParGridFunction* Pr, - apf::Field* VelField, - apf::Field* PrField, - apf::Field* VelMagField); + ParGridFunction* grid_vel, + ParGridFunction* grid_pr, + apf::Field* vel_field, + apf::Field* pr_field, + apf::Field* vel_mag_field); /// Transfer field from MFEM mesh to PUMI mesh [Scalar]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, - ParGridFunction* Pr, - apf::Field* PrField, - apf::Field* PrMagField); + ParGridFunction* grid_pr, + apf::Field* pr_field, + apf::Field* pr_mag_field); /// Transfer field from MFEM mesh to PUMI mesh [Vector]. void VectorFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, - ParGridFunction* Vel, - apf::Field* VelField, - apf::Field* VelMagField); + ParGridFunction* grid_vel, + apf::Field* vel_field, + apf::Field* vel_mag_field); + /// Transfer Nedelec field from MFEM mesh to PUMI mesh [Vector]. void NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* gf, - apf::Field* NedelecField); + apf::Field* nedelec_field); /// Update the mesh after adaptation. void UpdateMesh(const ParMesh* AdaptedpMesh); From 458c1f45ff4f406ae69b7fcdc4c84de9d4eb17a9 Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Sat, 2 May 2020 11:41:23 -0400 Subject: [PATCH 268/535] Changes ~ParPumiMesh() to default. v_num_loc must persist throughout. It will need to be updated each time the underlying pumi_mesh is changed, and should never be destroyed manually during an adaptive solve (in the application code). --- mesh/pumi.cpp | 22 ++++++++-------------- mesh/pumi.hpp | 4 +++- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 2c3117c89f..2c5180c2ea 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -325,9 +325,13 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, // Create local numbering that respects the global ordering apf::Field* apf_field_crd = apf_mesh->getCoordinateField(); apf::FieldShape* crd_shape = apf::getShape(apf_field_crd); - v_num_loc = apf::createNumbering(apf_mesh, - "LocalVertexNumbering", - crd_shape, 1); + // v_num_loc might already be associated the mesh. In that case + // there is no need to create it again. + v_num_loc = apf_mesh->findNumbering("LocalVertexNumbering"); + if (!v_num_loc) + v_num_loc = apf::createNumbering(apf_mesh, + "LocalVertexNumbering", + crd_shape, 1); // Construct the numbering v_num_loc and set the coordinates of the vertices. NumOfVertices = thisVertIds.Size(); @@ -709,16 +713,6 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, Finalize(refine, fix_orientation); } -ParPumiMesh::~ParPumiMesh() -{ - // clean ups - - // This is used during some of the field transfers, and therefore - // unlike the PumiMesh class, we cannot destroy this inside the - // constructor of the class. - apf::destroyNumbering(v_num_loc); -} - // GridFunctionPumi Implementation needed for high order meshes GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM, apf::Numbering* v_num_loc, @@ -1216,7 +1210,7 @@ void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, { // Pr->Update(); // Find local numbering - v_num_loc = apf_mesh->findNumbering("LocalVertexNumbering"); + /* v_num_loc = apf_mesh->findNumbering("LocalVertexNumbering"); */ // Loop over field to copy getShape(ScalarField); diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index c842a723a6..33a3ba3e1c 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -71,6 +71,8 @@ public: class ParPumiMesh : public ParMesh { private: + // This has to persist during an adaptive simulation, and therefore + // needs to be updated each time the mesh changes. apf::Numbering* v_num_loc; public: @@ -132,7 +134,7 @@ public: apf::Field* ScalarField, ParGridFunction* Pr); - virtual ~ParPumiMesh(); + virtual ~ParPumiMesh() {} }; From d6a48278694b3523eec40a473a5c6f1937f98ddd Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Sat, 2 May 2020 11:43:18 -0400 Subject: [PATCH 269/535] Updates pumi ex6p for changes made to pumi code --- examples/pumi/ex6p.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/pumi/ex6p.cpp b/examples/pumi/ex6p.cpp index fc9fb5386e..8f73786357 100644 --- a/examples/pumi/ex6p.cpp +++ b/examples/pumi/ex6p.cpp @@ -332,7 +332,6 @@ int main(int argc, char *argv[]) apf::destroyField(Tmag_field); apf::destroyField(ipfield); - apf::destroyNumbering(pumi_mesh->findNumbering("LocalVertexNumbering")); // 18. Perform MesAdapt. ma::Input* erinput = ma::configure(pumi_mesh, sizefield); From e4afb9dc7022a9714fd886cb237a430300d7e099 Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Sat, 2 May 2020 11:47:17 -0400 Subject: [PATCH 270/535] fixes style --- mesh/pumi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 2c5180c2ea..9f2ad05912 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -331,7 +331,7 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh, if (!v_num_loc) v_num_loc = apf::createNumbering(apf_mesh, "LocalVertexNumbering", - crd_shape, 1); + crd_shape, 1); // Construct the numbering v_num_loc and set the coordinates of the vertices. NumOfVertices = thisVertIds.Size(); From e1fc7d94b7e86aac3d7cb11907dd69fda750d404 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sat, 2 May 2020 23:47:46 -0700 Subject: [PATCH 271/535] Corresponding changes in the serial miniapp. --- fem/tmop.hpp | 6 +-- miniapps/meshing/mesh-optimizer.cpp | 68 ++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/fem/tmop.hpp b/fem/tmop.hpp index e0c654fb40..a2caa28039 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -839,12 +839,12 @@ protected: DiscreteAdaptTC *discr_tc; // Parameters for FD-based Gradient & Hessian calculation. - bool fdflag; + bool fdflag; + double dx; + double dxscale; // Specifies that ComputeElementTargets is being called by a FD function. // It's used to skip terms that have exact derivative calculations. bool fd_call_flag; - double dx; - double dxscale; Array ElemDer; //f'(x) Array ElemPertEnergy; //f(x+h) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 380df0c20f..1814e1684d 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -31,6 +31,11 @@ // // Compile with: make mesh-optimizer // +// Adaptive limiting: +// mesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 +// Adaptive limiting through FD (required GSLIB): +// * mesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 +// // Sample runs: // Adapted analytic Hessian: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 @@ -64,6 +69,7 @@ #include "mfem.hpp" +#include "miniapps/common/fem_extras.hpp" #include #include @@ -72,6 +78,8 @@ using namespace std; double weight_fun(const Vector &x); +double adapt_lim_fun(const Vector &x); + double ind_values(const Vector &x) { const int opt = 6; @@ -270,7 +278,9 @@ int main(int argc, char *argv[]) bool normalization = false; bool visualization = true; int verbosity_level = 0; - int fdscheme = 0; + bool fdscheme = 0; + int adapt_eval = 0; + bool adapt_lim = false; // 1. Parse command-line options. OptionsParser args(argc, argv); @@ -338,13 +348,17 @@ int main(int argc, char *argv[]) args.AddOption(&normalization, "-nor", "--normalization", "-no-nor", "--no-normalization", "Make all terms in the optimization functional unitless."); - args.AddOption(&fdscheme, "-fd", "--fd_approximation", + args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", "Enable finite difference based derivative computations."); + args.AddOption(&adapt_lim, "-al", "--adapt-limit", "no-ad", "no-adapt-limit", + "Enable adaptive limiting."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); + args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluator", + "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) { @@ -551,6 +565,37 @@ int main(int argc, char *argv[]) ConstantCoefficient lim_coeff(lim_const); if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); } + // Adaptive limiting. + GridFunction zeta_0(&ind_fes), zeta(&ind_fes); + ConstantCoefficient coef_zeta(0.5); + AdaptivityEvaluator *adapt_evaluator = NULL; + if (adapt_lim) + { + FunctionCoefficient alim_coeff(adapt_lim_fun); + zeta.ProjectCoefficient(alim_coeff); + zeta_0.ProjectCoefficient(alim_coeff); + + if (adapt_eval == 0) { adapt_evaluator = new AdvectorCG; } + else if (adapt_eval == 1) + { +#ifdef MFEM_USE_GSLIB + adapt_evaluator = new InterpolatorFP; +#else + MFEM_ABORT("MFEM is not built with GSLIB support!"); +#endif + } + else { MFEM_ABORT("Bad interpolation option."); } + + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, + *adapt_evaluator); + if (visualization) + { + socketstream vis1; + common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0", + 300, 600, 300, 300); + } + } + // 14. Setup the final NonlinearForm (which defines the integral of interest, // its first and second derivatives). Here we can use a combination of // metrics, i.e., optimize the sum of two integrals, where both are @@ -770,6 +815,13 @@ int main(int argc, char *argv[]) vis_tmop_metric_s(mesh_poly_deg, *metric, *target_c, *mesh, title, 600); } + if (adapt_lim && visualization) + { + socketstream vis0; + common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0", + 600, 600, 300, 300); + } + // 23. Visualize the mesh displacement. if (visualization) { @@ -808,3 +860,15 @@ double weight_fun(const Vector &x) + 0.5*std::tanh((r-0.23)/den) - 0.5*std::tanh((r-0.24)/den); return l2; } + +double adapt_lim_fun(const Vector &x) +{ + const double xc = x(0) - 0.1, yc = x(1) - 0.2; + const double r = sqrt(xc*xc + yc*yc); + double r1 = 0.45; double r2 = 0.55; double sf=30.0; + double val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); + + val = std::max(0.,val); + val = std::min(1.,val); + return val; +} From a95474b1e54ee2cc387a11bfa1363ddac0b0095b Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sun, 3 May 2020 01:19:08 -0700 Subject: [PATCH 272/535] Proposed updates for the 'x86' branch. --- INSTALL | 4 +- config/cmake/MFEMConfig.cmake.in | 1 + config/cmake/config.hpp.in | 3 + config/cmake/modules/MfemCmakeUtilities.cmake | 2 +- config/defaults.cmake | 1 + config/simd.hpp | 73 ++++++ config/simd/auto.hpp | 13 +- config/simd/m128.hpp | 21 +- config/simd/m256.hpp | 21 +- config/simd/m512.hpp | 21 +- config/simd/m64.hpp | 230 ------------------ config/simd/qpx.hpp | 12 +- config/simd/qpx256.hpp | 21 +- config/simd/qpx64.hpp | 224 ----------------- config/simd/vsx.hpp | 12 +- config/simd/vsx128.hpp | 21 +- config/simd/vsx64.hpp | 230 ------------------ config/simd/x86.hpp | 12 +- config/tconfig.hpp | 74 +----- fem/tbilinearform.hpp | 4 +- general/version.cpp | 3 + linalg/ttensor.hpp | 1 + makefile | 5 +- miniapps/performance/CMakeLists.txt | 1 - 24 files changed, 198 insertions(+), 812 deletions(-) create mode 100644 config/simd.hpp delete mode 100644 config/simd/m64.hpp delete mode 100644 config/simd/qpx64.hpp delete mode 100644 config/simd/vsx64.hpp diff --git a/INSTALL b/INSTALL index adbdb8d1e5..ced11c9a35 100644 --- a/INSTALL +++ b/INSTALL @@ -398,7 +398,9 @@ MFEM_USE_SIDRE = YES/NO MFEM_USE_SIMD = YES/NO Enables the high performance templated classes to use specific intrinsics - instead of the AutoSIMD (config/simd/auto.hpp) classe. + instead of the AutoSIMD (config/simd/auto.hpp) class. This option should be + combined with suitable compiler options, such as -march=native, to enable + optimal vectorization. MFEM_USE_CONDUIT = YES/NO Enables support for converting MFEM Mesh and Grid Function objects to and diff --git a/config/cmake/MFEMConfig.cmake.in b/config/cmake/MFEMConfig.cmake.in index 896e1c3510..7e98372647 100644 --- a/config/cmake/MFEMConfig.cmake.in +++ b/config/cmake/MFEMConfig.cmake.in @@ -47,6 +47,7 @@ set(MFEM_USE_OCCA @MFEM_USE_OCCA@) set(MFEM_USE_RAJA @MFEM_USE_RAJA@) set(MFEM_USE_CEED @MFEM_USE_CEED@) set(MFEM_USE_UMPIRE @MFEM_USE_UMPIRE@) +set(MFEM_USE_SIMD @MFEM_USE_SIMD@) set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@) set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@") diff --git a/config/cmake/config.hpp.in b/config/cmake/config.hpp.in index 26327ae59b..5c6fc0c0ce 100644 --- a/config/cmake/config.hpp.in +++ b/config/cmake/config.hpp.in @@ -107,6 +107,9 @@ // Enable MFEM functionality based on the Sidre library #cmakedefine MFEM_USE_SIDRE +// Enable the high performance templated classes to use SIMD +#cmakedefine MFEM_USE_SIMD + // Enable MFEM functionality based on Conduit #cmakedefine MFEM_USE_CONDUIT diff --git a/config/cmake/modules/MfemCmakeUtilities.cmake b/config/cmake/modules/MfemCmakeUtilities.cmake index 6f3428933c..5f0893d576 100644 --- a/config/cmake/modules/MfemCmakeUtilities.cmake +++ b/config/cmake/modules/MfemCmakeUtilities.cmake @@ -733,7 +733,7 @@ function(mfem_export_mk_files) MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA - MFEM_USE_UMPIRE) + MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2) foreach(var ${CONFIG_MK_BOOL_VARS}) if (${var}) set(${var} YES) diff --git a/config/defaults.cmake b/config/defaults.cmake index 5854e6916e..5703860e10 100644 --- a/config/defaults.cmake +++ b/config/defaults.cmake @@ -49,6 +49,7 @@ option(MFEM_USE_OCCA "Enable OCCA" OFF) option(MFEM_USE_RAJA "Enable RAJA" OFF) option(MFEM_USE_CEED "Enable CEED" OFF) option(MFEM_USE_UMPIRE "Enable Umpire" OFF) +option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" ON) option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF) set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests") diff --git a/config/simd.hpp b/config/simd.hpp new file mode 100644 index 0000000000..c48b69a50f --- /dev/null +++ b/config/simd.hpp @@ -0,0 +1,73 @@ +// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at +// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights +// reserved. See file COPYRIGHT for details. +// +// This file is part of the MFEM library. For more information and source code +// availability see http://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_SIMD_HPP +#define MFEM_SIMD_HPP + +#include "../config/tconfig.hpp" + +// --- AutoSIMD + specializations with intrinsics +#include "simd/auto.hpp" +#ifdef MFEM_USE_SIMD +#if defined(__VSX__) +#include "simd/vsx.hpp" +#elif defined (__bgq__) +#include "simd/qpx.hpp" +#elif defined(__x86_64__) +#include "simd/x86.hpp" +#else +#warning Unknown SIMD architecture +#endif +#endif + +// MFEM_SIMD_SIZE is the default SIMD size used by MFEM, see e.g. class +// TBilinearForm and the default traits class AutoImplTraits. +#if defined(_WIN32) +#define MFEM_SIMD_SIZE 8 +#elif defined(__AVX512F__) +#define MFEM_SIMD_SIZE 64 +#elif defined(__AVX__) || defined(__VECTOR4DOUBLE__) +#define MFEM_SIMD_SIZE 32 +#elif defined(__SSE2__) || defined(__VSX__) +#define MFEM_SIMD_SIZE 16 +#else +#define MFEM_SIMD_SIZE 8 +#endif + +// derived macros +#define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base)) +#define MFEM_ALIGN_SIZE(size,type) \ + MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type)) + +namespace mfem +{ + +template +struct AutoImplTraits +{ + static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; + + static const int align_size = MFEM_SIMD_SIZE; // in bytes + + static const int batch_size = 1; + + static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); + + static const int valign_size = simd_size; + + typedef AutoSIMD vcomplex_t; + typedef AutoSIMD vreal_t; + typedef AutoSIMD vint_t; +}; + +} // mfem namespace + +#endif // MFEM_SIMD_HPP diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index b0815d19ab..0c452f9dad 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -9,13 +9,16 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_AUTO -#define MFEM_TEMPLATE_CONFIG_SIMD_AUTO +#ifndef MFEM_SIMD_AUTO_HPP +#define MFEM_SIMD_AUTO_HPP #include "../tconfig.hpp" +namespace mfem +{ + template -struct MFEM_ALIGN_AS(align_S*sizeof(scalar_t)) AutoSIMD +struct alignas(align_S*sizeof(scalar_t)) AutoSIMD { typedef scalar_t scalar_type; static const int size = S; @@ -262,4 +265,6 @@ AutoSIMD operator/(const scalar_t &e, return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_AUTO +} // namespace mfem + +#endif // MFEM_SIMD_AUTO_HPP diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 7976300685..9f8db7ade3 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -9,15 +9,24 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M128 -#define MFEM_TEMPLATE_CONFIG_SIMD_M128 +#ifndef MFEM_SIMD_M128_HPP +#define MFEM_SIMD_M128_HPP + +#ifdef __SSE2__ #include "../tconfig.hpp" +#include + +namespace mfem +{ + +template struct AutoSIMD; template <> struct AutoSIMD { + typedef double scalar_type; static constexpr int size = 2; - static constexpr int align_size = 16; + static constexpr int align_size = 2; union { @@ -233,5 +242,9 @@ AutoSIMD operator/(const double &e, return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_M128 +} // namespace mfem + +#endif // __SSE2__ + +#endif // MFEM_SIMD_M128_HPP diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 2018921c11..9e510388fc 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -9,15 +9,24 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M256 -#define MFEM_TEMPLATE_CONFIG_SIMD_M256 +#ifndef MFEM_SIMD_M256_HPP +#define MFEM_SIMD_M256_HPP + +#ifdef __AVX__ #include "../tconfig.hpp" +#include + +namespace mfem +{ + +template struct AutoSIMD; template <> struct AutoSIMD { + typedef double scalar_type; static constexpr int size = 4; - static constexpr int align_size = 32; + static constexpr int align_size = 4; union { @@ -243,4 +252,8 @@ AutoSIMD operator/(const double &e, return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_M256 +} // namespace mfem + +#endif // __AVX__ + +#endif // MFEM_SIMD_M256_HPP diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 511fa67bb3..75096bed00 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -9,15 +9,24 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M512 -#define MFEM_TEMPLATE_CONFIG_SIMD_M512 +#ifndef MFEM_SIMD_M512_HPP +#define MFEM_SIMD_M512_HPP + +#ifdef __AVX512F__ #include "../tconfig.hpp" +#include + +namespace mfem +{ + +template struct AutoSIMD; template <> struct AutoSIMD { + typedef double scalar_type; static constexpr int size = 8; - static constexpr int align_size = 64; + static constexpr int align_size = 8; union { @@ -231,4 +240,8 @@ AutoSIMD operator/(const double &e, return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_M512 +} // namespace mfem + +#endif // __AVX512F__ + +#endif // MFEM_SIMD_M512_HPP diff --git a/config/simd/m64.hpp b/config/simd/m64.hpp deleted file mode 100644 index c30bb44fda..0000000000 --- a/config/simd/m64.hpp +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. -// -// This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. -// -// MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. - -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_M64 -#define MFEM_TEMPLATE_CONFIG_SIMD_M64 - -#include "../tconfig.hpp" - -template <> struct AutoSIMD -{ - static constexpr int size = 1; - static constexpr int align_size = 8; - - double vec[size]; - - inline MFEM_ALWAYS_INLINE double &operator[](int) - { - return vec[0]; - } - - inline MFEM_ALWAYS_INLINE const double &operator[](int) const - { - return vec[0]; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) - { - vec[0] = v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) - { - vec[0] = e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) - { - vec[0] += v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) - { - vec[0] += e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) - { - vec[0] -= v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) - { - vec[0] -= e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) - { - vec[0] *= v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) - { - vec[0] *= e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) - { - vec[0] /= v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) - { - vec[0] /= e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const - { - AutoSIMD r; - r[0] = -vec[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] + v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] + e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] - v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] - e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] * v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] * e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] / v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] / e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] += v[0] * w[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) - { - vec[0] += v[0] * e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) - { - vec[0] += e * v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] = v[0] * w[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) - { - vec[0] = v[0] * e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) - { - vec[0] = e * v[0]; - return *this; - } -}; - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e + v[0]; - return r; -} - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e - v[0]; - return r; -} - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e * v[0]; - return r; -} - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e / v[0]; - return r; -} - -#endif // MFEM_TEMPLATE_CONFIG_SIMD_M64 diff --git a/config/simd/qpx.hpp b/config/simd/qpx.hpp index 254504bfde..3e7113af3e 100644 --- a/config/simd/qpx.hpp +++ b/config/simd/qpx.hpp @@ -9,15 +9,9 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_QPX_HPP -#define MFEM_TEMPLATE_CONFIG_QPX_HPP - -#include "builtins.h" - -template struct AutoSIMD; - -#include "qpx64.hpp" +#ifndef MFEM_SIMD_QPX_HPP +#define MFEM_SIMD_QPX_HPP #include "qpx256.hpp" -#endif // MFEM_TEMPLATE_CONFIG_QPX_HPP +#endif // MFEM_SIMD_QPX_HPP diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index 328140162f..67c1c52d2c 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -9,15 +9,24 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 -#define MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 +#ifndef MFEM_SIMD_QPX_256_HPP +#define MFEM_SIMD_QPX_256_HPP + +#ifdef __bgq__ #include "../tconfig.hpp" +#include + +namespace mfem +{ + +template struct AutoSIMD; template <> struct AutoSIMD { + typedef double scalar_type; static constexpr int size = 4; - static constexpr int align_size = 32; + static constexpr int align_size = 4; union { @@ -225,4 +234,8 @@ AutoSIMD operator/(const double &e, return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_QPX_256 +} // namespace mfem + +#endif // __bgq__ + +#endif // MFEM_SIMD_QPX_256_HPP diff --git a/config/simd/qpx64.hpp b/config/simd/qpx64.hpp deleted file mode 100644 index 0b8444ec4a..0000000000 --- a/config/simd/qpx64.hpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. -// -// This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. -// -// MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. - -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 -#define MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 - -#include "../tconfig.hpp" - -template <> struct AutoSIMD -{ - static constexpr int size = 1; - static constexpr int align_size = 8; - - double vec[size]; - - inline __ATTRS_ai double &operator[](int i) { return vec[0]; } - - inline __ATTRS_ai const double &operator[](int i) const { return vec[0]; } - - inline __ATTRS_ai AutoSIMD &operator=(const AutoSIMD &v) - { - vec[0] = v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator=(const double &e) - { - vec[0] = e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const AutoSIMD &v) - { - vec[0] += v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator+=(const double &e) - { - vec[0] += e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const AutoSIMD &v) - { - vec[0] -= v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator-=(const double &e) - { - vec[0] -= e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const AutoSIMD &v) - { - vec[0] *= v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator*=(const double &e) - { - vec[0] *= e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const AutoSIMD &v) - { - vec[0] /= v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &operator/=(const double &e) - { - vec[0] /= e; - return *this; - } - - inline __ATTRS_ai AutoSIMD operator-() const - { - AutoSIMD r; - r[0] = -vec[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] + v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator+(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] + e; - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] - v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator-(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] - e; - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] * v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator*(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] * e; - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] / v[0]; - return r; - } - - inline __ATTRS_ai AutoSIMD operator/(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] / e; - return r; - } - - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] += v[0] * w[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const AutoSIMD &v, const double &e) - { - vec[0] += v[0] * e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &fma(const double &e, const AutoSIMD &v) - { - vec[0] += e * v[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] = v[0] * w[0]; - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const AutoSIMD &v, const double &e) - { - vec[0] = v[0] * e; - return *this; - } - - inline __ATTRS_ai AutoSIMD &mul(const double &e, const AutoSIMD &v) - { - vec[0] = e * v[0]; - return *this; - } -}; - -inline __ATTRS_ai -AutoSIMD operator+(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e + v[0]; - return r; -} - -inline __ATTRS_ai -AutoSIMD operator-(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e - v[0]; - return r; -} - -inline __ATTRS_ai -AutoSIMD operator*(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e * v[0]; - return r; -} - -inline __ATTRS_ai -AutoSIMD operator/(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e / v[0]; - return r; -} - -#endif // MFEM_TEMPLATE_CONFIG_SIMD_QPX_64 diff --git a/config/simd/vsx.hpp b/config/simd/vsx.hpp index 365f8b95eb..2ac29453a4 100644 --- a/config/simd/vsx.hpp +++ b/config/simd/vsx.hpp @@ -9,15 +9,9 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_VSX_HPP -#define MFEM_TEMPLATE_CONFIG_VSX_HPP - -#include "altivec.h" - -template struct AutoSIMD; - -#include "vsx64.hpp" +#ifndef MFEM_SIMD_VSX_HPP +#define MFEM_SIMD_VSX_HPP #include "vsx128.hpp" -#endif // MFEM_TEMPLATE_CONFIG_VSX_HPP +#endif // MFEM_SIMD_VSX_HPP diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp index 0ed0072a91..1010fac762 100644 --- a/config/simd/vsx128.hpp +++ b/config/simd/vsx128.hpp @@ -9,15 +9,24 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX128 -#define MFEM_TEMPLATE_CONFIG_SIMD_VSX128 +#ifndef MFEM_SIMD_VSX128_HPP +#define MFEM_SIMD_VSX128_HPP + +#ifdef __VSX__ #include "../tconfig.hpp" +#include + +namespace mfem +{ + +template struct AutoSIMD; template <> struct AutoSIMD { + typedef double scalar_type; static constexpr int size = 2; - static constexpr int align_size = 16; + static constexpr int align_size = 2; union { @@ -231,4 +240,8 @@ AutoSIMD operator/(const double &e, return r; } -#endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX128 +} // namespace mfem + +#endif // __VSX__ + +#endif // MFEM_SIMD_VSX128_HPP diff --git a/config/simd/vsx64.hpp b/config/simd/vsx64.hpp deleted file mode 100644 index e5d208711d..0000000000 --- a/config/simd/vsx64.hpp +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. -// -// This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. -// -// MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. - -#ifndef MFEM_TEMPLATE_CONFIG_SIMD_VSX64 -#define MFEM_TEMPLATE_CONFIG_SIMD_VSX64 - -#include "../tconfig.hpp" - -template <> struct AutoSIMD -{ - static constexpr int size = 1; - static constexpr int align_size = 8; - - double vec[size]; - - inline MFEM_ALWAYS_INLINE double &operator[](int i) - { - return vec[0]; - } - - inline MFEM_ALWAYS_INLINE const double &operator[](int i) const - { - return vec[0]; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v) - { - vec[0] = v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e) - { - vec[0] = e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v) - { - vec[0] += v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e) - { - vec[0] += e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v) - { - vec[0] -= v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e) - { - vec[0] -= e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v) - { - vec[0] *= v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e) - { - vec[0] *= e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v) - { - vec[0] /= v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e) - { - vec[0] /= e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const - { - AutoSIMD r; - r[0] = -vec[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] + v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] + e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] - v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] - e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] * v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] * e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const - { - AutoSIMD r; - r[0] = vec[0] / v[0]; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const - { - AutoSIMD r; - r[0] = vec[0] / e; - return r; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] += v[0] * w[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e) - { - vec[0] += v[0] * e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v) - { - vec[0] += e * v[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w) - { - vec[0] = v[0] * w[0]; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e) - { - vec[0] = v[0] * e; - return *this; - } - - inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v) - { - vec[0] = e * v[0]; - return *this; - } -}; - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e + v[0]; - return r; -} - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e - v[0]; - return r; -} - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e * v[0]; - return r; -} - -inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) -{ - AutoSIMD r; - r[0] = e / v[0]; - return r; -} - -#endif // MFEM_TEMPLATE_CONFIG_SIMD_VSX64 diff --git a/config/simd/x86.hpp b/config/simd/x86.hpp index 1920934f99..a26dd88bd2 100644 --- a/config/simd/x86.hpp +++ b/config/simd/x86.hpp @@ -9,14 +9,8 @@ // terms of the GNU Lesser General Public License (as published by the Free // Software Foundation) version 2.1 dated February 1999. -#ifndef MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP -#define MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP - -#include "x86intrin.h" - -template struct AutoSIMD; - -#include "m64.hpp" +#ifndef MFEM_SIMD_X86_HPP +#define MFEM_SIMD_X86_HPP #include "m128.hpp" @@ -24,4 +18,4 @@ template struct AutoSIMD; #include "m512.hpp" -#endif // MFEM_TEMPLATE_CONFIG_X86INTRIN_HPP +#endif // MFEM_SIMD_X86_HPP diff --git a/config/tconfig.hpp b/config/tconfig.hpp index 27f9af0c7b..a10ae8f4b6 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -37,72 +37,11 @@ #define MFEM_VECTORIZE_LOOP #endif -// --- MFEM_ALIGN_AS -#if (__cplusplus >= 201103L) -#define MFEM_ALIGN_AS(bytes) alignas(bytes) -#elif !defined(MFEM_DEBUG) && (defined(__GNUC__) || defined(__clang__)) -#define MFEM_ALIGN_AS(bytes) __attribute__ ((aligned (bytes))) -#else -#define MFEM_ALIGN_AS(bytes) -#endif - -// --- AutoSIMD or intrinsics -#ifndef MFEM_USE_SIMD -#include "simd/auto.hpp" -#else -#if defined(__VSX__) -#include "simd/vsx.hpp" -#elif defined (__bgq__) -#include "simd/qpx.hpp" -#elif defined(__x86_64__) -#include "simd/x86.hpp" -#else -#error Unknown SIMD architecture -#endif -#endif - -// --- SIMD and BLOCK sizes -#if defined(_WIN32) -#define MFEM_SIMD_SIZE 8 -#define MFEM_TEMPLATE_BLOCK_SIZE 1 -#elif defined(__AVX512F__) -#define MFEM_SIMD_SIZE 64 -#define MFEM_TEMPLATE_BLOCK_SIZE 8 -#elif defined(__AVX__) || defined(__VECTOR4DOUBLE__) -#define MFEM_SIMD_SIZE 32 +// MFEM_TEMPLATE_BLOCK_SIZE is the block size used by the template matrix-matrix +// multiply, Mult_AB, defined in tmatrix.hpp. This parameter will generally +// require tuning to determine good value. It is probably highly influenced by +// the SIMD width when Mult_AB is used with a SIMD type like AutoSIMD. #define MFEM_TEMPLATE_BLOCK_SIZE 4 -#elif defined(__SSE2__) || defined(__VSX__) -#define MFEM_SIMD_SIZE 16 -#define MFEM_TEMPLATE_BLOCK_SIZE 2 -#else -#define MFEM_SIMD_SIZE 8 -#define MFEM_TEMPLATE_BLOCK_SIZE 1 -#endif - -namespace mfem -{ - -template -struct AutoImplTraits -{ - static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; - - static const int align_size = MFEM_SIMD_SIZE; // in bytes - - static const int batch_size = 1; - - static const int simd_size = simd ? (MFEM_SIMD_SIZE/sizeof(complex_t)) : 1; - - static const int valign_size = simd ? simd_size : 1; - - typedef AutoSIMD vcomplex_t; - typedef AutoSIMD vreal_t; -#ifndef MFEM_USE_SIMD - typedef AutoSIMD vint_t; -#endif // MFEM_USE_SIMD -}; - -} // mfem namespace #define MFEM_TEMPLATE_ENABLE_SERIALIZE @@ -111,11 +50,6 @@ struct AutoImplTraits // #define MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS #define MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP -// derived macros -#define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base)) -#define MFEM_ALIGN_SIZE(size,type) \ - MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type)) - #ifdef MFEM_COUNT_FLOPS namespace mfem { diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 85843590ee..e493d38423 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -13,6 +13,7 @@ #define MFEM_TEMPLATE_BILINEAR_FORM #include "../config/tconfig.hpp" +#include "../config/simd.hpp" #include "../linalg/ttensor.hpp" #include "bilinearform.hpp" #include "tevaluator.hpp" @@ -29,10 +30,9 @@ namespace mfem // real_t - mesh nodes, sol basis, mesh basis data type template > + typename impl_traits_t = AutoImplTraits > class TBilinearForm : public Operator { public: diff --git a/general/version.cpp b/general/version.cpp index 19c5fecca5..704d9beead 100644 --- a/general/version.cpp +++ b/general/version.cpp @@ -148,6 +148,9 @@ const char *GetConfigStr() #ifdef MFEM_USE_OCCA "MFEM_USE_OCCA\n" #endif +#ifdef MFEM_USE_SIMD + "MFEM_USE_SIMD\n" +#endif #ifdef MFEM_USE_ADIOS2 "MFEM_USE_ADIOS2\n" #endif diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index 42d1ffaddd..c06b162af3 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -13,6 +13,7 @@ #define MFEM_TEMPLATE_TENSOR #include "../config/tconfig.hpp" +#include "../config/simd.hpp" #include "../general/tassign.hpp" #include "tlayout.hpp" #include "tmatrix.hpp" diff --git a/makefile b/makefile index 6e3dc761dc..25da0f07ca 100644 --- a/makefile +++ b/makefile @@ -322,8 +322,8 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\ MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS\ MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT\ MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\ - MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_SOURCE_DIR\ - MFEM_INSTALL_DIR MFEM_USE_SIMD + MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD\ + MFEM_USE_ADIOS2 MFEM_SOURCE_DIR MFEM_INSTALL_DIR # List of makefile variables that will be written to config.mk: MFEM_CONFIG_VARS = MFEM_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS MFEM_INC_DIR\ @@ -645,6 +645,7 @@ status info: $(info MFEM_USE_CEED = $(MFEM_USE_CEED)) $(info MFEM_USE_UMPIRE = $(MFEM_USE_UMPIRE)) $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) + $(info MFEM_USE_ADIOS2 = $(MFEM_USE_ADIOS2)) $(info MFEM_CXX = $(value MFEM_CXX)) $(info MFEM_CPPFLAGS = $(value MFEM_CPPFLAGS)) $(info MFEM_CXXFLAGS = $(value MFEM_CXXFLAGS)) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 168ff72dab..5494256400 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -24,7 +24,6 @@ if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") "-fcolor-diagnostics" "-fvectorize" "-fslp-vectorize" - "-fslp-vectorize-aggressive" "-ffp-contract=fast") elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") list(APPEND PERFORMANCE_CXX_OPTIONS From 00d182618febc357ddc1ada3f31e4edcfad88234 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 15:42:18 -0700 Subject: [PATCH 273/535] Improved the interface. --- fem/tmop.cpp | 31 +++++++++++++++++++--------- fem/tmop.hpp | 18 ++++------------ miniapps/meshing/mesh-optimizer.cpp | 8 +++---- miniapps/meshing/pmesh-optimizer.cpp | 10 ++++----- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index aacb5e8864..d0810f906b 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1202,6 +1202,17 @@ AdaptivityEvaluator::~AdaptivityEvaluator() #endif } +TMOP_Integrator::~TMOP_Integrator() +{ + delete lim_func; + delete zeta; + for (int i = 0; i < ElemDer.Size(); i++) + { + delete ElemDer[i]; + delete ElemPertEnergy[i]; + } +} + void TMOP_Integrator::EnableLimiting(const GridFunction &n0, const GridFunction &dist, Coefficient &w0, TMOP_LimiterFunction *lfunc) @@ -1227,13 +1238,13 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, } } -void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &zeta0_gf, - GridFunction &zeta_gf, +void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ad) { - zeta_0 = &zeta0_gf; - zeta = &zeta_gf; + zeta_0 = &z0; + delete zeta; + zeta = new GridFunction(z0); coeff_zeta = &coeff; adapt_eval = &ad; @@ -1243,18 +1254,18 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &zeta0_gf, (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } -void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, - ParGridFunction &zeta_gf, +void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ad) { - zeta_0 = &zeta0_gf; - zeta = &zeta_gf; + zeta_0 = &z0; + delete zeta; + zeta = new GridFunction(z0); coeff_zeta = &coeff; adapt_eval = &ad; - adapt_eval->SetParMetaInfo(*zeta_gf.ParFESpace()->GetParMesh(), - *zeta_gf.ParFESpace()->FEColl(), 1); + adapt_eval->SetParMetaInfo(*z0.ParFESpace()->GetParMesh(), + *z0.ParFESpace()->FEColl(), 1); adapt_eval->SetInitialField (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index a2caa28039..4446d29899 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -832,7 +832,7 @@ protected: // Adaptive limiting. const GridFunction *zeta_0; // Not owned. - GridFunction *zeta; // Not owned. + GridFunction *zeta; // Owned. Updated by adapt_eval. Coefficient *coeff_zeta; // Not owned. AdaptivityEvaluator *adapt_eval; // Not owned. @@ -937,15 +937,7 @@ public: fdflag(false), fd_call_flag(false), dxscale(1.0e3) { } - ~TMOP_Integrator() - { - delete lim_func; - for (int i = 0; i < ElemDer.Size(); i++) - { - delete ElemDer[i]; - delete ElemPertEnergy[i]; - } - } + ~TMOP_Integrator(); /// Sets a scaling Coefficient for the quality metric term of the integrator. /** With this addition, the integrator becomes @@ -974,12 +966,10 @@ public: void EnableLimiting(const GridFunction &n0, Coefficient &w0, TMOP_LimiterFunction *lfunc = NULL); - void EnableAdaptiveLimiting(const GridFunction &zeta0_gf, - GridFunction &zeta_gf, Coefficient &coeff, + void EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ad); #ifdef MFEM_USE_MPI - void EnableAdaptiveLimiting(const ParGridFunction &zeta0_gf, - ParGridFunction &zeta_gf, Coefficient &coeff, + void EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ad); #endif diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 1814e1684d..57d43cae9e 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -33,7 +33,7 @@ // // Adaptive limiting: // mesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 -// Adaptive limiting through FD (required GSLIB): +// Adaptive limiting through FD (requires GSLIB): // * mesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 // // Sample runs: @@ -566,13 +566,12 @@ int main(int argc, char *argv[]) if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); } // Adaptive limiting. - GridFunction zeta_0(&ind_fes), zeta(&ind_fes); + GridFunction zeta_0(&ind_fes); ConstantCoefficient coef_zeta(0.5); AdaptivityEvaluator *adapt_evaluator = NULL; if (adapt_lim) { FunctionCoefficient alim_coeff(adapt_lim_fun); - zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); if (adapt_eval == 0) { adapt_evaluator = new AdvectorCG; } @@ -586,8 +585,7 @@ int main(int argc, char *argv[]) } else { MFEM_ABORT("Bad interpolation option."); } - he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, - *adapt_evaluator); + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, coef_zeta, *adapt_evaluator); if (visualization) { socketstream vis1; diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 9b4e7d1729..97a55b235a 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -33,7 +33,7 @@ // // Adaptive limiting: // mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 -// Adaptive limiting through FD (required GSLIB): +// Adaptive limiting through FD (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 // // Sample runs: @@ -364,7 +364,7 @@ int main (int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); - args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluatior", + args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluator", "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) @@ -601,13 +601,12 @@ int main (int argc, char *argv[]) if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); } // Adaptive limiting. - ParGridFunction zeta_0(&ind_fes), zeta(&ind_fes); + ParGridFunction zeta_0(&ind_fes); ConstantCoefficient coef_zeta(0.5); AdaptivityEvaluator *adapt_evaluator = NULL; if (adapt_lim) { FunctionCoefficient alim_coeff(adapt_lim_fun); - zeta.ProjectCoefficient(alim_coeff); zeta_0.ProjectCoefficient(alim_coeff); if (adapt_eval == 0) { adapt_evaluator = new AdvectorCG; } @@ -621,8 +620,7 @@ int main (int argc, char *argv[]) } else { MFEM_ABORT("Bad interpolation option."); } - he_nlf_integ->EnableAdaptiveLimiting(zeta_0, zeta, coef_zeta, - *adapt_evaluator); + he_nlf_integ->EnableAdaptiveLimiting(zeta_0, coef_zeta, *adapt_evaluator); if (visualization) { socketstream vis1; From 53006001ceda8d979cd3bd64ebda90cca07f3484 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 15:44:16 -0700 Subject: [PATCH 274/535] Added a testing mesh. --- miniapps/meshing/mesh-optimizer.cpp | 4 +- miniapps/meshing/pmesh-optimizer.cpp | 4 +- miniapps/meshing/stretched2D.mesh | 930 +++++++++++++++++++++++++++ 3 files changed, 934 insertions(+), 4 deletions(-) create mode 100644 miniapps/meshing/stretched2D.mesh diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 57d43cae9e..6ab774de96 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make mesh-optimizer // // Adaptive limiting: -// mesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 +// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 // Adaptive limiting through FD (requires GSLIB): -// * mesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 +// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 97a55b235a..9ec77e38b3 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 +// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 // Adaptive limiting through FD (requires GSLIB): -// * mpirun -np 4 pmesh-optimizer -m adaptivity_2.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: diff --git a/miniapps/meshing/stretched2D.mesh b/miniapps/meshing/stretched2D.mesh new file mode 100644 index 0000000000..6fab492c72 --- /dev/null +++ b/miniapps/meshing/stretched2D.mesh @@ -0,0 +1,930 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# PRISM = 6 +# + +dimension +2 + +elements +256 +1 3 0 81 225 84 +1 3 81 25 82 225 +1 3 225 82 65 83 +1 3 84 225 83 28 +1 3 25 85 226 82 +1 3 85 1 86 226 +1 3 226 86 26 87 +1 3 82 226 87 65 +1 3 65 87 227 90 +1 3 87 26 88 227 +1 3 227 88 6 89 +1 3 90 227 89 27 +1 3 28 83 228 92 +1 3 83 65 90 228 +1 3 228 90 27 91 +1 3 92 228 91 5 +1 3 1 93 229 86 +1 3 93 29 94 229 +1 3 229 94 66 95 +1 3 86 229 95 26 +1 3 29 96 230 94 +1 3 96 2 97 230 +1 3 230 97 30 98 +1 3 94 230 98 66 +1 3 66 98 231 101 +1 3 98 30 99 231 +1 3 231 99 7 100 +1 3 101 231 100 31 +1 3 26 95 232 88 +1 3 95 66 101 232 +1 3 232 101 31 102 +1 3 88 232 102 6 +1 3 2 103 233 97 +1 3 103 32 104 233 +1 3 233 104 67 105 +1 3 97 233 105 30 +1 3 32 106 234 104 +1 3 106 3 107 234 +1 3 234 107 33 108 +1 3 104 234 108 67 +1 3 67 108 235 111 +1 3 108 33 109 235 +1 3 235 109 8 110 +1 3 111 235 110 34 +1 3 30 105 236 99 +1 3 105 67 111 236 +1 3 236 111 34 112 +1 3 99 236 112 7 +1 3 3 113 237 107 +1 3 113 35 114 237 +1 3 237 114 68 115 +1 3 107 237 115 33 +1 3 35 116 238 114 +1 3 116 4 117 238 +1 3 238 117 36 118 +1 3 114 238 118 68 +1 3 68 118 239 121 +1 3 118 36 119 239 +1 3 239 119 9 120 +1 3 121 239 120 37 +1 3 33 115 240 109 +1 3 115 68 121 240 +1 3 240 121 37 122 +1 3 109 240 122 8 +1 3 5 91 241 125 +1 3 91 27 123 241 +1 3 241 123 69 124 +1 3 125 241 124 40 +1 3 27 89 242 123 +1 3 89 6 126 242 +1 3 242 126 38 127 +1 3 123 242 127 69 +1 3 69 127 243 130 +1 3 127 38 128 243 +1 3 243 128 11 129 +1 3 130 243 129 39 +1 3 40 124 244 132 +1 3 124 69 130 244 +1 3 244 130 39 131 +1 3 132 244 131 10 +1 3 6 102 245 126 +1 3 102 31 133 245 +1 3 245 133 70 134 +1 3 126 245 134 38 +1 3 31 100 246 133 +1 3 100 7 135 246 +1 3 246 135 41 136 +1 3 133 246 136 70 +1 3 70 136 247 139 +1 3 136 41 137 247 +1 3 247 137 12 138 +1 3 139 247 138 42 +1 3 38 134 248 128 +1 3 134 70 139 248 +1 3 248 139 42 140 +1 3 128 248 140 11 +1 3 7 112 249 135 +1 3 112 34 141 249 +1 3 249 141 71 142 +1 3 135 249 142 41 +1 3 34 110 250 141 +1 3 110 8 143 250 +1 3 250 143 43 144 +1 3 141 250 144 71 +1 3 71 144 251 147 +1 3 144 43 145 251 +1 3 251 145 13 146 +1 3 147 251 146 44 +1 3 41 142 252 137 +1 3 142 71 147 252 +1 3 252 147 44 148 +1 3 137 252 148 12 +1 3 8 122 253 143 +1 3 122 37 149 253 +1 3 253 149 72 150 +1 3 143 253 150 43 +1 3 37 120 254 149 +1 3 120 9 151 254 +1 3 254 151 45 152 +1 3 149 254 152 72 +1 3 72 152 255 155 +1 3 152 45 153 255 +1 3 255 153 14 154 +1 3 155 255 154 46 +1 3 43 150 256 145 +1 3 150 72 155 256 +1 3 256 155 46 156 +1 3 145 256 156 13 +1 3 10 131 257 159 +1 3 131 39 157 257 +1 3 257 157 73 158 +1 3 159 257 158 49 +1 3 39 129 258 157 +1 3 129 11 160 258 +1 3 258 160 47 161 +1 3 157 258 161 73 +1 3 73 161 259 164 +1 3 161 47 162 259 +1 3 259 162 16 163 +1 3 164 259 163 48 +1 3 49 158 260 166 +1 3 158 73 164 260 +1 3 260 164 48 165 +1 3 166 260 165 15 +1 3 11 140 261 160 +1 3 140 42 167 261 +1 3 261 167 74 168 +1 3 160 261 168 47 +1 3 42 138 262 167 +1 3 138 12 169 262 +1 3 262 169 50 170 +1 3 167 262 170 74 +1 3 74 170 263 173 +1 3 170 50 171 263 +1 3 263 171 17 172 +1 3 173 263 172 51 +1 3 47 168 264 162 +1 3 168 74 173 264 +1 3 264 173 51 174 +1 3 162 264 174 16 +1 3 12 148 265 169 +1 3 148 44 175 265 +1 3 265 175 75 176 +1 3 169 265 176 50 +1 3 44 146 266 175 +1 3 146 13 177 266 +1 3 266 177 52 178 +1 3 175 266 178 75 +1 3 75 178 267 181 +1 3 178 52 179 267 +1 3 267 179 18 180 +1 3 181 267 180 53 +1 3 50 176 268 171 +1 3 176 75 181 268 +1 3 268 181 53 182 +1 3 171 268 182 17 +1 3 13 156 269 177 +1 3 156 46 183 269 +1 3 269 183 76 184 +1 3 177 269 184 52 +1 3 46 154 270 183 +1 3 154 14 185 270 +1 3 270 185 54 186 +1 3 183 270 186 76 +1 3 76 186 271 189 +1 3 186 54 187 271 +1 3 271 187 19 188 +1 3 189 271 188 55 +1 3 52 184 272 179 +1 3 184 76 189 272 +1 3 272 189 55 190 +1 3 179 272 190 18 +1 3 15 165 273 193 +1 3 165 48 191 273 +1 3 273 191 77 192 +1 3 193 273 192 58 +1 3 48 163 274 191 +1 3 163 16 194 274 +1 3 274 194 56 195 +1 3 191 274 195 77 +1 3 77 195 275 198 +1 3 195 56 196 275 +1 3 275 196 21 197 +1 3 198 275 197 57 +1 3 58 192 276 200 +1 3 192 77 198 276 +1 3 276 198 57 199 +1 3 200 276 199 20 +1 3 16 174 277 194 +1 3 174 51 201 277 +1 3 277 201 78 202 +1 3 194 277 202 56 +1 3 51 172 278 201 +1 3 172 17 203 278 +1 3 278 203 59 204 +1 3 201 278 204 78 +1 3 78 204 279 207 +1 3 204 59 205 279 +1 3 279 205 22 206 +1 3 207 279 206 60 +1 3 56 202 280 196 +1 3 202 78 207 280 +1 3 280 207 60 208 +1 3 196 280 208 21 +1 3 17 182 281 203 +1 3 182 53 209 281 +1 3 281 209 79 210 +1 3 203 281 210 59 +1 3 53 180 282 209 +1 3 180 18 211 282 +1 3 282 211 61 212 +1 3 209 282 212 79 +1 3 79 212 283 215 +1 3 212 61 213 283 +1 3 283 213 23 214 +1 3 215 283 214 62 +1 3 59 210 284 205 +1 3 210 79 215 284 +1 3 284 215 62 216 +1 3 205 284 216 22 +1 3 18 190 285 211 +1 3 190 55 217 285 +1 3 285 217 80 218 +1 3 211 285 218 61 +1 3 55 188 286 217 +1 3 188 19 219 286 +1 3 286 219 63 220 +1 3 217 286 220 80 +1 3 80 220 287 223 +1 3 220 63 221 287 +1 3 287 221 24 222 +1 3 223 287 222 64 +1 3 61 218 288 213 +1 3 218 80 223 288 +1 3 288 223 64 224 +1 3 213 288 224 23 + +boundary +64 +2 1 0 81 +2 1 81 25 +2 1 25 85 +2 1 85 1 +2 1 1 93 +2 1 93 29 +2 1 29 96 +2 1 96 2 +2 1 2 103 +2 1 103 32 +2 1 32 106 +2 1 106 3 +2 1 3 113 +2 1 113 35 +2 1 35 116 +2 1 116 4 +2 1 21 197 +2 1 197 57 +2 1 57 199 +2 1 199 20 +2 1 22 206 +2 1 206 60 +2 1 60 208 +2 1 208 21 +2 1 23 214 +2 1 214 62 +2 1 62 216 +2 1 216 22 +2 1 24 222 +2 1 222 64 +2 1 64 224 +2 1 224 23 +1 1 5 92 +1 1 92 28 +1 1 28 84 +1 1 84 0 +1 1 10 132 +1 1 132 40 +1 1 40 125 +1 1 125 5 +1 1 15 166 +1 1 166 49 +1 1 49 159 +1 1 159 10 +1 1 20 200 +1 1 200 58 +1 1 58 193 +1 1 193 15 +1 1 4 117 +1 1 117 36 +1 1 36 119 +1 1 119 9 +1 1 9 151 +1 1 151 45 +1 1 45 153 +1 1 153 14 +1 1 14 185 +1 1 185 54 +1 1 54 187 +1 1 187 19 +1 1 19 219 +1 1 219 63 +1 1 63 221 +1 1 221 24 + +vertices +289 + +nodes +FiniteElementSpace +FiniteElementCollection: H1_2D_P1 +VDim: 2 +Ordering: 0 + +0 +0.25 +0.5 +0.75 +1 +0 +0.25 +0.5 +0.75 +1 +0 +0.25 +0.5 +0.75 +1 +0 +0.25 +0.5 +0.75 +1 +0 +0.25 +0.5 +0.75 +1 +0.125 +0.25 +0.125 +0 +0.375 +0.5 +0.375 +0.625 +0.75 +0.625 +0.875 +1 +0.875 +0.25 +0.125 +0 +0.5 +0.375 +0.75 +0.625 +1 +0.875 +0.25 +0.125 +0 +0.5 +0.375 +0.75 +0.625 +1 +0.875 +0.25 +0.125 +0 +0.5 +0.375 +0.75 +0.625 +1 +0.875 +0.125 +0.375 +0.625 +0.875 +0.125 +0.375 +0.625 +0.875 +0.125 +0.375 +0.625 +0.875 +0.125 +0.375 +0.625 +0.875 +0.0625 +0.125 +0.0625 +0 +0.1875 +0.25 +0.1875 +0.25 +0.1875 +0.125 +0.0625 +0 +0.3125 +0.375 +0.3125 +0.4375 +0.5 +0.4375 +0.5 +0.4375 +0.375 +0.3125 +0.5625 +0.625 +0.5625 +0.6875 +0.75 +0.6875 +0.75 +0.6875 +0.625 +0.5625 +0.8125 +0.875 +0.8125 +0.9375 +1 +0.9375 +1 +0.9375 +0.875 +0.8125 +0.125 +0.0625 +0 +0.25 +0.1875 +0.25 +0.1875 +0.125 +0.0625 +0 +0.375 +0.3125 +0.5 +0.4375 +0.5 +0.4375 +0.375 +0.3125 +0.625 +0.5625 +0.75 +0.6875 +0.75 +0.6875 +0.625 +0.5625 +0.875 +0.8125 +1 +0.9375 +1 +0.9375 +0.875 +0.8125 +0.125 +0.0625 +0 +0.25 +0.1875 +0.25 +0.1875 +0.125 +0.0625 +0 +0.375 +0.3125 +0.5 +0.4375 +0.5 +0.4375 +0.375 +0.3125 +0.625 +0.5625 +0.75 +0.6875 +0.75 +0.6875 +0.625 +0.5625 +0.875 +0.8125 +1 +0.9375 +1 +0.9375 +0.875 +0.8125 +0.125 +0.0625 +0 +0.25 +0.1875 +0.25 +0.1875 +0.125 +0.0625 +0 +0.375 +0.3125 +0.5 +0.4375 +0.5 +0.4375 +0.375 +0.3125 +0.625 +0.5625 +0.75 +0.6875 +0.75 +0.6875 +0.625 +0.5625 +0.875 +0.8125 +1 +0.9375 +1 +0.9375 +0.875 +0.8125 +0.0625 +0.1875 +0.1875 +0.0625 +0.3125 +0.4375 +0.4375 +0.3125 +0.5625 +0.6875 +0.6875 +0.5625 +0.8125 +0.9375 +0.9375 +0.8125 +0.0625 +0.1875 +0.1875 +0.0625 +0.3125 +0.4375 +0.4375 +0.3125 +0.5625 +0.6875 +0.6875 +0.5625 +0.8125 +0.9375 +0.9375 +0.8125 +0.0625 +0.1875 +0.1875 +0.0625 +0.3125 +0.4375 +0.4375 +0.3125 +0.5625 +0.6875 +0.6875 +0.5625 +0.8125 +0.9375 +0.9375 +0.8125 +0.0625 +0.1875 +0.1875 +0.0625 +0.3125 +0.4375 +0.4375 +0.3125 +0.5625 +0.6875 +0.6875 +0.5625 +0.8125 +0.9375 +0.9375 +0.8125 +0 +0 +0 +0 +0 +0.015625 +0.015625 +0.015625 +0.015625 +0.015625 +0.125 +0.125 +0.125 +0.125 +0.125 +0.421875 +0.421875 +0.421875 +0.421875 +0.421875 +1 +1 +1 +1 +1 +0 +0.001953125 +0.015625 +0.001953125 +0 +0.001953125 +0.015625 +0 +0.001953125 +0.015625 +0 +0.001953125 +0.015625 +0.052734375 +0.125 +0.052734375 +0.052734375 +0.125 +0.052734375 +0.125 +0.052734375 +0.125 +0.24414062 +0.421875 +0.24414062 +0.24414062 +0.421875 +0.24414062 +0.421875 +0.24414062 +0.421875 +0.66992188 +1 +0.66992188 +0.66992188 +1 +0.66992188 +1 +0.66992188 +1 +0.001953125 +0.001953125 +0.001953125 +0.001953125 +0.052734375 +0.052734375 +0.052734375 +0.052734375 +0.24414062 +0.24414062 +0.24414062 +0.24414062 +0.66992188 +0.66992188 +0.66992188 +0.66992188 +0 +0.00024414062 +0.001953125 +0.00024414062 +0 +0.00024414062 +0.001953125 +0.0065917969 +0.015625 +0.0065917969 +0.015625 +0.0065917969 +0 +0.00024414062 +0.001953125 +0 +0.00024414062 +0.001953125 +0.0065917969 +0.015625 +0.0065917969 +0.015625 +0 +0.00024414062 +0.001953125 +0 +0.00024414062 +0.001953125 +0.0065917969 +0.015625 +0.0065917969 +0.015625 +0 +0.00024414062 +0.001953125 +0 +0.00024414062 +0.001953125 +0.0065917969 +0.015625 +0.0065917969 +0.015625 +0.030517578 +0.052734375 +0.030517578 +0.030517578 +0.052734375 +0.083740234 +0.125 +0.083740234 +0.125 +0.083740234 +0.030517578 +0.052734375 +0.030517578 +0.052734375 +0.083740234 +0.125 +0.083740234 +0.125 +0.030517578 +0.052734375 +0.030517578 +0.052734375 +0.083740234 +0.125 +0.083740234 +0.125 +0.030517578 +0.052734375 +0.030517578 +0.052734375 +0.083740234 +0.125 +0.083740234 +0.125 +0.17797852 +0.24414062 +0.17797852 +0.17797852 +0.24414062 +0.32495117 +0.421875 +0.32495117 +0.421875 +0.32495117 +0.17797852 +0.24414062 +0.17797852 +0.24414062 +0.32495117 +0.421875 +0.32495117 +0.421875 +0.17797852 +0.24414062 +0.17797852 +0.24414062 +0.32495117 +0.421875 +0.32495117 +0.421875 +0.17797852 +0.24414062 +0.17797852 +0.24414062 +0.32495117 +0.421875 +0.32495117 +0.421875 +0.53637695 +0.66992188 +0.53637695 +0.53637695 +0.66992188 +0.82397461 +1 +0.82397461 +1 +0.82397461 +0.53637695 +0.66992188 +0.53637695 +0.66992188 +0.82397461 +1 +0.82397461 +1 +0.53637695 +0.66992188 +0.53637695 +0.66992188 +0.82397461 +1 +0.82397461 +1 +0.53637695 +0.66992188 +0.53637695 +0.66992188 +0.82397461 +1 +0.82397461 +1 +0.00024414062 +0.00024414062 +0.0065917969 +0.0065917969 +0.00024414062 +0.00024414062 +0.0065917969 +0.0065917969 +0.00024414062 +0.00024414062 +0.0065917969 +0.0065917969 +0.00024414062 +0.00024414062 +0.0065917969 +0.0065917969 +0.030517578 +0.030517578 +0.083740234 +0.083740234 +0.030517578 +0.030517578 +0.083740234 +0.083740234 +0.030517578 +0.030517578 +0.083740234 +0.083740234 +0.030517578 +0.030517578 +0.083740234 +0.083740234 +0.17797852 +0.17797852 +0.32495117 +0.32495117 +0.17797852 +0.17797852 +0.32495117 +0.32495117 +0.17797852 +0.17797852 +0.32495117 +0.32495117 +0.17797852 +0.17797852 +0.32495117 +0.32495117 +0.53637695 +0.53637695 +0.82397461 +0.82397461 +0.53637695 +0.53637695 +0.82397461 +0.82397461 +0.53637695 +0.53637695 +0.82397461 +0.82397461 +0.53637695 +0.53637695 +0.82397461 +0.82397461 From d61ba836114f25d7c85f6bceeb8f2d3b66722615 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 16:40:51 -0700 Subject: [PATCH 275/535] Doxygen improvements. --- fem/tmop.cpp | 8 ++++---- fem/tmop.hpp | 34 +++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index d0810f906b..0fef70d70a 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1240,13 +1240,13 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0, void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff, - AdaptivityEvaluator &ad) + AdaptivityEvaluator &ae) { zeta_0 = &z0; delete zeta; zeta = new GridFunction(z0); coeff_zeta = &coeff; - adapt_eval = &ad; + adapt_eval = &ae; adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(), *zeta->FESpace()->FEColl(), 1); @@ -1256,13 +1256,13 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0, void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff, - AdaptivityEvaluator &ad) + AdaptivityEvaluator &ae) { zeta_0 = &z0; delete zeta; zeta = new GridFunction(z0); coeff_zeta = &coeff; - adapt_eval = &ad; + adapt_eval = &ae; adapt_eval->SetParMetaInfo(*z0.ParFESpace()->GetParMesh(), *z0.ParFESpace()->FEColl(), 1); diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 4446d29899..12f0c6dc7d 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -947,15 +947,15 @@ public: not in the target configuration which may be undefined. */ void SetCoefficient(Coefficient &w1) { coeff1 = &w1; } - /// Adds a limiting term to the integrator (general version). - /** With this addition, the integrator becomes - @f$ \int w1 W(Jpt) + w0 f(x, x_0, d) dx @f$, - where the second term measures the change with respect to the original - physical positions, @a n0. - @param[in] n0 Original mesh node coordinates. - @param[in] dist Limiting physical distances. - @param[in] w0 Coefficient scaling the limiting term. - @param[in] lfunc TMOP_LimiterFunction defining the limiting term f. If + /** @brief Limiting of the mesh displacements (general version). + + Adds the term @f$ \int w_0 f(x, x_0, d) dx @f$, where f is a measure of + the displacement between x and x_0, given the max allowed displacement d. + + @param[in] n0 Original mesh node coordinates (x0 above). + @param[in] dist Allowed displacement in physical space (d above). + @param[in] w0 Coefficient scaling the limiting integral. + @param[in] lfunc TMOP_LimiterFunction defining the function f. If NULL, a TMOP_QuadraticLimiter will be used. The TMOP_Integrator assumes ownership of this pointer. */ void EnableLimiting(const GridFunction &n0, const GridFunction &dist, @@ -966,11 +966,23 @@ public: void EnableLimiting(const GridFunction &n0, Coefficient &w0, TMOP_LimiterFunction *lfunc = NULL); + /** @brief Restriction of the node positions to certain regions. + + Adds the term @f$ \int c (z(x) - z_0(x_0))^2 @f$, where z0(x0) is a given + function on the starting mesh, and z(x) is its image on the new mesh. + Minimizing this, means that a node at x0 is allowed to move to a + position x(x0) only if z(x) ~ z0(x0). + Such term can be used for tangential mesh relaxation. + + @param[in] z0 Function z0 that controls the adaptive limiting. + @param[in] coeff Coefficient c for the above integral. + @param[in] ae AdaptivityEvaluator to compute z(x) from z0(x0). */ void EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff, - AdaptivityEvaluator &ad); + AdaptivityEvaluator &ae); #ifdef MFEM_USE_MPI + /// Parallel support for adaptive limiting. void EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff, - AdaptivityEvaluator &ad); + AdaptivityEvaluator &ae); #endif /// Update the original/reference nodes used for limiting. From ab68fd9a781be10cd0b0bd70fcc62cf99c8c2385 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 18:48:04 -0700 Subject: [PATCH 276/535] Shows the final value of the limiting term. --- miniapps/meshing/mesh-optimizer.cpp | 20 +++++++++++--------- miniapps/meshing/pmesh-optimizer.cpp | 20 +++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 6ab774de96..ab82d0ea52 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make mesh-optimizer // // Adaptive limiting: -// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 +// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 // Adaptive limiting through FD (requires GSLIB): -// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 +// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: @@ -267,6 +267,7 @@ int main(int argc, char *argv[]) int metric_id = 1; int target_id = 1; double lim_const = 0.0; + double adapt_lim_const = 0.0; int quad_type = 1; int quad_order = 8; int newton_iter = 10; @@ -280,7 +281,6 @@ int main(int argc, char *argv[]) int verbosity_level = 0; bool fdscheme = 0; int adapt_eval = 0; - bool adapt_lim = false; // 1. Parse command-line options. OptionsParser args(argc, argv); @@ -322,6 +322,8 @@ int main(int argc, char *argv[]) "4: Given full analytic Jacobian (in physical space)\n\t" "5: Ideal shape, given size (in physical space)"); args.AddOption(&lim_const, "-lc", "--limit-const", "Limiting constant."); + args.AddOption(&adapt_lim_const, "-alc", "--adapt-limit-const", + "Adaptive limiting coefficient constant."); args.AddOption(&quad_type, "-qt", "--quad-type", "Quadrature rule type:\n\t" "1: Gauss-Lobatto\n\t" @@ -350,8 +352,6 @@ int main(int argc, char *argv[]) "Make all terms in the optimization functional unitless."); args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", "Enable finite difference based derivative computations."); - args.AddOption(&adapt_lim, "-al", "--adapt-limit", "no-ad", "no-adapt-limit", - "Enable adaptive limiting."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -567,9 +567,9 @@ int main(int argc, char *argv[]) // Adaptive limiting. GridFunction zeta_0(&ind_fes); - ConstantCoefficient coef_zeta(0.5); + ConstantCoefficient coef_zeta(adapt_lim_const); AdaptivityEvaluator *adapt_evaluator = NULL; - if (adapt_lim) + if (adapt_lim_const > 0.0) { FunctionCoefficient alim_coeff(adapt_lim_fun); zeta_0.ProjectCoefficient(alim_coeff); @@ -791,11 +791,13 @@ int main(int argc, char *argv[]) // 21. Compute the amount of energy decrease. const double fin_energy = a.GetGridFunctionEnergy(x); double metric_part = fin_energy; - if (lim_const != 0.0) + if (lim_const > 0.0 || adapt_lim_const > 0.0) { lim_coeff.constant = 0.0; + coef_zeta.constant = 0.0; metric_part = a.GetGridFunctionEnergy(x); lim_coeff.constant = lim_const; + coef_zeta.constant = adapt_lim_const; } cout << "Initial strain energy: " << init_energy << " = metrics: " << init_energy @@ -813,7 +815,7 @@ int main(int argc, char *argv[]) vis_tmop_metric_s(mesh_poly_deg, *metric, *target_c, *mesh, title, 600); } - if (adapt_lim && visualization) + if (adapt_lim_const > 0.0 && visualization) { socketstream vis0; common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0", diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 9ec77e38b3..64b0b6c9eb 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,9 +32,9 @@ // Compile with: make pmesh-optimizer // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -ae 0 +// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 // Adaptive limiting through FD (requires GSLIB): -// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -al -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // // Sample runs: // Adapted analytic Hessian: @@ -273,6 +273,7 @@ int main (int argc, char *argv[]) int metric_id = 1; int target_id = 1; double lim_const = 0.0; + double adapt_lim_const = 0.0; int quad_type = 1; int quad_order = 8; int newton_iter = 10; @@ -286,7 +287,6 @@ int main (int argc, char *argv[]) int verbosity_level = 0; bool fdscheme = false; int adapt_eval = 0; - bool adapt_lim = false; // 2. Parse command-line options. OptionsParser args(argc, argv); @@ -329,6 +329,8 @@ int main (int argc, char *argv[]) "4: Given full analytic Jacobian (in physical space)\n\t" "5: Ideal shape, given size (in physical space)"); args.AddOption(&lim_const, "-lc", "--limit-const", "Limiting constant."); + args.AddOption(&adapt_lim_const, "-alc", "--adapt-limit-const", + "Adaptive limiting coefficient constant."); args.AddOption(&quad_type, "-qt", "--quad-type", "Quadrature rule type:\n\t" "1: Gauss-Lobatto\n\t" @@ -357,8 +359,6 @@ int main (int argc, char *argv[]) "Make all terms in the optimization functional unitless."); args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", "Enable finite difference based derivative computations."); - args.AddOption(&adapt_lim, "-al", "--adapt-limit", "no-ad", "no-adapt-limit", - "Enable adaptive limiting."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -602,9 +602,9 @@ int main (int argc, char *argv[]) // Adaptive limiting. ParGridFunction zeta_0(&ind_fes); - ConstantCoefficient coef_zeta(0.5); + ConstantCoefficient coef_zeta(adapt_lim_const); AdaptivityEvaluator *adapt_evaluator = NULL; - if (adapt_lim) + if (adapt_lim_const > 0.0) { FunctionCoefficient alim_coeff(adapt_lim_fun); zeta_0.ProjectCoefficient(alim_coeff); @@ -836,11 +836,13 @@ int main (int argc, char *argv[]) // 22. Compute the amount of energy decrease. const double fin_energy = a.GetParGridFunctionEnergy(x); double metric_part = fin_energy; - if (lim_const != 0.0) + if (lim_const > 0.0 || adapt_lim_const > 0.0) { lim_coeff.constant = 0.0; + coef_zeta.constant = 0.0; metric_part = a.GetParGridFunctionEnergy(x); lim_coeff.constant = lim_const; + coef_zeta.constant = adapt_lim_const; } if (myid == 0) { @@ -861,7 +863,7 @@ int main (int argc, char *argv[]) vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 600); } - if (adapt_lim && visualization) + if (adapt_lim_const > 0.0 && visualization) { socketstream vis0; common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0", From 2cc07be4aaaaa6dbce6b183697088c6d105126c3 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 19:05:25 -0700 Subject: [PATCH 277/535] Minor. --- fem/tmop.cpp | 2 ++ fem/tmop.hpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 0fef70d70a..b676d2ab94 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1254,6 +1254,7 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0, (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } +#ifdef MFEM_USE_MPI void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ae) @@ -1269,6 +1270,7 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0, adapt_eval->SetInitialField (*zeta->FESpace()->GetMesh()->GetNodes(), *zeta); } +#endif double TMOP_Integrator::GetElementEnergy(const FiniteElement &el, ElementTransformation &T, diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 12f0c6dc7d..62b9412514 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -934,7 +934,7 @@ public: lim_dist(NULL), lim_func(NULL), lim_normal(1.0), zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL), discr_tc(dynamic_cast(tc)), - fdflag(false), fd_call_flag(false), dxscale(1.0e3) + fdflag(false), dxscale(1.0e3), fd_call_flag(false) { } ~TMOP_Integrator(); From f77273f92af278fc2a429e6a832e8cdc9ca8a6b5 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 19:33:51 -0700 Subject: [PATCH 278/535] Forgot a delete statement. --- miniapps/meshing/mesh-optimizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index ab82d0ea52..61108e8f4f 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -842,6 +842,7 @@ int main(int argc, char *argv[]) delete target_c2; delete metric2; delete coeff1; + delete adapt_evaluator; delete target_c; delete metric; delete fespace; From f64ad892d36c14670df613ef2109b53659c5090e Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 3 May 2020 19:46:54 -0700 Subject: [PATCH 279/535] Minor. --- general/error.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/general/error.cpp b/general/error.cpp index 9a5800dc97..0e74fc2527 100644 --- a/general/error.cpp +++ b/general/error.cpp @@ -161,8 +161,6 @@ void mfem_error(const char *msg) merr << "\n\n" << msg << "\n"; } - std::abort(); // force crash by calling abort - #ifdef MFEM_USE_LIBUNWIND merr << "Backtrace:" << std::endl; mfem_backtrace(1, -1); From 523db914fc5659a0fab0ab610e7d3ea3a4220d3b Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Mon, 4 May 2020 16:32:15 -0700 Subject: [PATCH 280/535] make style --- fem/bilinearform.hpp | 4 ++-- fem/coefficient.hpp | 6 +++--- fem/fespace.hpp | 10 +++++----- general/communication.hpp | 2 +- general/optparser.hpp | 2 +- general/stable3d.hpp | 6 +++--- linalg/vector.hpp | 16 ++++++++-------- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index 530acc5f6b..02effa0ab8 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -163,8 +163,8 @@ public: /// Returns the assembly level AssemblyLevel GetAssemblyLevel() const { return assembly; } - /** @brief Enable the use of static condensation. For details see the - description for class StaticCondensation in fem/staticcond.hpp This method + /** @brief Enable the use of static condensation. For details see the + description for class StaticCondensation in fem/staticcond.hpp This method should be called before assembly. If the number of unknowns after static condensation is not reduced, it is not enabled. */ void EnableStaticCondensation(); diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index a4a8901536..8fd04b205a 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -27,8 +27,8 @@ class ParMesh; #endif -/** @brief Base class Coefficients that optionally depend on space and - time. These are used by the BilinearFormIntegrator, +/** @brief Base class Coefficients that optionally depend on space and + time. These are used by the BilinearFormIntegrator, LinearFormIntegrator, and NonlinearFormIntegrator classes to represent the physical coeffiencients in the PDEs that are being discretized. */ class Coefficient @@ -490,7 +490,7 @@ public: grid function is not owned by the coefficient. */ VectorGridFunctionCoefficient(GridFunction *gf); - /** @brief Set the grid function for this coefficient. Also sets the Vector + /** @brief Set the grid function for this coefficient. Also sets the Vector dimension to match that of the @a gf. */ void SetGridFunction(GridFunction *gf); diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 5e3a708238..71c3e5636b 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -536,21 +536,21 @@ public: int GetElementForDof(int i) const { return dof_elem_array[i]; } int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; } - /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in the mesh object. */ const FiniteElement *GetFE(int i) const; - /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary face in the mesh object. */ const FiniteElement *GetBE(int i) const; - /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the mesh object. Faces in this case refer - to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are + to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are points.*/ const FiniteElement *GetFaceElement(int i) const; - /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection + /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th edge in the mesh object. */ const FiniteElement *GetEdgeElement(int i) const; diff --git a/general/communication.hpp b/general/communication.hpp index 2d12100f29..570535e23c 100644 --- a/general/communication.hpp +++ b/general/communication.hpp @@ -384,7 +384,7 @@ struct VarMessage } } - /** @brief Return true if all messages in the map container were sent, + /** @brief Return true if all messages in the map container were sent, otherwise return false, without waiting. */ template static bool TestAllSent(MapT& rank_msg) diff --git a/general/optparser.hpp b/general/optparser.hpp index ab0d35b51d..4a9ab69627 100644 --- a/general/optparser.hpp +++ b/general/optparser.hpp @@ -76,7 +76,7 @@ public: error_type = error_idx = 0; } - /** @brief Add a boolean option and set 'var' to recieve the value. + /** @brief Add a boolean option and set 'var' to recieve the value. Enable/disable tags are used to set the bool to true/false respectively. */ void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, diff --git a/general/stable3d.hpp b/general/stable3d.hpp index 54a4d3e197..2c191d6505 100644 --- a/general/stable3d.hpp +++ b/general/stable3d.hpp @@ -28,9 +28,9 @@ public: /** @brief Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed - into the table. Diagonals of any kind are not allowed so the row, - column and floor must all be different for each node. Only one - node is stored for all 6 symmetric entries that are indexable by + into the table. Diagonals of any kind are not allowed so the row, + column and floor must all be different for each node. Only one + node is stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor. */ class STable3D diff --git a/linalg/vector.hpp b/linalg/vector.hpp index 318a62f949..9fd517445f 100644 --- a/linalg/vector.hpp +++ b/linalg/vector.hpp @@ -282,42 +282,42 @@ public: void median(const Vector &lo, const Vector &hi); /** @brief Extract entries listed in @a dofs to the output Vector @a elemvect. - Negative dof values cause the -dof-1 position in @a elemvect to recieve + Negative dof values cause the -dof-1 position in @a elemvect to recieve the -val in from this Vector. */ void GetSubVector(const Array &dofs, Vector &elemvect) const; /** @brief Extract entries listed in @a dofs to the output array @a elem_data. - Negative dof values cause the -dof-1 position in @a elem_data to recieve + Negative dof values cause the -dof-1 position in @a elem_data to recieve the -val in from this Vector. */ void GetSubVector(const Array &dofs, double *elem_data) const; /** @brief Set the entries listed in @a dofs to the given @a value. - Negative dof values cause the -dof-1 position in this Vector to recieve + Negative dof values cause the -dof-1 position in this Vector to recieve the -value. */ void SetSubVector(const Array &dofs, const double value); /** @brief Set the entries listed in @a dofs to the values given in the @a elemvect Vector. - Negative dof values cause the -dof-1 position in this Vector to recieve + Negative dof values cause the -dof-1 position in this Vector to recieve the -val from @a elemvect. */ void SetSubVector(const Array &dofs, const Vector &elemvect); /** @brief Set the entries listed in @a dofs to the values given the @a elem_data array. - Negative dof values cause the -dof-1 position in this Vector to recieve + Negative dof values cause the -dof-1 position in this Vector to recieve the -val from @a elem_data. */ void SetSubVector(const Array &dofs, double *elem_data); /** @brief Add elements of the @a elemvect Vector to the entries listed in @a dofs. - Negative dof values cause the -dof-1 position in this Vector to add + Negative dof values cause the -dof-1 position in this Vector to add the -val from @a elemvect. */ void AddElementVector(const Array & dofs, const Vector & elemvect); /** @brief Add elements of the @a elem_data array to the entries listed in @a dofs. - Negative dof values cause the -dof-1 position in this Vector to add + Negative dof values cause the -dof-1 position in this Vector to add the -val from @a elem_data. */ void AddElementVector(const Array & dofs, double *elem_data); /** @brief Add @a times the elements of the @a elemvect Vector to the entries listed in - @a dofs. Negative dof values cause the -dof-1 position in this Vector to add + @a dofs. Negative dof values cause the -dof-1 position in this Vector to add the -a*val from @a elemvect. */ void AddElementVector(const Array & dofs, const double a, const Vector & elemvect); From 28529993248c3f398486244b0394798a959e08ad Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Mon, 4 May 2020 16:45:52 -0700 Subject: [PATCH 281/535] Fixed a bug introduced by the merge. --- fem/fe.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fem/fe.cpp b/fem/fe.cpp index 4583f7149c..431a5906a7 100644 --- a/fem/fe.cpp +++ b/fem/fe.cpp @@ -10289,9 +10289,9 @@ RT_QuadrilateralElement::RT_QuadrilateralElement(const int p, const int ob_type) : VectorTensorFiniteElement(2, 2*(p + 1)*(p + 2), p + 1, cb_type, ob_type, H_DIV, DofMapType::L2_DOF_MAP), - dof2nk(Dof) + dof2nk(dof) { - dof_map.SetSize(Dof); + dof_map.SetSize(dof); const double *cp = poly1d.ClosedPoints(p + 1, cb_type); const double *op = poly1d.OpenPoints(p, ob_type); @@ -10500,9 +10500,9 @@ RT_HexahedronElement::RT_HexahedronElement(const int p, const int ob_type) : VectorTensorFiniteElement(3, 3*(p + 1)*(p + 1)*(p + 2), p + 1, cb_type, ob_type, H_DIV, DofMapType::L2_DOF_MAP), - dof2nk(Dof) + dof2nk(dof) { - dof_map.SetSize(Dof); + dof_map.SetSize(dof); const double *cp = poly1d.ClosedPoints(p + 1, cb_type); const double *op = poly1d.OpenPoints(p, ob_type); From ef54519a29a6de1f768fd3a74e38f2de9ffeb37c Mon Sep 17 00:00:00 2001 From: psocratis Date: Mon, 4 May 2020 19:54:24 -0700 Subject: [PATCH 282/535] Added LF integrators (Q, grard V), (Q, curl V) and (Q, div V) --- fem/lininteg.cpp | 163 +++++++++++++++++++++++++++++++++++++++++++++-- fem/lininteg.hpp | 84 ++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 7 deletions(-) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index adc9355d66..505b059899 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -63,6 +63,51 @@ void DomainLFIntegrator::AssembleDeltaElementVect( elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); } +void DomainLFGradIntegrator::AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) +{ + int dof = el.GetDof(); + int spaceDim = Tr.GetSpaceDim(); + + dshape.SetSize(dof, spaceDim); + + elvect.SetSize(dof); + elvect = 0.0; + + const IntegrationRule *ir = IntRule; + if (ir == NULL) + { + int intorder = 2 * el.GetOrder(); + ir = &IntRules.Get(el.GetGeomType(), intorder); + } + + for (int i = 0; i < ir->GetNPoints(); i++) + { + const IntegrationPoint &ip = ir->IntPoint(i); + + Tr.SetIntPoint(&ip); + el.CalcPhysDShape(Tr, dshape); + + Q.Eval(Qvec, Tr, ip); + Qvec *= ip.weight * Tr.Weight(); + + dshape.AddMult(Qvec, elvect); + } +} + +void DomainLFGradIntegrator::AssembleDeltaElementVect(const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) +{ + MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); + int dof = fe.GetDof(); + int spaceDim = Trans.GetSpaceDim(); + + dshape.SetSize(dof, spaceDim); + fe.CalcPhysDShape(Trans, dshape); + + vec_delta->EvalDelta(Qvec, Trans, Trans.GetIntPoint()); + + elvect.SetSize(dof); + dshape.Mult(Qvec, elvect); +} void BoundaryLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) @@ -255,7 +300,6 @@ void VectorDomainLFIntegrator::AssembleDeltaElementVect( MultVWt(shape, Qvec, elvec_as_mat); } - void VectorBoundaryLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { @@ -330,7 +374,6 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect( } } - void VectorFEDomainLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { @@ -360,7 +403,6 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect( QF.Eval (vec, Tr, ip); vec *= ip.weight * Tr.Weight(); - vshape.AddMult (vec, elvect); } } @@ -381,6 +423,117 @@ void VectorFEDomainLFIntegrator::AssembleDeltaElementVect( vshape.Mult(vec, elvect); } +void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect( + const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) +{ + int dof = el.GetDof(); + int spaceDim = Tr.GetSpaceDim(); + int n=(spaceDim == 3)? spaceDim : 1; + curlshape.SetSize(dof,n); + vec.SetSize(n); + + elvect.SetSize(dof); + elvect = 0.0; + + const IntegrationRule *ir = IntRule; + if (ir == NULL) + { + int intorder = 2*el.GetOrder(); + ir = &IntRules.Get(el.GetGeomType(), intorder); + } + + for (int i = 0; i < ir->GetNPoints(); i++) + { + const IntegrationPoint &ip = ir->IntPoint(i); + + Tr.SetIntPoint (&ip); + el.CalcPhysCurlShape(Tr, curlshape); + + switch (spaceDim) + { + case 3: + MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided"); + QF->Eval(vec, Tr, ip); + break; + case 2: + MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided"); + vec[0] = Q->Eval(Tr, ip); + break; + default: + break; // This should be unreachable + } + vec *= ip.weight * Tr.Weight(); + curlshape.AddMult (vec, elvect); + } +} + +void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect( + const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) +{ + MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); + int dof = fe.GetDof(); + int spaceDim = Trans.GetSpaceDim(); + int n=(spaceDim == 3)? spaceDim : 1; + curlshape.SetSize(dof, n); + elvect.SetSize(dof); + fe.CalcPhysCurlShape(Trans, curlshape); + + switch (spaceDim) + { + case 3: + vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint()); + curlshape.Mult(vec, elvect); + break; + case 2: + // Extract 1st column of curlshape to elvect + curlshape.GetColumn(0,elvect); + elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); + break; + default: + break; // This should be unreachable + } + +} + +void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(const FiniteElement &el, + ElementTransformation &Tr, + Vector &elvect) +{ + int dof = el.GetDof(); + + divshape.SetSize(dof); // vector of size dof + elvect.SetSize(dof); + elvect = 0.0; + + const IntegrationRule *ir = IntRule; + if (ir == NULL) + { + // ir = &IntRules.Get(el.GetGeomType(), + // oa * el.GetOrder() + ob + Tr.OrderW()); + ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob); + } + + for (int i = 0; i < ir->GetNPoints(); i++) + { + const IntegrationPoint &ip = ir->IntPoint(i); + + Tr.SetIntPoint (&ip); + double val = Tr.Weight() * Q.Eval(Tr, ip); + el.CalcPhysDivShape(Tr, divshape); + + add(elvect, ip.weight * val, divshape, elvect); + } +} + +void VectorFEDomainLFDivIntegrator::AssembleDeltaElementVect( + const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) +{ + MFEM_ASSERT(delta != NULL, "coefficient must be DeltaCoefficient"); + elvect.SetSize(fe.GetDof()); + fe.CalcPhysDivShape(Trans, elvect); + elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); +} + void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { @@ -446,7 +599,6 @@ void VectorFEBoundaryFluxLFIntegrator::AssembleRHSElementVect( } } - void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { @@ -481,7 +633,6 @@ void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect( } } - void BoundaryFlowIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { @@ -544,7 +695,6 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( } } - void DGDirichletLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { @@ -633,7 +783,6 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( } } - void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index 1b8c2e19cc..99df07e117 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -119,6 +119,33 @@ public: using LinearFormIntegrator::AssembleRHSElementVect; }; + +class DomainLFGradIntegrator : public DeltaLFIntegrator +{ +private: + Vector shape, Qvec; + VectorCoefficient &Q; + DenseMatrix dshape; + +public: + /// Constructs the domain integrator (Q, grad v) + DomainLFGradIntegrator(VectorCoefficient &QF) + : DeltaLFIntegrator(QF), Q(QF) { } + + /** Given a particular Finite Element and a transformation (Tr) + computes the element right hand side element vector, elvect. */ + virtual void AssembleRHSElementVect(const FiniteElement &el, + ElementTransformation &Tr, + Vector &elvect); + + virtual void AssembleDeltaElementVect(const FiniteElement &fe, + ElementTransformation &Trans, + Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; +}; + + /// Class for boundary integration L(v) := (g, v) class BoundaryLFIntegrator : public LinearFormIntegrator { @@ -252,7 +279,64 @@ public: using LinearFormIntegrator::AssembleRHSElementVect; }; +/// \f$ (Q, curl v)_{\Omega} \f$ for Nedelec Elements) +class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator +{ +private: + VectorCoefficient *QF=nullptr; + Coefficient *Q=nullptr; + DenseMatrix curlshape; + Vector vec; +public: + /// Constructs the domain integrator (Q, curl v) + VectorFEDomainLFCurlIntegrator(VectorCoefficient &F) + : DeltaLFIntegrator(F), QF(&F) { } + VectorFEDomainLFCurlIntegrator(Coefficient &F) + : DeltaLFIntegrator(F), Q(&F) { } + + virtual void AssembleRHSElementVect(const FiniteElement &el, + ElementTransformation &Tr, + Vector &elvect); + + virtual void AssembleDeltaElementVect(const FiniteElement &fe, + ElementTransformation &Trans, + Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; +}; + +/// \f$ (Q, div v)_{\Omega} \f$ for RT Elements) +class VectorFEDomainLFDivIntegrator : public DeltaLFIntegrator +{ +private: + Vector divshape; + Coefficient &Q; + int oa, ob; + +public: + /// Constructs the domain integrator (Q, div v) + VectorFEDomainLFDivIntegrator(Coefficient &QF, int a = 2, int b = 0) + // the old default was a = 1, b = 1 + // for simple elliptic problems a = 2, b = -2 is OK + : DeltaLFIntegrator(QF), Q(QF), oa(a), ob(b) { } + + /// Constructs a domain integrator with a given Coefficient + VectorFEDomainLFDivIntegrator(Coefficient &QF, const IntegrationRule *ir) + : DeltaLFIntegrator(QF, ir), Q(QF), oa(1), ob(1) { } + + /** Given a particular Finite Element and a transformation (Tr) + computes the element right hand side element vector, elvect. */ + virtual void AssembleRHSElementVect(const FiniteElement &el, + ElementTransformation &Tr, + Vector &elvect); + + virtual void AssembleDeltaElementVect(const FiniteElement &fe, + ElementTransformation &Trans, + Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; +}; /** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function v=(v1,...,vn) where all vi are in the same scalar FE space and f is a scalar function. */ From f6bc0f898869f6828fa001ab3ceac0f4460da2ac Mon Sep 17 00:00:00 2001 From: psocratis Date: Mon, 4 May 2020 19:55:00 -0700 Subject: [PATCH 283/535] Added test for the newly added LF integrators --- examples/BestApprox.cpp | 293 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 examples/BestApprox.cpp diff --git a/examples/BestApprox.cpp b/examples/BestApprox.cpp new file mode 100644 index 0000000000..40a187e379 --- /dev/null +++ b/examples/BestApprox.cpp @@ -0,0 +1,293 @@ +// +// Compile with: make helmholtz +// +// Sample runs: helmholtz -m ../data/one-hex.mesh +// helmholtz -m ../data/fichera.mesh +// helmholtz -m ../data/fichera-mixed.mesh +// +// Description: This example code demonstrates the use of MFEM to define a +// simple finite element discretization of the Helmholtz problem +// -Delta p - omega^2 u = 1 with impedance boundary conditiones. +// +#include "mfem.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +// H1 +double u_exact(const Vector &x); +void gradu_exact(const Vector &x, Vector &gradu); + +// Vector FE +void U_exact(const Vector &x, Vector & U); +// H(curl) +void curlU_exact(const Vector &x, Vector &curlU); +double curlU2D_exact(const Vector &x); +// H(div) +double divU_exact(const Vector &x); + +int dim; +int prob=0; +Vector alpha; + +int main(int argc, char *argv[]) +{ + // geometry file + const char *mesh_file = "../data/inline-quad.mesh"; + // finite element order of approximation + int order = 1; + // static condensation flag + bool visualization = 1; + // number of initial ref + int ref = 1; + + // optional command line inputs + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&prob, "-prob", "--problem", + "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); + args.AddOption(&ref, "-ref", "--ref", + "Number of refinements."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + // check if the inputs are correct + if (!args.Good()) + { + args.PrintUsage(cout); + return 1; + } + args.PrintOptions(cout); + + // 3. Read the mesh from the given mesh file. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + // Mesh *mesh = new Mesh(1, 1, Element::QUADRILATERAL, true, 1.0, 1.0, false); + dim = mesh->Dimension(); + + alpha.SetSize(dim); + for (int i=0; iUniformRefinement(); + } + + // 6. Define a finite element space on the mesh. + FiniteElementCollection *fec=nullptr; + switch (prob) + { + case 0: fec = new H1_FECollection(order,dim); break; + case 1: fec = new ND_FECollection(order,dim); break; + case 2: fec = new RT_FECollection(order-1,dim); break; + default: break; + } + FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); + cout << "Number of finite element unknowns: " << fespace->GetTrueVSize() + << endl; + + Array ess_tdof_list; + if (mesh->bdr_attributes.Size()) + { + Array ess_bdr(mesh->bdr_attributes.Max()); + ess_bdr = 0; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + + GridFunction u_gf(fespace); + FunctionCoefficient * u, *divU, *curlU2D; + VectorFunctionCoefficient * U, *gradu, *curlU; + + FunctionCoefficient *u_ex=nullptr; + VectorFunctionCoefficient *U_ex=nullptr; + + ConstantCoefficient one(1.0); + + // Calculate H1 projection + LinearForm b(fespace); + BilinearForm a(fespace); + + switch (prob) + { + case 0: //(grad u_ex, grad v) + (u_ex,v) + u_ex = new FunctionCoefficient(u_exact); + + u = new FunctionCoefficient(u_exact); + gradu = new VectorFunctionCoefficient(dim,gradu_exact); + b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); + b.AddDomainIntegrator(new DomainLFIntegrator(*u)); + + // (grad u, grad v) + (u,v) + a.AddDomainIntegrator(new DiffusionIntegrator(one)); + a.AddDomainIntegrator(new MassIntegrator(one)); + + break; + case 1: //(curl u_ex, curl v + (u_ex,v) + U_ex = new VectorFunctionCoefficient(dim,U_exact); + + U = new VectorFunctionCoefficient(dim,U_exact); + if (dim == 3) + { + curlU = new VectorFunctionCoefficient(dim,curlU_exact); + b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU)); + } + else if (dim == 2) + { + curlU2D = new FunctionCoefficient(curlU2D_exact); + b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); + } + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + // (curl u, curl v) + (u,v) + a.AddDomainIntegrator(new CurlCurlIntegrator(one)); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + break; + + case 2: //(div u_ex, div v) + (u_ex,v) + U_ex = new VectorFunctionCoefficient(dim,U_exact); + U = new VectorFunctionCoefficient(dim,U_exact); + divU = new FunctionCoefficient(divU_exact); + b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + + // (div u, div v) + (u,v) + a.AddDomainIntegrator(new DivDivIntegrator(one)); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + break; + + default: + break; + } + b.Assemble(); + a.Assemble(); + OperatorPtr A; + Vector X, B; + a.FormLinearSystem(ess_tdof_list, u_gf, b, A, X,B); + + UMFPackSolver umf_solver; + umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; + umf_solver.SetOperator(*A); + umf_solver.Mult(B, X); + + a.RecoverFEMSolution(X,B,u_gf); + + int order_quad = max(2, 2*order+1); + const IntegrationRule *irs[Geometry::NumGeom]; + for (int i=0; i < Geometry::NumGeom; ++i) + { + irs[i] = &(IntRules.Get(i, order_quad)); + } + + double L2err = 0.0; + switch (prob) + { + case 0: + L2err = u_gf.ComputeL2Error(*u_ex); + break; + case 1: + case 2: + L2err = u_gf.ComputeL2Error(*U_ex); + break; + default: + break; + } + + cout << " || u_h - u ||_{L^2} = " << L2err << endl; + + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + string keys; + if (dim ==2 ) + { + // keys = "keys mrRljc\n"; + keys = "keys \n"; + } + else + { + keys = "keys mc\n"; + } + socketstream sol_sock_re(vishost, visport); + sol_sock_re.precision(8); + sol_sock_re << "solution\n" << *mesh << u_gf << + "window_title 'Numerical Pressure (real part)' " + << keys << flush; + } + + delete fespace; + delete fec; + delete mesh; + return 0; +} + +double u_exact(const Vector &x) +{ + double u; + double y=0; + for (int i=0; i Date: Mon, 4 May 2020 19:56:38 -0700 Subject: [PATCH 284/535] make style --- examples/BestApprox.cpp | 112 ++++++++++++++++++++-------------------- fem/lininteg.cpp | 57 ++++++++++---------- fem/lininteg.hpp | 2 +- 3 files changed, 87 insertions(+), 84 deletions(-) diff --git a/examples/BestApprox.cpp b/examples/BestApprox.cpp index 40a187e379..a1e3403372 100644 --- a/examples/BestApprox.cpp +++ b/examples/BestApprox.cpp @@ -16,7 +16,7 @@ using namespace std; using namespace mfem; -// H1 +// H1 double u_exact(const Vector &x); void gradu_exact(const Vector &x, Vector &gradu); @@ -51,7 +51,7 @@ int main(int argc, char *argv[]) "Finite element order (polynomial degree) or -1 for" " isoparametric space."); args.AddOption(&prob, "-prob", "--problem", - "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); + "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); args.AddOption(&ref, "-ref", "--ref", "Number of refinements."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", @@ -71,8 +71,8 @@ int main(int argc, char *argv[]) // Mesh *mesh = new Mesh(1, 1, Element::QUADRILATERAL, true, 1.0, 1.0, false); dim = mesh->Dimension(); - alpha.SetSize(dim); - for (int i=0; iGetTrueVSize() << endl; - + Array ess_tdof_list; if (mesh->bdr_attributes.Size()) { @@ -101,8 +101,8 @@ int main(int argc, char *argv[]) } GridFunction u_gf(fespace); - FunctionCoefficient * u, *divU, *curlU2D; - VectorFunctionCoefficient * U, *gradu, *curlU; + FunctionCoefficient * u, *divU, *curlU2D; + VectorFunctionCoefficient * U, *gradu, *curlU; FunctionCoefficient *u_ex=nullptr; VectorFunctionCoefficient *U_ex=nullptr; @@ -115,53 +115,53 @@ int main(int argc, char *argv[]) switch (prob) { - case 0: //(grad u_ex, grad v) + (u_ex,v) - u_ex = new FunctionCoefficient(u_exact); + case 0: //(grad u_ex, grad v) + (u_ex,v) + u_ex = new FunctionCoefficient(u_exact); - u = new FunctionCoefficient(u_exact); - gradu = new VectorFunctionCoefficient(dim,gradu_exact); - b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); - b.AddDomainIntegrator(new DomainLFIntegrator(*u)); + u = new FunctionCoefficient(u_exact); + gradu = new VectorFunctionCoefficient(dim,gradu_exact); + b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); + b.AddDomainIntegrator(new DomainLFIntegrator(*u)); - // (grad u, grad v) + (u,v) - a.AddDomainIntegrator(new DiffusionIntegrator(one)); - a.AddDomainIntegrator(new MassIntegrator(one)); + // (grad u, grad v) + (u,v) + a.AddDomainIntegrator(new DiffusionIntegrator(one)); + a.AddDomainIntegrator(new MassIntegrator(one)); - break; - case 1: //(curl u_ex, curl v + (u_ex,v) - U_ex = new VectorFunctionCoefficient(dim,U_exact); + break; + case 1: //(curl u_ex, curl v + (u_ex,v) + U_ex = new VectorFunctionCoefficient(dim,U_exact); - U = new VectorFunctionCoefficient(dim,U_exact); - if (dim == 3) - { - curlU = new VectorFunctionCoefficient(dim,curlU_exact); - b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU)); - } - else if (dim == 2) - { - curlU2D = new FunctionCoefficient(curlU2D_exact); - b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); - } - b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); - // (curl u, curl v) + (u,v) - a.AddDomainIntegrator(new CurlCurlIntegrator(one)); - a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); - break; + U = new VectorFunctionCoefficient(dim,U_exact); + if (dim == 3) + { + curlU = new VectorFunctionCoefficient(dim,curlU_exact); + b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU)); + } + else if (dim == 2) + { + curlU2D = new FunctionCoefficient(curlU2D_exact); + b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); + } + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + // (curl u, curl v) + (u,v) + a.AddDomainIntegrator(new CurlCurlIntegrator(one)); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + break; - case 2: //(div u_ex, div v) + (u_ex,v) - U_ex = new VectorFunctionCoefficient(dim,U_exact); - U = new VectorFunctionCoefficient(dim,U_exact); - divU = new FunctionCoefficient(divU_exact); - b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); - b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + case 2: //(div u_ex, div v) + (u_ex,v) + U_ex = new VectorFunctionCoefficient(dim,U_exact); + U = new VectorFunctionCoefficient(dim,U_exact); + divU = new FunctionCoefficient(divU_exact); + b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); - // (div u, div v) + (u,v) - a.AddDomainIntegrator(new DivDivIntegrator(one)); - a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); - break; + // (div u, div v) + (u,v) + a.AddDomainIntegrator(new DivDivIntegrator(one)); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + break; - default: - break; + default: + break; } b.Assemble(); a.Assemble(); @@ -186,15 +186,15 @@ int main(int argc, char *argv[]) double L2err = 0.0; switch (prob) { - case 0: - L2err = u_gf.ComputeL2Error(*u_ex); - break; + case 0: + L2err = u_gf.ComputeL2Error(*u_ex); + break; case 1: case 2: - L2err = u_gf.ComputeL2Error(*U_ex); - break; - default: - break; + L2err = u_gf.ComputeL2Error(*U_ex); + break; + default: + break; } cout << " || u_h - u ||_{L^2} = " << L2err << endl; @@ -270,7 +270,7 @@ void curlU_exact(const Vector &x, Vector &curlU) curlU[2] = -alpha(1)*sin(alpha(1) * s) + alpha(0)*sin(alpha(0) * s); } -double curlU2D_exact(const Vector &x) +double curlU2D_exact(const Vector &x) { MFEM_VERIFY(dim == 2, "This should be called only for 2D cases"); double s = x(0) + x(1); diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 505b059899..865e4fbf69 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -63,7 +63,8 @@ void DomainLFIntegrator::AssembleDeltaElementVect( elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); } -void DomainLFGradIntegrator::AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) +void DomainLFGradIntegrator::AssembleRHSElementVect(const FiniteElement &el, + ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); int spaceDim = Tr.GetSpaceDim(); @@ -94,7 +95,8 @@ void DomainLFGradIntegrator::AssembleRHSElementVect(const FiniteElement &el, Ele } } -void DomainLFGradIntegrator::AssembleDeltaElementVect(const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) +void DomainLFGradIntegrator::AssembleDeltaElementVect(const FiniteElement &fe, + ElementTransformation &Trans, Vector &elvect) { MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); int dof = fe.GetDof(); @@ -445,22 +447,22 @@ void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect( for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); - + Tr.SetIntPoint (&ip); el.CalcPhysCurlShape(Tr, curlshape); switch (spaceDim) { - case 3: - MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided"); - QF->Eval(vec, Tr, ip); - break; - case 2: - MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided"); - vec[0] = Q->Eval(Tr, ip); - break; - default: - break; // This should be unreachable + case 3: + MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided"); + QF->Eval(vec, Tr, ip); + break; + case 2: + MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided"); + vec[0] = Q->Eval(Tr, ip); + break; + default: + break; // This should be unreachable } vec *= ip.weight * Tr.Weight(); curlshape.AddMult (vec, elvect); @@ -480,24 +482,25 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect( switch (spaceDim) { - case 3: - vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint()); - curlshape.Mult(vec, elvect); - break; - case 2: - // Extract 1st column of curlshape to elvect - curlshape.GetColumn(0,elvect); - elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); - break; - default: - break; // This should be unreachable + case 3: + vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint()); + curlshape.Mult(vec, elvect); + break; + case 2: + // Extract 1st column of curlshape to elvect + curlshape.GetColumn(0,elvect); + elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); + break; + default: + break; // This should be unreachable } } -void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(const FiniteElement &el, - ElementTransformation &Tr, - Vector &elvect) +void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect( + const FiniteElement &el, + ElementTransformation &Tr, + Vector &elvect) { int dof = el.GetDof(); diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index 99df07e117..f1778f1c7e 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -293,7 +293,7 @@ public: VectorFEDomainLFCurlIntegrator(VectorCoefficient &F) : DeltaLFIntegrator(F), QF(&F) { } VectorFEDomainLFCurlIntegrator(Coefficient &F) - : DeltaLFIntegrator(F), Q(&F) { } + : DeltaLFIntegrator(F), Q(&F) { } virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, From 99372de93396b3a0f3715e004831249750565c7b Mon Sep 17 00:00:00 2001 From: psocratis Date: Mon, 4 May 2020 20:35:27 -0700 Subject: [PATCH 285/535] Added parallel test --- examples/BestApprox.cpp | 10 +- examples/BestApproxp.cpp | 335 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+), 5 deletions(-) create mode 100644 examples/BestApproxp.cpp diff --git a/examples/BestApprox.cpp b/examples/BestApprox.cpp index a1e3403372..7472afd705 100644 --- a/examples/BestApprox.cpp +++ b/examples/BestApprox.cpp @@ -213,11 +213,11 @@ int main(int argc, char *argv[]) { keys = "keys mc\n"; } - socketstream sol_sock_re(vishost, visport); - sol_sock_re.precision(8); - sol_sock_re << "solution\n" << *mesh << u_gf << - "window_title 'Numerical Pressure (real part)' " - << keys << flush; + socketstream sol_sock(vishost, visport); + sol_sock.precision(8); + sol_sock << "solution\n" << *mesh << u_gf << + "window_title 'Numerical Pressure (real part)' " + << keys << flush; } delete fespace; diff --git a/examples/BestApproxp.cpp b/examples/BestApproxp.cpp new file mode 100644 index 0000000000..d80084e5e8 --- /dev/null +++ b/examples/BestApproxp.cpp @@ -0,0 +1,335 @@ +// +// Compile with: make helmholtz +// +// Sample runs: helmholtz -m ../data/one-hex.mesh +// helmholtz -m ../data/fichera.mesh +// helmholtz -m ../data/fichera-mixed.mesh +// +// Description: This example code demonstrates the use of MFEM to define a +// simple finite element discretization of the Helmholtz problem +// -Delta p - omega^2 u = 1 with impedance boundary conditiones. +// +#include "mfem.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +// H1 +double u_exact(const Vector &x); +void gradu_exact(const Vector &x, Vector &gradu); + +// Vector FE +void U_exact(const Vector &x, Vector & U); +// H(curl) +void curlU_exact(const Vector &x, Vector &curlU); +double curlU2D_exact(const Vector &x); +// H(div) +double divU_exact(const Vector &x); + +int dim; +int prob=0; +Vector alpha; + +int main(int argc, char *argv[]) +{ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + // geometry file + const char *mesh_file = "../data/inline-quad.mesh"; + // finite element order of approximation + int order = 1; + // static condensation flag + bool visualization = 1; + // number of initial ref + int sr = 1; + int pr = 1; + + // optional command line inputs + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&prob, "-prob", "--problem", + "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); + args.AddOption(&sr, "-sr", "--serial_ref", + "Number of serial refinements."); + args.AddOption(&pr, "-pr", "--parallel_ref", + "Number of parallel refinements."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + // check if the inputs are correct + if (!args.Good()) + { + if (myid == 0) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + if (myid == 0) + { + args.PrintOptions(cout); + } + + // 3. Read the mesh from the given mesh file. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + // Mesh *mesh = new Mesh(1, 1, Element::QUADRILATERAL, true, 1.0, 1.0, false); + dim = mesh->Dimension(); + + alpha.SetSize(dim); + for (int i=0; iUniformRefinement(); + } + + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + for (int l = 0; l < pr; l++) + { + pmesh->UniformRefinement(); + } + + // 6. Define a finite element space on the mesh. + FiniteElementCollection *fec=nullptr; + switch (prob) + { + case 0: fec = new H1_FECollection(order,dim); break; + case 1: fec = new ND_FECollection(order,dim); break; + case 2: fec = new RT_FECollection(order-1,dim); break; + default: break; + } + ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); + + Array ess_tdof_list; + if (pmesh->bdr_attributes.Size()) + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 0; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + + ParGridFunction u_gf(fespace); + FunctionCoefficient * u, *divU, *curlU2D; + VectorFunctionCoefficient * U, *gradu, *curlU; + + FunctionCoefficient *u_ex=nullptr; + VectorFunctionCoefficient *U_ex=nullptr; + + ConstantCoefficient one(1.0); + + // Calculate H1 projection + ParLinearForm b(fespace); + ParBilinearForm a(fespace); + + switch (prob) + { + case 0: //(grad u_ex, grad v) + (u_ex,v) + u_ex = new FunctionCoefficient(u_exact); + + u = new FunctionCoefficient(u_exact); + gradu = new VectorFunctionCoefficient(dim,gradu_exact); + b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); + b.AddDomainIntegrator(new DomainLFIntegrator(*u)); + + // (grad u, grad v) + (u,v) + a.AddDomainIntegrator(new DiffusionIntegrator(one)); + a.AddDomainIntegrator(new MassIntegrator(one)); + + break; + case 1: //(curl u_ex, curl v + (u_ex,v) + U_ex = new VectorFunctionCoefficient(dim,U_exact); + + U = new VectorFunctionCoefficient(dim,U_exact); + if (dim == 3) + { + curlU = new VectorFunctionCoefficient(dim,curlU_exact); + b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU)); + } + else if (dim == 2) + { + curlU2D = new FunctionCoefficient(curlU2D_exact); + b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); + } + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + // (curl u, curl v) + (u,v) + a.AddDomainIntegrator(new CurlCurlIntegrator(one)); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + break; + + case 2: //(div u_ex, div v) + (u_ex,v) + U_ex = new VectorFunctionCoefficient(dim,U_exact); + U = new VectorFunctionCoefficient(dim,U_exact); + divU = new FunctionCoefficient(divU_exact); + b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + + // (div u, div v) + (u,v) + a.AddDomainIntegrator(new DivDivIntegrator(one)); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + break; + + default: + break; + } + b.Assemble(); + a.Assemble(); + OperatorPtr A; + Vector X, B; + a.FormLinearSystem(ess_tdof_list, u_gf, b, A, X,B); + + Solver *prec = NULL; + switch (prob) + { + case 0: prec = new HypreBoomerAMG(*A.As()); break; + case 1: prec = new HypreAMS(*A.As(), fespace); break; + case 2: + if (dim == 2) {prec = new HypreAMS(*A.As(), fespace);} + else {prec = new HypreADS(*A.As(), fespace);} + break; + default: + break; + } + + CGSolver cg(MPI_COMM_WORLD); + cg.SetRelTol(1e-12); + cg.SetMaxIter(2000); + cg.SetPrintLevel(1); + if (prec) { cg.SetPreconditioner(*prec); } + cg.SetOperator(*A); + cg.Mult(B, X); + delete prec; + + a.RecoverFEMSolution(X,B,u_gf); + + int order_quad = max(2, 2*order+1); + const IntegrationRule *irs[Geometry::NumGeom]; + for (int i=0; i < Geometry::NumGeom; ++i) + { + irs[i] = &(IntRules.Get(i, order_quad)); + } + + double L2err = 0.0; + switch (prob) + { + case 0: + L2err = u_gf.ComputeL2Error(*u_ex); + break; + case 1: + case 2: + L2err = u_gf.ComputeL2Error(*U_ex); + break; + default: + break; + } + + if (myid == 0) + { + cout << " || u_h - u ||_{L^2} = " << L2err << endl; + } + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + string keys; + if (dim ==2 ) + { + keys = "keys UUmrRljc\n"; + } + else + { + keys = "keys mc\n"; + } + socketstream sol_sock(vishost, visport); + sol_sock << "parallel " << num_procs << " " << myid << "\n"; + sol_sock.precision(8); + sol_sock << "solution\n" << *pmesh << u_gf << + "window_title 'Numerical Pressure (real part)' " + << keys << flush; + } + + delete fespace; + delete fec; + delete pmesh; + MPI_Finalize(); + + return 0; +} + +double u_exact(const Vector &x) +{ + double u; + double y=0; + for (int i=0; i Date: Tue, 5 May 2020 10:48:28 -0700 Subject: [PATCH 286/535] Setting default value for `ElementTransformation::geom` --- fem/eltrans.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index f852577a9d..a0b1c5dda9 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -19,6 +19,7 @@ namespace mfem ElementTransformation::ElementTransformation() : IntPoint(static_cast(NULL)), EvalState(0), + geom(Geometry::INVALID), Attribute(-1), ElementNo(-1) { } From af3cdb67ea9bcecc4868d19a1397cbe38ef49cba Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 5 May 2020 11:09:11 -0700 Subject: [PATCH 287/535] Clarifying the `FaceElementTransformation::SetGeometryType` documentation --- fem/eltrans.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index ac9886b954..be9b42c91d 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -397,10 +397,11 @@ public: /** @brief Method to set the geometry type of the face. - @note This method should only be used when - [Par]Mesh::GetFaceTransformation will not be called i.e. when the - face transformation will not be needed but the neighboring - element transformations will be. + @note This method is designed to be used when + [Par]Mesh::GetFaceTransformation will not be called i.e. when + the face transformation will not be needed but the neighboring + element transformations will be. Using this method to override + the GeometryType should only be done with great care. */ void SetGeometryType(Geometry::Type g) { geom = g; } From a8ebdf16bd1da3455b9703cecea58ed710f1dd65 Mon Sep 17 00:00:00 2001 From: psocratis Date: Tue, 5 May 2020 15:19:27 -0700 Subject: [PATCH 288/535] Added convergence tests --- examples/BestApprox.cpp | 293 ------------------ fem/lininteg.cpp | 31 +- .../convergence/BAE.cpp | 203 ++++++------ tests/convergence/makefile | 77 +++++ 4 files changed, 211 insertions(+), 393 deletions(-) delete mode 100644 examples/BestApprox.cpp rename examples/BestApproxp.cpp => tests/convergence/BAE.cpp (61%) create mode 100644 tests/convergence/makefile diff --git a/examples/BestApprox.cpp b/examples/BestApprox.cpp deleted file mode 100644 index 7472afd705..0000000000 --- a/examples/BestApprox.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// -// Compile with: make helmholtz -// -// Sample runs: helmholtz -m ../data/one-hex.mesh -// helmholtz -m ../data/fichera.mesh -// helmholtz -m ../data/fichera-mixed.mesh -// -// Description: This example code demonstrates the use of MFEM to define a -// simple finite element discretization of the Helmholtz problem -// -Delta p - omega^2 u = 1 with impedance boundary conditiones. -// -#include "mfem.hpp" -#include -#include - -using namespace std; -using namespace mfem; - -// H1 -double u_exact(const Vector &x); -void gradu_exact(const Vector &x, Vector &gradu); - -// Vector FE -void U_exact(const Vector &x, Vector & U); -// H(curl) -void curlU_exact(const Vector &x, Vector &curlU); -double curlU2D_exact(const Vector &x); -// H(div) -double divU_exact(const Vector &x); - -int dim; -int prob=0; -Vector alpha; - -int main(int argc, char *argv[]) -{ - // geometry file - const char *mesh_file = "../data/inline-quad.mesh"; - // finite element order of approximation - int order = 1; - // static condensation flag - bool visualization = 1; - // number of initial ref - int ref = 1; - - // optional command line inputs - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); - args.AddOption(&prob, "-prob", "--problem", - "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); - args.AddOption(&ref, "-ref", "--ref", - "Number of refinements."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - // check if the inputs are correct - if (!args.Good()) - { - args.PrintUsage(cout); - return 1; - } - args.PrintOptions(cout); - - // 3. Read the mesh from the given mesh file. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - // Mesh *mesh = new Mesh(1, 1, Element::QUADRILATERAL, true, 1.0, 1.0, false); - dim = mesh->Dimension(); - - alpha.SetSize(dim); - for (int i=0; iUniformRefinement(); - } - - // 6. Define a finite element space on the mesh. - FiniteElementCollection *fec=nullptr; - switch (prob) - { - case 0: fec = new H1_FECollection(order,dim); break; - case 1: fec = new ND_FECollection(order,dim); break; - case 2: fec = new RT_FECollection(order-1,dim); break; - default: break; - } - FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); - cout << "Number of finite element unknowns: " << fespace->GetTrueVSize() - << endl; - - Array ess_tdof_list; - if (mesh->bdr_attributes.Size()) - { - Array ess_bdr(mesh->bdr_attributes.Max()); - ess_bdr = 0; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - - GridFunction u_gf(fespace); - FunctionCoefficient * u, *divU, *curlU2D; - VectorFunctionCoefficient * U, *gradu, *curlU; - - FunctionCoefficient *u_ex=nullptr; - VectorFunctionCoefficient *U_ex=nullptr; - - ConstantCoefficient one(1.0); - - // Calculate H1 projection - LinearForm b(fespace); - BilinearForm a(fespace); - - switch (prob) - { - case 0: //(grad u_ex, grad v) + (u_ex,v) - u_ex = new FunctionCoefficient(u_exact); - - u = new FunctionCoefficient(u_exact); - gradu = new VectorFunctionCoefficient(dim,gradu_exact); - b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); - b.AddDomainIntegrator(new DomainLFIntegrator(*u)); - - // (grad u, grad v) + (u,v) - a.AddDomainIntegrator(new DiffusionIntegrator(one)); - a.AddDomainIntegrator(new MassIntegrator(one)); - - break; - case 1: //(curl u_ex, curl v + (u_ex,v) - U_ex = new VectorFunctionCoefficient(dim,U_exact); - - U = new VectorFunctionCoefficient(dim,U_exact); - if (dim == 3) - { - curlU = new VectorFunctionCoefficient(dim,curlU_exact); - b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU)); - } - else if (dim == 2) - { - curlU2D = new FunctionCoefficient(curlU2D_exact); - b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); - } - b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); - // (curl u, curl v) + (u,v) - a.AddDomainIntegrator(new CurlCurlIntegrator(one)); - a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); - break; - - case 2: //(div u_ex, div v) + (u_ex,v) - U_ex = new VectorFunctionCoefficient(dim,U_exact); - U = new VectorFunctionCoefficient(dim,U_exact); - divU = new FunctionCoefficient(divU_exact); - b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); - b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); - - // (div u, div v) + (u,v) - a.AddDomainIntegrator(new DivDivIntegrator(one)); - a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); - break; - - default: - break; - } - b.Assemble(); - a.Assemble(); - OperatorPtr A; - Vector X, B; - a.FormLinearSystem(ess_tdof_list, u_gf, b, A, X,B); - - UMFPackSolver umf_solver; - umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; - umf_solver.SetOperator(*A); - umf_solver.Mult(B, X); - - a.RecoverFEMSolution(X,B,u_gf); - - int order_quad = max(2, 2*order+1); - const IntegrationRule *irs[Geometry::NumGeom]; - for (int i=0; i < Geometry::NumGeom; ++i) - { - irs[i] = &(IntRules.Get(i, order_quad)); - } - - double L2err = 0.0; - switch (prob) - { - case 0: - L2err = u_gf.ComputeL2Error(*u_ex); - break; - case 1: - case 2: - L2err = u_gf.ComputeL2Error(*U_ex); - break; - default: - break; - } - - cout << " || u_h - u ||_{L^2} = " << L2err << endl; - - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - string keys; - if (dim ==2 ) - { - // keys = "keys mrRljc\n"; - keys = "keys \n"; - } - else - { - keys = "keys mc\n"; - } - socketstream sol_sock(vishost, visport); - sol_sock.precision(8); - sol_sock << "solution\n" << *mesh << u_gf << - "window_title 'Numerical Pressure (real part)' " - << keys << flush; - } - - delete fespace; - delete fec; - delete mesh; - return 0; -} - -double u_exact(const Vector &x) -{ - double u; - double y=0; - for (int i=0; iEvalDelta(Trans, Trans.GetIntPoint()); } -void DomainLFGradIntegrator::AssembleRHSElementVect(const FiniteElement &el, - ElementTransformation &Tr, Vector &elvect) +void DomainLFGradIntegrator::AssembleRHSElementVect( + const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); int spaceDim = Tr.GetSpaceDim(); @@ -95,10 +95,10 @@ void DomainLFGradIntegrator::AssembleRHSElementVect(const FiniteElement &el, } } -void DomainLFGradIntegrator::AssembleDeltaElementVect(const FiniteElement &fe, - ElementTransformation &Trans, Vector &elvect) +void DomainLFGradIntegrator::AssembleDeltaElementVect( + const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) { - MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); + MFEM_ASSERT(vec_delta != NULL,"coefficient must be VectorDeltaCoefficient"); int dof = fe.GetDof(); int spaceDim = Trans.GetSpaceDim(); @@ -472,9 +472,21 @@ void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect( void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect( const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) { - MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); - int dof = fe.GetDof(); int spaceDim = Trans.GetSpaceDim(); + switch (spaceDim) + { + case 3: + MFEM_ASSERT(vec_delta != NULL, + "coefficient must be VectorDeltaCoefficient"); + break; + case 2: + MFEM_ASSERT(delta != NULL, + "coefficient must be DeltaCoefficient"); + break; + default: + break; // This should be unreachable + } + int dof = fe.GetDof(); int n=(spaceDim == 3)? spaceDim : 1; curlshape.SetSize(dof, n); elvect.SetSize(dof); @@ -487,7 +499,6 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect( curlshape.Mult(vec, elvect); break; case 2: - // Extract 1st column of curlshape to elvect curlshape.GetColumn(0,elvect); elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); break; @@ -498,9 +509,7 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect( } void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect( - const FiniteElement &el, - ElementTransformation &Tr, - Vector &elvect) + const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); diff --git a/examples/BestApproxp.cpp b/tests/convergence/BAE.cpp similarity index 61% rename from examples/BestApproxp.cpp rename to tests/convergence/BAE.cpp index d80084e5e8..f41960200c 100644 --- a/examples/BestApproxp.cpp +++ b/tests/convergence/BAE.cpp @@ -1,13 +1,20 @@ // -// Compile with: make helmholtz +// Compile with: make BAE // -// Sample runs: helmholtz -m ../data/one-hex.mesh -// helmholtz -m ../data/fichera.mesh -// helmholtz -m ../data/fichera-mixed.mesh +// Sample runs: mpirun -np 4 BAE -m ../../data/inline-segment.mesh -sr 1 -pr 4 -prob 0 -o 1 +// mpirun -np 4 BAE -m ../../data/inline-quad.mesh -sr 1 -pr 3 -prob 0 -o 2 +// mpirun -np 4 BAE -m ../../data/inline-quad.mesh -sr 1 -pr 3 -prob 1 -o 2 +// mpirun -np 4 BAE -m ../../data/inline-quad.mesh -sr 1 -pr 3 -prob 2 -o 2 +// mpirun -np 4 BAE -m ../../data/inline-tri.mesh -sr 1 -pr 3 -prob 2 -o 3 +// mpirun -np 4 BAE -m ../../data/star.mesh -sr 1 -pr 2 -prob 1 -o 4 +// mpirun -np 4 BAE -m ../../data/fichera.mesh -sr 1 -pr 2 -prob 2 -o 2 +// mpirun -np 4 BAE -m ../../data/inline-wedge.mesh -sr 0 -pr 2 -prob 0 -o 2 +// mpirun -np 4 BAE -m ../../data/inline-hex.mesh -sr 0 -pr 1 -prob 1 -o 3 +// mpirun -np 4 BAE -m ../../data/square-disc.mesh -sr 1 -pr 2 -prob 1 -o 2 // -// Description: This example code demonstrates the use of MFEM to define a -// simple finite element discretization of the Helmholtz problem -// -Delta p - omega^2 u = 1 with impedance boundary conditiones. +// Description: This example code is used for testing the LF-integrators +// (Q,grad v), (Q,curl V), (Q, div v) +// by solving the appropriate energy projection problems // #include "mfem.hpp" #include @@ -55,8 +62,7 @@ int main(int argc, char *argv[]) args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree) or -1 for" - " isoparametric space."); + "Finite element order (polynomial degree)"); args.AddOption(&prob, "-prob", "--problem", "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); args.AddOption(&sr, "-sr", "--serial_ref", @@ -84,11 +90,10 @@ int main(int argc, char *argv[]) // 3. Read the mesh from the given mesh file. Mesh *mesh = new Mesh(mesh_file, 1, 1); - // Mesh *mesh = new Mesh(1, 1, Element::QUADRILATERAL, true, 1.0, 1.0, false); - dim = mesh->Dimension(); + dim = mesh->Dimension(); if (dim == 1 ) prob = 0; - alpha.SetSize(dim); - for (int i=0; iUniformRefinement(); - } // 6. Define a finite element space on the mesh. FiniteElementCollection *fec=nullptr; @@ -113,32 +114,16 @@ int main(int argc, char *argv[]) } ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); - Array ess_tdof_list; - if (pmesh->bdr_attributes.Size()) - { - Array ess_bdr(pmesh->bdr_attributes.Max()); - ess_bdr = 0; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - ParGridFunction u_gf(fespace); - FunctionCoefficient * u, *divU, *curlU2D; - VectorFunctionCoefficient * U, *gradu, *curlU; - - FunctionCoefficient *u_ex=nullptr; - VectorFunctionCoefficient *U_ex=nullptr; + FunctionCoefficient *u, *divU, *curlU2D; + VectorFunctionCoefficient *U, *gradu, *curlU; ConstantCoefficient one(1.0); - - // Calculate H1 projection ParLinearForm b(fespace); ParBilinearForm a(fespace); - switch (prob) { case 0: //(grad u_ex, grad v) + (u_ex,v) - u_ex = new FunctionCoefficient(u_exact); - u = new FunctionCoefficient(u_exact); gradu = new VectorFunctionCoefficient(dim,gradu_exact); b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); @@ -150,8 +135,6 @@ int main(int argc, char *argv[]) break; case 1: //(curl u_ex, curl v + (u_ex,v) - U_ex = new VectorFunctionCoefficient(dim,U_exact); - U = new VectorFunctionCoefficient(dim,U_exact); if (dim == 3) { @@ -170,7 +153,6 @@ int main(int argc, char *argv[]) break; case 2: //(div u_ex, div v) + (u_ex,v) - U_ex = new VectorFunctionCoefficient(dim,U_exact); U = new VectorFunctionCoefficient(dim,U_exact); divU = new FunctionCoefficient(divU_exact); b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); @@ -184,61 +166,104 @@ int main(int argc, char *argv[]) default: break; } - b.Assemble(); - a.Assemble(); - OperatorPtr A; - Vector X, B; - a.FormLinearSystem(ess_tdof_list, u_gf, b, A, X,B); - Solver *prec = NULL; - switch (prob) + double L2err0 = 0.0; + for (int l = 0; l <= pr; l++) { - case 0: prec = new HypreBoomerAMG(*A.As()); break; - case 1: prec = new HypreAMS(*A.As(), fespace); break; - case 2: - if (dim == 2) {prec = new HypreAMS(*A.As(), fespace);} - else {prec = new HypreADS(*A.As(), fespace);} - break; - default: - break; + b.Assemble(); + a.Assemble(); + Array ess_tdof_list; + if (pmesh->bdr_attributes.Size()) + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 0; + fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + OperatorPtr A; + Vector X, B; + a.FormLinearSystem(ess_tdof_list, u_gf, b, A, X,B); + + Solver *prec = NULL; + switch (prob) + { + case 0: + prec = new HypreBoomerAMG(*A.As()); + dynamic_cast(prec)->SetPrintLevel(0); + break; + case 1: + prec = new HypreAMS(*A.As(), fespace); + dynamic_cast(prec)->SetPrintLevel(0); + break; + case 2: + if (dim == 2) + { + prec = new HypreAMS(*A.As(), fespace); + dynamic_cast(prec)->SetPrintLevel(0); + } + else + { + prec = new HypreADS(*A.As(), fespace); + dynamic_cast(prec)->SetPrintLevel(0); + } + break; + default: + break; + } + + CGSolver cg(MPI_COMM_WORLD); + cg.SetRelTol(1e-12); + cg.SetMaxIter(2000); + cg.SetPrintLevel(0); + if (prec) { cg.SetPreconditioner(*prec); } + cg.SetOperator(*A); + cg.Mult(B, X); + delete prec; + + a.RecoverFEMSolution(X,B,u_gf); + + int order_quad = max(2, 2*order+1); + const IntegrationRule *irs[Geometry::NumGeom]; + for (int i=0; i < Geometry::NumGeom; ++i) + { + irs[i] = &(IntRules.Get(i, order_quad)); + } + + double L2err = 0.0; + switch (prob) + { + case 0: + L2err = u_gf.ComputeL2Error(*u); + break; + case 1: + case 2: + L2err = u_gf.ComputeL2Error(*U); + break; + default: + break; + } + if (myid == 0) + { + double rate=0.0; + if (l>0) + { + rate = log(L2err0/L2err)/log(2.0); + } + cout << setprecision(3); + + cout << "|| u_h - u ||_{L^2} = " << scientific + << L2err << ", rate: " << fixed << rate << endl; + L2err0 = L2err; + } + + if (l==pr) break; + + pmesh->UniformRefinement(); + fespace->Update(); + a.Update(); + b.Update(); + u_gf.Update(); } - CGSolver cg(MPI_COMM_WORLD); - cg.SetRelTol(1e-12); - cg.SetMaxIter(2000); - cg.SetPrintLevel(1); - if (prec) { cg.SetPreconditioner(*prec); } - cg.SetOperator(*A); - cg.Mult(B, X); - delete prec; - - a.RecoverFEMSolution(X,B,u_gf); - - int order_quad = max(2, 2*order+1); - const IntegrationRule *irs[Geometry::NumGeom]; - for (int i=0; i < Geometry::NumGeom; ++i) - { - irs[i] = &(IntRules.Get(i, order_quad)); - } - - double L2err = 0.0; - switch (prob) - { - case 0: - L2err = u_gf.ComputeL2Error(*u_ex); - break; - case 1: - case 2: - L2err = u_gf.ComputeL2Error(*U_ex); - break; - default: - break; - } - - if (myid == 0) - { - cout << " || u_h - u ||_{L^2} = " << L2err << endl; - } if (visualization) { char vishost[] = "localhost"; diff --git a/tests/convergence/makefile b/tests/convergence/makefile new file mode 100644 index 0000000000..b723de9dc1 --- /dev/null +++ b/tests/convergence/makefile @@ -0,0 +1,77 @@ +# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# at the Lawrence Livermore National Laboratory. All Rights reserved. See files +# LICENSE and NOTICE for details. LLNL-CODE-806117. +# +# This file is part of the MFEM library. For more information and source code +# availability visit https://mfem.org. +# +# MFEM is free software; you can redistribute it and/or modify it under the +# terms of the BSD-3 license. We welcome feedback and contributions, see file +# CONTRIBUTING.md for details. + +# Use the MFEM build directory +MFEM_DIR ?= ../.. +MFEM_BUILD_DIR ?= ../.. +SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/tests/convergence/,) +CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk +# Use the MFEM install directory +# MFEM_INSTALL_DIR = ../mfem +# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk + +MFEM_LIB_FILE = mfem_is_not_built +-include $(CONFIG_MK) + +SEQ_EXAMPLES = +PAR_EXAMPLES = BAE + +ifeq ($(MFEM_USE_MPI),NO) + EXAMPLES = $(SEQ_EXAMPLES) +else + EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES) +endif + +SUBDIRS_ALL = $(addsuffix /all,$(SUBDIRS)) +SUBDIRS_TEST = $(addsuffix /test,$(SUBDIRS)) +SUBDIRS_CLEAN = $(addsuffix /clean,$(SUBDIRS)) +SUBDIRS_TPRINT = $(addsuffix /test-print,$(SUBDIRS)) + +.SUFFIXES: +.SUFFIXES: .o .cpp .mk +.PHONY: all clean clean-build + +# Remove built-in rule +%: %.cpp + +# Replace the default implicit rule for *.cpp files +%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) + $(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS) + +all: $(EXAMPLES) $(SUBDIRS_ALL) + +.PHONY: $(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_CLEAN) $(SUBDIRS_TPRINT) +$(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_CLEAN): + $(MAKE) -C $(@D) $(@F) +$(SUBDIRS_TPRINT): + @$(MAKE) -C $(@D) $(@F) + +MFEM_TESTS = EXAMPLES +include $(MFEM_TEST_MK) +test: $(SUBDIRS_TEST) +test-print: $(SUBDIRS_TPRINT) + +# Testing: Parallel vs. serial runs +RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP) +%-test-par: % + @$(call mfem-test,$<, $(RUN_MPI), Parallel example) +%-test-seq: % + @$(call mfem-test,$<,, Serial example) + +# Generate an error message if the MFEM library is not built and exit +$(MFEM_LIB_FILE): + $(error The MFEM library is not built) + +clean: clean-build clean-exec $(SUBDIRS_CLEAN) + +clean-build: + rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES) + rm -rf *.dSYM *.TVD.*breakpoints \ No newline at end of file From 20089dd62beaa848a26f6b40cbd8c912ed4b2002 Mon Sep 17 00:00:00 2001 From: Socratis Date: Tue, 5 May 2020 15:36:16 -0700 Subject: [PATCH 289/535] valgrind checks passed --- tests/convergence/BAE.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/convergence/BAE.cpp b/tests/convergence/BAE.cpp index f41960200c..5df1d6aa30 100644 --- a/tests/convergence/BAE.cpp +++ b/tests/convergence/BAE.cpp @@ -221,13 +221,6 @@ int main(int argc, char *argv[]) a.RecoverFEMSolution(X,B,u_gf); - int order_quad = max(2, 2*order+1); - const IntegrationRule *irs[Geometry::NumGeom]; - for (int i=0; i < Geometry::NumGeom; ++i) - { - irs[i] = &(IntRules.Get(i, order_quad)); - } - double L2err = 0.0; switch (prob) { From 0a6113d4979869a7bd99271909bdad0115ca6b7d Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 6 May 2020 13:44:46 -0700 Subject: [PATCH 290/535] Adding EDGE and FACE cases to GetValue and GetVectorValue for continuous fields --- fem/gridfunc.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 197719ba7e..faf114c3fc 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -694,6 +694,34 @@ double GridFunction::GetValue(ElementTransformation &T, fe = fes->GetFE(T.ElementNo); fes->GetElementDofs(T.ElementNo, dofs); break; + case ElementTransformation::EDGE: + if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + { + fe = fes->GetEdgeElement(T.ElementNo); + fes->GetEdgeDofs(T.ElementNo, dofs); + } + else + { + MFEM_ABORT("GridFunction::GetValue: Field continuity type \"" + << fes->FEColl()->GetContType() << "\" not supported " + << "on mesh edges."); + return NAN; + } + break; + case ElementTransformation::FACE: + if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + { + fe = fes->GetFaceElement(T.ElementNo); + fes->GetFaceDofs(T.ElementNo, dofs); + } + else + { + MFEM_ABORT("GridFunction::GetValue: Field continuity type \"" + << fes->FEColl()->GetContType() << "\" not supported " + << "on mesh faces."); + return NAN; + } + break; case ElementTransformation::BDR_ELEMENT: { if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) @@ -799,6 +827,34 @@ void GridFunction::GetVectorValue(ElementTransformation &T, fes->GetElementVDofs(T.ElementNo, vdofs); fe = fes->GetFE(T.ElementNo); break; + case ElementTransformation::EDGE: + if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + { + fe = fes->GetEdgeElement(T.ElementNo); + fes->GetEdgeVDofs(T.ElementNo, vdofs); + } + else + { + MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \"" + << fes->FEColl()->GetContType() << "\" not supported " + << "on mesh edges."); + return; + } + break; + case ElementTransformation::FACE: + if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + { + fe = fes->GetFaceElement(T.ElementNo); + fes->GetFaceVDofs(T.ElementNo, vdofs); + } + else + { + MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \"" + << fes->FEColl()->GetContType() << "\" not supported " + << "on mesh faces."); + return; + } + break; case ElementTransformation::BDR_ELEMENT: { if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) From a090b75f2667fe3272bca6ebe4c64b969e16a783 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 6 May 2020 14:21:10 -0700 Subject: [PATCH 291/535] Replacing explicit 2's and 3's with `dim` in get value unit tests --- tests/unit/fem/test_get_value.cpp | 102 +++++++++++++++--------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index ee224c9de9..f84ca21916 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -338,8 +338,8 @@ TEST_CASE("2D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[2]; - Vector tip(tip_data, 2); + double tip_data[dim]; + Vector tip(tip_data, dim); for (int j=0; j Date: Wed, 6 May 2020 14:21:43 -0700 Subject: [PATCH 292/535] Adding unit tests for EDGE and FACE cases of GetValue and GetVectorValue --- tests/unit/fem/test_get_value.cpp | 264 +++++++++++++++++++++++++++++- 1 file changed, 257 insertions(+), 7 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index f84ca21916..af225bb675 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -509,6 +509,45 @@ TEST_CASE("2D GetValue", REQUIRE(dgi_err == Approx(0.0)); } } + + SECTION("Edge Evaluation 2D (H1 Context)") + { + std::cout << "Edge Evaluation 2D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNEdges(); e++) + { + ElementTransformation *T = mesh.GetEdgeTransformation(e); + const FiniteElement *fe = h1_fespace.GetEdgeElement(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + } + } } } std::cout << "Checked GridFunction::GetValue at " @@ -743,6 +782,84 @@ TEST_CASE("3D GetValue", REQUIRE(dgi_err == Approx(0.0)); } } + + SECTION("Edge Evaluation 3D (H1 Context)") + { + std::cout << "Edge Evaluation 3D (H1 Context)" << std::endl; + for (int e = 0; e < mesh.GetNEdges(); e++) + { + ElementTransformation *T = mesh.GetEdgeTransformation(e); + const FiniteElement *fe = h1_fespace.GetEdgeElement(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + } + } + + SECTION("Face Evaluation 3D (H1 Context)") + { + std::cout << "Face Evaluation 3D (H1 Context)" << std::endl; + for (int f = 0; f < mesh.GetNFaces(); f++) + { + ElementTransformation *T = mesh.GetFaceTransformation(f); + const FiniteElement *fe = h1_fespace.GetFaceElement(f); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + + h1_err += fabs(f_val - h1_gf_val); + + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << f << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + + REQUIRE(h1_err == Approx(0.0)); + } + } } } std::cout << "Checked GridFunction::GetValue at " @@ -1140,6 +1257,49 @@ TEST_CASE("2D GetVectorValue", REQUIRE(dgi_err == Approx(0.0)); } } + + SECTION("Edge Evaluation 2D") + { + std::cout << "Edge Evaluation 2D" << std::endl; + for (int e = 0; e < mesh.GetNEdges(); e++) + { + ElementTransformation *T = mesh.GetEdgeTransformation(e); + const FiniteElement *fe = h1_fespace.GetEdgeElement(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_2D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, 2); + + h1_err += h1_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + } + h1_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + } + } } } std::cout << "Checked GridFunction::GetVectorValue at " @@ -1205,13 +1365,13 @@ TEST_CASE("3D GetVectorValue", dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); - Vector f_val(3); f_val = 0.0; - Vector h1_gf_val(3); h1_gf_val = 0.0; - Vector nd_gf_val(3); nd_gf_val = 0.0; - Vector rt_gf_val(3); rt_gf_val = 0.0; - Vector l2_gf_val(3); l2_gf_val = 0.0; - Vector dgv_gf_val(3); dgv_gf_val = 0.0; - Vector dgi_gf_val(3); dgi_gf_val = 0.0; + Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector nd_gf_val(dim); nd_gf_val = 0.0; + Vector rt_gf_val(dim); rt_gf_val = 0.0; + Vector l2_gf_val(dim); l2_gf_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector dgi_gf_val(dim); dgi_gf_val = 0.0; SECTION("Domain Evaluation 3D") { @@ -1573,6 +1733,96 @@ TEST_CASE("3D GetVectorValue", REQUIRE(dgi_err == Approx(0.0)); } } + + SECTION("Edge Evaluation 3D") + { + std::cout << "Edge Evaluation 3D" << std::endl; + for (int e = 0; e < mesh.GetNEdges(); e++) + { + ElementTransformation *T = mesh.GetEdgeTransformation(e); + const FiniteElement *fe = h1_fespace.GetEdgeElement(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + + h1_err += h1_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + } + } + + SECTION("Face Evaluation 3D") + { + std::cout << "Face Evaluation 3D" << std::endl; + for (int f = 0; f < mesh.GetNFaces(); f++) + { + ElementTransformation *T = mesh.GetFaceTransformation(f); + const FiniteElement *fe = h1_fespace.GetFaceElement(f); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + h1_xCoef.Eval(h1_gf_val, *T, ip); + + double h1_dist = Distance(f_val, h1_gf_val, dim); + + h1_err += h1_dist; + + if (log > 0 && h1_dist > tol) + { + std::cout << f << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + } + h1_err /= ir.GetNPoints(); + + REQUIRE( h1_err == Approx(0.0)); + } + } } } std::cout << "Checked GridFunction::GetVectorValue at " From ada4fcca83cc14230630a488939f4733eef6b837 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 6 May 2020 14:52:48 -0700 Subject: [PATCH 293/535] Moving field continuity `enum` to `FiniteElementCollection` --- fem/fe.hpp | 137 ----------------------------------------------- fem/fe_coll.hpp | 69 +++++++++++++----------- fem/gridfunc.cpp | 18 ++++--- 3 files changed, 51 insertions(+), 173 deletions(-) diff --git a/fem/fe.hpp b/fem/fe.hpp index 8390fb2ff6..b8d1982574 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -294,15 +294,6 @@ public: CURL ///< Implements CalcCurlShape methods }; - /** @brief Enumeration for ContType: defines the continuity of the - field across element interfaces. - */ - enum { CONTINUOUS, ///< Field is continuous across element interfaces - TANGENTIAL, ///< Tangential components of vector field - NORMAL, ///< Normal component of vector field - DISCONTINUOUS ///< Field is discontinuous across element interfaces - }; - /** Construct FiniteElement with given @param D Reference space dimension @param G Geometry type (of type Geometry::Type) @@ -346,8 +337,6 @@ public: int GetDerivMapType() const { return DerivMapType; } - virtual int GetContType() const = 0; - /** @brief Evaluate the values of all shape functions of a scalar finite element in reference space at the given point @a ip. */ /** The size (#Dof) of the result Vector @a shape must be set in advance. */ @@ -825,8 +814,6 @@ class PointFiniteElement : public NodalFiniteElement public: PointFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } - virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -840,9 +827,6 @@ public: /// Construct a linear FE on interval Linear1DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (2) */ @@ -863,9 +847,6 @@ public: /// Construct a linear FE on triangle Linear2DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (3) */ @@ -888,9 +869,6 @@ public: /// Construct a bilinear FE on quadrilateral BiLinear2DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (4) */ @@ -913,7 +891,6 @@ class GaussLinear2DFiniteElement : public NodalFiniteElement { public: GaussLinear2DFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -928,7 +905,6 @@ private: public: GaussBiLinear2DFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -939,7 +915,6 @@ class P1OnQuadFiniteElement : public NodalFiniteElement { public: P1OnQuadFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -954,9 +929,6 @@ public: /// Construct a quadratic FE on interval Quad1DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (3) */ @@ -974,7 +946,6 @@ class QuadPos1DFiniteElement : public PositiveFiniteElement { public: QuadPos1DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -987,9 +958,6 @@ public: /// Construct a quadratic FE on triangle Quad2DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (6) */ @@ -1017,7 +985,6 @@ private: mutable Vector pol; public: GaussQuad2DFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1031,9 +998,6 @@ public: /// Construct a biquadratic FE on quadrilateral BiQuad2DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (9) */ @@ -1052,7 +1016,6 @@ class BiQuadPos2DFiniteElement : public PositiveFiniteElement { public: BiQuadPos2DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1072,7 +1035,6 @@ class GaussBiQuad2DFiniteElement : public NodalFiniteElement { public: GaussBiQuad2DFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1083,7 +1045,6 @@ class BiCubic2DFiniteElement : public NodalFiniteElement { public: BiCubic2DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1096,8 +1057,6 @@ class Cubic1DFiniteElement : public NodalFiniteElement public: Cubic1DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1109,8 +1068,6 @@ class Cubic2DFiniteElement : public NodalFiniteElement public: Cubic2DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1127,8 +1084,6 @@ public: /// Construct a cubic FE on tetrahedron Cubic3DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1142,8 +1097,6 @@ public: /// Construct P0 triangle finite element P0TriangleFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } - /// evaluate shape function - constant 1 virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; @@ -1159,7 +1112,6 @@ class P0QuadFiniteElement : public NodalFiniteElement { public: P0QuadFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1175,9 +1127,6 @@ public: /// Construct a linear FE on tetrahedron Linear3DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (4) */ @@ -1203,9 +1152,6 @@ public: /// Construct a quadratic FE on tetrahedron Quadratic3DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1219,9 +1165,6 @@ public: /// Construct a tri-linear FE on cube TriLinear3DFiniteElement(); - /// Returns the continuity of the field - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (8) */ @@ -1244,7 +1187,6 @@ class CrouzeixRaviartFiniteElement : public NodalFiniteElement { public: CrouzeixRaviartFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1257,7 +1199,6 @@ class CrouzeixRaviartQuadFiniteElement : public NodalFiniteElement { public: CrouzeixRaviartQuadFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1267,7 +1208,6 @@ class P0SegmentFiniteElement : public NodalFiniteElement { public: P0SegmentFiniteElement(int Ord = 0); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1281,8 +1221,6 @@ private: public: RT0TriangleFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1310,8 +1248,6 @@ private: public: RT0QuadFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1339,8 +1275,6 @@ private: public: RT1TriangleFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1368,8 +1302,6 @@ private: public: RT1QuadFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1396,8 +1328,6 @@ private: public: RT2TriangleFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1419,8 +1349,6 @@ private: public: RT2QuadFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1445,7 +1373,6 @@ class P1SegmentFiniteElement : public NodalFiniteElement { public: P1SegmentFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1456,7 +1383,6 @@ class P2SegmentFiniteElement : public NodalFiniteElement { public: P2SegmentFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1471,7 +1397,6 @@ private: #endif public: Lagrange1DFiniteElement (int degree); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1481,7 +1406,6 @@ class P1TetNonConfFiniteElement : public NodalFiniteElement { public: P1TetNonConfFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1491,7 +1415,6 @@ class P0TetFiniteElement : public NodalFiniteElement { public: P0TetFiniteElement (); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1503,7 +1426,6 @@ class P0HexFiniteElement : public NodalFiniteElement { public: P0HexFiniteElement (); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1525,7 +1447,6 @@ private: public: LagrangeHexFiniteElement (int degree); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -1540,8 +1461,6 @@ public: /// Construct a quadratic FE on interval RefinedLinear1DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (3) */ @@ -1562,8 +1481,6 @@ public: /// Construct a quadratic FE on triangle RefinedLinear2DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (6) */ @@ -1584,8 +1501,6 @@ public: /// Construct a quadratic FE on tetrahedron RefinedLinear3DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, @@ -1599,8 +1514,6 @@ public: /// Construct a biquadratic FE on quadrilateral RefinedBiLinear2DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (9) */ @@ -1621,8 +1534,6 @@ public: /// Construct a biquadratic FE on quadrilateral RefinedTriLinear3DFiniteElement(); - virtual int GetContType() const { return CONTINUOUS; } - /** virtual function which evaluates the values of all shape functions at a given point ip and stores them in the vector shape of dimension Dof (9) */ @@ -1644,7 +1555,6 @@ private: public: Nedelec1HexFiniteElement(); - virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -1667,7 +1577,6 @@ private: public: Nedelec1TetFiniteElement(); - virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -1691,8 +1600,6 @@ private: public: RT0HexFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1721,8 +1628,6 @@ private: public: RT1HexFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1751,8 +1656,6 @@ private: public: RT0TetFiniteElement(); - virtual int GetContType() const { return NORMAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -1777,7 +1680,6 @@ class RotTriLinearHexFiniteElement : public NodalFiniteElement { public: RotTriLinearHexFiniteElement(); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2039,7 +1941,6 @@ private: public: H1_SegmentElement(const int p, const int btype = BasisType::GaussLobatto); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2057,7 +1958,6 @@ private: public: H1_QuadrilateralElement(const int p, const int btype = BasisType::GaussLobatto); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2074,7 +1974,6 @@ private: public: H1_HexahedronElement(const int p, const int btype = BasisType::GaussLobatto); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2095,7 +1994,6 @@ private: public: H1Pos_SegmentElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2113,7 +2011,6 @@ private: public: H1Pos_QuadrilateralElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2125,7 +2022,6 @@ class H1Ser_QuadrilateralElement : public ScalarFiniteElement { public: H1Ser_QuadrilateralElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2144,7 +2040,6 @@ private: public: H1Pos_HexahedronElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2164,7 +2059,6 @@ private: public: H1_TriangleElement(const int p, const int btype = BasisType::GaussLobatto); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2187,7 +2081,6 @@ private: public: H1_TetrahedronElement(const int p, const int btype = BasisType::GaussLobatto); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2208,8 +2101,6 @@ protected: public: H1Pos_TriangleElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } - // The size of shape is (p+1)(p+2)/2 (dof). static void CalcShape(const int p, const double x, const double y, double *shape); @@ -2236,8 +2127,6 @@ protected: public: H1Pos_TetrahedronElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } - // The size of shape is (p+1)(p+2)(p+3)/6 (dof). static void CalcShape(const int p, const double x, const double y, const double z, double *shape); @@ -2267,7 +2156,6 @@ private: public: H1_WedgeElement(const int p, const int btype = BasisType::GaussLobatto); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2312,7 +2200,6 @@ protected: public: H1Pos_WedgeElement(const int p); - virtual int GetContType() const { return CONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2328,7 +2215,6 @@ private: public: L2_SegmentElement(const int p, const int btype = BasisType::GaussLegendre); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2345,7 +2231,6 @@ private: public: L2Pos_SegmentElement(const int p); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2363,7 +2248,6 @@ private: public: L2_QuadrilateralElement(const int p, const int btype = BasisType::GaussLegendre); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2384,7 +2268,6 @@ private: public: L2Pos_QuadrilateralElement(const int p); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2402,7 +2285,6 @@ private: public: L2_HexahedronElement(const int p, const int btype = BasisType::GaussLegendre); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2419,7 +2301,6 @@ private: public: L2Pos_HexahedronElement(const int p); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2439,7 +2320,6 @@ private: public: L2_TriangleElement(const int p, const int btype = BasisType::GaussLegendre); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2460,7 +2340,6 @@ private: public: L2Pos_TriangleElement(const int p); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2481,7 +2360,6 @@ private: public: L2_TetrahedronElement(const int p, const int btype = BasisType::GaussLegendre); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2498,7 +2376,6 @@ private: public: L2Pos_TetrahedronElement(const int p); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2521,7 +2398,6 @@ private: public: L2_WedgeElement(const int p, const int btype = BasisType::GaussLegendre); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2548,7 +2424,6 @@ protected: public: L2Pos_WedgeElement(const int p); - virtual int GetContType() const { return DISCONTINUOUS; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; @@ -2571,7 +2446,6 @@ public: RT_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); - virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2628,7 +2502,6 @@ public: const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); - virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2678,7 +2551,6 @@ class RT_TriangleElement : public VectorFiniteElement public: RT_TriangleElement(const int p); - virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2734,7 +2606,6 @@ class RT_TetrahedronElement : public VectorFiniteElement public: RT_TetrahedronElement(const int p); - virtual int GetContType() const { return NORMAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2783,8 +2654,6 @@ public: const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); - virtual int GetContType() const { return TANGENTIAL; } - virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; @@ -2849,7 +2718,6 @@ public: ND_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); - virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2899,7 +2767,6 @@ class ND_TetrahedronElement : public VectorFiniteElement public: ND_TetrahedronElement(const int p); - virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2954,7 +2821,6 @@ class ND_TriangleElement : public VectorFiniteElement public: ND_TriangleElement(const int p); - virtual int GetContType() const { return TANGENTIAL; } virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const; virtual void CalcVShape(ElementTransformation &Trans, @@ -2999,7 +2865,6 @@ class ND_SegmentElement : public VectorFiniteElement public: ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre); - virtual int GetContType() const { return TANGENTIAL; } virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const { obasis1d.Eval(ip.x, shape); } virtual void CalcVShape(const IntegrationPoint &ip, @@ -3056,8 +2921,6 @@ public: weights = 1.0; } - virtual int GetContType() const { return CONTINUOUS; } - void Reset () const { patch = elem = -1; } void SetIJK (const int *IJK) const { ijk = IJK; } int GetPatch () const { return patch; } diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index fd101d98fa..89783d7ba9 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -40,6 +40,15 @@ protected: const int face_info); public: + /** @brief Enumeration for ContType: defines the continuity of the + field across element interfaces. + */ + enum { CONTINUOUS, ///< Field is continuous across element interfaces + TANGENTIAL, ///< Tangential components of vector field + NORMAL, ///< Normal component of vector field + DISCONTINUOUS ///< Field is discontinuous across element interfaces + }; + virtual const FiniteElement * FiniteElementForGeometry(Geometry::Type GeomType) const = 0; @@ -104,7 +113,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char *Name() const { return h1_name; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } FiniteElementCollection *GetTraceCollection() const; int GetBasisType() const { return b_type; } @@ -177,7 +186,7 @@ public: int Or) const; virtual const char *Name() const { return d_name; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } virtual const FiniteElement *TraceFiniteElementForGeometry( Geometry::Type GeomType) const @@ -226,7 +235,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char *Name() const { return rt_name; } - virtual int GetContType() const { return FiniteElement::NORMAL; } + virtual int GetContType() const { return NORMAL; } FiniteElementCollection *GetTraceCollection() const; virtual ~RT_FECollection(); @@ -276,7 +285,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char *Name() const { return nd_name; } - virtual int GetContType() const { return FiniteElement::TANGENTIAL; } + virtual int GetContType() const { return TANGENTIAL; } FiniteElementCollection *GetTraceCollection() const; virtual ~ND_FECollection(); @@ -341,7 +350,7 @@ public: virtual const char *Name() const { return name; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } FiniteElementCollection *GetTraceCollection() const; @@ -373,7 +382,7 @@ public: virtual const char * Name() const { return "Linear"; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } }; /// Piecewise-(bi)quadratic continuous finite elements. @@ -401,7 +410,7 @@ public: virtual const char * Name() const { return "Quadratic"; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } }; /// Version of QuadraticFECollection with positive basis functions. @@ -424,7 +433,7 @@ public: virtual const char * Name() const { return "QuadraticPos"; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } }; /// Piecewise-(bi)cubic continuous finite elements. @@ -453,7 +462,7 @@ public: virtual const char * Name() const { return "Cubic"; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } }; /// Crouzeix-Raviart nonconforming elements in 2D. @@ -476,7 +485,7 @@ public: virtual const char * Name() const { return "CrouzeixRaviart"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /// Piecewise-linear nonconforming finite elements in 3D. @@ -501,7 +510,7 @@ public: virtual const char * Name() const { return "LinearNonConf3D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; @@ -526,7 +535,7 @@ public: virtual const char * Name() const { return "RT0_2D"; } - virtual int GetContType() const { return FiniteElement::NORMAL; } + virtual int GetContType() const { return NORMAL; } }; /** Second order Raviart-Thomas finite elements in 2D. This class is kept only @@ -550,7 +559,7 @@ public: virtual const char * Name() const { return "RT1_2D"; } - virtual int GetContType() const { return FiniteElement::NORMAL; } + virtual int GetContType() const { return NORMAL; } }; /** Third order Raviart-Thomas finite elements in 2D. This class is kept only @@ -574,7 +583,7 @@ public: virtual const char * Name() const { return "RT2_2D"; } - virtual int GetContType() const { return FiniteElement::NORMAL; } + virtual int GetContType() const { return NORMAL; } }; /** Piecewise-constant discontinuous finite elements in 2D. This class is kept @@ -597,7 +606,7 @@ public: virtual const char * Name() const { return "Const2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /** Piecewise-linear discontinuous finite elements in 2D. This class is kept @@ -621,7 +630,7 @@ public: virtual const char * Name() const { return "LinearDiscont2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /// Version of LinearDiscont2DFECollection with dofs in the Gaussian points. @@ -645,7 +654,7 @@ public: virtual const char * Name() const { return "GaussLinearDiscont2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /// Linear (P1) finite elements on quadrilaterals. @@ -661,7 +670,7 @@ public: virtual const int *DofOrderForOrientation(Geometry::Type GeomType, int Or) const; virtual const char * Name() const { return "P1OnQuad"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept @@ -684,7 +693,7 @@ public: int Or) const; virtual const char * Name() const { return "QuadraticDiscont2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /// Version of QuadraticDiscont2DFECollection with positive basis functions. @@ -702,7 +711,7 @@ public: int Or) const { return NULL; } virtual const char * Name() const { return "QuadraticPosDiscont2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /// Version of QuadraticDiscont2DFECollection with dofs in the Gaussian points. @@ -725,7 +734,7 @@ public: int Or) const; virtual const char * Name() const { return "GaussQuadraticDiscont2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /** Piecewise-cubic discontinuous finite elements in 2D. This class is kept @@ -748,7 +757,7 @@ public: int Or) const; virtual const char * Name() const { return "CubicDiscont2D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /** Piecewise-constant discontinuous finite elements in 3D. This class is kept @@ -772,7 +781,7 @@ public: int Or) const; virtual const char * Name() const { return "Const3D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /** Piecewise-linear discontinuous finite elements in 3D. This class is kept @@ -795,7 +804,7 @@ public: int Or) const; virtual const char * Name() const { return "LinearDiscont3D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept @@ -818,7 +827,7 @@ public: int Or) const; virtual const char * Name() const { return "QuadraticDiscont3D"; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; /// Finite element collection on a macro-element. @@ -844,7 +853,7 @@ public: int Or) const; virtual const char * Name() const { return "RefinedLinear"; } - virtual int GetContType() const { return FiniteElement::CONTINUOUS; } + virtual int GetContType() const { return CONTINUOUS; } }; /** Lowest order Nedelec finite elements in 3D. This class is kept only for @@ -867,7 +876,7 @@ public: int Or) const; virtual const char * Name() const { return "ND1_3D"; } - virtual int GetContType() const { return FiniteElement::TANGENTIAL; } + virtual int GetContType() const { return TANGENTIAL; } }; /** First order Raviart-Thomas finite elements in 3D. This class is kept only @@ -891,7 +900,7 @@ public: int Or) const; virtual const char * Name() const { return "RT0_3D"; } - virtual int GetContType() const { return FiniteElement::NORMAL; } + virtual int GetContType() const { return NORMAL; } }; /** Second order Raviart-Thomas finite elements in 3D. This class is kept only @@ -914,7 +923,7 @@ public: int Or) const; virtual const char * Name() const { return "RT1_3D"; } - virtual int GetContType() const { return FiniteElement::NORMAL; } + virtual int GetContType() const { return NORMAL; } }; /// Discontinuous collection defined locally by a given finite element. @@ -939,7 +948,7 @@ public: virtual const char *Name() const { return d_name; } virtual ~Local_FECollection() { delete Local_Element; } - virtual int GetContType() const { return FiniteElement::DISCONTINUOUS; } + virtual int GetContType() const { return DISCONTINUOUS; } }; } diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index faf114c3fc..7626e73c18 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -695,7 +695,8 @@ double GridFunction::GetValue(ElementTransformation &T, fes->GetElementDofs(T.ElementNo, dofs); break; case ElementTransformation::EDGE: - if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + if (fes->FEColl()->GetContType() == + FiniteElementCollection::CONTINUOUS) { fe = fes->GetEdgeElement(T.ElementNo); fes->GetEdgeDofs(T.ElementNo, dofs); @@ -709,7 +710,8 @@ double GridFunction::GetValue(ElementTransformation &T, } break; case ElementTransformation::FACE: - if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + if (fes->FEColl()->GetContType() == + FiniteElementCollection::CONTINUOUS) { fe = fes->GetFaceElement(T.ElementNo); fes->GetFaceDofs(T.ElementNo, dofs); @@ -724,7 +726,8 @@ double GridFunction::GetValue(ElementTransformation &T, break; case ElementTransformation::BDR_ELEMENT: { - if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + if (fes->FEColl()->GetContType() == + FiniteElementCollection::CONTINUOUS) { // This is a continuous field so we can evaluate it on the boudnary fe = fes->GetBE(T.ElementNo); @@ -828,7 +831,8 @@ void GridFunction::GetVectorValue(ElementTransformation &T, fe = fes->GetFE(T.ElementNo); break; case ElementTransformation::EDGE: - if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + if (fes->FEColl()->GetContType() == + FiniteElementCollection::CONTINUOUS) { fe = fes->GetEdgeElement(T.ElementNo); fes->GetEdgeVDofs(T.ElementNo, vdofs); @@ -842,7 +846,8 @@ void GridFunction::GetVectorValue(ElementTransformation &T, } break; case ElementTransformation::FACE: - if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + if (fes->FEColl()->GetContType() == + FiniteElementCollection::CONTINUOUS) { fe = fes->GetFaceElement(T.ElementNo); fes->GetFaceVDofs(T.ElementNo, vdofs); @@ -857,7 +862,8 @@ void GridFunction::GetVectorValue(ElementTransformation &T, break; case ElementTransformation::BDR_ELEMENT: { - if (fes->FEColl()->GetContType() == FiniteElement::CONTINUOUS) + if (fes->FEColl()->GetContType() == + FiniteElementCollection::CONTINUOUS) { // This is a continuous field so we can evaluate it on the boudnary fes->GetBdrElementVDofs(T.ElementNo, vdofs); From 808ce8a771c8f8044ed70ebfc3fa9d2d69fabead Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Fri, 8 May 2020 14:16:38 -0700 Subject: [PATCH 294/535] LBFGS solver --- fem/tmop_tools.cpp | 234 +++++++++++---------------- fem/tmop_tools.hpp | 14 -- miniapps/meshing/mesh-optimizer.cpp | 67 ++++---- miniapps/meshing/mesh-optimizer.hpp | 154 ++++++++++++++++++ miniapps/meshing/pmesh-optimizer.cpp | 72 +++++---- 5 files changed, 326 insertions(+), 215 deletions(-) diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 03fb596176..e29a3e95cc 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -353,15 +353,53 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, energy_in = nlf->GetEnergy(x); } - const bool have_b = (b.Size() == Height()); - const int NE = fes->GetMesh()->GetNE(), dim = fes->GetFE(0)->GetDim(), dof = fes->GetFE(0)->GetDof(), nsp = ir.GetNPoints(); Array xdofs(dof * dim); DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim); Vector posV(pos.Data(), dof * dim); + Vector x_out_loc(fes->GetVSize()); - Vector x_out(x.Size()), x_out_loc(fes->GetVSize()); + if (serial) + { + const SparseMatrix *cP = fes->GetConformingProlongation(); + if (!cP) { x_out_loc = x; } + else { cP->Mult(x, x_out_loc); } + } +#ifdef MFEM_USE_MPI + else + { + fes->GetProlongationMatrix()->Mult(x, x_out_loc); + } +#endif + + double min_detJ = infinity(); + for (int i = 0; i < NE; i++) + { + fes->GetElementVDofs(i, xdofs); + x_out_loc.GetSubVector(xdofs, posV); + + for (int j = 0; j < nsp; j++) + { + fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape); + MultAtB(pos, dshape, Jpr); + min_detJ = std::min(min_detJ, Jpr.Det()); + } + } + double min_detJ_all = min_detJ; +#ifdef MFEM_USE_MPI + if (parallel) + { + MPI_Allreduce(&min_detJ, &min_detJ_all, 1, MPI_DOUBLE, MPI_MIN, + p_nlf->ParFESpace()->GetComm()); + } +#endif + bool untangling = false; + if (min_detJ_all <= 0) { untangling = true; } + + const bool have_b = (b.Size() == Height()); + + Vector x_out(x.Size()); bool x_out_ok = false; double scale = 1.0, energy_out = 0.0; double norm0 = Norm(r); @@ -384,35 +422,38 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, } #endif - int jac_ok = 1; - for (int i = 0; i < NE; i++) + if (!untangling) { - fes->GetElementVDofs(i, xdofs); - x_out_loc.GetSubVector(xdofs, posV); - for (int j = 0; j < nsp; j++) + int jac_ok = 1; + for (int i = 0; i < NE; i++) { - fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape); - MultAtB(pos, dshape, Jpr); - if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; } + fes->GetElementVDofs(i, xdofs); + x_out_loc.GetSubVector(xdofs, posV); + for (int j = 0; j < nsp; j++) + { + fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape); + MultAtB(pos, dshape, Jpr); + if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; } + } } - } - break2: - int jac_ok_all = jac_ok; + break2: + int jac_ok_all = jac_ok; #ifdef MFEM_USE_MPI - if (parallel) - { - MPI_Allreduce(&jac_ok, &jac_ok_all, 1, MPI_INT, MPI_LAND, - p_nlf->ParFESpace()->GetComm()); - } + if (parallel) + { + MPI_Allreduce(&jac_ok, &jac_ok_all, 1, MPI_INT, MPI_LAND, + p_nlf->ParFESpace()->GetComm()); + } #endif - if (jac_ok_all == 0) - { - if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; } - scale *= 0.5; continue; - } + if (jac_ok_all == 0) + { + if (print_level >= 0) + { mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; } + scale *= 0.5; continue; + } + } // endif(!untangling) ProcessNewState(x_out); if (serial) @@ -425,25 +466,37 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, energy_out = p_nlf->GetParGridFunctionEnergy(x_out_loc); } #endif - if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0) - { - if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Increasing energy.\n"; } - scale *= 0.5; continue; - } - oper->Mult(x_out, r); - if (have_b) { r -= b; } - double norm = Norm(r); - - if (norm > 1.2*norm0) + if (untangling) { - if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Norm increased.\n"; } - scale *= 0.5; continue; + if (energy_out > energy_in || std::isnan(energy_out) != 0) + { + scale *= 0.5; + } + else { x_out_ok = true; break; } } - else { x_out_ok = true; break; } - } + else + { + if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0) + { + if (print_level >= 0) + { mfem::out << "Scale = " << scale << " Increasing energy.\n"; } + scale *= 0.5; continue; + } + + oper->Mult(x_out, r); + if (have_b) { r -= b; } + double norm = Norm(r); + + if (norm > 1.2*norm0) + { + if (print_level >= 0) + { mfem::out << "Scale = " << scale << " Norm increased.\n"; } + scale *= 0.5; continue; + } + else { x_out_ok = true; break; } + } // endif (untangling) + } // enddo (i) if (print_level >= 0) { @@ -568,105 +621,6 @@ void TMOPNewtonSolver::UpdateDiscreteTC(const TMOP_Integrator &ti, } } -double TMOPDescentNewtonSolver::ComputeScalingFactor(const Vector &x, - const Vector &b) const -{ - const FiniteElementSpace *fes = NULL; - double energy_in = 0.0; -#ifdef MFEM_USE_MPI - const ParNonlinearForm *p_nlf = dynamic_cast(oper); - MFEM_VERIFY(!(parallel && p_nlf == NULL), "Invalid Operator subclass."); - if (parallel) - { - fes = p_nlf->FESpace(); - energy_in = p_nlf->GetEnergy(x); - } -#endif - const bool serial = !parallel; - const NonlinearForm *nlf = dynamic_cast(oper); - MFEM_VERIFY(!(serial && nlf == NULL), "Invalid Operator subclass."); - if (serial) - { - fes = nlf->FESpace(); - energy_in = nlf->GetEnergy(x); - } - - const int NE = fes->GetMesh()->GetNE(), dim = fes->GetFE(0)->GetDim(), - dof = fes->GetFE(0)->GetDof(), nsp = ir.GetNPoints(); - Array xdofs(dof * dim); - DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim); - Vector posV(pos.Data(), dof * dim); - Vector x_loc(fes->GetVSize()); - - double min_detJ = infinity(); - for (int i = 0; i < NE; i++) - { - fes->GetElementVDofs(i, xdofs); - // TODO x_loc doesn't have valid values here! - MFEM_ABORT("This function has to be fixed!"); - x_loc.GetSubVector(xdofs, posV); - - for (int j = 0; j < nsp; j++) - { - fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape); - MultAtB(pos, dshape, Jpr); - min_detJ = std::min(min_detJ, Jpr.Det()); - } - } - double min_detJ_all = min_detJ; -#ifdef MFEM_USE_MPI - if (parallel) - { - MPI_Allreduce(&min_detJ, &min_detJ_all, 1, MPI_DOUBLE, MPI_MIN, - p_nlf->ParFESpace()->GetComm()); - } -#endif - if (print_level >= 0) - { - mfem::out << "Minimum det(J) = " << min_detJ_all << '\n'; - } - - Vector x_out(x.Size()); - bool x_out_ok = false; - double scale = 1.0, energy_out = 0.0; - - for (int i = 0; i < 7; i++) - { - add(x, -scale, c, x_out); - if (serial) - { - const SparseMatrix *cP = fes->GetConformingProlongation(); - if (!cP) { x_loc = x_out; } - else { cP->Mult(x_out,x_loc); } - energy_out = nlf->GetGridFunctionEnergy(x_loc); - } -#ifdef MFEM_USE_MPI - else - { - fes->GetProlongationMatrix()->Mult(x_out, x_loc); - energy_out = p_nlf->GetParGridFunctionEnergy(x_loc); - } -#endif - - if (energy_out > energy_in || std::isnan(energy_out) != 0) - { - scale *= 0.5; - } - else { x_out_ok = true; break; } - } - - if (print_level >= 0) - { - mfem::out << "Energy decrease: " - << (energy_in - energy_out) / energy_in * 100.0 - << "% with " << scale << " scaling.\n"; - } - - if (x_out_ok == false) { return 0.0; } - - return scale; -} - #ifdef MFEM_USE_MPI // Metric values are visualized by creating an L2 finite element functions and // computing the metric values at the nodes. diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index e77e23c7e9..f4f5aff497 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -132,20 +132,6 @@ public: virtual void ProcessNewState(const Vector &x) const; }; -/// Allows negative Jacobians. Used for untangling. -class TMOPDescentNewtonSolver : public TMOPNewtonSolver -{ -public: -#ifdef MFEM_USE_MPI - TMOPDescentNewtonSolver(MPI_Comm comm, const IntegrationRule &irule) - : TMOPNewtonSolver(comm, irule) { } -#endif - TMOPDescentNewtonSolver(const IntegrationRule &irule) - : TMOPNewtonSolver(irule) { } - - virtual double ComputeScalingFactor(const Vector &x, const Vector &b) const; -}; - void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, Mesh &pmesh, char *title, int position); diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 89d6c8bac4..d17910f4b5 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -94,8 +94,9 @@ int main(int argc, char *argv[]) double lim_const = 0.0; int quad_type = 1; int quad_order = 8; - int newton_iter = 10; - double newton_rtol = 1e-10; + int solver_type = 0; + int solver_iter = 10; + double solver_rtol = 1e-10; int lin_solver = 2; int max_lin_iter = 100; bool move_bnd = true; @@ -153,9 +154,11 @@ int main(int argc, char *argv[]) "3: Closed uniform points"); args.AddOption(&quad_order, "-qo", "--quad_order", "Order of the quadrature rule."); - args.AddOption(&newton_iter, "-ni", "--newton-iters", + args.AddOption(&solver_type, "-st", "--solver-type", + " Type of solver: (default) 0: Newton, 1: LBFGS"); + args.AddOption(&solver_iter, "-ni", "--newton-iters", "Maximum number of Newton iterations."); - args.AddOption(&newton_rtol, "-rtol", "--newton-rel-tolerance", + args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance", "Relative tolerance for the Newton solver."); args.AddOption(&lin_solver, "-ls", "--lin-solver", "Linear solver: 0 - l1-Jacobi, 1 - CG, 2 - MINRES."); @@ -699,44 +702,47 @@ int main(int argc, char *argv[]) } } cout << "Minimum det(J) of the original mesh is " << tauval << endl; + tauval -= 0.01 * h0.Min(); // Slightly below minJ0 to avoid div by 0. // 19. Finally, perform the nonlinear optimization. - NewtonSolver *newton = NULL; - if (tauval > 0.0) + NewtonSolver *solver = NULL; + if (solver_type == 0) { - tauval = 0.0; TMOPNewtonSolver *tns = new TMOPNewtonSolver(*ir); - newton = tns; - cout << "TMOPNewtonSolver is used (as all det(J) > 0).\n"; + solver = tns; + solver->SetPreconditioner(*S); + solver->SetMaxIter(solver_iter); + solver->SetRelTol(solver_rtol); + solver->SetAbsTol(0.0); + solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); + solver->SetOperator(a); + solver->Mult(b, x.GetTrueVector()); + if (solver->GetConverged() == false) + { + cout << "NewtonIteration: rtol = " << solver_rtol << " not achieved." + << endl; + } } else { - if ( (dim == 2 && metric_id != 22 && metric_id != 252) || - (dim == 3 && metric_id != 352) ) + TMOPLBFGSOptimizer *tns = new TMOPLBFGSOptimizer(*ir); + tns->SetKDim(40); + solver = tns; + cout << "TMOPLBFGSOptimizer is used (as all det(J) > 0).\n"; + solver->SetMaxIter(solver_iter); + solver->SetRelTol(solver_rtol); + solver->SetAbsTol(0.0); + solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); + solver->SetOperator(a); + solver->Mult(b, x.GetTrueVector()); + if (solver->GetConverged() == false) { - cout << "The mesh is inverted. Use an untangling metric." << endl; - return 3; + cout << "LBFGSIteration: rtol = " << solver_rtol << " not achieved." + << endl; } - tauval -= 0.01 * h0.Min(); // Slightly below minJ0 to avoid div by 0. - newton = new TMOPDescentNewtonSolver(*ir); - cout << "The TMOPDescentNewtonSolver is used (as some det(J) < 0).\n"; } - newton->SetPreconditioner(*S); - newton->SetMaxIter(newton_iter); - newton->SetRelTol(newton_rtol); - newton->SetAbsTol(0.0); - newton->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); - newton->SetOperator(a); - newton->Mult(b, x.GetTrueVector()); x.SetFromTrueVector(); - if (newton->GetConverged() == false) - { - cout << "NewtonIteration: rtol = " << newton_rtol << " not achieved." - << endl; - } - delete newton; - // 20. Save the optimized mesh to a file. This output can be viewed later // using GLVis: "glvis -m optimized.mesh". { @@ -786,6 +792,7 @@ int main(int argc, char *argv[]) } // 24. Free the used memory. + delete solver; delete S; delete target_c2; delete metric2; diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index b907897d4f..44b7c170fa 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -226,3 +226,157 @@ void DiffuseField(ParGridFunction &field, int smooth_steps) delete Lap; } #endif + + +class TMOPLBFGSOptimizer : public TMOPNewtonSolver +{ +protected: + int m = 10; + +public: +#ifdef MFEM_USE_MPI + TMOPLBFGSOptimizer(MPI_Comm comm, const IntegrationRule &irule) + : TMOPNewtonSolver(comm, irule) { } +#endif + TMOPLBFGSOptimizer(const IntegrationRule &irule) + : TMOPNewtonSolver(irule) { } + + virtual void SetKDim(int dim) { m = dim; } + + virtual void Mult(const Vector &b, Vector &x) const; +}; + +void TMOPLBFGSOptimizer::Mult(const Vector &b, Vector &x) const +{ + MFEM_ASSERT(oper != NULL, "the Operator is not set (use SetOperator)."); + MFEM_ASSERT(prec != NULL, "the Solver is not set (use SetSolver)."); + + // Quadrature points that are checked for negative Jacobians etc. + Vector sk, rk, yk, skt, ykt, rho, alpha; + DenseMatrix skM(width, m), ykM(width, m); + + //r - r_{k+1}, c - descent direction + sk.SetSize(width); //x_{k+1}-x_k + rk.SetSize(width); //nabla(f(x_{k})) + yk.SetSize(width); //r_{k+1}-r_{k} + skt.SetSize(width); //work vector + ykt.SetSize(width); //work vector + rho.SetSize(m); //1/(dot(yk,sk) + alpha.SetSize(m); //rhok*sk'*c + + int it; + double norm0, norm, norm_goal; + const bool have_b = (b.Size() == Height()); + + const bool serial = !parallel; + const NonlinearForm *nlf = dynamic_cast(oper); + MFEM_VERIFY(!(serial && nlf == NULL), "Invalid Operator subclass."); + + if (!iterative_mode) + { + x = 0.0; + } + + oper->Mult(x, r); // r = b-Ax + if (have_b) + { + r -= b; + } + + c = r; // initial descent direction + + norm0 = norm = Norm(r); + norm_goal = std::max(rel_tol*norm, abs_tol); + for (it = 0; true; it++) + { + MFEM_ASSERT(IsFinite(norm), "norm = " << norm); + if (print_level >= 0) + { + mfem::out << "LBFGS iteration " << it + << " : ||r|| = " << norm; + if (it > 0) + { + mfem::out << ", ||r||/||r_0|| = " << norm/norm0; + } + mfem::out << '\n'; + } + + if (norm <= norm_goal) + { + converged = 1; + break; + } + + if (it >= max_iter) + { + converged = 0; + break; + } + + rk = r; + const double c_scale = ComputeScalingFactor(x, b); + if (c_scale == 0.0) + { + converged = 0; + break; + } + add(x, -c_scale, c, x); //x_{k+1} = x_k - c_scale*c + + ProcessNewState(x); + + oper->Mult(x, r); + if (have_b) + { + r -= b; + } + + // LBFGS - construct descent direction + int klim; + subtract(r, rk, yk); // yk = r_{k+1} - r_{k} + sk = c; sk *= -c_scale; //sk = x_{k+1} - x_{k} = -c_scale*c + double gamma = Dot(sk, yk)/Dot(yk, yk); + + // Save last m vectors + if ( it < m) + { + skM.SetCol(it, sk); + ykM.SetCol(it, yk); + klim = it+1; + } + else + { + for (int i = 0; i < m-1; i++) + { + skM.SetCol(i, skM.GetColumn(i+1)); //shift columns + ykM.SetCol(i, ykM.GetColumn(i+1)); //shift columns + } + skM.SetCol(m-1, sk); // copy new column + ykM.SetCol(m-1, yk); // copy new colum + klim = m; + } + + c = r; + for (int i = klim-1; i > -1; i--) + { + skM.GetColumn(i, skt); + ykM.GetColumn(i, ykt); + rho(i) = 1./Dot(skt, ykt); + alpha(i) = rho(i)*Dot(skt,c); + add(c, -alpha(i), ykt, c); + } + + c *= gamma; // scale search direction + for (int i = 0; i < klim ; i++) + { + skM.GetColumn(i,skt); + ykM.GetColumn(i,ykt); + double betai = rho(i)*Dot(ykt, c); + add(c, alpha(i)-betai, skt, c); + } + + norm = Norm(r); + } + + final_iter = it; + final_norm = norm; +} diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index d64932238c..128b548be0 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -100,8 +100,9 @@ int main (int argc, char *argv[]) double lim_const = 0.0; int quad_type = 1; int quad_order = 8; - int newton_iter = 10; - double newton_rtol = 1e-10; + int solver_type = 0; + int solver_iter = 10; + double solver_rtol = 1e-10; int lin_solver = 2; int max_lin_iter = 100; bool move_bnd = true; @@ -160,9 +161,11 @@ int main (int argc, char *argv[]) "3: Closed uniform points"); args.AddOption(&quad_order, "-qo", "--quad_order", "Order of the quadrature rule."); - args.AddOption(&newton_iter, "-ni", "--newton-iters", + args.AddOption(&solver_type, "-st", "--solver-type", + " Type of solver: (default) 0: Newton, 1: LBFGS"); + args.AddOption(&solver_iter, "-ni", "--newton-iters", "Maximum number of Newton iterations."); - args.AddOption(&newton_rtol, "-rtol", "--newton-rel-tolerance", + args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance", "Relative tolerance for the Newton solver."); args.AddOption(&lin_solver, "-ls", "--lin-solver", "Linear solver: 0 - l1-Jacobi, 1 - CG, 2 - MINRES."); @@ -744,47 +747,53 @@ int main (int argc, char *argv[]) tauval = minJ0; if (myid == 0) { cout << "Minimum det(J) of the original mesh is " << tauval << endl; } + double h0min = h0.Min(), h0min_all; + MPI_Allreduce(&h0min, &h0min_all, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); + tauval -= 0.01 * h0min_all; // Slightly below minJ0 to avoid div by 0. // 20. Finally, perform the nonlinear optimization. - NewtonSolver *newton = NULL; - if (tauval > 0.0) + NewtonSolver *solver = NULL; + if (solver_type == 0) { - tauval = 0.0; TMOPNewtonSolver *tns = new TMOPNewtonSolver(pfespace->GetComm(), *ir); - newton = tns; - if (myid == 0) - { cout << "TMOPNewtonSolver is used (as all det(J) > 0)." << endl; } + solver = tns; + solver->SetPreconditioner(*S); + solver->SetMaxIter(solver_iter); + solver->SetRelTol(solver_rtol); + solver->SetAbsTol(0.0); + solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); + solver->SetOperator(a); + solver->Mult(b, x.GetTrueVector()); + if (solver->GetConverged() == false) + { + cout << "NewtonIteration: rtol = " << solver_rtol << " not achieved." + << endl; + } } else { - if ( (dim == 2 && metric_id != 22 && metric_id != 252) || - (dim == 3 && metric_id != 352) ) + TMOPLBFGSOptimizer *tns = new TMOPLBFGSOptimizer(pfespace->GetComm(), *ir); + tns->SetKDim(40); + solver = tns; + cout << "TMOPLBFGSOptimizer is used (as all det(J) > 0).\n"; + solver->SetMaxIter(solver_iter); + solver->SetRelTol(solver_rtol); + solver->SetAbsTol(0.0); + solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); + solver->SetOperator(a); + solver->Mult(b, x.GetTrueVector()); + if (solver->GetConverged() == false) { - if (myid == 0) - { cout << "The mesh is inverted. Use an untangling metric.\n"; } - return 3; + cout << "LBFGSIteration: rtol = " << solver_rtol << " not achieved." + << endl; } - double h0min = h0.Min(), h0min_all; - MPI_Allreduce(&h0min, &h0min_all, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); - tauval -= 0.01 * h0min_all; // Slightly below minJ0 to avoid div by 0. - newton = new TMOPDescentNewtonSolver(pfespace->GetComm(), *ir); - if (myid == 0) - { cout << "TMOPDescentNewtonSolver is used (as some det(J) < 0).\n"; } } - newton->SetPreconditioner(*S); - newton->SetMaxIter(newton_iter); - newton->SetRelTol(newton_rtol); - newton->SetAbsTol(0.0); - newton->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); - newton->SetOperator(a); - newton->Mult(b, x.GetTrueVector()); x.SetFromTrueVector(); - if (myid == 0 && newton->GetConverged() == false) + if (myid == 0 && solver->GetConverged() == false) { - cout << "NewtonIteration: rtol = " << newton_rtol << " not achieved." + cout << "NewtonIteration: rtol = " << solver_rtol << " not achieved." << endl; } - delete newton; // 21. Save the optimized mesh to a file. This output can be viewed later // using GLVis: "glvis -m optimized -np num_mpi_tasks". @@ -846,6 +855,7 @@ int main (int argc, char *argv[]) } // 24. Free the used memory. + delete solver; delete S; delete target_c2; delete metric2; From fb73228fdb1bbcc9e1080dcaf48d5f3bea7621e0 Mon Sep 17 00:00:00 2001 From: Andreas Schafelner <35033720+aschaf@users.noreply.github.com> Date: Mon, 11 May 2020 10:48:41 +0200 Subject: [PATCH 295/535] Added a brief description. --- linalg/hypre.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp index bf0ff73266..8c272f1053 100644 --- a/linalg/hypre.hpp +++ b/linalg/hypre.hpp @@ -654,6 +654,8 @@ public: /// Set SOR-related parameters void SetSOROptions(double relax_weight, double omega); /// Set parameters for polynomial smoothing + /** By default, 10 iterations of CG are used to estimate the eigenvalues. + Setting eig_est_cg_iter = 0 uses hypre's hypre_ParCSRMaxEigEstimate() instead. */ void SetPolyOptions(int poly_order, double poly_fraction, int eig_est_cg_iter = 10); /// Set parameters for Taubin's lambda-mu method void SetTaubinOptions(double lambda, double mu, int iter); From 2245027aec34fd270f93d56365b88010d05716f7 Mon Sep 17 00:00:00 2001 From: Andreas Schafelner <35033720+aschaf@users.noreply.github.com> Date: Mon, 11 May 2020 14:36:06 +0200 Subject: [PATCH 296/535] make style --- linalg/hypre.cpp | 7 ++++--- linalg/hypre.hpp | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index f53ccf6118..449feeac6a 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1931,7 +1931,8 @@ void HypreSmoother::SetSOROptions(double _relax_weight, double _omega) omega = _omega; } -void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction, int _eig_est_cg_iter) +void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction, + int _eig_est_cg_iter) { poly_order = _poly_order; poly_fraction = _poly_fraction; @@ -2022,7 +2023,7 @@ void HypreSmoother::SetOperator(const Operator &op) if (eig_est_cg_iter > 0) { hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter, - &max_eig_est, &min_eig_est); + &max_eig_est, &min_eig_est); } else { @@ -2037,7 +2038,7 @@ void HypreSmoother::SetOperator(const Operator &op) if (eig_est_cg_iter > 0) { hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter, - &max_eig_est, &min_eig_est); + &max_eig_est, &min_eig_est); } else { diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp index 8c272f1053..fa748bd4e0 100644 --- a/linalg/hypre.hpp +++ b/linalg/hypre.hpp @@ -615,7 +615,7 @@ protected: double *l1_norms; /// If set, take absolute values of the computed l1_norms bool pos_l1_norms; - /// Number of CG iterations to determine eigenvalue estimates + /// Number of CG iterations to determine eigenvalue estimates int eig_est_cg_iter; /// Maximal eigenvalue estimate for polynomial smoothing double max_eig_est; @@ -654,9 +654,10 @@ public: /// Set SOR-related parameters void SetSOROptions(double relax_weight, double omega); /// Set parameters for polynomial smoothing - /** By default, 10 iterations of CG are used to estimate the eigenvalues. + /** By default, 10 iterations of CG are used to estimate the eigenvalues. Setting eig_est_cg_iter = 0 uses hypre's hypre_ParCSRMaxEigEstimate() instead. */ - void SetPolyOptions(int poly_order, double poly_fraction, int eig_est_cg_iter = 10); + void SetPolyOptions(int poly_order, double poly_fraction, + int eig_est_cg_iter = 10); /// Set parameters for Taubin's lambda-mu method void SetTaubinOptions(double lambda, double mu, int iter); From e340b7b8007052851a625e3548b3b0b49c2feae6 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Mon, 11 May 2020 19:19:19 -0700 Subject: [PATCH 297/535] minor --- fem/eltrans.hpp | 17 ++++--- fem/fe_coll.hpp | 4 +- fem/gridfunc.hpp | 117 +++++++++++++++++++++-------------------------- fem/lininteg.cpp | 5 +- 4 files changed, 65 insertions(+), 78 deletions(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index be9b42c91d..88ce985527 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -50,9 +50,8 @@ protected: public: /** This enumeration declares the values stored in - ElementTransformation::ElementType and indicates which group of - objects the index stored in ElementTransformation::ElementNo - refers: + ElementTransformation::ElementType and indicates which group of objects + the index stored in ElementTransformation::ElementNo refers: | ElementType | Range of ElementNo +-------------+------------------------- @@ -398,17 +397,17 @@ public: /** @brief Method to set the geometry type of the face. @note This method is designed to be used when - [Par]Mesh::GetFaceTransformation will not be called i.e. when - the face transformation will not be needed but the neighboring - element transformations will be. Using this method to override - the GeometryType should only be done with great care. + [Par]Mesh::GetFaceTransformation will not be called i.e. when the face + transformation will not be needed but the neighboring element + transformations will be. Using this method to override the GeometryType + should only be done with great care. */ void SetGeometryType(Geometry::Type g) { geom = g; } /// Set the mask indicating which portions of the object have been setup /** The argument @a m is a bitmask used in - Mesh::GetFaceElementTransformations to indicate which portions - of the FaceElement Transformations object have been configured. + Mesh::GetFaceElementTransformations to indicate which portions of the + FaceElement Transformations object have been configured. mask & 1: Elem1 is configured mask & 2: Elem2 is configured diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index 89783d7ba9..f21d5667ed 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -40,8 +40,8 @@ protected: const int face_info); public: - /** @brief Enumeration for ContType: defines the continuity of the - field across element interfaces. + /** @brief Enumeration for ContType: defines the continuity of the field + across element interfaces. */ enum { CONTINUOUS, ///< Field is continuous across element interfaces TANGENTIAL, ///< Tangential components of vector field diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index a9e9d8fdc6..dffc9c0870 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -146,17 +146,15 @@ public: /** @name Element index Get Value Methods - These methods take an element index and return the interpolated - value of the field at a given reference point within the - element. + These methods take an element index and return the interpolated value of + the field at a given reference point within the element. - @warning These methods retrieve and use the - ElementTransformation object from the mfem::Mesh. This can - alter the state of the ElementTransformation object. This can - lead to unexpected results when the ElementTransformation - object is already in use such as when these methods are called - from within an integration loop. Consider using - GetValue(ElementTransformation &T, ...) instead. + @warning These methods retrieve and use the ElementTransformation object + from the mfem::Mesh. This can alter the state of the element + transformation object and can also lead to unexpected results when the + ElementTransformation object is already in use such as when these methods + are called from within an integration loop. Consider using + GetValue(ElementTransformation &T, ...) instead. */ ///@{ /** Return a scalar value from within the given element. */ @@ -169,28 +167,26 @@ public: /** @name Element Index Get Values Methods - These are convenience methods for repeatedly calling GetValue - for multiple points within a given element. The GetValues - methods are optimized and should perform better than repeatedly - calling GetValue. The GetVectorValues method simply calls - GetVectorValue repeatedly. + These are convenience methods for repeatedly calling GetValue for + multiple points within a given element. The GetValues methods are + optimized and should perform better than repeatedly calling GetValue. The + GetVectorValues method simply calls GetVectorValue repeatedly. - @warning These methods retrieve and use the - ElementTransformation object from the mfem::Mesh. This can - alter the state of the ElementTransformation object. This can - lead to unexpected results when the ElementTransformation - object is already in use such as when these methods are called - from within an integration loop. Consider using + @warning These methods retrieve and use the ElementTransformation object + from the mfem::Mesh. This can alter the state of the element + transformation object and can alsp lead to unexpected results when the + ElementTransformation object is already in use such as when these methods + are called from within an integration loop. Consider using GetValues(ElementTransformation &T, ...) instead. */ ///@{ - /** Compute a collection of scalar values from within the element - indicated by the index i. */ + /** Compute a collection of scalar values from within the element indicated + by the index i. */ void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim = 1) const; - /** Compute a collection of vector values from within the element - indicated by the index i. */ + /** Compute a collection of vector values from within the element indicated + by the index i. */ void GetValues(int i, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim = 1) const; @@ -201,15 +197,13 @@ public: /** @name ElementTransformation Get Value Methods These member functions are designed for use within - GridFunctionCoefficient objects. These can be used with + GridFunctionCoefficient objects. These can be used with ElementTransformation objects coming from either - Mesh::GetElementTransformation() or - Mesh::GetBdrElementTransformation(). + Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation(). - @note These methods do not reset the ElementTransformation - object so they should be safe to use within integration loops - or other contexts where the ElementTransformation is already in - use. + @note These methods do not reset the ElementTransformation object so they + should be safe to use within integration loops or other contexts where + the ElementTransformation is already in use. */ ///@{ /** Return a scalar value from within the element indicated by the @@ -227,52 +221,47 @@ public: /** @name ElementTransformation Get Values Methods - These are convenience methods for repeatedly calling GetValue - for multiple points within a given element. They work by - calling either the ElementTransformation or - FaceElementTransformations versions described above. - Consequently, these methods should not be expected to run - faster than calling the above methods in an external loop. + These are convenience methods for repeatedly calling GetValue for + multiple points within a given element. They work by calling either the + ElementTransformation or FaceElementTransformations versions described + above. Consequently, these methods should not be expected to run faster + than calling the above methods in an external loop. - @note These methods do not reset the ElementTransformation - object so they should be safe to use within integration loops - or other contexts where the ElementTransformation is already in - use. + @note These methods do not reset the ElementTransformation object so they + should be safe to use within integration loops or other contexts where + the ElementTransformation is already in use. - @note These methods can also be used wtih - FaceElementTransformations objects. + @note These methods can also be used with FaceElementTransformations + objects. */ ///@{ - /** Compute a collection of scalar values from within the element - indicated by the ElementTransformation object. */ + /** Compute a collection of scalar values from within the element indicated + by the ElementTransformation object. */ void GetValues(ElementTransformation &T, const IntegrationRule &ir, Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const; - /** Compute a collection of vector values from within the element - indicated by the ElementTransformation object. */ + /** Compute a collection of vector values from within the element indicated + by the ElementTransformation object. */ void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix *tr = NULL) const; ///@} /** @name Face Index Get Values Methods - These methods are designed to work with Discontinuous Galerkin - basis functions. They compute field values on the interface - between elements, or on boundary elements, by interpolating the - field in a neighboring element. The \a side argument indices - which neighboring element should be used: 0, 1, or 2 - (automatically chosen). See the FaceElementTransformations - documentation in eltrans.hpp for more information on the \a - side parameter. + These methods are designed to work with Discontinuous Galerkin basis + functions. They compute field values on the interface between elements, + or on boundary elements, by interpolating the field in a neighboring + element. The \a side argument indices which neighboring element should be + used: 0, 1, or 2 (automatically chosen). See the + FaceElementTransformations documentation in eltrans.hpp for more + information on the \a side parameter. - @warning These methods retrieve and use the - FaceElementTransformations object from the mfem::Mesh. This - can alter the state of the FaceElementTransformations object. - This can lead to unexpected results when the - FaceElementTransformations object is already in use such as - when these methods are called from within an integration loop. - Consider using GetValues(ElementTransformation &T, ...) - instead. + @warning These methods retrieve and use the FaceElementTransformations + object from the mfem::Mesh. This can alter the state of the face element + transformations object and can also lead to unexpected results when the + FaceElementTransformations object is already in use such as when these + methods are called from within an integration loop. Consider using + GetValues(ElementTransformation &T, ...) instead. */ ///@{ /** Compute a collection of scalar values from within the face diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 53a84808d4..0ffc60978f 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -528,9 +528,8 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( Tr.SetIntPoint(&ip); - // Use Tr.Elem1 transformation for u so that it matches the - // coefficient used with the ConvectionIntegrator and/or the - // DGTraceIntegrator. + // Use Tr.Elem1 transformation for u so that it matches the coefficient + // used with the ConvectionIntegrator and/or the DGTraceIntegrator. u->Eval(vu, *Tr.Elem1, eip); if (dim == 1) From 239030b50afbe854f10319b13fe071475a7817d6 Mon Sep 17 00:00:00 2001 From: Tomov Date: Mon, 11 May 2020 19:46:54 -0700 Subject: [PATCH 298/535] make style --- fem/tmop.cpp | 26 +++++++++++++++----------- fem/tmop.hpp | 6 +++--- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index b676d2ab94..a3a08c13a2 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -845,7 +845,7 @@ void TargetConstructor::ComputeAvgVolume() const bool TargetConstructor::ContainsVolumeInfo() const { - switch(target_type) + switch (target_type) { case IDEAL_SHAPE_UNIT_SIZE: return false; case IDEAL_SHAPE_EQUAL_SIZE: @@ -853,8 +853,8 @@ bool TargetConstructor::ContainsVolumeInfo() const case GIVEN_SHAPE_AND_SIZE: case GIVEN_FULL: return true; default: MFEM_ABORT("TargetType not added to ContainsVolumeInfo."); - /* */ return false; } + return false; } void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe, @@ -1610,8 +1610,10 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el, } void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el, - const Vector &weights, IsoparametricTransformation &Tpr, - const IntegrationRule &ir, DenseMatrix &mat) + const Vector &weights, + IsoparametricTransformation &Tpr, + const IntegrationRule &ir, + DenseMatrix &mat) { if (zeta == NULL) { return; } @@ -1647,8 +1649,10 @@ void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el, } void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el, - const Vector &weights, IsoparametricTransformation &Tpr, - const IntegrationRule &ir, DenseMatrix &mat) + const Vector &weights, + IsoparametricTransformation &Tpr, + const IntegrationRule &ir, + DenseMatrix &mat) { if (zeta == NULL) { return; } @@ -1696,11 +1700,11 @@ void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el, for (int j = 0; j <= i; j++) { const int jdof = j % dof, jdim = j / dof; - const double entry = w * - ( 2.0 * zeta_grad_q(idim) * shape(idof) * - zeta_grad_q(jdim) * shape(jdof) + - 2.0 * (zeta_q(q) - zeta0_q(q)) * - zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof)); + const double entry = + w * ( 2.0 * zeta_grad_q(idim) * shape(idof) * + /* */ zeta_grad_q(jdim) * shape(jdof) + + 2.0 * (zeta_q(q) - zeta0_q(q)) * + zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof)); mat(i, j) += entry; if (i != j) { mat(j, i) += entry; } } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index 62b9412514..bc3879c2b2 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -911,7 +911,7 @@ protected: const IntegrationRule *EnergyIntegrationRule(const FiniteElement &el) const { return (IntRule) ? IntRule - /* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); + /* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); } const IntegrationRule *ActionIntegrationRule(const FiniteElement &el) const { @@ -979,11 +979,11 @@ public: @param[in] ae AdaptivityEvaluator to compute z(x) from z0(x0). */ void EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ae); - #ifdef MFEM_USE_MPI +#ifdef MFEM_USE_MPI /// Parallel support for adaptive limiting. void EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff, AdaptivityEvaluator &ae); - #endif +#endif /// Update the original/reference nodes used for limiting. void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; } From 1bf3e188fc7f5e7451d6a6b63b5c0eb386569b66 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 12 May 2020 12:51:33 +0200 Subject: [PATCH 299/535] Remove comment lines --- miniapps/nurbs/CMakeLists.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/miniapps/nurbs/CMakeLists.txt b/miniapps/nurbs/CMakeLists.txt index 06cfd66bd0..bc822d0121 100644 --- a/miniapps/nurbs/CMakeLists.txt +++ b/miniapps/nurbs/CMakeLists.txt @@ -9,18 +9,6 @@ # terms of the BSD-3 license. We welcome feedback and contributions, see file # CONTRIBUTING.md for details. -#configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/square-nurbs.mesh -# ${PROJECT_BINARY_DIR}/miniapps/nurbs/square-nurbs.mesh -# COPYONLY) - -#configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/cube-nurbs.mesh -# ${PROJECT_BINARY_DIR}/miniapps/nurbs/cube-nurbs.mesh -# COPYONLY) - -#configure_file(${PROJECT_SOURCE_DIR}/miniapps/nurbs/pipe-nurbs-2d.mesh -# ${PROJECT_BINARY_DIR}/miniapps/nurbs/pipe-nurbs-2d.mesh -# COPYONLY) - add_mfem_miniapp(nurbs_ex1 MAIN nurbs_ex1.cpp LIBRARIES mfem) From 0bd112160cff38f0a2372f1e46c73c511b7be74c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 12 May 2020 12:07:25 -0700 Subject: [PATCH 300/535] Removing reference to documentation that no longer exists --- fem/gridfunc.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index dffc9c0870..e81d697ea7 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -252,9 +252,7 @@ public: functions. They compute field values on the interface between elements, or on boundary elements, by interpolating the field in a neighboring element. The \a side argument indices which neighboring element should be - used: 0, 1, or 2 (automatically chosen). See the - FaceElementTransformations documentation in eltrans.hpp for more - information on the \a side parameter. + used: 0, 1, or 2 (automatically chosen). @warning These methods retrieve and use the FaceElementTransformations object from the mfem::Mesh. This can alter the state of the face element From 6b7c8bf33bf5b82ce7ecc5b271870c235c3b1bb1 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 12 May 2020 12:08:48 -0700 Subject: [PATCH 301/535] Changing to CeedGridCoef::coeff to `const` to conform to `GridFunctionCoefficient` class --- fem/libceed/ceed.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/libceed/ceed.hpp b/fem/libceed/ceed.hpp index 53b59bd727..9fd97a114a 100644 --- a/fem/libceed/ceed.hpp +++ b/fem/libceed/ceed.hpp @@ -40,7 +40,7 @@ struct CeedConstCoeff struct CeedGridCoeff { - GridFunction* coeff; + const GridFunction* coeff; CeedBasis basis; CeedElemRestriction restr; CeedVector coeffVector; From 66939bdf8c1f38892f307c3097675bfa778d7884 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 12 May 2020 13:52:59 -0700 Subject: [PATCH 302/535] Tweaks to comments --- mesh/mesh_readers.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index 5a2366ea5e..8115395800 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1291,7 +1291,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) MFEM_CONTRACT_VAR(elem_domain); } // section '$Elements' - else if (buff == "$Periodic") // reading master/slave node pairs + else if (buff == "$Periodic") // Reading master/slave node pairs { curved = 1; read_gf = 0; @@ -1309,8 +1309,9 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) getline(input, buff); // Read end-of-line for (int i = 0; i < num_per_ent; i++) { - getline(input, buff); // Read entity dimension and tags - getline(input, buff); // Read affine mapping + getline(input, buff); // Read and ignore entity dimension and tags + getline(input, buff); // Read and ignore affine mapping + // Read master/slave vertex pairs input >> num_nodes; for (int j=0; jSetCurvature(1, true, Dim, Ordering::byVDIM); - // renumber elements + // Renumber elements to remove slave vertices for (int i = 0; i < this->GetNE(); i++) { Element *el = this->GetElement(i); @@ -1334,7 +1335,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) v[j] = v2v[v[j]]; } } - // renumber boundary elements + // Renumber boundary elements to remove slave vertices for (int i = 0; i < this->GetNBE(); i++) { Element *el = this->GetBdrElement(i); From 328dc13ba40d0ccc40e9777ffd593c4cae0a34b9 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Tue, 12 May 2020 14:06:58 -0700 Subject: [PATCH 303/535] Added a small logo to the doxygen documentation. By resizing it I was able to make it look decent. --- doc/CodeDocumentation.conf.in | 2 +- doc/web/small-logo.png | Bin 0 -> 12334 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/web/small-logo.png diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in index 9b8709af15..4476775f2e 100644 --- a/doc/CodeDocumentation.conf.in +++ b/doc/CodeDocumentation.conf.in @@ -51,7 +51,7 @@ PROJECT_BRIEF = "Finite element discretization library" # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = web/small-logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is diff --git a/doc/web/small-logo.png b/doc/web/small-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..021cbcfe8a75888b8f86356f2a50b7394c51b667 GIT binary patch literal 12334 zcmV+}FwxJ6P)Px#32;bRa{vGmbN~PnbOGLGA9w%&FT+VhK~#8N?R*J% zRn@und(KI6GS83@NJ0o<9%M!aaX=9qL9uA9!?oI9TcaAjxTE|-3%2iQ8 z1Qab!%rgiHLzstz%sCm)e9r&AE7_Ppz@ZNPpXdMdWADB8-fMm9UEjF(KCy*K`2X~+ z(|v~f^1*Sc0Lx5WYtWc%6Iu^ovD7lBb0=`_Q$T8%`)D-ld zIu$>8>926|_=lkH6*C3 z-HJr+i~mJX`f~IX?h6Q`kgZz*C6HY_XlCOMZgaU!U|Y1E2R!MuwPrWOnLov^dB*zrSW?p$?~03;pd-Y9nCwx6;uKD0l_(&fFyH2%yUt8J2lis zw_t;v`=(9Dyr!1doT4pn4DfsuK@CcBx(PD@w#%LH5~JY*$cM=SUD}(pcQ0NUITG`q zp2ef@hrV--E&6OJYEPeFCa8g8ZFa1tx(yM41kMakAVmVS#gE$HxI9%8e6C-!SUnGZYId$&axv#*b|F#CaNVPdkmf$9+ ze%gC5#1O`PcQ}MCM6Vau!@-sCu}?p*lS@#LlUopJxr)ddUz1e3{BZwA9>JBj`~ppZ z5aJROzZ0|lR)O8RW(|rLEkg7MA7I1UwdlsS-ekW4i{?oHGP&mzh&(uBkxy?Q=@**OUNXeQArjHyXpuPY#I1ogb#~z+54h9YI@$6iI(b8BI52a-JTWRk> zvX#CGc%!+)`(gTd7o#XH8JT0pqF~IJZ?)+7R)8%zbPyk2eGQU6`wYzlKqTKOU#E#g z60}AR(@4$iL9J|#h=4u9fzJu@z?c|xjgE$cKnAIy%bQ#n6_;pC-$UShbO!>|=hxQH z;~@Ox0NVuiwqVF;q`>uYCJKU|lNG!o$#MzGCgeVJohe4h4JnD3KJ5ZzHH8rw>%?v? z{;juR;J|@A`|s1g1#E-cjZYqZ6ssP32*Y`-i716y&Ph(EpY&5h9W;A-QtV;-@Tf=x zqN3o8a>D71Ml?Y^!gJ*`?UdM9><{=bA(=hMrU@MUegw!~vd8B`v&X}IAG`uuOwerv zwvZgl{spQuR%w{P)UnBb$;u7{vRLh^-ki)9em!j}(+ z-uq_sje*^E=nxh&eaU1kFB6jB1=_xe%rNM{tHoKD2X#vzgb zhvVX4C%9pPy13qjv(q}!9nduhRBB_GzS>4WLj=@AZsbA=U^iI+`>DYm`bh_`T}M_4 ztgJ&pO@JD|OSXLO4zgsdBWnS6lV{#~3(H_THkX&7S4s+E3Gxmu^r2~&;_M4A;1%DD zzLDR4`H9CdGbaZb1T~t+(o}UMGm9js>0B#;8cBgG33LXt_}G|e#1P1YghWIpFy&86 zgS~TSgu7&7r85%e_8W+ZuH6vM%tSaVi+NHf*vQ~y?MX?9Wsr&E{V{YKkz5={WE9;= zB!izFKDwB}H04T;uOdUTv^XScPU}|GgS?NdYE0*~5Rbk277!P2(!E&r$3f7C$M%OG z!XwvTk9scdH=(Z$?A#yy2sL-!g^RggMwVuX2b16DERqPSa!N({C>~dH3Y{Yf1T{1! zItF$E0|I3@Jsm{^zi&==f|!nQI^BT4OieX_BAK3=fI?LhwK}>L)F}Gs2(p7GY37nFU^n_IzZOye?+M#QhK=rt#KTEteb5ykr9X^AkLUrIB51Z z0%{Xz)XaTq&+3BIygZ;w7uduZ8L;tOJAef&*+FoP#&VG&34op8+NiNMrE4N?l!a{P z_Sgt-0W1qsIjo7B5}Gm%PD;Vnno88uy{snCqi9Js`t`J~T``FZcQdzNm%g%({p(M! z!|uPneDpzyf|LN2AKOJ9MV7Ei$}^k}bfNES4zjvRh(oh+0W^PUpTMHvbqVn}KusIe zr!P?;4ANxzSBWF@Yoe!YV8Y~Ln5kv$MePA|;~?AXxL@Dg47b;VCi-13vjnd%z+BgF zl+Ki~WR<_tHOZ)B`Bg1}e64^Vf6(Dg77t}Qu)l;~I#$eL(zHSD{YOHy*+ z0A_ORSJtdW3>WjO&{xvfwcjAesD zaCst-7zo2A@ThS{`)J}j2+W{<{acRd5{zbwH7U7(RxOp!1GUNm-!4rhJ2XMM5&8pR zU=ULoEC7{OSy_O{(j3JCWeXV>ShJ{X?FvD_Ynxi}&AS0EWkbJgvtyA?ncgFB)9ToPU#QP&!gXH*hi2ytjFPoMqEAh zZrD;sQ5gwpfSMve1&GqKR-lZJwcNhiXrf0+?J{>xKFEEsLPRKJGx8Wv*`HhhmjnLJ zo$&5o{(|*hHyZPMqIk|iL`QW&Qf3?)%e{z8j5RME4eXK$^o!8oRUsun#g zJl2(#pf{Bunfds2r=M=-{OAog@ZXcu34v8*v;LvqnP;UkB~4p^%7^NGll8=2n!1eK zjRyi>9ab=C^`YPR*Jf5h$<$H@9fX2ZfWc_s7!>4PfU~L-aB$OF0!KJFIb(8S6$fIa zIIV?(*$QCphvW-e0Ts~ZcH;;LZfie!WVr6`n^CxDH!^R$5pi1!(LFyON%_5y5-P>~ zHwrOmcphq9%_y&LL>~szVOd=vA z!^-96x)ad}fqnksi%nXkD8GR$VFj+VLBUEIp`20fVH$ZqPs$A_m#iQT3(9R6#ni#! zrDl$#BPra%0-nWYIUP%V1wLN21#k2lfozC-t47}0B)v!7ip;iNMS_pcgbZq+`AV(XG+yTx1&H|QmZpn{*B~dE@X=MdLP5N_dKI30@kQ9F0Gcmz z8AFSiEuDxu1h)Cp&#=!U!*98Ox?+MBJtL@B*hrQp%jZgarOk2;O3sxjWH30z2gw9G zgUXiWV&=GNCGhTS*jNTry|_AY2s@5nNi?8#huPc51%>Iv==y#MxM94y+3^Li#A z=y9U6&xV22*7BxijA02K$;@CWgH$4e)wJHdQO*7rY}$y&pM4HHSFAMoyK-N7eC8`g zxi%5(6H$l2zVgf4P1GkQppF?6SMI9L1g^AL6_;4>%g?G#7r@N0u$zF!($A)_gUVtm z>fhM|%@gsAwDHmeawC^0pb=UqniCr^cnAs}e*)`!=3@^dZ@8E@Gwl(;Ap&fQ0fAap zhElfG%$R|*13{d{nm(pAD=_4zROPMXr4Zo6F4%v#8H-+d4llmE2E7xLkwky_$&TGP zt9y5veIq_SdPXv1)6yJxX z8q=9Hx`PJ#29}P9=Y%7q1MNxG((oCV!}-7iSUPM7n%1l~{?{vwCCDzii_IfOpbzuw z^Iv<-$aoydFJ^E|=A)?K@)KC}WX|Hr#iOwk@Y&42;qMDp;|%)VV!9xg&yUml^g}gW z!JpoG6N}$@2f1}prxwMLb!sbVRou!A3TUOETMISgY(5%LBSov@vZPY1NIDifM`0OxBI?$y z8z$WM0QRh3haH_#QNL>&YO*uXv|%HDv~($QdninvfLb#M#IkhhP8F!4v@~->C!&5^ zZ_K$Z8=+4=#S_22A8u-ECu-?G7Qc_*&-yc*yZ4x9yHYMet2iPhQVFm5DS%6A>Wl$+ z^HWdr-{a{xV7D@G$!}_fr20yQ#X8o-(q5UqfEMsNCn1(1_B56}Gz%k#4rx7e5>jeZMm=*A8b4v^ zOvjc;7?f!^lkm>|OVKp7Wez28y^UEfzF-ziaYV0eWQlTnL&?g5Bqn<_!C4BWIHS2M zNblJ$eLkMr0ej@oA=J5CWsX0#Sfm}c{b)b${C-E*-QYWFB!zCE^!a|%^mV^CMuD~tcKFE0XBkV5T z-2&c;NI@}^OWjCm%6YAu(noRpSjy6qaMkDH54}!7Eu*dcWfiju>%ExlK=YCUslt?X zYR9vec)1WdD0jU5clhJBR zlVvhN+Rm;hYL<`P*HE8j@^uVvt}=wvDSDDbBrtmW*8w%vhVY9Iw<2we2P+~8hL`nS zS4z@cf{LhU6da7k#q-vnXuqWBh}dt4W2SOpd(h+8a3RYW%;a;KucG=0jwDXUmT@-Z z5^ohfQV`8U0BbAO{8VWvBM{3HZREVTnR$iP)b-=xG}CLz$Y7Fso# zhfG3Stx^_QgQY~#M0CqK)hjyDnFt^`qQTGMbO(rTJ<31)kiXg12&bz0Q#a z3mf4i_u!!$IhNWzk6rZ0Bl!GRzcN~scp{5Bh{B#_ypMH^9tZnZv!J!9#hVI?=B87HV zP7J!9!^^0wRpgYjsc^(N#EUaz_zT82g+WyW5)_R zD(`lnZk7!d@7fV}T?DFM;W)GH@Z4?3&i8F7dd-IH*%9bXvnsu88XEHRv26P`BxPr} z6dxK#EYhTW^qQSnRwprX$dUpPcs=zJlu~P(a%?DME?vgCWirV0;OSiMv)TAvF`JI! zA(9r0f>laF+fzGW<*XHa6!mneqPhM(W)!yn6j82CS4sy&9z~? zJiarI)X@#->6LO;y_{1?s!Ge6pnz?rN+c&>^}TnQ<1(f`Ne=ou2D3L=rtYCr{^fA*Qlb3R9YgJa)k;_yfr6B<&H+`5@QjLBIJ}i6U1`Jrg0-JaymY`Jg+&ZRV zqj;U(RIK1VJqfx#Ln`I|Fq_?&;ZE)kW;a{8O(j?(*AJw;mHA~;l*L`*guM2NTFC7g6Gx(AIN!}<57tZN9CKK97waV+;!$&%$gZoBi0zL`xDpuA5(<#qxr z|5p~_#L%93Soq7S*my&CbgQSsX`%@@=%VDBvgxjh*RqXqKPnZr4V3k8EW8!xq4>ZI zJkjYqJUKcM!8`5fb|(AgWvR3jfha(gEeK#83$sMM1v!S=0UMi^Zf;UWK#Mo&l>k=I zJ;LKmf_&eqIQVA9W96>P=z#8EB%x#NrjnIj$VS1Xsm&ZVBaai|ejV+&yc~~C8;aUD z9>x{ZE@E#jlulq2UNoj6FpF0#=jw0cSoPfMk&3|HX$#|D+~3RgI37>uek8YLJYK~8 z{~>Qffq;9)EjBcb!^u|++2dIr!`&=GXhGH$Z*t!J|Ktf zx&MXYrrR+8X@dI}JqAIQYZO?#!&tQ*ms-yb(uW*hw6p^@Y4BjA#KxE#2T>zb2#9o% zK4{C1iiA5h0=K#nQ2D`HT(gLy?qi;?WhXUY7lGu;#nTle(UItxYNZS36gY8c?o+tu zr!yEYtf{w9D8_EG3U~KSdc6NWo__do z-1NE2co6lg#aG`t7P!*Z!#v<@(PhdM{@b3~0o!Nf2n0K2n9M-AswNOc;nhJhyNqIa zs#hrPXa~|GBk;Gf12|l_8v|83rYKm^q;Rk077`U+_T!QU-2DF!4 zRe=v4zYVMZavx3`r?7WoioeW{19Y0r6hn_G^^jbNx8zW{sGKyGvzSYkpf7UFkGU`N zla>omO^)_rf~}7C@S2nnL4( zNDi|8Pl!!KpJ*q-XXl~j=jUR0-+XFz2P$(6-4hs%(({1+ox;p#Z6*oVmxA(N(pZsl zN9E6YVpd84Gzs}-xdH_$;U`e_JUEdDvHgMnP40|FZ%5N@Pq|$(v8d_;EO_B=oV#f#cER=P^_^)lbcG)SB85$wF6c+H@)_n5x#-FHPf#;=?W|oprNpxE5$bc zU))rO{(3#FT$QVi1`kqd8{vBEZET%47l-xq|0Lu|JRg4_)gQHe!^YG!uJS`Y+f~pM zZ~|BpRyLp1s<0BYCOE!Nl)m^6+SRL7FXI&UqmiUrA_1zo*L9|g3hcEC1o*Z?1sX8AY; zkX7s{QYF?7vZ9Q?!YQTXvk zN6q^vmC;*v8i8LpuSOFKjr?fa(PzLiGYKa{6Ucf1A}!IrCM*)@`ifftOew`18T}AW z9u9j0WuPLorJ{A~u=s)tu$7!k`4lTOhM5~#V2K5?au>_i)Fwbhx=xEJ86}%6OfnVD zpU;2WQ#)Y2hYy>ZNOVq0cyRTXXsp09A%|Q2a7}(Mhv9!ad#xj&`lVnf5JZX3 zi)2dF$dtq@UkJsFme)X&Um=&VSG+Y z`G`eI_8V^?iow-KQ2n&B04+`r^(@mrmZe+*P8KFWMQT&wq{US#T2Fxlp5$`N@{XZ) z!0JFO6I0&m;epn@fEuhXv$y#C=ELG$1ePw*_|9f(q+UxKUhhmV@9 zCa&zj%er=xo>a$-WnZ+0dLLX{3(<7m6!?C9AG*cGqbZKnA}>*lFdE7^C{?n6Jr-ac z%YQ1yC{qz0@~Kuzr=X=YP{2#JP}?`et<$L>kArv%HJN;W5JaR(&FhsKc{YjYTN4+wDiPF*EAEW zW2qgm`X)*ps!={jCADtRzLoam^Pfm&0`j-|aKhuK)_UCr;5z!+I=Y4iF*Ue>VAqrD zxL?Pu+M9SyBew#ku(}abh7LyIPe$S1K8*GDT-={B6g7EaracaMB=dS*+NKFeE*YH` zS^+CSgqNiyz*XM~Hx2ED&5z%W-&{Kbdk&VOj%*-?w>c?rChy>9WeKH~al2AXt)E9V?PCp6q z2K)q-z*37F39dl2fOOF%=*6VAE^4w%Z30)ovZ&BPDK8eqv5bD?g3}Sc@8`(!T!8Y) z)J$8;kKbUSZW7sa$a}ri;Og#M6nlb^$3*( zqS0o?17o7e6x_=oW`1ua;iQUJ5}>W(otzl1H%E<&$v(ycE@KGaLO zTL6_6hD;uAfvBxU*1om1fU}ORHn|?T$hIV4b)EdLiiy1b*5@i;PfhITe*Z@k91*nGsP`}lZFIV3k zQQy3=xboel=s$lh_Q%Gyo1nDz{FyWHSWz*iU3eXjjwb`GU)4A|zE<`Pt| zm!?P1^lg>E^mxC}PQwD7LBtdE(LCu=*tfoFJrT(jjk$0tenNlT^Edx(UJp&W_cpx1 zey+a#c0{)3sU4At`rP_BPJpgU`*H!=TEJP`V*$2~+p;C4wwAU^K3SdSF>=_KxB?}< z-X1+nGOmZsGDB-HQ5AbkB3ph+#e!HS=MNKTg6%bdt;GkM04Hw!p|NsEKl5U9J@2;> zfG;Bn_}=JgnDxi?STgQf#0M4jzMK>jEZN%v`gK_MNkZK#IkYce%~QZue6o|1+Jo3i z$F=1@^pMfm9QLB>N1a-%1X%$^t0Z6y6C57_Gd~Fu3q%GrZ9UXxWezRpcntyd(kBN5 zGVe8y9#2G`dc3}DGi>*Ngx^%qhjq!vUut^6_J`egYQYLL*0rhNjv)bH0eUQ0Uj^W{ z_bJ8Gd@WIBCyFy^97L{Z>|GuIlIA#ICyg0nzQK}T(Gw*-BbA`Ku*H1a53GG7EKdYm zP0##o0fHJJpe;U*!9#%Z*jyuSy}u*cv~wrMzqTKjZ)Td_XCx=ZLL;QVt-&IsPcPh7 zQh=ea9l*;=*0$bpJaq)B_^7;X*g9_8Ze1tRzUD7Y)yFF;Ocb~jL`Sex?ua_lVq9|D zttKLCl~nl%TvZ|J*cwn<@lnlfWz!}tZruuGKbOP0zAYc?391_!G3luV82Zw7EDy29 zN@aPfFEn(WE@odgS_6_|u`4)fbD(p`s96oU(_l~Cyf$cYKni)_x%RviVsl6WGscttpF4+>y62=nJ zYHNGGtlBAr*6 zd&X4#qPSz~5ZM0XPlIpbSx3PTxT>91r^_8!Un*HbiY=kqPDuA#KzGE+aWPo1YCSSv zEyv>x1sv!IY)3ZV^$d=GLwuHC9RzJ5cUWE(y6`)*Z z9!($GV*tV%7Xmw%0|g^E8z%k*L+Q{6)cU#XkQqU5rZ%bROm@nlFmBZSq&5}nfuteHd&Y@?q)g=-4v&DG;!CLhN|n0#gdJ0BDK|O31{uAuig^|F!#4JO`kcK8mlUzIp?!F$nY~WsmilvW3s-bIc^hm4MgfDyBJ83H?B-(V z$#d}%M5T9v*B)`)xSE3nkmS_lC8wgiG9GECWS0-M-ehR*YSX?*_a_e=fT`D9)6#GP zIw7#4TW7zDLYkli5_mER2_Yfn9@H*>t9E@xueT0L(ezcfzH`Ut1Y&U73Y&v zk}+d+9424b4RKxA+y12p@B9?u&eYO!x&VR}?!+ZL#CE3*;V3u4Rol1?AbjL=?r-KQ zQHMGaj%~{*OcFIbh87k!GHU#`tTw$SS9Q6I=<4;g+??KZ$=ns7tr#M3q)5sDG-sXD z{HM*Dg&6&)?j&?lVAGOQaQUmRnzsmAS*01u9<9~4G}+Q(`CsL^`ielWRFpugU2a4R zqwB<)oWRvba}||UETwy*dqEEZoQG2`(^qM)6Zxmu5p5uw%hNcA9TSRV!Vs~VSpn0m zv=7+9Ja$N6`_o`O97SKGlV+DZTcDIw)UEkQMa z#kx-{bDQ^zo6z%5Pnp*@CA$tGV^DAOS^HnOF1r!)?)wn^n(E+5;FwhJBfP1>ZrNsynxhJb7-q5 zx<;~=B_?3@-n~dnv%=ZQ$y%5%rN>sSMgmPu`I~@~a1ypHYZ4OPauM3MwraE5#R5I# zh(V**fqnz_W8j=~G1=3I$X&U}Ig|*`?mF~HOT*}Ee}v)*6JU>t#bQofzA=~Ekk^i8 zX6$(zY?$~7aL?8ckskRRO=cZtH zAP&53L&?ep1lXy)!G@+rAELZ&j2So(jpN1|D-h{LW2HNU9t3wak#1ZC3|#=cLCwCd z+mndj@CTZ3OSPwQEKn`70A(FvWEU&)i>-Je3sI%jDLx)^TrR|Q@Lua=^!2VLJz7|Z z!RJpgQD4zgg3GCkCA@^zRvmYw)nc`4L2k_7iZQjNNUqC+>s>d7#b=|7Jr?PKNG#cV z5Sj5Y*jeL3*XS4on;Oi0)o_H=3m!Rq7)koeA77KcHn0-t!3B%(>-qDs-5F(olHXNywSHxz z6<6A&Z%P&Yt@O&;S7sq#R=!h?iZ>(h`Rr=+i|GpQem4PRJ)WF~&au&mkBdj0eis`V zVL&pUK9L2K-Wdo0eNA2M3M0AJhQ^cXWWBBU{;fs)a(8tp4PkTz;@1)x$W zWixv7tkh8z*Tqjfj@c!pNcje!ioQ0m7M*qBg?M_$4uol@0#p-LJ}6cy6V27vA}Hli zWEE>dnyA_Z%m7;^+y~jx5WtcBHP~HQi&HW=#eg6F5TOi(Sef$b*7$1qL2cESfD*Xc zZ*YfE&%w5r+c6<*Ge9YtTcBF3dt_BsRi%e2)*D#4whEg5?TZ)Vx?kSGqi;^%7+6u) z?s=HCWecu-_3!2{yeWMVkb*%!CyyM#1y4VXyy??TEiGYX zQi7zduM=|riT zvy)7kqk37tE`slTA~Ez`FS?6I`+`M+SyfnBI_`;i_?SfV(I zU=XDh1V~pVYjOm-DslG3?PeFEJy9~6$U(IBzi_H z!Ih2Z_pZ`b1tPf~Euh$X#V50rcB|ChNsGFC&YW*eGfza{iYqu7jrrM4cs;Ef9NSs< z*HhOjD^a4a8fo6WQ&SC?`t&?CvVxD;oNL`m=PVzr z2h!q|(pYX4lmz^z=S{&S-vg+k?;Kdsj63eYwqM5LSdyEAczu{mpQ}HaSE4Tv_4f-2viZ?St7p<{bqD=%q*WfZ zl6D2KfE0_gRlCwB1t$4Y>zdNRgE4yLN}Tf*{s`H(N#D7TJ(e`tl9Cb>KmJGL6JRg> zY@crQe$Gf7uB}Bf14%r&j%imFwK-o2I)Q(W!OOL5g)w>M#7gUw3rjo2O3nnPv{QwF zJvkYZmo7!WZ|QGte_i_Cfo)6gef%-pt5(9dW(^Yd>_t^<46Ye9nkwfsnp;k{krw4- z`sByF<;&nNEHc4MtU#r=7y@}6**uI^#&P}i$eKI_Q!o1B7mz;${h+{#G Date: Wed, 13 May 2020 10:53:06 -0700 Subject: [PATCH 304/535] Adding CHANGELOG entry --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c63467e078..f840735b28 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -38,6 +38,11 @@ Discretization improvements - Added new partial assembly kernels for H(div) bilinear forms, as well as VectorFEDivergenceIntegrator. +- Improved the documentation of the GridFunction GetValue and GetVectorValue + methods. Expanded the GetValue and GetVectorValue methods which accept an + ElementTransformation argument to support evaluation on boundary elements + and, in the continuous field case, arbirtrary mesh edges and faces. + Linear and nonlinear solvers ---------------------------- - Added power method to iteratively estimate the largest eigenvalue and the From 32c8c20f23012fc75c03af685fc7d4e7fab4ef0c Mon Sep 17 00:00:00 2001 From: "Robert W. Anderson" Date: Wed, 13 May 2020 10:55:24 -0700 Subject: [PATCH 305/535] remove local/global methods from mesh, make non-virtual in pmesh. --- mesh/mesh.hpp | 10 ---------- mesh/pmesh.hpp | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 640c8f49ad..cb24d69889 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -690,16 +690,6 @@ public: /// Utility function: sum integers from all processors (Allreduce). virtual long ReduceInt(int value) const { return value; } - /// Map a global element number to a local element number. (For a - /// serial mesh, the numberings are the same.) - virtual int GetLocalElementNum(long global_element_num) const - { return global_element_num; } - - /// Map a local element number to a global element number. (For a - /// serial mesh, the numberings are the same.) - virtual long GetGlobalElementNum(long local_element_num) const - { return local_element_num; } - /// Return the total (global) number of elements. long GetGlobalNE() const { return ReduceInt(NumOfElements); } diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 8535afcea6..5f9d2ca8f9 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -230,10 +230,10 @@ public: /** Map a global element number to a local element number. If the global element is not on this processor, return -1. */ - virtual int GetLocalElementNum(long global_element_num) const; + int GetLocalElementNum(long global_element_num) const; /// Map a local element number to a global element number. - virtual long GetGlobalElementNum(int local_element_num) const; + long GetGlobalElementNum(int local_element_num) const; GroupTopology gtopo; From 3ae7c0ae8a807f74efa99ce960eb62241c16d817 Mon Sep 17 00:00:00 2001 From: Bob Anderson Date: Wed, 13 May 2020 12:36:35 -0700 Subject: [PATCH 306/535] change convenience entry point for html docs from symbolic link to meta refresh. the symbolic link causes trouble with relative paths in chrome --- doc/makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/makefile b/doc/makefile index f8e111f1f3..8746515e3e 100644 --- a/doc/makefile +++ b/doc/makefile @@ -15,8 +15,7 @@ DOXYGEN_CONF = CodeDocumentation.conf # doxygen uses: graphviz, latex html: $(DOXYGEN_CONF) doxygen $(DOXYGEN_CONF) - rm -f CodeDocumentation.html - ln -s CodeDocumentation/html/index.html CodeDocumentation.html + echo "" > CodeDocumentation.html clean: rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~ From e55e61a32c9abf70f231a1cbd0e7f55a843f66b8 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 13 May 2020 15:44:48 -0700 Subject: [PATCH 307/535] Adding documentation header, changing default, behavior, and adding visualization --- miniapps/meshing/trimmer.cpp | 96 +++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp index e1061b6090..5dc912d5f8 100644 --- a/miniapps/meshing/trimmer.cpp +++ b/miniapps/meshing/trimmer.cpp @@ -9,6 +9,42 @@ // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. // +// ----------------------------------------------------------------------- +// Trimmer Miniap: Trim away elements according to their attribute numbers +// ----------------------------------------------------------------------- +// +// This miniapp creates a new mesh consisting of all the elements not +// possessing a given set of attribute numbers. The new boundary elements +// are created with boundary attribute numbers related to the trimmed elements' +// attribute numbers. +// +// By default the new boundary elements will have new attribute +// numbers so as not to interfere with existing boundaries. For +// example, consider a mesh with attriutes given by: +// +// attributes = {a1, a2, a3, a4, a5, a6, ..., amax} +// bdr_attributes = {b1, b2, ..., bmax} +// +// If we trim away elements with attributes a2 and a4 the new mesh will have +// attributes: +// +// attributes: {a1, a3, a5, a6, ..., amax} +// bdr_attributes = {b1, b2, ..., bmax, bmax + a2, bmax + a4} +// +// The user has the option of providing new attribute numbers for each group +// of elements to be trimmed. In this case the new boundary elements may have +// the same attribute numbers as existing boundary elements. +// +// The resulting mesh is displayed with GLVis (unless explicitly disabled) and +// is also written to the file "trimmer.mesh" +// +// Compile with: make trimmer +// +// Sample runs: +// trimmer -a '2' -b '2' +// trimmer -m ../../data/beam-hex.mesh -a '2' +// trimmer -m ../../data/beam-hex.mesh -a '2' -b '2' + #include "mfem.hpp" #include #include @@ -20,39 +56,51 @@ int main(int argc, char *argv[]) { // Parse command-line options. const char *mesh_file = "../../data/beam-tet.vtk"; - int offset = -1; Array attr; - + Array bdr_attr; + bool visualization = 1; + OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); - args.AddOption(&offset, "-o", "--attr-offset", - "Offset is added to the element attribute to generate " - "the boundary offset."); args.AddOption(&attr, "-a", "-attr", "Set of attributes to remove from " "the mesh."); + args.AddOption(&bdr_attr, "-b", "-bdr-attr", "Set of boundary attributes " + "to assign to the new boundary elements."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); args.Parse(); if (!args.Good()) { args.PrintUsage(cout); return 1; } - if (attr.Size() == 0) - { - attr.SetSize(1); - attr[0] = 2; - } - + Mesh mesh(mesh_file, 0, 0); - int max_attr = mesh.attributes.Max(); - int max_bdr_attr = (offset == -1) ? mesh.bdr_attributes.Max() : offset; + int max_attr = mesh.attributes.Max(); + int max_bdr_attr = mesh.bdr_attributes.Max(); + if (bdr_attr.Size() == 0) + { + bdr_attr.SetSize(attr.Size()); + for (int i=0; i marker(max_attr); + Array attr_inv(max_attr); marker = 0; + attr_inv = 0; for (int i=0; iDuplicate(&trimmed_mesh); - bel->SetAttribute(max_bdr_attr + a1); + bel->SetAttribute(bdr_attr[attr_inv[a1-1]]); trimmed_mesh.AddBdrElement(bel); } else if (!marker[a1-1] && marker[a2-1]) { Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); - bel->SetAttribute(max_bdr_attr + a2); + bel->SetAttribute(bdr_attr[attr_inv[a2-1]]); trimmed_mesh.AddBdrElement(bel); } } @@ -156,7 +204,19 @@ int main(int argc, char *argv[]) trimmed_mesh.Finalize(); trimmed_mesh.RemoveUnusedVertices(); - ofstream ofs("trimmed.mesh"); - trimmed_mesh.Print(ofs); - ofs.close(); + // Save the final mesh + ofstream mesh_ofs("trimmer.mesh"); + mesh_ofs.precision(8); + trimmed_mesh.Print(mesh_ofs); + + if (visualization) + { + // GLVis server to visualize to + char vishost[] = "localhost"; + int visport = 19916; + socketstream sol_sock(vishost, visport); + sol_sock.precision(8); + sol_sock << "mesh\n" << trimmed_mesh << flush; + } + } From df62917d0c0011d3c0ea97f12a8c84024817abdd Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 13 May 2020 15:45:11 -0700 Subject: [PATCH 308/535] Adding trimmer to the build system --- .gitignore | 2 ++ miniapps/meshing/CMakeLists.txt | 4 ++++ miniapps/meshing/makefile | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e2a2e99043..d02db6052b 100644 --- a/.gitignore +++ b/.gitignore @@ -167,6 +167,7 @@ miniapps/meshing/twist miniapps/meshing/mesh-explorer miniapps/meshing/shaper miniapps/meshing/extruder +miniapps/meshing/trimmer miniapps/meshing/mesh-optimizer miniapps/meshing/pmesh-optimizer miniapps/meshing/minimal-surface @@ -180,6 +181,7 @@ miniapps/meshing/mesh-explorer.mesh miniapps/meshing/partitioning.txt miniapps/meshing/shaper.mesh miniapps/meshing/extruder.mesh +miniapps/meshing/trimmer.mesh miniapps/meshing/optimized* miniapps/meshing/perturbed* diff --git a/miniapps/meshing/CMakeLists.txt b/miniapps/meshing/CMakeLists.txt index 6b882eedee..4a0f206949 100644 --- a/miniapps/meshing/CMakeLists.txt +++ b/miniapps/meshing/CMakeLists.txt @@ -41,6 +41,10 @@ add_mfem_miniapp(toroid MAIN toroid.cpp LIBRARIES mfem) +add_mfem_miniapp(trimmer + MAIN trimmer.cpp + LIBRARIES mfem) + add_mfem_miniapp(twist MAIN twist.cpp LIBRARIES mfem) diff --git a/miniapps/meshing/makefile b/miniapps/meshing/makefile index 8248dcf16f..65492b1c3b 100644 --- a/miniapps/meshing/makefile +++ b/miniapps/meshing/makefile @@ -21,7 +21,7 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk MFEM_LIB_FILE = mfem_is_not_built -include $(CONFIG_MK) -SEQ_MINIAPPS = mobius-strip klein-bottle toroid twist \ +SEQ_MINIAPPS = mobius-strip klein-bottle toroid trimmer twist \ mesh-explorer shaper extruder mesh-optimizer \ minimal-surface PAR_MINIAPPS = pmesh-optimizer pminimal-surface @@ -98,6 +98,6 @@ clean-build: clean-exec: @rm -f mobius-strip.mesh klein-bottle.mesh mesh-explorer.mesh - @rm -f toroid-*.mesh twist-*.mesh trimmed.mesh + @rm -f toroid-*.mesh twist-*.mesh trimmer.mesh @rm -f partitioning.txt shaper.mesh extruder.mesh @rm -f optimized* perturbed* From 9ce518a7227eba73403354b7327d1c1b44efbda0 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Wed, 13 May 2020 19:10:53 -0400 Subject: [PATCH 309/535] Cleans up pumi to mfem field transfer routine Now the same routine should work for both vector and scalar field --- mesh/pumi.cpp | 124 +++++++++++++++++++++++++------------------------- mesh/pumi.hpp | 18 ++++++-- 2 files changed, 78 insertions(+), 64 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 9f2ad05912..b17b192fea 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -991,7 +991,7 @@ IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, // for non zero "rotation", rotate the xi if (rotation) { - ma::rotateTetXi(pumi_xi[i], rotation); + ma::unrotateTetXi(pumi_xi[i], rotation); } IntegrationPoint& ip = mfem_xi.IntPoint(i); double tmp_xi[3]; @@ -1001,6 +1001,35 @@ IntegrationRule ParPumiMesh::ParentXisPUMItoMFEM(apf::Mesh2* apf_mesh, return mfem_xi; } +// Convert parent coordinate from MFEM tet to PUMI tet +void ParPumiMesh::ParentXisMFEMtoPUMI(apf::Mesh2* apf_mesh, + int elemId, + apf::MeshEntity* tet, + const IntegrationRule& mfem_xi, + apf::NewArray& pumi_xi, + bool checkOrientation) +{ + int num_nodes = mfem_xi.Size(); + if (!pumi_xi.allocated()) + pumi_xi.allocate(num_nodes); + else + pumi_xi.resize(num_nodes); + + int rotation = checkOrientation ? RotationPUMItoMFEM(apf_mesh, tet, elemId):0; + for (int i = 0; i < num_nodes; i++) + { + IntegrationPoint ip = mfem_xi.IntPoint(i); + pumi_xi[i] = apf::Vector3(ip.x, ip.y, ip.z); + + // for non zero "rotation", un-rotate the xi + if (rotation) + { + ma::rotateTetXi(pumi_xi[i], rotation); + } + } +} + + // Transfer a mixed vector-scalar field (i.e. velocity,pressure) and the // magnitude of the vector field to use for mesh adaptation. void ParPumiMesh::FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, @@ -1205,74 +1234,47 @@ void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, } void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, - apf::Field* ScalarField, - ParGridFunction* Pr) + apf::Field* field, + ParGridFunction* grid) { - // Pr->Update(); - // Find local numbering - /* v_num_loc = apf_mesh->findNumbering("LocalVertexNumbering"); */ + int nc = apf::countComponents(field); + ParFiniteElementSpace* fes = grid->ParFESpace(); + ParMesh* pmesh = fes->GetParMesh(); - // Loop over field to copy - getShape(ScalarField); - apf::MeshEntity* ent; - apf::MeshIterator* itr = apf_mesh->begin(0); - while ((ent = apf_mesh->iterate(itr))) - { - unsigned int id = apf::getNumber(v_num_loc, ent, 0, 0); - double fieldVal = apf::getScalar(ScalarField, ent, 0); + int dim = apf_mesh->getDimension(); - (Pr->GetData())[id] = fieldVal; - } - apf_mesh->end(itr); - - // Check for higher order - getShape(ScalarField); - if ( Pr->FESpace()->GetOrder(1) > 1 ) - { - // Assume all element type are the same i.e. tetrahedral - const FiniteElement* H1_elem = Pr->FESpace()->GetFE(1); - const IntegrationRule &All_nodes = H1_elem->GetNodes(); - int nnodes = All_nodes.Size(); - - // Loop over elements - int nc = apf::countComponents(ScalarField); - int iel = 0; - itr = apf_mesh->begin(3); - while ((ent = apf_mesh->iterate(itr))) + apf::MeshIterator* it = apf_mesh->begin(dim); + for(int i = 0; i < pmesh->GetNE(); i++) { + const FiniteElement* mfem_elem = fes->GetFE(i); + const IntegrationRule &mfem_xi = mfem_elem->GetNodes(); + int non = mfem_xi.Size(); + apf::MeshEntity* ent = apf_mesh->iterate(it); + apf::NewArray pumi_xi(non); + ParentXisMFEMtoPUMI(apf_mesh, + i, + ent, + mfem_xi, + pumi_xi, + true); + Array vdofs; + fes->GetElementVDofs(i, vdofs); + apf::MeshElement* me = apf::createMeshElement(apf_mesh, ent); + apf::Element* el = apf::createElement(field, me); + for(int j = 0; j < non; j++) { - Array vdofs; - Pr->FESpace()->GetElementVDofs(iel, vdofs); - - // Create PUMI element to interpolate - apf::MeshElement* mE = apf::createMeshElement(apf_mesh, ent); - apf::Element* elem = apf::createElement(ScalarField, mE); - - // Vertices are already interpolated - for (int ip = 0; ip < nnodes; ip++) //num_vert + apf::DynamicVector values(nc); + apf::getComponents(el, pumi_xi[j], &values[0]); + // Fill the nodes list + for (int c = 0; c < nc; c++) { - // Take parametric coordinates of the node - apf::Vector3 param; - param[0] = All_nodes.IntPoint(ip).x; - param[1] = All_nodes.IntPoint(ip).y; - param[2] = All_nodes.IntPoint(ip).z; - - // Compute the interpolating coordinates - apf::DynamicVector phCrd(nc); - apf::getComponents(elem, param, &phCrd[0]); - - // Fill the nodes list - for (int kk = 0; kk < nc; ++kk) - { - int dof_ctr = ip + kk * nnodes; - (Pr->GetData())[vdofs[dof_ctr]] = phCrd[kk]; - } + int dof_loc = j + c * non; + (grid->GetData())[vdofs[dof_loc]] = values[c]; } - iel++; - apf::destroyElement(elem); - apf::destroyMeshElement(mE); } - apf_mesh->end(itr); + apf::destroyElement(el); + apf::destroyMeshElement(me); } + apf_mesh->end(it); } } diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 33a3ba3e1c..b51af72b70 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -101,6 +101,18 @@ public: int elemId, apf::NewArray& pumi_xi, bool checkOrientation = true); + /// Convert the parent coordinate from MFEM to PUMI + /** This is the inverse of ParentXisPUMItoMFEM. + By default this functions assumes that there is always + change in the orientations of some of the elements. In case it + is known for sure that there is NO change in the orientation, + call the functions with last argument = false */ + void ParentXisMFEMtoPUMI(apf::Mesh2* apf_mesh, + int elemId, + apf::MeshEntity* tet, + const IntegrationRule& mfem_xi, + apf::NewArray& pumi_xi, + bool checkOrientation = true); /// Transfer field from MFEM mesh to PUMI mesh [Mixed]. void FieldMFEMtoPUMI(apf::Mesh2* apf_mesh, ParGridFunction* grid_vel, @@ -129,10 +141,10 @@ public: /// Update the mesh after adaptation. void UpdateMesh(const ParMesh* AdaptedpMesh); - /// Transfer a field from PUMI to MFEM after mesh adapt [Scalar]. + /// Transfer a field from PUMI to MFEM after mesh adapt [Scalar and Vector]. void FieldPUMItoMFEM(apf::Mesh2* apf_mesh, - apf::Field* ScalarField, - ParGridFunction* Pr); + apf::Field* field, + ParGridFunction* grid); virtual ~ParPumiMesh() {} }; From 76b3f742c5f54234a1d284994fb08669366ffd7b Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Wed, 13 May 2020 19:12:15 -0400 Subject: [PATCH 310/535] Removes commented code --- mesh/pumi.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index b51af72b70..643f74b413 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -56,8 +56,6 @@ public: PumiMesh(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1, bool fix_orientation = true); - /* using Mesh::Load; */ - /// Load a PUMI mesh (following the steps in the MFEM Load function). void Load(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1, bool fix_orientation = true); From 5667a72b24829bfe4b1b62cef1bfb06ec223b982 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Wed, 13 May 2020 19:46:21 -0400 Subject: [PATCH 311/535] Fixes styles --- mesh/pumi.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index b17b192fea..f76f25b3c8 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -1011,9 +1011,13 @@ void ParPumiMesh::ParentXisMFEMtoPUMI(apf::Mesh2* apf_mesh, { int num_nodes = mfem_xi.Size(); if (!pumi_xi.allocated()) - pumi_xi.allocate(num_nodes); + { + pumi_xi.allocate(num_nodes); + } else - pumi_xi.resize(num_nodes); + { + pumi_xi.resize(num_nodes); + } int rotation = checkOrientation ? RotationPUMItoMFEM(apf_mesh, tet, elemId):0; for (int i = 0; i < num_nodes; i++) @@ -1244,7 +1248,8 @@ void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, int dim = apf_mesh->getDimension(); apf::MeshIterator* it = apf_mesh->begin(dim); - for(int i = 0; i < pmesh->GetNE(); i++) { + for (int i = 0; i < pmesh->GetNE(); i++) + { const FiniteElement* mfem_elem = fes->GetFE(i); const IntegrationRule &mfem_xi = mfem_elem->GetNodes(); int non = mfem_xi.Size(); @@ -1260,14 +1265,14 @@ void ParPumiMesh::FieldPUMItoMFEM(apf::Mesh2* apf_mesh, fes->GetElementVDofs(i, vdofs); apf::MeshElement* me = apf::createMeshElement(apf_mesh, ent); apf::Element* el = apf::createElement(field, me); - for(int j = 0; j < non; j++) + for (int j = 0; j < non; j++) { - apf::DynamicVector values(nc); + apf::DynamicVector values(nc); apf::getComponents(el, pumi_xi[j], &values[0]); // Fill the nodes list for (int c = 0; c < nc; c++) { - int dof_loc = j + c * non; + int dof_loc = j + c * non; (grid->GetData())[vdofs[dof_loc]] = values[c]; } } From a23760dd801bc2f29245b1b0efc8c4fda43539fe Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Wed, 13 May 2020 19:54:16 -0400 Subject: [PATCH 312/535] Fixes variable length arrays --- mesh/pumi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index f76f25b3c8..ec2461ed84 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -951,7 +951,7 @@ int ParPumiMesh::RotationPUMItoMFEM(apf::Mesh2* apf_mesh, // get downward vertices of PUMI element apf::Downward vs; int nv = apf_mesh->getDownward(tet,0,vs); - int pumi_vid[nv]; + int pumi_vid[12]; for (int i = 0; i < nv; i++) { pumi_vid[i] = apf::getNumber(v_num_loc, vs[i], 0, 0); @@ -962,7 +962,7 @@ int ParPumiMesh::RotationPUMItoMFEM(apf::Mesh2* apf_mesh, this->GetElementVertices(elemId, mfem_vid); // get rotated indices of PUMI element - int pumi_vid_rot[nv]; + int pumi_vid_rot[12]; for (int i = 0; i < nv; i++) { pumi_vid_rot[i] = mfem_vid.Find(pumi_vid[i]); From a556dc8ebad5abfb2f40d1295a29aa4b71416d57 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Wed, 13 May 2020 17:07:38 -0700 Subject: [PATCH 313/535] consider support for Vectors/DenseMatrices in lu batch --- linalg/densemat.cpp | 35 +++++++++++++++++++++++++++-------- linalg/densemat.hpp | 16 +++++++++++++--- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 6582858ce5..da33c41f08 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3505,12 +3505,29 @@ DenseTensor &DenseTensor::operator=(double c) return *this; } -void BatchLUFactor(Vector &Minv,const int m,const int NE, Array &P) +void BatchLUFactor(Vector &Minv, const int m, const int NE, Array &P) { P.SetSize(m*NE); - auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); - auto piv_all = mfem::Reshape(P.Write(), m, NE); + BatchLUFactor_impl(Minv.ReadWrite(), m, NE, P.Write()); +} +void BatchLUFactor(DenseTensor &Minv,const int NE, Array &P) +{ + const int m = Minv.SizeI(); + P.SetSize(m*NE); + BatchLUFactor_impl(Minv.ReadWrite(), m, NE, P.Write()); +} + +void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) +{ + + auto data_all = mfem::Reshape(Minv, m, m, NE); + auto piv_all = mfem::Reshape(P, m, NE); + Array pivot_flag(1); + pivot_flag[0] = true; + bool *d_pivot_flag = pivot_flag.ReadWrite(); + const double TOL = 1.e-9; + MFEM_FORALL(e, NE, { @@ -3543,11 +3560,10 @@ void BatchLUFactor(Vector &Minv,const int m,const int NE, Array &P) } }//pivot end - //Q: How to check for errors? - //if (abs(data[i + i*m]) <= TOL) - //{ - //return false; // failed - //} + if (abs(data[i + i*m]) <= TOL) + { + d_pivot_flag[0] = false; + } const double a_ii_inv = 1.0 / data[i+i*m]; for (int j = i+1; j < m; j++) @@ -3568,8 +3584,11 @@ void BatchLUFactor(Vector &Minv,const int m,const int NE, Array &P) }); + MFEM_ASSERT(pivot_flag[0].HostRead(), "Batch LU factorization failed \n"); + } + void BatchLUSolve(Vector &Minv, int m, int NE, Array &P, Vector &X) { diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 3184a77800..4e857ccdd1 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -859,10 +859,20 @@ public: ~DenseTensor() { tdata.Delete(); } }; -void BatchLUFactor(Vector &Minv,int m,int NE, Array &P); +void BatchLUFactor(Vector &Minv, const int m,const int NE, Array &P); -void BatchLUSolve(Vector &Minv, int m, int NE, - Array &P, Vector &X); +void BatchLUFactor(DenseTensor &Minv, const int NE, Array &P); + +void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P); + +void BatchLUSolve(const Vector &Minv, const int m, const int NE, + const Array &P, Vector &X); + +void BatchLUSolve(const DenseTensor &Minv, const int NE, + const Array &P, Vector &X); + +void BatchLU_impl(const double *Minv, const int m, const int NE, + const int *P, Vector &X); // Inline methods From b0935c7f63e109d2882a057067ee017245ec9bb3 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Wed, 13 May 2020 20:22:37 -0400 Subject: [PATCH 314/535] Updates MFEM_USE_PUMI instructions in INSTALL --- INSTALL | 3 +++ 1 file changed, 3 insertions(+) diff --git a/INSTALL b/INSTALL index ddc911225b..e14d866d82 100644 --- a/INSTALL +++ b/INSTALL @@ -426,6 +426,8 @@ MFEM_USE_PUMI = YES/NO data management system that is capable of handling general non-manifold models and effectively supports automated adaptive analysis. PUMI enables support for parallel unstructured mesh modifications in MFEM. + The develop branch of PUMI repository (https://github.com/SCOREC/core) + should be used for most updated features. MFEM_USE_UMPIRE = YES/NO Enables support for Umpire, a resource management library that allows the @@ -609,6 +611,7 @@ The specific libraries and their options are: - PUMI (optional), used when MFEM_USE_PUMI = YES. URL: https://scorec.rpi.edu/pumi + https://github.com/SCOREC/core Options: PUMI_OPT, PUMI_LIB. Versions: PUMI >= 2.2.0. From 72e442ba45d868d21718b3510efae33a58485172 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 14 May 2020 11:34:07 +0200 Subject: [PATCH 315/535] Removing duplicate meshes --- miniapps/nurbs/cube-nurbs.mesh | 73 ------------------------------- miniapps/nurbs/pipe-nurbs-2d.mesh | 70 ----------------------------- miniapps/nurbs/square-nurbs.mesh | 57 ------------------------ 3 files changed, 200 deletions(-) delete mode 100644 miniapps/nurbs/cube-nurbs.mesh delete mode 100644 miniapps/nurbs/pipe-nurbs-2d.mesh delete mode 100644 miniapps/nurbs/square-nurbs.mesh diff --git a/miniapps/nurbs/cube-nurbs.mesh b/miniapps/nurbs/cube-nurbs.mesh deleted file mode 100644 index 513b58982b..0000000000 --- a/miniapps/nurbs/cube-nurbs.mesh +++ /dev/null @@ -1,73 +0,0 @@ -MFEM NURBS mesh v1.0 - -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# SEGMENT = 1 -# SQUARE = 3 -# CUBE = 5 -# - -dimension -3 - -elements -1 -1 5 0 1 2 3 4 5 6 7 - -boundary -6 -1 3 0 1 2 3 -1 3 4 5 6 7 -1 3 0 1 5 4 -1 3 1 2 6 5 -1 3 2 3 7 6 -1 3 3 0 4 7 - -edges -12 -0 0 1 -0 3 2 -0 4 5 -0 7 6 -1 0 3 -1 1 2 -1 4 7 -1 5 6 -2 0 4 -2 1 5 -2 2 6 -2 3 7 - -vertices -8 - -knotvectors -3 -1 2 0 0 1 1 -1 2 0 0 1 1 -1 2 0 0 1 1 - -weights -1 -1 -1 -1 -1 -1 -1 -1 - -FiniteElementSpace -FiniteElementCollection: NURBS1 -VDim: 3 -Ordering: 1 - -0 0 0 -1 0 0 -1 1 0 -0 1 0 -0 0 1 -1 0 1 -1 1 1 -0 1 1 diff --git a/miniapps/nurbs/pipe-nurbs-2d.mesh b/miniapps/nurbs/pipe-nurbs-2d.mesh deleted file mode 100644 index b02c040635..0000000000 --- a/miniapps/nurbs/pipe-nurbs-2d.mesh +++ /dev/null @@ -1,70 +0,0 @@ -MFEM NURBS mesh v1.0 - -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# SEGMENT = 1 -# SQUARE = 3 -# CUBE = 5 -# - -dimension -2 - -elements -1 -1 3 0 1 2 3 - -boundary -4 -1 1 0 1 -1 1 2 3 -1 1 3 0 -1 1 1 2 - -edges -4 -0 0 1 -0 3 2 -1 0 3 -1 1 2 - -vertices -4 - -knotvectors -2 -2 3 0 0 0 1 1 1 -2 3 0 0 0 1 1 1 - -weights -1 -1 -1 -1 - -0.7071067811865475244 -0.7071067811865475244 - -1 -1 - -0.7071067811865475244 - -FiniteElementSpace -FiniteElementCollection: NURBS2 -VDim: 2 -Ordering: 1 - -0 0 -2 2 -1 2 -0 1 - -2 0 -1 1 - -0 0.5 -1.5 2 - -1.5 0.5 diff --git a/miniapps/nurbs/square-nurbs.mesh b/miniapps/nurbs/square-nurbs.mesh deleted file mode 100644 index 282818ff41..0000000000 --- a/miniapps/nurbs/square-nurbs.mesh +++ /dev/null @@ -1,57 +0,0 @@ -MFEM NURBS mesh v1.0 - -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# SEGMENT = 1 -# SQUARE = 3 -# CUBE = 5 -# - -dimension -2 - -elements -1 -1 3 0 1 2 3 - -boundary -4 -1 1 0 1 -1 1 2 3 -1 1 3 0 -1 1 1 2 - - - -edges -4 -0 0 1 -0 3 2 -1 0 3 -1 1 2 - -vertices -4 - -knotvectors -2 -1 2 0 0 1 1 -1 2 0 0 1 1 - -weights -1 -1 -1 -1 - -FiniteElementSpace -FiniteElementCollection: NURBS1 -VDim: 2 -Ordering: 1 - -0 0 -1 0 -1 1 -0 1 - From 3e70d5da1c2a05a26262de022e204da525273cb4 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 14 May 2020 11:40:26 +0200 Subject: [PATCH 316/535] Removing whitespace/lines --- fem/fespace.cpp | 3 +-- fem/fespace.hpp | 3 +-- miniapps/nurbs/nurbs_ex1.cpp | 4 ++-- miniapps/nurbs/nurbs_ex1p.cpp | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index ce30107eb6..8f2bff0dad 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -6,7 +6,7 @@ // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file +// terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. // Implementation of FiniteElementSpace @@ -1521,7 +1521,6 @@ void FiniteElementSpace::UpdateNURBS() bdrElem_dof = NURBSext->GetBdrElementDofTable(); delete face_dof; face_dof = NULL; - } void FiniteElementSpace::GenerateFaceDofsFromBdr() diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 4e8b742ebf..63f719693a 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -6,7 +6,7 @@ // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file +// terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. #ifndef MFEM_FESPACE @@ -685,7 +685,6 @@ public: FiniteElementCollection *Load(Mesh *m, std::istream &input); virtual ~FiniteElementSpace(); - }; diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index bca6ba4f6f..e6b87ed0a4 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -300,11 +300,11 @@ int main(int argc, char *argv[]) Array ess_bdr(mesh->bdr_attributes.Max()); if (strongBC) { - ess_bdr = 1; + ess_bdr = 1; } else { - ess_bdr = 0; + ess_bdr = 0; } // Remove periodic BCs diff --git a/miniapps/nurbs/nurbs_ex1p.cpp b/miniapps/nurbs/nurbs_ex1p.cpp index eb73de0e0e..84b6b84f88 100644 --- a/miniapps/nurbs/nurbs_ex1p.cpp +++ b/miniapps/nurbs/nurbs_ex1p.cpp @@ -317,11 +317,11 @@ int main(int argc, char *argv[]) Array ess_bdr(pmesh->bdr_attributes.Max()); if (strongBC) { - ess_bdr = 1; + ess_bdr = 1; } else { - ess_bdr = 0; + ess_bdr = 0; } fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); } From 4f82fbda71ecea0dda243e45383bbe5da8c05017 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 14 May 2020 11:42:42 +0200 Subject: [PATCH 317/535] Correct penalty parameter input comment --- miniapps/nurbs/nurbs_ex1.cpp | 2 +- miniapps/nurbs/nurbs_ex1p.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/miniapps/nurbs/nurbs_ex1.cpp b/miniapps/nurbs/nurbs_ex1.cpp index e6b87ed0a4..e20fc0a1d4 100644 --- a/miniapps/nurbs/nurbs_ex1.cpp +++ b/miniapps/nurbs/nurbs_ex1.cpp @@ -158,7 +158,7 @@ int main(int argc, char *argv[]) "--weak-bc", "Selects strong or weak enforcement of Dirichlet BCs."); args.AddOption(&kappa, "-k", "--kappa", - "One of the two DG penalty parameters, should be positive." + "Sets the SIPG penalty parameters, should be positive." " Negative values are replaced with (order+1)^2."); args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", "--no-static-condensation", "Enable static condensation."); diff --git a/miniapps/nurbs/nurbs_ex1p.cpp b/miniapps/nurbs/nurbs_ex1p.cpp index 84b6b84f88..135d5882b7 100644 --- a/miniapps/nurbs/nurbs_ex1p.cpp +++ b/miniapps/nurbs/nurbs_ex1p.cpp @@ -167,7 +167,7 @@ int main(int argc, char *argv[]) "--weak-bc", "Selects strong or weak enforcement of Dirichlet BCs."); args.AddOption(&kappa, "-k", "--kappa", - "One of the two DG penalty parameters, should be positive." + "Sets the SIPG penalty parameters, should be positive." " Negative values are replaced with (order+1)^2."); args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc", "--no-static-condensation", "Enable static condensation."); From 1f45834e42fa5f0f3a8920ae5f5f05effe0b5b8c Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 14 May 2020 12:58:33 +0200 Subject: [PATCH 318/535] Remove braces --- mesh/mesh.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 4095d6abb7..4b9633e8e8 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -3343,9 +3343,7 @@ void Mesh::Loader(std::istream &input, int generate_edges, } else if (NURBSext) { - { - Nodes->FESpace()->GenerateFaceDofsFromBdr(); - } + Nodes->FESpace()->GenerateFaceDofsFromBdr(); } // If a parse tag was supplied, keep reading the stream until the tag is From 79312eeb084373745c685cb9efb8c7edc3b8593f Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Thu, 14 May 2020 13:29:34 +0200 Subject: [PATCH 319/535] Clearify comments --- fem/fespace.hpp | 8 ++++---- mesh/mesh.hpp | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 63f719693a..c273df52bc 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -112,8 +112,8 @@ protected: mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned. Table *bdrElem_dof; // used only with NURBS FE spaces; not owned. - Table *face_dof; // used only with NURBS FE spaces; - Array face_to_be; // used only with NURBS FE spaces; + Table *face_dof; // used only with NURBS FE spaces; owned. + Array face_to_be; // used only with NURBS FE spaces; owned. Array dof_elem_array, dof_ldof_array; @@ -530,8 +530,8 @@ public: /** @brief Generates partial face_dof table. - Table only defined for face on boundary. Uses bdrElem_dof table - and the mesh boundary information.*/ + The table is only defined for exterior faces that coincide with a boundary. + The routine uses the bdrElem_dof table and the mesh boundary information.*/ void GenerateFaceDofsFromBdr(); void BuildDofToArrays(); diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 8c97f8da2c..f5f519de2a 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -896,7 +896,8 @@ public: Return the face index of boundary element i. (3D) */ int GetBdrElementEdgeIndex(int i) const; - // Checks if the info required for the above function is available. + /** Checks if the boundary data structures required + for GetBdrElementFace() are available.*/ bool BdrInfoAvailable() const; /** @brief For the given boundary element, bdr_el, return its adjacent From 6983a71e635ba954f815f64434a30bfbd5d5f2da Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Thu, 14 May 2020 10:07:11 -0700 Subject: [PATCH 320/535] Set up the doc make to be silent if it succeeds for testing purposes. --- doc/makefile | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/doc/makefile b/doc/makefile index 80878d14ea..6f7a3df6aa 100644 --- a/doc/makefile +++ b/doc/makefile @@ -17,7 +17,7 @@ DOXYGEN_CONF = CodeDocumentation.conf # doxygen uses: graphviz, latex html: $(DOXYGEN_CONF) @# Generate the html documentation - doxygen $(DOXYGEN_CONF) + @doxygen $(DOXYGEN_CONF) @rm -f CodeDocumentation.html @ln -s CodeDocumentation/html/index.html CodeDocumentation.html @cat warnings.log @@ -25,14 +25,6 @@ html: $(DOXYGEN_CONF) @# Generate the log of undocumented methods @( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null - @# Display info about the warnings - @pwd - @echo "Warnings excluding undocumented:" - @wc -l < warnings.log - @echo "All warnings:" - @wc -l < undoc.log - - clean: rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~ rm -rf undoc.log warnings.log From 3722c0b1a7782adc1dd7a83926ec1f46647d4dcc Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 14 May 2020 11:21:32 -0700 Subject: [PATCH 321/535] make style --- miniapps/meshing/trimmer.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp index 5dc912d5f8..083563c777 100644 --- a/miniapps/meshing/trimmer.cpp +++ b/miniapps/meshing/trimmer.cpp @@ -59,14 +59,14 @@ int main(int argc, char *argv[]) Array attr; Array bdr_attr; bool visualization = 1; - + OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&attr, "-a", "-attr", "Set of attributes to remove from " "the mesh."); args.AddOption(&bdr_attr, "-b", "-bdr-attr", "Set of boundary attributes " - "to assign to the new boundary elements."); + "to assign to the new boundary elements."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) args.PrintUsage(cout); return 1; } - + Mesh mesh(mesh_file, 0, 0); int max_attr = mesh.attributes.Max(); @@ -84,15 +84,15 @@ int main(int argc, char *argv[]) if (bdr_attr.Size() == 0) { - bdr_attr.SetSize(attr.Size()); - for (int i=0; i marker(max_attr); Array attr_inv(max_attr); marker = 0; @@ -188,13 +188,13 @@ int main(int argc, char *argv[]) if (marker[a1-1] && !marker[a2-1]) { Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); - bel->SetAttribute(bdr_attr[attr_inv[a1-1]]); + bel->SetAttribute(bdr_attr[attr_inv[a1-1]]); trimmed_mesh.AddBdrElement(bel); } else if (!marker[a1-1] && marker[a2-1]) { Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); - bel->SetAttribute(bdr_attr[attr_inv[a2-1]]); + bel->SetAttribute(bdr_attr[attr_inv[a2-1]]); trimmed_mesh.AddBdrElement(bel); } } From 860d2aca1ce08fdabb08187948b02a1eafa49313 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Thu, 14 May 2020 16:32:22 -0700 Subject: [PATCH 322/535] add suport for vector and dense tensor types --- linalg/densemat.cpp | 26 +++++++++++++++++++------- linalg/densemat.hpp | 10 +++++----- linalg/kernels.hpp | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index da33c41f08..caa4ebca20 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3511,9 +3511,10 @@ void BatchLUFactor(Vector &Minv, const int m, const int NE, Array &P) BatchLUFactor_impl(Minv.ReadWrite(), m, NE, P.Write()); } -void BatchLUFactor(DenseTensor &Minv,const int NE, Array &P) +void BatchLUFactor(DenseTensor &Minv, Array &P) { const int m = Minv.SizeI(); + const int NE = Minv.SizeK(); P.SetSize(m*NE); BatchLUFactor_impl(Minv.ReadWrite(), m, NE, P.Write()); } @@ -3585,17 +3586,28 @@ void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) }); MFEM_ASSERT(pivot_flag[0].HostRead(), "Batch LU factorization failed \n"); - } +void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X){ -void BatchLUSolve(Vector &Minv, int m, int NE, - Array &P, Vector &X) + const int m = Minv.SizeI(); + const int NE = Minv.SizeK(); + BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); +} + +void BatchLUSolve(const Vector &Minv, const int m, const int NE, + const Array &P, Vector &X) +{ + BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); +} + +void BatchLUSolve_impl(const double *Minv, const int m, const int NE, + const int *P, double *X) { - auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); - auto piv_all = mfem::Reshape(P.Read(), m, NE); - auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); + auto data_all = mfem::Reshape(Minv, m, m, NE); + auto piv_all = mfem::Reshape(P, m, NE); + auto x_all = mfem::Reshape(X, m, NE); MFEM_FORALL(e, NE, { diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 4e857ccdd1..d563a4bb32 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -861,18 +861,18 @@ public: void BatchLUFactor(Vector &Minv, const int m,const int NE, Array &P); -void BatchLUFactor(DenseTensor &Minv, const int NE, Array &P); +void BatchLUFactor(DenseTensor &Minv, Array &P); void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P); void BatchLUSolve(const Vector &Minv, const int m, const int NE, const Array &P, Vector &X); -void BatchLUSolve(const DenseTensor &Minv, const int NE, - const Array &P, Vector &X); +void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X); + -void BatchLU_impl(const double *Minv, const int m, const int NE, - const int *P, Vector &X); +void BatchLUSolve_impl(const double *Minv, const int m, const int NE, + const int *P, double *X); // Inline methods diff --git a/linalg/kernels.hpp b/linalg/kernels.hpp index bebecdfbad..496b20c6b2 100644 --- a/linalg/kernels.hpp +++ b/linalg/kernels.hpp @@ -1376,6 +1376,44 @@ have_aa: return sqrt(fabs(aa))*mult; // take abs before we sort? } + +MFEM_HOST_DEVICE +inline void LUSolve(const double *data, const int m, int *ipiv, + const double *b, double *x) +{ + for (int t = 0; t < m; ++t) + { + x[t] = b[t]; + } + + // X <- P X + for (int i = 0; i < m; i++) + { + internal::Swap(x[i], x[ipiv[i]]); + } + + // X <- L^{-1} X + for (int j = 0; j < m; j++) + { + const double x_j = x[j]; + for (int i = j + 1; i < m; i++) + { + x[i] -= data[i + j * m] * x_j; + } + } + + // X <- U^{-1} X + for (int j = m - 1; j >= 0; j--) + { + const double x_j = (x[j] /= data[j + j * m]); + for (int i = 0; i < j; i++) + { + x[i] -= data[i + j * m] * x_j; + } + } +} + + } // namespace kernels } // namespace mfem From 7a9b2bb98ad96d3382bdd127d276cfc81de2fa64 Mon Sep 17 00:00:00 2001 From: Vargas Date: Thu, 14 May 2020 16:40:55 -0700 Subject: [PATCH 323/535] make style --- linalg/densemat.cpp | 19 ++++++++++--------- linalg/densemat.hpp | 2 +- linalg/kernels.hpp | 42 +++++++++++++++++++++--------------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index caa4ebca20..5b841fae47 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3524,11 +3524,11 @@ void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) auto data_all = mfem::Reshape(Minv, m, m, NE); auto piv_all = mfem::Reshape(P, m, NE); - Array pivot_flag(1); + Array pivot_flag(1); pivot_flag[0] = true; bool *d_pivot_flag = pivot_flag.ReadWrite(); const double TOL = 1.e-9; - + MFEM_FORALL(e, NE, { @@ -3563,7 +3563,7 @@ void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) if (abs(data[i + i*m]) <= TOL) { - d_pivot_flag[0] = false; + d_pivot_flag[0] = false; } const double a_ii_inv = 1.0 / data[i+i*m]; @@ -3588,20 +3588,21 @@ void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) MFEM_ASSERT(pivot_flag[0].HostRead(), "Batch LU factorization failed \n"); } -void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X){ +void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) +{ - const int m = Minv.SizeI(); - const int NE = Minv.SizeK(); - BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); + const int m = Minv.SizeI(); + const int NE = Minv.SizeK(); + BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); } void BatchLUSolve(const Vector &Minv, const int m, const int NE, const Array &P, Vector &X) { - BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); + BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); } -void BatchLUSolve_impl(const double *Minv, const int m, const int NE, +void BatchLUSolve_impl(const double *Minv, const int m, const int NE, const int *P, double *X) { diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index d563a4bb32..7a7d54e70d 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -869,7 +869,7 @@ void BatchLUSolve(const Vector &Minv, const int m, const int NE, const Array &P, Vector &X); void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X); - + void BatchLUSolve_impl(const double *Minv, const int m, const int NE, const int *P, double *X); diff --git a/linalg/kernels.hpp b/linalg/kernels.hpp index 496b20c6b2..814925aa19 100644 --- a/linalg/kernels.hpp +++ b/linalg/kernels.hpp @@ -1381,36 +1381,36 @@ MFEM_HOST_DEVICE inline void LUSolve(const double *data, const int m, int *ipiv, const double *b, double *x) { - for (int t = 0; t < m; ++t) - { + for (int t = 0; t < m; ++t) + { x[t] = b[t]; - } + } - // X <- P X - for (int i = 0; i < m; i++) - { + // X <- P X + for (int i = 0; i < m; i++) + { internal::Swap(x[i], x[ipiv[i]]); - } + } - // X <- L^{-1} X - for (int j = 0; j < m; j++) - { + // X <- L^{-1} X + for (int j = 0; j < m; j++) + { const double x_j = x[j]; for (int i = j + 1; i < m; i++) - { - x[i] -= data[i + j * m] * x_j; - } - } + { + x[i] -= data[i + j * m] * x_j; + } + } - // X <- U^{-1} X - for (int j = m - 1; j >= 0; j--) - { + // X <- U^{-1} X + for (int j = m - 1; j >= 0; j--) + { const double x_j = (x[j] /= data[j + j * m]); for (int i = 0; i < j; i++) - { - x[i] -= data[i + j * m] * x_j; - } - } + { + x[i] -= data[i + j * m] * x_j; + } + } } From b0350a5999497d08ed5939221d705675042dd222 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Thu, 14 May 2020 18:20:46 -0700 Subject: [PATCH 324/535] pivot flag host read fix --- linalg/densemat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 5b841fae47..b44df91cc3 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3585,7 +3585,7 @@ void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) }); - MFEM_ASSERT(pivot_flag[0].HostRead(), "Batch LU factorization failed \n"); + MFEM_ASSERT(pivot_flag.HostRead()[0], "Batch LU factorization failed \n"); } void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) From f55a46e2e784c31e67b21e02b615e40f39cf0542 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Fri, 15 May 2020 01:37:21 -0400 Subject: [PATCH 325/535] Adds notes about the location of pumi mesh/models --- examples/pumi/ex1.cpp | 7 +++++++ examples/pumi/ex1p.cpp | 8 ++++++++ examples/pumi/ex2.cpp | 8 ++++++++ examples/pumi/ex6p.cpp | 9 ++++++++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/examples/pumi/ex1.cpp b/examples/pumi/ex1.cpp index 95def29a73..c72d5ab5ba 100644 --- a/examples/pumi/ex1.cpp +++ b/examples/pumi/ex1.cpp @@ -32,6 +32,13 @@ // is used for the Finite Element order and "-go" is used for the // geometry order. Note that they can be used independently, i.e. // "-o 8 -go 3" solves for 8th order FE on a third order geometry. +// +// NOTE: Model/Mesh files for this example are in the (large) data file +// repository of MFEM here https://github.com/mfem/data under the +// folder named "pumi", which consists of the following sub-folders: +// a) geom --> model files +// b) parallel --> parallel pumi mesh files +// c) serial --> serial pumi mesh files #include "mfem.hpp" #include diff --git a/examples/pumi/ex1p.cpp b/examples/pumi/ex1p.cpp index c17a9aee8d..acf6b9832f 100644 --- a/examples/pumi/ex1p.cpp +++ b/examples/pumi/ex1p.cpp @@ -36,6 +36,14 @@ // option "-o" is used for the Finite Element order and "-go" for // the geometry order. Note that they can be used independently: // "-o 8 -go 3" solves for 8th order FE on third order geometry. +// +// NOTE: Model/Mesh files for this example are in the (large) data file +// repository of MFEM here https://github.com/mfem/data under the +// folder named "pumi", which consists of the following sub-folders: +// a) geom --> model files +// b) parallel --> parallel pumi mesh files +// c) serial --> serial pumi mesh files + #include "mfem.hpp" #include diff --git a/examples/pumi/ex2.cpp b/examples/pumi/ex2.cpp index f7b54c195d..e294b0e4b9 100644 --- a/examples/pumi/ex2.cpp +++ b/examples/pumi/ex2.cpp @@ -43,6 +43,14 @@ // also illustrated. // // We recommend viewing Example 1 before viewing this example. +// +// NOTE: Model/Mesh files for this example are in the (large) data file +// repository of MFEM here https://github.com/mfem/data under the +// folder named "pumi", which consists of the following sub-folders: +// a) geom --> model files +// b) parallel --> parallel pumi mesh files +// c) serial --> serial pumi mesh files + #include "mfem.hpp" #include diff --git a/examples/pumi/ex6p.cpp b/examples/pumi/ex6p.cpp index 8f73786357..70b6cd9554 100644 --- a/examples/pumi/ex6p.cpp +++ b/examples/pumi/ex6p.cpp @@ -1,7 +1,7 @@ // MFEM Example 6 - Parallel Version // PUMI Modification // -// Compile with: make ex1p +// Compile with: make ex6p // // Sample runs: mpirun -np 8 ex6p // @@ -18,6 +18,13 @@ // is added to modify the "adapt_ratio" which is the fraction of // allowable error that scales the output size field of the error // estimator. +// +// NOTE: Model/Mesh files for this example are in the (large) data file +// repository of MFEM here https://github.com/mfem/data under the +// folder named "pumi", which consists of the following sub-folders: +// a) geom --> model files +// b) parallel --> parallel pumi mesh files +// c) serial --> serial pumi mesh files #include "mfem.hpp" #include From c9d9d0f8ff3ced71f296b47cc5eca5ce2f068b5a Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 15 May 2020 12:33:07 -0700 Subject: [PATCH 326/535] Various tweaks in the template + SIMD code. Make sure the SIMD interinsics can be used when CUDA is enabled. A few tweaks related to adios2 when building with GNU make. --- config/cmake/modules/MfemCmakeUtilities.cmake | 1 + config/config.mk.in | 1 + config/simd.hpp | 57 +++++--- config/simd/auto.hpp | 9 +- config/simd/m128.hpp | 28 ++-- config/simd/m256.hpp | 28 ++-- config/simd/m512.hpp | 28 ++-- config/simd/qpx256.hpp | 28 ++-- config/simd/vsx128.hpp | 28 ++-- fem/adios2datacollection.cpp | 4 +- fem/adios2datacollection.hpp | 5 + fem/tbilinearform.hpp | 11 +- general/adios2stream.cpp | 4 + general/adios2stream.hpp | 4 + general/tassign.hpp | 52 +++++++- linalg/kernels.hpp | 6 +- linalg/tmatrix.hpp | 125 ++++++++++++++++-- linalg/ttensor.hpp | 46 ++++++- makefile | 25 ++-- miniapps/performance/CMakeLists.txt | 10 +- miniapps/performance/makefile | 54 +++++--- 21 files changed, 404 insertions(+), 150 deletions(-) diff --git a/config/cmake/modules/MfemCmakeUtilities.cmake b/config/cmake/modules/MfemCmakeUtilities.cmake index 5f0893d576..850479680f 100644 --- a/config/cmake/modules/MfemCmakeUtilities.cmake +++ b/config/cmake/modules/MfemCmakeUtilities.cmake @@ -743,6 +743,7 @@ function(mfem_export_mk_files) endforeach() # TODO: Add support for MFEM_USE_CUDA=YES set(MFEM_CXX ${CMAKE_CXX_COMPILER}) + set(MFEM_HOST_CXX ${MFEM_CXX}) set(MFEM_CPPFLAGS "") string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}" MFEM_CXXFLAGS) diff --git a/config/config.mk.in b/config/config.mk.in index d2e1b2cf8f..99d0c822b8 100644 --- a/config/config.mk.in +++ b/config/config.mk.in @@ -54,6 +54,7 @@ MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@ # Compiler, compile options, and link options MFEM_CXX = @MFEM_CXX@ +MFEM_HOST_CXX = @MFEM_HOST_CXX@ MFEM_CPPFLAGS = @MFEM_CPPFLAGS@ MFEM_CXXFLAGS = @MFEM_CXXFLAGS@ MFEM_TPLFLAGS = @MFEM_TPLFLAGS@ diff --git a/config/simd.hpp b/config/simd.hpp index c48b69a50f..39b5ced864 100644 --- a/config/simd.hpp +++ b/config/simd.hpp @@ -28,44 +28,69 @@ #endif #endif -// MFEM_SIMD_SIZE is the default SIMD size used by MFEM, see e.g. class -// TBilinearForm and the default traits class AutoImplTraits. -#if defined(_WIN32) -#define MFEM_SIMD_SIZE 8 +// MFEM_SIMD_BYTES is the default SIMD size used by MFEM, see e.g. class +// TBilinearForm and the default traits class AutoSIMDTraits. +// MFEM_ALIGN_BYTES deterimes the padding used in class TVector when its 'align' +// template parameter is set to true -- it ensues that the size of such TVector +// types is a multiple of MFEM_ALIGN_BYTES. MFEM_ALIGN_BYTES must be a multiple +// of MFEM_SIMD_BYTES. +#if !defined(MFEM_USE_SIMD) || defined(_WIN32) +#define MFEM_SIMD_BYTES 8 +#define MFEM_ALIGN_BYTES 32 #elif defined(__AVX512F__) -#define MFEM_SIMD_SIZE 64 +#define MFEM_SIMD_BYTES 64 +#define MFEM_ALIGN_BYTES 64 #elif defined(__AVX__) || defined(__VECTOR4DOUBLE__) -#define MFEM_SIMD_SIZE 32 +#define MFEM_SIMD_BYTES 32 +#define MFEM_ALIGN_BYTES 32 #elif defined(__SSE2__) || defined(__VSX__) -#define MFEM_SIMD_SIZE 16 +#define MFEM_SIMD_BYTES 16 +#define MFEM_ALIGN_BYTES 32 #else -#define MFEM_SIMD_SIZE 8 +#define MFEM_SIMD_BYTES 8 +#define MFEM_ALIGN_BYTES 32 #endif // derived macros #define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base)) #define MFEM_ALIGN_SIZE(size,type) \ - MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type)) + MFEM_ROUNDUP(size,(MFEM_ALIGN_BYTES)/sizeof(type)) namespace mfem { template -struct AutoImplTraits +struct AutoSIMDTraits { static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; - static const int align_size = MFEM_SIMD_SIZE; // in bytes + // Alignment for arrays of vcomplex_t and vreal_t + static const int align_bytes = MFEM_SIMD_BYTES; static const int batch_size = 1; - static const int simd_size = MFEM_SIMD_SIZE/sizeof(complex_t); + static const int simd_size = MFEM_SIMD_BYTES/sizeof(real_t); - static const int valign_size = simd_size; + typedef AutoSIMD vcomplex_t; + typedef AutoSIMD vreal_t; + typedef AutoSIMD vint_t; +}; - typedef AutoSIMD vcomplex_t; - typedef AutoSIMD vreal_t; - typedef AutoSIMD vint_t; +template +struct NoSIMDTraits +{ + static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE; + + // Alignment for arrays of vcomplex_t and vreal_t + static const int align_bytes = sizeof(real_t); + + static const int batch_size = 1; + + static const int simd_size = 1; + + typedef AutoSIMD vcomplex_t; + typedef AutoSIMD vreal_t; + typedef AutoSIMD vint_t; }; } // mfem namespace diff --git a/config/simd/auto.hpp b/config/simd/auto.hpp index 0c452f9dad..9b1e094b53 100644 --- a/config/simd/auto.hpp +++ b/config/simd/auto.hpp @@ -17,12 +17,15 @@ namespace mfem { -template -struct alignas(align_S*sizeof(scalar_t)) AutoSIMD +// Use this macro as a workaround for astyle formatting issue with 'alignas' +#define MFEM_AUTOSIMD_ALIGN__ alignas(align_bytes_) + +template +struct MFEM_AUTOSIMD_ALIGN__ AutoSIMD { typedef scalar_t scalar_type; static const int size = S; - static const int align_size = align_S; + static const int align_bytes = align_bytes_; scalar_t vec[size]; diff --git a/config/simd/m128.hpp b/config/simd/m128.hpp index 9f8db7ade3..800bc6f31d 100644 --- a/config/simd/m128.hpp +++ b/config/simd/m128.hpp @@ -22,11 +22,11 @@ namespace mfem template struct AutoSIMD; -template <> struct AutoSIMD +template <> struct AutoSIMD { typedef double scalar_type; static constexpr int size = 2; - static constexpr int align_size = 2; + static constexpr int align_bytes = 16; union { @@ -207,37 +207,37 @@ template <> struct AutoSIMD }; inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_add_pd(_mm_set1_pd(e),v.m128d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_sub_pd(_mm_set1_pd(e),v.m128d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m128d = _mm_div_pd(_mm_set1_pd(e),v.m128d); return r; } diff --git a/config/simd/m256.hpp b/config/simd/m256.hpp index 9e510388fc..4106bc5236 100644 --- a/config/simd/m256.hpp +++ b/config/simd/m256.hpp @@ -22,11 +22,11 @@ namespace mfem template struct AutoSIMD; -template <> struct AutoSIMD +template <> struct AutoSIMD { typedef double scalar_type; static constexpr int size = 4; - static constexpr int align_size = 4; + static constexpr int align_bytes = 32; union { @@ -217,37 +217,37 @@ template <> struct AutoSIMD }; inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_add_pd(_mm256_set1_pd(e),v.m256d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_sub_pd(_mm256_set1_pd(e),v.m256d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_mul_pd(_mm256_set1_pd(e),v.m256d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m256d = _mm256_div_pd(_mm256_set1_pd(e),v.m256d); return r; } diff --git a/config/simd/m512.hpp b/config/simd/m512.hpp index 75096bed00..3041950cb6 100644 --- a/config/simd/m512.hpp +++ b/config/simd/m512.hpp @@ -22,11 +22,11 @@ namespace mfem template struct AutoSIMD; -template <> struct AutoSIMD +template <> struct AutoSIMD { typedef double scalar_type; static constexpr int size = 8; - static constexpr int align_size = 8; + static constexpr int align_bytes = 64; union { @@ -205,37 +205,37 @@ template <> struct AutoSIMD }; inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_add_pd(_mm512_set1_pd(e),v.m512d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_sub_pd(_mm512_set1_pd(e),v.m512d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_mul_pd(_mm512_set1_pd(e),v.m512d); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.m512d = _mm512_div_pd(_mm512_set1_pd(e),v.m512d); return r; } diff --git a/config/simd/qpx256.hpp b/config/simd/qpx256.hpp index 67c1c52d2c..0a848a658e 100644 --- a/config/simd/qpx256.hpp +++ b/config/simd/qpx256.hpp @@ -22,11 +22,11 @@ namespace mfem template struct AutoSIMD; -template <> struct AutoSIMD +template <> struct AutoSIMD { typedef double scalar_type; static constexpr int size = 4; - static constexpr int align_size = 4; + static constexpr int align_bytes = 32; union { @@ -199,37 +199,37 @@ template <> struct AutoSIMD }; inline __ATTRS_ai -AutoSIMD operator+(const double &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_add(vec_splats(e),v.vd); return r; } inline __ATTRS_ai -AutoSIMD operator-(const double &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_sub(vec_splats(e),v.vd); return r; } inline __ATTRS_ai -AutoSIMD operator*(const double &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_mul(vec_splats(e),v.vd); return r; } inline __ATTRS_ai -AutoSIMD operator/(const double &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_swdiv(vec_splats(e),v.vd); return r; } diff --git a/config/simd/vsx128.hpp b/config/simd/vsx128.hpp index 1010fac762..6bce826a46 100644 --- a/config/simd/vsx128.hpp +++ b/config/simd/vsx128.hpp @@ -22,11 +22,11 @@ namespace mfem template struct AutoSIMD; -template <> struct AutoSIMD +template <> struct AutoSIMD { typedef double scalar_type; static constexpr int size = 2; - static constexpr int align_size = 2; + static constexpr int align_bytes = 16; union { @@ -205,37 +205,37 @@ template <> struct AutoSIMD }; inline MFEM_ALWAYS_INLINE -AutoSIMD operator+(const double &e, - const AutoSIMD &v) +AutoSIMD operator+(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_add(vec_splats(e),v.vd); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator-(const double &e, - const AutoSIMD &v) +AutoSIMD operator-(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_sub(vec_splats(e),v.vd); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator*(const double &e, - const AutoSIMD &v) +AutoSIMD operator*(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_mul(vec_splats(e),v.vd); return r; } inline MFEM_ALWAYS_INLINE -AutoSIMD operator/(const double &e, - const AutoSIMD &v) +AutoSIMD operator/(const double &e, + const AutoSIMD &v) { - AutoSIMD r; + AutoSIMD r; r.vd = vec_div(vec_splats(e),v.vd); return r; } diff --git a/fem/adios2datacollection.cpp b/fem/adios2datacollection.cpp index 8c2c8e6425..51703c01cc 100644 --- a/fem/adios2datacollection.cpp +++ b/fem/adios2datacollection.cpp @@ -15,6 +15,8 @@ #include "adios2datacollection.hpp" +#ifdef MFEM_USE_ADIOS2 + namespace mfem { @@ -87,4 +89,4 @@ noexcept } //end namespace mfem - +#endif // MFEM_USE_ADIOS2 diff --git a/fem/adios2datacollection.hpp b/fem/adios2datacollection.hpp index c611f73675..dd05b4c478 100644 --- a/fem/adios2datacollection.hpp +++ b/fem/adios2datacollection.hpp @@ -17,6 +17,9 @@ #define MFEM_ADIOS2DATACOLLECTION #include "../config/config.hpp" + +#ifdef MFEM_USE_ADIOS2 + #include "../general/adios2stream.hpp" #include "datacollection.hpp" @@ -85,4 +88,6 @@ private: } // namespace mfem +#endif // MFEM_USE_ADIOS2 + #endif /* MFEM_ADIOS2DATACOLLECTION */ diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index e493d38423..25a749845b 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -32,7 +32,7 @@ template > + typename impl_traits_t = AutoSIMDTraits > class TBilinearForm : public Operator { public: @@ -53,6 +53,7 @@ protected: static const int dofs = solFE_type::dofs; static const int vdim = solVecLayout_t::vec_dim; static const int qpts = IR::qpts; + static const int AB = impl_traits_t::align_bytes; static const int SS = impl_traits_t::simd_size; static const int BE = impl_traits_t::batch_size; static const int TE = SS*BE; @@ -118,8 +119,8 @@ public: assembled_data(), in_fes(sol_fes) { - assembled_data.Reset(SS == 64 ? MemoryType::HOST_64 : - SS == 32 ? MemoryType::HOST_32 : + assembled_data.Reset(AB == 64 ? MemoryType::HOST_64 : + AB == 32 ? MemoryType::HOST_32 : MemoryType::HOST); } @@ -200,7 +201,7 @@ public: if (assembled_data.Empty()) { const int size = ((NE+TE-1)/TE)*BE; - assembled_data = Memory(size, MemoryType::HOST_32); + assembled_data.New(size, assembled_data.GetMemoryType()); } for (int el = 0; el < NE; el += TE) { @@ -301,7 +302,7 @@ public: if (assembled_data.Empty()) { const int size = ((NE+TE-1)/TE)*BE; - assembled_data = Memory(size, MemoryType::HOST_32); + assembled_data.New(size, assembled_data.GetMemoryType()); } const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData()); for (int el = 0; el < NE; el += TE) diff --git a/general/adios2stream.cpp b/general/adios2stream.cpp index 0fa79a78b2..59d88cb06b 100644 --- a/general/adios2stream.cpp +++ b/general/adios2stream.cpp @@ -15,6 +15,8 @@ #include "adios2stream.hpp" +#ifdef MFEM_USE_ADIOS2 + #include "../fem/geom.hpp" #include "../general/array.hpp" #include "../mesh/element.hpp" @@ -750,3 +752,5 @@ noexcept } } // end namespace mfem + +#endif // MFEM_USE_ADIOS2 diff --git a/general/adios2stream.hpp b/general/adios2stream.hpp index 78ad7d793a..2c483b0b7a 100644 --- a/general/adios2stream.hpp +++ b/general/adios2stream.hpp @@ -18,6 +18,8 @@ #include "../config/config.hpp" +#ifdef MFEM_USE_ADIOS2 + #include #include // std::unique_ptr #include @@ -230,4 +232,6 @@ private: } // end namespace mfem +#endif // MFEM_USE_ADIOS2 + #endif /* MFEM_ADIOS2STREAM */ diff --git a/general/tassign.hpp b/general/tassign.hpp index c72482b21c..7018a203b2 100644 --- a/general/tassign.hpp +++ b/general/tassign.hpp @@ -43,70 +43,110 @@ template <> struct AssignOp_Impl { template - MFEM_HOST_DEVICE static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b) { return (a = b); } + + template + MFEM_HOST_DEVICE + static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b) + { + return (a = b); + } }; template <> struct AssignOp_Impl { template - MFEM_HOST_DEVICE static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b) { MFEM_FLOPS_ADD(1); return (a += b); } + + template + MFEM_HOST_DEVICE + static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b) + { + MFEM_FLOPS_ADD(1); + return (a += b); + } }; template <> struct AssignOp_Impl { template - MFEM_HOST_DEVICE static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b) { MFEM_FLOPS_ADD(1); return (a *= b); } + + template + MFEM_HOST_DEVICE + static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b) + { + MFEM_FLOPS_ADD(1); + return (a *= b); + } }; template <> struct AssignOp_Impl { template - MFEM_HOST_DEVICE static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b) { MFEM_FLOPS_ADD(1); return (a /= b); } + + template + MFEM_HOST_DEVICE + static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b) + { + MFEM_FLOPS_ADD(1); + return (a /= b); + } }; template <> struct AssignOp_Impl { template - MFEM_HOST_DEVICE static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b) { MFEM_FLOPS_ADD(1); return (a = b/a); } + + template + MFEM_HOST_DEVICE + static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b) + { + MFEM_FLOPS_ADD(1); + return (a = b/a); + } }; } // namespace mfem::internal template -MFEM_HOST_DEVICE inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b) { return internal::AssignOp_Impl::Assign(a, b); } +template +MFEM_HOST_DEVICE +inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b) +{ + return internal::AssignOp_Impl::AssignHD(a, b); +} + } // namespace mfem #endif // MFEM_TEMPLATE_ASSIGN diff --git a/linalg/kernels.hpp b/linalg/kernels.hpp index bebecdfbad..e2e18a46a0 100644 --- a/linalg/kernels.hpp +++ b/linalg/kernels.hpp @@ -120,7 +120,7 @@ void Symmetrize(const int size, T *data) template MFEM_HOST_DEVICE inline T Det(const T *data) { - return TDet(ColumnMajorLayout2D(), data); + return TDetHD(ColumnMajorLayout2D(), data); } /** @brief Return the inverse a matrix with given @a size and @a data into the @@ -130,8 +130,8 @@ MFEM_HOST_DEVICE inline void CalcInverse(const T *data, T *inv_data) { typedef ColumnMajorLayout2D layout_t; - const T det = TAdjDet(layout_t(), data, layout_t(), inv_data); - TAssign(layout_t(), inv_data, static_cast(1.0)/det); + const T det = TAdjDetHD(layout_t(), data, layout_t(), inv_data); + TAssignHD(layout_t(), inv_data, static_cast(1.0)/det); } /** @brief Compute C = A + alpha*B, where the matrices A, B and C are of size @a diff --git a/linalg/tmatrix.hpp b/linalg/tmatrix.hpp index 57a5ab589e..ca34453d1f 100644 --- a/linalg/tmatrix.hpp +++ b/linalg/tmatrix.hpp @@ -281,7 +281,6 @@ struct MatrixOps<1,1> template - MFEM_HOST_DEVICE static inline scalar_t AdjDet(const A_layout_t &a, const A_data_t &A, const B_layout_t &b, B_data_t &B) { @@ -295,7 +294,6 @@ struct MatrixOps<2,2> { // Compute det(A). template - MFEM_HOST_DEVICE static inline scalar_t Det(const layout_t &a, const data_t &A) { MFEM_FLOPS_ADD(3); @@ -303,6 +301,16 @@ struct MatrixOps<2,2> A[a.ind(1,0)]*A[a.ind(0,1)]); } + // Compute det(A), host+device version. + template + MFEM_HOST_DEVICE + static inline scalar_t DetHD(const layout_t &a, const data_t &A) + { + MFEM_FLOPS_ADD(3); + return (A[a.ind(0,0)]*A[a.ind(1,1)] - + A[a.ind(1,0)]*A[a.ind(0,1)]); + } + // Compute det(A). Batched version: D[i] {=,+=,*=} det(A[i,*,*]) template @@ -321,7 +329,6 @@ struct MatrixOps<2,2> template - MFEM_HOST_DEVICE static inline void Adjugate(const A_layout_t &a, const A_data_t &A, const B_layout_t &b, B_data_t &B) { @@ -331,11 +338,24 @@ struct MatrixOps<2,2> B[b.ind(1,1)] = A[a.ind(0,0)]; } + // Compute B = adj(A), host+device version. + template + MFEM_HOST_DEVICE + static inline void AdjugateHD(const A_layout_t &a, const A_data_t &A, + const B_layout_t &b, B_data_t &B) + { + B[b.ind(0,0)] = A[a.ind(1,1)]; + B[b.ind(0,1)] = -A[a.ind(0,1)]; + B[b.ind(1,0)] = -A[a.ind(1,0)]; + B[b.ind(1,1)] = A[a.ind(0,0)]; + } + // Compute adj(A) and det(A). template - MFEM_HOST_DEVICE static inline scalar_t AdjDet(const A_layout_t &a, const A_data_t &A, const B_layout_t &b, B_data_t &B) { @@ -343,6 +363,18 @@ struct MatrixOps<2,2> return Det(a, A); } + // Compute adj(A) and det(A), host+device version. + template + MFEM_HOST_DEVICE + static inline scalar_t AdjDetHD(const A_layout_t &a, const A_data_t &A, + const B_layout_t &b, B_data_t &B) + { + AdjugateHD(a, A, b, B); + return DetHD(a, A); + } + template struct Symm; }; @@ -380,7 +412,6 @@ struct MatrixOps<3,3> { // Compute det(A). template - MFEM_HOST_DEVICE static inline scalar_t Det(const layout_t &a, const data_t &A) { MFEM_FLOPS_ADD(14); @@ -392,6 +423,20 @@ struct MatrixOps<3,3> A[a.ind(1,1)]*A[a.ind(0,2)])); } + // Compute det(A), host+device version. + template + MFEM_HOST_DEVICE + static inline scalar_t DetHD(const layout_t &a, const data_t &A) + { + MFEM_FLOPS_ADD(14); + return (A[a.ind(0,0)]*(A[a.ind(1,1)]*A[a.ind(2,2)] - + A[a.ind(2,1)]*A[a.ind(1,2)]) - + A[a.ind(1,0)]*(A[a.ind(0,1)]*A[a.ind(2,2)] - + A[a.ind(2,1)]*A[a.ind(0,2)]) + + A[a.ind(2,0)]*(A[a.ind(0,1)]*A[a.ind(1,2)] - + A[a.ind(1,1)]*A[a.ind(0,2)])); + } + // Compute det(A). Batched version: D[i] {=,+=,*=} det(A[i,*,*]) template @@ -416,7 +461,6 @@ struct MatrixOps<3,3> template - MFEM_HOST_DEVICE static inline void Adjugate(const A_layout_t &a, const A_data_t &A, const B_layout_t &b, B_data_t &B) { @@ -432,11 +476,30 @@ struct MatrixOps<3,3> B[b.ind(2,2)] = A[a.ind(0,0)]*A[a.ind(1,1)] - A[a.ind(0,1)]*A[a.ind(1,0)]; } + // Compute B = adj(A), host+device version. + template + MFEM_HOST_DEVICE + static inline void AdjugateHD(const A_layout_t &a, const A_data_t &A, + const B_layout_t &b, B_data_t &B) + { + MFEM_FLOPS_ADD(27); + B[b.ind(0,0)] = A[a.ind(1,1)]*A[a.ind(2,2)] - A[a.ind(1,2)]*A[a.ind(2,1)]; + B[b.ind(0,1)] = A[a.ind(0,2)]*A[a.ind(2,1)] - A[a.ind(0,1)]*A[a.ind(2,2)]; + B[b.ind(0,2)] = A[a.ind(0,1)]*A[a.ind(1,2)] - A[a.ind(0,2)]*A[a.ind(1,1)]; + B[b.ind(1,0)] = A[a.ind(1,2)]*A[a.ind(2,0)] - A[a.ind(1,0)]*A[a.ind(2,2)]; + B[b.ind(1,1)] = A[a.ind(0,0)]*A[a.ind(2,2)] - A[a.ind(0,2)]*A[a.ind(2,0)]; + B[b.ind(1,2)] = A[a.ind(0,2)]*A[a.ind(1,0)] - A[a.ind(0,0)]*A[a.ind(1,2)]; + B[b.ind(2,0)] = A[a.ind(1,0)]*A[a.ind(2,1)] - A[a.ind(1,1)]*A[a.ind(2,0)]; + B[b.ind(2,1)] = A[a.ind(0,1)]*A[a.ind(2,0)] - A[a.ind(0,0)]*A[a.ind(2,1)]; + B[b.ind(2,2)] = A[a.ind(0,0)]*A[a.ind(1,1)] - A[a.ind(0,1)]*A[a.ind(1,0)]; + } + // Compute adj(A) and det(A). template - MFEM_HOST_DEVICE static inline scalar_t AdjDet(const A_layout_t &a, const A_data_t &A, const B_layout_t &b, B_data_t &B) { @@ -447,6 +510,21 @@ struct MatrixOps<3,3> A[a.ind(2,0)]*B[b.ind(0,2)]); } + // Compute adj(A) and det(A), host+device version. + template + MFEM_HOST_DEVICE + static inline scalar_t AdjDetHD(const A_layout_t &a, const A_data_t &A, + const B_layout_t &b, B_data_t &B) + { + MFEM_FLOPS_ADD(5); + AdjugateHD(a, A, b, B); + return (A[a.ind(0,0)]*B[b.ind(0,0)] + + A[a.ind(1,0)]*B[b.ind(0,1)] + + A[a.ind(2,0)]*B[b.ind(0,2)]); + } + template struct Symm; }; @@ -493,7 +571,6 @@ struct MatrixOps<3,3>::Symm // Compute the determinant of a (small) matrix: det(A). template -MFEM_HOST_DEVICE inline scalar_t TDet(const layout_t &a, const data_t &A) { MFEM_STATIC_ASSERT(layout_t::rank == 2, "invalid rank"); @@ -506,11 +583,25 @@ inline scalar_t TDet(const layout_t &a, const data_t &A) #endif } +// Compute the determinant of a (small) matrix: det(A). Host+device version. +template +MFEM_HOST_DEVICE +inline scalar_t TDetHD(const layout_t &a, const data_t &A) +{ + MFEM_STATIC_ASSERT(layout_t::rank == 2, "invalid rank"); +#if !defined(__xlC__) || (__xlC__ >= 0x0d00) + return internal::MatrixOps:: + template DetHD(a, A); +#else + return internal::MatrixOps:: + DetHD(a, A); +#endif +} + // Compute the determinants of a set of (small) matrices: D[i] = det(A[i,*,*]). // The layout of A is (M x N1 x N2) and the size of D is M. template -MFEM_HOST_DEVICE inline void TDet(const A_layout_t &a, const A_data_t &A, D_data_t &D) { MFEM_STATIC_ASSERT(A_layout_t::rank == 3, "invalid rank"); @@ -541,7 +632,6 @@ inline void TAdjugate(const A_layout_t &a, const A_data_t &A, template -MFEM_HOST_DEVICE inline scalar_t TAdjDet(const A_layout_t &a, const A_data_t &A, const B_layout_t &b, B_data_t &B) { @@ -551,6 +641,21 @@ inline scalar_t TAdjDet(const A_layout_t &a, const A_data_t &A, template AdjDet(a, A, b, B); } +// Compute the adjugate and the determinant of a (small) matrix: B = adj(A), +// return det(A). Host+device version. +template +MFEM_HOST_DEVICE +inline scalar_t TAdjDetHD(const A_layout_t &a, const A_data_t &A, + const B_layout_t &b, B_data_t &B) +{ + MFEM_STATIC_ASSERT(A_layout_t::rank == 2 && B_layout_t::rank == 2, + "invalid ranks"); + return internal::MatrixOps:: + template AdjDetHD(a, A, b, B); +} + } // namespace mfem #endif // MFEM_TEMPLATE_MATRIX diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index c06b162af3..a89f582586 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -39,7 +39,6 @@ struct TensorOps<1> // rank = 1 // Assign: A {=,+=,*=} scalar_value template - MFEM_HOST_DEVICE static void Assign(const A_layout_t &A_layout, A_data_t &A_data, const scalar_t value) { @@ -50,6 +49,20 @@ struct TensorOps<1> // rank = 1 } } + // Assign: A {=,+=,*=} scalar_value, host+device version + template + MFEM_HOST_DEVICE + static void AssignHD(const A_layout_t &A_layout, A_data_t &A_data, + const scalar_t value) + { + MFEM_STATIC_ASSERT(A_layout_t::rank == 1, "invalid rank"); + for (int i1 = 0; i1 < A_layout_t::dim_1; i1++) + { + mfem::AssignHD(A_data[A_layout.ind(i1)], value); + } + } + // Assign: A {=,+=,*=} B template // rank = 2 // Assign: A {=,+=,*=} scalar_value template - MFEM_HOST_DEVICE static void Assign(const A_layout_t &A_layout, A_data_t &A_data, scalar_t value) { @@ -88,6 +100,23 @@ struct TensorOps<2> // rank = 2 } } + // Assign: A {=,+=,*=} scalar_value, host+device version + template + MFEM_HOST_DEVICE + static void AssignHD(const A_layout_t &A_layout, A_data_t &A_data, + scalar_t value) + { + MFEM_STATIC_ASSERT(A_layout_t::rank == 2, "invalid rank"); + for (int i2 = 0; i2 < A_layout_t::dim_2; i2++) + { + for (int i1 = 0; i1 < A_layout_t::dim_1; i1++) + { + mfem::AssignHD(A_data[A_layout.ind(i1,i2)], value); + } + } + } + // Assign: A {=,+=,*=} B template // rank = 4 // Tensor or sub-tensor assign function: A {=,+=,*=} scalar_value. template -MFEM_HOST_DEVICE inline void TAssign(const A_layout_t &A_layout, A_data_t &A_data, const scalar_t value) { @@ -229,6 +257,18 @@ inline void TAssign(const A_layout_t &A_layout, A_data_t &A_data, template Assign(A_layout, A_data, value); } +// Tensor or sub-tensor assign function: A {=,+=,*=} scalar_value. +// Host+device version. +template +MFEM_HOST_DEVICE +inline void TAssignHD(const A_layout_t &A_layout, A_data_t &A_data, + const scalar_t value) +{ + internal::TensorOps:: + template AssignHD(A_layout, A_data, value); +} + // Tensor assign function: A {=,+=,*=} B that allows different input and output // layouts. With suitable layouts this function can be used to permute // (transpose) tensors, extract sub-tensors, etc. diff --git a/makefile b/makefile index 25da0f07ca..f67b723136 100644 --- a/makefile +++ b/makefile @@ -203,28 +203,27 @@ CXXFLAGS ?= $(OPTIM_FLAGS) # MPI configuration ifneq ($(MFEM_USE_MPI),YES) - CXX_OR_MPICXX = $(CXX) + MFEM_HOST_CXX = $(CXX) PKGS_NEED_MPI = SUPERLU STRUMPACK PETSC PUMI $(foreach mpidep,$(PKGS_NEED_MPI),$(if $(MFEM_USE_$(mpidep):NO=),\ $(warning *** [MPI is OFF] setting MFEM_USE_$(mpidep) = NO)\ $(eval override MFEM_USE_$(mpidep)=NO),)) else - CXX_OR_MPICXX = $(MPICXX) + MFEM_HOST_CXX = $(MPICXX) INCFLAGS += $(HYPRE_OPT) ALL_LIBS += $(HYPRE_LIB) endif -ALL_LIBS += $(GSLIB_FPT_LIB) # Default configuration ifeq ($(MFEM_USE_CUDA)$(MFEM_USE_HIP),NONO) - MFEM_CXX ?= $(CXX_OR_MPICXX) + MFEM_CXX ?= $(MFEM_HOST_CXX) XCOMPILER = $(CXX_XCOMPILER) XLINKER = $(CXX_XLINKER) endif ifeq ($(MFEM_USE_CUDA),YES) MFEM_CXX ?= $(CUDA_CXX) - CXXFLAGS += $(CUDA_FLAGS) -ccbin $(CXX_OR_MPICXX) + CXXFLAGS += $(CUDA_FLAGS) -ccbin $(MFEM_HOST_CXX) XCOMPILER = $(CUDA_XCOMPILER) XLINKER = $(CUDA_XLINKER) # CUDA_OPT and CUDA_LIB are added below @@ -238,6 +237,7 @@ endif ifeq ($(MFEM_USE_HIP),YES) MFEM_CXX ?= $(HIP_CXX) ALL_LIBS += $(HIP_FLAGS) + # TODO: set XCOMPILER and XLINKER # HIP_OPT and HIP_LIB are added below # Compatibility test against MFEM_USE_CUDA ifeq ($(MFEM_USE_CUDA),YES) @@ -326,10 +326,11 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\ MFEM_USE_ADIOS2 MFEM_SOURCE_DIR MFEM_INSTALL_DIR # List of makefile variables that will be written to config.mk: -MFEM_CONFIG_VARS = MFEM_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS MFEM_INC_DIR\ - MFEM_TPLFLAGS MFEM_INCFLAGS MFEM_PICFLAG MFEM_FLAGS MFEM_LIB_DIR MFEM_EXT_LIBS\ - MFEM_LIBS MFEM_LIB_FILE MFEM_STATIC MFEM_SHARED MFEM_BUILD_TAG MFEM_PREFIX\ - MFEM_CONFIG_EXTRA MFEM_MPIEXEC MFEM_MPIEXEC_NP MFEM_MPI_NP MFEM_TEST_MK +MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\ + MFEM_INC_DIR MFEM_TPLFLAGS MFEM_INCFLAGS MFEM_PICFLAG MFEM_FLAGS MFEM_LIB_DIR\ + MFEM_EXT_LIBS MFEM_LIBS MFEM_LIB_FILE MFEM_STATIC MFEM_SHARED MFEM_BUILD_TAG\ + MFEM_PREFIX MFEM_CONFIG_EXTRA MFEM_MPIEXEC MFEM_MPIEXEC_NP MFEM_MPI_NP\ + MFEM_TEST_MK # Config vars: values of the form @VAL@ are replaced by $(VAL) in config.mk MFEM_CPPFLAGS ?= $(CPPFLAGS) @@ -390,11 +391,8 @@ ifneq (,$(filter install,$(MAKECMDGOALS))) endif # Source dirs in logical order -DIRS = general linalg mesh fem fem/libceed +DIRS = general linalg config/simd mesh fem fem/libceed SOURCE_FILES = $(foreach dir,$(DIRS),$(wildcard $(SRC)$(dir)/*.cpp)) -ADIOS2_FILES = $(SRC)general/adios2stream.h $(SRC)general/adios2stream.cpp \ - $(SRC)fem/adios2datacollection.hpp $(SRC)fem/adios2datacollection.cpp -SOURCE_FILES := $(filter-out $(ADIOS2_FILES),$(SOURCE_FILES)) RELSRC_FILES = $(patsubst $(SRC)%,%,$(SOURCE_FILES)) OBJECT_FILES = $(patsubst $(SRC)%,$(BLD)%,$(SOURCE_FILES:.cpp=.o)) OKL_DIRS = fem @@ -647,6 +645,7 @@ status info: $(info MFEM_USE_SIMD = $(MFEM_USE_SIMD)) $(info MFEM_USE_ADIOS2 = $(MFEM_USE_ADIOS2)) $(info MFEM_CXX = $(value MFEM_CXX)) + $(info MFEM_HOST_CXX = $(value MFEM_HOST_CXX)) $(info MFEM_CPPFLAGS = $(value MFEM_CPPFLAGS)) $(info MFEM_CXXFLAGS = $(value MFEM_CXXFLAGS)) $(info MFEM_TPLFLAGS = $(value MFEM_TPLFLAGS)) diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 5494256400..375e6874c5 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -18,9 +18,7 @@ endif() set(PERFORMANCE_CXX_OPTIONS) if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") list(APPEND PERFORMANCE_CXX_OPTIONS - ${MFEM_PERF_CXX_ARCH_FLAGS} - "-Wpedantic" - "-Wall" + "-march=native" "-fcolor-diagnostics" "-fvectorize" "-fslp-vectorize" @@ -28,11 +26,13 @@ if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") list(APPEND PERFORMANCE_CXX_OPTIONS ${MFEM_PERF_CXX_ARCH_FLAGS} - "-Wall" - "--param" "max-completely-peel-times=3") + "-Wall") if (NOT MFEM_USE_CUDA) list(APPEND PERFORMANCE_CXX_OPTIONS "-pedantic") endif() + if (NOT MFEM_USE_SIMD) + list(APPEND PERFORMANCE_CXX_OPTIONS "--param" "max-completely-peel-times=3") + endif() elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel") list(APPEND PERFORMANCE_CXX_OPTIONS "-xHost") endif() diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 7713a8d88f..23d4b6b40c 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -24,31 +24,50 @@ MFEM_LIB_FILE = mfem_is_not_built # Distinguish x86 from PowerPC systems MFEM_MACHINE ?= $(shell uname -m) -# Choose the switch MFEM_PERF_SW: gcc_x86_64, gcc_ppc64, clang, or icc. +# Choose the switch MFEM_PERF_SW: gcc_x86_64, gcc_ppc64, clang, etc. # The value of MFEM_PERF_SW is used to select MFEM_PERF_CXXFLAGS below. -ifneq (,$(MFEM_PERF_SW)) - # Use the value of MFEM_PERF_SW if already defined -else ifneq (,$(filter %clang++ %mpiclang++,$(MFEM_CXX))) - MFEM_PERF_SW = clang -else ifneq (,$(filter %g++ %mpicxx %mpic++,$(MFEM_CXX))) +define cxx_detect +cxx_v="$$($(MFEM_HOST_CXX) --version -c 2>&1)"; +if [ 0 -ne $$? ]; then + cxx_id="unknown"; +elif [ -z "$${cxx_v##g++*}" ]; then + cxx_id="gcc"; +elif [ -z "$${cxx_v##*clang version*}" ]; then + cxx_id="clang"; +elif [ -z "$${cxx_v##*icpc*}" ]; then + cxx_id="icc"; +elif [ -z "$${cxx_v##*IBM XL*}" ]; then + cxx_id="xlc"; +elif [ -z "$${cxx_v##*pgc++*}" ]; then + cxx_id="pgi"; +else + cxx_id="unknown"; +fi; +printf "%s" "$$cxx_id" +endef +ifneq (,$(MFEM_HOST_CXX)) + MFEM_PERF_SW := $(shell $(cxx_detect)) + # $(info Detected host compiler: $(MFEM_PERF_SW)) +endif +ifeq (gcc,$(MFEM_PERF_SW)) ifeq ($(MFEM_MACHINE),x86_64) MFEM_PERF_SW = gcc_x86_64 else ifneq (,$(findstring ppc64,$(MFEM_MACHINE))) MFEM_PERF_SW = gcc_ppc64 endif -else ifneq (,$(filter %icpc %mpiicpc,$(MFEM_CXX))) - MFEM_PERF_SW = icc -else ifneq (,$(filter %xlc++ %mpixlC,$(MFEM_CXX))) - MFEM_PERF_SW = xlc endif # Compiler specific optimizations. # For best performance, GCC 5 (or newer) is recommended. +ifneq (YES,$(MFEM_USE_CUDA)) + PEDANTIC_FLAG = -pedantic +endif + # - GCC extra options: -MFEM_PERF_CXXFLAGS_gcc_common += -pedantic -Wall +MFEM_PERF_CXXFLAGS_gcc_common += $(PEDANTIC_FLAG) -Wall ifeq ($(MFEM_USE_SIMD),NO) -MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 + MFEM_PERF_CXXFLAGS_gcc_common += --param max-completely-peel-times=3 endif #MFEM_PERF_CXXFLAGS_gcc_common += -fdump-tree-optimized-blocks MFEM_PERF_CXXFLAGS_gcc_x86_64 = -march=native $(MFEM_PERF_CXXFLAGS_gcc_common) @@ -60,8 +79,7 @@ MFEM_PERF_CXXFLAGS_xlc = -mcpu=native # - Clang extra options: MFEM_PERF_CXXFLAGS_clang += -march=native -# MFEM_PERF_CXXFLAGS_clang += -std=c++03 -MFEM_PERF_CXXFLAGS_clang += -pedantic -Wall +MFEM_PERF_CXXFLAGS_clang += $(PEDANTIC_FLAG) -Wall MFEM_PERF_CXXFLAGS_clang += -fcolor-diagnostics MFEM_PERF_CXXFLAGS_clang += -fvectorize MFEM_PERF_CXXFLAGS_clang += -fslp-vectorize @@ -73,7 +91,13 @@ MFEM_PERF_CXXFLAGS_icc += -xHost # Choose MFEM_PERF_CXXFLAGS based on MFEM_PERF_SW: MFEM_PERF_CXXFLAGS = $(MFEM_PERF_CXXFLAGS_$(MFEM_PERF_SW)) # Add MFEM_PERF_CXXFLAGS to MFEM_CXXFLAGS: -MFEM_CXXFLAGS += $(MFEM_PERF_CXXFLAGS) +ifeq (YES,$(MFEM_USE_CUDA)) + ifneq (,$(MFEM_PERF_CXXFLAGS)) + MFEM_CXXFLAGS += -Xcompiler="$(MFEM_PERF_CXXFLAGS)" + endif +else + MFEM_CXXFLAGS += $(MFEM_PERF_CXXFLAGS) +endif SEQ_MINIAPPS = ex1 PAR_MINIAPPS = ex1p From b60159377c7674caf3af383e32f0b08dd3b81341 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 15 May 2020 17:27:31 -0700 Subject: [PATCH 327/535] In class Memory, guard against allocating over-aligned types with 'new' if not using c++17 or newer. --- general/mem_manager.hpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index c225dc1e8e..54728966d4 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -16,6 +16,7 @@ #include "error.hpp" #include // std::memcpy #include // std::is_const +#include // std::max_align_t namespace mfem { @@ -413,6 +414,38 @@ public: /** This method can be useful for debugging. It is explicitly instantiated for Memory with T = int and T = double. */ inline int CompareHostAndDevice(int size) const; + +private: + // GCC 4.8 workaround: max_align_t is not in std. + static constexpr std::size_t def_align_bytes_() + { + using namespace std; + return alignof(max_align_t); + } + static constexpr std::size_t def_align_bytes = def_align_bytes_(); + static constexpr std::size_t new_align_bytes = + alignof(T) > def_align_bytes ? alignof(T) : def_align_bytes; + + template struct Alloc + { + static inline T *New(std::size_t) + { +#if __cplusplus < 201703L + // Generate an error in debug mode + MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST"); + return nullptr; +#else + return new T[size]; +#endif + } + }; + +#if __cplusplus < 201703L + template struct Alloc + { + static inline T *New(std::size_t size) { return new T[size]; } + }; +#endif }; @@ -625,7 +658,7 @@ inline void Memory::New(int size) capacity = size; flags = OWNS_HOST | VALID_HOST; h_mt = MemoryManager::host_mem_type; - h_ptr = (h_mt == MemoryType::HOST) ? new T[size] : + h_ptr = (h_mt == MemoryType::HOST) ? Alloc::New(size) : (T*)MemoryManager::New_(nullptr, size*sizeof(T), h_mt, flags); } @@ -637,7 +670,8 @@ inline void Memory::New(int size, MemoryType mt) const bool mt_host = mt == MemoryType::HOST; if (mt_host) { flags = OWNS_HOST | VALID_HOST; } h_mt = IsHostMemory(mt) ? mt : MemoryManager::GetDualMemoryType_(mt); - T *h_tmp = (h_mt == MemoryType::HOST) ? new T[size] : nullptr; + T *h_tmp = (h_mt == MemoryType::HOST) ? + Alloc::New(size) : nullptr; h_ptr = (mt_host) ? h_tmp : (T*)MemoryManager::New_(h_tmp, bytes, mt, flags); } From d0221b980c59cec5e5168eb985ff953d01c24d33 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 16 May 2020 08:14:38 -0700 Subject: [PATCH 328/535] Move the SIMD headers from 'config' to 'linalg'. --- INSTALL | 8 ++++---- fem/tbilinearform.hpp | 2 +- {config => linalg}/simd.hpp | 0 {config => linalg}/simd/auto.hpp | 2 +- {config => linalg}/simd/m128.hpp | 2 +- {config => linalg}/simd/m256.hpp | 2 +- {config => linalg}/simd/m512.hpp | 2 +- {config => linalg}/simd/qpx.hpp | 0 {config => linalg}/simd/qpx256.hpp | 2 +- {config => linalg}/simd/vsx.hpp | 0 {config => linalg}/simd/vsx128.hpp | 2 +- {config => linalg}/simd/x86.hpp | 0 linalg/ttensor.hpp | 2 +- 13 files changed, 12 insertions(+), 12 deletions(-) rename {config => linalg}/simd.hpp (100%) rename {config => linalg}/simd/auto.hpp (99%) rename {config => linalg}/simd/m128.hpp (99%) rename {config => linalg}/simd/m256.hpp (99%) rename {config => linalg}/simd/m512.hpp (99%) rename {config => linalg}/simd/qpx.hpp (100%) rename {config => linalg}/simd/qpx256.hpp (99%) rename {config => linalg}/simd/vsx.hpp (100%) rename {config => linalg}/simd/vsx128.hpp (99%) rename {config => linalg}/simd/x86.hpp (100%) diff --git a/INSTALL b/INSTALL index ced11c9a35..c25b2b7385 100644 --- a/INSTALL +++ b/INSTALL @@ -397,10 +397,10 @@ MFEM_USE_SIDRE = YES/NO HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project. MFEM_USE_SIMD = YES/NO - Enables the high performance templated classes to use specific intrinsics - instead of the AutoSIMD (config/simd/auto.hpp) class. This option should be - combined with suitable compiler options, such as -march=native, to enable - optimal vectorization. + Enables the high performance templated classes to use architecture dependent + SIMD intrinsics instead of the generic implementation of class AutoSIMD in + linalg/simd/auto.hpp. This option should be combined with suitable + compiler options, such as -march=native, to enable optimal vectorization. MFEM_USE_CONDUIT = YES/NO Enables support for converting MFEM Mesh and Grid Function objects to and diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 25a749845b..dbafc8cdc6 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -13,7 +13,7 @@ #define MFEM_TEMPLATE_BILINEAR_FORM #include "../config/tconfig.hpp" -#include "../config/simd.hpp" +#include "../linalg/simd.hpp" #include "../linalg/ttensor.hpp" #include "bilinearform.hpp" #include "tevaluator.hpp" diff --git a/config/simd.hpp b/linalg/simd.hpp similarity index 100% rename from config/simd.hpp rename to linalg/simd.hpp diff --git a/config/simd/auto.hpp b/linalg/simd/auto.hpp similarity index 99% rename from config/simd/auto.hpp rename to linalg/simd/auto.hpp index 9b1e094b53..7ad4ced090 100644 --- a/config/simd/auto.hpp +++ b/linalg/simd/auto.hpp @@ -12,7 +12,7 @@ #ifndef MFEM_SIMD_AUTO_HPP #define MFEM_SIMD_AUTO_HPP -#include "../tconfig.hpp" +#include "../../config/tconfig.hpp" namespace mfem { diff --git a/config/simd/m128.hpp b/linalg/simd/m128.hpp similarity index 99% rename from config/simd/m128.hpp rename to linalg/simd/m128.hpp index 800bc6f31d..70e0d06e40 100644 --- a/config/simd/m128.hpp +++ b/linalg/simd/m128.hpp @@ -14,7 +14,7 @@ #ifdef __SSE2__ -#include "../tconfig.hpp" +#include "../../config/tconfig.hpp" #include namespace mfem diff --git a/config/simd/m256.hpp b/linalg/simd/m256.hpp similarity index 99% rename from config/simd/m256.hpp rename to linalg/simd/m256.hpp index 4106bc5236..4f9cf7296e 100644 --- a/config/simd/m256.hpp +++ b/linalg/simd/m256.hpp @@ -14,7 +14,7 @@ #ifdef __AVX__ -#include "../tconfig.hpp" +#include "../../config/tconfig.hpp" #include namespace mfem diff --git a/config/simd/m512.hpp b/linalg/simd/m512.hpp similarity index 99% rename from config/simd/m512.hpp rename to linalg/simd/m512.hpp index 3041950cb6..184ba09666 100644 --- a/config/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -14,7 +14,7 @@ #ifdef __AVX512F__ -#include "../tconfig.hpp" +#include "../../config/tconfig.hpp" #include namespace mfem diff --git a/config/simd/qpx.hpp b/linalg/simd/qpx.hpp similarity index 100% rename from config/simd/qpx.hpp rename to linalg/simd/qpx.hpp diff --git a/config/simd/qpx256.hpp b/linalg/simd/qpx256.hpp similarity index 99% rename from config/simd/qpx256.hpp rename to linalg/simd/qpx256.hpp index 0a848a658e..573526a706 100644 --- a/config/simd/qpx256.hpp +++ b/linalg/simd/qpx256.hpp @@ -14,7 +14,7 @@ #ifdef __bgq__ -#include "../tconfig.hpp" +#include "../../config/tconfig.hpp" #include namespace mfem diff --git a/config/simd/vsx.hpp b/linalg/simd/vsx.hpp similarity index 100% rename from config/simd/vsx.hpp rename to linalg/simd/vsx.hpp diff --git a/config/simd/vsx128.hpp b/linalg/simd/vsx128.hpp similarity index 99% rename from config/simd/vsx128.hpp rename to linalg/simd/vsx128.hpp index 6bce826a46..b49a94b00e 100644 --- a/config/simd/vsx128.hpp +++ b/linalg/simd/vsx128.hpp @@ -14,7 +14,7 @@ #ifdef __VSX__ -#include "../tconfig.hpp" +#include "../../config/tconfig.hpp" #include namespace mfem diff --git a/config/simd/x86.hpp b/linalg/simd/x86.hpp similarity index 100% rename from config/simd/x86.hpp rename to linalg/simd/x86.hpp diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index a89f582586..6c923d0e3a 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -13,7 +13,7 @@ #define MFEM_TEMPLATE_TENSOR #include "../config/tconfig.hpp" -#include "../config/simd.hpp" +#include "../linalg/simd.hpp" #include "../general/tassign.hpp" #include "tlayout.hpp" #include "tmatrix.hpp" From 74a892bb781e85a3eaff0d8dfb29d8a1618442bd Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 16 May 2020 13:21:13 -0700 Subject: [PATCH 329/535] Add support for x86/x64 intrinsics with MSVC. --- linalg/simd.hpp | 8 +++++--- linalg/simd/m128.hpp | 4 ++++ linalg/simd/m256.hpp | 4 ++++ linalg/simd/m512.hpp | 5 +++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/linalg/simd.hpp b/linalg/simd.hpp index 39b5ced864..fd21529104 100644 --- a/linalg/simd.hpp +++ b/linalg/simd.hpp @@ -21,10 +21,12 @@ #include "simd/vsx.hpp" #elif defined (__bgq__) #include "simd/qpx.hpp" -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) #include "simd/x86.hpp" -#else +#elif !defined(_MSC_VER) #warning Unknown SIMD architecture +#else +#pragma message("warning: Unknown SIMD architecture") #endif #endif @@ -34,7 +36,7 @@ // template parameter is set to true -- it ensues that the size of such TVector // types is a multiple of MFEM_ALIGN_BYTES. MFEM_ALIGN_BYTES must be a multiple // of MFEM_SIMD_BYTES. -#if !defined(MFEM_USE_SIMD) || defined(_WIN32) +#if !defined(MFEM_USE_SIMD) #define MFEM_SIMD_BYTES 8 #define MFEM_ALIGN_BYTES 32 #elif defined(__AVX512F__) diff --git a/linalg/simd/m128.hpp b/linalg/simd/m128.hpp index 70e0d06e40..1620811888 100644 --- a/linalg/simd/m128.hpp +++ b/linalg/simd/m128.hpp @@ -15,7 +15,11 @@ #ifdef __SSE2__ #include "../../config/tconfig.hpp" +#if defined(__x86_64__) #include +#else // assiming MSVC with _M_X64 or _M_IX86 +#include +#endif namespace mfem { diff --git a/linalg/simd/m256.hpp b/linalg/simd/m256.hpp index 4f9cf7296e..613fadd18b 100644 --- a/linalg/simd/m256.hpp +++ b/linalg/simd/m256.hpp @@ -15,7 +15,11 @@ #ifdef __AVX__ #include "../../config/tconfig.hpp" +#if defined(__x86_64__) #include +#else // assiming MSVC with _M_X64 or _M_IX86 +#include +#endif namespace mfem { diff --git a/linalg/simd/m512.hpp b/linalg/simd/m512.hpp index 184ba09666..2fb0ca8e96 100644 --- a/linalg/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -15,7 +15,12 @@ #ifdef __AVX512F__ #include "../../config/tconfig.hpp" +#if defined(__x86_64__) #include +#else // assiming MSVC with _M_X64 or _M_IX86 +#include +#endif + namespace mfem { From b68643cbecb1820fb63ce5df4a28e1efa404b5e4 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 16 May 2020 14:04:54 -0700 Subject: [PATCH 330/535] In the performance miniapps, print the MFEM SIMD width. In the miniapps/performance makefile, print the auto-detected compiler and if that fails, the print the output used for auto-dection. --- .travis.yml | 3 --- miniapps/performance/ex1.cpp | 2 ++ miniapps/performance/ex1p.cpp | 5 +++++ miniapps/performance/makefile | 9 ++++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b678d91809..d2fd9589ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -384,9 +384,6 @@ script: if [ "$CODECOV" == "YES" ]; then CPPFLAGS="--coverage -g"; fi; - if [ "$CXX" == "clang++" ]; then - export MFEM_PERF_SW=clang; - fi # Configure the library - make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG MFEM_CXX="$MYCXX" diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index c0b3ab69a3..bfb181cd36 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -124,6 +124,8 @@ int main(int argc, char *argv[]) return 3; } + cout << "\nMFEM SIMD width: " << MFEM_SIMD_BYTES << " bytes\n" << endl; + // See class BasisType in fem/fe_coll.hpp for available basis types int basis = BasisType::GetType(basis_type[0]); cout << "Using " << BasisType::Name(basis) << " basis ..." << endl; diff --git a/miniapps/performance/ex1p.cpp b/miniapps/performance/ex1p.cpp index ecf9e92c6b..109caf0dff 100644 --- a/miniapps/performance/ex1p.cpp +++ b/miniapps/performance/ex1p.cpp @@ -144,6 +144,11 @@ int main(int argc, char *argv[]) return 3; } + if (myid == 0) + { + cout << "\nMFEM SIMD width: " << MFEM_SIMD_BYTES << " bytes\n" << endl; + } + // See class BasisType in fem/fe_coll.hpp for available basis types int basis = BasisType::GetType(basis_type[0]); if (myid == 0) diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 23d4b6b40c..5e4c230080 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -47,7 +47,14 @@ printf "%s" "$$cxx_id" endef ifneq (,$(MFEM_HOST_CXX)) MFEM_PERF_SW := $(shell $(cxx_detect)) - # $(info Detected host compiler: $(MFEM_PERF_SW)) + $(info Detected host compiler: $(MFEM_PERF_SW)) + ifeq (unknown,$(MFEM_PERF_SW)) + $(info -------------------------------------------) + $(info Output from '$(MFEM_HOST_CXX) --version -c') + $(info -------------------------------------------) + $(shell $(MFEM_HOST_CXX) --version -c 1>&2) + $(info -------------------------------------------) + endif endif ifeq (gcc,$(MFEM_PERF_SW)) ifeq ($(MFEM_MACHINE),x86_64) From 41e5c9b20540672ae38a1488314ea5be5c211a2d Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 16 May 2020 15:28:04 -0700 Subject: [PATCH 331/535] A few small fixes and tweaks. --- .travis.yml | 4 +++- makefile | 3 ++- miniapps/performance/makefile | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2fd9589ee..173667f6ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -370,8 +370,10 @@ script: # Compiler - if [ $MPI == "YES" ]; then export MYCXX=mpic++; + export MAKE_CXX_FLAG=MPICXX=$MYCXX else export MYCXX="$CXX"; + export MAKE_CXX_FLAG=CXX=$MYCXX fi # Print the compiler version @@ -386,7 +388,7 @@ script: fi; # Configure the library - - make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG MFEM_CXX="$MYCXX" + - make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG $MAKE_CXX_FLAG MFEM_MPI_NP=$NPROCS CPPFLAGS="$CPPFLAGS" # Show the configuration - make info diff --git a/makefile b/makefile index f67b723136..8a08847656 100644 --- a/makefile +++ b/makefile @@ -217,6 +217,7 @@ endif # Default configuration ifeq ($(MFEM_USE_CUDA)$(MFEM_USE_HIP),NONO) MFEM_CXX ?= $(MFEM_HOST_CXX) + MFEM_HOST_CXX := $(MFEM_CXX) XCOMPILER = $(CXX_XCOMPILER) XLINKER = $(CXX_XLINKER) endif @@ -391,7 +392,7 @@ ifneq (,$(filter install,$(MAKECMDGOALS))) endif # Source dirs in logical order -DIRS = general linalg config/simd mesh fem fem/libceed +DIRS = general linalg linalg/simd mesh fem fem/libceed SOURCE_FILES = $(foreach dir,$(DIRS),$(wildcard $(SRC)$(dir)/*.cpp)) RELSRC_FILES = $(patsubst $(SRC)%,%,$(SOURCE_FILES)) OBJECT_FILES = $(patsubst $(SRC)%,$(BLD)%,$(SOURCE_FILES:.cpp=.o)) diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index 5e4c230080..d18cef7b47 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -32,7 +32,7 @@ if [ 0 -ne $$? ]; then cxx_id="unknown"; elif [ -z "$${cxx_v##g++*}" ]; then cxx_id="gcc"; -elif [ -z "$${cxx_v##*clang version*}" ]; then +elif [ -z "$${cxx_v##*clang version*}" -o -z "$${cxx_v##*LLVM version*}" ]; then cxx_id="clang"; elif [ -z "$${cxx_v##*icpc*}" ]; then cxx_id="icc"; From fbb60d2ae175879aa75784986cecec23439c278d Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 16 May 2020 16:56:18 -0700 Subject: [PATCH 332/535] Fix .travis.yml [skip appveyor] --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 173667f6ec..4adc20c551 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,6 @@ language: cpp -sudo: false - stages: - checks - tests @@ -370,10 +368,10 @@ script: # Compiler - if [ $MPI == "YES" ]; then export MYCXX=mpic++; - export MAKE_CXX_FLAG=MPICXX=$MYCXX + export MAKE_CXX_FLAG=MPICXX=$MYCXX; else export MYCXX="$CXX"; - export MAKE_CXX_FLAG=CXX=$MYCXX + export MAKE_CXX_FLAG=CXX=$MYCXX; fi # Print the compiler version From ed96b2754788b64990b759f8d86028d622d650a6 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 16 May 2020 17:40:27 -0700 Subject: [PATCH 333/535] Minor consistency fix. --- mesh/hexahedron.hpp | 2 +- mesh/quadrilateral.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mesh/hexahedron.hpp b/mesh/hexahedron.hpp index 2bd984ab98..a85d0345dd 100644 --- a/mesh/hexahedron.hpp +++ b/mesh/hexahedron.hpp @@ -68,7 +68,7 @@ public: virtual ~Hexahedron() { } }; -extern TriLinear3DFiniteElement HexahedronFE; +extern class TriLinear3DFiniteElement HexahedronFE; } diff --git a/mesh/quadrilateral.hpp b/mesh/quadrilateral.hpp index dcf312222f..33dc6d70b7 100644 --- a/mesh/quadrilateral.hpp +++ b/mesh/quadrilateral.hpp @@ -69,7 +69,7 @@ public: virtual ~Quadrilateral() { } }; -extern BiLinear2DFiniteElement QuadrilateralFE; +extern class BiLinear2DFiniteElement QuadrilateralFE; } From f487715dca92cc117a890e8ed1096f77d196430b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Tue, 12 May 2020 16:05:29 -0700 Subject: [PATCH 334/535] PETSc example with 2D Maxwell eigenproblem --- examples/petsc/maxwell2d.cpp | 385 +++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 examples/petsc/maxwell2d.cpp diff --git a/examples/petsc/maxwell2d.cpp b/examples/petsc/maxwell2d.cpp new file mode 100644 index 0000000000..59dd153ea4 --- /dev/null +++ b/examples/petsc/maxwell2d.cpp @@ -0,0 +1,385 @@ +// MFEM Example 5 - Parallel Version +// PETSc Modification +// +// Compile with: make ex5p +// +// Sample runs: +// mpirun -np 4 ex5p -m ../../data/beam-tet.mesh --petscopts rc_ex5p_fieldsplit +// mpirun -np 4 ex5p -m ../../data/star.mesh --petscopts rc_ex5p_bddc --nonoverlapping +// +// Description: This example code solves a simple 2D/3D mixed Darcy problem +// corresponding to the saddle point system +// k*u + grad p = f +// - div u = g +// with natural boundary condition -p = . +// Here, we use a given exact solution (u,p) and compute the +// corresponding r.h.s. (f,g). We discretize with Raviart-Thomas +// finite elements (velocity u) and piecewise discontinuous +// polynomials (pressure p). +// +// The example demonstrates the use of the BlockMatrix class, as +// well as the collective saving of several grid functions in a +// VisIt (visit.llnl.gov) visualization format. +// +// Two types of PETSc solvers can be used: BDDC or fieldsplit. +// When using BDDC, the nonoverlapping assembly feature should be +// used. This specific example needs PETSc compiled with support +// for SuiteSparse and/or MUMPS for using BDDC. +// +// We recommend viewing examples 1-4 before viewing this example. + +#include "mfem.hpp" +#include +#include +#include + +#ifndef MFEM_USE_PETSC +#error This example requires that MFEM is built with MFEM_USE_PETSC=YES +#endif + +using namespace std; +using namespace mfem; + +int main(int argc, char *argv[]) +{ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + bool verbose = (myid == 0); + + // 2. Parse command-line options. + const char *mesh_file = "../../data/star.mesh"; + int ser_ref_levels = 2; + int par_ref_levels = 1; + int order = 1; + int nev = 5; + bool par_format = false; + bool visualization = 1; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", + "Number of times to refine the mesh uniformly in serial."); + args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", + "Number of times to refine the mesh uniformly in parallel."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree)."); + args.AddOption(&par_format, "-pf", "--parallel-format", "-sf", + "--serial-format", + "Format to use when saving the results for VisIt."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + if (verbose) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + if (verbose) + { + args.PrintOptions(cout); + } + // 2b. We initialize PETSc + MFEMInitializePetsc(NULL,NULL,(char*)0,NULL); + SlepcInitialize(NULL,NULL,(char*)0,NULL); + + // 3. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 4. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 10,000 elements. + /*for (int lev = 0; lev < ser_ref_levels; lev++) + { + mesh->UniformRefinement(); + }*/ + + // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + /*for (int l = 0; l < par_ref_levels; l++) + { + pmesh->UniformRefinement(); + }*/ + pmesh->ReorientTetMesh(); + + // 6. Define a parallel finite element space on the parallel mesh. Here we + // use the Raviart-Thomas finite elements of the specified order. + std::cout << "dim: " << dim << "\n"; + FiniteElementCollection *hcurl_coll = new ND_FECollection(order, dim); + FiniteElementCollection *h1_coll = new H1_FECollection(order, dim); + + ParFiniteElementSpace *N_space = new ParFiniteElementSpace(pmesh, hcurl_coll); + ParFiniteElementSpace *L_space = new ParFiniteElementSpace(pmesh, h1_coll); + + HYPRE_Int dimN = N_space->GlobalTrueVSize(); + HYPRE_Int dimL = L_space->GlobalTrueVSize(); + + if (verbose) + { + std::cout << "***********************************************************\n"; + std::cout << "dim(N) = " << dimN << "\n"; + std::cout << "dim(L) = " << dimL << "\n"; + std::cout << "dim(N+L) = " << dimN + dimL << "\n"; + std::cout << "***********************************************************\n"; + } + + // 7. Define the two BlockStructure of the problem. block_offsets is used + // for Vector based on dof (like ParGridFunction or ParLinearForm), + // block_trueOffstes is used for Vector based on trueDof (HypreParVector + // for the rhs and solution of the linear system). The offsets computed + // here are local to the processor. + Array block_offsets(3); // number of variables + 1 + block_offsets[0] = 0; + block_offsets[1] = N_space->GetVSize(); + block_offsets[2] = L_space->GetVSize(); + block_offsets.PartialSum(); + + Array block_trueOffsets(3); // number of variables + 1 + block_trueOffsets[0] = 0; + block_trueOffsets[1] = N_space->TrueVSize(); + block_trueOffsets[2] = L_space->TrueVSize(); + block_trueOffsets.PartialSum(); + + // 8. Define the coefficients, analytical solution, and rhs of the PDE. + ConstantCoefficient u_r_func(1.0); + Vector e_r(2); + double k0 = M_PI*2/1.55; + e_r(0) = -pow(k0*1.45,2);//-k0^2*e_r + e_r(1) = -pow(k0*3.45,2); + PWConstCoefficient e_r_func(e_r); + + // 9. Define the parallel grid function and parallel linear forms, solution + // vector and rhs. + BlockVector x(block_offsets); + BlockVector trueX(block_trueOffsets); + + //boundary attributes + Array ess_bdr; + if (pmesh->bdr_attributes.Size()) + { + std::cout << "mesh bdr " << pmesh->bdr_attributes.Size() << " " << pmesh->bdr_attributes.Max() << "\n"; + ess_bdr.SetSize(pmesh->bdr_attributes.Max()); + ess_bdr = 0; + } + + + + // 10. Assemble the finite element matrices for the Darcy operator + // + // D = [ M B^T ] + // [ B 0 ] + // where: + // + // M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h + // B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h + ParBilinearForm *att = new ParBilinearForm(N_space); + ParBilinearForm *btt = new ParBilinearForm(N_space); + ParBilinearForm *azz = new ParBilinearForm(L_space); + ParBilinearForm *bzz = new ParBilinearForm(L_space); + ParMixedBilinearForm *btz = new ParMixedBilinearForm(N_space, L_space); + + PetscParMatrix *pAtt = NULL, *pBtt = NULL, *pBzz = NULL; + PetscParMatrix *pAzz = NULL, *pBtz = NULL, *pBzt = NULL; + Operator::Type tid = Operator::PETSC_MATAIJ; + OperatorHandle Atth(tid), Btth(tid), Bzzh(tid), Btzh(tid), Azzh(tid); + + att->AddDomainIntegrator(new CurlCurlIntegrator(u_r_func)); + att->AddDomainIntegrator(new VectorFEMassIntegrator(e_r_func)); + att->Assemble(); + att->EliminateEssentialBCDiag(ess_bdr, 1.0); + att->Finalize(); + att->ParallelAssemble(Atth); + Atth.Get(pAtt); + Atth.SetOperatorOwner(false); + + azz->Assemble(); + azz->EliminateEssentialBCDiag(ess_bdr, 1.0); + azz->Finalize(); + azz->ParallelAssemble(Azzh); + Azzh.Get(pAzz); + Azzh.SetOperatorOwner(false); + + btt->AddDomainIntegrator(new VectorFEMassIntegrator(u_r_func)); + btt->Assemble(); + btt->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); + btt->Finalize(); + btt->ParallelAssemble(Btth); + Btth.Get(pBtt); + Btth.SetOperatorOwner(false); + (*pBtt) *= -1; + + bzz->AddDomainIntegrator(new DiffusionIntegrator(u_r_func)); + bzz->AddDomainIntegrator(new MassIntegrator(e_r_func)); + bzz->Assemble(); + btt->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); + bzz->Finalize(); + bzz->ParallelAssemble(Bzzh); + Bzzh.Get(pBzz); + Bzzh.SetOperatorOwner(false); + (*pBzz) *= -1; + + ParLinearForm dummy(N_space); + btz->AddDomainIntegrator(new MixedVectorWeakDivergenceIntegrator(u_r_func)); + btz->Assemble(); + btz->EliminateTestDofs(ess_bdr); + btz->EliminateTrialDofs(ess_bdr,x.GetBlock(0),dummy); + btz->Finalize(); + btz->ParallelAssemble(Btzh); + Btzh.Get(pBtz); + Btzh.SetOperatorOwner(false); + //(*pBtz) *= -1; + + pBzt = pBtz->Transpose(); + + PetscParMatrix *LHSOp = NULL, *RHSOp = NULL; + // We construct the BlockOperator and we then convert it to a + // PetscParMatrix to avoid any conversion in the construction of the + // preconditioners. + BlockOperator *tLHSOp = new BlockOperator(block_trueOffsets); + tLHSOp->SetBlock(0,0,pAtt); + tLHSOp->SetBlock(1,1,pAzz); + LHSOp = new PetscParMatrix(MPI_COMM_WORLD,tLHSOp,Operator::PETSC_MATAIJ); + delete tLHSOp; + + BlockOperator *tRHSOp = new BlockOperator(block_trueOffsets); + tRHSOp->SetBlock(0,0,pBtt); + tRHSOp->SetBlock(1,1,pBzz); + tRHSOp->SetBlock(1,0,pBtz); + tRHSOp->SetBlock(0,1,pBzt); + RHSOp = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp,Operator::PETSC_MATAIJ); + delete tRHSOp; + + // 12. Solve the linear system with slepc. + std::cout << "Solving...\n"; + int maxIter(500); + double rtol(1.e-6); + double atol(1.e-10); + + trueX = 0.0; + + PetscParVector *X = new PetscParVector(*LHSOp, true, false); + X->PlaceArray(trueX.GetData()); + EPS eps; + EPSCreate(PETSC_COMM_WORLD,&eps); + EPSSetDimensions(eps,1,PETSC_DECIDE,PETSC_DECIDE); + EPSSetTolerances(eps,1e-12,500); + EPSSetOperators(eps,*LHSOp,*RHSOp); + EPSSetWhichEigenpairs(eps,EPS_TARGET_MAGNITUDE); + EPSSetTarget(eps,pow(k0*3.44,2)); + ST st; + EPSGetST(eps,&st); + STSetType(st,STSINVERT); + EPSSetFromOptions(eps); + EPSSolve(eps); + + PetscInt num_converged; + PetscInt it_num; + PetscScalar lr, lc; + EPSGetConverged(eps,&num_converged); + std::cout << "num_converged = " << num_converged << "\n"; + EPSGetIterationNumber(eps,&it_num); + std::cout <<"it_num = " << it_num << "\n"; + EPSReasonView(eps,PETSC_VIEWER_STDOUT_WORLD); + Vec xi; + MatCreateVecs(*LHSOp,NULL,&xi); + EPSGetEigenpair(eps,0,&lr,&lc,*X,xi); + X->ResetArray(); + PetscReal re,im; + re = lr; + im = lc; + std::cout << sqrt(re)/k0 <<"+1i*"<< (double)im << "\n"; + + // 13. Extract the parallel grid function corresponding to the finite element + // approximation X. This is the local solution on each processor. Compute + // L2 error norms. + ParGridFunction *exy(new ParGridFunction); + ParGridFunction *ez(new ParGridFunction); + exy->MakeRef(N_space, x.GetBlock(0), 0); + ez->MakeRef(L_space, x.GetBlock(1), 0); + exy->Distribute(&(trueX.GetBlock(0))); + ez->Distribute(&(trueX.GetBlock(1))); + + // 14. Save the refined mesh and the solution in parallel. This output can be + // viewed later using GLVis: "glvis -np -m mesh -g sol_*". + { + ostringstream mesh_name, u_name, p_name; + mesh_name << "mesh." << setfill('0') << setw(6) << myid; + u_name << "sol_u." << setfill('0') << setw(6) << myid; + p_name << "sol_p." << setfill('0') << setw(6) << myid; + + ofstream mesh_ofs(mesh_name.str().c_str()); + mesh_ofs.precision(8); + pmesh->Print(mesh_ofs); + + ofstream exy_ofs(u_name.str().c_str()); + exy_ofs.precision(8); + exy->Save(exy_ofs); + + ofstream ez_ofs(p_name.str().c_str()); + ez_ofs.precision(8); + ez->Save(ez_ofs); + } + + // 15. Save data in the VisIt format + VisItDataCollection visit_dc("Example5-Parallel", pmesh); + visit_dc.RegisterField("Exy", exy); + visit_dc.RegisterField("Ez", ez); + visit_dc.SetFormat(!par_format ? + DataCollection::SERIAL_FORMAT : + DataCollection::PARALLEL_FORMAT); + visit_dc.Save(); + + // 16. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream u_sock(vishost, visport); + u_sock << "parallel " << num_procs << " " << myid << "\n"; + u_sock.precision(8); + u_sock << "solution\n" << *pmesh << *exy << "window_title 'Velocity'" + << endl; + u_sock << "keys Rjl!\n"; + // Make sure all ranks have sent their 'u' solution before initiating + // another set of GLVis connections (one from each rank): + MPI_Barrier(pmesh->GetComm()); + socketstream p_sock(vishost, visport); + p_sock << "parallel " << num_procs << " " << myid << "\n"; + p_sock.precision(8); + p_sock << "solution\n" << *pmesh << *ez << "window_title 'Pressure'" + << endl; + p_sock << "keys Rjl!\n"; + } + + // 17. Free the used memory. + delete exy; + delete ez; + delete N_space; + delete L_space; + delete h1_coll; + delete hcurl_coll; + delete pmesh; + + // We finalize PETSc + MFEMFinalizePetsc(); + SlepcFinalize(); + MPI_Finalize(); + + return 0; +} + From c7d65ff383b4b735597c75fab08cfeb987c57ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Fri, 15 May 2020 11:00:02 -0700 Subject: [PATCH 335/535] Create SLEPc class Add SLEPc to build system Add example 11 to PETSc folder using SLEPc eigensolver --- CMakeLists.txt | 9 +- config/XSDKDefaults.cmake | 4 + config/cmake/MFEMConfig.cmake.in | 1 + config/cmake/config.hpp.in | 3 + config/cmake/modules/FindSLEPc.cmake | 278 +++++++++++ config/cmake/modules/MfemCmakeUtilities.cmake | 2 +- config/config.hpp | 3 + config/config.hpp.in | 3 + config/config.mk.in | 1 + config/defaults.cmake | 5 + config/defaults.mk | 14 + examples/petsc/CMakeLists.txt | 1 + examples/petsc/ex11p.cpp | 439 ++++++++++++++++++ examples/petsc/maxwell2d.cpp | 45 +- linalg/CMakeLists.txt | 6 + linalg/linalg.hpp | 4 + linalg/slepc.cpp | 280 +++++++++++ linalg/slepc.hpp | 111 +++++ makefile | 8 +- 19 files changed, 1195 insertions(+), 22 deletions(-) create mode 100644 config/cmake/modules/FindSLEPc.cmake create mode 100644 examples/petsc/ex11p.cpp create mode 100644 linalg/slepc.cpp create mode 100644 linalg/slepc.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ebdbc318f..b88156478c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,9 +149,14 @@ if (MFEM_USE_MPI) message(FATAL_ERROR "PETSc version >= 3.8.0 is required") endif() set(PETSC_INCLUDE_DIRS ${PETSC_INCLUDES}) + if (MFEM_USE_SLEPC) + find_package(SLEPc REQUIRED) + message(STATUS "Found SLEPc version ${SLEPC_VERSION}") + set(SLEPC_INCLUDE_DIRS ${SLEPC_INCLUDES}) + endif() endif() else() - set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK PUMI) + set(PKGS_NEED_MPI SUPERLU PETSC SLEPC STRUMPACK PUMI) foreach(PKG IN LISTS PKGS_NEED_MPI) if (MFEM_USE_${PKG}) message(STATUS "Disabling package ${PKG} - requires MPI") @@ -352,7 +357,7 @@ endif() # integers, the METIS header (with 32-bit indices, as used by mfem) needs to # be before SuiteSparse. set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC - MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF + SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2) # Add all *_FOUND libraries in the variable TPL_LIBRARIES. set(TPL_LIBRARIES "") diff --git a/config/XSDKDefaults.cmake b/config/XSDKDefaults.cmake index da9f380b78..0cb8339501 100644 --- a/config/XSDKDefaults.cmake +++ b/config/XSDKDefaults.cmake @@ -244,6 +244,10 @@ IF (DEFINED TPL_ENABLE_PETSC) SET(MFEM_USE_PETSC ${TPL_ENABLE_PETSC} CACHE BOOL "Enable PETSc support." FORCE) ENDIF() +IF (DEFINED TPL_ENABLE_SLEPC) + SET(MFEM_USE_SLEPC ${TPL_ENABLE_SLEPC} CACHE BOOL "Enable SLEPc support." FORCE) +ENDIF() + IF (DEFINED TPL_ENABLE_MPFR) SET(MFEM_USE_MPFR ${TPL_ENABLE_MPFR} CACHE BOOL "Enable MPFR usage." FORCE) ENDIF() diff --git a/config/cmake/MFEMConfig.cmake.in b/config/cmake/MFEMConfig.cmake.in index 896e1c3510..8512ff1807 100644 --- a/config/cmake/MFEMConfig.cmake.in +++ b/config/cmake/MFEMConfig.cmake.in @@ -38,6 +38,7 @@ set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@) set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@) set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@) set(MFEM_USE_PETSC @MFEM_USE_PETSC@) +set(MFEM_USE_SLEPC @MFEM_USE_SLEPC@) set(MFEM_USE_MPFR @MFEM_USE_MPFR@) set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@) set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@) diff --git a/config/cmake/config.hpp.in b/config/cmake/config.hpp.in index 26327ae59b..38073d07e3 100644 --- a/config/cmake/config.hpp.in +++ b/config/cmake/config.hpp.in @@ -104,6 +104,9 @@ // Enable MFEM functionality based on the PETSc library #cmakedefine MFEM_USE_PETSC +// Enable MFEM functionality based on the SLEPc library +#cmakedefine MFEM_USE_SLEPC + // Enable MFEM functionality based on the Sidre library #cmakedefine MFEM_USE_SIDRE diff --git a/config/cmake/modules/FindSLEPc.cmake b/config/cmake/modules/FindSLEPc.cmake new file mode 100644 index 0000000000..93ba853fab --- /dev/null +++ b/config/cmake/modules/FindSLEPc.cmake @@ -0,0 +1,278 @@ +# - Try to find SLEPC +# Once done this will define +# +# SLEPC_FOUND - system has SLEPc +# SLEPC_INCLUDE_DIR - include directories for SLEPc +# SLEPC_LIBARIES - libraries for SLEPc +# SLEPC_DIR - directory where SLEPc is built +# SLEPC_VERSION - version of SLEPc +# SLEPC_VERSION_MAJOR - First number in SLEPC_VERSION +# SLEPC_VERSION_MINOR - Second number in SLEPC_VERSION +# SLEPC_VERSION_SUBMINOR - Third number in SLEPC_VERSION +# +# Assumes that PETSC_DIR and PETSC_ARCH has been set by +# alredy calling find_package(PETSc) + +#============================================================================= +# Copyright (C) 2010-2012 Garth N. Wells, Anders Logg and Johannes Ring +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +message(STATUS "Checking for package 'SLEPc'") + +# Set debian_arches (PETSC_ARCH for Debian-style installations) +foreach (debian_arches linux kfreebsd) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(DEBIAN_FLAVORS ${debian_arches}-gnu-c-debug ${debian_arches}-gnu-c-opt ${DEBIAN_FLAVORS}) + else() + set(DEBIAN_FLAVORS ${debian_arches}-gnu-c-opt ${debian_arches}-gnu-c-debug ${DEBIAN_FLAVORS}) + endif() +endforeach() + +# List of possible locations for SLEPC_DIR +set(slepc_dir_locations "") +list(APPEND slepc_dir_locations "/usr/lib/slepc") +list(APPEND slepc_dir_locations "/opt/local/lib/petsc") # Macports +list(APPEND slepc_dir_locations "/usr/local/lib/slepc") +list(APPEND slepc_dir_locations "$ENV{HOME}/slepc") + +# Add other possible locations for SLEPC_DIR +set(_SYSTEM_LIB_PATHS "${CMAKE_SYSTEM_LIBRARY_PATH};${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES}") +string(REGEX REPLACE ":" ";" libdirs ${_SYSTEM_LIB_PATHS}) +foreach (libdir ${libdirs}) + get_filename_component(slepc_dir_location "${libdir}/" PATH) + list(APPEND slepc_dir_locations ${slepc_dir_location}) +endforeach() + +# Try to figure out SLEPC_DIR by finding slepc.h +find_path(SLEPC_DIR include/slepc.h + HINTS ${SLEPC_DIR} $ENV{SLEPC_DIR} + PATHS ${slepc_dir_locations} + DOC "SLEPc directory") + +# Report result of search for SLEPC_DIR +if (DEFINED SLEPC_DIR) + message(STATUS "SLEPC_DIR is ${SLEPC_DIR}") +else() + message(STATUS "SLEPC_DIR is empty") +endif() + +# Get variables from SLEPc configuration +if (SLEPC_DIR) + + find_library(SLEPC_LIBRARY + NAMES slepc + HINTS ${SLEPC_DIR}/lib $ENV{SLEPC_DIR}/lib ${SLEPC_DIR}/${PETSC_ARCH}/lib $ENV{SLEPC_DIR}/$ENV{PETSC_ARCH}/lib + NO_DEFAULT_PATH + DOC "The SLEPc library") + find_library(SLEPC_LIBRARY + NAMES slepc + DOC "The SLEPc library") + mark_as_advanced(SLEPC_LIBRARY) + + # Find SLEPc config file + find_file(SLEPC_CONFIG_FILE NAMES slepc_common PATHS + ${SLEPC_DIR}/lib/slepc/conf + ${SLEPC_DIR}/lib/slepc-conf ${SLEPC_DIR}/conf) + + # Create a temporary Makefile to probe the SLEPc configuration + set(slepc_config_makefile ${PROJECT_BINARY_DIR}/Makefile.slepc) + file(WRITE ${slepc_config_makefile} +"# This file was autogenerated by FindSLEPc.cmake +SLEPC_DIR = ${SLEPC_DIR} +PETSC_ARCH = ${PETSC_ARCH} +PETSC_DIR = ${PETSC_DIR} +include ${SLEPC_CONFIG_FILE} +show : + -@echo -n \${\${VARIABLE}} +") + + # Define macro for getting SLEPc variables from Makefile + macro(SLEPC_GET_VARIABLE var name) + set(${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} --no-print-directory -f ${slepc_config_makefile} show VARIABLE=${name} + OUTPUT_VARIABLE ${var} + RESULT_VARIABLE slepc_return) + endmacro() + + # Call macro to get the SLEPc variables + slepc_get_variable(SLEPC_INCLUDE SLEPC_INCLUDE) + slepc_get_variable(SLEPC_EXTERNAL_LIB SLEPC_EXTERNAL_LIB) + + # Remove temporary Makefile + file(REMOVE ${slepc_config_makefile}) + + # Extract include paths and libraries from compile command line + include(ResolveCompilerPaths) + resolve_includes(SLEPC_INCLUDE_DIRS "${SLEPC_INCLUDE}") + resolve_libraries(SLEPC_EXTERNAL_LIBRARIES "${SLEPC_EXTERNAL_LIB}") + + # Add variables to CMake cache and mark as advanced + set(SLEPC_INCLUDE_DIRS ${SLEPC_INCLUDE_DIRS} CACHE STRING "SLEPc include paths." FORCE) + set(SLEPC_LIBRARIES ${SLEPC_LIBRARY} CACHE STRING "SLEPc libraries." FORCE) + mark_as_advanced(SLEPC_INCLUDE_DIRS SLEPC_LIBRARIES) +endif() + +if (DOLFIN_SKIP_BUILD_TESTS) + set(SLEPC_TEST_RUNS TRUE) + set(SLEPC_VERSION "UNKNOWN") + set(SLEPC_VERSION_OK TRUE) +elseif (SLEPC_LIBRARIES AND SLEPC_INCLUDE_DIRS) + + # Set flags for building test program + set(CMAKE_REQUIRED_INCLUDES ${SLEPC_INCLUDE_DIRS} ${PETSC_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${SLEPC_LIBRARIES} ${PETSC_LIBRARIES}) + + # Add MPI variables if MPI has been found + if (MPI_C_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MPI_C_INCLUDE_PATH}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${MPI_C_LIBRARIES}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${MPI_C_COMPILE_FLAGS}") + endif() + + # Check SLEPc version + set(SLEPC_CONFIG_TEST_VERSION_CPP + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/slepc_config_test_version.cpp") + file(WRITE ${SLEPC_CONFIG_TEST_VERSION_CPP} " +#include +#include \"slepcversion.h\" + +int main() { + std::cout << SLEPC_VERSION_MAJOR << \".\" + << SLEPC_VERSION_MINOR << \".\" + << SLEPC_VERSION_SUBMINOR; + return 0; +} +") + + try_run( + SLEPC_CONFIG_TEST_VERSION_EXITCODE + SLEPC_CONFIG_TEST_VERSION_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${SLEPC_CONFIG_TEST_VERSION_CPP} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" + COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE OUTPUT + ) + + if (SLEPC_CONFIG_TEST_VERSION_EXITCODE EQUAL 0) + set(SLEPC_VERSION ${OUTPUT} CACHE STRING STRING) + string(REPLACE "." ";" SLEPC_VERSION_LIST ${SLEPC_VERSION}) + list(GET SLEPC_VERSION_LIST 0 SLEPC_VERSION_MAJOR) + list(GET SLEPC_VERSION_LIST 1 SLEPC_VERSION_MINOR) + list(GET SLEPC_VERSION_LIST 2 SLEPC_VERSION_SUBMINOR) + mark_as_advanced(SLEPC_VERSION) + mark_as_advanced(SLEPC_VERSION_MAJOR, SLEPC_VERSION_MINOR, SLEPC_VERSION_SUBMINOR) + endif() + + if (SLEPc_FIND_VERSION) + # Check if version found is >= required version + if (NOT "${SLEPC_VERSION}" VERSION_LESS "${SLEPc_FIND_VERSION}") + set(SLEPC_VERSION_OK TRUE) + endif() + else() + # No specific version requested + set(SLEPC_VERSION_OK TRUE) + endif() + mark_as_advanced(SLEPC_VERSION_OK) + + # Run SLEPc test program + set(SLEPC_TEST_LIB_CPP + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/slepc_test_lib.cpp") + file(WRITE ${SLEPC_TEST_LIB_CPP} " +#include \"petsc.h\" +#include \"slepceps.h\" +int main() +{ + PetscErrorCode ierr; + int argc = 0; + char** argv = NULL; + ierr = SlepcInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL); + EPS eps; + ierr = EPSCreate(PETSC_COMM_SELF, &eps); CHKERRQ(ierr); + //ierr = EPSSetFromOptions(eps); CHKERRQ(ierr); +#if PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR <= 1 + ierr = EPSDestroy(eps); CHKERRQ(ierr); +#else + ierr = EPSDestroy(&eps); CHKERRQ(ierr); +#endif + ierr = SlepcFinalize(); CHKERRQ(ierr); + return 0; +} +") + + try_run( + SLEPC_TEST_LIB_EXITCODE + SLEPC_TEST_LIB_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${SLEPC_TEST_LIB_CPP} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" + "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}" + COMPILE_OUTPUT_VARIABLE SLEPC_TEST_LIB_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE SLEPC_TEST_LIB_OUTPUT + ) + + if (SLEPC_TEST_LIB_COMPILED AND SLEPC_TEST_LIB_EXITCODE EQUAL 0) + message(STATUS "Performing test SLEPC_TEST_RUNS - Success") + set(SLEPC_TEST_RUNS TRUE) + else() + message(STATUS "Performing test SLEPC_TEST_RUNS - Failed") + + # Test program does not run - try adding SLEPc 3rd party libs and test again + list(APPEND CMAKE_REQUIRED_LIBRARIES ${SLEPC_EXTERNAL_LIBRARIES}) + + try_run( + SLEPC_TEST_3RD_PARTY_LIBS_EXITCODE + SLEPC_TEST_3RD_PARTY_LIBS_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${SLEPC_TEST_LIB_CPP} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" + "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}" + COMPILE_OUTPUT_VARIABLE SLEPC_TEST_3RD_PARTY_LIBS_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE SLEPC_TEST_3RD_PARTY_LIBS_OUTPUT + ) + + if (SLEPC_TEST_3RD_PARTY_LIBS_COMPILED AND SLEPC_TEST_3RD_PARTY_LIBS_EXITCODE EQUAL 0) + message(STATUS "Performing test SLEPC_TEST_3RD_PARTY_LIBS_RUNS - Success") + set(SLEPC_LIBRARIES ${SLEPC_LIBRARIES} ${SLEPC_EXTERNAL_LIBRARIES} + CACHE STRING "SLEPc libraries." FORCE) + set(SLEPC_TEST_RUNS TRUE) + else() + message(STATUS "Performing test SLEPC_TEST_3RD_PARTY_LIBS_RUNS - Failed") + endif() + endif() +endif() + +# Standard package handling +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SLEPc + "SLEPc could not be found. Be sure to set SLEPC_DIR, PETSC_DIR, and PETSC_ARCH." + SLEPC_LIBRARIES SLEPC_DIR SLEPC_INCLUDE_DIRS SLEPC_TEST_RUNS + SLEPC_VERSION SLEPC_VERSION_OK) diff --git a/config/cmake/modules/MfemCmakeUtilities.cmake b/config/cmake/modules/MfemCmakeUtilities.cmake index 6f3428933c..045fbf2594 100644 --- a/config/cmake/modules/MfemCmakeUtilities.cmake +++ b/config/cmake/modules/MfemCmakeUtilities.cmake @@ -731,7 +731,7 @@ function(mfem_export_mk_files) MFEM_USE_LAPACK MFEM_THREAD_SAFE MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS - MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE + MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA MFEM_USE_UMPIRE) foreach(var ${CONFIG_MK_BOOL_VARS}) diff --git a/config/config.hpp b/config/config.hpp index 8d96d2a054..74ae1507fc 100644 --- a/config/config.hpp +++ b/config/config.hpp @@ -48,6 +48,9 @@ #ifdef MFEM_USE_PETSC #error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES) #endif +#ifdef MFEM_USE_SLEPC +#error Building with SLEPc (MFEM_USE_SLEPC=YES) requires MPI (MFEM_USE_MPI=YES) +#endif #ifdef MFEM_USE_PUMI #error Building with PUMI (MFEM_USE_PUMI=YES) requires MPI (MFEM_USE_MPI=YES) #endif diff --git a/config/config.hpp.in b/config/config.hpp.in index d71cfcfbe0..185143e0ee 100644 --- a/config/config.hpp.in +++ b/config/config.hpp.in @@ -115,6 +115,9 @@ // Enable functionality based on the PETSc library // #define MFEM_USE_PETSC +// Enable functionality based on the SLEPc library +// #define MFEM_USE_SLEPC + // Enable functionality based on the MPFR library. // #define MFEM_USE_MPFR diff --git a/config/config.mk.in b/config/config.mk.in index 4d7c34affc..a3d72c75c6 100644 --- a/config/config.mk.in +++ b/config/config.mk.in @@ -37,6 +37,7 @@ MFEM_USE_GINKGO = @MFEM_USE_GINKGO@ MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@ MFEM_USE_NETCDF = @MFEM_USE_NETCDF@ MFEM_USE_PETSC = @MFEM_USE_PETSC@ +MFEM_USE_SLEPC = @MFEM_USE_SLEPC@ MFEM_USE_MPFR = @MFEM_USE_MPFR@ MFEM_USE_SIDRE = @MFEM_USE_SIDRE@ MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@ diff --git a/config/defaults.cmake b/config/defaults.cmake index 5854e6916e..ca4916a1b1 100644 --- a/config/defaults.cmake +++ b/config/defaults.cmake @@ -39,6 +39,7 @@ option(MFEM_USE_GNUTLS "Enable GNUTLS usage" OFF) option(MFEM_USE_GSLIB "Enable GSLIB usage" OFF) option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF) option(MFEM_USE_PETSC "Enable PETSc support." OFF) +option(MFEM_USE_SLEPC "Enable SLEPc support." OFF) option(MFEM_USE_MPFR "Enable MPFR usage." OFF) option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF) option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF) @@ -154,6 +155,10 @@ set(PETSC_DIR "${MFEM_DIR}/../petsc" CACHE PATH "Path to the PETSc main directory.") set(PETSC_ARCH "arch-linux2-c-debug" CACHE STRING "PETSc build architecture.") +set(SLEPC_DIR "${MFEM_DIR}/../slepc" CACHE PATH + "Path to the SLEPc main directory.") +set(SLEPC_ARCH "arch-linux2-c-debug" CACHE STRING "SLEPC build architecture.") + set(MPFR_DIR "" CACHE PATH "Path to the MPFR library.") set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH diff --git a/config/defaults.mk b/config/defaults.mk index 490fa4f0e3..f8720fcabe 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -125,6 +125,7 @@ MFEM_USE_GINKGO = NO MFEM_USE_GNUTLS = NO MFEM_USE_NETCDF = NO MFEM_USE_PETSC = NO +MFEM_USE_SLEPC = NO MFEM_USE_MPFR = NO MFEM_USE_SIDRE = NO MFEM_USE_CONDUIT = NO @@ -275,6 +276,19 @@ ifeq ($(PETSC_FOUND),YES) -L$(abspath $(PETSC_DIR))/lib -lpetsc $(PETSC_LIB) endif +SLEPC_ARCH := arch-linux2-c-debug +SLEPC_DIR := $(MFEM_DIR)/../slepc/$(SLEPC_ARCH) +SLEPC_VARS := $(SLEPC_DIR)/lib/slepc/conf/slepc_variables +SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,) +SLEPC_INC_VAR = SLEPC_CC_INCLUDES +SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB_BASIC +ifeq ($(SLEPC_FOUND),YES) + SLEPC_OPT := $(shell set -n "s/$(SLEPC_INC_VAR) = *//p" $(SLEPC_VARS)) + SLEPC_LIB := $(shell set -n "s/$(SLEPC_INC_LIB) = *//p" $(SLEPC_VARS)) + PETSC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/lib\ + -L$(abspath $(SLEPC_DIR))/lib -lslepc $(SLEPC_LIB) +endif + # MPFR library configuration MPFR_OPT = MPFR_LIB = -lmpfr diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 3318a75a83..80ceeae874 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -22,6 +22,7 @@ if (MFEM_USE_MPI) ex6p.cpp ex9p.cpp ex10p.cpp + ex11p.cpp ) list(APPEND PETSC_RC_FILES rc_ex1p diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp new file mode 100644 index 0000000000..83cf8cbab5 --- /dev/null +++ b/examples/petsc/ex11p.cpp @@ -0,0 +1,439 @@ +// MFEM Example 11 - Parallel Version +// +// Compile with: make ex11p +// +// Sample runs: mpirun -np 4 ex11p -m ../data/square-disc.mesh +// mpirun -np 4 ex11p -m ../data/star.mesh +// mpirun -np 4 ex11p -m ../data/star-mixed.mesh +// mpirun -np 4 ex11p -m ../data/escher.mesh +// mpirun -np 4 ex11p -m ../data/fichera.mesh +// mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh +// mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2 +// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2 +// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3 +// mpirun -np 4 ex11p -m ../data/square-disc-nurbs.mesh -o -1 +// mpirun -np 4 ex11p -m ../data/disc-nurbs.mesh -o -1 -n 20 +// mpirun -np 4 ex11p -m ../data/pipe-nurbs.mesh -o -1 +// mpirun -np 4 ex11p -m ../data/ball-nurbs.mesh -o 2 +// mpirun -np 4 ex11p -m ../data/star-surf.mesh +// mpirun -np 4 ex11p -m ../data/square-disc-surf.mesh +// mpirun -np 4 ex11p -m ../data/inline-segment.mesh +// mpirun -np 4 ex11p -m ../data/inline-quad.mesh +// mpirun -np 4 ex11p -m ../data/inline-tri.mesh +// mpirun -np 4 ex11p -m ../data/inline-hex.mesh +// mpirun -np 4 ex11p -m ../data/inline-tet.mesh +// mpirun -np 4 ex11p -m ../data/inline-wedge.mesh -s 83 +// mpirun -np 4 ex11p -m ../data/amr-quad.mesh +// mpirun -np 4 ex11p -m ../data/amr-hex.mesh +// mpirun -np 4 ex11p -m ../data/mobius-strip.mesh -n 8 +// mpirun -np 4 ex11p -m ../data/klein-bottle.mesh -n 10 +// +// Description: This example code demonstrates the use of MFEM to solve the +// eigenvalue problem -Delta u = lambda u with homogeneous +// Dirichlet boundary conditions. +// +// We compute a number of the lowest eigenmodes by discretizing +// the Laplacian and Mass operators using a FE space of the +// specified order, or an isoparametric/isogeometric space if +// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for +// NURBS mesh, etc.) +// +// The example highlights the use of the LOBPCG eigenvalue solver +// together with the BoomerAMG preconditioner in HYPRE, as well as +// optionally the SuperLU or STRUMPACK parallel direct solvers. +// Reusing a single GLVis visualization window for multiple +// eigenfunctions is also illustrated. +// +// We recommend viewing Example 1 before viewing this example. + +#include "mfem.hpp" +#include +#include + +#ifndef MFEM_USE_SLEPC +#error This examples requires that MFEM is build with MFEM_USE_SLEPC=YES +#endif + +using namespace std; +using namespace mfem; + +int main(int argc, char *argv[]) +{ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + // 2. Parse command-line options. + const char *mesh_file = "../data/star.mesh"; + int ser_ref_levels = 2; + int par_ref_levels = 1; + int order = 1; + int nev = 5; + int seed = 75; + bool slu_solver = false; + bool sp_solver = false; + bool visualization = 1; + bool use_slepc = true; + const char *slepcrc_file = ""; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", + "Number of times to refine the mesh uniformly in serial."); + args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", + "Number of times to refine the mesh uniformly in parallel."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree) or -1 for" + " isoparametric space."); + args.AddOption(&nev, "-n", "--num-eigs", + "Number of desired eigenmodes."); + args.AddOption(&seed, "-s", "--seed", + "Random seed used to initialize LOBPCG."); +#ifdef MFEM_USE_SUPERLU + args.AddOption(&slu_solver, "-slu", "--superlu", "-no-slu", + "--no-superlu", "Use the SuperLU Solver."); +#endif +#ifdef MFEM_USE_STRUMPACK + args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp", + "--no-strumpack", "Use the STRUMPACK Solver."); +#endif + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.AddOption(&use_slepc, "-useslepc","--useslepc","-no-slepc", + "--no-slepc","Use or not SLEPc to solve the eigenvalue problem"); + args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts", + "SlepcOptions file to use."); + args.Parse(); + if (slu_solver && sp_solver) + { + if (myid == 0) + cout << "WARNING: Both SuperLU and STRUMPACK have been selected," + << " please choose either one." << endl + << " Defaulting to SuperLU." << endl; + sp_solver = false; + } + // The command line options are also passed to the STRUMPACK + // solver. So do not exit if some options are not recognized. + if (!sp_solver) + { + if (!args.Good()) + { + if (myid == 0) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + } + if (myid == 0) + { + args.PrintOptions(cout); + } + + // 2b. We initialize SLEPc. This internally initializes PETSc as well. + MFEMInitializeSlepc(NULL,NULL,slepcrc_file,NULL); + + // 3. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 4. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement (2 by default, or + // specified on the command line with -rs). + for (int lev = 0; lev < ser_ref_levels; lev++) + { + mesh->UniformRefinement(); + } + + // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution (1 time by + // default, or specified on the command line with -rp). Once the parallel + // mesh is defined, the serial mesh can be deleted. + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + for (int lev = 0; lev < par_ref_levels; lev++) + { + pmesh->UniformRefinement(); + } + + // 6. Define a parallel finite element space on the parallel mesh. Here we + // use continuous Lagrange finite elements of the specified order. If + // order < 1, we instead use an isoparametric/isogeometric space. + FiniteElementCollection *fec; + if (order > 0) + { + fec = new H1_FECollection(order, dim); + } + else if (pmesh->GetNodes()) + { + fec = pmesh->GetNodes()->OwnFEC(); + } + else + { + fec = new H1_FECollection(order = 1, dim); + } + ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); + HYPRE_Int size = fespace->GlobalTrueVSize(); + if (myid == 0) + { + cout << "Number of unknowns: " << size << endl; + } + + // 7. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite + // element space. The first corresponds to the Laplacian operator -Delta, + // while the second is a simple mass matrix needed on the right hand side + // of the generalized eigenvalue problem below. The boundary conditions + // are implemented by elimination with special values on the diagonal to + // shift the Dirichlet eigenvalues out of the computational range. After + // serial and parallel assembly we extract the corresponding parallel + // matrices A and M. + ConstantCoefficient one(1.0); + Array ess_bdr; + if (pmesh->bdr_attributes.Size()) + { + ess_bdr.SetSize(pmesh->bdr_attributes.Max()); + ess_bdr = 1; + } + + ParBilinearForm *a = new ParBilinearForm(fespace); + a->AddDomainIntegrator(new DiffusionIntegrator(one)); + if (pmesh->bdr_attributes.Size() == 0) + { + // Add a mass term if the mesh has no boundary, e.g. periodic mesh or + // closed surface. + a->AddDomainIntegrator(new MassIntegrator(one)); + } + a->Assemble(); + a->EliminateEssentialBCDiag(ess_bdr, 1.0); + a->Finalize(); + + ParBilinearForm *m = new ParBilinearForm(fespace); + m->AddDomainIntegrator(new MassIntegrator(one)); + m->Assemble(); + // shift the eigenvalue corresponding to eliminated dofs to a large value + m->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); + m->Finalize(); + + HypreParMatrix *A = a->ParallelAssemble(); + HypreParMatrix *M = m->ParallelAssemble(); + +#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK) + Operator * Arow = NULL; +#ifdef MFEM_USE_SUPERLU + if (slu_solver) + { + Arow = new SuperLURowLocMatrix(*A); + } +#endif +#ifdef MFEM_USE_STRUMPACK + if (sp_solver) + { + Arow = new STRUMPACKRowLocMatrix(*A); + } +#endif +#endif + + delete a; + delete m; + + // 8. Define and configure the LOBPCG eigensolver and the BoomerAMG + // preconditioner for A to be used within the solver. Set the matrices + // which define the generalized eigenproblem A x = lambda M x. + Solver * precond = NULL; + if (!slu_solver && !sp_solver) + { + HypreBoomerAMG * amg = new HypreBoomerAMG(*A); + amg->SetPrintLevel(0); + precond = amg; + } + else + { +#ifdef MFEM_USE_SUPERLU + if (slu_solver) + { + SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD); + superlu->SetPrintStatistics(false); + superlu->SetSymmetricPattern(true); + superlu->SetColumnPermutation(superlu::PARMETIS); + superlu->SetOperator(*Arow); + precond = superlu; + } +#endif +#ifdef MFEM_USE_STRUMPACK + if (sp_solver) + { + STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD); + strumpack->SetPrintFactorStatistics(true); + strumpack->SetPrintSolveStatistics(false); + strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT); + strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS); + strumpack->DisableMatching(); + strumpack->SetOperator(*Arow); + strumpack->SetFromCommandLine(); + precond = strumpack; + } +#endif + } + + HypreLOBPCG * lobpcg; + SlepcEigenSolver * slepc; + if (!use_slepc) + { + + lobpcg = new HypreLOBPCG(MPI_COMM_WORLD); + lobpcg->SetNumModes(nev); + lobpcg->SetRandomSeed(seed); + lobpcg->SetPreconditioner(*precond); + lobpcg->SetMaxIter(200); + lobpcg->SetTol(1e-8); + lobpcg->SetPrecondUsageMode(1); + lobpcg->SetPrintLevel(1); + lobpcg->SetMassMatrix(*M); + lobpcg->SetOperator(*A); + } + else + { + slepc = new SlepcEigenSolver(MPI_COMM_WORLD); + slepc->SetNumModes(nev); + slepc->SetWhichEigenpairs(SlepcEigenSolver::TARGET_REAL); + slepc->SetTarget(0.0); + slepc->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT); + slepc->SetOperators(*A,*M); + } + + // 9. Compute the eigenmodes and extract the array of eigenvalues. Define a + // parallel grid function to represent each of the eigenmodes returned by + // the solver. + Array eigenvalues; + if (!use_slepc) + { + lobpcg->Solve(); + lobpcg->GetEigenvalues(eigenvalues); + } + else + { + slepc->Solve(); + eigenvalues.SetSize(nev); + for (int i=0; iGetEigenvalue(i,eigenvalues[i]); + } + } + ParGridFunction x(fespace); + + // 10. Save the refined mesh and the modes in parallel. This output can be + // viewed later using GLVis: "glvis -np -m mesh -g mode". + { + ostringstream mesh_name, mode_name; + mesh_name << "mesh." << setfill('0') << setw(6) << myid; + + ofstream mesh_ofs(mesh_name.str().c_str()); + mesh_ofs.precision(8); + pmesh->Print(mesh_ofs); + + for (int i=0; iGetEigenvector(i); + } + else + { + slepc->GetEigenvector(i,x); + + } + + mode_name << "mode_" << setfill('0') << setw(2) << i << "." + << setfill('0') << setw(6) << myid; + + ofstream mode_ofs(mode_name.str().c_str()); + mode_ofs.precision(8); + x.Save(mode_ofs); + mode_name.str(""); + } + } + + // 11. Send the solution by socket to a GLVis server. + if (visualization) + { + char vishost[] = "localhost"; + int visport = 19916; + socketstream mode_sock(vishost, visport); + mode_sock.precision(8); + + for (int i=0; i " << flush; + cin >> c; + } + MPI_Bcast(&c, 1, MPI_CHAR, 0, MPI_COMM_WORLD); + + if (c != 'c') + { + break; + } + } + mode_sock.close(); + } + + // 12. Free the used memory. + if (!use_slepc) + { + delete lobpcg; + } + else + { + delete slepc; + } + delete precond; + delete M; + delete A; +#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK) + delete Arow; +#endif + + delete fespace; + if (order > 0) + { + delete fec; + } + delete pmesh; + + // We finalize SLEPc + MFEMFinalizeSlepc(); + MPI_Finalize(); + + return 0; +} diff --git a/examples/petsc/maxwell2d.cpp b/examples/petsc/maxwell2d.cpp index 59dd153ea4..51e0ac9375 100644 --- a/examples/petsc/maxwell2d.cpp +++ b/examples/petsc/maxwell2d.cpp @@ -31,7 +31,7 @@ #include "mfem.hpp" #include #include -#include +//#include #ifndef MFEM_USE_PETSC #error This example requires that MFEM is built with MFEM_USE_PETSC=YES @@ -101,20 +101,20 @@ int main(int argc, char *argv[]) // this example we do 'ref_levels' of uniform refinement. We choose // 'ref_levels' to be the largest number that gives a final mesh with no // more than 10,000 elements. - /*for (int lev = 0; lev < ser_ref_levels; lev++) + for (int lev = 0; lev < ser_ref_levels; lev++) { mesh->UniformRefinement(); - }*/ + } // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine // this mesh further in parallel to increase the resolution. Once the // parallel mesh is defined, the serial mesh can be deleted. ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; - /*for (int l = 0; l < par_ref_levels; l++) + for (int l = 0; l < par_ref_levels; l++) { pmesh->UniformRefinement(); - }*/ + } pmesh->ReorientTetMesh(); // 6. Define a parallel finite element space on the parallel mesh. Here we @@ -172,7 +172,8 @@ int main(int argc, char *argv[]) Array ess_bdr; if (pmesh->bdr_attributes.Size()) { - std::cout << "mesh bdr " << pmesh->bdr_attributes.Size() << " " << pmesh->bdr_attributes.Max() << "\n"; + std::cout << "mesh bdr " << pmesh->bdr_attributes.Size() << " " << + pmesh->bdr_attributes.Max() << "\n"; ess_bdr.SetSize(pmesh->bdr_attributes.Max()); ess_bdr = 0; } @@ -222,7 +223,7 @@ int main(int argc, char *argv[]) Btth.Get(pBtt); Btth.SetOperatorOwner(false); (*pBtt) *= -1; - + bzz->AddDomainIntegrator(new DiffusionIntegrator(u_r_func)); bzz->AddDomainIntegrator(new MassIntegrator(e_r_func)); bzz->Assemble(); @@ -243,7 +244,7 @@ int main(int argc, char *argv[]) Btzh.Get(pBtz); Btzh.SetOperatorOwner(false); //(*pBtz) *= -1; - + pBzt = pBtz->Transpose(); PetscParMatrix *LHSOp = NULL, *RHSOp = NULL; @@ -263,7 +264,7 @@ int main(int argc, char *argv[]) tRHSOp->SetBlock(0,1,pBzt); RHSOp = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp,Operator::PETSC_MATAIJ); delete tRHSOp; - + // 12. Solve the linear system with slepc. std::cout << "Solving...\n"; int maxIter(500); @@ -271,8 +272,8 @@ int main(int argc, char *argv[]) double atol(1.e-10); trueX = 0.0; - - PetscParVector *X = new PetscParVector(*LHSOp, true, false); + + /*PetscParVector *X = new PetscParVector(*LHSOp, true, false); X->PlaceArray(trueX.GetData()); EPS eps; EPSCreate(PETSC_COMM_WORLD,&eps); @@ -285,9 +286,17 @@ int main(int argc, char *argv[]) EPSGetST(eps,&st); STSetType(st,STSINVERT); EPSSetFromOptions(eps); - EPSSolve(eps); - - PetscInt num_converged; + EPSSolve(eps);*/ + SlepcEigenSolver *solver = new SlepcEigenSolver(MPI_COMM_WORLD); + solver->SetOperators(*LHSOp,*RHSOp); + solver->SetTol(1e-12); + solver->SetMaxIter(500); + solver->SetNumModes(1); + solver->SetWhichEigenpairs(SlepcEigenSolver::TARGET_MAGNITUDE); + solver->SetTarget(pow(k0*3.44,2)); + solver->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT); + solver->Solve(); + /*PetscInt num_converged; PetscInt it_num; PetscScalar lr, lc; EPSGetConverged(eps,&num_converged); @@ -301,8 +310,12 @@ int main(int argc, char *argv[]) X->ResetArray(); PetscReal re,im; re = lr; - im = lc; - std::cout << sqrt(re)/k0 <<"+1i*"<< (double)im << "\n"; + im = lc;*/ + double re; + solver->GetEigenvalue(0,re); + Vector dummy2(block_trueOffsets[2]); + solver->GetEigenvector(0,trueX); + std::cout << sqrt(re)/k0 << "\n"; // 13. Extract the parallel grid function corresponding to the finite element // approximation X. This is the local solution on each processor. Compute diff --git a/linalg/CMakeLists.txt b/linalg/CMakeLists.txt index 274fd9e154..a97345a461 100644 --- a/linalg/CMakeLists.txt +++ b/linalg/CMakeLists.txt @@ -62,6 +62,12 @@ if (MFEM_USE_MPI) petsc.cpp) list(APPEND HDRS petsc.hpp) + if (MFEM_USE_SLEPC) + list(APPEND SRCS + slepc.cpp) + list(APPEND HDRS + slepc.hpp) + endif() endif() endif() diff --git a/linalg/linalg.hpp b/linalg/linalg.hpp index 5a0dbf91fa..f56aa4fabb 100644 --- a/linalg/linalg.hpp +++ b/linalg/linalg.hpp @@ -49,6 +49,10 @@ #include "petsc.hpp" #endif +#ifdef MFEM_USE_SLEPC +#include "slepc.hpp" +#endif + #ifdef MFEM_USE_SUPERLU #include "superlu.hpp" #endif diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp new file mode 100644 index 0000000000..e2cbd49add --- /dev/null +++ b/linalg/slepc.cpp @@ -0,0 +1,280 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "../config/config.hpp" + +#include "linalg.hpp" + +#include "slepc.h" + +static PetscErrorCode ierr; + +namespace mfem +{ +void MFEMInitializeSlepc() +{ + MFEMInitializeSlepc(NULL,NULL,NULL,NULL); +} + +void MFEMInitializeSlepc(int *argc,char*** argv) +{ + MFEMInitializeSlepc(argc,argv,NULL,NULL); +} + +void MFEMInitializeSlepc(int *argc,char ***argv,const char rc_file[], + const char help[]) +{ + ierr = SlepcInitialize(argc,argv,rc_file,help); + MFEM_VERIFY(!ierr,"Unable to initialize SLEPc"); +} + +void MFEMFinalizeSlepc() +{ + ierr = SlepcFinalize(); + MFEM_VERIFY(!ierr,"Unable to finalize SLEPc"); +} + + +SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix) +{ + ierr = EPSCreate(comm,&eps); CCHKERRQ(comm,ierr); + ierr = EPSSetOptionsPrefix(eps, prefix.c_str()); PCHKERRQ(eps, ierr); +} + +SlepcEigenSolver::~SlepcEigenSolver() +{ + MPI_Comm comm; + ierr = PetscObjectGetComm((PetscObject)eps,&comm); PCHKERRQ(eps,ierr); + ierr = EPSDestroy(&eps); CCHKERRQ(comm,ierr); +} + + +void SlepcEigenSolver::SetOperator(const Operator &op) +{ + PetscParMatrix *pA = const_cast + (dynamic_cast(&op)); + const HypreParMatrix *hA = dynamic_cast(&op); + const Operator *oA = dynamic_cast(&op); + bool delete_pA = false; + + if (!pA) + { + if (hA) + { + pA = new PetscParMatrix(hA,Operator::PETSC_MATAIJ); + delete_pA = true; + } + else if (oA) + { + pA = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oA, + Operator::PETSC_MATAIJ); + delete_pA = true; + + } + } + MFEM_VERIFY(pA, "Unsupported operation!"); + + + ierr = EPSSetOperators(eps,*pA,NULL); PCHKERRQ(eps, ierr); + if (delete_pA) {delete_pA;} +} + +void SlepcEigenSolver::SetOperators(const Operator &op, const Operator &opB) +{ + PetscParMatrix *pA = const_cast + (dynamic_cast(&op)); + PetscParMatrix *pB = const_cast + (dynamic_cast(&opB)); + const HypreParMatrix *hA = dynamic_cast(&op); + const HypreParMatrix *hB = dynamic_cast(&opB); + + const Operator *oA = dynamic_cast(&op); + const Operator *oB = dynamic_cast(&opB); + bool delete_pA = false; + bool delete_pB = false; + if (!pA) + { + if (hA) + { + pA = new PetscParMatrix(hA,Operator::PETSC_MATAIJ); + delete_pA = true; + } + else if (oA) + { + pA = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oA, + Operator::PETSC_MATAIJ); + delete_pA = true; + } + } + MFEM_VERIFY(pA, "Unsupported Operation!"); + if (!pB) + { + if (hB) + { + pB = new PetscParMatrix(hB, Operator::PETSC_MATAIJ); + delete_pB = true; + } + else if (oB) + { + pB = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oB, + Operator::PETSC_MATAIJ); + delete_pB = true; + } + } + MFEM_VERIFY(pB, "Unsupported Operation!"); + + ierr = EPSSetOperators(eps,*pA,*pB); PCHKERRQ(eps,ierr); + if (delete_pA) {delete_pA;} + if (delete_pB) {delete_pB;} +} + +void SlepcEigenSolver::SetTol(double tol) +{ + _tol = tol; + ierr = EPSSetTolerances(eps,_tol,_max_its); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::SetMaxIter(int max_its) +{ + _max_its = max_its; + ierr = EPSSetTolerances(eps,_tol,_max_its); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::SetNumModes(int num_eigs) +{ + ierr = EPSSetDimensions(eps,num_eigs,PETSC_DECIDE,PETSC_DECIDE); + PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::Solve() +{ + Customize(); + + ierr = EPSSolve(eps); PCHKERRQ(eps,ierr); + + ierr = EPSGetConverged(eps,&_num_conv); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::Customize() +{ + ierr = EPSSetFromOptions(eps); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr) const +{ + MFEM_VERIFY(i < _num_conv,"Eigenvalue not computed"); + ierr = EPSGetEigenvalue(eps,i,&lr,NULL); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr, + double & lc) const +{ + MFEM_VERIFY(i < _num_conv,"Eigenvalue not computed"); + ierr = EPSGetEigenvalue(eps,i,&lr,&lc); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr) const +{ + if (!VR) + { + Mat pA = NULL; + ierr = EPSGetOperators(eps, &pA, NULL); PCHKERRQ(eps,ierr); + VR = new PetscParVector(pA, true, false); + } + VR->PlaceArray(vr.GetData()); + ierr = EPSGetEigenvector(eps,i,*VR,NULL); PCHKERRQ(eps,ierr); + VR->ResetArray(); + +} + +void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr, + Vector & vc) const +{ + if (!VR || !VC) + { + Mat pA = NULL; + ierr = EPSGetOperators(eps, &pA, NULL); PCHKERRQ(eps,ierr); + + if (!VR) + { + VR = new PetscParVector(pA, true, false); + } + if (!VC) + { + VC = new PetscParVector(pA, true, false); + } + } + VR->PlaceArray(vr.GetData()); + VC->PlaceArray(vc.GetData()); + ierr = EPSGetEigenvector(eps,i,*VR,*VC); PCHKERRQ(eps,ierr); + VR->ResetArray(); + VC->ResetArray(); +} + +void SlepcEigenSolver::SetWhichEigenpairs(SlepcEigenSolver::Which which) +{ + switch (which) + { + case SlepcEigenSolver::LARGEST_MAGNITUDE: + ierr = EPSSetWhichEigenpairs(eps,EPS_LARGEST_MAGNITUDE); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::SMALLEST_MAGNITUDE: + ierr = EPSSetWhichEigenpairs(eps,EPS_SMALLEST_MAGNITUDE); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::LARGEST_REAL: + ierr = EPSSetWhichEigenpairs(eps,EPS_LARGEST_REAL); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::SMALLEST_REAL: + ierr = EPSSetWhichEigenpairs(eps,EPS_SMALLEST_REAL); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::LARGEST_IMAGINARY: + ierr = EPSSetWhichEigenpairs(eps,EPS_LARGEST_IMAGINARY); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::SMALLEST_IMAGINARY: + ierr = EPSSetWhichEigenpairs(eps,EPS_SMALLEST_IMAGINARY); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::TARGET_MAGNITUDE: + ierr = EPSSetWhichEigenpairs(eps,EPS_TARGET_MAGNITUDE); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::TARGET_REAL: + ierr = EPSSetWhichEigenpairs(eps,EPS_TARGET_REAL); PCHKERRQ(eps,ierr); + break; + default: + MFEM_ABORT("Which eigenpair not implemented!"); + break; + } +} + +void SlepcEigenSolver::SetTarget(double target) +{ + ierr = EPSSetTarget(eps,target); PCHKERRQ(eps,ierr); +} + +void SlepcEigenSolver::SetSpectralTransformation( + SlepcEigenSolver::SpectralTransformation transformation) +{ + ST st; + ierr = EPSGetST(eps,&st); PCHKERRQ(eps,ierr); + switch (transformation) + { + case SlepcEigenSolver::SHIFT: + ierr = STSetType(st,STSHIFT); PCHKERRQ(eps,ierr); + break; + case SlepcEigenSolver::SHIFT_INVERT: + ierr = STSetType(st,STSINVERT); PCHKERRQ(eps,ierr); + break; + default: + MFEM_ABORT("Spectral transformation not implemented!"); + break; + } +} + +} diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp new file mode 100644 index 0000000000..a5dc6c4640 --- /dev/null +++ b/linalg/slepc.hpp @@ -0,0 +1,111 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef MFEM_SLEPC +#define MFEM_SLEPC + +#include "../config/config.hpp" + +#ifdef MFEM_USE_SLEPC +#ifdef MFEM_USE_PETSC +#ifdef MFEM_USE_MPI + +#include "petsc.hpp" +#include "slepc.h" + +namespace mfem +{ + +void MFEMInitializeSlepc(); +void MFEMInitializeSlepc(int*,char***); +void MFEMInitializeSlepc(int*,char***,const char[],const char[]); +void MFEMFinalizeSlepc(); + +class SlepcEigenSolver +{ +private: + /// SLEPc linear eigensolver object + EPS eps; + /// Solver tolerance + double _tol = PETSC_DEFAULT; + + /// Maximum number of iterations + int _max_its = PETSC_DEFAULT; + + /// Number of converged eigenvectors. Start with a negative value before the solver is run. + int _num_conv = -1; + + /// Real and imaginary part of eigenvector + mutable PetscParVector *VR = NULL, *VC = NULL; +public: + /// Constructors + SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string()); + + virtual ~SlepcEigenSolver(); + + /// Set solver tolerance + void SetTol(double tol); + + /// Set maximum number of iterations + void SetMaxIter(int max_iter); + void SetNumModes(int num_eigs); + /// Set operator for standard eigenvalue problem + void SetOperator(const Operator &op); + /// Set operator for generalized eigenvalue problem + void SetOperators(const Operator &op, const Operator &opB); + + /// Customize object with options set + void Customize(); + + /// Solve the eigenvalue problem for the specified number of eigenvalues + void Solve(); + + /// Get the corresponding eigenvalue + void GetEigenvalue(unsigned int i, double & lr) const; + void GetEigenvalue(unsigned int i, double & lr, double & lc) const; + + /// Get the corresponding eigenvector + void GetEigenvector(unsigned int i, Vector & vr) const; + void GetEigenvector(unsigned int i, Vector & vr, Vector & vc) const; + + /// Target spectrum for the eigensolver. Target imaginary is not supported without complex support in SLEPc, and intervals are not implemented. + enum Which + { + LARGEST_MAGNITUDE, + SMALLEST_MAGNITUDE, + LARGEST_REAL, + SMALLEST_REAL, + LARGEST_IMAGINARY, + SMALLEST_IMAGINARY, + TARGET_MAGNITUDE, + TARGET_REAL + }; + + enum SpectralTransformation + { + SHIFT, + SHIFT_INVERT + }; + + void SetWhichEigenpairs(Which which); + void SetTarget(double target); + void SetSpectralTransformation(SpectralTransformation transformation); + + /// Conversion function to SLEPc's EPS type. + operator EPS() const { return eps; } +}; + +} +#endif // MFEM_USE_MPI +#endif // MFEM_USE_PETSC +#endif // MFEM_USE_SLEPC + +#endif // MFEM_SLEPC diff --git a/makefile b/makefile index 15684d1b7e..fb5a31204d 100644 --- a/makefile +++ b/makefile @@ -204,7 +204,7 @@ CXXFLAGS ?= $(OPTIM_FLAGS) # MPI configuration ifneq ($(MFEM_USE_MPI),YES) CXX_OR_MPICXX = $(CXX) - PKGS_NEED_MPI = SUPERLU STRUMPACK PETSC PUMI + PKGS_NEED_MPI = SUPERLU STRUMPACK PETSC PUMI SLEPC $(foreach mpidep,$(PKGS_NEED_MPI),$(if $(MFEM_USE_$(mpidep):NO=),\ $(warning *** [MPI is OFF] setting MFEM_USE_$(mpidep) = NO)\ $(eval override MFEM_USE_$(mpidep)=NO),)) @@ -259,9 +259,10 @@ endif # List of MFEM dependencies, that require the *_LIB variable to be non-empty MFEM_REQ_LIB_DEPS = SUPERLU METIS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\ - SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC MPFR PUMI HIOP GSLIB\ + SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP GSLIB\ OCCA CEED RAJA UMPIRE PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS)) +SLEPC_ERROR_MSG = $(if $(SLEPC_FOUND),,. SLEPC config not found: $(SLEPC_VARS)) define mfem_check_dependency ifeq ($$(MFEM_USE_$(1)),YES) @@ -320,7 +321,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\ MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP MFEM_USE_MEMALLOC MFEM_TIMER_TYPE\ MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE MFEM_USE_GINKGO\ MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS\ - MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT\ + MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT\ MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\ MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_SOURCE_DIR\ MFEM_INSTALL_DIR @@ -632,6 +633,7 @@ status info: $(info MFEM_USE_GNUTLS = $(MFEM_USE_GNUTLS)) $(info MFEM_USE_NETCDF = $(MFEM_USE_NETCDF)) $(info MFEM_USE_PETSC = $(MFEM_USE_PETSC)) + $(info MFEM_USE_SLEPC = $(MFEM_USE_SLEPC)) $(info MFEM_USE_MPFR = $(MFEM_USE_MPFR)) $(info MFEM_USE_SIDRE = $(MFEM_USE_SIDRE)) $(info MFEM_USE_CONDUIT = $(MFEM_USE_CONDUIT)) From 6ef4c662360325863bdf033e086ecaed729b1cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Fri, 15 May 2020 11:31:01 -0700 Subject: [PATCH 336/535] Rename 2D Maxwell eigenproblem example (ex28p) --- examples/petsc/CMakeLists.txt | 1 + examples/petsc/{maxwell2d.cpp => ex28p.cpp} | 0 2 files changed, 1 insertion(+) rename examples/petsc/{maxwell2d.cpp => ex28p.cpp} (100%) diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 80ceeae874..37fdec1204 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -23,6 +23,7 @@ if (MFEM_USE_MPI) ex9p.cpp ex10p.cpp ex11p.cpp + ex28p.cpp ) list(APPEND PETSC_RC_FILES rc_ex1p diff --git a/examples/petsc/maxwell2d.cpp b/examples/petsc/ex28p.cpp similarity index 100% rename from examples/petsc/maxwell2d.cpp rename to examples/petsc/ex28p.cpp From 35519303a932f2b3c75da3c0b41647ec594f17ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Fri, 15 May 2020 17:17:33 -0700 Subject: [PATCH 337/535] Small fixes to SLEPc. --- examples/petsc/ex28p.cpp | 10 ++++------ linalg/slepc.cpp | 27 +++++++++++++++++++++++++++ linalg/slepc.hpp | 12 +++++++----- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index 51e0ac9375..e44c827805 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -87,9 +87,8 @@ int main(int argc, char *argv[]) { args.PrintOptions(cout); } - // 2b. We initialize PETSc - MFEMInitializePetsc(NULL,NULL,(char*)0,NULL); - SlepcInitialize(NULL,NULL,(char*)0,NULL); + // 2b. We initialize SLEPc + MFEMInitializeSlepc(NULL,NULL,(char*)0,NULL); // 3. Read the (serial) mesh from the given mesh file on all processors. We // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface @@ -388,9 +387,8 @@ int main(int argc, char *argv[]) delete hcurl_coll; delete pmesh; - // We finalize PETSc - MFEMFinalizePetsc(); - SlepcFinalize(); + // We finalize SLEPc + MFEMFinalizeSlepc(); MPI_Finalize(); return 0; diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index e2cbd49add..7137ed35f8 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -15,6 +15,27 @@ #include "slepc.h" +// Error handling +// Prints SLEPc's stacktrace and then calls MFEM_ABORT +// We cannot use PETSc's CHKERRQ since it returns a PetscErrorCode +#define PCHKERRQ(obj,err) do { \ + if ((err)) \ + { \ + PetscError(PetscObjectComm((PetscObject)(obj)),__LINE__,_MFEM_FUNC_NAME, \ + __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ + MFEM_ABORT("Error in SLEPc. See stacktrace above."); \ + } \ + } while(0); +#define CCHKERRQ(comm,err) do { \ + if ((err)) \ + { \ + PetscError(comm,__LINE__,_MFEM_FUNC_NAME, \ + __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ + MFEM_ABORT("Error in SLEPc. See stacktrace above."); \ + } \ + } while(0); + + static PetscErrorCode ierr; namespace mfem @@ -45,6 +66,12 @@ void MFEMFinalizeSlepc() SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix) { + _tol = PETSC_DEFAULT; + _max_its = PETSC_DEFAULT; + _num_conv = -1; + VR = NULL; + VC = NULL; + ierr = EPSCreate(comm,&eps); CCHKERRQ(comm,ierr); ierr = EPSSetOptionsPrefix(eps, prefix.c_str()); PCHKERRQ(eps, ierr); } diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index a5dc6c4640..9b270693a0 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -19,7 +19,9 @@ #ifdef MFEM_USE_MPI #include "petsc.hpp" -#include "slepc.h" + +// Forward declarations +typedef struct _p_EPS *EPS; namespace mfem { @@ -35,16 +37,16 @@ private: /// SLEPc linear eigensolver object EPS eps; /// Solver tolerance - double _tol = PETSC_DEFAULT; + double _tol; /// Maximum number of iterations - int _max_its = PETSC_DEFAULT; + int _max_its; /// Number of converged eigenvectors. Start with a negative value before the solver is run. - int _num_conv = -1; + int _num_conv; /// Real and imaginary part of eigenvector - mutable PetscParVector *VR = NULL, *VC = NULL; + mutable PetscParVector *VR, *VC; public: /// Constructors SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string()); From 92946031346c391d1a1e74cb6883215736ea26a9 Mon Sep 17 00:00:00 2001 From: Tomov Date: Sat, 16 May 2020 22:39:25 -0700 Subject: [PATCH 338/535] Minor - comments, alignments, etc. --- fem/coefficient.cpp | 16 ++++++---------- fem/coefficient.hpp | 7 +++---- fem/field_interpolant.hpp | 27 +++++++++++++++------------ 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index f5057cf01a..436fb862d5 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -777,8 +777,7 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient( QuadratureFunction *qf) - : VectorCoefficient(qf->GetVDim()), QuadF(qf), index(0), - length(qf->GetVDim()) {} + : VectorCoefficient(qf->GetVDim()), QuadF(qf), index(0), length(vdim) { } void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) @@ -799,9 +798,7 @@ void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length) index = _index; MFEM_VERIFY(_length > 0, "Length must be > 0"); - - int diff = QuadF->GetVDim() - index; - MFEM_VERIFY(_length <= diff, + MFEM_VERIFY(_length <= QuadF->GetVDim() - index, "Length must be <= (QuadratureFunction length - index)"); length = _length; @@ -815,17 +812,16 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); QuadF->HostRead(); - int elem_no = T.ElementNo; if (index == 0 && length == QuadF->GetVDim()) { Vector temp; - QuadF->GetElementValues(elem_no, ip.index, temp); + QuadF->GetElementValues(T.ElementNo, ip.index, temp); V = temp; } else { Vector temp; - QuadF->GetElementValues(elem_no, ip.index, temp); + QuadF->GetElementValues(T.ElementNo, ip.index, temp); double *data = temp.HostReadWrite(); V.SetSize(length); for (int i = 0; i < length; i++) @@ -840,7 +836,7 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, QuadratureFunctionCoefficient::QuadratureFunctionCoefficient( QuadratureFunction *qf) : QuadF(qf) { - MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); + MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction's vdim must be 1"); } void QuadratureFunctionCoefficient::SetQuadratureFunction( @@ -848,7 +844,7 @@ void QuadratureFunctionCoefficient::SetQuadratureFunction( { MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); - MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction vdim must be equal to 1"); + MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction's vdim must be 1"); QuadF = qf; } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 5ae939848d..494df9d510 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -974,7 +974,7 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - virtual ~VectorQuadratureFunctionCoefficient() { }; + virtual ~VectorQuadratureFunctionCoefficient() { } }; /// Quadrature function coefficient which requires that the quadrature rules used for this @@ -992,10 +992,9 @@ public: QuadratureFunction *GetQuadFunction() const { return QuadF; } - virtual double Eval(ElementTransformation &T, - const IntegrationPoint &ip); + virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); - virtual ~QuadratureFunctionCoefficient() { }; + virtual ~QuadratureFunctionCoefficient() { } }; /** Compute the Lp norm of a function f. diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 18385c9a6e..212187fad2 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -37,8 +37,8 @@ protected: bool setup_disc; bool setup_full; Vector m_all_data; - BilinearForm *L2; - CGSolver *cg; + BilinearForm *L2; // Owned. + CGSolver *cg; // Owned. int NE; public: // The FiniteElementSpace passed into here should have a vdim set to 1 in order for the @@ -160,32 +160,35 @@ class VectorQuadratureIntegrator : public LinearFormIntegrator { private: VectorQuadratureFunctionCoefficient &vqfc; + public: - VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) : vqfc( - vqfc) { } + VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) + : vqfc(vqfc) { } VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc, - const IntegrationRule *ir) : LinearFormIntegrator(ir), vqfc( - vqfc) { } + const IntegrationRule *ir) + : LinearFormIntegrator(ir), vqfc(vqfc) { } + using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect); + ElementTransformation &Tr, Vector &elvect); }; class QuadratureIntegrator : public LinearFormIntegrator { private: QuadratureFunctionCoefficient &qfc; + public: QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } QuadratureIntegrator(QuadratureFunctionCoefficient &qfc, - const IntegrationRule *ir) : LinearFormIntegrator(ir), qfc(qfc) { } + const IntegrationRule *ir) + : LinearFormIntegrator(ir), qfc(qfc) { } + using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect); + ElementTransformation &Tr, Vector &elvect); }; } -#endif \ No newline at end of file +#endif From 2274d411f7ae98ca3057367fcae277b1cb24ad96 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sun, 17 May 2020 11:30:15 -0700 Subject: [PATCH 339/535] New COPYRIGHT banner, minor edits --- INSTALL | 2 +- linalg/simd.hpp | 14 +++++++------- linalg/simd/auto.hpp | 12 ++++++------ linalg/simd/m128.hpp | 14 +++++++------- linalg/simd/m256.hpp | 14 +++++++------- linalg/simd/m512.hpp | 14 +++++++------- linalg/simd/qpx.hpp | 12 ++++++------ linalg/simd/qpx256.hpp | 12 ++++++------ linalg/simd/vsx.hpp | 12 ++++++------ linalg/simd/vsx128.hpp | 12 ++++++------ linalg/simd/x86.hpp | 12 ++++++------ 11 files changed, 65 insertions(+), 65 deletions(-) diff --git a/INSTALL b/INSTALL index c25b2b7385..0e25a392f5 100644 --- a/INSTALL +++ b/INSTALL @@ -396,7 +396,7 @@ MFEM_USE_SIDRE = YES/NO blueprint specification. When enabled, this option requires installation of HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project. -MFEM_USE_SIMD = YES/NO +MFEM_USE_SIMD = YES/NO Enables the high performance templated classes to use architecture dependent SIMD intrinsics instead of the generic implementation of class AutoSIMD in linalg/simd/auto.hpp. This option should be combined with suitable diff --git a/linalg/simd.hpp b/linalg/simd.hpp index fd21529104..26df56f0da 100644 --- a/linalg/simd.hpp +++ b/linalg/simd.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_HPP #define MFEM_SIMD_HPP @@ -32,7 +32,7 @@ // MFEM_SIMD_BYTES is the default SIMD size used by MFEM, see e.g. class // TBilinearForm and the default traits class AutoSIMDTraits. -// MFEM_ALIGN_BYTES deterimes the padding used in class TVector when its 'align' +// MFEM_ALIGN_BYTES determines the padding used in TVector when its 'align' // template parameter is set to true -- it ensues that the size of such TVector // types is a multiple of MFEM_ALIGN_BYTES. MFEM_ALIGN_BYTES must be a multiple // of MFEM_SIMD_BYTES. diff --git a/linalg/simd/auto.hpp b/linalg/simd/auto.hpp index 7ad4ced090..7e8f3a3e02 100644 --- a/linalg/simd/auto.hpp +++ b/linalg/simd/auto.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_AUTO_HPP #define MFEM_SIMD_AUTO_HPP diff --git a/linalg/simd/m128.hpp b/linalg/simd/m128.hpp index 1620811888..eb3dbc0692 100644 --- a/linalg/simd/m128.hpp +++ b/linalg/simd/m128.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_M128_HPP #define MFEM_SIMD_M128_HPP @@ -17,7 +17,7 @@ #include "../../config/tconfig.hpp" #if defined(__x86_64__) #include -#else // assiming MSVC with _M_X64 or _M_IX86 +#else // assuming MSVC with _M_X64 or _M_IX86 #include #endif diff --git a/linalg/simd/m256.hpp b/linalg/simd/m256.hpp index 613fadd18b..6bc8c42ef0 100644 --- a/linalg/simd/m256.hpp +++ b/linalg/simd/m256.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_M256_HPP #define MFEM_SIMD_M256_HPP @@ -17,7 +17,7 @@ #include "../../config/tconfig.hpp" #if defined(__x86_64__) #include -#else // assiming MSVC with _M_X64 or _M_IX86 +#else // assuming MSVC with _M_X64 or _M_IX86 #include #endif diff --git a/linalg/simd/m512.hpp b/linalg/simd/m512.hpp index 2fb0ca8e96..85c2b9b719 100644 --- a/linalg/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_M512_HPP #define MFEM_SIMD_M512_HPP @@ -17,7 +17,7 @@ #include "../../config/tconfig.hpp" #if defined(__x86_64__) #include -#else // assiming MSVC with _M_X64 or _M_IX86 +#else // assuming MSVC with _M_X64 or _M_IX86 #include #endif diff --git a/linalg/simd/qpx.hpp b/linalg/simd/qpx.hpp index 3e7113af3e..b0c37f9d40 100644 --- a/linalg/simd/qpx.hpp +++ b/linalg/simd/qpx.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_QPX_HPP #define MFEM_SIMD_QPX_HPP diff --git a/linalg/simd/qpx256.hpp b/linalg/simd/qpx256.hpp index 573526a706..7705fa7f83 100644 --- a/linalg/simd/qpx256.hpp +++ b/linalg/simd/qpx256.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_QPX_256_HPP #define MFEM_SIMD_QPX_256_HPP diff --git a/linalg/simd/vsx.hpp b/linalg/simd/vsx.hpp index 2ac29453a4..638da44dcf 100644 --- a/linalg/simd/vsx.hpp +++ b/linalg/simd/vsx.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_VSX_HPP #define MFEM_SIMD_VSX_HPP diff --git a/linalg/simd/vsx128.hpp b/linalg/simd/vsx128.hpp index b49a94b00e..175884edfc 100644 --- a/linalg/simd/vsx128.hpp +++ b/linalg/simd/vsx128.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_VSX128_HPP #define MFEM_SIMD_VSX128_HPP diff --git a/linalg/simd/x86.hpp b/linalg/simd/x86.hpp index a26dd88bd2..c13e67db59 100644 --- a/linalg/simd/x86.hpp +++ b/linalg/simd/x86.hpp @@ -1,13 +1,13 @@ -// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at -// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights -// reserved. See file COPYRIGHT for details. +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code -// availability see http://mfem.org. +// availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the -// terms of the GNU Lesser General Public License (as published by the Free -// Software Foundation) version 2.1 dated February 1999. +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. #ifndef MFEM_SIMD_X86_HPP #define MFEM_SIMD_X86_HPP From a34395c5408642fd0d23001dd0a90f4328fee038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Sun, 17 May 2020 19:02:30 -0700 Subject: [PATCH 340/535] SLEPc: Add options to wrap or not matrix, and to specify options file Fix SLEPc ex11p --- examples/petsc/ex11p.cpp | 2 +- examples/petsc/rc_ex28p | 3 +++ linalg/slepc.cpp | 47 +++++++++++++++++++++++++++++++--------- linalg/slepc.hpp | 18 +++++++++++++-- 4 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 examples/petsc/rc_ex28p diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index 83cf8cbab5..d2cd9aa12e 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -300,7 +300,7 @@ int main(int argc, char *argv[]) } else { - slepc = new SlepcEigenSolver(MPI_COMM_WORLD); + slepc = new SlepcEigenSolver(MPI_COMM_WORLD,"",false); slepc->SetNumModes(nev); slepc->SetWhichEigenpairs(SlepcEigenSolver::TARGET_REAL); slepc->SetTarget(0.0); diff --git a/examples/petsc/rc_ex28p b/examples/petsc/rc_ex28p new file mode 100644 index 0000000000..0265304c31 --- /dev/null +++ b/examples/petsc/rc_ex28p @@ -0,0 +1,3 @@ +-eps_type jd +-st_ksp_type gmres +-st_pc_type jacobi diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index 7137ed35f8..a41ce0cf40 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -64,13 +64,17 @@ void MFEMFinalizeSlepc() } -SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix) +SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix, + bool wrap) { + clcustom = false; _tol = PETSC_DEFAULT; _max_its = PETSC_DEFAULT; _num_conv = -1; + _wrap = wrap; VR = NULL; VC = NULL; + operatorset = false; ierr = EPSCreate(comm,&eps); CCHKERRQ(comm,ierr); ierr = EPSSetOptionsPrefix(eps, prefix.c_str()); PCHKERRQ(eps, ierr); @@ -96,21 +100,29 @@ void SlepcEigenSolver::SetOperator(const Operator &op) { if (hA) { - pA = new PetscParMatrix(hA,Operator::PETSC_MATAIJ); + pA = new PetscParMatrix(hA, + _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); delete_pA = true; } else if (oA) { pA = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oA, - Operator::PETSC_MATAIJ); + _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); delete_pA = true; } } MFEM_VERIFY(pA, "Unsupported operation!"); - + if (operatorset) + { + delete VR; + delete VC; + VR = VC = NULL; + } ierr = EPSSetOperators(eps,*pA,NULL); PCHKERRQ(eps, ierr); + operatorset = true; + if (delete_pA) {delete_pA;} } @@ -131,13 +143,14 @@ void SlepcEigenSolver::SetOperators(const Operator &op, const Operator &opB) { if (hA) { - pA = new PetscParMatrix(hA,Operator::PETSC_MATAIJ); + pA = new PetscParMatrix(hA, + _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); delete_pA = true; } else if (oA) { pA = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oA, - Operator::PETSC_MATAIJ); + _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); delete_pA = true; } } @@ -146,18 +159,27 @@ void SlepcEigenSolver::SetOperators(const Operator &op, const Operator &opB) { if (hB) { - pB = new PetscParMatrix(hB, Operator::PETSC_MATAIJ); + pB = new PetscParMatrix(hB, + _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); delete_pB = true; } else if (oB) { pB = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oB, - Operator::PETSC_MATAIJ); + _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); delete_pB = true; } } MFEM_VERIFY(pB, "Unsupported Operation!"); + if (operatorset) + { + delete VR; + delete VC; + VR = VC = NULL; + } + operatorset = true; + ierr = EPSSetOperators(eps,*pA,*pB); PCHKERRQ(eps,ierr); if (delete_pA) {delete_pA;} if (delete_pB) {delete_pB;} @@ -190,9 +212,14 @@ void SlepcEigenSolver::Solve() ierr = EPSGetConverged(eps,&_num_conv); PCHKERRQ(eps,ierr); } -void SlepcEigenSolver::Customize() +void SlepcEigenSolver::Customize(bool customize) const { - ierr = EPSSetFromOptions(eps); PCHKERRQ(eps,ierr); + if (!customize) {clcustom = true; } + if (!clcustom) + { + ierr = EPSSetFromOptions(eps); PCHKERRQ(eps,ierr); + } + clcustom = true; } void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr) const diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index 9b270693a0..fe0c530dae 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -34,6 +34,12 @@ void MFEMFinalizeSlepc(); class SlepcEigenSolver { private: + /// Boolean to handle SetFromOptions calls + mutable bool clcustom; + + /// Internal flag to handle matrix conversion or not. + bool _wrap; + /// SLEPc linear eigensolver object EPS eps; /// Solver tolerance @@ -47,9 +53,14 @@ private: /// Real and imaginary part of eigenvector mutable PetscParVector *VR, *VC; + + /// Boolean to handle SetOperator calls + mutable bool operatorset; + public: /// Constructors - SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string()); + SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string(), + bool wrap = true); virtual ~SlepcEigenSolver(); @@ -65,11 +76,14 @@ public: void SetOperators(const Operator &op, const Operator &opB); /// Customize object with options set - void Customize(); + void Customize(bool customize = true) const; /// Solve the eigenvalue problem for the specified number of eigenvalues void Solve(); + /// Get the number of converged eigenvalues + int GetNumConverged() {return _num_conv;} + /// Get the corresponding eigenvalue void GetEigenvalue(unsigned int i, double & lr) const; void GetEigenvalue(unsigned int i, double & lr, double & lc) const; From 1be972b036d1dfe7254aa50988705da74b7ff79e Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Mon, 18 May 2020 10:56:06 -0700 Subject: [PATCH 341/535] In the performance miniapps, print the SIMD width in terms of "doubles". --- miniapps/performance/ex1.cpp | 3 ++- miniapps/performance/ex1p.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/miniapps/performance/ex1.cpp b/miniapps/performance/ex1.cpp index bfb181cd36..97bcc273c9 100644 --- a/miniapps/performance/ex1.cpp +++ b/miniapps/performance/ex1.cpp @@ -124,7 +124,8 @@ int main(int argc, char *argv[]) return 3; } - cout << "\nMFEM SIMD width: " << MFEM_SIMD_BYTES << " bytes\n" << endl; + cout << "\nMFEM SIMD width: " << MFEM_SIMD_BYTES/sizeof(double) + << " doubles\n" << endl; // See class BasisType in fem/fe_coll.hpp for available basis types int basis = BasisType::GetType(basis_type[0]); diff --git a/miniapps/performance/ex1p.cpp b/miniapps/performance/ex1p.cpp index 109caf0dff..c55819e88b 100644 --- a/miniapps/performance/ex1p.cpp +++ b/miniapps/performance/ex1p.cpp @@ -146,7 +146,8 @@ int main(int argc, char *argv[]) if (myid == 0) { - cout << "\nMFEM SIMD width: " << MFEM_SIMD_BYTES << " bytes\n" << endl; + cout << "\nMFEM SIMD width: " << MFEM_SIMD_BYTES/sizeof(double) + << " doubles\n" << endl; } // See class BasisType in fem/fe_coll.hpp for available basis types From 5f8dab5dd304e24b7ec5c16ff62d744753599808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Mon, 18 May 2020 11:40:40 -0700 Subject: [PATCH 342/535] Improve ex28p (2D Maxwell waveguide) documentation --- examples/petsc/CMakeLists.txt | 1 + examples/petsc/ex11p.cpp | 52 +++++++------- examples/petsc/ex28p.cpp | 128 +++++++++++----------------------- 3 files changed, 69 insertions(+), 112 deletions(-) diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 37fdec1204..06a517a7c5 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -33,6 +33,7 @@ if (MFEM_USE_MPI) rc_ex5p_bddc rc_ex5p_fieldsplit rc_ex9p_expl rc_ex9p_impl rc_ex10p + rc_ex28p ) endif() diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index d2cd9aa12e..8af15f7b1c 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -2,31 +2,31 @@ // // Compile with: make ex11p // -// Sample runs: mpirun -np 4 ex11p -m ../data/square-disc.mesh -// mpirun -np 4 ex11p -m ../data/star.mesh -// mpirun -np 4 ex11p -m ../data/star-mixed.mesh -// mpirun -np 4 ex11p -m ../data/escher.mesh -// mpirun -np 4 ex11p -m ../data/fichera.mesh -// mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh -// mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2 -// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2 -// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3 -// mpirun -np 4 ex11p -m ../data/square-disc-nurbs.mesh -o -1 -// mpirun -np 4 ex11p -m ../data/disc-nurbs.mesh -o -1 -n 20 -// mpirun -np 4 ex11p -m ../data/pipe-nurbs.mesh -o -1 -// mpirun -np 4 ex11p -m ../data/ball-nurbs.mesh -o 2 -// mpirun -np 4 ex11p -m ../data/star-surf.mesh -// mpirun -np 4 ex11p -m ../data/square-disc-surf.mesh -// mpirun -np 4 ex11p -m ../data/inline-segment.mesh -// mpirun -np 4 ex11p -m ../data/inline-quad.mesh -// mpirun -np 4 ex11p -m ../data/inline-tri.mesh -// mpirun -np 4 ex11p -m ../data/inline-hex.mesh -// mpirun -np 4 ex11p -m ../data/inline-tet.mesh -// mpirun -np 4 ex11p -m ../data/inline-wedge.mesh -s 83 -// mpirun -np 4 ex11p -m ../data/amr-quad.mesh -// mpirun -np 4 ex11p -m ../data/amr-hex.mesh -// mpirun -np 4 ex11p -m ../data/mobius-strip.mesh -n 8 -// mpirun -np 4 ex11p -m ../data/klein-bottle.mesh -n 10 +// Sample runs: mpirun -np 4 ex11p -m ../../data/square-disc.mesh +// mpirun -np 4 ex11p -m ../../data/star.mesh +// mpirun -np 4 ex11p -m ../../data/star-mixed.mesh +// mpirun -np 4 ex11p -m ../../data/escher.mesh +// mpirun -np 4 ex11p -m ../../data/fichera.mesh +// mpirun -np 4 ex11p -m ../../data/fichera-mixed.mesh +// mpirun -np 4 ex11p -m ../../data/toroid-wedge.mesh -o 2 +// mpirun -np 4 ex11p -m ../../data/square-disc-p2.vtk -o 2 +// mpirun -np 4 ex11p -m ../../data/square-disc-p3.mesh -o 3 +// mpirun -np 4 ex11p -m ../../data/square-disc-nurbs.mesh -o -1 +// mpirun -np 4 ex11p -m ../../data/disc-nurbs.mesh -o -1 -n 20 +// mpirun -np 4 ex11p -m ../../data/pipe-nurbs.mesh -o -1 +// mpirun -np 4 ex11p -m ../../data/ball-nurbs.mesh -o 2 +// mpirun -np 4 ex11p -m ../../data/star-surf.mesh +// mpirun -np 4 ex11p -m ../../data/square-disc-surf.mesh +// mpirun -np 4 ex11p -m ../../data/inline-segment.mesh +// mpirun -np 4 ex11p -m ../../data/inline-quad.mesh +// mpirun -np 4 ex11p -m ../../data/inline-tri.mesh +// mpirun -np 4 ex11p -m ../../data/inline-hex.mesh +// mpirun -np 4 ex11p -m ../../data/inline-tet.mesh +// mpirun -np 4 ex11p -m ../../data/inline-wedge.mesh -s 83 +// mpirun -np 4 ex11p -m ../../data/amr-quad.mesh +// mpirun -np 4 ex11p -m ../../data/amr-hex.mesh +// mpirun -np 4 ex11p -m ../../data/mobius-strip.mesh -n 8 +// mpirun -np 4 ex11p -m ../../data/klein-bottle.mesh -n 10 // // Description: This example code demonstrates the use of MFEM to solve the // eigenvalue problem -Delta u = lambda u with homogeneous @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) MPI_Comm_rank(MPI_COMM_WORLD, &myid); // 2. Parse command-line options. - const char *mesh_file = "../data/star.mesh"; + const char *mesh_file = "../../data/star.mesh"; int ser_ref_levels = 2; int par_ref_levels = 1; int order = 1; diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index e44c827805..7a45fd36bc 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -1,32 +1,26 @@ -// MFEM Example 5 - Parallel Version -// PETSc Modification +// MFEM Example 28 - Parallel Version +// SLEPc Modification // -// Compile with: make ex5p +// Compile with: make ex28p // // Sample runs: -// mpirun -np 4 ex5p -m ../../data/beam-tet.mesh --petscopts rc_ex5p_fieldsplit -// mpirun -np 4 ex5p -m ../../data/star.mesh --petscopts rc_ex5p_bddc --nonoverlapping +// mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p // -// Description: This example code solves a simple 2D/3D mixed Darcy problem -// corresponding to the saddle point system -// k*u + grad p = f -// - div u = g -// with natural boundary condition -p = . -// Here, we use a given exact solution (u,p) and compute the -// corresponding r.h.s. (f,g). We discretize with Raviart-Thomas -// finite elements (velocity u) and piecewise discontinuous -// polynomials (pressure p). +// Description: This example code solves a simple 2D dielectric waveguide problem +// corresponding to the generalized eigenvalue equation +// curl 1/mu curl exy - beta^2/mu (grad ez - exy) = k^2 epsilon exy +// beta^2 div 1/mu (grad exy - et) = beta^2 k^2 epsilon ez +// with essential boundary condition (corresponding to metallic walls). +// We discretize with Nédélec edge elements (transverge field exy) +// and piecewise continuous polynomials (longitudinal field ez). // // The example demonstrates the use of the BlockMatrix class, as // well as the collective saving of several grid functions in a // VisIt (visit.llnl.gov) visualization format. // -// Two types of PETSc solvers can be used: BDDC or fieldsplit. -// When using BDDC, the nonoverlapping assembly feature should be -// used. This specific example needs PETSc compiled with support -// for SuiteSparse and/or MUMPS for using BDDC. +// This specific example needs SLEPc compiled. The default options +// file uses the Jacobi-Davidson method with Jacobi preconditioner. // -// We recommend viewing examples 1-4 before viewing this example. #include "mfem.hpp" #include @@ -50,13 +44,14 @@ int main(int argc, char *argv[]) bool verbose = (myid == 0); // 2. Parse command-line options. - const char *mesh_file = "../../data/star.mesh"; - int ser_ref_levels = 2; + const char *mesh_file = "../../data/inline-tri.mesh"; + int ser_ref_levels = 1; int par_ref_levels = 1; - int order = 1; - int nev = 5; + int order = 2; + int nev = 1; bool par_format = false; bool visualization = 1; + const char *slepcrc_file = ""; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", @@ -73,6 +68,8 @@ int main(int argc, char *argv[]) args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); + args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts", + "SLepcOptions file to use."); args.Parse(); if (!args.Good()) { @@ -88,7 +85,7 @@ int main(int argc, char *argv[]) args.PrintOptions(cout); } // 2b. We initialize SLEPc - MFEMInitializeSlepc(NULL,NULL,(char*)0,NULL); + MFEMInitializeSlepc(NULL,NULL,slepcrc_file,NULL); // 3. Read the (serial) mesh from the given mesh file on all processors. We // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface @@ -154,39 +151,34 @@ int main(int argc, char *argv[]) block_trueOffsets[2] = L_space->TrueVSize(); block_trueOffsets.PartialSum(); - // 8. Define the coefficients, analytical solution, and rhs of the PDE. + // 8. Define the coefficients of the PDE. ConstantCoefficient u_r_func(1.0); Vector e_r(2); - double k0 = M_PI*2/1.55; - e_r(0) = -pow(k0*1.45,2);//-k0^2*e_r - e_r(1) = -pow(k0*3.45,2); + double k0 = M_PI*2/1.0; + e_r(0) = -pow(k0*1.0,2);//-k0^2*e_r + // This is an example to use different refractive indices in mesh domains + e_r(1) = -pow(k0*2.0,2); PWConstCoefficient e_r_func(e_r); - // 9. Define the parallel grid function and parallel linear forms, solution - // vector and rhs. + // 9. Define the parallel grid function and parallel linear forms. BlockVector x(block_offsets); BlockVector trueX(block_trueOffsets); - //boundary attributes + // Define the boundary attributes Array ess_bdr; if (pmesh->bdr_attributes.Size()) { - std::cout << "mesh bdr " << pmesh->bdr_attributes.Size() << " " << - pmesh->bdr_attributes.Max() << "\n"; ess_bdr.SetSize(pmesh->bdr_attributes.Max()); ess_bdr = 0; } - - - // 10. Assemble the finite element matrices for the Darcy operator + // 10. Assemble the finite element matrices for the LHS and RHS // - // D = [ M B^T ] - // [ B 0 ] - // where: + // A = [ Att 0 ] + // [ 0 0 ] // - // M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h - // B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h + // B = [ Btt Bzt ] + // [ Btz Bzz ] ParBilinearForm *att = new ParBilinearForm(N_space); ParBilinearForm *btt = new ParBilinearForm(N_space); ParBilinearForm *azz = new ParBilinearForm(L_space); @@ -207,6 +199,8 @@ int main(int argc, char *argv[]) Atth.Get(pAtt); Atth.SetOperatorOwner(false); + // A dummy Azz is required to set the block size and apply the + // essential boundary condition azz->Assemble(); azz->EliminateEssentialBCDiag(ess_bdr, 1.0); azz->Finalize(); @@ -242,14 +236,12 @@ int main(int argc, char *argv[]) btz->ParallelAssemble(Btzh); Btzh.Get(pBtz); Btzh.SetOperatorOwner(false); - //(*pBtz) *= -1; pBzt = pBtz->Transpose(); PetscParMatrix *LHSOp = NULL, *RHSOp = NULL; // We construct the BlockOperator and we then convert it to a - // PetscParMatrix to avoid any conversion in the construction of the - // preconditioners. + // PetscParMatrix. BlockOperator *tLHSOp = new BlockOperator(block_trueOffsets); tLHSOp->SetBlock(0,0,pAtt); tLHSOp->SetBlock(1,1,pAzz); @@ -264,61 +256,25 @@ int main(int argc, char *argv[]) RHSOp = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp,Operator::PETSC_MATAIJ); delete tRHSOp; - // 12. Solve the linear system with slepc. + // 12. Solve the eigenvalue problem with slepc. std::cout << "Solving...\n"; - int maxIter(500); - double rtol(1.e-6); - double atol(1.e-10); trueX = 0.0; - /*PetscParVector *X = new PetscParVector(*LHSOp, true, false); - X->PlaceArray(trueX.GetData()); - EPS eps; - EPSCreate(PETSC_COMM_WORLD,&eps); - EPSSetDimensions(eps,1,PETSC_DECIDE,PETSC_DECIDE); - EPSSetTolerances(eps,1e-12,500); - EPSSetOperators(eps,*LHSOp,*RHSOp); - EPSSetWhichEigenpairs(eps,EPS_TARGET_MAGNITUDE); - EPSSetTarget(eps,pow(k0*3.44,2)); - ST st; - EPSGetST(eps,&st); - STSetType(st,STSINVERT); - EPSSetFromOptions(eps); - EPSSolve(eps);*/ SlepcEigenSolver *solver = new SlepcEigenSolver(MPI_COMM_WORLD); solver->SetOperators(*LHSOp,*RHSOp); - solver->SetTol(1e-12); - solver->SetMaxIter(500); - solver->SetNumModes(1); + solver->SetNumModes(nev); solver->SetWhichEigenpairs(SlepcEigenSolver::TARGET_MAGNITUDE); - solver->SetTarget(pow(k0*3.44,2)); - solver->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT); + solver->SetTarget(pow(k0,2)); solver->Solve(); - /*PetscInt num_converged; - PetscInt it_num; - PetscScalar lr, lc; - EPSGetConverged(eps,&num_converged); - std::cout << "num_converged = " << num_converged << "\n"; - EPSGetIterationNumber(eps,&it_num); - std::cout <<"it_num = " << it_num << "\n"; - EPSReasonView(eps,PETSC_VIEWER_STDOUT_WORLD); - Vec xi; - MatCreateVecs(*LHSOp,NULL,&xi); - EPSGetEigenpair(eps,0,&lr,&lc,*X,xi); - X->ResetArray(); - PetscReal re,im; - re = lr; - im = lc;*/ double re; solver->GetEigenvalue(0,re); Vector dummy2(block_trueOffsets[2]); solver->GetEigenvector(0,trueX); - std::cout << sqrt(re)/k0 << "\n"; + std::cout << "Effective index: " << sqrt(re)/k0 << "\n"; // 13. Extract the parallel grid function corresponding to the finite element - // approximation X. This is the local solution on each processor. Compute - // L2 error norms. + // approximation X. This is the local solution on each processor. ParGridFunction *exy(new ParGridFunction); ParGridFunction *ez(new ParGridFunction); exy->MakeRef(N_space, x.GetBlock(0), 0); @@ -367,7 +323,7 @@ int main(int argc, char *argv[]) u_sock << "solution\n" << *pmesh << *exy << "window_title 'Velocity'" << endl; u_sock << "keys Rjl!\n"; - // Make sure all ranks have sent their 'u' solution before initiating + // Make sure all ranks have sent their 'exy' solution before initiating // another set of GLVis connections (one from each rank): MPI_Barrier(pmesh->GetComm()); socketstream p_sock(vishost, visport); From a78aef812c00606382c9c9de6592a5da3f889816 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Mon, 18 May 2020 22:11:50 +0200 Subject: [PATCH 343/535] Changing access functions and adding NURBSext verify, both for safety --- fem/fespace.cpp | 2 ++ fem/fespace.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 8f2bff0dad..cd3a0fa1e2 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1507,6 +1507,8 @@ NURBSExtension *FiniteElementSpace::StealNURBSext() void FiniteElementSpace::UpdateNURBS() { + MFEM_VERIFY(NURBSext, "NURBSExt not defined."); + nvdofs = 0; nedofs = 0; nfdofs = 0; diff --git a/fem/fespace.hpp b/fem/fespace.hpp index c273df52bc..6d4688f6e7 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -537,8 +537,8 @@ public: void BuildDofToArrays(); const Table &GetElementToDofTable() const { return *elem_dof; } - const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; } - const Table &GetFaceToDofTable() const { return *face_dof; } + const Table *GetBdrElementToDofTable() const { return bdrElem_dof; } + const Table *GetFaceToDofTable() const { return face_dof; } int GetElementForDof(int i) const { return dof_elem_array[i]; } int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; } From 728777c5be276a2cf76e4c732a1ef897f82a9a26 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 18 May 2020 13:34:54 -0700 Subject: [PATCH 344/535] Address comments regarding VQFC, QFC, QF classes --- fem/coefficient.cpp | 23 +++++++++-------------- fem/coefficient.hpp | 25 +++++++++++++------------ fem/gridfunc.hpp | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 436fb862d5..0e13116aa6 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -777,7 +777,7 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient( QuadratureFunction *qf) - : VectorCoefficient(qf->GetVDim()), QuadF(qf), index(0), length(vdim) { } + : VectorCoefficient(qf->GetVDim()), QuadF(qf), index(0) { } void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( QuadratureFunction *qf) @@ -785,8 +785,7 @@ void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); index = 0; - length = qf->GetVDim(); - vdim = length; + vdim = qf->GetVDim(); QuadF = qf; } @@ -801,8 +800,7 @@ void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length) MFEM_VERIFY(_length <= QuadF->GetVDim() - index, "Length must be <= (QuadratureFunction length - index)"); - length = _length; - vdim = length; + vdim = _length; } void VectorQuadratureFunctionCoefficient::Eval(Vector &V, @@ -812,21 +810,18 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); QuadF->HostRead(); - if (index == 0 && length == QuadF->GetVDim()) + Vector temp; + QuadF->GetElementValues(T.ElementNo, ip.index, temp); + if (index == 0 && vdim == QuadF->GetVDim()) { - Vector temp; - QuadF->GetElementValues(T.ElementNo, ip.index, temp); V = temp; } else { - Vector temp; - QuadF->GetElementValues(T.ElementNo, ip.index, temp); - double *data = temp.HostReadWrite(); - V.SetSize(length); - for (int i = 0; i < length; i++) + V.SetSize(vdim); + for (int i = 0; i < vdim; i++) { - V(i) = data[index + i]; + V(i) = temp(index + i); } } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 494df9d510..317e0be519 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -948,14 +948,14 @@ public: class QuadratureFunction; -/// Vector quadrature function coefficient which requires that the quadrature rules used for this -/// vector coefficient be the same as those that live within the supplied QuadratureFunction. +/** @brief Vector quadrature function coefficient which requires that the + quadrature rules used for this vector coefficient be the same as those that + live within the supplied QuadratureFunction. */ class VectorQuadratureFunctionCoefficient : public VectorCoefficient { private: - QuadratureFunction *QuadF; //do not own + const QuadratureFunction *QuadF; //do not own int index; - int length; public: /// Constructor with a quadrature function as input @@ -963,12 +963,12 @@ public: void SetQuadratureFunction(QuadratureFunction *qf); - /// Set the starting index within the QuadFunc that'll be used to project outwards as well - /// as the corresponding length. The projected length should have the bounds of - /// 1 <= length <= (length QuadFunc - index). + /** Set the starting index within the QuadFunc that'll be used to + project outwards as well as the corresponding length. The projected length + should have the bounds of 1 <= length <= (length QuadFunc - index). */ void SetComponent(int _index, int _length); - QuadratureFunction *GetQuadFunction() const { return QuadF; } + const QuadratureFunction *GetQuadFunction() const { return QuadF; } using VectorCoefficient::Eval; virtual void Eval(Vector &V, ElementTransformation &T, @@ -977,12 +977,13 @@ public: virtual ~VectorQuadratureFunctionCoefficient() { } }; -/// Quadrature function coefficient which requires that the quadrature rules used for this -/// coefficient be the same as those that live within the supplied QuadratureFunction. +/** @brief Quadrature function coefficient which requires that the quadrature + rules used for this coefficient be the same as those that live within the + supplied QuadratureFunction. */ class QuadratureFunctionCoefficient : public Coefficient { private: - QuadratureFunction *QuadF; + const QuadratureFunction *QuadF; public: /// Constructor with a quadrature function as input @@ -990,7 +991,7 @@ public: void SetQuadratureFunction(QuadratureFunction *qf); - QuadratureFunction *GetQuadFunction() const { return QuadF; } + const QuadratureFunction *GetQuadFunction() const { return QuadF; } virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index b09a2a50e4..78d1c14b1f 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -638,6 +638,11 @@ public: global values. */ inline void GetElementValues(int idx, const int ip_num, Vector &values); + /// Return the quadrature function values at an integration point. + /** The result is stored in the Vector @a values as a copy to the + global values. */ + inline void GetElementValues(int idx, const int ip_num, Vector &values) const; + /// Return all values associated with mesh element @a idx in a DenseMatrix. /** The result is stored in the DenseMatrix @a values as a reference to the global values. @@ -749,6 +754,18 @@ inline void QuadratureFunction::GetElementValues(int idx, const int ip_num, values.NewDataAndSize(data + s_offset, vdim); } +inline void QuadratureFunction::GetElementValues(int idx, const int ip_num, + Vector &values) const +{ + const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim; + values.SetSize(vdim); + const double *q = data + s_offset; + for (int i = 0; i < values.Size(); i++) + { + values(i) = *(q++); + } +} + inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values) { const int s_offset = qspace->element_offsets[idx]; From e9e145b01bc31be278f4e45e2b6bfcfd16116225 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 18 May 2020 16:09:28 -0700 Subject: [PATCH 345/535] Change VQFC and QFC from holding pointers for QF to it being a reference --- fem/coefficient.cpp | 45 +++++++++++---------------------------------- fem/coefficient.hpp | 16 ++++++---------- 2 files changed, 17 insertions(+), 44 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 0e13116aa6..ddb909fb9a 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -776,28 +776,18 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh, #endif VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient( - QuadratureFunction *qf) - : VectorCoefficient(qf->GetVDim()), QuadF(qf), index(0) { } - -void VectorQuadratureFunctionCoefficient::SetQuadratureFunction( - QuadratureFunction *qf) -{ - MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); - - index = 0; - vdim = qf->GetVDim(); - QuadF = qf; -} + QuadratureFunction &qf) + : VectorCoefficient(qf.GetVDim()), QuadF(qf), index(0) { } void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length) { MFEM_VERIFY(_index >= 0, "Index must be >= 0"); - MFEM_VERIFY(_index < QuadF->GetVDim(), + MFEM_VERIFY(_index < QuadF.GetVDim(), "Index must be < QuadratureFunction length"); index = _index; MFEM_VERIFY(_length > 0, "Length must be > 0"); - MFEM_VERIFY(_length <= QuadF->GetVDim() - index, + MFEM_VERIFY(_length <= QuadF.GetVDim() - index, "Length must be <= (QuadratureFunction length - index)"); vdim = _length; @@ -807,12 +797,11 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { - MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); - QuadF->HostRead(); + QuadF.HostRead(); Vector temp; - QuadF->GetElementValues(T.ElementNo, ip.index, temp); - if (index == 0 && vdim == QuadF->GetVDim()) + QuadF.GetElementValues(T.ElementNo, ip.index, temp); + if (index == 0 && vdim == QuadF.GetVDim()) { V = temp; } @@ -829,29 +818,17 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, } QuadratureFunctionCoefficient::QuadratureFunctionCoefficient( - QuadratureFunction *qf) : QuadF(qf) + QuadratureFunction &qf) : QuadF(qf) { - MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction's vdim must be 1"); + MFEM_VERIFY(qf.GetVDim() == 1, "QuadratureFunction's vdim must be 1"); } -void QuadratureFunctionCoefficient::SetQuadratureFunction( - QuadratureFunction *qf) -{ - MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); - - MFEM_VERIFY(qf->GetVDim() == 1, "QuadratureFunction's vdim must be 1"); - QuadF = qf; -} - -/// Evaluate the function coefficient at a specific quadrature point double QuadratureFunctionCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) { - MFEM_VERIFY(QuadF, "QuadratureFunction must be set to a nonnull ptr"); - - QuadF->HostRead(); + QuadF.HostRead(); Vector temp(1); - QuadF->GetElementValues(T.ElementNo, ip.index, temp); + QuadF.GetElementValues(T.ElementNo, ip.index, temp); return temp[0]; } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 317e0be519..475a699845 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -954,21 +954,19 @@ class QuadratureFunction; class VectorQuadratureFunctionCoefficient : public VectorCoefficient { private: - const QuadratureFunction *QuadF; //do not own + const QuadratureFunction &QuadF; //do not own int index; public: /// Constructor with a quadrature function as input - VectorQuadratureFunctionCoefficient(QuadratureFunction *qf); - - void SetQuadratureFunction(QuadratureFunction *qf); + VectorQuadratureFunctionCoefficient(QuadratureFunction &qf); /** Set the starting index within the QuadFunc that'll be used to project outwards as well as the corresponding length. The projected length should have the bounds of 1 <= length <= (length QuadFunc - index). */ void SetComponent(int _index, int _length); - const QuadratureFunction *GetQuadFunction() const { return QuadF; } + const QuadratureFunction *GetQuadFunction() const { return &QuadF; } using VectorCoefficient::Eval; virtual void Eval(Vector &V, ElementTransformation &T, @@ -983,15 +981,13 @@ public: class QuadratureFunctionCoefficient : public Coefficient { private: - const QuadratureFunction *QuadF; + const QuadratureFunction &QuadF; public: /// Constructor with a quadrature function as input - QuadratureFunctionCoefficient(QuadratureFunction *qf); + QuadratureFunctionCoefficient(QuadratureFunction &qf); - void SetQuadratureFunction(QuadratureFunction *qf); - - const QuadratureFunction *GetQuadFunction() const { return QuadF; } + const QuadratureFunction *GetQuadFunction() const { return &QuadF; } virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); From 8e22e2b2e93b3ac5ef427539af7a2066608aa5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Mon, 18 May 2020 16:48:53 -0700 Subject: [PATCH 346/535] Don't build SLEPc when not asked --- linalg/slepc.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index a41ce0cf40..3f65d4f8f6 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -11,6 +11,10 @@ #include "../config/config.hpp" +#ifdef MFEM_USE_MPI +#ifdef MFEM_USE_PETSC +#ifdef MFEM_USE_SLEPC + #include "linalg.hpp" #include "slepc.h" @@ -332,3 +336,7 @@ void SlepcEigenSolver::SetSpectralTransformation( } } + +#endif // MFEM_USE_SLEPC +#endif // MFEM_USE_PETSC +#endif // MFEM_USE_MPI From 763a8c62367997d925808b86f83a7af6f7b3eca3 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 18 May 2020 16:52:50 -0700 Subject: [PATCH 347/535] Addressing some of the concerns in relations to FieldInterpolant class --- fem/field_interpolant.cpp | 330 ++++++++++------------------- fem/field_interpolant.hpp | 124 ++++------- fem/lininteg.cpp | 67 ++++++ fem/lininteg.hpp | 35 +++ tests/unit/fem/test_quadf_coef.cpp | 50 +++-- 5 files changed, 279 insertions(+), 327 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 84506c4f39..3ba555706d 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -18,216 +18,90 @@ namespace mfem { -void VectorQuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect) +void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc) { - const int nqp = IntRule->GetNPoints(); - const int vdim = vqfc.GetVDim(); - const int ndofs = fe.GetDof(); - Vector shape(ndofs); - Vector temp(vdim); - elvect.SetSize(vdim * ndofs); - elvect = 0.0; - for (int q = 0; q < nqp; q++) { - const IntegrationPoint &ip = IntRule->IntPoint(q); - Tr.SetIntPoint(&ip); - const double w = Tr.Weight() * ip.weight; - vqfc.Eval(temp, Tr, ip); - fe.CalcShape(ip, shape); - for (int ind = 0; ind < vdim; ind++) - { - for (int nd = 0; nd < ndofs; nd++) - { - elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind); - } - } - } -} - -void QuadratureIntegrator::AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect) -{ - const int nqp = IntRule->GetNPoints(); - const int ndofs = fe.GetDof(); - Vector shape(ndofs); - elvect.SetSize(ndofs); - elvect = 0.0; - for (int q = 0; q < nqp; q++) - { - const IntegrationPoint &ip = IntRule->IntPoint(q); - Tr.SetIntPoint (&ip); - const double w = Tr.Weight() * ip.weight; - double temp = qfc.Eval(Tr, ip); - fe.CalcShape(ip, shape); - shape *= (w * temp); - elvect += shape; - } -} - -//As a change to this we should have a setup phase where all the inverse matrices are stored off. -//If we do that we don't need to do the inverse and assemble step constantly. We can store the value in a vec -//and then just just use the DenseMatrix UseExternalData function. -//We can therefore provide a set-up phase that is run at the start of this if the vector this is all stored in is null. -//We should also provide a function that clears this. -//We'll need to assume that this is already an L2 space. -//One of the assumptions that we make down below is that our integration scheme is the same across all elements. -//If that isn't the case we might be able to still do things but things will most likely be slower. -void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &fes) -{ - int ndofs; - DenseMatrix mi; - DenseMatrixInverse inv(&mi); - const IntegrationRule* ir; - NE = fes.GetMesh()->GetNE(); - { - // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same - const FiniteElement &el = *fes.GetFE(0); - ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const FiniteElementSpace *fes = gf.FESpace(); + MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), + "FiniteElementSpace corresponding to this GridFunction should have the \ + same vdim of the VectorQuadratureFunctionCoefficient"); + + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); - const IntegrationRule *ir_qf = &qf->GetSpace()->GetElementIntRule(0); + const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); - // This should be the number of nodes available - ndofs = el.GetDof(); - } - int vdim = vqfc.GetVDim(); - - Vector rhs(ndofs * vdim), rhs_sub(ndofs); - Vector qfv(ndofs * vdim), qfv_sub(ndofs); - - VectorQuadratureIntegrator qi(vqfc); - qi.SetIntRule(ir); - - Array dbfi = *L2->GetDBFI(); - - if (!setup_disc) - { - m_all_data.SetSize(ndofs * ndofs * NE); - double* data = m_all_data.HostReadWrite(); - for (int e = 0; e < NE; e++) - { - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); - mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - dbfi[0]->AssembleElementMatrix(fe, eltr, mi); - } - setup_disc = true; - } - - double* data = m_all_data.HostReadWrite(); - Array dofs; - for (int e = 0; e < NE; e++) - { - qfv = 0.0; - mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(mi); - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); - qi.AssembleRHSElementVect(fe, eltr, rhs); - for (int ind = 0; ind < vdim; ind++) - { - qfv_sub.MakeRef(qfv, ndofs * ind); - rhs_sub.MakeRef(rhs, ndofs * ind); - inv.Mult(rhs_sub, qfv_sub); - } - fes.GetElementVDofs(e, dofs); - gf.SetSubVector(dofs, qfv); + "IntegrationRule for GridFunction and in QuadratureFunction \ + appear to be different"); } + gf.HostReadWrite(); + // Later on we might be able to swap this over to something that can run on + // on the gpu. + gf.ProjectDiscCoefficient(vqfc, GridFunction::ARITHMETIC); } -void FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &fes) +void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc) { - int ndofs; - DenseMatrix mi; - DenseMatrixInverse inv(&mi); - const IntegrationRule* ir; { - // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same - const FiniteElement &el = *fes.GetFE(0); - ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const FiniteElementSpace *fes = gf.FESpace(); + MFEM_VERIFY(fes->GetVDim() == 1, + "FiniteElementSpace corresponding to this GridFunction should have a vdim\ + of 1"); + + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); - // This should be the number of nodes available - ndofs = el.GetDof(); - } - - Vector rhs(ndofs); - Vector qfv(ndofs); - Array dofs; - - QuadratureIntegrator qi(qfc); - qi.SetIntRule(ir); - Array dbfi = *L2->GetDBFI(); - - if (!setup_disc) - { - m_all_data.SetSize(ndofs * ndofs * NE); - double* data = m_all_data.HostReadWrite(); - for (int e = 0; e < NE; e++) - { - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); - mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - dbfi[0]->AssembleElementMatrix(fe, eltr, mi); - } - setup_disc = true; - } - - - - double* data = m_all_data.HostReadWrite(); - for (int e = 0; e < NE; e++) - { - mi.UseExternalData((data + (ndofs * ndofs * e)), ndofs, ndofs); - inv.Factor(mi); - const FiniteElement &fe = *fes.GetFE(e); - ElementTransformation &eltr = *fes.GetElementTransformation(e); - qi.AssembleRHSElementVect(fe, eltr, rhs); - inv.Mult(rhs, qfv); - fes.GetElementDofs(e, dofs); - gf.SetSubVector(dofs, qfv); + "IntegrationRule for GridFunction and in QuadratureFunction \ + appear to be different"); } + gf.HostReadWrite(); + // Later on we might be able to swap this over to something that can run on + // on the gpu. + gf.ProjectDiscCoefficient(qfc, GridFunction::ARITHMETIC); } -void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &fes) +void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc) { - const IntegrationRule* ir; + FiniteElementSpace *fes = gf.FESpace(); { - // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same - const FiniteElement &el = *fes.GetFE(0); - ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), + "FiniteElementSpace corresponding to this GridFunction should have the \ + same vdim of the VectorQuadratureFunctionCoefficient"); + + // This is the best way I can think of to make sure the IntegrationRule in + // the FiniteElementSpace and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ + appear to be different"); } int vdim = vqfc.GetVDim(); int size = gf.Size() / vdim; - LinearForm *b = new LinearForm(&fes); - b->AddDomainIntegrator(new VectorQuadratureIntegrator(vqfc, ir)); + LinearForm *b = new LinearForm(fes); + b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, + &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); // If our FES is byVDIM then we're going to rearrange b to be in byNodes order - if (fes.GetOrdering() == Ordering::byVDIM) + if (fes->GetOrdering() == Ordering::byVDIM) { Vector tmp = *b; double* data = b->HostReadWrite(); @@ -242,7 +116,7 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, // L2->Assemble(); - GridFunction x(&fes); + GridFunction x(fes); x = 0.0; OperatorPtr A; Vector B, b_sub, X_sub, X; @@ -262,7 +136,7 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, L2->RecoverFEMSolution(X, *b, X_sub); } - if (fes.GetOrdering() == Ordering::byNODES) + if (fes->GetOrdering() == Ordering::byNODES) { gf = x; } @@ -279,29 +153,36 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, delete b; } -void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &fes) +void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, + QuadratureFunctionCoefficient &qfc) { - const IntegrationRule* ir; + FiniteElementSpace *fes = gf.FESpace(); { - // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + MFEM_VERIFY(fes->GetVDim() == 1, + "FiniteElementSpace corresponding to this GridFunction should have a \ + vdim of 1"); + + // This is the best way I can think of to make sure the + // IntegrationRule in the FiniteElementSpace // and the QuadratureSpace correspond to the same - const FiniteElement &el = *fes.GetFE(0); - ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ + appear to be different"); } - LinearForm *b = new LinearForm(&fes); - b->AddDomainIntegrator(new QuadratureIntegrator(qfc, ir)); + LinearForm *b = new LinearForm(fes); + b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, + &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); // L2->Assemble(); - GridFunction x(&fes); + GridFunction x(fes); x = 0.0; OperatorPtr A; Vector B, X; @@ -320,32 +201,38 @@ void FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, #ifdef MFEM_USE_MPI // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector // quadrature function coefficient. -void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - ParFiniteElementSpace &fes) +void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, + VectorQuadratureFunctionCoefficient &vqfc) { - const IntegrationRule* ir; + ParFiniteElementSpace *fes = gf.ParFESpace(); { - // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same - const FiniteElement &el = *fes.GetFE(0); - ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), + "FiniteElementSpace corresponding to this GridFunction should have the \ + same vdim of the VectorQuadratureFunctionCoefficient"); + + // This is the best way I can think of to make sure the IntegrationRule in + // the FiniteElementSpace and the QuadratureSpace correspond to the same + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ + appear to be different"); } int vdim = vqfc.GetVDim(); int size = gf.Size() / vdim; - ParLinearForm *b = new ParLinearForm(&fes); - b->AddDomainIntegrator(new VectorQuadratureIntegrator(vqfc, ir)); + ParLinearForm *b = new ParLinearForm(fes); + b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, + &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); // If our FES is byVDIM then we're going to rearrange b to be in byNodes order - if (fes.GetOrdering() == Ordering::byVDIM) + if (fes->GetOrdering() == Ordering::byVDIM) { Vector tmp = *b; double* data = b->HostReadWrite(); @@ -360,7 +247,7 @@ void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, // ParL2->Assemble(); - ParGridFunction x(&fes); + ParGridFunction x(fes); x = 0.0; OperatorPtr A; Vector B, b_sub, X_sub, X; @@ -379,7 +266,7 @@ void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, ParL2->RecoverFEMSolution(X, *b, X_sub); } - if (fes.GetOrdering() == Ordering::byNODES) + if (fes->GetOrdering() == Ordering::byNODES) { gf = x; } @@ -398,29 +285,34 @@ void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, } // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as // quadrature function coefficient. -void ParFieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc, - ParFiniteElementSpace &fes) +void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, + QuadratureFunctionCoefficient &qfc) { - const IntegrationRule* ir; + ParFiniteElementSpace *fes = gf.ParFESpace(); { - // This is the best way I can think of to make sure the IntegrationRule in the FiniteElementSpace + MFEM_VERIFY(fes->GetVDim() == 1, + "FiniteElementSpace corresponding to this GridFunction should have a \ + a vdim of 1"); + + // This is the best way I can think of to make sure the + // IntegrationRule in the FiniteElementSpace // and the QuadratureSpace correspond to the same - const FiniteElement &el = *fes.GetFE(0); - ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); + const FiniteElement &el = *fes->GetFE(0); + const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule in FiniteElementSpace and in QuadratureFunction appear to be different"); + "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ + appear to be different"); } - ParLinearForm *b = new ParLinearForm(&fes); - b->AddDomainIntegrator(new QuadratureIntegrator(qfc, ir)); + ParLinearForm *b = new ParLinearForm(fes); + b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, + &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); - // ParL2->Assemble(); - - ParGridFunction x(&fes); + ParGridFunction x(fes); x = 0.0; OperatorPtr A; Vector B, X; diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 212187fad2..fe4cc42d99 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -31,20 +31,20 @@ namespace mfem { -class FieldInterpolant +/** @brief Provides methods to take quadrature data and project it onto a field + * within a H1 or L2 space. + * + * */ +class Quad2FieldInterpolant { protected: - bool setup_disc; - bool setup_full; - Vector m_all_data; BilinearForm *L2; // Owned. CGSolver *cg; // Owned. - int NE; public: - // The FiniteElementSpace passed into here should have a vdim set to 1 in order for the - // MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with - // a VectorQuadratureFunctionCoefficient. - FieldInterpolant(FiniteElementSpace *fes) : setup_disc(false), setup_full(false) + /** The FiniteElementSpace passed into here should have a vdim set to 1 in order + for the MassIntegrator to work properly if the ProjectQuadratureCoefficient + method is used with a VectorQuadratureFunctionCoefficient.*/ + Quad2FieldInterpolant(FiniteElementSpace *fes) { L2 = new BilinearForm(fes); @@ -55,29 +55,25 @@ public: L2->AddDomainIntegrator(new MassIntegrator(ir)); L2->Assemble(); } - // This function takes a vector quadrature function coefficient and projects it onto a GridFunction that lives - // in L2 space. This function requires fes to be L2 finite element space that we're projecting onto. + /** @brief This function takes a vector quadrature function coefficient and projects + it onto a GridFunction that lives either in a H1 or L2 space.*/ + /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ void ProjectQuadratureDiscCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &fes); - // This function takes a quadrature function coefficient and projects it onto a GridFunction that lives - // in L2 space. This function requires fes to be L2 finite element space that we're projecting onto. + VectorQuadratureFunctionCoefficient &vqfc); + /** @brief This function takes a quadrature function coefficient and projects + it onto a GridFunction lives either in a H1 or L2 space.*/ + /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ void ProjectQuadratureDiscCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &fes); - // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector - // quadrature function coefficient. + QuadratureFunctionCoefficient &qfc); + /** This function takes a vector quadrature function coefficient and projects + it onto a GridFunction through the use of an L2 projection method.*/ void ProjectQuadratureCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - FiniteElementSpace &fes); - // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as - // quadrature function coefficient. + VectorQuadratureFunctionCoefficient &vqfc); + /** This function takes a quadrature function coefficient and projects it onto + a GridFunction through the use of an L2 projection method. */ void ProjectQuadratureCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc, - FiniteElementSpace &fes); - // Tells the ProjectQuadratureDiscCoefficient that they need to recalculate the data. - void SetupDiscReset() { setup_disc = false; } - // Tells the ProjectQuadratureCoefficient that they need to recalculate the data. + QuadratureFunctionCoefficient &qfc); + /// This function resets the internal bilinearform due to any mesh changes. virtual void FullReset() { L2->Update(); @@ -92,7 +88,7 @@ public: cg->SetRelTol(rel_tol); cg->SetAbsTol(abs_tol); } - ~FieldInterpolant() + virtual ~Quad2FieldInterpolant() { delete L2; delete cg; @@ -100,15 +96,15 @@ public: }; #ifdef MFEM_USE_MPI -class ParFieldInterpolant : public FieldInterpolant +class ParQuad2FieldInterpolant : public Quad2FieldInterpolant { protected: ParBilinearForm *ParL2; public: - // The ParFiniteElementSpace passed into here should have a vdim set to 1 in order for the - // MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with - // a VectorQuadratureFunctionCoefficient. - ParFieldInterpolant(ParFiniteElementSpace *pfes) : FieldInterpolant(pfes) + /** The ParFiniteElementSpace passed into here should have a vdim set to 1 in + order for the MassIntegrator to work properly if the ProjectQuadratureCoefficient + method is used with a VectorQuadratureFunctionCoefficient.*/ + ParQuad2FieldInterpolant(ParFiniteElementSpace *pfes) : Quad2FieldInterpolant(pfes) { ParL2 = new ParBilinearForm(pfes); @@ -119,25 +115,24 @@ public: ParL2->AddDomainIntegrator(new MassIntegrator(ir)); ParL2->Assemble(); } - // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector - // quadrature function coefficient. + /** @brief This function takes a vector quadrature function coefficient and projects + it onto a GridFunction that lives either in a H1 or L2 space.*/ + /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ void ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc, - ParFiniteElementSpace &fes); - // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as - // quadrature function coefficient. + VectorQuadratureFunctionCoefficient &vqfc); + /** @brief This function takes a quadrature function coefficient and projects + it onto a GridFunction that lives either in a H1 or L2 space.*/ + /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ void ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc, - ParFiniteElementSpace &fes); - // Tells the internal bilinearform needs to be reset in order to reset the sparse matrix + QuadratureFunctionCoefficient &qfc); + /// This function resets the internal bilinearform due to any mesh changes. virtual void FullReset() override { - FieldInterpolant::FullReset(); ParL2->Update(); ParL2->Assemble(); } - using FieldInterpolant::SetupCG; - // Setup the CG solver with an MPI communicator + using Quad2FieldInterpolant::SetupCG; + /// Setup the CG solver with an MPI communicator virtual void SetupCG(MPI_Comm _comm, double rel_tol = 1e-15, double abs_tol = 0.0, int print_level = 0, int max_iter = 2000) @@ -149,46 +144,11 @@ public: cg->SetAbsTol(abs_tol); } - ~ParFieldInterpolant() + virtual ~ParQuad2FieldInterpolant() { delete ParL2; } }; #endif - -class VectorQuadratureIntegrator : public LinearFormIntegrator -{ -private: - VectorQuadratureFunctionCoefficient &vqfc; - -public: - VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc) - : vqfc(vqfc) { } - VectorQuadratureIntegrator(VectorQuadratureFunctionCoefficient &vqfc, - const IntegrationRule *ir) - : LinearFormIntegrator(ir), vqfc(vqfc) { } - - using LinearFormIntegrator::AssembleRHSElementVect; - void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, Vector &elvect); -}; - -class QuadratureIntegrator : public LinearFormIntegrator -{ -private: - QuadratureFunctionCoefficient &qfc; - -public: - QuadratureIntegrator(QuadratureFunctionCoefficient &qfc) : qfc(qfc) { } - QuadratureIntegrator(QuadratureFunctionCoefficient &qfc, - const IntegrationRule *ir) - : LinearFormIntegrator(ir), qfc(qfc) { } - - using LinearFormIntegrator::AssembleRHSElementVect; - void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, Vector &elvect); -}; - } - #endif diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index adc9355d66..7d5e85d5d6 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -768,4 +768,71 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( } } +void VectorQuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect) +{ + + const IntegrationRule *ir = IntRule; + + if (ir == NULL) + { + int intorder = 2 * fe.GetOrder(); + ir = &IntRules.Get(fe.GetGeomType(), intorder); + } + + const int nqp = IntRule->GetNPoints(); + const int vdim = vqfc.GetVDim(); + const int ndofs = fe.GetDof(); + Vector shape(ndofs); + Vector temp(vdim); + elvect.SetSize(vdim * ndofs); + elvect = 0.0; + for (int q = 0; q < nqp; q++) + { + const IntegrationPoint &ip = IntRule->IntPoint(q); + Tr.SetIntPoint(&ip); + const double w = Tr.Weight() * ip.weight; + vqfc.Eval(temp, Tr, ip); + fe.CalcShape(ip, shape); + for (int ind = 0; ind < vdim; ind++) + { + for (int nd = 0; nd < ndofs; nd++) + { + elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind); + } + } + } +} + +void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect) +{ + + const IntegrationRule *ir = IntRule; + + if (ir == NULL) + { + int intorder = 2 * fe.GetOrder(); + ir = &IntRules.Get(fe.GetGeomType(), intorder); + } + + const int nqp = IntRule->GetNPoints(); + const int ndofs = fe.GetDof(); + Vector shape(ndofs); + elvect.SetSize(ndofs); + elvect = 0.0; + for (int q = 0; q < nqp; q++) + { + const IntegrationPoint &ip = IntRule->IntPoint(q); + Tr.SetIntPoint (&ip); + const double w = Tr.Weight() * ip.weight; + double temp = qfc.Eval(Tr, ip); + fe.CalcShape(ip, shape); + shape *= (w * temp); + elvect += shape; + } +} + } diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index 1b8c2e19cc..85e3c754f6 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -426,6 +426,41 @@ public: Vector &elvect); }; +/** Class for domain integration of L(v) := (f, v), where + f=(f1,...,fn) and v=(v1,...,vn). that makes use of + VectorQuadratureFunctionCoefficient*/ +class VectorQuadratureLFIntegrator : public LinearFormIntegrator +{ +private: + VectorQuadratureFunctionCoefficient &vqfc; + +public: + VectorQuadratureLFIntegrator(VectorQuadratureFunctionCoefficient &vqfc, + const IntegrationRule *ir) + : LinearFormIntegrator(ir), vqfc(vqfc) { } + + using LinearFormIntegrator::AssembleRHSElementVect; + void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, Vector &elvect); +}; + +/** Class for domain integration L(v) := (f, v) that makes use + of QuadratureFunctionCoefficient. */ +class QuadratureLFIntegrator : public LinearFormIntegrator +{ +private: + QuadratureFunctionCoefficient &qfc; + +public: + QuadratureLFIntegrator(QuadratureFunctionCoefficient &qfc, + const IntegrationRule *ir) + : LinearFormIntegrator(ir), qfc(qfc) { } + + using LinearFormIntegrator::AssembleRHSElementVect; + void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, Vector &elvect); +}; + } #endif diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 8cca7aa65c..8ad5ad6754 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -64,18 +64,18 @@ TEST_CASE("Quadrature Function Coefficients", { //X has dims nqpts x sdim x ne quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( - i * nqpts * vdim) + (j * nqpts) + k ); + i * nqpts * vdim) + (j * nqpts) + k ); } } } } - QuadratureFunctionCoefficient qfc(&quadf_coeff); - VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); + QuadratureFunctionCoefficient qfc(quadf_coeff); + VectorQuadratureFunctionCoefficient qfvc(quadf_vcoeff); H1_FECollection fec_h1(order_h1, dim); FiniteElementSpace fespace_hv1(&mesh, &fec_h1, 1); - FieldInterpolant fi(&fespace_hv1); + Quad2FieldInterpolant fi(&fespace_hv1); fi.SetupCG(); SECTION("Operators on VecQuadFuncCoeff") @@ -113,7 +113,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -137,7 +137,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -157,7 +157,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + fi.ProjectQuadratureCoefficient(g0, qfvc); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -176,7 +176,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + fi.ProjectQuadratureCoefficient(g0, qfvc); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -195,10 +195,9 @@ TEST_CASE("Quadrature Function Coefficients", GridFunction g0(&fespace_l2); GridFunction gtrue(&fespace_l2); - fi.SetupDiscReset(); - // When using an L2 FE space of the same order as the mesh, the below highlights - // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. + // that the ProjectDiscCoeff method is just taking the quadrature point + // values and making them node values. { GridFunction nodes_z(&fespace_hv1); @@ -210,7 +209,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfc); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -238,7 +237,7 @@ TEST_CASE("Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfc, fespace_h1); + fi.ProjectQuadratureCoefficient(g0, qfc); gtrue -= g0; REQUIRE(gtrue.Norml2() < tol); } @@ -297,18 +296,18 @@ TEST_CASE("Parallel Quadrature Function Coefficients", { //X has dims nqpts x sdim x ne quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( - i * nqpts * vdim) + (j * nqpts) + k ); + i * nqpts * vdim) + (j * nqpts) + k ); } } } } - QuadratureFunctionCoefficient qfc(&quadf_coeff); - VectorQuadratureFunctionCoefficient qfvc(&quadf_vcoeff); + QuadratureFunctionCoefficient qfc(quadf_coeff); + VectorQuadratureFunctionCoefficient qfvc(quadf_vcoeff); H1_FECollection fec_h1(order_h1, dim); ParFiniteElementSpace fespace_hv1(&mesh, &fec_h1, 1); - ParFieldInterpolant fi(&fespace_hv1); + ParQuad2FieldInterpolant fi(&fespace_hv1); fi.SetupCG(MPI_COMM_WORLD); SECTION("Operators on VecQuadFuncCoeff") @@ -345,7 +344,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -375,7 +374,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfvc); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -401,7 +400,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + fi.ProjectQuadratureCoefficient(g0, qfvc); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -429,7 +428,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc, fespace_h1); + fi.ProjectQuadratureCoefficient(g0, qfvc); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -454,10 +453,9 @@ TEST_CASE("Parallel Quadrature Function Coefficients", ParGridFunction g0(&fespace_l2); ParGridFunction gtrue(&fespace_l2); - fi.SetupDiscReset(); - // When using an L2 FE space of the same order as the mesh, the below highlights - // that the ProjectDiscCoeff method is just taking the quadrature point values and making them node values. + // that the ProjectDiscCoeff method is just taking the quadrature point + // values and making them node values. { ParGridFunction nodes_z(&fespace_hv1); @@ -469,7 +467,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfc, fespace_l2); + fi.ProjectQuadratureDiscCoefficient(g0, qfc); gtrue -= g0; double lerr = gtrue.Norml2(); @@ -501,7 +499,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", } g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfc, fespace_h1); + fi.ProjectQuadratureCoefficient(g0, qfc); gtrue -= g0; double lerr = gtrue.Norml2(); From 069ad591431c01b78ae20ad5eb58649fefe46925 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Mon, 18 May 2020 16:54:29 -0700 Subject: [PATCH 348/535] minor --- CHANGELOG | 36 ++++++++++++++++++++---------------- config/cmake/config.hpp.in | 2 +- config/config.hpp.in | 2 +- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f0387f8456..ba0b6b2d97 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,8 +23,17 @@ Meshing improvements Hessian for r-adaptivity using discrete fields, and allows use of skewness and orientation based metrics. -Improved GPU capabilities -------------------------- +Performance improvements +------------------------ +- Added support for explicit vectorization in the high-performance templated + code, which can now take advantage of specific intrinsics classes on the + following architectures: + - x86 (SSE/AVX/AVX2/AVX512), + - Power8 & Power9 (VSX), + - BG/Q (QPX). + These are now enabled by default, and can be disabled with MFEM_USE_SIMD=NO. + See the new file linalg/simd.hpp and the new directory linalg/simd. + - Added support for Chebyshev accelerated polynomial smoother on GPU. Discretization improvements @@ -52,10 +61,17 @@ Linear and nonlinear solvers - Added initial support for h- and p-multigrid solvers and preconditioners for matrix-based and matrix-free discretizations with basic GPU capability. +- Added a new IterativeSolverMonitor class that allows to monitor the residual + and solution during the solving process of an IterativeSolver after every + iteration. + - Block arrays of parallel matrices can now be merged into a single parallel matrix with the function HypreParMatrixFromBlocks. This could be useful for solving block systems with parallel direct solvers such as STRUMPACK. +- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the + solver can work with non-SPD preconditioner B. + New and updated examples and miniapps ------------------------------------- - Added a new example, Example 25/25p, to demonstrate the use of a Perfectly @@ -93,26 +109,14 @@ Improved testing Miscellaneous ------------- -- Added support for explicit vectorization for the high-performance templated - code, which can now take advantage of specific intrinsics classes on the - following architectures: - - x86 (SSE/AVX/AVX2/AVX512), - - Power8 & Power9 (VSX), - - BG/Q (QPX). - It is now enabled by default, and can be disabled with MFEM_USE_SIMD=NO. - -- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the - solver can work with non-SPD preconditioner B. - - Added support for ADIOS2 for parallel I/O with ParaView visualization. The classes adios2stream and ADIOS2DataCollection are introduced in mfem as the interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the entire spatial and temporal data. In addition, ADIOS2 allows for setting a user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16. -- Added a new IterativeSolverMonitor class that allows to monitor the residual - and solution during the solving process of an IterativeSolver after every - iteration. +- Various other simplifications, extensions, and bugfixes in the code. + Version 4.1, released on March 10, 2020 ======================================= diff --git a/config/cmake/config.hpp.in b/config/cmake/config.hpp.in index 5c6fc0c0ce..4bcbf59d88 100644 --- a/config/cmake/config.hpp.in +++ b/config/cmake/config.hpp.in @@ -107,7 +107,7 @@ // Enable MFEM functionality based on the Sidre library #cmakedefine MFEM_USE_SIDRE -// Enable the high performance templated classes to use SIMD +// Enable the use of SIMD in the high performance templated classes #cmakedefine MFEM_USE_SIMD // Enable MFEM functionality based on Conduit diff --git a/config/config.hpp.in b/config/config.hpp.in index 32ba404a9b..56a8cee7da 100644 --- a/config/config.hpp.in +++ b/config/config.hpp.in @@ -106,7 +106,7 @@ // Enable Sidre support // #define MFEM_USE_SIDRE -// Enable the high performance templated classes to use SIMD +// Enable the use of SIMD in the high performance templated classes // #define MFEM_USE_SIMD // Enable Conduit support From 17580ca0448affeb4400d882e5f2c5fd60f08e8f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 18 May 2020 18:56:35 -0700 Subject: [PATCH 349/535] make style and a few small edits to address some other concerns --- fem/field_interpolant.cpp | 66 +++++++++++++++++------------- fem/field_interpolant.hpp | 33 +++++++++++---- fem/lininteg.cpp | 15 +++---- fem/lininteg.hpp | 4 +- tests/unit/fem/test_quadf_coef.cpp | 4 +- 5 files changed, 75 insertions(+), 47 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 3ba555706d..454b2f8ae5 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -19,20 +19,20 @@ namespace mfem { void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc) + VectorQuadratureFunctionCoefficient &vqfc) { { const FiniteElementSpace *fes = gf.FESpace(); MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), - "FiniteElementSpace corresponding to this GridFunction should have the \ + "FiniteElementSpace corresponding to this GridFunction should have the \ same vdim of the VectorQuadratureFunctionCoefficient"); - + const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), "IntegrationRule for GridFunction and in QuadratureFunction \ @@ -45,20 +45,20 @@ void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc) + QuadratureFunctionCoefficient &qfc) { { const FiniteElementSpace *fes = gf.FESpace(); MFEM_VERIFY(fes->GetVDim() == 1, - "FiniteElementSpace corresponding to this GridFunction should have a vdim\ + "FiniteElementSpace corresponding to this GridFunction should have a vdim\ of 1"); - + const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - + MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && (ir->GetNPoints() == ir_qf->GetNPoints()), "IntegrationRule for GridFunction and in QuadratureFunction \ @@ -71,19 +71,21 @@ void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, } void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc) + VectorQuadratureFunctionCoefficient &vqfc) { FiniteElementSpace *fes = gf.FESpace(); { + MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ + function.") MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), - "FiniteElementSpace corresponding to this GridFunction should have the \ + "FiniteElementSpace corresponding to this GridFunction should have the \ same vdim of the VectorQuadratureFunctionCoefficient"); // This is the best way I can think of to make sure the IntegrationRule in // the FiniteElementSpace and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && @@ -97,7 +99,7 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, LinearForm *b = new LinearForm(fes); b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, - &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); + &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); // If our FES is byVDIM then we're going to rearrange b to be in byNodes order @@ -154,12 +156,14 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, delete b; } void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc) + QuadratureFunctionCoefficient &qfc) { FiniteElementSpace *fes = gf.FESpace(); { + MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ + function.") MFEM_VERIFY(fes->GetVDim() == 1, - "FiniteElementSpace corresponding to this GridFunction should have a \ + "FiniteElementSpace corresponding to this GridFunction should have a \ vdim of 1"); // This is the best way I can think of to make sure the @@ -167,7 +171,7 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, // and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && @@ -176,8 +180,8 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, appear to be different"); } LinearForm *b = new LinearForm(fes); - b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, - &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); + b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, + &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); // L2->Assemble(); @@ -202,19 +206,21 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, // This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector // quadrature function coefficient. void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc) + VectorQuadratureFunctionCoefficient &vqfc) { ParFiniteElementSpace *fes = gf.ParFESpace(); { + MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ + function.") MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), - "FiniteElementSpace corresponding to this GridFunction should have the \ + "FiniteElementSpace corresponding to this GridFunction should have the \ same vdim of the VectorQuadratureFunctionCoefficient"); // This is the best way I can think of to make sure the IntegrationRule in // the FiniteElementSpace and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && @@ -227,8 +233,8 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, int size = gf.Size() / vdim; ParLinearForm *b = new ParLinearForm(fes); - b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, - &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); + b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, + &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); // If our FES is byVDIM then we're going to rearrange b to be in byNodes order @@ -286,12 +292,14 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, // This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as // quadrature function coefficient. void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc) + QuadratureFunctionCoefficient &qfc) { ParFiniteElementSpace *fes = gf.ParFESpace(); { + MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ + function.") MFEM_VERIFY(fes->GetVDim() == 1, - "FiniteElementSpace corresponding to this GridFunction should have a \ + "FiniteElementSpace corresponding to this GridFunction should have a \ a vdim of 1"); // This is the best way I can think of to make sure the @@ -299,7 +307,7 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, // and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); + 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && @@ -308,8 +316,8 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, appear to be different"); } ParLinearForm *b = new ParLinearForm(fes); - b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, - &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); + b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, + &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); ParGridFunction x(fes); diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index fe4cc42d99..3b7c70a9fa 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -38,13 +38,13 @@ namespace mfem class Quad2FieldInterpolant { protected: - BilinearForm *L2; // Owned. - CGSolver *cg; // Owned. + BilinearForm *L2 = nullptr; // Owned. + CGSolver *cg = nullptr; // Owned. public: /** The FiniteElementSpace passed into here should have a vdim set to 1 in order for the MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with a VectorQuadratureFunctionCoefficient.*/ - Quad2FieldInterpolant(FiniteElementSpace *fes) + Quad2FieldInterpolant(FiniteElementSpace *fes) { L2 = new BilinearForm(fes); @@ -82,6 +82,10 @@ public: virtual void SetupCG(double rel_tol = 1e-15, double abs_tol = 0.0, int print_level = 0, int max_iter = 2000) { + if (cg) + { + delete cg; + } cg = new CGSolver(); cg->SetPrintLevel(print_level); cg->SetMaxIter(max_iter); @@ -90,21 +94,32 @@ public: } virtual ~Quad2FieldInterpolant() { - delete L2; - delete cg; + if (L2) + { + delete L2; + } + if (cg) + { + delete cg; + } } + +protected: + // Should only be needed for children classes to avoid unneeded resources + // from being allocated. + Quad2FieldInterpolant() {} }; #ifdef MFEM_USE_MPI class ParQuad2FieldInterpolant : public Quad2FieldInterpolant { protected: - ParBilinearForm *ParL2; + ParBilinearForm *ParL2 = nullptr; public: /** The ParFiniteElementSpace passed into here should have a vdim set to 1 in order for the MassIntegrator to work properly if the ProjectQuadratureCoefficient method is used with a VectorQuadratureFunctionCoefficient.*/ - ParQuad2FieldInterpolant(ParFiniteElementSpace *pfes) : Quad2FieldInterpolant(pfes) + ParQuad2FieldInterpolant(ParFiniteElementSpace *pfes) { ParL2 = new ParBilinearForm(pfes); @@ -137,6 +152,10 @@ public: double abs_tol = 0.0, int print_level = 0, int max_iter = 2000) { + if (cg) + { + delete cg; + } cg = new CGSolver(_comm); cg->SetPrintLevel(print_level); cg->SetMaxIter(max_iter); diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 7d5e85d5d6..44f30df6b9 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -768,13 +768,14 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( } } -void VectorQuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect) +void VectorQuadratureLFIntegrator::AssembleRHSElementVect( + const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect) { const IntegrationRule *ir = IntRule; - + if (ir == NULL) { int intorder = 2 * fe.GetOrder(); @@ -806,12 +807,12 @@ void VectorQuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &f } void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect) + ElementTransformation &Tr, + Vector &elvect) { const IntegrationRule *ir = IntRule; - + if (ir == NULL) { int intorder = 2 * fe.GetOrder(); diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index 85e3c754f6..f227c61bbb 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -436,7 +436,7 @@ private: public: VectorQuadratureLFIntegrator(VectorQuadratureFunctionCoefficient &vqfc, - const IntegrationRule *ir) + const IntegrationRule *ir) : LinearFormIntegrator(ir), vqfc(vqfc) { } using LinearFormIntegrator::AssembleRHSElementVect; @@ -453,7 +453,7 @@ private: public: QuadratureLFIntegrator(QuadratureFunctionCoefficient &qfc, - const IntegrationRule *ir) + const IntegrationRule *ir) : LinearFormIntegrator(ir), qfc(qfc) { } using LinearFormIntegrator::AssembleRHSElementVect; diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 8ad5ad6754..1ccca89d75 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -64,7 +64,7 @@ TEST_CASE("Quadrature Function Coefficients", { //X has dims nqpts x sdim x ne quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( - i * nqpts * vdim) + (j * nqpts) + k ); + i * nqpts * vdim) + (j * nqpts) + k ); } } } @@ -296,7 +296,7 @@ TEST_CASE("Parallel Quadrature Function Coefficients", { //X has dims nqpts x sdim x ne quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( - i * nqpts * vdim) + (j * nqpts) + k ); + i * nqpts * vdim) + (j * nqpts) + k ); } } } From c915cc791f0f51018ad54aa60aed2be13fe5d11b Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 18 May 2020 20:12:22 -0700 Subject: [PATCH 350/535] Improve on verification checks related to making sure integration rules are the same --- fem/field_interpolant.cpp | 77 +++++++++++++++++++++------------------ fem/field_interpolant.hpp | 24 +++++++----- fem/lininteg.cpp | 4 +- 3 files changed, 57 insertions(+), 48 deletions(-) diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp index 454b2f8ae5..451ade8980 100644 --- a/fem/field_interpolant.cpp +++ b/fem/field_interpolant.cpp @@ -33,9 +33,8 @@ void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && - (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule for GridFunction and in QuadratureFunction \ + MFEM_VERIFY(ir == ir_qf, + "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ appear to be different"); } gf.HostReadWrite(); @@ -59,9 +58,8 @@ void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && - (ir->GetNPoints() == ir_qf->GetNPoints()), - "IntegrationRule for GridFunction and in QuadratureFunction \ + MFEM_VERIFY(ir == ir_qf, + "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ appear to be different"); } gf.HostReadWrite(); @@ -81,17 +79,22 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, "FiniteElementSpace corresponding to this GridFunction should have the \ same vdim of the VectorQuadratureFunctionCoefficient"); - // This is the best way I can think of to make sure the IntegrationRule in - // the FiniteElementSpace and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && - (ir->GetNPoints() == ir_qf->GetNPoints()), + MFEM_VERIFY(ir == ir_qf, "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ appear to be different"); + + const FiniteElementSpace* l2_fes = L2->FESpace(); + const FiniteElement &l2_el = *l2_fes->GetFE(0); + const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); + MFEM_VERIFY(ir_l2 == ir_qf, + "IntegrationRule in FiniteElementSpace supplied to class and \ + in QuadratureFunction appear to be different"); } int vdim = vqfc.GetVDim(); @@ -116,8 +119,6 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, } } - // L2->Assemble(); - GridFunction x(fes); x = 0.0; OperatorPtr A; @@ -131,7 +132,6 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, b_sub.MakeRef(*b, offset, size); X_sub.MakeRef(x, offset, size); L2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); - // Fix this to be more efficient; cg->SetOperator(*A); cg->Mult(B, X); // Recover the solution as a finite element grid function. @@ -166,26 +166,28 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, "FiniteElementSpace corresponding to this GridFunction should have a \ vdim of 1"); - // This is the best way I can think of to make sure the - // IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && - (ir->GetNPoints() == ir_qf->GetNPoints()), + MFEM_VERIFY(ir == ir_qf, "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ appear to be different"); + + const FiniteElementSpace* l2_fes = L2->FESpace(); + const FiniteElement &l2_el = *l2_fes->GetFE(0); + const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); + MFEM_VERIFY(ir_l2 == ir_qf, + "IntegrationRule in FiniteElementSpace supplied to class and \ + in QuadratureFunction appear to be different"); } LinearForm *b = new LinearForm(fes); b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); b->Assemble(); - // L2->Assemble(); - GridFunction x(fes); x = 0.0; OperatorPtr A; @@ -203,8 +205,6 @@ void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, } #ifdef MFEM_USE_MPI -// This function takes a vector quadrature function coefficient and projects it onto a GridFunction of the same space as vector -// quadrature function coefficient. void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, VectorQuadratureFunctionCoefficient &vqfc) { @@ -216,17 +216,22 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, "FiniteElementSpace corresponding to this GridFunction should have the \ same vdim of the VectorQuadratureFunctionCoefficient"); - // This is the best way I can think of to make sure the IntegrationRule in - // the FiniteElementSpace and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = vqfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && - (ir->GetNPoints() == ir_qf->GetNPoints()), + MFEM_VERIFY(ir == ir_qf, "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ appear to be different"); + + const ParFiniteElementSpace* l2_fes = ParL2->ParFESpace(); + const FiniteElement &l2_el = *l2_fes->GetFE(0); + const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); + MFEM_VERIFY(ir_l2 == ir_qf, + "IntegrationRule in FiniteElementSpace supplied to class and \ + in QuadratureFunction appear to be different"); } int vdim = vqfc.GetVDim(); @@ -251,8 +256,6 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, } } - // ParL2->Assemble(); - ParGridFunction x(fes); x = 0.0; OperatorPtr A; @@ -289,8 +292,7 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, delete b; } -// This function takes a quadrature function coefficient and projects it onto a GridFunction of the same space as -// quadrature function coefficient. + void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, QuadratureFunctionCoefficient &qfc) { @@ -302,18 +304,22 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, "FiniteElementSpace corresponding to this GridFunction should have a \ a vdim of 1"); - // This is the best way I can think of to make sure the - // IntegrationRule in the FiniteElementSpace - // and the QuadratureSpace correspond to the same const FiniteElement &el = *fes->GetFE(0); const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 1)); const QuadratureFunction* qf = qfc.GetQuadFunction(); const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY((ir->GetOrder() == ir_qf->GetOrder()) && - (ir->GetNPoints() == ir_qf->GetNPoints()), + MFEM_VERIFY(ir == ir_qf, "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ appear to be different"); + + const ParFiniteElementSpace* l2_fes = ParL2->ParFESpace(); + const FiniteElement &l2_el = *l2_fes->GetFE(0); + const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), + 2 * el.GetOrder() + 1)); + MFEM_VERIFY(ir_l2 == ir_qf, + "IntegrationRule in FiniteElementSpace supplied to class and \ + in QuadratureFunction appear to be different"); } ParLinearForm *b = new ParLinearForm(fes); b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, @@ -327,7 +333,6 @@ void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, Array ess_tdof_list; ParL2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - // Fix this to be more efficient cg->SetOperator(*A); cg->Mult(B, X); // Recover the solution as a finite element grid function. diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp index 3b7c70a9fa..21b1d2186f 100644 --- a/fem/field_interpolant.hpp +++ b/fem/field_interpolant.hpp @@ -32,20 +32,21 @@ namespace mfem { /** @brief Provides methods to take quadrature data and project it onto a field - * within a H1 or L2 space. - * - * */ + within a H1 or L2 space.*/ class Quad2FieldInterpolant { protected: BilinearForm *L2 = nullptr; // Owned. CGSolver *cg = nullptr; // Owned. public: - /** The FiniteElementSpace passed into here should have a vdim set to 1 in order - for the MassIntegrator to work properly if the ProjectQuadratureCoefficient - method is used with a VectorQuadratureFunctionCoefficient.*/ + /** The FiniteElementSpace passed into here should be of the same order + and space as those used within the ProjectQuadratureCoefficient method. + The vdim on the FES should be equal to 1, so the L2 method can work on + either scalar or vector GridFunctions.*/ Quad2FieldInterpolant(FiniteElementSpace *fes) { + MFEM_VERIFY(fes->GetVDim() == 1, "FiniteElementSpace should have a \ + a vdim of 1"); L2 = new BilinearForm(fes); const FiniteElement &el = *fes->GetFE(0); @@ -114,13 +115,16 @@ protected: class ParQuad2FieldInterpolant : public Quad2FieldInterpolant { protected: - ParBilinearForm *ParL2 = nullptr; + ParBilinearForm *ParL2 = nullptr; // Owned public: - /** The ParFiniteElementSpace passed into here should have a vdim set to 1 in - order for the MassIntegrator to work properly if the ProjectQuadratureCoefficient - method is used with a VectorQuadratureFunctionCoefficient.*/ + /** The FiniteElementSpace passed into here should be of the same order + and space as those used within the ProjectQuadratureCoefficient method. + The vdim on the FES should be equal to 1, so the L2 method can work on + either scalar or vector GridFunctions.*/ ParQuad2FieldInterpolant(ParFiniteElementSpace *pfes) { + MFEM_VERIFY(pfes->GetVDim() == 1, "FiniteElementSpace should have a \ + a vdim of 1"); ParL2 = new ParBilinearForm(pfes); const FiniteElement &el = *pfes->GetFE(0); diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 44f30df6b9..96a87d7e36 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -774,7 +774,7 @@ void VectorQuadratureLFIntegrator::AssembleRHSElementVect( Vector &elvect) { - const IntegrationRule *ir = IntRule; + const IntegrationRule *ir = &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); if (ir == NULL) { @@ -811,7 +811,7 @@ void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, Vector &elvect) { - const IntegrationRule *ir = IntRule; + const IntegrationRule *ir = &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); if (ir == NULL) { From 03ed06bd7a443bf53319c96d2831e618b8f681a6 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 18 May 2020 20:13:16 -0700 Subject: [PATCH 351/535] make style --- fem/lininteg.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 96a87d7e36..ba68d9a2e2 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -774,7 +774,8 @@ void VectorQuadratureLFIntegrator::AssembleRHSElementVect( Vector &elvect) { - const IntegrationRule *ir = &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); + const IntegrationRule *ir = + &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); if (ir == NULL) { @@ -811,7 +812,8 @@ void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, Vector &elvect) { - const IntegrationRule *ir = &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); + const IntegrationRule *ir = + &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); if (ir == NULL) { From 100cae115811e0026c312e7e96b58790cbe3357e Mon Sep 17 00:00:00 2001 From: Tzanio Date: Tue, 19 May 2020 10:30:47 -0700 Subject: [PATCH 352/535] minor --- CHANGELOG | 4 ++-- fem/gridfunc.cpp | 18 +++++++++--------- fem/gridfunc.hpp | 8 +++----- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f840735b28..2623828937 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -39,9 +39,9 @@ Discretization improvements VectorFEDivergenceIntegrator. - Improved the documentation of the GridFunction GetValue and GetVectorValue - methods. Expanded the GetValue and GetVectorValue methods which accept an + methods. Expanded the GetValue and GetVectorValue methods which accept an ElementTransformation argument to support evaluation on boundary elements - and, in the continuous field case, arbirtrary mesh edges and faces. + and, in the continuous field case, arbitrary mesh edges and faces. Linear and nonlinear solvers ---------------------------- diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 7626e73c18..cf955b1047 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -729,14 +729,14 @@ double GridFunction::GetValue(ElementTransformation &T, if (fes->FEColl()->GetContType() == FiniteElementCollection::CONTINUOUS) { - // This is a continuous field so we can evaluate it on the boudnary + // This is a continuous field so we can evaluate it on the boundary. fe = fes->GetBE(T.ElementNo); fes->GetBdrElementDofs(T.ElementNo, dofs); } else { - // This is a discontinuous field which cannot be evaluated on - // the boudary so we'll evaluate it in the neighboring elememt. + // This is a discontinuous field which cannot be evaluated on the + // boundary so we'll evaluate it in the neighboring element. FaceElementTransformations * FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); @@ -865,14 +865,14 @@ void GridFunction::GetVectorValue(ElementTransformation &T, if (fes->FEColl()->GetContType() == FiniteElementCollection::CONTINUOUS) { - // This is a continuous field so we can evaluate it on the boudnary + // This is a continuous field so we can evaluate it on the boundary. fes->GetBdrElementVDofs(T.ElementNo, vdofs); fe = fes->GetBE(T.ElementNo); } else { // This is a discontinuous vector field which cannot be evaluated on - // the boudary so we'll evaluate it in the neighboring elememt. + // the boundary so we'll evaluate it in the neighboring element. FaceElementTransformations * FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); @@ -2989,15 +2989,15 @@ void GridFunction::ComputeElementLpErrors(const double p, loc_errs.SetSize(vals.Width()); if (!v_weight) { - // compute the lengths of the errors at the integration points - // thus the vector norm is rotationally invariant + // compute the lengths of the errors at the integration points thus the + // vector norm is rotationally invariant vals.Norm2(loc_errs); } else { v_weight->Eval(exact_vals, *T, *ir); - // column-wise dot product of the vector error (in vals) and the - // vector weight (in exact_vals) + // column-wise dot product of the vector error (in vals) and the vector + // weight (in exact_vals) for (int j = 0; j < vals.Width(); j++) { double err = 0.0; diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index e81d697ea7..e73568a3e1 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -174,7 +174,7 @@ public: @warning These methods retrieve and use the ElementTransformation object from the mfem::Mesh. This can alter the state of the element - transformation object and can alsp lead to unexpected results when the + transformation object and can also lead to unexpected results when the ElementTransformation object is already in use such as when these methods are called from within an integration loop. Consider using GetValues(ElementTransformation &T, ...) instead. @@ -207,14 +207,12 @@ public: */ ///@{ /** Return a scalar value from within the element indicated by the - ElementTransformation Object. - */ + ElementTransformation Object. */ double GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp = 0, Vector *tr = NULL) const; /** Return a vector value from within the element indicated by the - ElementTransformation Object. - */ + ElementTransformation Object. */ void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; ///@} From b4daabfc1080a3795ffb3a71b5ea70299393aa3a Mon Sep 17 00:00:00 2001 From: Will Pazner Date: Tue, 19 May 2020 12:01:16 -0700 Subject: [PATCH 353/535] Change `Elem2No` in `GetSharedFaceTransformations` Instead of returning the element neighbor index (i.e. starting from 0) in `Elem2No`, now return the "shifted element index" (i.e. starting from `NumOfElements`), so that callers of method (e.g. integrators) can distinguish between local elements (`index < NumOfElements`) and face neighbor element (`index >= NumOfElements`). The element neighbor index can be recovered simply by subtracting `NumOfElements`. --- fem/pbilinearform.cpp | 5 +++-- fem/pnonlinearform.cpp | 5 +++-- mesh/pmesh.cpp | 12 +++++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/fem/pbilinearform.cpp b/fem/pbilinearform.cpp index 88bf107fa3..13c45f9b37 100644 --- a/fem/pbilinearform.cpp +++ b/fem/pbilinearform.cpp @@ -198,8 +198,9 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros) for (int i = 0; i < nfaces; i++) { T = pmesh->GetSharedFaceTransformations(i); + int Elem2NbrNo = T->Elem2No - pmesh->GetNE(); pfes->GetElementVDofs(T->Elem1No, vdofs1); - pfes->GetFaceNbrElementVDofs(T->Elem2No, vdofs2); + pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2); vdofs1.Copy(vdofs_all); for (int j = 0; j < vdofs2.Size(); j++) { @@ -216,7 +217,7 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros) for (int k = 0; k < fbfi.Size(); k++) { fbfi[k]->AssembleFaceMatrix(*pfes->GetFE(T->Elem1No), - *pfes->GetFaceNbrFE(T->Elem2No), + *pfes->GetFaceNbrFE(Elem2NbrNo), *T, elemmat); if (keep_nbr_block) { diff --git a/fem/pnonlinearform.cpp b/fem/pnonlinearform.cpp index 75109d91d5..3ebd305ef9 100644 --- a/fem/pnonlinearform.cpp +++ b/fem/pnonlinearform.cpp @@ -64,12 +64,13 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const for (int i = 0; i < n_shared_faces; i++) { tr = pmesh->GetSharedFaceTransformations(i, true); + int Elem2NbrNo = tr->Elem2No - pmesh->GetNE(); fe1 = pfes->GetFE(tr->Elem1No); - fe2 = pfes->GetFaceNbrFE(tr->Elem2No); + fe2 = pfes->GetFaceNbrFE(Elem2NbrNo); pfes->GetElementVDofs(tr->Elem1No, vdofs1); - pfes->GetFaceNbrElementVDofs(tr->Elem2No, vdofs2); + pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2); el_x.SetSize(vdofs1.Size() + vdofs2.Size()); X.GetSubVector(vdofs1, el_x.GetData()); diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 8772778066..924e4b2811 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2380,10 +2380,16 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem1 = &Transformation; // setup the transformation for the second (neighbor) element + int Elem2NbrNo; if (fill2) { - FaceElemTr.Elem2No = -1 - face_info.Elem2No; - GetFaceNbrElementTransformation(FaceElemTr.Elem2No, &Transformation2); + Elem2NbrNo = -1 - face_info.Elem2No; + // Store the "shifted index" for element 2 in FaceElemTr.Elem2No. + // `Elem2NbrNo` is the index of the face neighbor (starting from 0), + // and `FaceElemTr.Elem2No` will be offset by the number of (local) + // elements in the mesh. + FaceElemTr.Elem2No = NumOfElements + Elem2NbrNo; + GetFaceNbrElementTransformation(Elem2NbrNo, &Transformation2); FaceElemTr.Elem2 = &Transformation2; } else @@ -2409,7 +2415,7 @@ GetSharedFaceTransformations(int sf, bool fill2) if (fill2) { - elem_type = face_nbr_elements[FaceElemTr.Elem2No]->GetType(); + elem_type = face_nbr_elements[Elem2NbrNo]->GetType(); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc2.Transf, face_info.Elem2Inf); } From 8d983963ddcce9e4e9987cdded5f731f5f46fdd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Tue, 19 May 2020 16:08:22 -0700 Subject: [PATCH 354/535] Update CHANGELOG and INSTALL for SLEPc Fix compiling SLEPc with regular make Don't store number of converged eigenvalues for SLEPc --- CHANGELOG | 9 +++++++++ INSTALL | 10 ++++++++++ config/config.mk.in | 2 +- config/defaults.mk | 12 ++++++------ examples/petsc/ex28p.cpp | 2 +- examples/petsc/makefile | 2 +- linalg/slepc.cpp | 13 ++++++++----- linalg/slepc.hpp | 7 +------ 8 files changed, 37 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2b316faf93..04aab2babf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,6 +56,8 @@ Linear and nonlinear solvers matrix with the function HypreParMatrixFromBlocks. This could be useful for solving block systems with parallel direct solvers such as STRUMPACK. +- Added support for the SLEPc eigensolver package. + New and updated examples and miniapps ------------------------------------- - Added a new example, Example 25/25p, to demonstrate the use of a Perfectly @@ -71,6 +73,13 @@ New and updated examples and miniapps inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG discretizations. +- Ported example 11p to SLEPc, to demonstrate solving the Laplace eigenvalue + equation with the shift-and-invert spectral transformation method. + +- Added a new example, Example 28p, to demonstrate the solution of the 2D + Maxwell eigenvalue problem in a dielectric waveguide. This examples shows the + use of the SLEPc eigensolvers with mixed finite elements and block operators. + - Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of stitching together opposite surfaces of a mesh to create a topologically periodic mesh. diff --git a/INSTALL b/INSTALL index ddc911225b..ba7ff695ac 100644 --- a/INSTALL +++ b/INSTALL @@ -383,6 +383,10 @@ MFEM_USE_PETSC = YES/NO and other features based on the PETSc package. When enabled, this option uses the PETSC_* library options, see below. +MFEM_USE_SLEPC = YES/NO + Enable MFEM eigensolvers based on the SLEPc package. When enabled, this + option uses the SLEPC_* library options, see below. + MFEM_USE_MPFR = YES/NO MPFR is a library for multiple-precision floating-point computations. This option enables the use of MPFR in MFEM, e.g. for precise computation of 1D @@ -589,6 +593,12 @@ The specific libraries and their options are: Options: PETSC_OPT, PETSC_LIB. Versions: PETSc >= 3.8.0. +- SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and + uses some of the PETSc options when compiled. + URL: https://slepc.upv.es/ + Options: SLEPC_OPT, SLEPC_LIB + Versions: SLEPc >= 3.8.0 + - Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES. Starting with MFEM v4.1, Axom version 0.3.1 or later is required. URL: https://github.com/LLNL/axom diff --git a/config/config.mk.in b/config/config.mk.in index a3d72c75c6..8c49fbb149 100644 --- a/config/config.mk.in +++ b/config/config.mk.in @@ -37,7 +37,7 @@ MFEM_USE_GINKGO = @MFEM_USE_GINKGO@ MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@ MFEM_USE_NETCDF = @MFEM_USE_NETCDF@ MFEM_USE_PETSC = @MFEM_USE_PETSC@ -MFEM_USE_SLEPC = @MFEM_USE_SLEPC@ +MFEM_USE_SLEPC = @MFEM_USE_SLEPC@ MFEM_USE_MPFR = @MFEM_USE_MPFR@ MFEM_USE_SIDRE = @MFEM_USE_SIDRE@ MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@ diff --git a/config/defaults.mk b/config/defaults.mk index f8720fcabe..d38e14c1de 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -125,7 +125,7 @@ MFEM_USE_GINKGO = NO MFEM_USE_GNUTLS = NO MFEM_USE_NETCDF = NO MFEM_USE_PETSC = NO -MFEM_USE_SLEPC = NO +MFEM_USE_SLEPC = NO MFEM_USE_MPFR = NO MFEM_USE_SIDRE = NO MFEM_USE_CONDUIT = NO @@ -280,12 +280,12 @@ SLEPC_ARCH := arch-linux2-c-debug SLEPC_DIR := $(MFEM_DIR)/../slepc/$(SLEPC_ARCH) SLEPC_VARS := $(SLEPC_DIR)/lib/slepc/conf/slepc_variables SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,) -SLEPC_INC_VAR = SLEPC_CC_INCLUDES -SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB_BASIC +SLEPC_INC_VAR = SLEPC_INCLUDE +SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB ifeq ($(SLEPC_FOUND),YES) - SLEPC_OPT := $(shell set -n "s/$(SLEPC_INC_VAR) = *//p" $(SLEPC_VARS)) - SLEPC_LIB := $(shell set -n "s/$(SLEPC_INC_LIB) = *//p" $(SLEPC_VARS)) - PETSC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/lib\ + SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS)) + SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS)) + SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/lib\ -L$(abspath $(SLEPC_DIR))/lib -lslepc $(SLEPC_LIB) endif diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index 7a45fd36bc..c6ea667159 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) pmesh->ReorientTetMesh(); // 6. Define a parallel finite element space on the parallel mesh. Here we - // use the Raviart-Thomas finite elements of the specified order. + // use the Nedelec finite elements of the specified order. std::cout << "dim: " << dim << "\n"; FiniteElementCollection *hcurl_coll = new ND_FECollection(order, dim); FiniteElementCollection *h1_coll = new H1_FECollection(order, dim); diff --git a/examples/petsc/makefile b/examples/petsc/makefile index 55f1f89b8a..65c30c624a 100644 --- a/examples/petsc/makefile +++ b/examples/petsc/makefile @@ -22,7 +22,7 @@ MFEM_LIB_FILE = mfem_is_not_built -include $(CONFIG_MK) SEQ_EXAMPLES = -PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p +PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p ex11p ex28p ifeq ($(MFEM_USE_MPI),NO) EXAMPLES = $(SEQ_EXAMPLES) else diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index 3f65d4f8f6..8297ce1ae0 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -74,7 +74,6 @@ SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix, clcustom = false; _tol = PETSC_DEFAULT; _max_its = PETSC_DEFAULT; - _num_conv = -1; _wrap = wrap; VR = NULL; VC = NULL; @@ -212,8 +211,6 @@ void SlepcEigenSolver::Solve() Customize(); ierr = EPSSolve(eps); PCHKERRQ(eps,ierr); - - ierr = EPSGetConverged(eps,&_num_conv); PCHKERRQ(eps,ierr); } void SlepcEigenSolver::Customize(bool customize) const @@ -228,14 +225,12 @@ void SlepcEigenSolver::Customize(bool customize) const void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr) const { - MFEM_VERIFY(i < _num_conv,"Eigenvalue not computed"); ierr = EPSGetEigenvalue(eps,i,&lr,NULL); PCHKERRQ(eps,ierr); } void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr, double & lc) const { - MFEM_VERIFY(i < _num_conv,"Eigenvalue not computed"); ierr = EPSGetEigenvalue(eps,i,&lr,&lc); PCHKERRQ(eps,ierr); } @@ -277,6 +272,14 @@ void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr, VC->ResetArray(); } +int SlepcEigenSolver::GetNumConverged() +{ + int num_conv; + ierr = EPSGetConverged(eps,&num_conv); PCHKERRQ(eps,ierr); + return num_conv; +} + + void SlepcEigenSolver::SetWhichEigenpairs(SlepcEigenSolver::Which which) { switch (which) diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index fe0c530dae..74dc5403d2 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -15,7 +15,6 @@ #include "../config/config.hpp" #ifdef MFEM_USE_SLEPC -#ifdef MFEM_USE_PETSC #ifdef MFEM_USE_MPI #include "petsc.hpp" @@ -48,9 +47,6 @@ private: /// Maximum number of iterations int _max_its; - /// Number of converged eigenvectors. Start with a negative value before the solver is run. - int _num_conv; - /// Real and imaginary part of eigenvector mutable PetscParVector *VR, *VC; @@ -82,7 +78,7 @@ public: void Solve(); /// Get the number of converged eigenvalues - int GetNumConverged() {return _num_conv;} + int GetNumConverged(); /// Get the corresponding eigenvalue void GetEigenvalue(unsigned int i, double & lr) const; @@ -121,7 +117,6 @@ public: } #endif // MFEM_USE_MPI -#endif // MFEM_USE_PETSC #endif // MFEM_USE_SLEPC #endif // MFEM_SLEPC From 08eb0f5bbb7d682b07a84cab4fd16aa117f0f6e3 Mon Sep 17 00:00:00 2001 From: Aaron Fisher Date: Tue, 19 May 2020 16:29:46 -0700 Subject: [PATCH 355/535] Updated the cmake documentation system. --- doc/CMakeLists.txt | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 8a48e4045a..57ef3f97ab 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -16,36 +16,21 @@ if (DOXYGEN_FOUND) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CodeDocumentation.conf.in ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf @ONLY) - if (UNIX) - # Only create symlinks if UNIX operating system - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf - COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html - COMMAND ${CMAKE_COMMAND} -E create_symlink - ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html - ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html - BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html" - VERBATIM) - add_custom_target(clean-doc - COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html - COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation - COMMENT "Removing API documentation" - VERBATIM) + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf + COMMAND echo "" > ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html" + VERBATIM) + + add_custom_target(clean-doc + COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html + COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/warnings.log + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation + COMMENT "Removing API documentation" + VERBATIM) - else (UNIX) - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf - BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen to CodeDocumentation/html/index.html" - VERBATIM) - add_custom_target(clean-doc - COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation - COMMENT "Removing API documentation" - VERBATIM) - endif (UNIX) endif (DOXYGEN_FOUND) From 5f0ff9d5ca35d804c5dd9fe4dcacc6ddc7f83e7a Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 19 May 2020 20:31:24 -0700 Subject: [PATCH 356/535] Remove repeated CHANGELOG entry. --- CHANGELOG | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5ab09c53ae..796d9a677c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -123,10 +123,6 @@ Miscellaneous - The integration order used in the ComputeLpError and ComputeElementLpError methods of class GridFunction has been increased. -- Added a new IterativeSolverMonitor class that allows to monitor the residual - and solution during the solving process of an IterativeSolver after every - iteration. - Version 4.1, released on March 10, 2020 ======================================= From b28b5370d139a2ecffc1c9ebe55527ed05a28d95 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 19 May 2020 20:32:50 -0700 Subject: [PATCH 357/535] Remove the MFEM_HOST_DEVICE specifiers from the `operator[]` methods in class TVector -- this was causing compilation errors when CUDA is enabled. --- linalg/ttensor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index 6c923d0e3a..a991503ae1 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -297,8 +297,8 @@ public: typedef StridedLayout1D layout_type; static const layout_type layout; - MFEM_HOST_DEVICE data_t &operator[](int i) { return data[i]; } - MFEM_HOST_DEVICE const data_t &operator[](int i) const { return data[i]; } + data_t &operator[](int i) { return data[i]; } + const data_t &operator[](int i) const { return data[i]; } template void Assign(const data_t d) From 44837bbb66fa2f99d46031a9d321996c77e60e95 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 19 May 2020 20:41:44 -0700 Subject: [PATCH 358/535] Restore a CHANGELOG entry. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 796d9a677c..d4efc8fb48 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -123,6 +123,9 @@ Miscellaneous - The integration order used in the ComputeLpError and ComputeElementLpError methods of class GridFunction has been increased. +- Various other simplifications, extensions, and bugfixes in the code. + + Version 4.1, released on March 10, 2020 ======================================= From 7206a673eedd3d0e2473c6a1247549bf1db27e64 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Wed, 20 May 2020 10:20:57 -0700 Subject: [PATCH 359/535] Alternative definition for unary minus with AVX512 when AVX512DQ is not available. --- linalg/simd/m512.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linalg/simd/m512.hpp b/linalg/simd/m512.hpp index 85c2b9b719..59bace2a39 100644 --- a/linalg/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -112,7 +112,15 @@ template <> struct AutoSIMD inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const { AutoSIMD r; +#ifdef __AVX512DQ__ r.m512d = _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); +#else + // Derived from https://github.com/vectorclass/version2 + r.m512d = _mm512_castsi512_pd( + _mm512_xor_epi32( + _mm512_castpd_si512(m512d), + _mm512_set1_epi64(0x8000000000000000))); +#endif return r; } From 6f6e134d45b5a39f556cecfa284396cb515795f6 Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Wed, 20 May 2020 15:01:04 -0400 Subject: [PATCH 360/535] Uses (( )) inside while loop condition --- mesh/pumi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index ec2461ed84..b46f73369b 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -1193,7 +1193,7 @@ void ParPumiMesh::NedelecFieldMFEMtoPUMI(apf::Mesh2* apf_mesh, size_t elemNo = 0; apf::MeshEntity* ent; apf::MeshIterator* it = apf_mesh->begin(dim); - while ( ent = apf_mesh->iterate(it) ) + while ( (ent = apf_mesh->iterate(it)) ) { // get all the pumi nodes and rotate them apf::NewArray pumi_nodes; From 13a2b369c2b9395dc19c853f2079d40c1712e53e Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Wed, 20 May 2020 12:23:32 -0700 Subject: [PATCH 361/535] In the miniapps/performance makefile, run compiler auto-detection only when needed. --- miniapps/performance/makefile | 48 +++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index d18cef7b47..a98d303a6e 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -45,24 +45,37 @@ else fi; printf "%s" "$$cxx_id" endef -ifneq (,$(MFEM_HOST_CXX)) - MFEM_PERF_SW := $(shell $(cxx_detect)) - $(info Detected host compiler: $(MFEM_PERF_SW)) - ifeq (unknown,$(MFEM_PERF_SW)) - $(info -------------------------------------------) - $(info Output from '$(MFEM_HOST_CXX) --version -c') - $(info -------------------------------------------) - $(shell $(MFEM_HOST_CXX) --version -c 1>&2) - $(info -------------------------------------------) +define DETECT_PERF_CXXFLAGS +ifneq (,$$(MFEM_HOST_CXX)) + MFEM_PERF_SW := $$(shell $$(cxx_detect)) + $$(info Detected host compiler: $$(MFEM_PERF_SW)) + ifeq (unknown,$$(MFEM_PERF_SW)) + $$(info -------------------------------------------) + $$(info Output from '$$(MFEM_HOST_CXX) --version -c') + $$(info -------------------------------------------) + $$(shell $$(MFEM_HOST_CXX) --version -c 1>&2) + $$(info -------------------------------------------) endif endif -ifeq (gcc,$(MFEM_PERF_SW)) - ifeq ($(MFEM_MACHINE),x86_64) +ifeq (gcc,$$(MFEM_PERF_SW)) + ifeq ($$(MFEM_MACHINE),x86_64) MFEM_PERF_SW = gcc_x86_64 - else ifneq (,$(findstring ppc64,$(MFEM_MACHINE))) + else ifneq (,$$(findstring ppc64,$$(MFEM_MACHINE))) MFEM_PERF_SW = gcc_ppc64 endif endif +# Choose MFEM_PERF_CXXFLAGS based on MFEM_PERF_SW: +MFEM_PERF_CXXFLAGS = $$(MFEM_PERF_CXXFLAGS_$$(MFEM_PERF_SW)) +# Add MFEM_PERF_CXXFLAGS to MFEM_CXXFLAGS: +ifeq (YES,$$(MFEM_USE_CUDA)) + ifneq (,$$(MFEM_PERF_CXXFLAGS)) + MFEM_CXXFLAGS += -Xcompiler="$$(MFEM_PERF_CXXFLAGS)" + endif +else + MFEM_CXXFLAGS += $$(MFEM_PERF_CXXFLAGS) +endif +DETECT_PERF_CXXFLAGS_DONE = YES +endef # Compiler specific optimizations. # For best performance, GCC 5 (or newer) is recommended. @@ -95,16 +108,6 @@ MFEM_PERF_CXXFLAGS_clang += -ffp-contract=fast # - Intel C++ compiler extra options: MFEM_PERF_CXXFLAGS_icc += -xHost -# Choose MFEM_PERF_CXXFLAGS based on MFEM_PERF_SW: -MFEM_PERF_CXXFLAGS = $(MFEM_PERF_CXXFLAGS_$(MFEM_PERF_SW)) -# Add MFEM_PERF_CXXFLAGS to MFEM_CXXFLAGS: -ifeq (YES,$(MFEM_USE_CUDA)) - ifneq (,$(MFEM_PERF_CXXFLAGS)) - MFEM_CXXFLAGS += -Xcompiler="$(MFEM_PERF_CXXFLAGS)" - endif -else - MFEM_CXXFLAGS += $(MFEM_PERF_CXXFLAGS) -endif SEQ_MINIAPPS = ex1 PAR_MINIAPPS = ex1p @@ -123,6 +126,7 @@ endif # Replace the default implicit rule for *.cpp files %: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) + $(if $(DETECT_PERF_CXXFLAGS_DONE),,$(eval $(DETECT_PERF_CXXFLAGS))) $(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS) all: $(MINIAPPS) From 8e7c37ace6bbcbba217bcb8a792684226a1e0f70 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 20 May 2020 14:23:46 -0700 Subject: [PATCH 362/535] Fixing typo in unit test --- tests/unit/fem/test_get_value.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index ce22e3c631..fea16aff5a 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -606,7 +606,7 @@ TEST_CASE("2D GetValue", T->SetIntPoint(&ip); T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + double f_val = func_2D_lin(tip); double h1_gf_val = h1_xCoef.Eval(*T, ip); h1_err += fabs(f_val - h1_gf_val); From 5d5f35af694272df0b1b2c911987e4c79c726897 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 20 May 2020 14:24:16 -0700 Subject: [PATCH 363/535] Removing unnecessary local variable --- fem/gridfunc.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index d476095df2..77f8c5a51d 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1340,8 +1340,6 @@ void GridFunction::GetVectorGradientHat( double GridFunction::GetDivergence(ElementTransformation &T) const { - double div_v = 0.0; - switch (T.ElementType) { case ElementTransformation::ELEMENT: @@ -1355,7 +1353,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const DenseMatrix grad_hat; GetVectorGradientHat(T, grad_hat); const DenseMatrix &Jinv = T.InverseJacobian(); - div_v = 0.0; + double div_v = 0.0; for (int i = 0; i < Jinv.Width(); i++) { for (int j = 0; j < Jinv.Height(); j++) @@ -1363,6 +1361,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const div_v += grad_hat(i, j) * Jinv(j, i); } } + return div_v; } else { @@ -1372,7 +1371,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const Vector loc_data, divshape(fe->GetDof()); GetSubVector(dofs, loc_data); fe->CalcDivShape(T.GetIntPoint(), divshape); - div_v = (loc_data * divshape) / T.Weight(); + return (loc_data * divshape) / T.Weight(); } } break; @@ -1398,7 +1397,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const FET->SetIntPoint(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); - div_v = GetDivergence(T1); + return GetDivergence(T1); } break; case ElementTransformation::BDR_FACE: @@ -1409,7 +1408,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const // Evaluate in neighboring element ElementTransformation & T1 = FET->GetElement1Transformation(); - div_v = GetDivergence(T1); + return GetDivergence(T1); } break; default: @@ -1418,7 +1417,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const << T.ElementType << "\""); } } - return div_v; + return NAN; } void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const From 552971d35f86702fa8207f70a1f5a90d100cfaeb Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 20 May 2020 14:24:38 -0700 Subject: [PATCH 364/535] make style --- fem/gridfunc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 77f8c5a51d..a5d3d3a4cf 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1361,7 +1361,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const div_v += grad_hat(i, j) * Jinv(j, i); } } - return div_v; + return div_v; } else { From d4416684e85e068a767aaecf624192ab51c4d224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Wed, 20 May 2020 15:33:46 -0700 Subject: [PATCH 365/535] Improve comments and fix formatting. --- .gitignore | 3 ++- examples/petsc/ex11p.cpp | 9 ++++--- examples/petsc/ex28p.cpp | 52 +++++++++++++++++++++++----------------- linalg/slepc.hpp | 1 + 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index e2a2e99043..e78cf90054 100644 --- a/.gitignore +++ b/.gitignore @@ -120,7 +120,8 @@ examples/sundials/ex16-final.* examples/sundials/Example16* examples/petsc/ex[1-69]p -examples/petsc/ex10p +examples/petsc/ex1[0-1]p +examples/petsc/ex28p examples/petsc/mesh.* examples/petsc/sol.* diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index 8af15f7b1c..9e81ed003c 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -38,9 +38,12 @@ // order < 1 (quadratic for quadratic curvilinear mesh, NURBS for // NURBS mesh, etc.) // -// The example highlights the use of the LOBPCG eigenvalue solver -// together with the BoomerAMG preconditioner in HYPRE, as well as -// optionally the SuperLU or STRUMPACK parallel direct solvers. +// The example demonstrates the use of the SLEPc eigensolver as an +// alternative to the LOBPCG eigenvalue solver. The shift and +// invert spectral transformation is used to help the convergence +// to the smaller eigenvalues. Alternative solver parameters can +// be passed in a file with "-slepcopts". +// // Reusing a single GLVis visualization window for multiple // eigenfunctions is also illustrated. // diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index c6ea667159..8689859612 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -6,12 +6,17 @@ // Sample runs: // mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p // -// Description: This example code solves a simple 2D dielectric waveguide problem -// corresponding to the generalized eigenvalue equation -// curl 1/mu curl exy - beta^2/mu (grad ez - exy) = k^2 epsilon exy -// beta^2 div 1/mu (grad exy - et) = beta^2 k^2 epsilon ez -// with essential boundary condition (corresponding to metallic walls). -// We discretize with Nédélec edge elements (transverge field exy) +// Description: This example code solves a simple 2D dielectric waveguide +// problem corresponding to the generalized eigenvalue equation +// curl curl et - beta^2 (grad ez - et) = k^2 epsilon et +// div (grad ez - et) = k^2 epsilon ez +// with essential boundary condition (corresponding to metallic +// walls), where k is the wavenumber and epsilon is the material +// dielectric constant. We are searching for the eigenvalue beta +// which corresponds to the propagation constant. We assume the +// material relative permeability (mu) is 1. +// +// We discretize with Nedelec edge elements (transverse field et) // and piecewise continuous polynomials (longitudinal field ez). // // The example demonstrates the use of the BlockMatrix class, as @@ -19,13 +24,13 @@ // VisIt (visit.llnl.gov) visualization format. // // This specific example needs SLEPc compiled. The default options -// file uses the Jacobi-Davidson method with Jacobi preconditioner. +// file uses the Jacobi-Davidson method with Jacobi +// preconditioner. // #include "mfem.hpp" #include #include -//#include #ifndef MFEM_USE_PETSC #error This example requires that MFEM is built with MFEM_USE_PETSC=YES @@ -69,7 +74,7 @@ int main(int argc, char *argv[]) "--no-visualization", "Enable or disable GLVis visualization."); args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts", - "SLepcOptions file to use."); + "SlepcOptions file to use."); args.Parse(); if (!args.Good()) { @@ -155,7 +160,10 @@ int main(int argc, char *argv[]) ConstantCoefficient u_r_func(1.0); Vector e_r(2); double k0 = M_PI*2/1.0; - e_r(0) = -pow(k0*1.0,2);//-k0^2*e_r + // We lump the sign, the wavenumber and the dielectric constant into one + // coefficient. The dielectric contsant is the square of the refractive + // index. + e_r(0) = -pow(k0*1.0,2); // This is an example to use different refractive indices in mesh domains e_r(1) = -pow(k0*2.0,2); PWConstCoefficient e_r_func(e_r); @@ -199,8 +207,8 @@ int main(int argc, char *argv[]) Atth.Get(pAtt); Atth.SetOperatorOwner(false); - // A dummy Azz is required to set the block size and apply the - // essential boundary condition + // A dummy Azz is required to set the block size and apply the essential + // boundary condition azz->Assemble(); azz->EliminateEssentialBCDiag(ess_bdr, 1.0); azz->Finalize(); @@ -275,11 +283,11 @@ int main(int argc, char *argv[]) // 13. Extract the parallel grid function corresponding to the finite element // approximation X. This is the local solution on each processor. - ParGridFunction *exy(new ParGridFunction); + ParGridFunction *et(new ParGridFunction); ParGridFunction *ez(new ParGridFunction); - exy->MakeRef(N_space, x.GetBlock(0), 0); + et->MakeRef(N_space, x.GetBlock(0), 0); ez->MakeRef(L_space, x.GetBlock(1), 0); - exy->Distribute(&(trueX.GetBlock(0))); + et->Distribute(&(trueX.GetBlock(0))); ez->Distribute(&(trueX.GetBlock(1))); // 14. Save the refined mesh and the solution in parallel. This output can be @@ -294,9 +302,9 @@ int main(int argc, char *argv[]) mesh_ofs.precision(8); pmesh->Print(mesh_ofs); - ofstream exy_ofs(u_name.str().c_str()); - exy_ofs.precision(8); - exy->Save(exy_ofs); + ofstream et_ofs(u_name.str().c_str()); + et_ofs.precision(8); + et->Save(et_ofs); ofstream ez_ofs(p_name.str().c_str()); ez_ofs.precision(8); @@ -305,7 +313,7 @@ int main(int argc, char *argv[]) // 15. Save data in the VisIt format VisItDataCollection visit_dc("Example5-Parallel", pmesh); - visit_dc.RegisterField("Exy", exy); + visit_dc.RegisterField("Exy", et); visit_dc.RegisterField("Ez", ez); visit_dc.SetFormat(!par_format ? DataCollection::SERIAL_FORMAT : @@ -320,10 +328,10 @@ int main(int argc, char *argv[]) socketstream u_sock(vishost, visport); u_sock << "parallel " << num_procs << " " << myid << "\n"; u_sock.precision(8); - u_sock << "solution\n" << *pmesh << *exy << "window_title 'Velocity'" + u_sock << "solution\n" << *pmesh << *et << "window_title 'Velocity'" << endl; u_sock << "keys Rjl!\n"; - // Make sure all ranks have sent their 'exy' solution before initiating + // Make sure all ranks have sent their 'et' solution before initiating // another set of GLVis connections (one from each rank): MPI_Barrier(pmesh->GetComm()); socketstream p_sock(vishost, visport); @@ -335,7 +343,7 @@ int main(int argc, char *argv[]) } // 17. Free the used memory. - delete exy; + delete et; delete ez; delete N_space; delete L_space; diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index 74dc5403d2..ef161043dc 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -65,6 +65,7 @@ public: /// Set maximum number of iterations void SetMaxIter(int max_iter); + /// Set the number of required eigenmodes void SetNumModes(int num_eigs); /// Set operator for standard eigenvalue problem void SetOperator(const Operator &op); From e024ac0f9cef26958114b30648d107c6e9cc73c3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 20 May 2020 15:43:17 -0700 Subject: [PATCH 366/535] Adding accessor methods to compound coefficient classes (and adding a couple new ones) --- fem/coefficient.cpp | 109 ++++++++++++++++--- fem/coefficient.hpp | 259 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 344 insertions(+), 24 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 1cea8b7967..cc529f1511 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -416,13 +416,43 @@ double DeterminantCoefficient::Eval(ElementTransformation &T, return ma.Det(); } -VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A, - VectorCoefficient &B, - double _alpha, double _beta) - : VectorCoefficient(A.GetVDim()), a(&A), b(&B), alpha(_alpha), beta(_beta), - va(A.GetVDim()) +VectorSumCoefficient::VectorSumCoefficient(int dim) + : VectorCoefficient(dim), + ACoef(NULL), BCoef(NULL), + A(dim), B(dim), + alphaCoef(NULL), betaCoef(NULL), + alpha(1.0), beta(1.0) { - MFEM_ASSERT(A.GetVDim() == B.GetVDim(), + A = 0.0; B = 0.0; +} + +VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A, + VectorCoefficient &_B, + double _alpha, double _beta) + : VectorCoefficient(_A.GetVDim()), + ACoef(&_A), BCoef(&_B), + A(_A.GetVDim()), B(_A.GetVDim()), + alphaCoef(NULL), betaCoef(NULL), + alpha(_alpha), beta(_beta) +{ + MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(), + "VectorSumCoefficient: " + "Arguments must have the same dimension."); +} + +VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A, + VectorCoefficient &_B, + Coefficient &_alpha, + Coefficient &_beta) + : VectorCoefficient(_A.GetVDim()), + ACoef(&_A), BCoef(&_B), + A(_A.GetVDim()), + B(_A.GetVDim()), + alphaCoef(&_alpha), + betaCoef(&_beta), + alpha(0.0), beta(0.0) +{ + MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(), "VectorSumCoefficient: " "Arguments must have the same dimension."); } @@ -430,26 +460,47 @@ VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A, void VectorSumCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { - b->Eval(V, T, ip); - if ( beta != 1.0 ) { V *= beta; } - a->Eval(va, T, ip); - V.Add(alpha, va); + V.SetSize(A.Size()); + if ( ACoef) { ACoef->Eval(A, T, ip); } + if ( BCoef) { BCoef->Eval(B, T, ip); } + if (alphaCoef) { alpha = alphaCoef->Eval(T, ip); } + if ( betaCoef) { beta = betaCoef->Eval(T, ip); } + add(alpha, A, beta, B, V); } +ScalarVectorProductCoefficient::ScalarVectorProductCoefficient( + double A, + VectorCoefficient &B) + : VectorCoefficient(B.GetVDim()), aConst(A), a(NULL), b(&B) +{} + ScalarVectorProductCoefficient::ScalarVectorProductCoefficient( Coefficient &A, VectorCoefficient &B) - : VectorCoefficient(B.GetVDim()), a(&A), b(&B) + : VectorCoefficient(B.GetVDim()), aConst(0.0), a(&A), b(&B) {} void ScalarVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { - double sa = a->Eval(T, ip); + double sa = (a == NULL) ? aConst : a->Eval(T, ip); b->Eval(V, T, ip); V *= sa; } +NormalizedVectorCoefficient::NormalizedVectorCoefficient(VectorCoefficient &A, + double _tol) + : VectorCoefficient(A.GetVDim()), a(&A), tol(_tol) +{} + +void NormalizedVectorCoefficient::Eval(Vector &V, ElementTransformation &T, + const IntegrationPoint &ip) +{ + a->Eval(V, T, ip); + double nv = V.Norml2(); + V *= (nv > tol) ? (1.0/nv) : 0.0; +} + VectorCrossProductCoefficient::VectorCrossProductCoefficient( VectorCoefficient &A, VectorCoefficient &B) @@ -517,17 +568,23 @@ void MatrixSumCoefficient::Eval(DenseMatrix &M, ElementTransformation &T, M.Add(alpha, ma); } +ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient( + double A, + MatrixCoefficient &B) + : MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(A), a(NULL), b(&B) +{} + ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient( Coefficient &A, MatrixCoefficient &B) - : MatrixCoefficient(B.GetHeight(), B.GetWidth()), a(&A), b(&B) + : MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(0.0), a(&A), b(&B) {} void ScalarMatrixProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip) { - double sa = a->Eval(T, ip); + double sa = (a == NULL) ? aConst : a->Eval(T, ip); b->Eval(M, T, ip); M *= sa; } @@ -581,6 +638,30 @@ void OuterProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T, } } +CrossCrossCoefficient::CrossCrossCoefficient(Coefficient &A, + VectorCoefficient &K) + : MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(0.0), a(&A), k(&K), + vk(K.GetVDim()) +{} + +void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T, + const IntegrationPoint &ip) +{ + k->Eval(vk, T, ip); + M.SetSize(vk.Size(), vk.Size()); + M = 0.0; + double k2 = vk*vk; + for (int i=0; iEval(T, ip) ); +} + double LpNormLoop(double p, Coefficient &coeff, Mesh &mesh, const IntegrationRule *irs[]) { diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 214a994ae1..99dfb28fbd 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -671,10 +671,12 @@ public: /// Coefficients based on sums and products of other coefficients -/// Scalar coefficient defined as the sum of two scalar coefficients +/** Scalar coefficient defined as the linear combination of two scalar + coefficients or a scalar and a scalar coefficient */ class SumCoefficient : public Coefficient { private: + double aConst; Coefficient * a; Coefficient * b; @@ -682,32 +684,107 @@ private: double beta; public: + // Result is _alpha * A + _beta * B + SumCoefficient(double A, Coefficient &B, + double _alpha = 1.0, double _beta = 1.0) + : aConst(A), a(NULL), b(&B), alpha(_alpha), beta(_beta) { } + // Result is _alpha * A + _beta * B SumCoefficient(Coefficient &A, Coefficient &B, double _alpha = 1.0, double _beta = 1.0) - : a(&A), b(&B), alpha(_alpha), beta(_beta) { } + : aConst(0.0), a(&A), b(&B), alpha(_alpha), beta(_beta) { } + + void SetAConst(double A) { a = NULL; aConst = A; } + double GetAConst() const { return aConst; } + + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetBCoef(Coefficient &B) { b = &B; } + Coefficient * GetBCoef() const { return b; } + + void SetAlpha(double _alpha) { alpha = _alpha; } + double GetAlpha() const { return alpha; } + + void SetBeta(double _beta) { beta = _beta; } + double GetBeta() const { return beta; } /// Evaluate the coefficient virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) - { return alpha * a->Eval(T, ip) + beta * b->Eval(T, ip); } + { + return alpha * ((a == NULL ) ? aConst : a->Eval(T, ip) ) + + beta * b->Eval(T, ip); + } }; -/// Scalar coefficient defined as the product of two scalar coefficients +/** Scalar coefficient defined as the product of two scalar coefficients or + a scalar and a scalar coefficient. */ class ProductCoefficient : public Coefficient { private: + double aConst; Coefficient * a; Coefficient * b; public: + ProductCoefficient(double A, Coefficient &B) + : aConst(A), a(NULL), b(&B) { } ProductCoefficient(Coefficient &A, Coefficient &B) - : a(&A), b(&B) { } + : aConst(0.0), a(&A), b(&B) { } + + void SetAConst(double A) { a = NULL; aConst = A; } + double GetAConst() const { return aConst; } + + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetBCoef(Coefficient &B) { b = &B; } + Coefficient * GetBCoef() const { return b; } /// Evaluate the coefficient virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) - { return a->Eval(T, ip) * b->Eval(T, ip); } + { return ((a == NULL ) ? aConst : a->Eval(T, ip) ) * b->Eval(T, ip); } +}; + +/** Scalar coefficient defined as the ratio of two scalars where one or both + scalars are scalar coefficients. */ +class RatioCoefficient : public Coefficient +{ +private: + double aConst; + double bConst; + Coefficient * a; + Coefficient * b; + +public: + RatioCoefficient(double A, Coefficient &B) + : aConst(A), bConst(1.0), a(NULL), b(&B) { } + RatioCoefficient(Coefficient &A, Coefficient &B) + : aConst(0.0), bConst(1.0), a(&A), b(&B) { } + RatioCoefficient(Coefficient &A, double B) + : aConst(0.0), bConst(B), a(&A), b(NULL) { } + + void SetAConst(double A) { a = NULL; aConst = A; } + double GetAConst() const { return aConst; } + + void SetBConst(double B) { b = NULL; bConst = B; } + double GetBConst() const { return bConst; } + + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetBCoef(Coefficient &B) { b = &B; } + Coefficient * GetBCoef() const { return b; } + + /// Evaluate the coefficient + virtual double Eval(ElementTransformation &T, + const IntegrationPoint &ip) + { + return ((a == NULL ) ? aConst : a->Eval(T, ip) ) / + ((b == NULL ) ? bConst : b->Eval(T, ip) ); + } }; /// Scalar coefficient defined as a scalar raised to a power @@ -723,6 +800,12 @@ public: PowerCoefficient(Coefficient &A, double _p) : a(&A), p(_p) { } + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetExponent(double _p) { p = _p; } + double GetExponent() const { return p; } + /// Evaluate the coefficient virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) @@ -741,6 +824,12 @@ private: public: InnerProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + void SetACoef(VectorCoefficient &A) { a = &A; } + VectorCoefficient * GetACoef() const { return a; } + + void SetBCoef(VectorCoefficient &B) { b = &B; } + VectorCoefficient * GetBCoef() const { return b; } + /// Evaluate the coefficient virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); @@ -759,6 +848,12 @@ private: public: VectorRotProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + void SetACoef(VectorCoefficient &A) { a = &A; } + VectorCoefficient * GetACoef() const { return a; } + + void SetBCoef(VectorCoefficient &B) { b = &B; } + VectorCoefficient * GetBCoef() const { return b; } + virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; @@ -774,17 +869,26 @@ private: public: DeterminantCoefficient(MatrixCoefficient &A); + void SetACoef(MatrixCoefficient &A) { a = &A; } + MatrixCoefficient * GetACoef() const { return a; } + /// Evaluate the coefficient virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); }; -/// Vector coefficient defined as the sum of two vector coefficients +/// Vector coefficient defined as the linear combination of two vectors class VectorSumCoefficient : public VectorCoefficient { private: - VectorCoefficient * a; - VectorCoefficient * b; + VectorCoefficient * ACoef; + VectorCoefficient * BCoef; + + Vector A; + Vector B; + + Coefficient * alphaCoef; + Coefficient * betaCoef; double alpha; double beta; @@ -792,10 +896,41 @@ private: mutable Vector va; public: + // To be used with the various "Set" methods + VectorSumCoefficient(int dim); + // Result is _alpha * A + _beta * B VectorSumCoefficient(VectorCoefficient &A, VectorCoefficient &B, double _alpha = 1.0, double _beta = 1.0); + // Result is _alpha * _A + _beta * _B + VectorSumCoefficient(VectorCoefficient &_A, VectorCoefficient &_B, + Coefficient &_alpha, Coefficient &_beta); + + void SetACoef(VectorCoefficient &A) { ACoef = &A; } + VectorCoefficient * GetACoef() const { return ACoef; } + + void SetBCoef(VectorCoefficient &B) { BCoef = &B; } + VectorCoefficient * GetBCoef() const { return BCoef; } + + void SetAlphaCoef(Coefficient &A) { alphaCoef = &A; } + Coefficient * GetAlphaCoef() const { return alphaCoef; } + + void SetBetaCoef(Coefficient &B) { betaCoef = &B; } + Coefficient * GetBetaCoef() const { return betaCoef; } + + void SetA(const Vector &_A) { A = _A; ACoef = NULL; } + const Vector & GetA() const { return A; } + + void SetB(const Vector &_B) { B = _B; BCoef = NULL; } + const Vector & GetB() const { return B; } + + void SetAlpha(double _alpha) { alpha = _alpha; alphaCoef = NULL; } + double GetAlpha() const { return alpha; } + + void SetBeta(double _beta) { beta = _beta; betaCoef = NULL; } + double GetBeta() const { return beta; } + /// Evaluate the coefficient virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -806,12 +941,42 @@ public: class ScalarVectorProductCoefficient : public VectorCoefficient { private: + double aConst; Coefficient * a; VectorCoefficient * b; public: + ScalarVectorProductCoefficient(double A, VectorCoefficient &B); ScalarVectorProductCoefficient(Coefficient &A, VectorCoefficient &B); + void SetAConst(double A) { a = NULL; aConst = A; } + double GetAConst() const { return aConst; } + + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetBCoef(VectorCoefficient &B) { b = &B; } + VectorCoefficient * GetBCoef() const { return b; } + + virtual void Eval(Vector &V, ElementTransformation &T, + const IntegrationPoint &ip); + using VectorCoefficient::Eval; +}; + +/// Vector coefficient defined as a normalized vector field (returns v/|v|) +class NormalizedVectorCoefficient : public VectorCoefficient +{ +private: + VectorCoefficient * a; + + double tol; + +public: + NormalizedVectorCoefficient(VectorCoefficient &A, double tol = 1e-6); + + void SetACoef(VectorCoefficient &A) { a = &A; } + VectorCoefficient * GetACoef() const { return a; } + virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; @@ -830,6 +995,12 @@ private: public: VectorCrossProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + void SetACoef(VectorCoefficient &A) { a = &A; } + VectorCoefficient * GetACoef() const { return a; } + + void SetBCoef(VectorCoefficient &B) { b = &B; } + VectorCoefficient * GetBCoef() const { return b; } + virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; @@ -848,6 +1019,12 @@ private: public: MatVecCoefficient(MatrixCoefficient &A, VectorCoefficient &B); + void SetACoef(MatrixCoefficient &A) { a = &A; } + MatrixCoefficient * GetACoef() const { return a; } + + void SetBCoef(VectorCoefficient &B) { b = &B; } + VectorCoefficient * GetBCoef() const { return b; } + virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; @@ -867,7 +1044,7 @@ public: const IntegrationPoint &ip); }; -/// Matrix coefficient defined as the sum of two matrix coefficients +/// Matrix coefficient defined as the linear combination of two matrices class MatrixSumCoefficient : public MatrixCoefficient { private: @@ -884,6 +1061,18 @@ public: MatrixSumCoefficient(MatrixCoefficient &A, MatrixCoefficient &B, double _alpha = 1.0, double _beta = 1.0); + void SetACoef(MatrixCoefficient &A) { a = &A; } + MatrixCoefficient * GetACoef() const { return a; } + + void SetBCoef(MatrixCoefficient &B) { b = &B; } + MatrixCoefficient * GetBCoef() const { return b; } + + void SetAlpha(double _alpha) { alpha = _alpha; } + double GetAlpha() const { return alpha; } + + void SetBeta(double _beta) { beta = _beta; } + double GetBeta() const { return beta; } + /// Evaluate the coefficient virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); @@ -893,12 +1082,23 @@ public: class ScalarMatrixProductCoefficient : public MatrixCoefficient { private: + double aConst; Coefficient * a; MatrixCoefficient * b; public: + ScalarMatrixProductCoefficient(double A, MatrixCoefficient &B); ScalarMatrixProductCoefficient(Coefficient &A, MatrixCoefficient &B); + void SetAConst(double A) { a = NULL; aConst = A; } + double GetAConst() const { return aConst; } + + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetBCoef(MatrixCoefficient &B) { b = &B; } + MatrixCoefficient * GetBCoef() const { return b; } + virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; @@ -912,6 +1112,9 @@ private: public: TransposeMatrixCoefficient(MatrixCoefficient &A); + void SetACoef(MatrixCoefficient &A) { a = &A; } + MatrixCoefficient * GetACoef() const { return a; } + virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; @@ -925,6 +1128,9 @@ private: public: InverseMatrixCoefficient(MatrixCoefficient &A); + void SetACoef(MatrixCoefficient &A) { a = &A; } + MatrixCoefficient * GetACoef() const { return a; } + virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; @@ -942,6 +1148,39 @@ private: public: OuterProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + void SetACoef(VectorCoefficient &A) { a = &A; } + VectorCoefficient * GetACoef() const { return a; } + + void SetBCoef(VectorCoefficient &B) { b = &B; } + VectorCoefficient * GetBCoef() const { return b; } + + virtual void Eval(DenseMatrix &M, ElementTransformation &T, + const IntegrationPoint &ip); +}; + +/// Matrix coefficient defined as -a k x k x, for a vector k and scalar a +class CrossCrossCoefficient : public MatrixCoefficient +{ +private: + double aConst; + Coefficient * a; + VectorCoefficient * k; + + mutable Vector vk; + +public: + CrossCrossCoefficient(double A, VectorCoefficient &K); + CrossCrossCoefficient(Coefficient &A, VectorCoefficient &K); + + void SetAConst(double A) { a = NULL; aConst = A; } + double GetAConst() const { return aConst; } + + void SetACoef(Coefficient &A) { a = &A; } + Coefficient * GetACoef() const { return a; } + + void SetKCoef(VectorCoefficient &K) { k = &K; } + VectorCoefficient * GetKCoef() const { return k; } + virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; From bc40981ffe641e8e195e47ede3e903b2f34bdbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Wed, 20 May 2020 15:51:05 -0700 Subject: [PATCH 367/535] Move PETSc error handling to shared header --- linalg/petsc.cpp | 20 +------------------- linalg/petscinternals.hpp | 35 +++++++++++++++++++++++++++++++++++ linalg/slepc.cpp | 21 +-------------------- 3 files changed, 37 insertions(+), 39 deletions(-) create mode 100644 linalg/petscinternals.hpp diff --git a/linalg/petsc.cpp b/linalg/petsc.cpp index 5e3be98ae4..2f2063397c 100644 --- a/linalg/petsc.cpp +++ b/linalg/petsc.cpp @@ -37,25 +37,7 @@ // Note: there are additional #include statements below. -// Error handling -// Prints PETSc's stacktrace and then calls MFEM_ABORT -// We cannot use PETSc's CHKERRQ since it returns a PetscErrorCode -#define PCHKERRQ(obj,err) do { \ - if ((err)) \ - { \ - PetscError(PetscObjectComm((PetscObject)(obj)),__LINE__,_MFEM_FUNC_NAME, \ - __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ - MFEM_ABORT("Error in PETSc. See stacktrace above."); \ - } \ - } while(0); -#define CCHKERRQ(comm,err) do { \ - if ((err)) \ - { \ - PetscError(comm,__LINE__,_MFEM_FUNC_NAME, \ - __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ - MFEM_ABORT("Error in PETSc. See stacktrace above."); \ - } \ - } while(0); +#include "petscinternals.hpp" // Callback functions: these functions will be called by PETSc static PetscErrorCode __mfem_ts_monitor(TS,PetscInt,PetscReal,Vec,void*); diff --git a/linalg/petscinternals.hpp b/linalg/petscinternals.hpp new file mode 100644 index 0000000000..7b4af106a5 --- /dev/null +++ b/linalg/petscinternals.hpp @@ -0,0 +1,35 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef MFEM_PETSCINTERNALS +#define MFEM_PETSCINTERNALS + +// Error handling +// Prints PETSc's stacktrace and then calls MFEM_ABORT +// We cannot use PETSc's CHKERRQ since it returns a PetscErrorCode +#define PCHKERRQ(obj,err) do { \ + if ((err)) \ + { \ + PetscError(PetscObjectComm((PetscObject)(obj)),__LINE__,_MFEM_FUNC_NAME, \ + __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ + MFEM_ABORT("Error in PETSc. See stacktrace above."); \ + } \ + } while(0); +#define CCHKERRQ(comm,err) do { \ + if ((err)) \ + { \ + PetscError(comm,__LINE__,_MFEM_FUNC_NAME, \ + __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ + MFEM_ABORT("Error in PETSc. See stacktrace above."); \ + } \ + } while(0); + +#endif diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index 8297ce1ae0..a3b1c10aa0 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -19,26 +19,7 @@ #include "slepc.h" -// Error handling -// Prints SLEPc's stacktrace and then calls MFEM_ABORT -// We cannot use PETSc's CHKERRQ since it returns a PetscErrorCode -#define PCHKERRQ(obj,err) do { \ - if ((err)) \ - { \ - PetscError(PetscObjectComm((PetscObject)(obj)),__LINE__,_MFEM_FUNC_NAME, \ - __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ - MFEM_ABORT("Error in SLEPc. See stacktrace above."); \ - } \ - } while(0); -#define CCHKERRQ(comm,err) do { \ - if ((err)) \ - { \ - PetscError(comm,__LINE__,_MFEM_FUNC_NAME, \ - __FILE__,(err),PETSC_ERROR_REPEAT,NULL); \ - MFEM_ABORT("Error in SLEPc. See stacktrace above."); \ - } \ - } while(0); - +#include "petscinternals.hpp" static PetscErrorCode ierr; From 45881cbdd5744d3878635803d3a020c8f79223b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Wed, 20 May 2020 17:13:18 -0700 Subject: [PATCH 368/535] Only allow PetscParMatrix for SLEPc operators --- examples/petsc/ex11p.cpp | 78 +++++++++++++++++++++-------------- linalg/slepc.cpp | 88 ++++------------------------------------ linalg/slepc.hpp | 10 ++--- 3 files changed, 58 insertions(+), 118 deletions(-) diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index 9e81ed003c..4157b54783 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -224,8 +224,21 @@ int main(int argc, char *argv[]) m->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); m->Finalize(); - HypreParMatrix *A = a->ParallelAssemble(); - HypreParMatrix *M = m->ParallelAssemble(); + PetscParMatrix *pA = NULL, *pM = NULL; + HypreParMatrix *A = NULL, *M = NULL; + Operator::Type tid = + !use_slepc ? Operator::Hypre_ParCSR : Operator::PETSC_MATAIJ; + OperatorHandle Ah(tid), Mh(tid); + + a->ParallelAssemble(Ah); + if (!use_slepc) { Ah.Get(A); } + else { Ah.Get(pA); } + Ah.SetOperatorOwner(false); + + m->ParallelAssemble(Mh); + if (!use_slepc) {Mh.Get(M); } + else {Mh.Get(pM); } + Mh.SetOperatorOwner(false); #if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK) Operator * Arow = NULL; @@ -250,39 +263,42 @@ int main(int argc, char *argv[]) // preconditioner for A to be used within the solver. Set the matrices // which define the generalized eigenproblem A x = lambda M x. Solver * precond = NULL; - if (!slu_solver && !sp_solver) + if (!use_slepc) { - HypreBoomerAMG * amg = new HypreBoomerAMG(*A); - amg->SetPrintLevel(0); - precond = amg; - } - else - { -#ifdef MFEM_USE_SUPERLU - if (slu_solver) + if (!slu_solver && !sp_solver) { - SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD); - superlu->SetPrintStatistics(false); - superlu->SetSymmetricPattern(true); - superlu->SetColumnPermutation(superlu::PARMETIS); - superlu->SetOperator(*Arow); - precond = superlu; + HypreBoomerAMG * amg = new HypreBoomerAMG(*A); + amg->SetPrintLevel(0); + precond = amg; } + else + { +#ifdef MFEM_USE_SUPERLU + if (slu_solver) + { + SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD); + superlu->SetPrintStatistics(false); + superlu->SetSymmetricPattern(true); + superlu->SetColumnPermutation(superlu::PARMETIS); + superlu->SetOperator(*Arow); + precond = superlu; + } #endif #ifdef MFEM_USE_STRUMPACK - if (sp_solver) - { - STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD); - strumpack->SetPrintFactorStatistics(true); - strumpack->SetPrintSolveStatistics(false); - strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT); - strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS); - strumpack->DisableMatching(); - strumpack->SetOperator(*Arow); - strumpack->SetFromCommandLine(); - precond = strumpack; - } + if (sp_solver) + { + STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD); + strumpack->SetPrintFactorStatistics(true); + strumpack->SetPrintSolveStatistics(false); + strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT); + strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS); + strumpack->DisableMatching(); + strumpack->SetOperator(*Arow); + strumpack->SetFromCommandLine(); + precond = strumpack; + } #endif + } } HypreLOBPCG * lobpcg; @@ -303,12 +319,12 @@ int main(int argc, char *argv[]) } else { - slepc = new SlepcEigenSolver(MPI_COMM_WORLD,"",false); + slepc = new SlepcEigenSolver(MPI_COMM_WORLD); slepc->SetNumModes(nev); slepc->SetWhichEigenpairs(SlepcEigenSolver::TARGET_REAL); slepc->SetTarget(0.0); slepc->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT); - slepc->SetOperators(*A,*M); + slepc->SetOperators(*pA,*pM); } // 9. Compute the eigenmodes and extract the array of eigenvalues. Define a diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index a3b1c10aa0..c1c38d1c81 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -49,13 +49,11 @@ void MFEMFinalizeSlepc() } -SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix, - bool wrap) +SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix) { clcustom = false; _tol = PETSC_DEFAULT; _max_its = PETSC_DEFAULT; - _wrap = wrap; VR = NULL; VC = NULL; operatorset = false; @@ -72,101 +70,31 @@ SlepcEigenSolver::~SlepcEigenSolver() } -void SlepcEigenSolver::SetOperator(const Operator &op) +void SlepcEigenSolver::SetOperator(const PetscParMatrix &op) { - PetscParMatrix *pA = const_cast - (dynamic_cast(&op)); - const HypreParMatrix *hA = dynamic_cast(&op); - const Operator *oA = dynamic_cast(&op); - bool delete_pA = false; - - if (!pA) - { - if (hA) - { - pA = new PetscParMatrix(hA, - _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); - delete_pA = true; - } - else if (oA) - { - pA = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oA, - _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); - delete_pA = true; - - } - } - MFEM_VERIFY(pA, "Unsupported operation!"); - if (operatorset) { delete VR; delete VC; VR = VC = NULL; } - ierr = EPSSetOperators(eps,*pA,NULL); PCHKERRQ(eps, ierr); - operatorset = true; - if (delete_pA) {delete_pA;} + ierr = EPSSetOperators(eps,op,NULL); PCHKERRQ(eps, ierr); + operatorset = true; } -void SlepcEigenSolver::SetOperators(const Operator &op, const Operator &opB) +void SlepcEigenSolver::SetOperators(const PetscParMatrix &op, + const PetscParMatrix&opB) { - PetscParMatrix *pA = const_cast - (dynamic_cast(&op)); - PetscParMatrix *pB = const_cast - (dynamic_cast(&opB)); - const HypreParMatrix *hA = dynamic_cast(&op); - const HypreParMatrix *hB = dynamic_cast(&opB); - - const Operator *oA = dynamic_cast(&op); - const Operator *oB = dynamic_cast(&opB); - bool delete_pA = false; - bool delete_pB = false; - if (!pA) - { - if (hA) - { - pA = new PetscParMatrix(hA, - _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); - delete_pA = true; - } - else if (oA) - { - pA = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oA, - _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); - delete_pA = true; - } - } - MFEM_VERIFY(pA, "Unsupported Operation!"); - if (!pB) - { - if (hB) - { - pB = new PetscParMatrix(hB, - _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); - delete_pB = true; - } - else if (oB) - { - pB = new PetscParMatrix(PetscObjectComm((PetscObject)eps),oB, - _wrap ? Operator::PETSC_MATSHELL : Operator::PETSC_MATAIJ); - delete_pB = true; - } - } - MFEM_VERIFY(pB, "Unsupported Operation!"); - if (operatorset) { delete VR; delete VC; VR = VC = NULL; } - operatorset = true; - ierr = EPSSetOperators(eps,*pA,*pB); PCHKERRQ(eps,ierr); - if (delete_pA) {delete_pA;} - if (delete_pB) {delete_pB;} + ierr = EPSSetOperators(eps,op,opB); PCHKERRQ(eps,ierr); + operatorset = true; } void SlepcEigenSolver::SetTol(double tol) diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index ef161043dc..4dfbf88506 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -36,9 +36,6 @@ private: /// Boolean to handle SetFromOptions calls mutable bool clcustom; - /// Internal flag to handle matrix conversion or not. - bool _wrap; - /// SLEPc linear eigensolver object EPS eps; /// Solver tolerance @@ -55,8 +52,7 @@ private: public: /// Constructors - SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string(), - bool wrap = true); + SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string()); virtual ~SlepcEigenSolver(); @@ -68,9 +64,9 @@ public: /// Set the number of required eigenmodes void SetNumModes(int num_eigs); /// Set operator for standard eigenvalue problem - void SetOperator(const Operator &op); + void SetOperator(const PetscParMatrix &op); /// Set operator for generalized eigenvalue problem - void SetOperators(const Operator &op, const Operator &opB); + void SetOperators(const PetscParMatrix &op, const PetscParMatrix &opB); /// Customize object with options set void Customize(bool customize = true) const; From 89648f1c008e2499fd2cda80402276f460b73784 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Thu, 21 May 2020 08:09:35 -0700 Subject: [PATCH 369/535] make style --- fem/coefficient.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index b2d1783426..401977a9da 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -552,7 +552,7 @@ public: @a gf. The grid function is not owned by the coefficient. */ CurlGridFunctionCoefficient(const GridFunction *gf); - /// Set the vector grid function. + /// Set the vector grid function. void SetGridFunction(const GridFunction *gf); /// Get the vector grid function. @@ -580,7 +580,7 @@ public: /// Set the vector grid function. void SetGridFunction(const GridFunction *gf) { GridFunc = gf; } - /// Get the vector grid function. + /// Get the vector grid function. const GridFunction * GetGridFunction() const { return GridFunc; } /// Evaluate the scalar divergence coefficient at @a ip. From 51dfbfeb6e1d2aa753fb9a7b7fdb104a2c8451bc Mon Sep 17 00:00:00 2001 From: Tzanio Date: Thu, 21 May 2020 10:38:00 -0700 Subject: [PATCH 370/535] Fix fo unary minus with AVX512 when AVX512DQ is not available. --- linalg/simd/m512.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/linalg/simd/m512.hpp b/linalg/simd/m512.hpp index 59bace2a39..53620ae11f 100644 --- a/linalg/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -115,11 +115,7 @@ template <> struct AutoSIMD #ifdef __AVX512DQ__ r.m512d = _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); #else - // Derived from https://github.com/vectorclass/version2 - r.m512d = _mm512_castsi512_pd( - _mm512_xor_epi32( - _mm512_castpd_si512(m512d), - _mm512_set1_epi64(0x8000000000000000))); + r = 0.0 - (*this); #endif return r; } From 7d4a7b2680454f03e0ceb55354b2f774d5c0e5a7 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 10:47:49 -0700 Subject: [PATCH 371/535] These macros have been moved to hypre_parcsr.hpp --- linalg/complex_operator.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/linalg/complex_operator.cpp b/linalg/complex_operator.cpp index 2cf7f23793..d3d3e182db 100644 --- a/linalg/complex_operator.cpp +++ b/linalg/complex_operator.cpp @@ -13,26 +13,6 @@ #include #include -// Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree: -// mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively. -// Note: the same macros are defined in hypre.cpp and hypre_parser.cpp. -#if MFEM_HYPRE_VERSION < 21400 - -#define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size) -#define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size) -#define mfem_hypre_TFree(ptr) hypre_TFree(ptr) - -#else // MFEM_HYPRE_VERSION >= 21400 - -// See the notes about hypre 2.14.0 in hypre.cpp -#define mfem_hypre_TAlloc(type, size) \ - hypre_TAlloc(type, size, HYPRE_MEMORY_HOST) -#define mfem_hypre_CTAlloc(type, size) \ - hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST) -#define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST) - -#endif // #if MFEM_HYPRE_VERSION < 21400 - namespace mfem { From db9c3c91420c909a1e6097f1b9248c637702dd73 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 10:48:28 -0700 Subject: [PATCH 372/535] Uninitialized pointer --- linalg/hypre.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index ffb0f79eaf..4c6a46f38b 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -2699,7 +2699,7 @@ HypreGMRES::HypreGMRES(MPI_Comm comm) : precond(NULL) SetDefaultOptions(); } -HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A) +HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A), precond(NULL) { MPI_Comm comm; From dc31c573590fc44c5805c26bef6d1979f196ab86 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 10:55:43 -0700 Subject: [PATCH 373/535] Adding DenseMatrixInverse::Mult(double*, double*) method similar to DenseMatrix --- linalg/densemat.cpp | 9 +++++++++ linalg/densemat.hpp | 3 +++ 2 files changed, 12 insertions(+) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 27f0555ad9..b19414a6f5 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3272,6 +3272,15 @@ void DenseMatrixInverse::SetOperator(const Operator &op) Factor(*p); } +void DenseMatrixInverse::Mult(const double *x, double *y) const +{ + for (int row = 0; row < height; row++) + { + y[row] = x[row]; + } + lu.Solve(width, 1, y); +} + void DenseMatrixInverse::Mult(const Vector &x, Vector &y) const { y = x; diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 3cd4abac12..9c21e0d70c 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -643,6 +643,9 @@ public: virtual void SetOperator(const Operator &op); + /// Matrix vector multiplication with the inverse of dense matrix. + void Mult(const double *x, double *y) const; + /// Matrix vector multiplication with the inverse of dense matrix. virtual void Mult(const Vector &x, Vector &y) const; From 6cb5a2abb11eb6f9689d12ac5b323262159c579e Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Thu, 21 May 2020 10:56:52 -0700 Subject: [PATCH 374/535] Small tweak to avoid using a function before it is declared. --- linalg/simd/m512.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linalg/simd/m512.hpp b/linalg/simd/m512.hpp index 53620ae11f..dec27db24e 100644 --- a/linalg/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -115,7 +115,7 @@ template <> struct AutoSIMD #ifdef __AVX512DQ__ r.m512d = _mm512_xor_pd(_mm512_set1_pd(-0.0), m512d); #else - r = 0.0 - (*this); + r.m512d = _mm512_sub_pd(_mm512_set1_pd(0.0), m512d); #endif return r; } From e88a811861ec66ae3b92e465e8a20b2d43d3aa82 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 11:00:33 -0700 Subject: [PATCH 375/535] Correcting a comment --- fem/bilininteg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/bilininteg.hpp b/fem/bilininteg.hpp index 1c6c77e5db..9ec3d8de14 100644 --- a/fem/bilininteg.hpp +++ b/fem/bilininteg.hpp @@ -1563,7 +1563,7 @@ public: }; /** Class for integrating the bilinear form a(u,v) := (-V u, Grad v) in 2D or 3D - and where V is a vector coefficient, u is in H1 and v is in H1. */ + and where V is a vector coefficient, u is in H1 or L2 and v is in H1. */ class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator { public: From 93d968393184e137043cc4d020218137d707111c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 11:03:22 -0700 Subject: [PATCH 376/535] Avoiding memory leak in BlockOperator --- linalg/blockoperator.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linalg/blockoperator.cpp b/linalg/blockoperator.cpp index 7035c7916a..0b5c98c91f 100644 --- a/linalg/blockoperator.cpp +++ b/linalg/blockoperator.cpp @@ -56,6 +56,10 @@ void BlockOperator::SetDiagonalBlock(int iblock, Operator *op, double c) void BlockOperator::SetBlock(int iRow, int iCol, Operator *opt, double c) { + if (owns_blocks && op(iRow, iCol)) + { + delete op(iRow, iCol); + } op(iRow, iCol) = opt; coef(iRow, iCol) = c; From 872e044a6975e3069852b1d7c4261c1f915a5601 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 11:08:10 -0700 Subject: [PATCH 377/535] Avoiding memory leak in BlockDiagonalPreconditioner --- linalg/blockoperator.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linalg/blockoperator.cpp b/linalg/blockoperator.cpp index 0b5c98c91f..ade097fddc 100644 --- a/linalg/blockoperator.cpp +++ b/linalg/blockoperator.cpp @@ -152,6 +152,10 @@ void BlockDiagonalPreconditioner::SetDiagonalBlock(int iblock, Operator *opt) offsets[iblock+1] - offsets[iblock] == opt->Width(), "incompatible Operator dimensions"); + if (owns_blocks && op[iblock]) + { + delete op[iblock]; + } op[iblock] = opt; } From 271e8ad822f327fec8a090b4ea84a02174691a37 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 11:12:30 -0700 Subject: [PATCH 378/535] Adding read-only access to BlockOperator member data --- linalg/blockoperator.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/linalg/blockoperator.hpp b/linalg/blockoperator.hpp index 27e8217960..17e332c051 100644 --- a/linalg/blockoperator.hpp +++ b/linalg/blockoperator.hpp @@ -76,6 +76,9 @@ public: //! Return a reference to block i,j Operator & GetBlock(int i, int j) { MFEM_VERIFY(op(i,j), ""); return *op(i,j); } + //! Read only access to the reference to block i,j + const Operator & GetBlock(int i, int j) const + { MFEM_VERIFY(op(i,j), ""); return *op(i,j); } //! Return the coefficient for block i,j double GetBlockCoef(int i, int j) const { MFEM_VERIFY(op(i,j), ""); return coef(i,j); } @@ -85,8 +88,12 @@ public: //! Return the row offsets for block starts Array & RowOffsets() { return row_offsets; } + //! Read only access to the row offsets for block starts + const Array & RowOffsets() const { return row_offsets; } //! Return the columns offsets for block starts Array & ColOffsets() { return col_offsets; } + //! Read only access to the columns offsets for block starts + const Array & ColOffsets() const { return col_offsets; } /// Operator application virtual void Mult (const Vector & x, Vector & y) const; @@ -153,9 +160,16 @@ public: Operator & GetDiagonalBlock(int iblock) { MFEM_VERIFY(op[iblock], ""); return *op[iblock]; } + //! Read only access to the reference to block i,i. + const Operator & GetDiagonalBlock(int iblock) const + { MFEM_VERIFY(op[iblock], ""); return *op[iblock]; } + //! Return the offsets for block starts Array & Offsets() { return offsets; } + //! Read only access to the offsets for block starts + const Array & Offsets() const { return offsets; } + /// Operator application virtual void Mult (const Vector & x, Vector & y) const; From f75aa06cd1c48286f5876146bc82ede6ac1909b7 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 11:15:31 -0700 Subject: [PATCH 379/535] Adding accessor method to BlockVector for number of blocks --- linalg/blockvector.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linalg/blockvector.hpp b/linalg/blockvector.hpp index 76cd683bf8..d8bc6fe333 100644 --- a/linalg/blockvector.hpp +++ b/linalg/blockvector.hpp @@ -72,6 +72,9 @@ public: */ BlockVector(double *data, const Array & bOffsets); + //! Return the number of blocks + int NumBlocks() const { return numBlocks; } + //! Assignment operator. this and original must have the same block structure. BlockVector & operator=(const BlockVector & original); //! Set each entry of this equal to val From 3f9ca7403abe3a0698d6059a00a1d89766a011a9 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 21 May 2020 11:16:45 -0700 Subject: [PATCH 380/535] Adjusting comment on new const member functions --- linalg/blockoperator.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linalg/blockoperator.hpp b/linalg/blockoperator.hpp index 17e332c051..4a07485c32 100644 --- a/linalg/blockoperator.hpp +++ b/linalg/blockoperator.hpp @@ -76,7 +76,7 @@ public: //! Return a reference to block i,j Operator & GetBlock(int i, int j) { MFEM_VERIFY(op(i,j), ""); return *op(i,j); } - //! Read only access to the reference to block i,j + //! Return a reference to block i,j (const version) const Operator & GetBlock(int i, int j) const { MFEM_VERIFY(op(i,j), ""); return *op(i,j); } //! Return the coefficient for block i,j @@ -160,7 +160,7 @@ public: Operator & GetDiagonalBlock(int iblock) { MFEM_VERIFY(op[iblock], ""); return *op[iblock]; } - //! Read only access to the reference to block i,i. + //! Return a reference to block i,i (const version). const Operator & GetDiagonalBlock(int iblock) const { MFEM_VERIFY(op[iblock], ""); return *op[iblock]; } From 21c73b40766b61e427a9c8e67d0c31448a7094c7 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 May 2020 11:33:24 -0700 Subject: [PATCH 381/535] Addressing comments made in tech talk --- fem/CMakeLists.txt | 2 - fem/fem.hpp | 1 - fem/field_interpolant.cpp | 346 --------------------- fem/field_interpolant.hpp | 177 ----------- fem/lininteg.cpp | 20 +- tests/unit/fem/test_quadf_coef.cpp | 467 ++++------------------------- 6 files changed, 60 insertions(+), 953 deletions(-) delete mode 100644 fem/field_interpolant.cpp delete mode 100644 fem/field_interpolant.hpp diff --git a/fem/CMakeLists.txt b/fem/CMakeLists.txt index 51c02bd0b9..f3c49ae42b 100644 --- a/fem/CMakeLists.txt +++ b/fem/CMakeLists.txt @@ -32,7 +32,6 @@ set(SRCS fe.cpp fe_coll.cpp fespace.cpp - field_interpolant.cpp geom.cpp gridfunc.cpp hybridization.cpp @@ -68,7 +67,6 @@ set(HDRS fe_coll.hpp fem.hpp fespace.hpp - field_interpolant.hpp geom.hpp gridfunc.hpp hybridization.hpp diff --git a/fem/fem.hpp b/fem/fem.hpp index ed8bb89d6b..5082b6cc59 100644 --- a/fem/fem.hpp +++ b/fem/fem.hpp @@ -23,7 +23,6 @@ #include "nonlininteg.hpp" #include "bilininteg.hpp" #include "fespace.hpp" -#include "field_interpolant.hpp" #include "gridfunc.hpp" #include "linearform.hpp" #include "nonlinearform.hpp" diff --git a/fem/field_interpolant.cpp b/fem/field_interpolant.cpp deleted file mode 100644 index 451ade8980..0000000000 --- a/fem/field_interpolant.cpp +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced -// at the Lawrence Livermore National Laboratory. All Rights reserved. See files -// LICENSE and NOTICE for details. LLNL-CODE-806117. -// -// This file is part of the MFEM library. For more information and source code -// availability visit https://mfem.org. -// -// MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file -// CONTRIBUTING.md for details. - -// Implementation of Field Interpolants and necessary (Vector)QuadratorIntegrators - -#include "field_interpolant.hpp" -#include "../linalg/densemat.hpp" -#include "fem.hpp" - -namespace mfem -{ - -void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc) -{ - { - const FiniteElementSpace *fes = gf.FESpace(); - MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), - "FiniteElementSpace corresponding to this GridFunction should have the \ - same vdim of the VectorQuadratureFunctionCoefficient"); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - const QuadratureFunction* qf = vqfc.GetQuadFunction(); - const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - - MFEM_VERIFY(ir == ir_qf, - "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ - appear to be different"); - } - gf.HostReadWrite(); - // Later on we might be able to swap this over to something that can run on - // on the gpu. - gf.ProjectDiscCoefficient(vqfc, GridFunction::ARITHMETIC); -} - -void Quad2FieldInterpolant::ProjectQuadratureDiscCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc) -{ - { - const FiniteElementSpace *fes = gf.FESpace(); - MFEM_VERIFY(fes->GetVDim() == 1, - "FiniteElementSpace corresponding to this GridFunction should have a vdim\ - of 1"); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - const QuadratureFunction* qf = qfc.GetQuadFunction(); - const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - - MFEM_VERIFY(ir == ir_qf, - "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ - appear to be different"); - } - gf.HostReadWrite(); - // Later on we might be able to swap this over to something that can run on - // on the gpu. - gf.ProjectDiscCoefficient(qfc, GridFunction::ARITHMETIC); -} - -void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc) -{ - FiniteElementSpace *fes = gf.FESpace(); - { - MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ - function.") - MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), - "FiniteElementSpace corresponding to this GridFunction should have the \ - same vdim of the VectorQuadratureFunctionCoefficient"); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - const QuadratureFunction* qf = vqfc.GetQuadFunction(); - const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY(ir == ir_qf, - "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ - appear to be different"); - - const FiniteElementSpace* l2_fes = L2->FESpace(); - const FiniteElement &l2_el = *l2_fes->GetFE(0); - const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - MFEM_VERIFY(ir_l2 == ir_qf, - "IntegrationRule in FiniteElementSpace supplied to class and \ - in QuadratureFunction appear to be different"); - } - - int vdim = vqfc.GetVDim(); - int size = gf.Size() / vdim; - - LinearForm *b = new LinearForm(fes); - b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, - &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); - b->Assemble(); - - // If our FES is byVDIM then we're going to rearrange b to be in byNodes order - if (fes->GetOrdering() == Ordering::byVDIM) - { - Vector tmp = *b; - double* data = b->HostReadWrite(); - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < size; j++) - { - data[j + i * size] = tmp(i + j * vdim); - } - } - } - - GridFunction x(fes); - x = 0.0; - OperatorPtr A; - Vector B, b_sub, X_sub, X; - - Array ess_tdof_list; - - for (int ind = 0; ind < vdim; ind++) - { - int offset = ind * size; - b_sub.MakeRef(*b, offset, size); - X_sub.MakeRef(x, offset, size); - L2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); - cg->SetOperator(*A); - cg->Mult(B, X); - // Recover the solution as a finite element grid function. - L2->RecoverFEMSolution(X, *b, X_sub); - } - - if (fes->GetOrdering() == Ordering::byNODES) - { - gf = x; - } - else - { - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < size; j++) - { - gf(i + j * vdim) = x(i * size + j); - } - } - } - - delete b; -} -void Quad2FieldInterpolant::ProjectQuadratureCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc) -{ - FiniteElementSpace *fes = gf.FESpace(); - { - MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ - function.") - MFEM_VERIFY(fes->GetVDim() == 1, - "FiniteElementSpace corresponding to this GridFunction should have a \ - vdim of 1"); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - const QuadratureFunction* qf = qfc.GetQuadFunction(); - const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY(ir == ir_qf, - "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ - appear to be different"); - - const FiniteElementSpace* l2_fes = L2->FESpace(); - const FiniteElement &l2_el = *l2_fes->GetFE(0); - const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - MFEM_VERIFY(ir_l2 == ir_qf, - "IntegrationRule in FiniteElementSpace supplied to class and \ - in QuadratureFunction appear to be different"); - } - LinearForm *b = new LinearForm(fes); - b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, - &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); - b->Assemble(); - - GridFunction x(fes); - x = 0.0; - OperatorPtr A; - Vector B, X; - Array ess_tdof_list; - - L2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cg->SetOperator(*A); - cg->Mult(B, X); - // Recover the solution as a finite element grid function. - L2->RecoverFEMSolution(X, *b, x); - gf = x; - - delete b; -} - -#ifdef MFEM_USE_MPI -void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc) -{ - ParFiniteElementSpace *fes = gf.ParFESpace(); - { - MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ - function.") - MFEM_VERIFY(fes->GetVDim() == vqfc.GetVDim(), - "FiniteElementSpace corresponding to this GridFunction should have the \ - same vdim of the VectorQuadratureFunctionCoefficient"); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - const QuadratureFunction* qf = vqfc.GetQuadFunction(); - const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY(ir == ir_qf, - "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ - appear to be different"); - - const ParFiniteElementSpace* l2_fes = ParL2->ParFESpace(); - const FiniteElement &l2_el = *l2_fes->GetFE(0); - const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - MFEM_VERIFY(ir_l2 == ir_qf, - "IntegrationRule in FiniteElementSpace supplied to class and \ - in QuadratureFunction appear to be different"); - } - - int vdim = vqfc.GetVDim(); - int size = gf.Size() / vdim; - - ParLinearForm *b = new ParLinearForm(fes); - b->AddDomainIntegrator(new VectorQuadratureLFIntegrator(vqfc, - &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); - b->Assemble(); - - // If our FES is byVDIM then we're going to rearrange b to be in byNodes order - if (fes->GetOrdering() == Ordering::byVDIM) - { - Vector tmp = *b; - double* data = b->HostReadWrite(); - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < size; j++) - { - data[j + i * size] = tmp(i + j * vdim); - } - } - } - - ParGridFunction x(fes); - x = 0.0; - OperatorPtr A; - Vector B, b_sub, X_sub, X; - - Array ess_tdof_list; - - for (int ind = 0; ind < vdim; ind++) - { - int offset = ind * size; - b_sub.MakeRef(*b, offset, size); - X_sub.MakeRef(x, offset, size); - ParL2->FormLinearSystem(ess_tdof_list, X_sub, b_sub, A, X, B); - // Recover the solution as a finite element grid function. - cg->SetOperator(*A); - cg->Mult(B, X); - ParL2->RecoverFEMSolution(X, *b, X_sub); - } - - if (fes->GetOrdering() == Ordering::byNODES) - { - gf = x; - } - else - { - for (int i = 0; i < vdim; i++) - { - for (int j = 0; j < size; j++) - { - gf(i + j * vdim) = x(i * size + j); - } - } - } - - delete b; -} - -void ParQuad2FieldInterpolant::ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc) -{ - ParFiniteElementSpace *fes = gf.ParFESpace(); - { - MFEM_VERIFY(cg, "CGSolver has not been set yet call SetupCG() before this \ - function.") - MFEM_VERIFY(fes->GetVDim() == 1, - "FiniteElementSpace corresponding to this GridFunction should have a \ - a vdim of 1"); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule* ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - const QuadratureFunction* qf = qfc.GetQuadFunction(); - const IntegrationRule* ir_qf = &qf->GetSpace()->GetElementIntRule(0); - MFEM_VERIFY(ir == ir_qf, - "IntegrationRule in FiniteElementSpace and in QuadratureFunction \ - appear to be different"); - - const ParFiniteElementSpace* l2_fes = ParL2->ParFESpace(); - const FiniteElement &l2_el = *l2_fes->GetFE(0); - const IntegrationRule* ir_l2 = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - MFEM_VERIFY(ir_l2 == ir_qf, - "IntegrationRule in FiniteElementSpace supplied to class and \ - in QuadratureFunction appear to be different"); - } - ParLinearForm *b = new ParLinearForm(fes); - b->AddDomainIntegrator(new QuadratureLFIntegrator(qfc, - &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(0))); - b->Assemble(); - - ParGridFunction x(fes); - x = 0.0; - OperatorPtr A; - Vector B, X; - Array ess_tdof_list; - - ParL2->FormLinearSystem(ess_tdof_list, x, *b, A, X, B); - cg->SetOperator(*A); - cg->Mult(B, X); - // Recover the solution as a finite element grid function. - ParL2->RecoverFEMSolution(X, *b, x); - gf = x; - - delete b; -} -#endif - -} \ No newline at end of file diff --git a/fem/field_interpolant.hpp b/fem/field_interpolant.hpp deleted file mode 100644 index 21b1d2186f..0000000000 --- a/fem/field_interpolant.hpp +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced -// at the Lawrence Livermore National Laboratory. All Rights reserved. See files -// LICENSE and NOTICE for details. LLNL-CODE-806117. -// -// This file is part of the MFEM library. For more information and source code -// availability visit https://mfem.org. -// -// MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file -// CONTRIBUTING.md for details. - -// Implementation of Field Interpolants - -#ifndef MFEM_FIELD_INTERPOLANT -#define MFEM_FIELD_INTERPOLANT - -#include "../config/config.hpp" -#include "../linalg/linalg.hpp" -#include "intrules.hpp" -#include "eltrans.hpp" -#include "coefficient.hpp" -#include "bilininteg.hpp" -#include "bilinearform.hpp" -#include "lininteg.hpp" -#include "gridfunc.hpp" -#ifdef MFEM_USE_MPI -#include "pgridfunc.hpp" -#include "pbilinearform.hpp" -#endif - -namespace mfem -{ - -/** @brief Provides methods to take quadrature data and project it onto a field - within a H1 or L2 space.*/ -class Quad2FieldInterpolant -{ -protected: - BilinearForm *L2 = nullptr; // Owned. - CGSolver *cg = nullptr; // Owned. -public: - /** The FiniteElementSpace passed into here should be of the same order - and space as those used within the ProjectQuadratureCoefficient method. - The vdim on the FES should be equal to 1, so the L2 method can work on - either scalar or vector GridFunctions.*/ - Quad2FieldInterpolant(FiniteElementSpace *fes) - { - MFEM_VERIFY(fes->GetVDim() == 1, "FiniteElementSpace should have a \ - a vdim of 1"); - L2 = new BilinearForm(fes); - - const FiniteElement &el = *fes->GetFE(0); - const IntegrationRule *ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - - L2->AddDomainIntegrator(new MassIntegrator(ir)); - L2->Assemble(); - } - /** @brief This function takes a vector quadrature function coefficient and projects - it onto a GridFunction that lives either in a H1 or L2 space.*/ - /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ - void ProjectQuadratureDiscCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc); - /** @brief This function takes a quadrature function coefficient and projects - it onto a GridFunction lives either in a H1 or L2 space.*/ - /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ - void ProjectQuadratureDiscCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc); - /** This function takes a vector quadrature function coefficient and projects - it onto a GridFunction through the use of an L2 projection method.*/ - void ProjectQuadratureCoefficient(GridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc); - /** This function takes a quadrature function coefficient and projects it onto - a GridFunction through the use of an L2 projection method. */ - void ProjectQuadratureCoefficient(GridFunction &gf, - QuadratureFunctionCoefficient &qfc); - /// This function resets the internal bilinearform due to any mesh changes. - virtual void FullReset() - { - L2->Update(); - L2->Assemble(); - } - virtual void SetupCG(double rel_tol = 1e-15, double abs_tol = 0.0, - int print_level = 0, int max_iter = 2000) - { - if (cg) - { - delete cg; - } - cg = new CGSolver(); - cg->SetPrintLevel(print_level); - cg->SetMaxIter(max_iter); - cg->SetRelTol(rel_tol); - cg->SetAbsTol(abs_tol); - } - virtual ~Quad2FieldInterpolant() - { - if (L2) - { - delete L2; - } - if (cg) - { - delete cg; - } - } - -protected: - // Should only be needed for children classes to avoid unneeded resources - // from being allocated. - Quad2FieldInterpolant() {} -}; - -#ifdef MFEM_USE_MPI -class ParQuad2FieldInterpolant : public Quad2FieldInterpolant -{ -protected: - ParBilinearForm *ParL2 = nullptr; // Owned -public: - /** The FiniteElementSpace passed into here should be of the same order - and space as those used within the ProjectQuadratureCoefficient method. - The vdim on the FES should be equal to 1, so the L2 method can work on - either scalar or vector GridFunctions.*/ - ParQuad2FieldInterpolant(ParFiniteElementSpace *pfes) - { - MFEM_VERIFY(pfes->GetVDim() == 1, "FiniteElementSpace should have a \ - a vdim of 1"); - ParL2 = new ParBilinearForm(pfes); - - const FiniteElement &el = *pfes->GetFE(0); - const IntegrationRule *ir = &(IntRules.Get(el.GetGeomType(), - 2 * el.GetOrder() + 1)); - - ParL2->AddDomainIntegrator(new MassIntegrator(ir)); - ParL2->Assemble(); - } - /** @brief This function takes a vector quadrature function coefficient and projects - it onto a GridFunction that lives either in a H1 or L2 space.*/ - /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ - void ProjectQuadratureCoefficient(ParGridFunction &gf, - VectorQuadratureFunctionCoefficient &vqfc); - /** @brief This function takes a quadrature function coefficient and projects - it onto a GridFunction that lives either in a H1 or L2 space.*/ - /** Internally, this function makes use of the GridFunction::ProjectDiscCoefficient.*/ - void ProjectQuadratureCoefficient(ParGridFunction &gf, - QuadratureFunctionCoefficient &qfc); - /// This function resets the internal bilinearform due to any mesh changes. - virtual void FullReset() override - { - ParL2->Update(); - ParL2->Assemble(); - } - using Quad2FieldInterpolant::SetupCG; - /// Setup the CG solver with an MPI communicator - virtual void SetupCG(MPI_Comm _comm, double rel_tol = 1e-15, - double abs_tol = 0.0, - int print_level = 0, int max_iter = 2000) - { - if (cg) - { - delete cg; - } - cg = new CGSolver(_comm); - cg->SetPrintLevel(print_level); - cg->SetMaxIter(max_iter); - cg->SetRelTol(rel_tol); - cg->SetAbsTol(abs_tol); - } - - virtual ~ParQuad2FieldInterpolant() - { - delete ParL2; - } -}; -#endif -} -#endif diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index ba68d9a2e2..2e8ad862dd 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -777,13 +777,7 @@ void VectorQuadratureLFIntegrator::AssembleRHSElementVect( const IntegrationRule *ir = &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); - if (ir == NULL) - { - int intorder = 2 * fe.GetOrder(); - ir = &IntRules.Get(fe.GetGeomType(), intorder); - } - - const int nqp = IntRule->GetNPoints(); + const int nqp = ir->GetNPoints(); const int vdim = vqfc.GetVDim(); const int ndofs = fe.GetDof(); Vector shape(ndofs); @@ -792,7 +786,7 @@ void VectorQuadratureLFIntegrator::AssembleRHSElementVect( elvect = 0.0; for (int q = 0; q < nqp; q++) { - const IntegrationPoint &ip = IntRule->IntPoint(q); + const IntegrationPoint &ip = ir->IntPoint(q); Tr.SetIntPoint(&ip); const double w = Tr.Weight() * ip.weight; vqfc.Eval(temp, Tr, ip); @@ -815,20 +809,14 @@ void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, const IntegrationRule *ir = &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); - if (ir == NULL) - { - int intorder = 2 * fe.GetOrder(); - ir = &IntRules.Get(fe.GetGeomType(), intorder); - } - - const int nqp = IntRule->GetNPoints(); + const int nqp = ir->GetNPoints(); const int ndofs = fe.GetDof(); Vector shape(ndofs); elvect.SetSize(ndofs); elvect = 0.0; for (int q = 0; q < nqp; q++) { - const IntegrationPoint &ip = IntRule->IntPoint(q); + const IntegrationPoint &ip = ir->IntPoint(q); Tr.SetIntPoint (&ip); const double w = Tr.Weight() * ip.weight; double temp = qfc.Eval(Tr, ip); diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 1ccca89d75..4bd3317ade 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -21,7 +21,7 @@ TEST_CASE("Quadrature Function Coefficients", "[Quadrature Function Coefficients]") { int order_h1 = 2, n = 4, dim = 3; - double tol = 1e-9; + double tol = 1e-14; Mesh mesh(n, n, n, Element::HEXAHEDRON, false, 1.0, 1.0, 1.0); mesh.SetCurvature(order_h1); @@ -73,11 +73,6 @@ TEST_CASE("Quadrature Function Coefficients", QuadratureFunctionCoefficient qfc(quadf_coeff); VectorQuadratureFunctionCoefficient qfvc(quadf_vcoeff); - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_hv1(&mesh, &fec_h1, 1); - Quad2FieldInterpolant fi(&fespace_hv1); - fi.SetupCG(); - SECTION("Operators on VecQuadFuncCoeff") { std::cout << "Testing VecQuadFuncCoeff: " << std::endl; @@ -92,425 +87,75 @@ TEST_CASE("Quadrature Function Coefficients", REQUIRE_THROWS(qfvc.SetComponent(0, 0)); #endif qfvc.SetComponent(0, 3); - - SECTION("Gridfunction L2 tests") - { - std::cout << " Testing GridFunc L2 projection" << std::endl; - L2_FECollection fec_l2(order_h1, dim); - FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - - GridFunction g0(&fespace_l2); - GridFunction gtrue(&fespace_l2); - - { - - GridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue.ProjectGridFunction(nodes); - - } - - g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc); - gtrue -= g0; - REQUIRE(gtrue.Norml2() < tol); - } - - SECTION("Gridfunction L2 tests byVDIM") - { - std::cout << " Testing GridFunc L2 projection byVDIM" << std::endl; - L2_FECollection fec_l2(order_h1, dim); - FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim, Ordering::byVDIM); - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); - GridFunction g0(&fespace_l2); - GridFunction gtrue(&fespace_l2); - - { - - GridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue.ProjectGridFunction(nodes); - - } - - g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc); - gtrue -= g0; - REQUIRE(gtrue.Norml2() < tol); - } - - SECTION("Gridfunction H1 tests") - { - std::cout << " Testing GridFunc H1 projection" << std::endl; - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - GridFunction g0(&fespace_h1); - GridFunction gtrue(&fespace_h1); - - { - GridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue = nodes; - } - - g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc); - gtrue -= g0; - REQUIRE(gtrue.Norml2() < tol); - } - SECTION("Gridfunction H1 tests byVDIM") - { - std::cout << " Testing GridFunc H1 projection byVDIM" << std::endl; - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); - GridFunction g0(&fespace_h1); - GridFunction gtrue(&fespace_h1); - - { - GridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue = nodes; - } - - g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc); - gtrue -= g0; - REQUIRE(gtrue.Norml2() < tol); - } } - SECTION("Operators on QuadFuncCoeff") + SECTION("Operators on VectorQuadratureLFIntegrator") { - SECTION("Gridfunction L2 tests") - { - std::cout << "Testing QuadFuncCoeff:"; - std::cout << " Testing GridFunc L2 projection" << std::endl; - L2_FECollection fec_l2(order_h1, dim); - FiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - GridFunction g0(&fespace_l2); - GridFunction gtrue(&fespace_l2); + std::cout << "Testing VectorQuadratureLFIntegrator: " << std::endl; + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - // When using an L2 FE space of the same order as the mesh, the below highlights - // that the ProjectDiscCoeff method is just taking the quadrature point - // values and making them node values. - { + GridFunction nodes(&fespace_h1); + mesh.GetNodes(nodes); - GridFunction nodes_z(&fespace_hv1); - GridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - nodes_z.MakeRef(nodes, nodes_z.Size() * 2); - gtrue.ProjectGridFunction(nodes_z); + Vector output(nodes.Size()); + output = 0.0; - } + LinearForm lf(&fespace_h1); + lf.AddDomainIntegrator(new VectorQuadratureLFIntegrator(qfvc, NULL)); - g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfc); - gtrue -= g0; - REQUIRE(gtrue.Norml2() < tol); - } + lf.Assemble(); - SECTION("Gridfunction H1 tests") - { - std::cout << " Testing GridFunc H1 projection" << std::endl; - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); - GridFunction g0(&fespace_h1); - GridFunction gtrue(&fespace_h1); + BilinearForm L2(&fespace_h1); - fi.FullReset(); + L2.AddDomainIntegrator(new VectorMassIntegrator()); + L2.Assemble(); - { - int nnodes = gtrue.Size(); - int vdim = 1; + SparseMatrix mat = L2.SpMat(); - Vector nodes; - mesh.GetNodes(nodes); - for (int i = 0; i < nnodes; i++) - { - gtrue(i) = nodes(i * dim + 2); - } - } + mat.Mult(nodes, output); - g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfc); - gtrue -= g0; - REQUIRE(gtrue.Norml2() < tol); - } + output -= lf; + + REQUIRE(output.Norml2() < tol); } + + SECTION("Operators on QuadratureLFIntegrator") + { + std::cout << "Testing QuadratureLFIntegrator: " << std::endl; + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); + FiniteElementSpace fespace_h3(&mesh, &fec_h1, 3); + + GridFunction nodes(&fespace_h3); + mesh.GetNodes(nodes); + + Vector output(nodes.Size() / dim); + Vector nz(nodes.Size() / dim); + output = 0.0; + + nz.MakeRef(nodes, nz.Size() * 2); + + LinearForm lf(&fespace_h1); + lf.AddDomainIntegrator(new QuadratureLFIntegrator(qfc, NULL)); + + lf.Assemble(); + + BilinearForm L2(&fespace_h1); + + L2.AddDomainIntegrator(new MassIntegrator(&ir)); + L2.Assemble(); + + SparseMatrix mat = L2.SpMat(); + + mat.Mult(nz, output); + + output -= lf; + + REQUIRE(output.Norml2() < tol); + } + } -#ifdef MFEM_USE_MPI - -TEST_CASE("Parallel Quadrature Function Coefficients", - "[Parallel] , [Parallel Quadrature Function Coefficients]") -{ - int order_h1 = 2, n = 4, dim = 3; - double tol = 1e-9; - - Mesh *tmesh = new Mesh(n, n, n, Element::HEXAHEDRON, false, 1.0, 1.0, 1.0); - tmesh->SetCurvature(order_h1); - ParMesh mesh(MPI_COMM_WORLD, *tmesh); - - delete tmesh; - - int intOrder = 2 * order_h1 + 1; - - QuadratureSpace qspace(&mesh, intOrder); - QuadratureFunction quadf_coeff(&qspace, 1); - QuadratureFunction quadf_vcoeff(&qspace, dim); - - const IntegrationRule ir = qspace.GetElementIntRule(0); - - const GeometricFactors *geom_facts = mesh.GetGeometricFactors(ir, - GeometricFactors::COORDINATES); - - { - int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim() / ir.GetNPoints(); - int vdim = ir.GetNPoints(); - - for (int i = 0; i < nelems; i++) - { - for (int j = 0; j < vdim; j++) - { - //X has dims nqpts x sdim x ne - quadf_coeff((i * vdim) + j) = geom_facts->X((i * vdim * dim) + (vdim * 2) + j ); - } - } - } - - { - int nqpts = ir.GetNPoints(); - int nelems = quadf_vcoeff.Size() / quadf_vcoeff.GetVDim() / nqpts; - int vdim = quadf_vcoeff.GetVDim(); - - for (int i = 0; i < nelems; i++) - { - for (int j = 0; j < vdim; j++) - { - for (int k = 0; k < nqpts; k++) - { - //X has dims nqpts x sdim x ne - quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( - i * nqpts * vdim) + (j * nqpts) + k ); - } - } - } - } - - QuadratureFunctionCoefficient qfc(quadf_coeff); - VectorQuadratureFunctionCoefficient qfvc(quadf_vcoeff); - - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_hv1(&mesh, &fec_h1, 1); - ParQuad2FieldInterpolant fi(&fespace_hv1); - fi.SetupCG(MPI_COMM_WORLD); - - SECTION("Operators on VecQuadFuncCoeff") - { - std::cout << "Testing VecQuadFuncCoeff: " << std::endl; -#ifdef MFEM_USE_EXCEPTIONS - std::cout << " Setting Component" << std::endl; - REQUIRE_THROWS(qfvc.SetComponent(3, 1)); - REQUIRE_THROWS(qfvc.SetComponent(-1, 1)); - REQUIRE_NOTHROW(qfvc.SetComponent(1, 2)); - REQUIRE_THROWS(qfvc.SetComponent(0, 4)); - REQUIRE_THROWS(qfvc.SetComponent(1, 3)); - REQUIRE_NOTHROW(qfvc.SetComponent(0, 2)); - REQUIRE_THROWS(qfvc.SetComponent(0, 0)); -#endif - qfvc.SetComponent(0, 3); - - SECTION("Gridfunction L2 tests") - { - std::cout << " Testing GridFunc L2 projection" << std::endl; - L2_FECollection fec_l2(order_h1, dim); - ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - ParGridFunction g0(&fespace_l2); - ParGridFunction gtrue(&fespace_l2); - - { - - ParGridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue.ProjectGridFunction(nodes); - - } - - g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc); - gtrue -= g0; - - double lerr = gtrue.Norml2(); - double error = 0; - - MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - REQUIRE(error < tol); - } - - SECTION("Gridfunction L2 tests byVDIM") - { - std::cout << " Testing GridFunc L2 projection byVDIM" << std::endl; - L2_FECollection fec_l2(order_h1, dim); - ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, dim, Ordering::byVDIM); - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); - ParGridFunction g0(&fespace_l2); - ParGridFunction gtrue(&fespace_l2); - - { - - ParGridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue.ProjectGridFunction(nodes); - - } - - g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfvc); - gtrue -= g0; - - double lerr = gtrue.Norml2(); - double error = 0; - - MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - REQUIRE(error < tol); - } - - SECTION("Gridfunction H1 tests") - { - std::cout << " Testing GridFunc H1 projection" << std::endl; - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - ParGridFunction g0(&fespace_h1); - ParGridFunction gtrue(&fespace_h1); - - { - ParGridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue = nodes; - } - - g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc); - gtrue -= g0; - - double lerr = gtrue.Norml2(); - double error = 0; - - MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - REQUIRE(error < tol); - } - - SECTION("Gridfunction H1 tests byVDIM") - { - std::cout << " Testing GridFunc H1 projection byVDIM" << std::endl; - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim, Ordering::byVDIM); - ParGridFunction g0(&fespace_h1); - ParGridFunction gtrue(&fespace_h1); - - fi.FullReset(); - - { - ParGridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - gtrue = nodes; - } - - g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfvc); - gtrue -= g0; - - double lerr = gtrue.Norml2(); - double error = 0; - - MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - REQUIRE(error < tol); - } - } - - SECTION("Operators on QuadFuncCoeff") - { - SECTION("Gridfunction L2 tests") - { - std::cout << "Testing QuadFuncCoeff:"; - std::cout << " Testing GridFunc L2 projection" << std::endl; - L2_FECollection fec_l2(order_h1, dim); - ParFiniteElementSpace fespace_l2(&mesh, &fec_l2, 1); - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, dim); - ParGridFunction g0(&fespace_l2); - ParGridFunction gtrue(&fespace_l2); - - // When using an L2 FE space of the same order as the mesh, the below highlights - // that the ProjectDiscCoeff method is just taking the quadrature point - // values and making them node values. - { - - ParGridFunction nodes_z(&fespace_hv1); - ParGridFunction nodes(&fespace_h1); - mesh.GetNodes(nodes); - nodes_z.MakeRef(nodes, nodes_z.Size() * 2); - gtrue.ProjectGridFunction(nodes_z); - - } - - g0 = 0.0; - fi.ProjectQuadratureDiscCoefficient(g0, qfc); - gtrue -= g0; - - double lerr = gtrue.Norml2(); - double error = 0; - - MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - REQUIRE(error < tol); - } - - SECTION("Gridfunction H1 tests") - { - std::cout << " Testing GridFunc H1 projection" << std::endl; - H1_FECollection fec_h1(order_h1, dim); - ParFiniteElementSpace fespace_h1(&mesh, &fec_h1, 1); - ParGridFunction g0(&fespace_h1); - ParGridFunction gtrue(&fespace_h1); - - { - int nnodes = gtrue.Size(); - int vdim = 1; - - Vector nodes; - mesh.GetNodes(nodes); - for (int i = 0; i < nnodes; i++) - { - gtrue(i) = nodes(i * dim + 2); - } - } - - g0 = 0.0; - fi.ProjectQuadratureCoefficient(g0, qfc); - gtrue -= g0; - - double lerr = gtrue.Norml2(); - double error = 0; - - MPI_Allreduce(&lerr, &error, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - REQUIRE(error < tol); - } - } -} -#endif } // namespace qf_coeff From c663cc39253f0e23dd9133a5af6109df2fc6f761 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 May 2020 11:34:35 -0700 Subject: [PATCH 382/535] make style --- tests/unit/fem/test_quadf_coef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 4bd3317ade..4380a90ca2 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -120,7 +120,7 @@ TEST_CASE("Quadrature Function Coefficients", REQUIRE(output.Norml2() < tol); } - SECTION("Operators on QuadratureLFIntegrator") + SECTION("Operators on QuadratureLFIntegrator") { std::cout << "Testing QuadratureLFIntegrator: " << std::endl; H1_FECollection fec_h1(order_h1, dim); From 78a8c79755344e40a85c0228c3744169ff9bd16a Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Thu, 21 May 2020 15:01:56 -0400 Subject: [PATCH 383/535] Removes unused static functions --- mesh/pumi.cpp | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index b46f73369b..106699e499 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -33,40 +33,6 @@ using namespace std; namespace mfem { -static void getPumiNodeXis(apf::FieldShape* fs, - int type, - IntegrationRule& xis) -{ - apf::NewArray pumiXis; - apf::getElementNodeXis(fs, type, pumiXis); - xis.SetSize(pumiXis.size()); - for (size_t i = 0; i < pumiXis.size(); i++) - { - IntegrationPoint& ip = xis.IntPoint(i); - double xi[3]; - pumiXis[i].toArray(xi); - ip.Set(xi, 3); - } -} - -static void getPumiNodeXis(apf::FieldShape* fs, - apf::Mesh2* m, - apf::MeshEntity* e, - IntegrationRule& xis) -{ - apf::NewArray pumiXis; - apf::getElementNodeXis(fs, m, e, pumiXis); - xis.SetSize(pumiXis.size()); - for (size_t i = 0; i < pumiXis.size(); i++) - { - IntegrationPoint& ip = xis.IntPoint(i); - double xi[3]; - pumiXis[i].toArray(xi); - ip.Set(xi, 3); - } -} - - static void ReadPumiElement(apf::MeshEntity* Ent, /* ptr to pumi entity */ apf::Downward Verts, const int Attr, apf::Numbering* vert_num, From 40fb14767668b793de74b5f4b12025da26f12e2c Mon Sep 17 00:00:00 2001 From: "Morteza H. Siboni" Date: Thu, 21 May 2020 15:19:20 -0400 Subject: [PATCH 384/535] Fixes problem with overloaded virt. function Load --- mesh/pumi.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 643f74b413..2cd831457d 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -56,6 +56,7 @@ public: PumiMesh(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1, bool fix_orientation = true); + using Mesh::Load; /// Load a PUMI mesh (following the steps in the MFEM Load function). void Load(apf::Mesh2* apf_mesh, int generate_edges = 0, int refine = 1, bool fix_orientation = true); From 9bd653526edb39fb9ae47d445cd64747b7567f70 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Thu, 21 May 2020 13:33:55 -0700 Subject: [PATCH 385/535] PR comments --- linalg/densemat.cpp | 69 +++++++------------------ tests/unit/linalg/test_matrix_dense.cpp | 6 +-- 2 files changed, 22 insertions(+), 53 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index e4fd8a185e..243cb2cc0b 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3502,25 +3502,14 @@ DenseTensor &DenseTensor::operator=(double c) return *this; } -void BatchLUFactor(Vector &Minv, const int m, const int NE, Array &P) -{ - P.SetSize(m*NE); - BatchLUFactor_impl(Minv.ReadWrite(), m, NE, P.Write()); -} - void BatchLUFactor(DenseTensor &Minv, Array &P) { const int m = Minv.SizeI(); const int NE = Minv.SizeK(); P.SetSize(m*NE); - BatchLUFactor_impl(Minv.ReadWrite(), m, NE, P.Write()); -} -void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) -{ - - auto data_all = mfem::Reshape(Minv, m, m, NE); - auto piv_all = mfem::Reshape(P, m, NE); + auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); + auto ipiv_all = mfem::Reshape(P.Write(), m, NE); Array pivot_flag(1); pivot_flag[0] = true; bool *d_pivot_flag = pivot_flag.ReadWrite(); @@ -3528,53 +3517,49 @@ void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P) MFEM_FORALL(e, NE, { - - double *data = &data_all(0,0,e); - int *ipiv = &piv_all(0,e); for (int i = 0; i < m; i++) { - // pivoting { int piv = i; - double a = fabs(data[piv+i*m]); + double a = fabs(data_all(piv,i,e)); for (int j = i+1; j < m; j++) { - const double b = fabs(data[j+i*m]); + const double b = fabs(data_all(j,i,e)); if (b > a) { a = b; piv = j; } } - ipiv[i] = piv; + ipiv_all(i,e) = piv; if (piv != i) { // swap rows i and piv in both L and U parts for (int j = 0; j < m; j++) { - mfem::kernels::internal::Swap(data[i+j*m], data[piv+j*m]); + mfem::kernels::internal::Swap(data_all(i,j,e), data_all(piv,j,e)); } } }//pivot end - if (abs(data[i + i*m]) <= TOL) + if (abs(data_all(i,i,e)) <= TOL) { d_pivot_flag[0] = false; } - const double a_ii_inv = 1.0 / data[i+i*m]; + const double a_ii_inv = 1.0 / data_all(i,i,e); for (int j = i+1; j < m; j++) { - data[j+i*m] *= a_ii_inv; + data_all(j,i,e) *= a_ii_inv; } for (int k = i+1; k < m; k++) { - const double a_ik = data[i+k*m]; + const double a_ik = data_all(i,k,e); for (int j = i+1; j < m; j++) { - data[j+k*m] -= a_ik * data[j+i*m]; + data_all(j,k,e) -= a_ik * data_all(j,i,e); } } @@ -3590,53 +3575,37 @@ void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) const int m = Minv.SizeI(); const int NE = Minv.SizeK(); - BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); -} -void BatchLUSolve(const Vector &Minv, const int m, const int NE, - const Array &P, Vector &X) -{ - BatchLUSolve_impl(Minv.Read(), m, NE, P.Read(), X.ReadWrite()); -} - -void BatchLUSolve_impl(const double *Minv, const int m, const int NE, - const int *P, double *X) -{ - - auto data_all = mfem::Reshape(Minv, m, m, NE); - auto piv_all = mfem::Reshape(P, m, NE); - auto x_all = mfem::Reshape(X, m, NE); + auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); + auto piv_all = mfem::Reshape(P.Read(), m, NE); + auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); MFEM_FORALL(e, NE, { - const double *data = &data_all(0,0,e); - const int *ipiv = &piv_all(0,e); - double *x = &x_all(0,e); - // X <- P X for (int i = 0; i < m; i++) { - mfem::kernels::internal::Swap(x[i], x[ipiv[i]]); + mfem::kernels::internal::Swap(x_all(i,e), x_all(piv_all(i,e),e)); } // X <- L^{-1} X for (int j = 0; j < m; j++) { - const double x_j = x[j]; + const double x_j = x_all(j,e); for (int i = j+1; i < m; i++) { - x[i] -= data[i+j*m] * x_j; + x_all(i,e) -= data_all(i,j,e) * x_j; } } // X <- U^{-1} X for (int j = m-1; j >= 0; j--) { - const double x_j = ( x[j] /= data[j+j*m] ); + const double x_j = ( x_all(j,e) /= data_all(j,j,e) ); for (int i = 0; i < j; i++) { - x[i] -= data[i+j*m] * x_j; + x_all(i,e) -= data_all(i,j,e) * x_j; } } }); diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index bba8f08f76..5bc2ec25ce 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -261,7 +261,7 @@ TEST_CASE("DenseTensor LinearSolve methods", int NE = 10; Vector X_batch(N*NE); - Vector A_batch(N*N*NE); + DenseTensor A_batch(N,N,NE); auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE); auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE); @@ -280,8 +280,8 @@ TEST_CASE("DenseTensor LinearSolve methods", } Array P; - BatchLUFactor(A_batch, N, NE, P); - BatchLUSolve(A_batch, N, NE, P, X_batch); + BatchLUFactor(A_batch, P); + BatchLUSolve(A_batch, P, X_batch); auto xans_batch = mfem::Reshape(X_batch.HostRead(),N,NE); REQUIRE(LinearSolve(A,X)); From e37c2c7fb1415a9d2111c02d0c9712635ac2f080 Mon Sep 17 00:00:00 2001 From: Vargas Date: Thu, 21 May 2020 13:35:05 -0700 Subject: [PATCH 386/535] make style --- linalg/densemat.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 243cb2cc0b..cfa3e7423c 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3525,7 +3525,7 @@ void BatchLUFactor(DenseTensor &Minv, Array &P) double a = fabs(data_all(piv,i,e)); for (int j = i+1; j < m; j++) { - const double b = fabs(data_all(j,i,e)); + const double b = fabs(data_all(j,i,e)); if (b > a) { a = b; @@ -3538,7 +3538,7 @@ void BatchLUFactor(DenseTensor &Minv, Array &P) // swap rows i and piv in both L and U parts for (int j = 0; j < m; j++) { - mfem::kernels::internal::Swap(data_all(i,j,e), data_all(piv,j,e)); + mfem::kernels::internal::Swap(data_all(i,j,e), data_all(piv,j,e)); } } }//pivot end @@ -3559,7 +3559,7 @@ void BatchLUFactor(DenseTensor &Minv, Array &P) const double a_ik = data_all(i,k,e); for (int j = i+1; j < m; j++) { - data_all(j,k,e) -= a_ik * data_all(j,i,e); + data_all(j,k,e) -= a_ik * data_all(j,i,e); } } @@ -3586,7 +3586,7 @@ void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) // X <- P X for (int i = 0; i < m; i++) { - mfem::kernels::internal::Swap(x_all(i,e), x_all(piv_all(i,e),e)); + mfem::kernels::internal::Swap(x_all(i,e), x_all(piv_all(i,e),e)); } // X <- L^{-1} X @@ -3595,7 +3595,7 @@ void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) const double x_j = x_all(j,e); for (int i = j+1; i < m; i++) { - x_all(i,e) -= data_all(i,j,e) * x_j; + x_all(i,e) -= data_all(i,j,e) * x_j; } } @@ -3605,7 +3605,7 @@ void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) const double x_j = ( x_all(j,e) /= data_all(j,j,e) ); for (int i = 0; i < j; i++) { - x_all(i,e) -= data_all(i,j,e) * x_j; + x_all(i,e) -= data_all(i,j,e) * x_j; } } }); From c6d5d3923a46f479631eef192c90b1e892131897 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Thu, 21 May 2020 13:46:01 -0700 Subject: [PATCH 387/535] remove dead code --- linalg/densemat.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 7a7d54e70d..594c99bd25 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -859,21 +859,11 @@ public: ~DenseTensor() { tdata.Delete(); } }; -void BatchLUFactor(Vector &Minv, const int m,const int NE, Array &P); - void BatchLUFactor(DenseTensor &Minv, Array &P); -void BatchLUFactor_impl(double *Minv, const int m, const int NE, int *P); - -void BatchLUSolve(const Vector &Minv, const int m, const int NE, - const Array &P, Vector &X); - void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X); -void BatchLUSolve_impl(const double *Minv, const int m, const int NE, - const int *P, double *X); - // Inline methods inline double &DenseMatrix::operator()(int i, int j) From aa354598ca43ef936d8467f46d8f35c71283037c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Thu, 21 May 2020 13:47:41 -0700 Subject: [PATCH 388/535] Add proper includes to petsinternals.hpp Remove operatorset logic Use EPSGetTolerances instead of storing internal state --- linalg/petscinternals.hpp | 3 ++ linalg/slepc.cpp | 67 ++++++++++++++++----------------------- linalg/slepc.hpp | 8 ----- 3 files changed, 30 insertions(+), 48 deletions(-) diff --git a/linalg/petscinternals.hpp b/linalg/petscinternals.hpp index 7b4af106a5..974fc53b4e 100644 --- a/linalg/petscinternals.hpp +++ b/linalg/petscinternals.hpp @@ -12,6 +12,9 @@ #ifndef MFEM_PETSCINTERNALS #define MFEM_PETSCINTERNALS +#include "../general/error.hpp" +#include "petsc.h" + // Error handling // Prints PETSc's stacktrace and then calls MFEM_ABORT // We cannot use PETSc's CHKERRQ since it returns a PetscErrorCode diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index c1c38d1c81..e327ed350e 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -52,11 +52,8 @@ void MFEMFinalizeSlepc() SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix) { clcustom = false; - _tol = PETSC_DEFAULT; - _max_its = PETSC_DEFAULT; VR = NULL; VC = NULL; - operatorset = false; ierr = EPSCreate(comm,&eps); CCHKERRQ(comm,ierr); ierr = EPSSetOptionsPrefix(eps, prefix.c_str()); PCHKERRQ(eps, ierr); @@ -72,41 +69,46 @@ SlepcEigenSolver::~SlepcEigenSolver() void SlepcEigenSolver::SetOperator(const PetscParMatrix &op) { - if (operatorset) - { - delete VR; - delete VC; - VR = VC = NULL; - } + delete VR; + delete VC; + VR = VC = NULL; ierr = EPSSetOperators(eps,op,NULL); PCHKERRQ(eps, ierr); - operatorset = true; + + VR = new PetscParVector(op, true, false); + VC = new PetscParVector(op, true, false); + } void SlepcEigenSolver::SetOperators(const PetscParMatrix &op, const PetscParMatrix&opB) { - if (operatorset) - { - delete VR; - delete VC; - VR = VC = NULL; - } + delete VR; + delete VC; + VR = VC = NULL; ierr = EPSSetOperators(eps,op,opB); PCHKERRQ(eps,ierr); - operatorset = true; + + VR = new PetscParVector(op, true, false); + VC = new PetscParVector(op, true, false); } void SlepcEigenSolver::SetTol(double tol) { - _tol = tol; - ierr = EPSSetTolerances(eps,_tol,_max_its); PCHKERRQ(eps,ierr); + int max_its; + + ierr = EPSGetTolerances(eps,NULL,&max_its); PCHKERRQ(eps,ierr); + // Work around uninitialized maximum iterations + if (max_its==0) { max_its = PETSC_DECIDE; } + ierr = EPSSetTolerances(eps,tol,max_its); PCHKERRQ(eps,ierr); } void SlepcEigenSolver::SetMaxIter(int max_its) { - _max_its = max_its; - ierr = EPSSetTolerances(eps,_tol,_max_its); PCHKERRQ(eps,ierr); + double tol; + + ierr = EPSGetTolerances(eps,&tol,NULL); PCHKERRQ(eps,ierr); + ierr = EPSSetTolerances(eps,tol,max_its); PCHKERRQ(eps,ierr); } void SlepcEigenSolver::SetNumModes(int num_eigs) @@ -145,12 +147,8 @@ void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr, void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr) const { - if (!VR) - { - Mat pA = NULL; - ierr = EPSGetOperators(eps, &pA, NULL); PCHKERRQ(eps,ierr); - VR = new PetscParVector(pA, true, false); - } + MFEM_VERIFY(VR,"Missing real vector"); + VR->PlaceArray(vr.GetData()); ierr = EPSGetEigenvector(eps,i,*VR,NULL); PCHKERRQ(eps,ierr); VR->ResetArray(); @@ -160,20 +158,9 @@ void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr) const void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr, Vector & vc) const { - if (!VR || !VC) - { - Mat pA = NULL; - ierr = EPSGetOperators(eps, &pA, NULL); PCHKERRQ(eps,ierr); + MFEM_VERIFY(VR,"Missing real vector"); + MFEM_VERIFY(VC,"Missing imaginary vector"); - if (!VR) - { - VR = new PetscParVector(pA, true, false); - } - if (!VC) - { - VC = new PetscParVector(pA, true, false); - } - } VR->PlaceArray(vr.GetData()); VC->PlaceArray(vc.GetData()); ierr = EPSGetEigenvector(eps,i,*VR,*VC); PCHKERRQ(eps,ierr); diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index 4dfbf88506..8b118f9cad 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -38,18 +38,10 @@ private: /// SLEPc linear eigensolver object EPS eps; - /// Solver tolerance - double _tol; - - /// Maximum number of iterations - int _max_its; /// Real and imaginary part of eigenvector mutable PetscParVector *VR, *VC; - /// Boolean to handle SetOperator calls - mutable bool operatorset; - public: /// Constructors SlepcEigenSolver(MPI_Comm comm, const std::string &prefix = std::string()); From aae15033bc6e8aa1569196edcfb35a394c4ec2a9 Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 21 May 2020 17:05:31 -0700 Subject: [PATCH 389/535] The common lib gets built for the meshing miniapps. --- miniapps/meshing/makefile | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/miniapps/meshing/makefile b/miniapps/meshing/makefile index 665b323e0f..28be87aa4f 100644 --- a/miniapps/meshing/makefile +++ b/miniapps/meshing/makefile @@ -31,22 +31,30 @@ else MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS) endif -MFEM_LIBS += -L$(MFEM_DIR)/miniapps/common -lmfem-common -Wl,-rpath,$(abspath\ - $(MFEM_DIR)/miniapps/common) +COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common + +# If MFEM_SHARED is set, add the ../common rpath +COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\ + $(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\ + $(MFEM_BUILD_DIR)/miniapps/common)) .SUFFIXES: .SUFFIXES: .o .cpp .mk -.PHONY: all clean clean-build clean-exec +.PHONY: all lib-common clean clean-build clean-exec # Remove built-in rule %: %.cpp # Replace the default implicit rule for *.cpp files -%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) - $(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS) +%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common + $(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(COMMON_LIB) $(MFEM_LIBS) all: $(MINIAPPS) +# Rule for building lib-common +lib-common: + $(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common + # Rules to copy the *.mesh files - needed for running the sample runs when # building out-of-source: ifneq ($(SRC),) From 7d0ecbba20f10d3b585f525789d43159c381da84 Mon Sep 17 00:00:00 2001 From: Julian Andrej Date: Thu, 21 May 2020 17:23:14 -0700 Subject: [PATCH 390/535] disable exceptions in zstr --- general/zstr.hpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/general/zstr.hpp b/general/zstr.hpp index dc61bcdcce..405b600667 100644 --- a/general/zstr.hpp +++ b/general/zstr.hpp @@ -203,10 +203,10 @@ public: { mode |= std::ios_base::in; exceptions(std::ios_base::badbit); - detail::static_method_holder::check_mode(filename, mode); + // detail::static_method_holder::check_mode(filename, mode); std::ifstream::open(filename, mode); - detail::static_method_holder::check_open(this, filename, mode); - detail::static_method_holder::check_peek(this, filename, mode); + // detail::static_method_holder::check_open(this, filename, mode); + // detail::static_method_holder::check_peek(this, filename, mode); } }; // class ifstream @@ -225,9 +225,9 @@ public: { mode |= std::ios_base::out; exceptions(std::ios_base::badbit); - detail::static_method_holder::check_mode(filename, mode); + // detail::static_method_holder::check_mode(filename, mode); std::ofstream::open(filename, mode); - detail::static_method_holder::check_open(this, filename, mode); + // detail::static_method_holder::check_open(this, filename, mode); } }; // class ofstream @@ -246,10 +246,10 @@ public: { if (! (mode & std::ios_base::out)) { mode |= std::ios_base::in; } exceptions(std::ios_base::badbit); - detail::static_method_holder::check_mode(filename, mode); + // detail::static_method_holder::check_mode(filename, mode); std::fstream::open(filename, mode); - detail::static_method_holder::check_open(this, filename, mode); - detail::static_method_holder::check_peek(this, filename, mode); + // detail::static_method_holder::check_open(this, filename, mode); + // detail::static_method_holder::check_peek(this, filename, mode); } }; // class fstream @@ -754,6 +754,7 @@ public: { rdbuf(_fs.rdbuf()); } + setstate(_fs.rdstate()); exceptions(std::ios_base::badbit); } @@ -781,6 +782,7 @@ public: #else rdbuf(_fs.rdbuf()); #endif + setstate(_fs.rdstate()); exceptions(std::ios_base::badbit); } From c0721762872a57d4dd48a9cfffd95a4e86f43a36 Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 21 May 2020 17:29:01 -0700 Subject: [PATCH 391/535] cmake fix. --- miniapps/meshing/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miniapps/meshing/CMakeLists.txt b/miniapps/meshing/CMakeLists.txt index 6b882eedee..e5afee4fc4 100644 --- a/miniapps/meshing/CMakeLists.txt +++ b/miniapps/meshing/CMakeLists.txt @@ -31,7 +31,8 @@ add_mfem_miniapp(extruder add_mfem_miniapp(mesh-optimizer MAIN mesh-optimizer.cpp - LIBRARIES mfem) + ${MFEM_MINIAPPS_COMMON_HEADERS} + LIBRARIES mfem mfem-common) add_mfem_miniapp(minimal-surface MAIN minimal-surface.cpp @@ -55,7 +56,8 @@ add_test(NAME minimal-surface COMMAND minimal-surface -no-vis) if (MFEM_USE_MPI) add_mfem_miniapp(pmesh-optimizer MAIN pmesh-optimizer.cpp - LIBRARIES mfem) + ${MFEM_MINIAPPS_COMMON_HEADERS} + LIBRARIES mfem mfem-common) add_mfem_miniapp(pminimal-surface MAIN pminimal-surface.cpp From c6d74cda89de8dfe18b6889622bf6cd716cd8aeb Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 21 May 2020 19:38:53 -0700 Subject: [PATCH 392/535] Fixed an include. --- miniapps/meshing/mesh-optimizer.cpp | 2 +- miniapps/meshing/pmesh-optimizer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 61108e8f4f..486cb5349f 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -69,7 +69,7 @@ #include "mfem.hpp" -#include "miniapps/common/fem_extras.hpp" +#include "../common/mfem-common.hpp" #include #include diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 64b0b6c9eb..6a48aaf891 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -68,7 +68,7 @@ // mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 #include "mfem.hpp" -#include "miniapps/common/pfem_extras.hpp" +#include "../common/mfem-common.hpp" #include #include From 695e98a6c8a4bdd2726048eadce901f0b101e095 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 22 May 2020 12:42:08 -0700 Subject: [PATCH 393/535] Make LinearFormIntegrator::SetIntRule virtual --- fem/lininteg.hpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index f227c61bbb..b94a68598c 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -36,7 +36,7 @@ public: FaceElementTransformations &Tr, Vector &elvect); - void SetIntRule(const IntegrationRule *ir) { IntRule = ir; } + virtual void SetIntRule(const IntegrationRule *ir) { IntRule = ir; } const IntegrationRule* GetIntRule() { return IntRule; } virtual ~LinearFormIntegrator() { } @@ -437,11 +437,23 @@ private: public: VectorQuadratureLFIntegrator(VectorQuadratureFunctionCoefficient &vqfc, const IntegrationRule *ir) - : LinearFormIntegrator(ir), vqfc(vqfc) { } + : LinearFormIntegrator(ir), vqfc(vqfc) + { + if (ir) + { + MFEM_WARNING("Integration rule not used in this class. " + "The QuadratureFunction integration rules are used instead"); + } + } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect); + void SetIntRule(const IntegrationRule *ir) override + { + MFEM_WARNING("Integration rule not used in this class. " + "The QuadratureFunction integration rules are used instead"); + } }; /** Class for domain integration L(v) := (f, v) that makes use @@ -454,11 +466,23 @@ private: public: QuadratureLFIntegrator(QuadratureFunctionCoefficient &qfc, const IntegrationRule *ir) - : LinearFormIntegrator(ir), qfc(qfc) { } + : LinearFormIntegrator(ir), qfc(qfc) + { + if (ir) + { + MFEM_WARNING("Integration rule not used in this class. " + "The QuadratureFunction integration rules are used instead"); + } + } using LinearFormIntegrator::AssembleRHSElementVect; void AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect); + void SetIntRule(const IntegrationRule *ir) override + { + MFEM_WARNING("Integration rule not used in this class. " + "The QuadratureFunction integration rules are used instead"); + } }; } From 1d43d15b5cf5d2e725e4e74fc049d0bf3653a81d Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 22 May 2020 16:05:46 -0700 Subject: [PATCH 394/535] Alignments. --- fem/coefficient.cpp | 1 - fem/lininteg.cpp | 6 +----- tests/unit/fem/test_quadf_coef.cpp | 11 ++++++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index ba99b6d7fc..202d5b0d4b 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -780,7 +780,6 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) { - QuadF.HostRead(); Vector temp; QuadF.GetElementValues(T.ElementNo, ip.index, temp); diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 1a661c3553..2725e1dbc5 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -772,11 +772,8 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( } void VectorQuadratureLFIntegrator::AssembleRHSElementVect( - const FiniteElement &fe, - ElementTransformation &Tr, - Vector &elvect) + const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect) { - const IntegrationRule *ir = &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); @@ -808,7 +805,6 @@ void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect) { - const IntegrationRule *ir = &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index 4380a90ca2..334d016f3b 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -34,8 +34,8 @@ TEST_CASE("Quadrature Function Coefficients", const IntegrationRule ir = qspace.GetElementIntRule(0); - const GeometricFactors *geom_facts = mesh.GetGeometricFactors(ir, - GeometricFactors::COORDINATES); + const GeometricFactors *geom_facts = + mesh.GetGeometricFactors(ir, GeometricFactors::COORDINATES); { int nelems = quadf_coeff.Size() / quadf_coeff.GetVDim() / ir.GetNPoints(); @@ -46,7 +46,8 @@ TEST_CASE("Quadrature Function Coefficients", for (int j = 0; j < vdim; j++) { //X has dims nqpts x sdim x ne - quadf_coeff((i * vdim) + j) = geom_facts->X((i * vdim * dim) + (vdim * 2) + j ); + quadf_coeff((i * vdim) + j) = + geom_facts->X((i * vdim * dim) + (vdim * 2) + j ); } } } @@ -63,8 +64,8 @@ TEST_CASE("Quadrature Function Coefficients", for (int k = 0; k < nqpts; k++) { //X has dims nqpts x sdim x ne - quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = geom_facts->X(( - i * nqpts * vdim) + (j * nqpts) + k ); + quadf_vcoeff((i * nqpts * vdim) + (k * vdim ) + j) = + geom_facts->X((i * nqpts * vdim) + (j * nqpts) + k); } } } From ecaf79cb0b9f5707b8f367a3247af9861069b4f3 Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 22 May 2020 16:30:10 -0700 Subject: [PATCH 395/535] Compilation warnings. --- fem/lininteg.hpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index b94a68598c..1a203f0e83 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -447,9 +447,11 @@ public: } using LinearFormIntegrator::AssembleRHSElementVect; - void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, Vector &elvect); - void SetIntRule(const IntegrationRule *ir) override + virtual void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect); + + virtual void SetIntRule(const IntegrationRule *ir) { MFEM_WARNING("Integration rule not used in this class. " "The QuadratureFunction integration rules are used instead"); @@ -476,9 +478,11 @@ public: } using LinearFormIntegrator::AssembleRHSElementVect; - void AssembleRHSElementVect(const FiniteElement &fe, - ElementTransformation &Tr, Vector &elvect); - void SetIntRule(const IntegrationRule *ir) override + virtual void AssembleRHSElementVect(const FiniteElement &fe, + ElementTransformation &Tr, + Vector &elvect); + + virtual void SetIntRule(const IntegrationRule *ir) { MFEM_WARNING("Integration rule not used in this class. " "The QuadratureFunction integration rules are used instead"); From a68ed06b7eb9cceb1ba2a7c223220ff419c471e1 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 22 May 2020 19:50:45 -0700 Subject: [PATCH 396/535] address last few comments --- fem/coefficient.cpp | 7 ++++--- fem/coefficient.hpp | 4 ++-- fem/lininteg.cpp | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 202d5b0d4b..4ecddeb634 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -781,14 +781,15 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V, const IntegrationPoint &ip) { QuadF.HostRead(); - Vector temp; - QuadF.GetElementValues(T.ElementNo, ip.index, temp); + if (index == 0 && vdim == QuadF.GetVDim()) { - V = temp; + QuadF.GetElementValues(T.ElementNo, ip.index, V); } else { + Vector temp; + QuadF.GetElementValues(T.ElementNo, ip.index, temp); V.SetSize(vdim); for (int i = 0; i < vdim; i++) { diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 51032856f6..0a24d9d861 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -966,7 +966,7 @@ public: should have the bounds of 1 <= length <= (length QuadFunc - index). */ void SetComponent(int _index, int _length); - const QuadratureFunction *GetQuadFunction() const { return &QuadF; } + const QuadratureFunction& GetQuadFunction() const { return QuadF; } using VectorCoefficient::Eval; virtual void Eval(Vector &V, ElementTransformation &T, @@ -987,7 +987,7 @@ public: /// Constructor with a quadrature function as input QuadratureFunctionCoefficient(QuadratureFunction &qf); - const QuadratureFunction *GetQuadFunction() const { return &QuadF; } + const QuadratureFunction& GetQuadFunction() const { return QuadF; } virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 2725e1dbc5..98dbd6213c 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -775,7 +775,7 @@ void VectorQuadratureLFIntegrator::AssembleRHSElementVect( const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect) { const IntegrationRule *ir = - &vqfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); + &vqfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo); const int nqp = ir->GetNPoints(); const int vdim = vqfc.GetVDim(); @@ -806,7 +806,7 @@ void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, Vector &elvect) { const IntegrationRule *ir = - &qfc.GetQuadFunction()->GetSpace()->GetElementIntRule(Tr.ElementNo); + &qfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo); const int nqp = ir->GetNPoints(); const int ndofs = fe.GetDof(); From db90d96e3b6fd2bdf08e5684774774db73c4e7bd Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 22 May 2020 19:51:10 -0700 Subject: [PATCH 397/535] CHANGELOG additions --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 720e879a86..310b363423 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -49,6 +49,10 @@ Discretization improvements ElementTransformation argument to support evaluation on boundary elements and, in the continuous field case, arbitrary mesh edges and faces. +- Added new coefficient and vector coefficient classes for QuadratureFunctions. + Additionaly, new LinearForm integrators were also added which make use of + these new QuadratureFunction coefficient classes. + Linear and nonlinear solvers ---------------------------- - Added power method to iteratively estimate the largest eigenvalue and the From deceb79c31a1454bdbd156fc202c4697f3fff94a Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 22 May 2020 20:43:30 -0700 Subject: [PATCH 398/535] LBFGSSolver inherits NewtonSolver. TMOPSolver inherits LBFGSSolver and switches its Mult(). --- fem/tmop_tools.hpp | 39 ++++++-- linalg/solvers.cpp | 127 +++++++++++++++++++++++++++ linalg/solvers.hpp | 26 ++++++ miniapps/meshing/mesh-optimizer.hpp | 3 +- miniapps/meshing/pmesh-optimizer.cpp | 2 +- 5 files changed, 190 insertions(+), 7 deletions(-) diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index f4f5aff497..35543ec5c5 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -109,9 +109,11 @@ public: }; #endif -class TMOPNewtonSolver : public NewtonSolver +class TMOPNewtonSolver : public LBFGSSolver { protected: + // 0 - Newton, 1 - LBFGS. + int solver_type; bool parallel; // Quadrature points that are checked for negative Jacobians etc. @@ -121,15 +123,42 @@ protected: public: #ifdef MFEM_USE_MPI - TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule) - : NewtonSolver(comm), parallel(true), ir(irule) { } + TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0) + : LBFGSSolver(comm), solver_type(type), parallel(true), ir(irule) { } #endif - TMOPNewtonSolver(const IntegrationRule &irule) - : NewtonSolver(), parallel(false), ir(irule) { } + TMOPNewtonSolver(const IntegrationRule &irule, int type = 0) + : LBFGSSolver(), solver_type(type), parallel(false), ir(irule) { } virtual double ComputeScalingFactor(const Vector &x, const Vector &b) const; virtual void ProcessNewState(const Vector &x) const; + + virtual void Mult(const Vector &b, Vector &x) const + { + if (solver_type == 0) + { + NewtonSolver::Mult(b, x); + } + else if (solver_type == 1) + { + LBFGSSolver::Mult(b, x); + } + else { MFEM_ABORT("Invalid type"); } + } + + virtual void SetSolver(Solver &solver) + { + if (solver_type == 0) + { + NewtonSolver::SetSolver(solver); + } + else if (solver_type == 1) + { + LBFGSSolver::SetSolver(solver); + } + else { MFEM_ABORT("Invalid type"); } + } + virtual void SetPreconditioner(Solver &pr) { SetSolver(pr); } }; void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm, diff --git a/linalg/solvers.cpp b/linalg/solvers.cpp index f67afb8f54..f99dc2470b 100644 --- a/linalg/solvers.cpp +++ b/linalg/solvers.cpp @@ -1641,6 +1641,133 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const final_norm = norm; } +void LBFGSSolver::Mult(const Vector &b, Vector &x) const +{ + MFEM_ASSERT(oper != NULL, "the Operator is not set (use SetOperator)."); + + // Quadrature points that are checked for negative Jacobians etc. + Vector sk, rk, yk, skt, ykt, rho, alpha; + DenseMatrix skM(width, m), ykM(width, m); + + //r - r_{k+1}, c - descent direction + sk.SetSize(width); //x_{k+1}-x_k + rk.SetSize(width); //nabla(f(x_{k})) + yk.SetSize(width); //r_{k+1}-r_{k} + skt.SetSize(width); //work vector + ykt.SetSize(width); //work vector + rho.SetSize(m); //1/(dot(yk,sk) + alpha.SetSize(m); //rhok*sk'*c + + int it; + double norm0, norm, norm_goal; + const bool have_b = (b.Size() == Height()); + + if (!iterative_mode) + { + x = 0.0; + } + + // r = F(x)-b + oper->Mult(x, r); + if (have_b) { r -= b; } + + c = r; // initial descent direction + + norm0 = norm = Norm(r); + norm_goal = std::max(rel_tol*norm, abs_tol); + for (it = 0; true; it++) + { + MFEM_ASSERT(IsFinite(norm), "norm = " << norm); + if (print_level >= 0) + { + mfem::out << "LBFGS iteration " << it + << " : ||r|| = " << norm; + if (it > 0) + { + mfem::out << ", ||r||/||r_0|| = " << norm/norm0; + } + mfem::out << '\n'; + } + + if (norm <= norm_goal) + { + converged = 1; + break; + } + + if (it >= max_iter) + { + converged = 0; + break; + } + + rk = r; + const double c_scale = ComputeScalingFactor(x, b); + if (c_scale == 0.0) + { + converged = 0; + break; + } + add(x, -c_scale, c, x); //x_{k+1} = x_k - c_scale*c + + ProcessNewState(x); + + oper->Mult(x, r); + if (have_b) + { + r -= b; + } + + // LBFGS - construct descent direction + int klim; + subtract(r, rk, yk); // yk = r_{k+1} - r_{k} + sk = c; sk *= -c_scale; //sk = x_{k+1} - x_{k} = -c_scale*c + double gamma = Dot(sk, yk)/Dot(yk, yk); + + // Save last m vectors + if ( it < m) + { + skM.SetCol(it, sk); + ykM.SetCol(it, yk); + klim = it+1; + } + else + { + for (int i = 0; i < m-1; i++) + { + skM.SetCol(i, skM.GetColumn(i+1)); //shift columns + ykM.SetCol(i, ykM.GetColumn(i+1)); //shift columns + } + skM.SetCol(m-1, sk); // copy new column + ykM.SetCol(m-1, yk); // copy new colum + klim = m; + } + + c = r; + for (int i = klim-1; i > -1; i--) + { + skM.GetColumn(i, skt); + ykM.GetColumn(i, ykt); + rho(i) = 1./Dot(skt, ykt); + alpha(i) = rho(i)*Dot(skt,c); + add(c, -alpha(i), ykt, c); + } + + c *= gamma; // scale search direction + for (int i = 0; i < klim ; i++) + { + skM.GetColumn(i,skt); + ykM.GetColumn(i,ykt); + double betai = rho(i)*Dot(ykt, c); + add(c, alpha(i)-betai, skt, c); + } + + norm = Norm(r); + } + + final_iter = it; + final_norm = norm; +} int aGMRES(const Operator &A, Vector &x, const Vector &b, const Operator &M, int &max_iter, diff --git a/linalg/solvers.hpp b/linalg/solvers.hpp index 904a55f6a9..d5290334c8 100644 --- a/linalg/solvers.hpp +++ b/linalg/solvers.hpp @@ -416,6 +416,32 @@ public: virtual void ProcessNewState(const Vector &x) const { } }; +/** L-BFGS method for solving F(x)=b for a given operator F, by minimizing + the norm of F(x) - b. Requires only the action of the operator F. */ +class LBFGSSolver : public NewtonSolver +{ +protected: + int m = 20; + +public: + LBFGSSolver() : NewtonSolver() { } + +#ifdef MFEM_USE_MPI + LBFGSSolver(MPI_Comm _comm) : NewtonSolver(_comm) { } +#endif + + void SetKDim(int dim) { m = dim; } + + /// Solve the nonlinear system with right-hand side @a b. + /** If `b.Size() != Height()`, then @a b is assumed to be zero. */ + virtual void Mult(const Vector &b, Vector &x) const; + + virtual void SetPreconditioner(Solver &pr) + { MFEM_WARNING("L-BFGS won't use the given preconditioner."); } + virtual void SetSolver(Solver &solver) + { MFEM_WARNING("L-BFGS won't use the given solver."); } +}; + /** Adaptive restarted GMRES. m_max and m_min(=1) are the maximal and minimal restart parameters. m_step(=1) is the step to use for going from m_max and m_min. diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index ef3e64bae2..ba57b55511 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -227,7 +227,7 @@ void DiffuseField(ParGridFunction &field, int smooth_steps) } #endif - +/* class TMOPLBFGSOptimizer : public TMOPNewtonSolver { protected: @@ -380,3 +380,4 @@ void TMOPLBFGSOptimizer::Mult(const Vector &b, Vector &x) const final_iter = it; final_norm = norm; } +*/ diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 128b548be0..4ef1279be7 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -772,7 +772,7 @@ int main (int argc, char *argv[]) } else { - TMOPLBFGSOptimizer *tns = new TMOPLBFGSOptimizer(pfespace->GetComm(), *ir); + TMOPNewtonSolver *tns = new TMOPNewtonSolver(pfespace->GetComm(), *ir, 1); tns->SetKDim(40); solver = tns; cout << "TMOPLBFGSOptimizer is used (as all det(J) > 0).\n"; From 9e300dd1594fbd87e5ab2ff878d67cbb8b8aceca Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Mon, 25 May 2020 12:12:50 +0200 Subject: [PATCH 399/535] Make GenerateFaceDofsFromBdr work for non-NURBS meshes --- fem/fespace.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index cd3a0fa1e2..992d698599 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1530,6 +1530,8 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() if (face_dof) { return; } if (!mesh->BdrInfoAvailable()) { return; } + // MFEM_VERIFY(bdrElem_dof, "NURBSExt not defined."); + // Find bdr to face mapping face_to_be.SetSize(mesh->GetNumFaces()); face_to_be = -1; @@ -1547,7 +1549,7 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() { int b = face_to_be[f]; if (b == -1) { continue;} - bdrElem_dof->GetRow(b, row); + GetBdrElementDofs(b, row); Connection conn(f,0); for (int i = 0; i < row.Size(); i++) { From 8d458616a77bc812c7d7626c519f9522ee9e3d38 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Mon, 25 May 2020 14:03:08 -0400 Subject: [PATCH 400/535] Updates PUMI version --- INSTALL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index e14d866d82..5bbd0ab4a7 100644 --- a/INSTALL +++ b/INSTALL @@ -613,7 +613,7 @@ The specific libraries and their options are: URL: https://scorec.rpi.edu/pumi https://github.com/SCOREC/core Options: PUMI_OPT, PUMI_LIB. - Versions: PUMI >= 2.2.0. + Versions: Any version after commit e013b92e7 in PUMI's master branch - HiOp (optional), used when MFEM_USE_HIOP = YES. URL: https://github.com/LLNL/hiop From efa34ab718ca08b8c7a56e6512a39325c77f8f9f Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 26 May 2020 11:25:34 +0200 Subject: [PATCH 401/535] make style --- fem/fespace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 992d698599..9a98bc3dec 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1530,7 +1530,7 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() if (face_dof) { return; } if (!mesh->BdrInfoAvailable()) { return; } - // MFEM_VERIFY(bdrElem_dof, "NURBSExt not defined."); + // MFEM_VERIFY(bdrElem_dof, "NURBSExt not defined."); // Find bdr to face mapping face_to_be.SetSize(mesh->GetNumFaces()); From 5d10bdb33956bcd2dc432cae90a965d4a3ef5bf5 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Tue, 26 May 2020 06:50:46 -0700 Subject: [PATCH 402/535] LBFGS removed from mesh-optimizer.hpp --- linalg/solvers.hpp | 2 +- miniapps/meshing/mesh-optimizer.cpp | 4 +- miniapps/meshing/mesh-optimizer.hpp | 155 --------------------------- miniapps/meshing/pmesh-optimizer.cpp | 2 - 4 files changed, 2 insertions(+), 161 deletions(-) diff --git a/linalg/solvers.hpp b/linalg/solvers.hpp index d5290334c8..a31f2d983b 100644 --- a/linalg/solvers.hpp +++ b/linalg/solvers.hpp @@ -421,7 +421,7 @@ public: class LBFGSSolver : public NewtonSolver { protected: - int m = 20; + int m = 10; public: LBFGSSolver() : NewtonSolver() { } diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index d17910f4b5..fd14c98490 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -725,10 +725,8 @@ int main(int argc, char *argv[]) } else { - TMOPLBFGSOptimizer *tns = new TMOPLBFGSOptimizer(*ir); - tns->SetKDim(40); + TMOPNewtonSolver *tns = new TMOPNewtonSolver(*ir, 1); solver = tns; - cout << "TMOPLBFGSOptimizer is used (as all det(J) > 0).\n"; solver->SetMaxIter(solver_iter); solver->SetRelTol(solver_rtol); solver->SetAbsTol(0.0); diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index ba57b55511..b907897d4f 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -226,158 +226,3 @@ void DiffuseField(ParGridFunction &field, int smooth_steps) delete Lap; } #endif - -/* -class TMOPLBFGSOptimizer : public TMOPNewtonSolver -{ -protected: - int m = 20; - -public: -#ifdef MFEM_USE_MPI - TMOPLBFGSOptimizer(MPI_Comm comm, const IntegrationRule &irule) - : TMOPNewtonSolver(comm, irule) { } -#endif - TMOPLBFGSOptimizer(const IntegrationRule &irule) - : TMOPNewtonSolver(irule) { } - - virtual void SetKDim(int dim) { m = dim; } - - virtual void Mult(const Vector &b, Vector &x) const; -}; - -void TMOPLBFGSOptimizer::Mult(const Vector &b, Vector &x) const -{ - MFEM_ASSERT(oper != NULL, "the Operator is not set (use SetOperator)."); - MFEM_ASSERT(prec != NULL, "the Solver is not set (use SetSolver)."); - - // Quadrature points that are checked for negative Jacobians etc. - Vector sk, rk, yk, skt, ykt, rho, alpha; - DenseMatrix skM(width, m), ykM(width, m); - - //r - r_{k+1}, c - descent direction - sk.SetSize(width); //x_{k+1}-x_k - rk.SetSize(width); //nabla(f(x_{k})) - yk.SetSize(width); //r_{k+1}-r_{k} - skt.SetSize(width); //work vector - ykt.SetSize(width); //work vector - rho.SetSize(m); //1/(dot(yk,sk) - alpha.SetSize(m); //rhok*sk'*c - - int it; - double norm0, norm, norm_goal; - const bool have_b = (b.Size() == Height()); - - const bool serial = !parallel; - const NonlinearForm *nlf = dynamic_cast(oper); - MFEM_VERIFY(!(serial && nlf == NULL), "Invalid Operator subclass."); - - if (!iterative_mode) - { - x = 0.0; - } - - oper->Mult(x, r); // r = b-Ax - if (have_b) - { - r -= b; - } - - c = r; // initial descent direction - - norm0 = norm = Norm(r); - norm_goal = std::max(rel_tol*norm, abs_tol); - for (it = 0; true; it++) - { - MFEM_ASSERT(IsFinite(norm), "norm = " << norm); - if (print_level >= 0) - { - mfem::out << "LBFGS iteration " << it - << " : ||r|| = " << norm; - if (it > 0) - { - mfem::out << ", ||r||/||r_0|| = " << norm/norm0; - } - mfem::out << '\n'; - } - - if (norm <= norm_goal) - { - converged = 1; - break; - } - - if (it >= max_iter) - { - converged = 0; - break; - } - - rk = r; - const double c_scale = ComputeScalingFactor(x, b); - if (c_scale == 0.0) - { - converged = 0; - break; - } - add(x, -c_scale, c, x); //x_{k+1} = x_k - c_scale*c - - ProcessNewState(x); - - oper->Mult(x, r); - if (have_b) - { - r -= b; - } - - // LBFGS - construct descent direction - int klim; - subtract(r, rk, yk); // yk = r_{k+1} - r_{k} - sk = c; sk *= -c_scale; //sk = x_{k+1} - x_{k} = -c_scale*c - double gamma = Dot(sk, yk)/Dot(yk, yk); - - // Save last m vectors - if ( it < m) - { - skM.SetCol(it, sk); - ykM.SetCol(it, yk); - klim = it+1; - } - else - { - for (int i = 0; i < m-1; i++) - { - skM.SetCol(i, skM.GetColumn(i+1)); //shift columns - ykM.SetCol(i, ykM.GetColumn(i+1)); //shift columns - } - skM.SetCol(m-1, sk); // copy new column - ykM.SetCol(m-1, yk); // copy new colum - klim = m; - } - - c = r; - for (int i = klim-1; i > -1; i--) - { - skM.GetColumn(i, skt); - ykM.GetColumn(i, ykt); - rho(i) = 1./Dot(skt, ykt); - alpha(i) = rho(i)*Dot(skt,c); - add(c, -alpha(i), ykt, c); - } - - c *= gamma; // scale search direction - for (int i = 0; i < klim ; i++) - { - skM.GetColumn(i,skt); - ykM.GetColumn(i,ykt); - double betai = rho(i)*Dot(ykt, c); - add(c, alpha(i)-betai, skt, c); - } - - norm = Norm(r); - } - - final_iter = it; - final_norm = norm; -} -*/ diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 4ef1279be7..986ec0a4c0 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -773,9 +773,7 @@ int main (int argc, char *argv[]) else { TMOPNewtonSolver *tns = new TMOPNewtonSolver(pfespace->GetComm(), *ir, 1); - tns->SetKDim(40); solver = tns; - cout << "TMOPLBFGSOptimizer is used (as all det(J) > 0).\n"; solver->SetMaxIter(solver_iter); solver->SetRelTol(solver_rtol); solver->SetAbsTol(0.0); From a9bcd488cb99c88f76877e3840c1557e4ea1ad45 Mon Sep 17 00:00:00 2001 From: Morteza HS Date: Tue, 26 May 2020 13:14:52 -0400 Subject: [PATCH 403/535] Adds the new pumi version 2.2.3 --- INSTALL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 5bbd0ab4a7..fff398f14a 100644 --- a/INSTALL +++ b/INSTALL @@ -613,7 +613,7 @@ The specific libraries and their options are: URL: https://scorec.rpi.edu/pumi https://github.com/SCOREC/core Options: PUMI_OPT, PUMI_LIB. - Versions: Any version after commit e013b92e7 in PUMI's master branch + Versions: PUMI >= 2.2.3. - HiOp (optional), used when MFEM_USE_HIOP = YES. URL: https://github.com/LLNL/hiop From 46e436b8199a6144c00c5bb775640a1848386307 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 26 May 2020 15:01:56 -0700 Subject: [PATCH 404/535] Correcting comments for clarity --- mesh/mesh_readers.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index 8115395800..649488a52d 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1324,7 +1324,8 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) // Convert nodes to discontinuous GridFunction this->SetCurvature(1, true, Dim, Ordering::byVDIM); - // Renumber elements to remove slave vertices + // Replace "slave" vertex indices in the element connectivity + // with their corresponding "master" vertex indices. for (int i = 0; i < this->GetNE(); i++) { Element *el = this->GetElement(i); @@ -1335,7 +1336,8 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) v[j] = v2v[v[j]]; } } - // Renumber boundary elements to remove slave vertices + // Replace "slave" vertex indices in the boundary element connectivity + // with their corresponding "master" vertex indices. for (int i = 0; i < this->GetNBE(); i++) { Element *el = this->GetBdrElement(i); From faa5a79a164ba1d47397005ef4041c0a5b362aeb Mon Sep 17 00:00:00 2001 From: Tomov Date: Tue, 26 May 2020 17:19:30 -0700 Subject: [PATCH 405/535] Fixed wrong indexing in FiniteElementCollection::GetEdge(). --- fem/fe_coll.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fem/fe_coll.cpp b/fem/fe_coll.cpp index 50c541941b..017775138d 100644 --- a/fem/fe_coll.cpp +++ b/fem/fe_coll.cpp @@ -311,10 +311,10 @@ GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info) eo = edge_info%64; MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, ""); MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, ""); - v[0] = g_consts::Edges[e][0]; - v[1] = g_consts::Edges[e][1]; - v[0] = e_consts::Orient[eo][v[0]]; - v[1] = e_consts::Orient[eo][v[1]]; + v[0] = e_consts::Orient[eo][0]; + v[1] = e_consts::Orient[eo][1]; + v[0] = g_consts::Edges[e][v[0]]; + v[1] = g_consts::Edges[e][v[1]]; } template Date: Tue, 26 May 2020 17:20:44 -0700 Subject: [PATCH 406/535] Adding Gmsh example meshes and corresponding sample runs --- data/annulus-pi-3.msh | 236 ++++ data/torus-pi-3.msh | 2984 +++++++++++++++++++++++++++++++++++++++++ examples/ex1.cpp | 2 + examples/ex1p.cpp | 2 + 4 files changed, 3224 insertions(+) create mode 100644 data/annulus-pi-3.msh create mode 100644 data/torus-pi-3.msh diff --git a/data/annulus-pi-3.msh b/data/annulus-pi-3.msh new file mode 100644 index 0000000000..9366a5567f --- /dev/null +++ b/data/annulus-pi-3.msh @@ -0,0 +1,236 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$Comment +//////////////////////////////////////////////////////////////////////////////// +This is an example of a 3D periodic mesh generated by Gmsh 4.5.6 using +the script: + +//////////////////////////////////////////////////////////////////////////////// +SetFactory("OpenCASCADE"); + +Point(1) = {0.0, 0, 0, 1.0}; +Point(2) = {0.5, 0, 0, 1.0}; +Point(3) = {1.5, 0, 0, 1.0}; +Point(4) = {0.5*Cos(Pi/3), 0.5*Sin(Pi/3), 0, 1.0}; +Point(5) = {1.5*Cos(Pi/3), 1.5*Sin(Pi/3), 0, 1.0}; +Line(1) = {2, 3}; +Line(2) = {4, 5}; +Circle(3) = {2, 1, 4}; +Circle(4) = {3, 1, 5}; +Curve Loop(5) = {1, 4, -2, -3}; +Plane Surface(1) = {5}; + +Transfinite Curve{1} = 7; +Transfinite Curve{2} = 7; +Transfinite Curve{3} = 4; +Transfinite Curve{4} = 10; + +// Set a rotation periodicity constraint: +Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3}; + +// Tag surfaces and volumes with positive integers +Physical Curve(1) = {3}; +Physical Curve(2) = {4}; +Physical Curve(3) = {1}; +Physical Curve(4) = {2}; +Physical Surface(1) = {1}; + +// Generate 2D mesh +Mesh 2; +Mesh.MshFileVersion = 2.2; + +Save "annulus-pi-3.msh"; +//////////////////////////////////////////////////////////////////////////////// +$EndComment +$Nodes +58 +1 0.5 0 0 +2 1.5 0 0 +3 0.2500000000000001 0.4330127018922193 0 +4 0.7500000000000002 1.299038105676658 0 +5 0.6666666666666667 0 0 +6 0.8333333333333333 0 0 +7 1 0 0 +8 1.166666666666667 0 0 +9 1.333333333333333 0 0 +10 0.3333333333333334 0.5773502691896257 0 +11 0.4166666666666667 0.7216878364870322 0 +12 0.5000000000000002 0.8660254037844386 0 +13 0.5833333333333335 1.010362971081845 0 +14 0.6666666666666669 1.154700538379251 0 +15 0.4698463103929543 0.1710100716628341 0 +16 0.3830222215594893 0.3213938048432693 0 +17 1.489857536612915 0.1741393711878452 0 +18 1.459567305869736 0.3459238061136595 0 +19 1.409538931178863 0.5130302149885024 0 +20 1.340448960485119 0.6731987703006925 0 +21 1.253231717119405 0.8242634671062079 0 +22 1.149066664678468 0.9641814145298073 0 +23 1.029362456803102 1.091060462359572 0 +24 0.8957378875541815 1.203184789132564 0 +25 1.184124119469803 0.6608103551010475 0 +26 0.5562637595138884 0.3214512390923595 0 +27 0.9308820471914755 0.1491045483084179 0 +28 0.5833333333333335 0.7216878364870323 0 +29 0.9908713588166244 0.9254330604161887 0 +30 1.306574011075295 0.400897874306144 0 +31 0.7382433711320909 1.010999438281314 0 +32 1.251100814888701 0.1356586735371923 0 +33 0.4514589594438195 0.4598872000487043 0 +34 0.6196542456631401 0.4653889072226228 0 +35 0.7185833139470013 0.3138834998381275 0 +36 0.7983695404145397 0.4676807665456855 0 +37 0.880453986992947 0.3096187380232559 0 +38 0.9767392319645739 0.4683038433902925 0 +39 0.8641456853620439 0.6080729367737738 0 +40 1.03732284470747 0.302923118508485 0 +41 0.628820193941076 0.1639511722116236 0 +42 1.098221397346878 0.1439825951016894 0 +43 0.6666666666666669 0.8660254037844387 0 +44 0.7559765450579081 0.7310702822998748 0 +45 1.149172458135534 0.4699647837754962 0 +46 0.8324867696098854 0.8920763595074568 0 +47 1.094750898576393 0.7929083374477056 0 +48 0.9297946367501273 0.7590648072409287 0 +49 0.8833480450355555 1.041864842383078 0 +50 1.347606581519112 0.2450942159796899 0 +51 0.5060636140126749 0.6002905543163177 0 +52 0.7766222941605497 0.1482744252573178 0 +53 1.04053656307791 0.6048278670005733 0 +54 1.277971696068923 0.5435803996943765 0 +55 0.6819060373191272 0.6018743334085058 0 +56 1.203356010626955 0.2762092302560412 0 +57 0.7881283488918066 1.138689644312559 0 +58 1.374784569260408 0.1201569270856769 0 +$EndNodes +$Elements +114 +1 1 2 3 1 1 5 +2 1 2 3 1 5 6 +3 1 2 3 1 6 7 +4 1 2 3 1 7 8 +5 1 2 3 1 8 9 +6 1 2 3 1 9 2 +7 1 2 4 2 3 10 +8 1 2 4 2 10 11 +9 1 2 4 2 11 12 +10 1 2 4 2 12 13 +11 1 2 4 2 13 14 +12 1 2 4 2 14 4 +13 1 2 1 3 1 15 +14 1 2 1 3 15 16 +15 1 2 1 3 16 3 +16 1 2 2 4 2 17 +17 1 2 2 4 17 18 +18 1 2 2 4 18 19 +19 1 2 2 4 19 20 +20 1 2 2 4 20 21 +21 1 2 2 4 21 22 +22 1 2 2 4 22 23 +23 1 2 2 4 23 24 +24 1 2 2 4 24 4 +25 2 2 1 1 27 42 40 +26 2 2 1 1 27 40 37 +27 2 2 1 1 35 52 37 +28 2 2 1 1 39 55 36 +29 2 2 1 1 37 52 27 +30 2 2 1 1 44 55 39 +31 2 2 1 1 5 41 1 +32 2 2 1 1 3 33 10 +33 2 2 1 1 1 41 15 +34 2 2 1 1 16 33 3 +35 2 2 1 1 48 53 47 +36 2 2 1 1 47 53 25 +37 2 2 1 1 39 48 44 +38 2 2 1 1 44 48 46 +39 2 2 1 1 25 53 45 +40 2 2 1 1 41 52 35 +41 2 2 1 1 36 55 34 +42 2 2 1 1 45 54 25 +43 2 2 1 1 34 51 33 +44 2 2 1 1 40 56 45 +45 2 2 1 1 45 56 30 +46 2 2 1 1 34 55 51 +47 2 2 1 1 26 41 35 +48 2 2 1 1 15 41 26 +49 2 2 1 1 26 33 16 +50 2 2 1 1 21 25 20 +51 2 2 1 1 23 29 22 +52 2 2 1 1 19 30 18 +53 2 2 1 1 26 34 33 +54 2 2 1 1 35 37 36 +55 2 2 1 1 35 36 34 +56 2 2 1 1 39 53 48 +57 2 2 1 1 26 35 34 +58 2 2 1 1 37 40 38 +59 2 2 1 1 15 26 16 +60 2 2 1 1 37 38 36 +61 2 2 1 1 38 39 36 +62 2 2 1 1 46 49 31 +63 2 2 1 1 11 28 12 +64 2 2 1 1 7 27 6 +65 2 2 1 1 12 43 13 +66 2 2 1 1 8 42 7 +67 2 2 1 1 13 31 14 +68 2 2 1 1 9 32 8 +69 2 2 1 1 42 56 40 +70 2 2 1 1 7 42 27 +71 2 2 1 1 28 43 12 +72 2 2 1 1 13 43 31 +73 2 2 1 1 32 42 8 +74 2 2 1 1 28 44 43 +75 2 2 1 1 29 49 46 +76 2 2 1 1 43 46 31 +77 2 2 1 1 40 45 38 +78 2 2 1 1 5 52 41 +79 2 2 1 1 44 46 43 +80 2 2 1 1 32 56 42 +81 2 2 1 1 33 51 10 +82 2 2 1 1 6 52 5 +83 2 2 1 1 10 51 11 +84 2 2 1 1 4 57 24 +85 2 2 1 1 17 58 2 +86 2 2 1 1 21 47 25 +87 2 2 1 1 29 47 22 +88 2 2 1 1 14 57 4 +89 2 2 1 1 2 58 9 +90 2 2 1 1 22 47 21 +91 2 2 1 1 45 53 38 +92 2 2 1 1 18 50 17 +93 2 2 1 1 24 49 23 +94 2 2 1 1 25 54 20 +95 2 2 1 1 19 54 30 +96 2 2 1 1 30 54 45 +97 2 2 1 1 23 49 29 +98 2 2 1 1 30 50 18 +99 2 2 1 1 38 53 39 +100 2 2 1 1 20 54 19 +101 2 2 1 1 11 51 28 +102 2 2 1 1 27 52 6 +103 2 2 1 1 46 48 29 +104 2 2 1 1 28 55 44 +105 2 2 1 1 51 55 28 +106 2 2 1 1 29 48 47 +107 2 2 1 1 31 57 14 +108 2 2 1 1 9 58 32 +109 2 2 1 1 50 56 32 +110 2 2 1 1 50 58 17 +111 2 2 1 1 24 57 49 +112 2 2 1 1 30 56 50 +113 2 2 1 1 49 57 31 +114 2 2 1 1 32 58 50 +$EndElements +$Periodic +1 +1 1 2 +Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1 +7 +1 3 +2 4 +5 10 +6 11 +7 12 +8 13 +9 14 +$EndPeriodic diff --git a/data/torus-pi-3.msh b/data/torus-pi-3.msh new file mode 100644 index 0000000000..c0664131d2 --- /dev/null +++ b/data/torus-pi-3.msh @@ -0,0 +1,2984 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$Comments +//////////////////////////////////////////////////////////////////////////////// +This is an example of a 3D periodic mesh generated by Gmsh 4.5.6 using +the script: + +//////////////////////////////////////////////////////////////////////////////// +SetFactory("OpenCASCADE"); + +Torus(1) = {0,0,0, 1.5, 1, Pi/3}; + +pts() = PointsOf{ Volume{1}; }; + +Characteristic Length{ pts() } = 0.25; + +// Set a rotation periodicity constraint: +Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3}; + +// Tag surfaces and volumes with positive integers +Physical Surface(1) = {1}; +Physical Surface(2) = {2}; +Physical Surface(3) = {3}; +Physical Volume(1) = {1}; + +// Generate 3D mesh +Mesh 3; + +Mesh.MshFileVersion = 2.2; +Save "torus-pi-3.msh"; +//////////////////////////////////////////////////////////////////////////////// +$EndComments +$Nodes +471 +1 1.25 2.165063509461096 -2.449293598294706e-16 +2 2.5 0 -2.449293598294706e-16 +3 2.488679806432712 0.237640108260457 -2.449293598294706e-16 +4 2.454821743156767 0.4731281109010261 -2.449293598294706e-16 +5 2.398732434036243 0.704331392103575 -2.449293598294706e-16 +6 2.320919832540181 0.9291561391508196 -2.449293598294706e-16 +7 2.222088621637308 1.145566304318527 -2.449293598294706e-16 +8 2.103133832077952 1.351602043638995 -2.449293598294706e-16 +9 1.965132736856968 1.545397465551513 -2.449293598294706e-16 +10 1.809335095262675 1.72519752870528 -2.449293598294706e-16 +11 1.637151834863212 1.889373935885646 -2.449293598294706e-16 +12 1.450142273927995 2.036439880125839 -2.449293598294706e-16 +13 1.235470908713021 2.139898385164242 0.2393156642875992 +14 1.192728012821542 2.065865517817574 0.4647231720630622 +15 1.124255373808909 1.94726742811937 0.6631226588653242 +16 1.034032368818138 1.790996599463815 0.8229838721713985 +17 0.9273024435212676 1.606134946161604 0.9350162426854153 +18 0.8102683401255636 1.403425932861976 0.9927088740985636 +19 0.6897316597286507 1.194650278238831 0.9927088740631602 +20 0.5726975541129594 0.9919412610940719 0.9350162408909761 +21 0.4659676266344224 0.8070796040131041 0.8229838658936566 +22 0.3757446259142614 0.650808782754462 0.6631226582403703 +23 0.3072719871531447 0.5322106934918979 0.4647231719666005 +24 0.2645290910297036 0.4581778257434591 0.239315662199983 +25 0.2500000000000001 0.4330127018922194 1.224646799147353e-16 +26 0.2645290912869792 0.4581778261890734 -0.2393156642875988 +27 0.3072719871784581 0.5322106935357419 -0.4647231720630619 +28 0.3757446261910917 0.6508087832339461 -0.6631226588653238 +29 0.465967631181862 0.8070796118895007 -0.8229838721713983 +30 0.5726975564787327 0.9919412651917113 -0.9350162426854151 +31 0.6897316598744364 1.19465027849134 -0.9927088740985635 +32 0.8102683402713494 1.403425933114484 -0.9927088740631603 +33 0.9273024458870408 1.606134950259244 -0.9350162408909763 +34 1.034032373365578 1.790996607340212 -0.8229838658936566 +35 1.124255374085739 1.947267428598854 -0.6631226582403708 +36 1.192728012846856 2.065865517861418 -0.464723171966601 +37 1.235470908970297 2.139898385609857 -0.2393156621999836 +38 2.470941817426052 0 0.2393156642875577 +39 2.38545602565321 0 0.4647231720437685 +40 2.248510748171101 0 0.6631226582407952 +41 2.068064746731156 0 0.8229838658936564 +42 1.854604887042536 0 0.9350162426854147 +43 1.620536680255323 0 0.992708874098054 +44 1.379463319744677 0 0.992708874098054 +45 1.145395112957464 0 0.9350162426854149 +46 0.9319352532688444 0 0.8229838658936566 +47 0.7514892518288991 0 0.6631226582407954 +48 0.6145439743467902 0 0.4647231720437687 +49 0.5290581825739481 0 0.2393156642875581 +50 0.5 0 1.224646799147353e-16 +51 0.5290581825739479 0 -0.2393156642875575 +52 0.6145439743467901 0 -0.4647231720437685 +53 0.7514892518288987 0 -0.663122658240795 +54 0.9319352532688441 0 -0.8229838658936564 +55 1.145395112957464 0 -0.9350162426854147 +56 1.379463319744676 0 -0.992708874098054 +57 1.620536680255322 0 -0.9927088740980541 +58 1.854604887042536 0 -0.9350162426854148 +59 2.068064746731156 0 -0.8229838658936566 +60 2.248510748171101 0 -0.6631226582407955 +61 2.38545602565321 0 -0.4647231720437692 +62 2.470941817426052 0 -0.2393156642875587 +63 1.161950520411713 1.595027107313167 0.8808567025634668 +64 1.16111495353952 1.631339134675958 -0.864657150131166 +65 1.993338608714705 0.1898855044486915 0.864657149241256 +66 1.962309259490651 0.2087651244602831 -0.8808566995508391 +67 2.143269427830786 1.235251366396636 0.2276108945998273 +68 2.144774983786486 1.239076746984393 -0.2133854546576661 +69 1.257163299677245 0.2056949521188911 -0.9740994282274332 +70 0.9306978626594941 1.194712146198956 -0.9998957038608219 +71 0.8067186995663457 0.9858878802543444 0.9740994279795938 +72 1.499999999999821 0.2086519190873416 0.9998957038631872 +73 2.340705550917026 0.815046814717805 0.2060155120167518 +74 1.873290363694945 1.623215340227059 0.2052080035217707 +75 2.342390902296706 0.8107093735108847 -0.20520800352177 +76 1.876204012167479 1.619587082207711 -0.206015487245415 +77 0.6956520153984462 0.7887050642846799 -0.8938627795124352 +78 1.030864624066582 0.2080997947850345 0.8938627777919494 +79 1.339111263725038 1.901858404757476 0.5636674802141222 +80 1.340063611529316 1.900556139880006 -0.5644229116404256 +81 2.315961703157284 0.2102510682052372 0.5644229121460563 +82 2.316613325045473 0.2087751701423494 -0.5636674798788656 +83 0.8257233900307956 0.2073786653528784 -0.7611009570103594 +84 0.5924568856662578 0.6114081008615074 0.7611009567525712 +85 0.6552631076664096 0.2199540300745461 0.5880759196713039 +86 0.518117332361219 0.4574974827803283 -0.5880759208938083 +87 1.532242043414882 1.948404256783631 0.2052080035217706 +88 1.534433561498189 1.950620672846501 -0.1898384713660102 +89 2.453488604923804 0.352758405952052 0.2052080035217711 +90 2.453488604923804 0.352758405952052 -0.2052080035217709 +91 0.4337477642844972 0.3581271528103677 0.3479515779329294 +92 0.5270210945461641 0.1965730066058266 -0.3479515789408426 +93 0.6514981143803358 0.2245342592436242 -0.5851914012243407 +94 0.5202014294249768 0.4519467876355929 0.5851914006358678 +95 0.4014403423552208 0.310054077259639 -0.1200778916456693 +96 0.4690743845310645 0.1937014713713605 0.122202935540906 +97 0.5801752991739216 0.6202829134728381 -0.7593569988644425 +98 0.7971906289338729 0.5725550546315054 -0.8550745202842129 +99 0.9299895953318537 0.7538050487583471 -0.953029551478182 +100 1.020807935619515 0.5609391978028184 -0.9421382258712735 +101 1.158775704398517 0.7331406603224976 -0.9916737595531294 +102 1.07079436896178 0.9395834763300965 -0.9971515774414794 +103 1.309688021011989 0.9072674962661023 -0.9956435646545561 +104 1.408580520839082 0.6577928881834649 -0.9985081419734843 +105 1.545871219796618 0.873285367854039 -0.9613055173471736 +106 1.451217818270691 1.10313640870309 -0.9464350828739435 +107 1.679105395582128 1.054804002495066 -0.8756596518832466 +108 1.77189593044693 0.8331112405270859 -0.8889619900552521 +109 1.581016579212857 1.272915440875944 -0.8481473660987684 +110 1.888803398279099 1.005484134934533 -0.7685740150485127 +111 1.983327592458931 0.7978554730297511 -0.7702072828570967 +112 2.077265785740169 0.9459551527661192 -0.6226346041973602 +113 2.164956684129825 0.724958584078208 -0.6218801439863675 +114 1.975636250565757 1.163059112399909 -0.6097900428701994 +115 1.857758850062941 0.6084947204092939 -0.8905556215828939 +116 1.355501724155206 1.313817462506936 -0.9217755874265015 +117 1.493084698535482 1.4798424031496 -0.7983469473822233 +118 1.690391730004402 1.432036463042488 -0.6986792066622279 +119 1.588938705312047 1.621449856179052 -0.6377977102936896 +120 1.763518611044919 1.561866114128629 -0.5174367243381106 +121 1.64228663731985 1.745234789011533 -0.4431544898946779 +122 2.136508707943542 1.092914485111334 -0.4362632868539859 +123 0.8286805041675077 0.9729264863222208 -0.9750478525559744 +124 1.379174264031979 1.683944246340221 -0.7363080526676612 +125 2.026141971161382 1.301985875131233 -0.4180895827224266 +126 0.8272684058174414 0.1923050883282038 0.7593569946991177 +127 0.8944425213507604 0.4041098171401778 0.8550745137555074 +128 1.117809107877708 0.4284921095499341 0.9530295502360074 +129 0.9961915489312382 0.6035760163814639 0.9421382235278785 +130 1.21430626806377 0.6369588939265005 0.9916737588091861 +131 1.349100332961367 0.4575434206294663 0.9971515774564784 +132 1.440560687544275 0.6805893880448953 0.9956435650232734 +133 1.273955587794313 0.8909700911730075 0.99850814240254 +134 1.529222889149096 0.9021211066699351 0.9613055194540464 +135 1.680953039386213 0.7052233381775018 0.9464350842720805 +136 1.753039724372543 0.9267459820847649 0.8756596550280391 +137 1.607443419141945 1.117951315400981 0.8889619950647425 +138 1.892885372103278 0.7327428635840514 0.8481473672235668 +139 1.815176456956073 1.133009716585031 0.7685740218936316 +140 1.682626870419913 1.318684379285022 0.7702072862702635 +141 1.857854037059084 1.325987417659986 0.6226346154414321 +142 1.710310878756236 1.512428237210446 0.6218801213956152 +143 1.995056816005703 1.129421694625275 0.6097900514039523 +144 1.455851259289336 1.304619036328911 0.8905556281968932 +145 1.815550145268847 0.5169902548551503 0.9217755869112219 +146 2.028123447205333 0.5531281399950182 0.7983469471672885 +147 2.085375793954983 0.7479040216119029 0.6986792077701024 +148 2.198686105353924 0.5653364207293526 0.6377977067994971 +149 2.23437500752076 0.7463189448006358 0.5174367272737342 +150 2.33256096421613 0.549644629861044 0.4431544886181681 +151 2.016526565486886 1.303539104797304 0.4334761314315916 +152 1.256919307065314 0.231195140997 0.9750478536177046 +153 2.147925624607719 0.3524278634459152 0.736308050043917 +154 2.139882952433509 1.103620904410053 0.4195932786269019 +155 1.591523049737069 0.4470789416753918 0.98820669030398 +156 1.773347685675709 0.2499958912548627 0.9567587985602205 +157 1.182943234960579 1.154759937221901 -0.9882066897501199 +158 1.103176619915856 1.410766211750977 -0.9567587986441293 +159 0.6776017770360423 0.7764200539868567 0.8829433125538813 +160 1.011200381154429 0.198610327009629 -0.8829433136803488 +161 0.7087970592418741 0.4129187978480285 -0.7334919842231511 +162 0.7119966957841659 0.4073768612880556 0.7334919825932171 +163 2.252206790904938 1.024469582375116 -0.225417828058159 +164 2.232156252238418 0.8801412111855693 -0.4371052509884357 +165 2.306767605586851 0.6518373635269503 -0.4418358896236437 +166 2.219803764229007 0.48638003809805 -0.6350581105711051 +167 2.012443905783075 1.431141498391836 0.2453584903487805 +168 1.879239263428174 1.491302075944445 0.4378112284475578 +169 1.718225273090827 1.671330573001638 0.4420157376406979 +170 1.531119330381165 1.679216534047617 0.6350580359177905 +171 0.9190640841350129 1.184629926085916 0.9999997836100309 +172 1.049798373764997 1.381807097473364 0.9719087402402153 +173 1.153985062431529 1.165116090062648 0.9901697289787016 +174 1.384115559403521 1.077909319314016 0.9671181980368939 +175 1.029024257768673 0.9508543119579772 0.9950950230568771 +176 1.48545165184756 0.2036178817765078 -0.9999997836098622 +177 1.721579236265735 0.2182485114955622 -0.9719087402873856 +178 1.58601266163587 0.4168223353949511 -0.9901697292149241 +179 1.625554649345303 0.6597246097044436 -0.9671181908258678 +180 1.337976111157614 0.4157340126351193 -0.9950950229733188 +181 2.402270425674217 0.5810915549862188 -0.2368252487583065 +182 1.70593749744366 1.786238502273994 0.243128554091969 +183 1.954857324880494 0.9431011777158674 0.7419435166184849 +184 1.794178202127611 1.221405580903979 -0.741943512037614 +185 2.249773424997405 1.029094771269818 0.2266865432150113 +186 2.018654063412176 1.433602746510706 -0.2181276558421402 +187 1.701538918701969 1.797051296027637 -0.2230867820887245 +188 2.406405674227529 0.5743726817581494 0.2265338911405251 +189 1.251235724142822 1.762855981959914 0.7497064068024704 +190 1.381739529336837 1.555447441778505 0.8142361531898541 +191 2.152295929686154 0.2021739354113657 -0.7497064030049929 +192 2.037926742934737 0.4188978626238546 -0.8142361604185483 +193 1.872905315244544 1.365480933874247 -0.5754670716221548 +194 2.119286420053609 0.9404301384966269 0.5744015822664972 +195 1.833535077728957 0.4057869027258597 -0.9258458224179789 +196 1.268189283192839 1.384994523680911 0.9258458227499975 +197 1.377265921278483 2.005430891725938 0.3603419747750946 +198 1.546795264550916 1.839873835551548 0.4281935989751613 +199 1.381891104564456 1.998857975709812 -0.3674781719964972 +200 2.422007337797244 0.1973238139516733 0.3674781720157486 +201 2.425387058454348 0.1900318299839833 -0.3603419746042364 +202 2.367058173220222 0.4190208657847906 -0.4278283619092008 +203 0.8899712834428033 0.7807261905059222 0.9487206789798943 +204 1.121114358662251 0.3803746373713242 -0.9487206789882416 +205 0.914757224585851 0.3892421606728923 -0.8626084842378261 +206 0.7944722043702587 0.5975819158712172 0.8626084813224804 +207 0.5437468686508761 0.1753948845348323 0.3709203029958322 +208 0.4236548317432472 0.3832096360207821 -0.37072088053857 +209 1.901148152895707 1.498470095187491 -0.3902767076285737 +210 2.247889479047726 0.8969112365780697 0.3914053943906234 +211 2.06115073291544 0.6149026421550068 -0.759148174490955 +212 1.563096665160738 1.477557608942776 0.7591481606873587 +213 2.293538770716872 0.3975684508448159 0.5611095359772014 +214 1.491073734293782 1.787478637883094 -0.5611095372128085 +215 2.160934921274194 0.1465662156768363 0.7460413036221629 +216 1.207397490267293 1.798141452453983 -0.7460413050692806 +217 1.77632091546844 1.662027374751479 -0.360854191128632 +218 2.327518353212576 0.7073254288138934 0.3608542136339237 +219 1.38808479900803 2.061575849627878 -0.1706492015269236 +220 2.478948087855883 0.1719191240847288 0.1731106987058312 +221 1.389096580246771 2.060356370273965 0.1732046903180589 +222 2.478869247629586 0.1728147416673262 -0.1732046903187114 +223 2.389519884070642 0.37518921408793 0.3947336057780582 +224 1.520122986826133 1.882489046625287 -0.3928198464625023 +225 1.94882169109996 0.3797502874104242 0.874249810509526 +226 1.303284213694452 1.497853971095424 -0.8742498110826699 +227 0.3626210387554522 0.3551456057285723 0.1227727244605137 +228 0.4888756360882149 0.1364662287623708 -0.1227727255505153 +229 1.086114096153235 0.7757817768037119 0.9862469172774405 +230 1.214903771215531 0.5527115271809405 -0.9862469179371743 +231 1.719469475572177 0.5273210164956065 -0.9544061143209133 +232 1.316408107079081 1.225443763275427 0.9544061152363752 +233 0.5422951238057707 0.3059592744937097 0.4798540144189912 +234 0.536079395155085 0.3166713490100215 -0.4798052395521509 +235 0.7234766020502333 0 0.06319084407049604 +236 2.276408697239476 0 -0.1038332116551961 +237 1.281564074160823 0 -0.7815450354819452 +238 1.687607499234412 0 0.7611535450957393 +239 1.864311932538833 0 -0.6941383931109288 +240 0.9824677737969774 0 0.6079094555764485 +241 0.8538614889377032 0 -0.4560869484954775 +242 2.14197338776787 0 0.4640993597096316 +243 2.145309988793692 0 -0.4501798711749596 +244 1.300634269303989 0 0.7623839983864482 +245 1.700240711187027 0 -0.8019064501110774 +246 1.675590523152915 0 -0.5791715422382202 +247 1.900023573701088 0 -0.454623482418549 +248 1.66468575399941 0 -0.3388653259535993 +249 1.861804827553214 0 -0.2063019587468402 +250 1.653303668642545 0 -0.0965510845269546 +251 1.447433111560146 0 -0.2223570746281137 +252 1.441646586126126 0 0.01885927027041822 +253 1.647765612163517 0 0.1432517193449556 +254 1.235106815066154 0 -0.1058278068838464 +255 1.436693623107965 0 0.2597162564404173 +256 1.248346455709191 0 -0.3418224077231802 +257 1.63881019087097 0 0.376463356021949 +258 1.846857487731521 0 0.2544945090792877 +259 1.861009725360342 0 0.5145051509153519 +260 1.421184826888508 0 0.5375048936337171 +261 1.22556002569893 0 0.376190528980096 +262 0.9970599615356726 0 -0.2524739698086225 +263 0.9785762007483654 0 0.03562131165296409 +264 1.468545234544223 0 -0.4598103596351082 +265 1.855705914185911 0 0.02608781117112623 +266 2.065126085550818 0 0.1510765117070129 +267 1.222783030310453 0 0.1393737718970882 +268 1.019114931115178 0 0.2516830709224802 +269 0.8265890464543634 0 -0.1136715848090973 +270 2.060779434825952 0 -0.06040484733817086 +271 2.279058019184917 0 0.1070695414119101 +272 1.266650491755973 0 -0.5625597545084002 +273 1.066881711342736 0 -0.4758711207039364 +274 1.104906898175 0 -0.6992855791290147 +275 1.484655862114423 0 -0.7386301271672655 +276 0.7254662717714151 0 -0.2893135921118692 +277 0.844397287769171 0 0.486542411644844 +278 0.8234459508503615 0 0.2809629482984198 +279 2.264224982218241 0 -0.3081051521832103 +280 1.904641258028338 0 0.731329411646097 +281 1.502652777570647 0 0.7884339610073496 +282 1.11883427047969 0 0.7409827498784481 +283 2.044839973211761 0 0.6392080892811064 +284 2.045244197987174 0 -0.617009654167778 +285 1.215590375596072 0 0.5760683567251723 +286 1.612856736166523 0 0.5788562441904899 +287 2.058223470199073 0 -0.2757078962364384 +288 0.9394638145164449 0 -0.6206622407006543 +289 2.227302932754278 0 0.2912169793454392 +290 0.6470285364900668 0 -0.1035694867313699 +291 1.018429390804448 0 0.4298927953579101 +292 2.021262260942802 0 0.321017626912755 +293 0.3617383010251167 0.6265491164191468 0.06319084407049604 +294 1.138204348619738 1.971427761205225 -0.1038332116551961 +295 0.6407820370804114 1.109867044800757 -0.7815450354819452 +296 0.8438037496172062 1.461510965954128 0.7611535450957393 +297 0.9321559662694168 1.61454149415709 -0.6941383931109288 +298 0.4912338868984888 0.8508420505077258 0.6079094555764485 +299 0.4269307444688517 0.7394657407332563 -0.4560869484954775 +300 1.070986693883935 1.855003368037192 0.4640993597096316 +301 1.072654994396846 1.857892949287847 -0.4501798711749596 +302 0.6503171346519945 1.126382318249865 0.7623839983864482 +303 0.8501203555935136 1.472451648436486 -0.8019064501110774 +304 0.8377952615764576 1.451103959390882 -0.5791715422382202 +305 0.9500117868505443 1.645468682614437 -0.454623482418549 +306 0.8323428769997053 1.441660152281542 -0.3388653259535993 +307 0.9309024137766072 1.612370277549589 -0.2063019587468402 +308 0.8266518343212725 1.431802977214453 -0.0965510845269546 +309 0.723716555780073 1.253513844889842 -0.2223570746281137 +310 0.720823293063063 1.248502566864335 0.01885927027041822 +311 0.8238828060817588 1.427006879616023 0.1432517193449556 +312 0.617553407533077 1.069633878234578 -0.1058278068838464 +313 0.7183468115539827 1.244213175066604 0.2597162564404173 +314 0.6241732278545958 1.081099743368425 -0.3418224077231802 +315 0.8194050954354855 1.419251257275085 0.376463356021949 +316 0.9234287438657607 1.599425501545004 0.2544945090792877 +317 0.9305048626801711 1.611681698851957 0.5145051509153519 +318 0.7105924134442541 1.230782163558438 0.5375048936337171 +319 0.6127800128494653 1.061366116117983 0.376190528980096 +320 0.4985299807678364 0.8634792557862276 -0.2524739698086225 +321 0.4892881003741828 0.847471849386945 0.03562131165296409 +322 0.7342726172721118 1.271797479721874 -0.4598103596351082 +323 0.9278529570929556 1.607088463638024 0.02608781117112623 +324 1.032563042775409 1.788451652104924 0.1510765117070129 +325 0.6113915151552265 1.058961167565369 0.1393737718970882 +326 0.5095574655575892 0.8825794197217725 0.2516830709224802 +327 0.4132945232271818 0.7158471127194341 -0.1136715848090973 +328 1.030389717412976 1.784687342155812 -0.06040484733817086 +329 1.139529009592459 1.973722141312781 0.1070695414119101 +330 0.6333252458779864 1.096951503576724 -0.5625597545084002 +331 0.5334408556713682 0.923946664855826 -0.4758711207039364 +332 0.5524534490875003 0.9568774426362162 -0.6992855791290147 +333 0.7423279310572114 1.285749692468577 -0.7386301271672655 +334 0.3627331358857076 0.628272220942831 -0.2893135921118692 +335 0.4221986438845857 0.7312695020947813 0.486542411644844 +336 0.4117229754251809 0.7131251120798453 0.2809629482984198 +337 1.13211249110912 1.960876354484365 -0.3081051521832103 +338 0.9523206290141693 1.649467714548493 0.731329411646097 +339 0.7513263887853235 1.301335478443427 0.7884339610073496 +340 0.5594171352398453 0.9689389008600416 0.7409827498784481 +341 1.022419986605881 1.770883363475276 0.6392080892811064 +342 1.022622098993587 1.771233432399622 -0.617009654167778 +343 0.607795187798036 1.052732145862065 0.5760683567251723 +344 0.8064283680832618 1.396774906185065 0.5788562441904899 +345 1.029111735099537 1.782473811857761 -0.2757078962364384 +346 0.4697319072582226 0.8135995293074731 -0.6206622407006543 +347 1.113651466377139 1.928900921688788 0.2912169793454392 +348 0.3235142682450334 0.5603431495738644 -0.1035694867313699 +349 0.5092146954022242 0.881985724397362 0.4298927953579101 +350 1.010631130471401 1.750464465687237 0.321017626912755 +351 1.418635001501272 0.8190492999985843 -0.1023703321158247 +352 1.006307913666113 0.5809921448427808 0.2632906758093849 +353 1.265327502315069 1.06533112816762 0.4110304201391338 +354 1.8108482485899 0.5573834805298281 0.2017017803896481 +355 1.380215925684095 1.340220657134674 -0.2334677620662884 +356 0.9913665364332176 0.5413074569027571 -0.2885030876157972 +357 1.612856969725634 0.4979937306821383 -0.45293802610268 +358 1.143916785727387 0.9765641491555823 -0.4974763498679757 +359 1.431014071730337 0.6129347670235737 0.5088098738940131 +360 1.699479877999052 1.018418464902874 0.2245161261321199 +361 1.366509217989849 1.473361213592895 0.2096048208646426 +362 1.862200179790552 0.7763841411086148 -0.1936516780784303 +363 1.392131171785957 0.4305669718356104 0.1076251504271724 +364 1.242345214149243 0.5075396430559113 -0.5934211709051677 +365 1.587621984957066 0.9666260696788359 -0.4669075217439702 +366 1.041060328494321 0.9595575993853922 0.05614026652743735 +367 1.058729532053908 0.7744221311360611 0.5975116678100523 +368 0.7294374265287789 0.5192318029393697 -0.002296726057127052 +369 1.730194889453991 1.163838789846815 -0.148045666975564 +370 2.044298702632946 0.4122923994887411 -0.1100148416481616 +371 1.322436651322489 0.3710779620407529 -0.254766099207305 +372 1.135530529689598 0.3742602834680934 0.5588259404205825 +373 0.8382517647831981 0.7450384683701989 -0.5422127333026093 +374 1.763158572846889 0.4468633779238019 0.5561796716402778 +375 1.192700534227963 1.34114988115434 -0.5551244559864699 +376 1.678726322631293 0.3670544075308987 -0.1149584378428671 +377 1.359220955957618 1.135678262863201 0.06666049099639326 +378 1.577215249631691 0.9561381396426961 0.5600324465840711 +379 1.065430367121712 1.199298878138994 -0.1937698051692187 +380 1.062294504610921 0.3452570106465946 0.001202393181407947 +381 1.35965500667398 1.661318642318972 -0.08883951555708131 +382 2.054747825331541 0.34323380961532 0.3182827628833362 +383 1.846084516030049 0.7750900966433136 0.4596090638257971 +384 1.488429466246604 0.7200613986226235 -0.6688437029431646 +385 1.000703927312493 0.3119825216587705 -0.5130404821839643 +386 1.299273693675256 0.7702466488539538 0.2240595613141949 +387 1.561448685218078 1.273279736306895 0.4173408748078854 +388 0.7635648558793097 0.6683314979305912 0.4780119661275764 +389 0.8595739642445496 0.8507493814656514 -0.2153376212242464 +390 1.978477439452769 0.8463593318541685 0.1218811845060402 +391 0.8313792036173077 0.3188255473345841 0.3355638674761983 +392 1.020855919956406 1.118325453266675 0.6574477121534414 +393 0.6832294399459129 0.5553575812073663 -0.3409721529927112 +394 1.253086756924487 1.394021993734984 0.5313127541741292 +395 0.8082327561325133 0.2981029812766474 -0.2110513803219472 +396 1.942182871711016 0.3560891485782794 -0.4491612347524943 +397 1.613694365036505 1.451747759436326 -0.01800591311493325 +398 1.289926859873265 1.601229732331073 -0.3955655286625344 +399 0.9339530554611122 0.9797370181660322 0.3691667658879731 +400 1.126678951239092 0.6607133075406245 -0.02322843206438263 +401 1.250778788798854 0.7145330589942874 -0.3517833801887749 +402 1.451765263880889 0.3127555354447675 0.666265928479598 +403 1.605053414392174 1.277430208547506 -0.4410216342941474 +404 1.086202065814923 1.244769321969722 0.2066762905501359 +405 0.7940822003319083 0.7872787771187758 0.1522709762555385 +406 1.878326137952758 0.6608170557985893 -0.5056996778120829 +407 1.637761487911216 0.2963357217251025 0.2596453211629388 +408 1.411018126178102 1.147284756395386 -0.6324199671085715 +409 1.488277492618901 0.32177571627524 -0.6955066325998237 +410 1.089673866546784 0.73921752083501 -0.7019376496748817 +411 1.171771511824859 1.428946797464596 -0.02201892070556395 +412 2.05466855499991 0.6328301538230341 0.3279502839160386 +413 1.353143674651522 1.128954649713943 0.6817060935447485 +414 1.353320018560723 0.2770211235786472 0.3684704776718821 +415 0.9070404862699556 1.00350823810525 -0.6841643163183184 +416 1.588187280033317 0.75127362290324 0.1381805442291818 +417 1.354311500310051 1.045101571939138 -0.2919839172335082 +418 0.8073330000041892 0.8769055635423104 0.6561063758264086 +419 1.539015621160407 1.560392971281782 -0.2694899107826355 +420 1.335739094857388 0.8349257453386124 0.6773841296580436 +421 1.856966769621279 1.033721526281692 -0.3765453788271407 +422 1.317808306372784 1.756547911079501 0.1819106358629041 +423 1.921753700420389 1.128289426655543 0.06979877893193551 +424 1.877839488866478 0.2837631284404755 0.09316597733410573 +425 1.211530198066868 0.2549303656898473 -0.7011263029425323 +426 1.613882796944428 0.6331152797895598 -0.2000168538857371 +427 1.731777323465674 0.4830144101577302 -0.6914560664620741 +428 1.068991343412805 0.2897189416432697 -0.2578923469342631 +429 2.215712428289467 0.2747068699434122 0.07030608531412151 +430 1.748804902741179 1.31965441206944 0.2014470425914964 +431 2.160972336241817 0.2578142594068452 -0.3091483571309573 +432 1.656998891131385 0.7004881423174387 0.6611974795081834 +433 2.135311785831417 0.6205070361134138 0.05761485799094201 +434 1.128872897166343 0.9125082420473587 -0.2019132117667884 +435 0.8065905731232743 0.2627003090228302 0.06219635997810313 +436 1.558579951737068 0.2543796712533649 -0.3359677314044994 +437 1.095300929684706 0.2668762697018797 0.26576342874253 +438 1.221850386488509 0.5846909618837201 0.7187134232149368 +439 0.9392598522401714 0.5390092060013327 0.6302275824396208 +440 0.6483332954363064 0.5215048636343409 0.2672692532571793 +441 1.00534759833767 0.5601117728552446 -0.5366970652009414 +442 1.669186083204167 0.9140987684193717 -0.06261302060885673 +443 1.300868157238982 0.912765896024329 -0.7217689151430906 +444 1.936410040849841 0.2454562465870731 0.6062747708512596 +445 1.261222079650665 0.5239216508313133 0.3216023378653879 +446 1.771114097121214 1.113687211388049 0.4641200874722527 +447 2.06605772633019 0.6163360316512467 -0.3016837250026109 +448 0.9077354499702041 1.068360147261763 -0.3821640919890156 +449 1.098341887804344 1.430722226382691 -0.3222640812714789 +450 1.740683266083933 0.2257228161438156 -0.6846991730401913 +451 1.431109538720755 1.440642807876566 -0.5412046315536471 +452 1.723438259361296 0.8234808519877937 -0.6346989579036486 +453 1.500847566861419 0.726092448023743 -0.4117874473610533 +454 1.72250839002415 1.391315141205534 -0.2518012658885989 +455 1.142474233200014 1.131876331068075 -0.7187971453772315 +456 1.452766288703132 0.2461665321109213 -0.066545663674481 +457 1.997114282263472 1.002217016533608 -0.152320737212002 +458 1.2335751749254 0.2310833922437358 -0.4483286610347972 +459 1.243509471602743 1.645634220311118 0.4218349305400673 +460 1.353154544950395 0.5723876900207028 -0.1009399294228396 +461 1.568151906445483 0.5451655206615679 0.297212198001392 +462 1.211912683108393 0.2238805188548799 0.7331781210365729 +463 1.939054772847803 0.9749516564389743 0.3358968291625145 +464 1.473108008187662 0.9365131111254542 0.3226364653260583 +465 0.5500086468869504 0.5304906880452636 -0.151031664317606 +466 1.839679917746078 0.5598091156524675 -0.05487762694700804 +467 1.81588422207515 0.521659312162986 -0.303848089847952 +468 1.292909852420306 0.6444747339717066 -0.7811755399907123 +469 1.968283335011498 0.5828894651298034 0.5529682806762651 +470 1.163116866805931 1.572087255828068 -0.6280053147816038 +471 1.015606540629819 0.7644234338809101 -0.3788243692674071 +$EndNodes +$Elements +2384 +1 2 2 1 1 12 219 1 +2 2 2 1 1 1 221 12 +3 2 2 1 1 13 221 1 +4 2 2 1 1 1 219 37 +5 2 2 1 1 3 220 2 +6 2 2 1 1 2 222 3 +7 2 2 1 1 2 220 38 +8 2 2 1 1 62 222 2 +9 2 2 1 1 4 89 3 +10 2 2 1 1 3 90 4 +11 2 2 1 1 89 220 3 +12 2 2 1 1 3 222 90 +13 2 2 1 1 4 181 5 +14 2 2 1 1 5 188 4 +15 2 2 1 1 4 188 89 +16 2 2 1 1 90 181 4 +17 2 2 1 1 6 73 5 +18 2 2 1 1 5 75 6 +19 2 2 1 1 73 188 5 +20 2 2 1 1 5 181 75 +21 2 2 1 1 6 163 7 +22 2 2 1 1 7 185 6 +23 2 2 1 1 6 185 73 +24 2 2 1 1 75 163 6 +25 2 2 1 1 8 67 7 +26 2 2 1 1 7 68 8 +27 2 2 1 1 67 185 7 +28 2 2 1 1 7 163 68 +29 2 2 1 1 9 167 8 +30 2 2 1 1 8 186 9 +31 2 2 1 1 8 167 67 +32 2 2 1 1 68 186 8 +33 2 2 1 1 10 74 9 +34 2 2 1 1 9 76 10 +35 2 2 1 1 74 167 9 +36 2 2 1 1 9 186 76 +37 2 2 1 1 11 182 10 +38 2 2 1 1 10 187 11 +39 2 2 1 1 10 182 74 +40 2 2 1 1 76 187 10 +41 2 2 1 1 12 87 11 +42 2 2 1 1 11 88 12 +43 2 2 1 1 87 182 11 +44 2 2 1 1 11 187 88 +45 2 2 1 1 12 221 87 +46 2 2 1 1 88 219 12 +47 2 2 1 1 38 200 39 +48 2 2 1 1 38 220 200 +49 2 2 1 1 39 81 40 +50 2 2 1 1 39 200 81 +51 2 2 1 1 40 215 41 +52 2 2 1 1 81 215 40 +53 2 2 1 1 41 65 42 +54 2 2 1 1 41 215 65 +55 2 2 1 1 42 156 43 +56 2 2 1 1 65 156 42 +57 2 2 1 1 43 72 44 +58 2 2 1 1 43 156 72 +59 2 2 1 1 44 152 45 +60 2 2 1 1 72 152 44 +61 2 2 1 1 45 78 46 +62 2 2 1 1 45 152 78 +63 2 2 1 1 46 126 47 +64 2 2 1 1 78 126 46 +65 2 2 1 1 47 85 48 +66 2 2 1 1 47 126 85 +67 2 2 1 1 48 207 49 +68 2 2 1 1 85 207 48 +69 2 2 1 1 49 96 50 +70 2 2 1 1 49 207 96 +71 2 2 1 1 50 228 51 +72 2 2 1 1 96 228 50 +73 2 2 1 1 51 92 52 +74 2 2 1 1 51 228 92 +75 2 2 1 1 52 93 53 +76 2 2 1 1 92 93 52 +77 2 2 1 1 53 83 54 +78 2 2 1 1 53 93 83 +79 2 2 1 1 54 160 55 +80 2 2 1 1 83 160 54 +81 2 2 1 1 55 69 56 +82 2 2 1 1 55 160 69 +83 2 2 1 1 56 176 57 +84 2 2 1 1 69 176 56 +85 2 2 1 1 57 177 58 +86 2 2 1 1 176 177 57 +87 2 2 1 1 58 66 59 +88 2 2 1 1 58 177 66 +89 2 2 1 1 59 191 60 +90 2 2 1 1 66 191 59 +91 2 2 1 1 60 82 61 +92 2 2 1 1 60 191 82 +93 2 2 1 1 61 201 62 +94 2 2 1 1 82 201 61 +95 2 2 1 1 201 222 62 +96 2 2 1 1 14 197 13 +97 2 2 1 1 197 221 13 +98 2 2 1 1 15 79 14 +99 2 2 1 1 79 197 14 +100 2 2 1 1 16 189 15 +101 2 2 1 1 15 189 79 +102 2 2 1 1 17 63 16 +103 2 2 1 1 63 189 16 +104 2 2 1 1 18 172 17 +105 2 2 1 1 17 172 63 +106 2 2 1 1 19 171 18 +107 2 2 1 1 171 172 18 +108 2 2 1 1 20 71 19 +109 2 2 1 1 71 171 19 +110 2 2 1 1 21 159 20 +111 2 2 1 1 20 159 71 +112 2 2 1 1 22 84 21 +113 2 2 1 1 84 159 21 +114 2 2 1 1 23 94 22 +115 2 2 1 1 22 94 84 +116 2 2 1 1 24 91 23 +117 2 2 1 1 91 94 23 +118 2 2 1 1 25 227 24 +119 2 2 1 1 24 227 91 +120 2 2 1 1 26 95 25 +121 2 2 1 1 95 227 25 +122 2 2 1 1 27 208 26 +123 2 2 1 1 26 208 95 +124 2 2 1 1 28 86 27 +125 2 2 1 1 86 208 27 +126 2 2 1 1 29 97 28 +127 2 2 1 1 28 97 86 +128 2 2 1 1 30 77 29 +129 2 2 1 1 77 97 29 +130 2 2 1 1 31 123 30 +131 2 2 1 1 30 123 77 +132 2 2 1 1 32 70 31 +133 2 2 1 1 70 123 31 +134 2 2 1 1 33 158 32 +135 2 2 1 1 32 158 70 +136 2 2 1 1 34 64 33 +137 2 2 1 1 64 158 33 +138 2 2 1 1 35 216 34 +139 2 2 1 1 34 216 64 +140 2 2 1 1 36 80 35 +141 2 2 1 1 80 216 35 +142 2 2 1 1 37 199 36 +143 2 2 1 1 36 199 80 +144 2 2 1 1 37 219 199 +145 2 2 1 1 172 196 63 +146 2 2 1 1 63 190 189 +147 2 2 1 1 63 196 190 +148 2 2 1 1 64 216 124 +149 2 2 1 1 124 226 64 +150 2 2 1 1 64 226 158 +151 2 2 1 1 65 215 153 +152 2 2 1 1 153 225 65 +153 2 2 1 1 65 225 156 +154 2 2 1 1 177 195 66 +155 2 2 1 1 66 192 191 +156 2 2 1 1 66 195 192 +157 2 2 1 1 151 154 67 +158 2 2 1 1 67 167 151 +159 2 2 1 1 154 185 67 +160 2 2 1 1 122 125 68 +161 2 2 1 1 68 163 122 +162 2 2 1 1 125 186 68 +163 2 2 1 1 160 204 69 +164 2 2 1 1 69 180 176 +165 2 2 1 1 69 204 180 +166 2 2 1 1 102 123 70 +167 2 2 1 1 70 157 102 +168 2 2 1 1 70 158 157 +169 2 2 1 1 159 203 71 +170 2 2 1 1 71 175 171 +171 2 2 1 1 71 203 175 +172 2 2 1 1 131 152 72 +173 2 2 1 1 72 155 131 +174 2 2 1 1 72 156 155 +175 2 2 1 1 185 210 73 +176 2 2 1 1 73 218 188 +177 2 2 1 1 210 218 73 +178 2 2 1 1 74 168 167 +179 2 2 1 1 74 169 168 +180 2 2 1 1 74 182 169 +181 2 2 1 1 75 164 163 +182 2 2 1 1 75 165 164 +183 2 2 1 1 75 181 165 +184 2 2 1 1 186 209 76 +185 2 2 1 1 76 217 187 +186 2 2 1 1 209 217 76 +187 2 2 1 1 77 98 97 +188 2 2 1 1 77 99 98 +189 2 2 1 1 77 123 99 +190 2 2 1 1 78 127 126 +191 2 2 1 1 78 128 127 +192 2 2 1 1 78 152 128 +193 2 2 1 1 79 189 170 +194 2 2 1 1 170 198 79 +195 2 2 1 1 79 198 197 +196 2 2 1 1 80 214 124 +197 2 2 1 1 124 216 80 +198 2 2 1 1 199 224 80 +199 2 2 1 1 80 224 214 +200 2 2 1 1 81 213 153 +201 2 2 1 1 153 215 81 +202 2 2 1 1 200 223 81 +203 2 2 1 1 81 223 213 +204 2 2 1 1 82 191 166 +205 2 2 1 1 166 202 82 +206 2 2 1 1 82 202 201 +207 2 2 1 1 93 161 83 +208 2 2 1 1 83 205 160 +209 2 2 1 1 161 205 83 +210 2 2 1 1 94 162 84 +211 2 2 1 1 84 206 159 +212 2 2 1 1 162 206 84 +213 2 2 1 1 85 162 94 +214 2 2 1 1 94 233 85 +215 2 2 1 1 126 162 85 +216 2 2 1 1 85 233 207 +217 2 2 1 1 86 161 93 +218 2 2 1 1 93 234 86 +219 2 2 1 1 97 161 86 +220 2 2 1 1 86 234 208 +221 2 2 1 1 87 198 182 +222 2 2 1 1 197 198 87 +223 2 2 1 1 87 221 197 +224 2 2 1 1 187 224 88 +225 2 2 1 1 199 219 88 +226 2 2 1 1 88 224 199 +227 2 2 1 1 188 223 89 +228 2 2 1 1 200 220 89 +229 2 2 1 1 89 223 200 +230 2 2 1 1 90 202 181 +231 2 2 1 1 201 202 90 +232 2 2 1 1 90 222 201 +233 2 2 1 1 91 233 94 +234 2 2 1 1 96 207 91 +235 2 2 1 1 91 227 96 +236 2 2 1 1 207 233 91 +237 2 2 1 1 92 234 93 +238 2 2 1 1 95 208 92 +239 2 2 1 1 92 228 95 +240 2 2 1 1 208 234 92 +241 2 2 1 1 96 227 95 +242 2 2 1 1 95 228 96 +243 2 2 1 1 98 161 97 +244 2 2 1 1 99 100 98 +245 2 2 1 1 100 205 98 +246 2 2 1 1 98 205 161 +247 2 2 1 1 99 101 100 +248 2 2 1 1 99 102 101 +249 2 2 1 1 99 123 102 +250 2 2 1 1 101 230 100 +251 2 2 1 1 204 205 100 +252 2 2 1 1 100 230 204 +253 2 2 1 1 102 103 101 +254 2 2 1 1 103 104 101 +255 2 2 1 1 104 230 101 +256 2 2 1 1 102 157 103 +257 2 2 1 1 103 105 104 +258 2 2 1 1 103 106 105 +259 2 2 1 1 103 157 106 +260 2 2 1 1 105 179 104 +261 2 2 1 1 104 179 178 +262 2 2 1 1 178 180 104 +263 2 2 1 1 180 230 104 +264 2 2 1 1 106 107 105 +265 2 2 1 1 107 108 105 +266 2 2 1 1 108 179 105 +267 2 2 1 1 106 109 107 +268 2 2 1 1 106 116 109 +269 2 2 1 1 106 157 116 +270 2 2 1 1 107 110 108 +271 2 2 1 1 109 184 107 +272 2 2 1 1 107 184 110 +273 2 2 1 1 110 111 108 +274 2 2 1 1 111 115 108 +275 2 2 1 1 115 179 108 +276 2 2 1 1 116 117 109 +277 2 2 1 1 117 118 109 +278 2 2 1 1 118 184 109 +279 2 2 1 1 110 112 111 +280 2 2 1 1 110 114 112 +281 2 2 1 1 110 184 114 +282 2 2 1 1 112 113 111 +283 2 2 1 1 113 211 111 +284 2 2 1 1 111 211 115 +285 2 2 1 1 112 164 113 +286 2 2 1 1 114 122 112 +287 2 2 1 1 122 164 112 +288 2 2 1 1 164 165 113 +289 2 2 1 1 165 166 113 +290 2 2 1 1 166 211 113 +291 2 2 1 1 114 125 122 +292 2 2 1 1 114 193 125 +293 2 2 1 1 184 193 114 +294 2 2 1 1 115 231 179 +295 2 2 1 1 192 195 115 +296 2 2 1 1 115 211 192 +297 2 2 1 1 195 231 115 +298 2 2 1 1 116 226 117 +299 2 2 1 1 157 158 116 +300 2 2 1 1 158 226 116 +301 2 2 1 1 117 119 118 +302 2 2 1 1 117 124 119 +303 2 2 1 1 117 226 124 +304 2 2 1 1 119 120 118 +305 2 2 1 1 120 193 118 +306 2 2 1 1 118 193 184 +307 2 2 1 1 119 121 120 +308 2 2 1 1 119 214 121 +309 2 2 1 1 124 214 119 +310 2 2 1 1 121 217 120 +311 2 2 1 1 120 209 193 +312 2 2 1 1 120 217 209 +313 2 2 1 1 187 217 121 +314 2 2 1 1 121 224 187 +315 2 2 1 1 214 224 121 +316 2 2 1 1 163 164 122 +317 2 2 1 1 125 209 186 +318 2 2 1 1 193 209 125 +319 2 2 1 1 127 162 126 +320 2 2 1 1 128 129 127 +321 2 2 1 1 129 206 127 +322 2 2 1 1 127 206 162 +323 2 2 1 1 128 130 129 +324 2 2 1 1 128 131 130 +325 2 2 1 1 128 152 131 +326 2 2 1 1 130 229 129 +327 2 2 1 1 203 206 129 +328 2 2 1 1 129 229 203 +329 2 2 1 1 131 132 130 +330 2 2 1 1 132 133 130 +331 2 2 1 1 133 229 130 +332 2 2 1 1 131 155 132 +333 2 2 1 1 132 134 133 +334 2 2 1 1 132 135 134 +335 2 2 1 1 132 155 135 +336 2 2 1 1 134 174 133 +337 2 2 1 1 133 174 173 +338 2 2 1 1 173 175 133 +339 2 2 1 1 175 229 133 +340 2 2 1 1 135 136 134 +341 2 2 1 1 136 137 134 +342 2 2 1 1 137 174 134 +343 2 2 1 1 135 138 136 +344 2 2 1 1 135 145 138 +345 2 2 1 1 135 155 145 +346 2 2 1 1 136 139 137 +347 2 2 1 1 138 183 136 +348 2 2 1 1 136 183 139 +349 2 2 1 1 139 140 137 +350 2 2 1 1 140 144 137 +351 2 2 1 1 144 174 137 +352 2 2 1 1 145 146 138 +353 2 2 1 1 146 147 138 +354 2 2 1 1 147 183 138 +355 2 2 1 1 139 141 140 +356 2 2 1 1 139 143 141 +357 2 2 1 1 139 183 143 +358 2 2 1 1 141 142 140 +359 2 2 1 1 142 212 140 +360 2 2 1 1 140 212 144 +361 2 2 1 1 141 168 142 +362 2 2 1 1 143 151 141 +363 2 2 1 1 151 168 141 +364 2 2 1 1 168 169 142 +365 2 2 1 1 169 170 142 +366 2 2 1 1 170 212 142 +367 2 2 1 1 143 154 151 +368 2 2 1 1 143 194 154 +369 2 2 1 1 183 194 143 +370 2 2 1 1 144 232 174 +371 2 2 1 1 190 196 144 +372 2 2 1 1 144 212 190 +373 2 2 1 1 196 232 144 +374 2 2 1 1 145 225 146 +375 2 2 1 1 155 156 145 +376 2 2 1 1 156 225 145 +377 2 2 1 1 146 148 147 +378 2 2 1 1 146 153 148 +379 2 2 1 1 146 225 153 +380 2 2 1 1 148 149 147 +381 2 2 1 1 149 194 147 +382 2 2 1 1 147 194 183 +383 2 2 1 1 148 150 149 +384 2 2 1 1 148 213 150 +385 2 2 1 1 153 213 148 +386 2 2 1 1 150 218 149 +387 2 2 1 1 149 210 194 +388 2 2 1 1 149 218 210 +389 2 2 1 1 188 218 150 +390 2 2 1 1 150 223 188 +391 2 2 1 1 213 223 150 +392 2 2 1 1 167 168 151 +393 2 2 1 1 154 210 185 +394 2 2 1 1 194 210 154 +395 2 2 1 1 159 206 203 +396 2 2 1 1 160 205 204 +397 2 2 1 1 165 202 166 +398 2 2 1 1 181 202 165 +399 2 2 1 1 191 192 166 +400 2 2 1 1 192 211 166 +401 2 2 1 1 169 198 170 +402 2 2 1 1 182 198 169 +403 2 2 1 1 189 190 170 +404 2 2 1 1 190 212 170 +405 2 2 1 1 171 173 172 +406 2 2 1 1 171 175 173 +407 2 2 1 1 173 196 172 +408 2 2 1 1 174 232 173 +409 2 2 1 1 173 232 196 +410 2 2 1 1 203 229 175 +411 2 2 1 1 176 178 177 +412 2 2 1 1 176 180 178 +413 2 2 1 1 178 195 177 +414 2 2 1 1 179 231 178 +415 2 2 1 1 178 231 195 +416 2 2 1 1 204 230 180 +417 2 2 2 2 38 271 2 +418 2 2 2 2 2 236 62 +419 2 2 2 2 2 271 236 +420 2 2 2 2 39 289 38 +421 2 2 2 2 38 289 271 +422 2 2 2 2 40 242 39 +423 2 2 2 2 242 289 39 +424 2 2 2 2 41 283 40 +425 2 2 2 2 40 283 242 +426 2 2 2 2 42 280 41 +427 2 2 2 2 280 283 41 +428 2 2 2 2 43 238 42 +429 2 2 2 2 238 280 42 +430 2 2 2 2 44 281 43 +431 2 2 2 2 43 281 238 +432 2 2 2 2 45 244 44 +433 2 2 2 2 244 281 44 +434 2 2 2 2 46 282 45 +435 2 2 2 2 45 282 244 +436 2 2 2 2 47 240 46 +437 2 2 2 2 240 282 46 +438 2 2 2 2 48 277 47 +439 2 2 2 2 47 277 240 +440 2 2 2 2 49 278 48 +441 2 2 2 2 48 278 277 +442 2 2 2 2 50 235 49 +443 2 2 2 2 235 278 49 +444 2 2 2 2 51 290 50 +445 2 2 2 2 50 290 235 +446 2 2 2 2 52 276 51 +447 2 2 2 2 276 290 51 +448 2 2 2 2 53 241 52 +449 2 2 2 2 241 276 52 +450 2 2 2 2 54 288 53 +451 2 2 2 2 53 288 241 +452 2 2 2 2 55 274 54 +453 2 2 2 2 274 288 54 +454 2 2 2 2 56 237 55 +455 2 2 2 2 237 274 55 +456 2 2 2 2 57 275 56 +457 2 2 2 2 56 275 237 +458 2 2 2 2 58 245 57 +459 2 2 2 2 245 275 57 +460 2 2 2 2 59 239 58 +461 2 2 2 2 239 245 58 +462 2 2 2 2 60 284 59 +463 2 2 2 2 59 284 239 +464 2 2 2 2 61 243 60 +465 2 2 2 2 243 284 60 +466 2 2 2 2 62 279 61 +467 2 2 2 2 61 279 243 +468 2 2 2 2 236 279 62 +469 2 2 2 2 235 269 263 +470 2 2 2 2 263 278 235 +471 2 2 2 2 235 290 269 +472 2 2 2 2 236 271 270 +473 2 2 2 2 270 287 236 +474 2 2 2 2 236 287 279 +475 2 2 2 2 272 274 237 +476 2 2 2 2 237 275 272 +477 2 2 2 2 259 280 238 +478 2 2 2 2 238 286 259 +479 2 2 2 2 281 286 238 +480 2 2 2 2 239 246 245 +481 2 2 2 2 239 247 246 +482 2 2 2 2 239 284 247 +483 2 2 2 2 277 291 240 +484 2 2 2 2 240 285 282 +485 2 2 2 2 240 291 285 +486 2 2 2 2 241 273 262 +487 2 2 2 2 262 276 241 +488 2 2 2 2 241 288 273 +489 2 2 2 2 242 283 259 +490 2 2 2 2 259 292 242 +491 2 2 2 2 242 292 289 +492 2 2 2 2 247 284 243 +493 2 2 2 2 243 287 247 +494 2 2 2 2 279 287 243 +495 2 2 2 2 260 281 244 +496 2 2 2 2 244 285 260 +497 2 2 2 2 282 285 244 +498 2 2 2 2 246 275 245 +499 2 2 2 2 247 248 246 +500 2 2 2 2 248 264 246 +501 2 2 2 2 264 275 246 +502 2 2 2 2 247 249 248 +503 2 2 2 2 247 287 249 +504 2 2 2 2 249 250 248 +505 2 2 2 2 250 251 248 +506 2 2 2 2 251 264 248 +507 2 2 2 2 249 265 250 +508 2 2 2 2 249 270 265 +509 2 2 2 2 249 287 270 +510 2 2 2 2 250 252 251 +511 2 2 2 2 250 253 252 +512 2 2 2 2 250 265 253 +513 2 2 2 2 252 254 251 +514 2 2 2 2 254 256 251 +515 2 2 2 2 256 264 251 +516 2 2 2 2 253 255 252 +517 2 2 2 2 252 267 254 +518 2 2 2 2 255 267 252 +519 2 2 2 2 253 257 255 +520 2 2 2 2 253 258 257 +521 2 2 2 2 253 265 258 +522 2 2 2 2 254 262 256 +523 2 2 2 2 254 263 262 +524 2 2 2 2 254 267 263 +525 2 2 2 2 257 260 255 +526 2 2 2 2 260 261 255 +527 2 2 2 2 261 267 255 +528 2 2 2 2 262 273 256 +529 2 2 2 2 256 272 264 +530 2 2 2 2 256 273 272 +531 2 2 2 2 258 259 257 +532 2 2 2 2 259 286 257 +533 2 2 2 2 257 286 260 +534 2 2 2 2 258 292 259 +535 2 2 2 2 265 266 258 +536 2 2 2 2 266 292 258 +537 2 2 2 2 259 283 280 +538 2 2 2 2 260 285 261 +539 2 2 2 2 260 286 281 +540 2 2 2 2 261 268 267 +541 2 2 2 2 261 291 268 +542 2 2 2 2 285 291 261 +543 2 2 2 2 263 269 262 +544 2 2 2 2 269 276 262 +545 2 2 2 2 267 268 263 +546 2 2 2 2 268 278 263 +547 2 2 2 2 272 275 264 +548 2 2 2 2 265 270 266 +549 2 2 2 2 270 271 266 +550 2 2 2 2 271 289 266 +551 2 2 2 2 289 292 266 +552 2 2 2 2 268 291 278 +553 2 2 2 2 269 290 276 +554 2 2 2 2 273 274 272 +555 2 2 2 2 273 288 274 +556 2 2 2 2 278 291 277 +557 2 2 3 3 13 1 329 +558 2 2 3 3 1 37 294 +559 2 2 3 3 1 294 329 +560 2 2 3 3 14 13 347 +561 2 2 3 3 13 329 347 +562 2 2 3 3 15 14 300 +563 2 2 3 3 300 14 347 +564 2 2 3 3 16 15 341 +565 2 2 3 3 15 300 341 +566 2 2 3 3 17 16 338 +567 2 2 3 3 338 16 341 +568 2 2 3 3 18 17 296 +569 2 2 3 3 296 17 338 +570 2 2 3 3 19 18 339 +571 2 2 3 3 18 296 339 +572 2 2 3 3 20 19 302 +573 2 2 3 3 302 19 339 +574 2 2 3 3 21 20 340 +575 2 2 3 3 20 302 340 +576 2 2 3 3 22 21 298 +577 2 2 3 3 298 21 340 +578 2 2 3 3 23 22 335 +579 2 2 3 3 22 298 335 +580 2 2 3 3 24 23 336 +581 2 2 3 3 23 335 336 +582 2 2 3 3 25 24 293 +583 2 2 3 3 293 24 336 +584 2 2 3 3 26 25 348 +585 2 2 3 3 25 293 348 +586 2 2 3 3 27 26 334 +587 2 2 3 3 334 26 348 +588 2 2 3 3 28 27 299 +589 2 2 3 3 299 27 334 +590 2 2 3 3 29 28 346 +591 2 2 3 3 28 299 346 +592 2 2 3 3 30 29 332 +593 2 2 3 3 332 29 346 +594 2 2 3 3 31 30 295 +595 2 2 3 3 295 30 332 +596 2 2 3 3 32 31 333 +597 2 2 3 3 31 295 333 +598 2 2 3 3 33 32 303 +599 2 2 3 3 303 32 333 +600 2 2 3 3 34 33 297 +601 2 2 3 3 297 33 303 +602 2 2 3 3 35 34 342 +603 2 2 3 3 34 297 342 +604 2 2 3 3 36 35 301 +605 2 2 3 3 301 35 342 +606 2 2 3 3 37 36 337 +607 2 2 3 3 36 301 337 +608 2 2 3 3 294 37 337 +609 2 2 3 3 293 321 327 +610 2 2 3 3 321 293 336 +611 2 2 3 3 293 327 348 +612 2 2 3 3 294 328 329 +613 2 2 3 3 328 294 345 +614 2 2 3 3 294 337 345 +615 2 2 3 3 330 295 332 +616 2 2 3 3 295 330 333 +617 2 2 3 3 317 296 338 +618 2 2 3 3 296 317 344 +619 2 2 3 3 339 296 344 +620 2 2 3 3 297 303 304 +621 2 2 3 3 297 304 305 +622 2 2 3 3 297 305 342 +623 2 2 3 3 335 298 349 +624 2 2 3 3 298 340 343 +625 2 2 3 3 298 343 349 +626 2 2 3 3 299 320 331 +627 2 2 3 3 320 299 334 +628 2 2 3 3 299 331 346 +629 2 2 3 3 300 317 341 +630 2 2 3 3 317 300 350 +631 2 2 3 3 300 347 350 +632 2 2 3 3 305 301 342 +633 2 2 3 3 301 305 345 +634 2 2 3 3 337 301 345 +635 2 2 3 3 318 302 339 +636 2 2 3 3 302 318 343 +637 2 2 3 3 340 302 343 +638 2 2 3 3 304 303 333 +639 2 2 3 3 305 304 306 +640 2 2 3 3 306 304 322 +641 2 2 3 3 322 304 333 +642 2 2 3 3 305 306 307 +643 2 2 3 3 305 307 345 +644 2 2 3 3 307 306 308 +645 2 2 3 3 308 306 309 +646 2 2 3 3 309 306 322 +647 2 2 3 3 307 308 323 +648 2 2 3 3 307 323 328 +649 2 2 3 3 307 328 345 +650 2 2 3 3 308 309 310 +651 2 2 3 3 308 310 311 +652 2 2 3 3 308 311 323 +653 2 2 3 3 310 309 312 +654 2 2 3 3 312 309 314 +655 2 2 3 3 314 309 322 +656 2 2 3 3 311 310 313 +657 2 2 3 3 310 312 325 +658 2 2 3 3 313 310 325 +659 2 2 3 3 311 313 315 +660 2 2 3 3 311 315 316 +661 2 2 3 3 311 316 323 +662 2 2 3 3 312 314 320 +663 2 2 3 3 312 320 321 +664 2 2 3 3 312 321 325 +665 2 2 3 3 315 313 318 +666 2 2 3 3 318 313 319 +667 2 2 3 3 319 313 325 +668 2 2 3 3 320 314 331 +669 2 2 3 3 314 322 330 +670 2 2 3 3 314 330 331 +671 2 2 3 3 316 315 317 +672 2 2 3 3 317 315 344 +673 2 2 3 3 315 318 344 +674 2 2 3 3 316 317 350 +675 2 2 3 3 323 316 324 +676 2 2 3 3 324 316 350 +677 2 2 3 3 317 338 341 +678 2 2 3 3 318 319 343 +679 2 2 3 3 318 339 344 +680 2 2 3 3 319 325 326 +681 2 2 3 3 319 326 349 +682 2 2 3 3 343 319 349 +683 2 2 3 3 321 320 327 +684 2 2 3 3 327 320 334 +685 2 2 3 3 325 321 326 +686 2 2 3 3 326 321 336 +687 2 2 3 3 330 322 333 +688 2 2 3 3 323 324 328 +689 2 2 3 3 328 324 329 +690 2 2 3 3 329 324 347 +691 2 2 3 3 347 324 350 +692 2 2 3 3 326 336 349 +693 2 2 3 3 327 334 348 +694 2 2 3 3 331 330 332 +695 2 2 3 3 331 332 346 +696 2 2 3 3 336 335 349 +697 4 2 1 1 234 93 393 395 +698 4 2 1 1 161 393 385 441 +699 4 2 1 1 126 372 240 391 +700 4 2 1 1 182 361 397 430 +701 4 2 1 1 277 126 240 391 +702 4 2 1 1 367 386 352 399 +703 4 2 1 1 315 394 392 404 +704 4 2 1 1 381 397 182 422 +705 4 2 1 1 132 432 402 438 +706 4 2 1 1 199 381 337 398 +707 4 2 1 1 304 375 448 455 +708 4 2 1 1 249 376 370 396 +709 4 2 1 1 392 399 315 404 +710 4 2 1 1 402 432 359 438 +711 4 2 1 1 304 448 415 455 +712 4 2 1 1 356 389 368 400 +713 4 2 1 1 286 402 374 407 +714 4 2 1 1 310 366 312 379 +715 4 2 1 1 357 371 364 458 +716 4 2 1 1 376 396 249 436 +717 4 2 1 1 369 377 360 430 +718 4 2 1 1 385 393 93 395 +719 4 2 1 1 312 379 366 389 +720 4 2 1 1 299 97 346 373 +721 4 2 1 1 175 229 367 420 +722 4 2 1 1 11 381 182 422 +723 4 2 1 1 384 107 443 452 +724 4 2 1 1 219 337 199 381 +725 4 2 1 1 361 182 397 422 +726 4 2 1 1 182 169 361 430 +727 4 2 1 1 366 379 310 404 +728 4 2 1 1 132 155 402 432 +729 4 2 1 1 93 385 161 393 +730 4 2 1 1 291 240 372 391 +731 4 2 1 1 182 381 11 397 +732 4 2 1 1 378 383 359 464 +733 4 2 1 1 354 416 376 461 +734 4 2 1 1 303 375 304 455 +735 4 2 1 1 291 277 240 391 +736 4 2 1 1 366 352 386 399 +737 4 2 1 1 383 461 359 464 +738 4 2 1 1 344 392 315 394 +739 4 2 1 1 321 389 368 465 +740 4 2 1 1 373 389 331 393 +741 4 2 1 1 408 443 107 452 +742 4 2 1 1 369 397 377 430 +743 4 2 1 1 310 379 308 404 +744 4 2 1 1 376 416 363 461 +745 4 2 1 1 353 386 367 399 +746 4 2 1 1 355 369 377 417 +747 4 2 1 1 368 400 389 405 +748 4 2 1 1 304 322 415 448 +749 4 2 1 1 372 391 126 439 +750 4 2 1 1 258 382 407 444 +751 4 2 1 1 172 196 392 394 +752 4 2 1 1 364 371 357 453 +753 4 2 1 1 367 392 175 420 +754 4 2 1 1 309 310 312 379 +755 4 2 1 1 365 384 443 452 +756 4 2 1 1 357 364 409 458 +757 4 2 1 1 175 367 203 418 +758 4 2 1 1 363 416 376 426 +759 4 2 1 1 169 387 361 430 +760 4 2 1 1 364 401 371 453 +761 4 2 1 1 205 204 100 364 +762 4 2 1 1 370 376 249 424 +763 4 2 1 1 354 376 416 466 +764 4 2 1 1 364 356 385 428 +765 4 2 1 1 107 365 408 452 +766 4 2 1 1 204 364 205 425 +767 4 2 1 1 377 417 369 442 +768 4 2 1 1 365 443 408 452 +769 4 2 1 1 364 205 425 441 +770 4 2 1 1 164 406 362 421 +771 4 2 1 1 356 393 385 395 +772 4 2 1 1 367 386 353 420 +773 4 2 1 1 63 196 172 394 +774 4 2 1 1 249 396 370 431 +775 4 2 1 1 364 371 356 428 +776 4 2 1 1 315 316 394 404 +777 4 2 1 1 355 377 369 397 +778 4 2 1 1 100 205 364 441 +779 4 2 1 1 361 397 381 422 +780 4 2 1 1 161 373 393 441 +781 4 2 1 1 357 436 371 458 +782 4 2 1 1 267 380 363 456 +783 4 2 1 1 356 364 385 441 +784 4 2 1 1 355 377 397 411 +785 4 2 1 1 394 404 316 459 +786 4 2 1 1 182 397 74 430 +787 4 2 1 1 361 316 404 459 +788 4 2 1 1 364 401 384 468 +789 4 2 1 1 356 371 364 401 +790 4 2 1 1 361 387 170 394 +791 4 2 1 1 359 383 378 432 +792 4 2 1 1 311 310 308 404 +793 4 2 1 1 362 433 447 457 +794 4 2 1 1 286 402 407 414 +795 4 2 1 1 359 386 367 420 +796 4 2 1 1 365 406 362 453 +797 4 2 1 1 172 392 296 394 +798 4 2 1 1 416 461 383 464 +799 4 2 1 1 308 404 379 411 +800 4 2 1 1 131 132 402 438 +801 4 2 1 1 338 63 296 394 +802 4 2 1 1 367 386 359 445 +803 4 2 1 1 361 404 316 411 +804 4 2 1 1 385 425 205 441 +805 4 2 1 1 368 389 321 405 +806 4 2 1 1 360 377 369 442 +807 4 2 1 1 361 387 377 430 +808 4 2 1 1 238 374 286 402 +809 4 2 1 1 364 425 385 441 +810 4 2 1 1 369 397 9 454 +811 4 2 1 1 363 380 267 437 +812 4 2 1 1 352 386 367 445 +813 4 2 1 1 9 369 423 430 +814 4 2 1 1 368 380 356 400 +815 4 2 1 1 299 97 373 393 +816 4 2 1 1 364 410 401 468 +817 4 2 1 1 186 369 9 454 +818 4 2 1 1 353 377 361 387 +819 4 2 1 1 170 361 169 387 +820 4 2 1 1 313 366 310 404 +821 4 2 1 1 362 406 164 447 +822 4 2 1 1 327 320 321 465 +823 4 2 1 1 392 394 353 404 +824 4 2 1 1 175 392 367 418 +825 4 2 1 1 355 379 375 417 +826 4 2 1 1 352 367 439 445 +827 4 2 1 1 105 384 107 443 +828 4 2 1 1 363 414 267 456 +829 4 2 1 1 376 426 416 466 +830 4 2 1 1 385 393 356 441 +831 4 2 1 1 372 439 367 445 +832 4 2 1 1 63 172 296 394 +833 4 2 1 1 352 399 366 405 +834 4 2 1 1 203 175 229 367 +835 4 2 1 1 384 401 443 468 +836 4 2 1 1 9 397 369 430 +837 4 2 1 1 361 377 397 430 +838 4 2 1 1 318 315 392 399 +839 4 2 1 1 164 112 406 421 +840 4 2 1 1 248 436 247 450 +841 4 2 1 1 247 436 396 450 +842 4 2 1 1 219 294 337 381 +843 4 2 1 1 269 395 380 428 +844 4 2 1 1 313 399 366 404 +845 4 2 1 1 286 407 257 414 +846 4 2 1 1 357 409 436 458 +847 4 2 1 1 361 394 170 459 +848 4 2 1 1 241 385 93 395 +849 4 2 1 1 313 325 366 399 +850 4 2 1 1 75 447 433 457 +851 4 2 1 1 319 399 388 405 +852 4 2 1 1 310 313 325 366 +853 4 2 1 1 304 415 333 455 +854 4 2 1 1 377 387 360 430 +855 4 2 1 1 356 368 389 393 +856 4 2 1 1 286 374 238 444 +857 4 2 1 1 333 303 304 455 +858 4 2 1 1 156 374 238 402 +859 4 2 1 1 158 375 303 455 +860 4 2 1 1 364 428 385 458 +861 4 2 1 1 353 361 377 404 +862 4 2 1 1 320 389 321 465 +863 4 2 1 1 374 402 155 432 +864 4 2 1 1 361 397 377 411 +865 4 2 1 1 356 400 380 460 +866 4 2 1 1 351 377 366 386 +867 4 2 1 1 352 439 372 445 +868 4 2 1 1 184 107 365 408 +869 4 2 1 1 184 403 365 421 +870 4 2 1 1 131 132 155 402 +871 4 2 1 1 388 399 319 418 +872 4 2 1 1 353 399 392 404 +873 4 2 1 1 6 433 390 457 +874 4 2 1 1 410 443 401 468 +875 4 2 1 1 198 361 169 459 +876 4 2 1 1 182 361 198 422 +877 4 2 1 1 374 407 382 444 +878 4 2 1 1 325 366 399 405 +879 4 2 1 1 349 388 319 418 +880 4 2 1 1 312 389 366 405 +881 4 2 1 1 316 324 350 422 +882 4 2 1 1 362 406 365 421 +883 4 2 1 1 219 199 88 381 +884 4 2 1 1 358 443 365 453 +885 4 2 1 1 352 388 367 399 +886 4 2 1 1 364 371 428 458 +887 4 2 1 1 389 393 368 465 +888 4 2 1 1 95 368 395 465 +889 4 2 1 1 320 331 389 393 +890 4 2 1 1 369 417 365 442 +891 4 2 1 1 363 416 426 460 +892 4 2 1 1 182 74 169 430 +893 4 2 1 1 356 380 371 460 +894 4 2 1 1 253 407 376 456 +895 4 2 1 1 224 381 199 398 +896 4 2 1 1 352 400 368 405 +897 4 2 1 1 253 376 250 456 +898 4 2 1 1 107 184 365 452 +899 4 2 1 1 246 436 248 450 +900 4 2 1 1 316 323 324 411 +901 4 2 1 1 337 381 345 398 +902 4 2 1 1 374 407 402 461 +903 4 2 1 1 355 403 369 417 +904 4 2 1 1 353 366 386 399 +905 4 2 1 1 355 375 408 417 +906 4 2 1 1 107 384 105 452 +907 4 2 1 1 406 365 452 453 +908 4 2 1 1 383 390 354 416 +909 4 2 1 1 358 365 417 453 +910 4 2 1 1 353 366 377 386 +911 4 2 1 1 311 404 308 411 +912 4 2 1 1 360 390 383 416 +913 4 2 1 1 383 432 359 461 +914 4 2 1 1 407 414 402 461 +915 4 2 1 1 258 407 382 424 +916 4 2 1 1 338 341 189 394 +917 4 2 1 1 307 381 411 449 +918 4 2 1 1 6 75 433 457 +919 4 2 1 1 361 404 394 459 +920 4 2 1 1 253 250 376 424 +921 4 2 1 1 352 380 368 400 +922 4 2 1 1 363 267 414 437 +923 4 2 1 1 376 407 354 461 +924 4 2 1 1 346 97 332 373 +925 4 2 1 1 375 379 358 417 +926 4 2 1 1 238 374 156 444 +927 4 2 1 1 365 403 184 408 +928 4 2 1 1 316 361 422 459 +929 4 2 1 1 277 85 126 391 +930 4 2 1 1 246 248 247 450 +931 4 2 1 1 416 442 377 464 +932 4 2 1 1 375 379 355 449 +933 4 2 1 1 100 364 204 468 +934 4 2 1 1 312 366 325 405 +935 4 2 1 1 162 391 388 439 +936 4 2 1 1 376 407 253 424 +937 4 2 1 1 255 267 414 456 +938 4 2 1 1 303 375 158 470 +939 4 2 1 1 355 403 408 451 +940 4 2 1 1 360 377 442 464 +941 4 2 1 1 331 299 346 373 +942 4 2 1 1 362 390 433 457 +943 4 2 1 1 269 380 395 435 +944 4 2 1 1 365 421 406 452 +945 4 2 1 1 364 425 204 468 +946 4 2 1 1 100 364 410 441 +947 4 2 1 1 355 408 375 451 +948 4 2 1 1 363 407 376 461 +949 4 2 1 1 196 392 394 413 +950 4 2 1 1 304 375 303 470 +951 4 2 1 1 369 403 365 417 +952 4 2 1 1 133 175 392 420 +953 4 2 1 1 360 442 416 464 +954 4 2 1 1 351 377 416 442 +955 4 2 1 1 351 417 377 442 +956 4 2 1 1 299 86 97 393 +957 4 2 1 1 164 421 362 457 +958 4 2 1 1 187 397 381 419 +959 4 2 1 1 184 110 114 421 +960 4 2 1 1 178 384 179 468 +961 4 2 1 1 366 386 352 400 +962 4 2 1 1 354 382 374 407 +963 4 2 1 1 355 408 403 417 +964 4 2 1 1 133 392 413 420 +965 4 2 1 1 338 317 341 394 +966 4 2 1 1 95 395 368 435 +967 4 2 1 1 310 325 312 366 +968 4 2 1 1 356 380 368 395 +969 4 2 1 1 193 403 125 454 +970 4 2 1 1 353 394 361 404 +971 4 2 1 1 351 386 366 400 +972 4 2 1 1 155 374 156 402 +973 4 2 1 1 351 416 377 464 +974 4 2 1 1 212 394 387 413 +975 4 2 1 1 351 365 442 453 +976 4 2 1 1 353 387 361 394 +977 4 2 1 1 389 400 366 405 +978 4 2 1 1 140 387 378 413 +979 4 2 1 1 296 392 344 394 +980 4 2 1 1 178 409 384 468 +981 4 2 1 1 366 377 351 434 +982 4 2 1 1 367 438 372 445 +983 4 2 1 1 94 388 162 391 +984 4 2 1 1 320 393 389 465 +985 4 2 1 1 291 391 372 437 +986 4 2 1 1 95 228 395 435 +987 4 2 1 1 212 387 140 413 +988 4 2 1 1 169 198 182 361 +989 4 2 1 1 184 114 193 403 +990 4 2 1 1 286 259 257 444 +991 4 2 1 1 353 420 386 464 +992 4 2 1 1 249 270 370 424 +993 4 2 1 1 304 322 333 415 +994 4 2 1 1 406 426 362 453 +995 4 2 1 1 370 396 376 467 +996 4 2 1 1 107 110 184 452 +997 4 2 1 1 371 380 356 428 +998 4 2 1 1 360 387 377 464 +999 4 2 1 1 358 401 443 453 +1000 4 2 1 1 351 377 386 464 +1001 4 2 1 1 132 420 432 438 +1002 4 2 1 1 241 385 395 428 +1003 4 2 1 1 175 133 229 420 +1004 4 2 1 1 306 322 304 449 +1005 4 2 1 1 169 361 170 459 +1006 4 2 1 1 358 417 401 453 +1007 4 2 1 1 382 412 188 433 +1008 4 2 1 1 351 365 417 442 +1009 4 2 1 1 345 381 307 449 +1010 4 2 1 1 316 422 350 459 +1011 4 2 1 1 125 403 421 454 +1012 4 2 1 1 377 379 366 404 +1013 4 2 1 1 239 247 284 450 +1014 4 2 1 1 287 249 370 431 +1015 4 2 1 1 145 374 155 432 +1016 4 2 1 1 142 212 170 387 +1017 4 2 1 1 125 403 193 421 +1018 4 2 1 1 344 318 315 392 +1019 4 2 1 1 299 373 331 393 +1020 4 2 1 1 184 114 403 421 +1021 4 2 1 1 360 416 383 464 +1022 4 2 1 1 240 372 126 462 +1023 4 2 1 1 353 377 366 404 +1024 4 2 1 1 345 398 381 449 +1025 4 2 1 1 328 324 411 422 +1026 4 2 1 1 359 432 420 438 +1027 4 2 1 1 140 378 387 446 +1028 4 2 1 1 352 380 400 445 +1029 4 2 1 1 304 303 297 470 +1030 4 2 1 1 363 400 380 445 +1031 4 2 1 1 188 382 150 412 +1032 4 2 1 1 180 204 425 468 +1033 4 2 1 1 355 397 381 411 +1034 4 2 1 1 352 388 399 405 +1035 4 2 1 1 359 386 420 464 +1036 4 2 1 1 352 366 400 405 +1037 4 2 1 1 224 88 199 381 +1038 4 2 1 1 364 356 401 441 +1039 4 2 1 1 384 443 401 453 +1040 4 2 1 1 249 250 376 436 +1041 4 2 1 1 267 255 252 456 +1042 4 2 1 1 198 422 361 459 +1043 4 2 1 1 374 402 359 461 +1044 4 2 1 1 129 203 367 439 +1045 4 2 1 1 363 426 376 460 +1046 4 2 1 1 179 384 178 427 +1047 4 2 1 1 170 169 142 387 +1048 4 2 1 1 170 387 212 394 +1049 4 2 1 1 317 315 316 394 +1050 4 2 1 1 351 386 416 464 +1051 4 2 1 1 382 188 429 433 +1052 4 2 1 1 355 377 379 417 +1053 4 2 1 1 274 160 288 385 +1054 4 2 1 1 186 369 68 423 +1055 4 2 1 1 416 442 390 466 +1056 4 2 1 1 365 362 421 442 +1057 4 2 1 1 77 373 99 415 +1058 4 2 1 1 357 371 426 453 +1059 4 2 1 1 193 403 114 421 +1060 4 2 1 1 129 203 229 367 +1061 4 2 1 1 315 399 313 404 +1062 4 2 1 1 328 411 381 422 +1063 4 2 1 1 359 402 414 461 +1064 4 2 1 1 366 379 377 434 +1065 4 2 1 1 364 384 357 409 +1066 4 2 1 1 183 383 378 446 +1067 4 2 1 1 367 359 438 445 +1068 4 2 1 1 379 417 377 434 +1069 4 2 1 1 357 396 436 450 +1070 4 2 1 1 351 400 366 434 +1071 4 2 1 1 189 63 338 394 +1072 4 2 1 1 129 206 203 439 +1073 4 2 1 1 10 182 11 397 +1074 4 2 1 1 140 378 137 413 +1075 4 2 1 1 155 145 156 374 +1076 4 2 1 1 125 68 186 369 +1077 4 2 1 1 186 125 369 454 +1078 4 2 1 1 11 381 187 397 +1079 4 2 1 1 353 377 387 464 +1080 4 2 1 1 375 448 379 449 +1081 4 2 1 1 356 371 401 460 +1082 4 2 1 1 97 77 332 373 +1083 4 2 1 1 77 332 373 415 +1084 4 2 1 1 125 68 369 421 +1085 4 2 1 1 306 448 322 449 +1086 4 2 1 1 354 382 424 433 +1087 4 2 1 1 358 379 375 448 +1088 4 2 1 1 249 248 250 436 +1089 4 2 1 1 379 404 377 411 +1090 4 2 1 1 178 384 409 427 +1091 4 2 1 1 100 410 364 468 +1092 4 2 1 1 378 383 183 432 +1093 4 2 1 1 70 303 333 455 +1094 4 2 1 1 426 453 371 460 +1095 4 2 1 1 247 396 284 450 +1096 4 2 1 1 261 291 285 372 +1097 4 2 1 1 83 288 160 385 +1098 4 2 1 1 383 390 360 463 +1099 4 2 1 1 286 260 402 414 +1100 4 2 1 1 12 294 381 422 +1101 4 2 1 1 307 381 328 411 +1102 4 2 1 1 267 254 380 456 +1103 4 2 1 1 355 379 377 411 +1104 4 2 1 1 249 270 287 370 +1105 4 2 1 1 194 210 412 463 +1106 4 2 1 1 371 380 254 456 +1107 4 2 1 1 77 98 99 373 +1108 4 2 1 1 401 371 453 460 +1109 4 2 1 1 396 436 376 467 +1110 4 2 1 1 353 392 367 420 +1111 4 2 1 1 151 430 423 463 +1112 4 2 1 1 382 444 213 469 +1113 4 2 1 1 366 399 353 404 +1114 4 2 1 1 254 380 371 428 +1115 4 2 1 1 357 384 364 453 +1116 4 2 1 1 365 358 408 443 +1117 4 2 1 1 89 223 188 429 +1118 4 2 1 1 253 252 407 456 +1119 4 2 1 1 362 447 164 457 +1120 4 2 1 1 80 199 337 398 +1121 4 2 1 1 179 178 231 427 +1122 4 2 1 1 368 380 352 435 +1123 4 2 1 1 287 370 270 431 +1124 4 2 1 1 149 194 210 412 +1125 4 2 1 1 269 380 263 428 +1126 4 2 1 1 136 378 183 432 +1127 4 2 1 1 133 392 173 413 +1128 4 2 1 1 331 346 332 373 +1129 4 2 1 1 140 139 378 446 +1130 4 2 1 1 291 240 285 372 +1131 4 2 1 1 317 338 296 394 +1132 4 2 1 1 205 161 385 441 +1133 4 2 1 1 354 416 390 466 +1134 4 2 1 1 381 397 361 411 +1135 4 2 1 1 284 396 191 450 +1136 4 2 1 1 133 175 173 392 +1137 4 2 1 1 99 373 410 415 +1138 4 2 1 1 229 367 420 438 +1139 4 2 1 1 365 408 358 417 +1140 4 2 1 1 291 372 261 437 +1141 4 2 1 1 365 421 369 442 +1142 4 2 1 1 228 290 395 435 +1143 4 2 1 1 98 373 161 441 +1144 4 2 1 1 374 382 354 469 +1145 4 2 1 1 289 382 200 429 +1146 4 2 1 1 317 394 316 459 +1147 4 2 1 1 227 293 368 465 +1148 4 2 1 1 311 316 404 411 +1149 4 2 1 1 140 139 137 378 +1150 4 2 1 1 384 365 443 453 +1151 4 2 1 1 158 303 70 455 +1152 4 2 1 1 198 169 170 459 +1153 4 2 1 1 284 243 191 396 +1154 4 2 1 1 368 393 356 395 +1155 4 2 1 1 151 446 430 463 +1156 4 2 1 1 372 352 391 439 +1157 4 2 1 1 301 80 337 398 +1158 4 2 1 1 396 406 211 427 +1159 4 2 1 1 112 406 421 452 +1160 4 2 1 1 356 401 400 460 +1161 4 2 1 1 351 442 426 453 +1162 4 2 1 1 331 373 330 448 +1163 4 2 1 1 326 405 388 440 +1164 4 2 1 1 125 421 369 454 +1165 4 2 1 1 253 265 250 424 +1166 4 2 1 1 194 412 383 463 +1167 4 2 1 1 381 398 355 449 +1168 4 2 1 1 189 394 341 459 +1169 4 2 1 1 71 392 175 418 +1170 4 2 1 1 369 421 68 457 +1171 4 2 1 1 100 98 205 441 +1172 4 2 1 1 343 349 319 418 +1173 4 2 1 1 286 257 260 414 +1174 4 2 1 1 381 355 411 449 +1175 4 2 1 1 382 412 354 469 +1176 4 2 1 1 370 424 382 433 +1177 4 2 1 1 241 93 276 395 +1178 4 2 1 1 126 127 372 439 +1179 4 2 1 1 181 90 4 370 +1180 4 2 1 1 223 382 188 429 +1181 4 2 1 1 227 368 95 465 +1182 4 2 1 1 368 352 391 435 +1183 4 2 1 1 377 417 351 434 +1184 4 2 1 1 137 378 134 413 +1185 4 2 1 1 92 234 393 395 +1186 4 2 1 1 357 426 371 436 +1187 4 2 1 1 224 381 398 419 +1188 4 2 1 1 183 378 139 446 +1189 4 2 1 1 99 373 98 410 +1190 4 2 1 1 96 368 227 440 +1191 4 2 1 1 12 219 88 381 +1192 4 2 1 1 370 382 429 433 +1193 4 2 1 1 367 392 353 399 +1194 4 2 1 1 360 383 378 464 +1195 4 2 1 1 302 392 71 418 +1196 4 2 1 1 366 389 379 434 +1197 4 2 1 1 362 390 442 466 +1198 4 2 1 1 323 328 324 411 +1199 4 2 1 1 4 370 90 429 +1200 4 2 1 1 341 394 317 459 +1201 4 2 1 1 92 93 234 395 +1202 4 2 1 1 354 412 382 433 +1203 4 2 1 1 186 68 8 423 +1204 4 2 1 1 358 408 375 417 +1205 4 2 1 1 12 294 219 381 +1206 4 2 1 1 90 370 181 431 +1207 4 2 1 1 149 383 194 412 +1208 4 2 1 1 136 139 183 378 +1209 4 2 1 1 382 424 370 429 +1210 4 2 1 1 71 175 203 418 +1211 4 2 1 1 11 187 10 397 +1212 4 2 1 1 311 323 316 411 +1213 4 2 1 1 255 407 252 456 +1214 4 2 1 1 351 417 365 453 +1215 4 2 1 1 384 409 364 468 +1216 4 2 1 1 369 68 423 457 +1217 4 2 1 1 100 410 98 441 +1218 4 2 1 1 214 121 419 451 +1219 4 2 1 1 227 368 293 440 +1220 4 2 1 1 354 383 416 461 +1221 4 2 1 1 169 168 387 430 +1222 4 2 1 1 129 367 229 438 +1223 4 2 1 1 188 223 150 382 +1224 4 2 1 1 222 429 90 431 +1225 4 2 1 1 374 432 138 469 +1226 4 2 1 1 371 426 376 436 +1227 4 2 1 1 289 81 200 382 +1228 4 2 1 1 249 265 270 424 +1229 4 2 1 1 4 181 370 433 +1230 4 2 1 1 246 409 436 450 +1231 4 2 1 1 274 160 385 425 +1232 4 2 1 1 285 261 372 414 +1233 4 2 1 1 337 294 345 381 +1234 4 2 1 1 375 358 448 455 +1235 4 2 1 1 384 401 364 453 +1236 4 2 1 1 355 369 403 454 +1237 4 2 1 1 354 382 407 424 +1238 4 2 1 1 345 328 307 381 +1239 4 2 1 1 374 432 383 461 +1240 4 2 1 1 106 107 408 443 +1241 4 2 1 1 230 100 204 468 +1242 4 2 1 1 318 313 315 399 +1243 4 2 1 1 388 391 352 439 +1244 4 2 1 1 96 435 368 440 +1245 4 2 1 1 372 438 367 439 +1246 4 2 1 1 269 263 380 435 +1247 4 2 1 1 116 375 226 455 +1248 4 2 1 1 95 368 96 435 +1249 4 2 1 1 176 245 177 450 +1250 4 2 1 1 354 433 424 466 +1251 4 2 1 1 359 402 374 432 +1252 4 2 1 1 180 230 204 468 +1253 4 2 1 1 352 367 388 439 +1254 4 2 1 1 317 344 315 394 +1255 4 2 1 1 352 368 391 440 +1256 4 2 1 1 368 405 321 440 +1257 4 2 1 1 269 262 395 428 +1258 4 2 1 1 355 397 369 454 +1259 4 2 1 1 75 164 447 457 +1260 4 2 1 1 318 399 392 418 +1261 4 2 1 1 354 374 383 461 +1262 4 2 1 1 104 178 179 468 +1263 4 2 1 1 127 128 372 439 +1264 4 2 1 1 321 389 312 405 +1265 4 2 1 1 363 380 371 456 +1266 4 2 1 1 184 109 107 408 +1267 4 2 1 1 389 400 356 471 +1268 4 2 1 1 255 253 252 407 +1269 4 2 1 1 183 194 383 463 +1270 4 2 1 1 224 88 381 419 +1271 4 2 1 1 386 416 363 460 +1272 4 2 1 1 176 409 245 450 +1273 4 2 1 1 210 390 73 412 +1274 4 2 1 1 192 396 211 427 +1275 4 2 1 1 90 429 370 431 +1276 4 2 1 1 372 414 261 437 +1277 4 2 1 1 116 226 375 451 +1278 4 2 1 1 353 386 377 464 +1279 4 2 1 1 318 343 399 418 +1280 4 2 1 1 92 395 393 465 +1281 4 2 1 1 138 145 374 469 +1282 4 2 1 1 183 143 194 463 +1283 4 2 1 1 240 285 372 462 +1284 4 2 1 1 138 146 145 469 +1285 4 2 1 1 401 410 358 443 +1286 4 2 1 1 173 172 196 392 +1287 4 2 1 1 180 409 178 468 +1288 4 2 1 1 426 453 406 467 +1289 4 2 1 1 116 117 226 451 +1290 4 2 1 1 134 413 378 420 +1291 4 2 1 1 214 419 398 451 +1292 4 2 1 1 153 213 444 469 +1293 4 2 1 1 145 225 156 374 +1294 4 2 1 1 67 151 423 463 +1295 4 2 1 1 164 112 113 406 +1296 4 2 1 1 284 247 243 396 +1297 4 2 1 1 106 105 107 443 +1298 4 2 1 1 357 406 453 467 +1299 4 2 1 1 181 431 370 447 +1300 4 2 1 1 156 374 225 444 +1301 4 2 1 1 296 344 317 394 +1302 4 2 1 1 179 384 427 452 +1303 4 2 1 1 290 269 395 435 +1304 4 2 1 1 75 163 164 457 +1305 4 2 1 1 369 360 423 430 +1306 4 2 1 1 362 426 406 467 +1307 4 2 1 1 212 144 394 413 +1308 4 2 1 1 120 403 419 451 +1309 4 2 1 1 375 408 116 451 +1310 4 2 1 1 84 206 388 418 +1311 4 2 1 1 240 78 282 462 +1312 4 2 1 1 380 391 352 435 +1313 4 2 1 1 371 380 363 460 +1314 4 2 1 1 388 418 206 439 +1315 4 2 1 1 353 413 392 420 +1316 4 2 1 1 227 96 95 368 +1317 4 2 1 1 321 293 368 440 +1318 4 2 1 1 134 378 136 432 +1319 4 2 1 1 376 426 371 460 +1320 4 2 1 1 214 119 121 451 +1321 4 2 1 1 205 98 161 441 +1322 4 2 1 1 343 319 399 418 +1323 4 2 1 1 373 98 410 441 +1324 4 2 1 1 11 12 381 422 +1325 4 2 1 1 386 400 363 445 +1326 4 2 1 1 354 407 376 424 +1327 4 2 1 1 243 82 396 431 +1328 4 2 1 1 112 421 110 452 +1329 4 2 1 1 241 395 262 428 +1330 4 2 1 1 97 161 98 373 +1331 4 2 1 1 367 399 388 418 +1332 4 2 1 1 326 321 405 440 +1333 4 2 1 1 87 11 182 422 +1334 4 2 1 1 128 438 372 439 +1335 4 2 1 1 320 299 331 393 +1336 4 2 1 1 371 436 251 458 +1337 4 2 1 1 237 409 69 425 +1338 4 2 1 1 171 339 172 392 +1339 4 2 1 1 264 436 409 458 +1340 4 2 1 1 390 412 210 463 +1341 4 2 1 1 127 372 128 462 +1342 4 2 1 1 12 329 294 422 +1343 4 2 1 1 424 433 370 466 +1344 4 2 1 1 365 403 369 421 +1345 4 2 1 1 274 288 273 385 +1346 4 2 1 1 302 171 71 392 +1347 4 2 1 1 84 388 298 418 +1348 4 2 1 1 134 420 378 432 +1349 4 2 1 1 236 429 222 431 +1350 4 2 1 1 332 330 331 373 +1351 4 2 1 1 226 375 158 455 +1352 4 2 1 1 95 96 228 435 +1353 4 2 1 1 356 393 389 471 +1354 4 2 1 1 145 138 374 432 +1355 4 2 1 1 400 401 356 471 +1356 4 2 1 1 409 357 436 450 +1357 4 2 1 1 352 391 380 437 +1358 4 2 1 1 146 374 145 469 +1359 4 2 1 1 357 453 426 467 +1360 4 2 1 1 8 9 423 430 +1361 4 2 1 1 181 370 433 447 +1362 4 2 1 1 202 431 181 447 +1363 4 2 1 1 352 372 391 437 +1364 4 2 1 1 118 408 403 451 +1365 4 2 1 1 310 309 308 379 +1366 4 2 1 1 363 400 386 460 +1367 4 2 1 1 372 285 414 462 +1368 4 2 1 1 352 437 380 445 +1369 4 2 1 1 390 416 360 442 +1370 4 2 1 1 264 246 409 436 +1371 4 2 1 1 200 382 223 429 +1372 4 2 1 1 76 397 187 419 +1373 4 2 1 1 171 302 339 392 +1374 4 2 1 1 269 263 262 428 +1375 4 2 1 1 359 402 372 414 +1376 4 2 1 1 134 137 136 378 +1377 4 2 1 1 364 401 410 441 +1378 4 2 1 1 187 381 88 419 +1379 4 2 1 1 374 354 383 469 +1380 4 2 1 1 144 212 140 413 +1381 4 2 1 1 363 380 437 445 +1382 4 2 1 1 122 421 164 457 +1383 4 2 1 1 153 148 213 469 +1384 4 2 1 1 306 379 448 449 +1385 4 2 1 1 357 409 384 427 +1386 4 2 1 1 155 132 135 432 +1387 4 2 1 1 117 116 408 451 +1388 4 2 1 1 293 327 321 465 +1389 4 2 1 1 147 194 149 383 +1390 4 2 1 1 176 69 237 409 +1391 4 2 1 1 369 421 403 454 +1392 4 2 1 1 330 373 332 415 +1393 4 2 1 1 240 126 78 462 +1394 4 2 1 1 4 370 429 433 +1395 4 2 1 1 354 390 383 412 +1396 4 2 1 1 351 416 386 460 +1397 4 2 1 1 325 399 319 405 +1398 4 2 1 1 109 408 118 451 +1399 4 2 1 1 67 423 151 430 +1400 4 2 1 1 92 276 93 395 +1401 4 2 1 1 378 383 360 446 +1402 4 2 1 1 84 335 298 388 +1403 4 2 1 1 330 373 415 448 +1404 4 2 1 1 95 395 92 465 +1405 4 2 1 1 335 388 94 440 +1406 4 2 1 1 356 373 393 471 +1407 4 2 1 1 160 205 385 425 +1408 4 2 1 1 370 429 270 431 +1409 4 2 1 1 430 446 360 463 +1410 4 2 1 1 376 407 363 456 +1411 4 2 1 1 273 274 385 425 +1412 4 2 1 1 92 234 208 393 +1413 4 2 1 1 331 330 314 448 +1414 4 2 1 1 266 382 289 429 +1415 4 2 1 1 368 352 405 440 +1416 4 2 1 1 356 395 385 428 +1417 4 2 1 1 213 382 81 444 +1418 4 2 1 1 357 436 396 467 +1419 4 2 1 1 164 406 113 447 +1420 4 2 1 1 256 371 251 458 +1421 4 2 1 1 77 295 332 415 +1422 4 2 1 1 260 414 285 462 +1423 4 2 1 1 423 430 360 463 +1424 4 2 1 1 183 383 138 432 +1425 4 2 1 1 380 400 363 460 +1426 4 2 1 1 373 356 393 441 +1427 4 2 1 1 132 420 134 432 +1428 4 2 1 1 377 404 361 411 +1429 4 2 1 1 120 419 403 454 +1430 4 2 1 1 386 359 461 464 +1431 4 2 1 1 357 376 426 436 +1432 4 2 1 1 229 420 130 438 +1433 4 2 1 1 149 383 412 469 +1434 4 2 1 1 426 442 416 466 +1435 4 2 1 1 311 313 310 404 +1436 4 2 1 1 389 393 373 471 +1437 4 2 1 1 304 449 375 470 +1438 4 2 1 1 349 336 326 388 +1439 4 2 1 1 228 290 276 395 +1440 4 2 1 1 6 390 7 457 +1441 4 2 1 1 359 414 372 445 +1442 4 2 1 1 169 168 142 387 +1443 4 2 1 1 357 427 396 450 +1444 4 2 1 1 384 357 427 452 +1445 4 2 1 1 228 235 290 435 +1446 4 2 1 1 98 77 97 373 +1447 4 2 1 1 245 409 275 450 +1448 4 2 1 1 192 396 427 450 +1449 4 2 1 1 192 66 191 450 +1450 4 2 1 1 337 345 301 398 +1451 4 2 1 1 318 392 302 418 +1452 4 2 1 1 378 387 353 413 +1453 4 2 1 1 116 226 158 455 +1454 4 2 1 1 409 425 272 458 +1455 4 2 1 1 147 138 183 383 +1456 4 2 1 1 357 406 452 453 +1457 4 2 1 1 209 193 125 454 +1458 4 2 1 1 381 411 361 422 +1459 4 2 1 1 192 191 396 450 +1460 4 2 1 1 226 158 375 470 +1461 4 2 1 1 242 81 289 382 +1462 4 2 1 1 392 399 367 418 +1463 4 2 1 1 376 371 456 460 +1464 4 2 1 1 83 205 161 385 +1465 4 2 1 1 298 388 349 418 +1466 4 2 1 1 251 371 254 456 +1467 4 2 1 1 149 147 383 469 +1468 4 2 1 1 370 424 270 429 +1469 4 2 1 1 235 96 207 435 +1470 4 2 1 1 389 434 400 471 +1471 4 2 1 1 403 408 365 417 +1472 4 2 1 1 366 400 389 434 +1473 4 2 1 1 176 275 245 409 +1474 4 2 1 1 314 320 331 389 +1475 4 2 1 1 179 427 115 452 +1476 4 2 1 1 73 412 390 433 +1477 4 2 1 1 367 359 420 438 +1478 4 2 1 1 168 141 387 446 +1479 4 2 1 1 168 387 430 446 +1480 4 2 1 1 266 292 382 424 +1481 4 2 1 1 224 187 88 419 +1482 4 2 1 1 190 212 144 394 +1483 4 2 1 1 179 115 108 452 +1484 4 2 1 1 147 138 383 469 +1485 4 2 1 1 326 388 336 440 +1486 4 2 1 1 176 177 409 450 +1487 4 2 1 1 266 424 382 429 +1488 4 2 1 1 122 112 164 421 +1489 4 2 1 1 268 435 391 437 +1490 4 2 1 1 133 173 174 413 +1491 4 2 1 1 127 128 78 462 +1492 4 2 1 1 356 380 395 428 +1493 4 2 1 1 210 73 218 412 +1494 4 2 1 1 12 88 11 381 +1495 4 2 1 1 359 420 378 464 +1496 4 2 1 1 308 411 379 449 +1497 4 2 1 1 293 321 368 465 +1498 4 2 1 1 181 433 75 447 +1499 4 2 1 1 371 256 428 458 +1500 4 2 1 1 386 461 416 464 +1501 4 2 1 1 208 92 393 465 +1502 4 2 1 1 296 172 339 392 +1503 4 2 1 1 102 415 410 455 +1504 4 2 1 1 273 425 385 458 +1505 4 2 1 1 363 416 386 461 +1506 4 2 1 1 367 438 129 439 +1507 4 2 1 1 304 305 449 470 +1508 4 2 1 1 352 400 386 445 +1509 4 2 1 1 258 382 292 424 +1510 4 2 1 1 260 402 414 462 +1511 4 2 1 1 70 333 415 455 +1512 4 2 1 1 381 397 355 419 +1513 4 2 1 1 292 289 266 382 +1514 4 2 1 1 353 387 378 464 +1515 4 2 1 1 388 405 352 440 +1516 4 2 1 1 235 207 278 435 +1517 4 2 1 1 94 335 84 388 +1518 4 2 1 1 254 251 256 371 +1519 4 2 1 1 218 188 150 412 +1520 4 2 1 1 372 402 359 438 +1521 4 2 1 1 410 441 401 471 +1522 4 2 1 1 196 394 144 413 +1523 4 2 1 1 357 452 384 453 +1524 4 2 1 1 343 318 302 418 +1525 4 2 1 1 7 390 185 423 +1526 4 2 1 1 238 281 72 402 +1527 4 2 1 1 323 311 308 411 +1528 4 2 1 1 90 181 202 431 +1529 4 2 1 1 102 410 443 455 +1530 4 2 1 1 67 151 167 430 +1531 4 2 1 1 174 137 134 413 +1532 4 2 1 1 294 328 381 422 +1533 4 2 1 1 400 434 401 471 +1534 4 2 1 1 176 237 275 409 +1535 4 2 1 1 138 432 383 469 +1536 4 2 1 1 362 433 390 466 +1537 4 2 1 1 227 348 293 465 +1538 4 2 1 1 384 443 105 468 +1539 4 2 1 1 63 190 196 394 +1540 4 2 1 1 351 386 400 460 +1541 4 2 1 1 391 435 380 437 +1542 4 2 1 1 104 180 178 468 +1543 4 2 1 1 351 401 400 434 +1544 4 2 1 1 114 110 112 421 +1545 4 2 1 1 254 371 256 428 +1546 4 2 1 1 362 447 433 466 +1547 4 2 1 1 7 6 185 390 +1548 4 2 1 1 7 390 423 457 +1549 4 2 1 1 264 409 272 458 +1550 4 2 1 1 351 401 417 453 +1551 4 2 1 1 212 142 140 387 +1552 4 2 1 1 406 427 357 452 +1553 4 2 1 1 243 396 247 431 +1554 4 2 1 1 233 391 207 440 +1555 4 2 1 1 131 438 402 462 +1556 4 2 1 1 82 191 243 396 +1557 4 2 1 1 352 391 388 440 +1558 4 2 1 1 354 412 383 469 +1559 4 2 1 1 160 205 83 385 +1560 4 2 1 1 182 10 74 397 +1561 4 2 1 1 375 398 355 451 +1562 4 2 1 1 390 442 423 457 +1563 4 2 1 1 80 398 301 470 +1564 4 2 1 1 6 163 75 457 +1565 4 2 1 1 139 136 137 378 +1566 4 2 1 1 89 200 223 429 +1567 4 2 1 1 84 388 206 439 +1568 4 2 1 1 374 359 432 461 +1569 4 2 1 1 363 376 456 460 +1570 4 2 1 1 360 423 390 442 +1571 4 2 1 1 67 167 423 430 +1572 4 2 1 1 11 87 12 422 +1573 4 2 1 1 387 394 353 413 +1574 4 2 1 1 156 238 72 402 +1575 4 2 1 1 369 423 360 442 +1576 4 2 1 1 188 412 218 433 +1577 4 2 1 1 375 451 226 470 +1578 4 2 1 1 81 382 242 444 +1579 4 2 1 1 263 380 254 428 +1580 4 2 1 1 4 429 188 433 +1581 4 2 1 1 326 336 321 440 +1582 4 2 1 1 351 426 416 460 +1583 4 2 1 1 236 270 429 431 +1584 4 2 1 1 76 10 187 397 +1585 4 2 1 1 352 372 437 445 +1586 4 2 1 1 140 387 141 446 +1587 4 2 1 1 126 162 127 439 +1588 4 2 1 1 368 395 380 435 +1589 4 2 1 1 354 407 374 461 +1590 4 2 1 1 335 336 349 388 +1591 4 2 1 1 415 448 358 455 +1592 4 2 1 1 92 95 228 395 +1593 4 2 1 1 116 408 375 455 +1594 4 2 1 1 127 129 128 439 +1595 4 2 1 1 134 174 413 420 +1596 4 2 1 1 207 391 278 435 +1597 4 2 1 1 168 430 151 446 +1598 4 2 1 1 364 425 409 458 +1599 4 2 1 1 73 218 412 433 +1600 4 2 1 1 185 73 210 390 +1601 4 2 1 1 3 90 222 429 +1602 4 2 1 1 65 280 156 444 +1603 4 2 1 1 397 419 76 454 +1604 4 2 1 1 73 390 6 433 +1605 4 2 1 1 353 394 392 413 +1606 4 2 1 1 379 434 389 448 +1607 4 2 1 1 340 159 298 418 +1608 4 2 1 1 368 435 391 440 +1609 4 2 1 1 250 376 436 456 +1610 4 2 1 1 223 200 81 382 +1611 4 2 1 1 312 321 320 389 +1612 4 2 1 1 211 396 166 406 +1613 4 2 1 1 400 401 351 460 +1614 4 2 1 1 94 23 335 440 +1615 4 2 1 1 372 438 359 445 +1616 4 2 1 1 128 372 438 462 +1617 4 2 1 1 282 240 46 78 +1618 4 2 1 1 93 83 161 385 +1619 4 2 1 1 289 200 220 429 +1620 4 2 1 1 136 183 138 432 +1621 4 2 1 1 144 196 190 394 +1622 4 2 1 1 358 448 373 471 +1623 4 2 1 1 375 355 398 449 +1624 4 2 1 1 80 224 199 398 +1625 4 2 1 1 179 108 384 452 +1626 4 2 1 1 125 193 114 421 +1627 4 2 1 1 129 438 128 439 +1628 4 2 1 1 185 423 390 463 +1629 4 2 1 1 123 295 77 415 +1630 4 2 1 1 171 175 71 392 +1631 4 2 1 1 128 438 131 462 +1632 4 2 1 1 306 379 309 448 +1633 4 2 1 1 209 120 193 454 +1634 4 2 1 1 251 436 371 456 +1635 4 2 1 1 308 307 411 449 +1636 4 2 1 1 325 319 326 405 +1637 4 2 1 1 355 398 381 419 +1638 4 2 1 1 93 53 83 288 +1639 4 2 1 1 53 93 241 288 +1640 4 2 1 1 84 162 388 439 +1641 4 2 1 1 264 251 436 458 +1642 4 2 1 1 117 109 118 451 +1643 4 2 1 1 85 277 207 391 +1644 4 2 1 1 187 11 88 381 +1645 4 2 1 1 63 189 190 394 +1646 4 2 1 1 358 410 401 471 +1647 4 2 1 1 354 424 376 466 +1648 4 2 1 1 111 406 112 452 +1649 4 2 1 1 120 403 193 454 +1650 4 2 1 1 71 340 302 418 +1651 4 2 1 1 358 415 373 448 +1652 4 2 1 1 115 427 406 452 +1653 4 2 1 1 362 442 390 457 +1654 4 2 1 1 358 417 379 434 +1655 4 2 1 1 72 281 244 462 +1656 4 2 1 1 117 408 109 451 +1657 4 2 1 1 266 270 424 429 +1658 4 2 1 1 298 349 343 418 +1659 4 2 1 1 166 406 396 447 +1660 4 2 1 1 225 374 146 444 +1661 4 2 1 1 197 347 422 459 +1662 4 2 1 1 335 336 388 440 +1663 4 2 1 1 113 406 166 447 +1664 4 2 1 1 358 410 373 415 +1665 4 2 1 1 316 315 311 404 +1666 4 2 1 1 169 74 168 430 +1667 4 2 1 1 362 442 426 466 +1668 4 2 1 1 142 168 141 387 +1669 4 2 1 1 84 298 159 418 +1670 4 2 1 1 374 444 382 469 +1671 4 2 1 1 355 419 403 451 +1672 4 2 1 1 369 442 421 457 +1673 4 2 1 1 132 134 135 432 +1674 4 2 1 1 185 390 210 463 +1675 4 2 1 1 72 402 281 462 +1676 4 2 1 1 242 382 292 444 +1677 4 2 1 1 146 444 374 469 +1678 4 2 1 1 353 378 420 464 +1679 4 2 1 1 354 390 433 466 +1680 4 2 1 1 9 397 76 454 +1681 4 2 1 1 225 145 146 374 +1682 4 2 1 1 253 250 252 456 +1683 4 2 1 1 72 155 156 402 +1684 4 2 1 1 358 373 410 471 +1685 4 2 1 1 295 123 70 415 +1686 4 2 1 1 72 244 152 462 +1687 4 2 1 1 273 288 241 385 +1688 4 2 1 1 291 268 391 437 +1689 4 2 1 1 111 115 406 452 +1690 4 2 1 1 108 107 105 452 +1691 4 2 1 1 232 174 173 413 +1692 4 2 1 1 197 422 198 459 +1693 4 2 1 1 387 446 378 464 +1694 4 2 1 1 91 207 96 440 +1695 4 2 1 1 4 5 181 433 +1696 4 2 1 1 238 156 280 444 +1697 4 2 1 1 360 446 387 464 +1698 4 2 1 1 229 133 130 420 +1699 4 2 1 1 319 318 343 399 +1700 4 2 1 1 321 336 293 440 +1701 4 2 1 1 87 182 198 422 +1702 4 2 1 1 383 360 446 463 +1703 4 2 1 1 181 5 75 433 +1704 4 2 1 1 96 207 49 235 +1705 4 2 1 1 145 155 135 432 +1706 4 2 1 1 393 395 368 465 +1707 4 2 1 1 71 159 340 418 +1708 4 2 1 1 313 319 325 399 +1709 4 2 1 1 67 423 185 463 +1710 4 2 1 1 222 201 279 431 +1711 4 2 1 1 363 386 445 461 +1712 4 2 1 1 351 401 453 460 +1713 4 2 1 1 120 118 403 451 +1714 4 2 1 1 264 256 251 458 +1715 4 2 1 1 354 390 412 433 +1716 4 2 1 1 323 307 328 411 +1717 4 2 1 1 140 142 141 387 +1718 4 2 1 1 108 105 384 452 +1719 4 2 1 1 168 151 141 446 +1720 4 2 1 1 268 278 391 435 +1721 4 2 1 1 421 442 362 457 +1722 4 2 1 1 372 414 402 462 +1723 4 2 1 1 328 345 294 381 +1724 4 2 1 1 266 258 292 424 +1725 4 2 1 1 267 380 263 437 +1726 4 2 1 1 290 228 50 235 +1727 4 2 1 1 227 95 348 465 +1728 4 2 1 1 294 329 328 422 +1729 4 2 1 1 185 6 73 390 +1730 4 2 1 1 102 99 410 415 +1731 4 2 1 1 217 419 120 454 +1732 4 2 1 1 385 428 273 458 +1733 4 2 1 1 103 105 443 468 +1734 4 2 1 1 268 263 435 437 +1735 4 2 1 1 290 269 276 395 +1736 4 2 1 1 309 306 308 379 +1737 4 2 1 1 77 99 123 415 +1738 4 2 1 1 115 179 231 427 +1739 4 2 1 1 321 312 325 405 +1740 4 2 1 1 367 418 388 439 +1741 4 2 1 1 91 233 207 440 +1742 4 2 1 1 253 407 258 424 +1743 4 2 1 1 179 108 105 384 +1744 4 2 1 1 86 299 208 393 +1745 4 2 1 1 84 206 162 439 +1746 4 2 1 1 133 413 174 420 +1747 4 2 1 1 410 415 358 455 +1748 4 2 1 1 357 406 396 427 +1749 4 2 1 1 403 419 355 454 +1750 4 2 1 1 8 423 167 430 +1751 4 2 1 1 383 412 390 463 +1752 4 2 1 1 89 188 4 429 +1753 4 2 1 1 222 279 236 431 +1754 4 2 1 1 287 243 247 431 +1755 4 2 1 1 171 172 173 392 +1756 4 2 1 1 115 211 406 427 +1757 4 2 1 1 147 183 194 383 +1758 4 2 1 1 263 267 254 380 +1759 4 2 1 1 355 379 411 449 +1760 4 2 1 1 262 263 254 428 +1761 4 2 1 1 410 358 443 455 +1762 4 2 1 1 351 453 426 460 +1763 4 2 1 1 240 282 285 462 +1764 4 2 1 1 190 170 212 394 +1765 4 2 1 1 8 167 9 430 +1766 4 2 1 1 84 159 206 418 +1767 4 2 1 1 180 69 409 425 +1768 4 2 1 1 196 144 232 413 +1769 4 2 1 1 308 379 306 449 +1770 4 2 1 1 166 211 192 396 +1771 4 2 1 1 254 267 252 456 +1772 4 2 1 1 211 166 113 406 +1773 4 2 1 1 207 277 278 391 +1774 4 2 1 1 29 332 346 97 +1775 4 2 1 1 292 242 289 382 +1776 4 2 1 1 409 427 357 450 +1777 4 2 1 1 299 334 208 393 +1778 4 2 1 1 397 355 419 454 +1779 4 2 1 1 371 436 376 456 +1780 4 2 1 1 373 448 389 471 +1781 4 2 1 1 72 152 402 462 +1782 4 2 1 1 190 170 394 459 +1783 4 2 1 1 295 70 333 415 +1784 4 2 1 1 207 85 48 277 +1785 4 2 1 1 250 436 251 456 +1786 4 2 1 1 67 154 151 463 +1787 4 2 1 1 183 139 143 446 +1788 4 2 1 1 190 394 189 459 +1789 4 2 1 1 380 435 263 437 +1790 4 2 1 1 221 329 12 422 +1791 4 2 1 1 223 81 213 382 +1792 4 2 1 1 373 356 441 471 +1793 4 2 1 1 211 111 115 406 +1794 4 2 1 1 375 408 358 455 +1795 4 2 1 1 223 213 150 382 +1796 4 2 1 1 241 276 262 395 +1797 4 2 1 1 335 23 336 440 +1798 4 2 1 1 257 407 255 414 +1799 4 2 1 1 378 413 353 420 +1800 4 2 1 1 118 184 193 403 +1801 4 2 1 1 276 52 93 241 +1802 4 2 1 1 96 235 228 435 +1803 4 2 1 1 402 438 372 462 +1804 4 2 1 1 86 27 208 299 +1805 4 2 1 1 213 81 153 444 +1806 4 2 1 1 363 456 371 460 +1807 4 2 1 1 423 442 369 457 +1808 4 2 1 1 414 445 359 461 +1809 4 2 1 1 117 116 109 408 +1810 4 2 1 1 235 207 49 278 +1811 4 2 1 1 126 46 240 78 +1812 4 2 1 1 84 162 94 388 +1813 4 2 1 1 140 141 139 446 +1814 4 2 1 1 351 417 401 434 +1815 4 2 1 1 433 447 370 466 +1816 4 2 1 1 272 264 275 409 +1817 4 2 1 1 275 264 246 409 +1818 4 2 1 1 323 308 307 411 +1819 4 2 1 1 357 396 406 467 +1820 4 2 1 1 305 301 398 470 +1821 4 2 1 1 355 398 419 451 +1822 4 2 1 1 76 419 217 454 +1823 4 2 1 1 236 3 222 429 +1824 4 2 1 1 73 188 218 433 +1825 4 2 1 1 261 414 267 437 +1826 4 2 1 1 9 74 397 430 +1827 4 2 1 1 227 293 24 440 +1828 4 2 1 1 186 9 76 454 +1829 4 2 1 1 130 420 132 438 +1830 4 2 1 1 99 98 100 410 +1831 4 2 1 1 349 298 335 388 +1832 4 2 1 1 140 137 144 413 +1833 4 2 1 1 312 314 309 448 +1834 4 2 1 1 124 214 398 451 +1835 4 2 1 1 312 389 314 448 +1836 4 2 1 1 242 283 215 444 +1837 4 2 1 1 305 342 301 470 +1838 4 2 1 1 401 441 356 471 +1839 4 2 1 1 160 204 205 425 +1840 4 2 1 1 76 187 217 419 +1841 4 2 1 1 106 443 408 455 +1842 4 2 1 1 363 437 414 445 +1843 4 2 1 1 125 122 68 421 +1844 4 2 1 1 299 27 208 334 +1845 4 2 1 1 149 150 148 412 +1846 4 2 1 1 220 200 89 429 +1847 4 2 1 1 256 273 428 458 +1848 4 2 1 1 228 276 92 395 +1849 4 2 1 1 6 75 5 433 +1850 4 2 1 1 358 434 379 448 +1851 4 2 1 1 131 402 152 462 +1852 4 2 1 1 178 195 427 450 +1853 4 2 1 1 124 398 80 470 +1854 4 2 1 1 290 235 269 435 +1855 4 2 1 1 186 209 125 454 +1856 4 2 1 1 166 396 82 431 +1857 4 2 1 1 357 376 436 467 +1858 4 2 1 1 192 427 195 450 +1859 4 2 1 1 120 119 118 451 +1860 4 2 1 1 122 164 163 457 +1861 4 2 1 1 271 289 220 429 +1862 4 2 1 1 273 272 274 425 +1863 4 2 1 1 178 427 409 450 +1864 4 2 1 1 351 416 426 442 +1865 4 2 1 1 111 112 110 452 +1866 4 2 1 1 385 425 364 458 +1867 4 2 1 1 378 420 359 432 +1868 4 2 1 1 224 80 214 398 +1869 4 2 1 1 313 318 319 399 +1870 4 2 1 1 91 96 227 440 +1871 4 2 1 1 124 226 451 470 +1872 4 2 1 1 238 286 281 402 +1873 4 2 1 1 197 79 347 459 +1874 4 2 1 1 70 415 102 455 +1875 4 2 1 1 386 359 445 461 +1876 4 2 1 1 318 339 302 392 +1877 4 2 1 1 106 408 116 455 +1878 4 2 1 1 291 268 278 391 +1879 4 2 1 1 178 177 195 450 +1880 4 2 1 1 214 80 124 398 +1881 4 2 1 1 297 303 33 64 +1882 4 2 1 1 206 159 203 418 +1883 4 2 1 1 121 120 217 419 +1884 4 2 1 1 257 255 260 414 +1885 4 2 1 1 265 253 258 424 +1886 4 2 1 1 357 426 376 467 +1887 4 2 1 1 122 68 421 457 +1888 4 2 1 1 311 315 313 404 +1889 4 2 1 1 94 91 23 440 +1890 4 2 1 1 237 55 274 425 +1891 4 2 1 1 273 272 425 458 +1892 4 2 1 1 278 207 48 277 +1893 4 2 1 1 4 90 3 429 +1894 4 2 1 1 134 136 135 432 +1895 4 2 1 1 358 401 417 434 +1896 4 2 1 1 370 376 466 467 +1897 4 2 1 1 120 118 193 403 +1898 4 2 1 1 106 157 443 455 +1899 4 2 1 1 278 277 291 391 +1900 4 2 1 1 97 29 332 77 +1901 4 2 1 1 173 175 171 392 +1902 4 2 1 1 103 104 105 468 +1903 4 2 1 1 266 270 265 424 +1904 4 2 1 1 360 378 446 464 +1905 4 2 1 1 246 275 409 450 +1906 4 2 1 1 106 107 109 408 +1907 4 2 1 1 176 180 69 409 +1908 4 2 1 1 334 393 320 465 +1909 4 2 1 1 7 185 67 423 +1910 4 2 1 1 143 151 154 463 +1911 4 2 1 1 215 81 242 444 +1912 4 2 1 1 178 409 177 450 +1913 4 2 1 1 276 93 52 92 +1914 4 2 1 1 111 113 112 406 +1915 4 2 1 1 296 339 344 392 +1916 4 2 1 1 197 198 79 459 +1917 4 2 1 1 208 95 92 465 +1918 4 2 1 1 129 229 130 438 +1919 4 2 1 1 160 54 274 288 +1920 4 2 1 1 102 410 101 443 +1921 4 2 1 1 284 59 239 66 +1922 4 2 1 1 202 165 166 447 +1923 4 2 1 1 329 324 328 422 +1924 4 2 1 1 363 414 407 461 +1925 4 2 1 1 305 398 345 449 +1926 4 2 1 1 153 444 146 469 +1927 4 2 1 1 370 431 396 447 +1928 4 2 1 1 128 131 152 462 +1929 4 2 1 1 124 226 117 451 +1930 4 2 1 1 218 149 210 412 +1931 4 2 1 1 143 446 151 463 +1932 4 2 1 1 10 76 9 397 +1933 4 2 1 1 159 340 298 21 +1934 4 2 1 1 376 424 370 466 +1935 4 2 1 1 68 7 423 457 +1936 4 2 1 1 305 398 449 470 +1937 4 2 1 1 306 309 322 448 +1938 4 2 1 1 221 12 87 422 +1939 4 2 1 1 276 269 262 395 +1940 4 2 1 1 360 430 387 446 +1941 4 2 1 1 192 195 66 450 +1942 4 2 1 1 259 286 238 444 +1943 4 2 1 1 363 445 414 461 +1944 4 2 1 1 227 24 91 440 +1945 4 2 1 1 35 342 216 301 +1946 4 2 1 1 51 228 290 276 +1947 4 2 1 1 124 119 214 451 +1948 4 2 1 1 160 83 54 288 +1949 4 2 1 1 124 451 398 470 +1950 4 2 1 1 180 204 69 425 +1951 4 2 1 1 268 267 263 437 +1952 4 2 1 1 149 412 148 469 +1953 4 2 1 1 190 189 170 459 +1954 4 2 1 1 152 131 72 402 +1955 4 2 1 1 102 123 99 415 +1956 4 2 1 1 261 255 267 414 +1957 4 2 1 1 94 22 84 335 +1958 4 2 1 1 245 239 66 450 +1959 4 2 1 1 216 124 80 470 +1960 4 2 1 1 383 432 374 469 +1961 4 2 1 1 299 320 334 393 +1962 4 2 1 1 285 260 261 414 +1963 4 2 1 1 340 71 20 159 +1964 4 2 1 1 67 185 154 463 +1965 4 2 1 1 171 19 302 71 +1966 4 2 1 1 133 132 130 420 +1967 4 2 1 1 165 202 181 447 +1968 4 2 1 1 250 248 251 436 +1969 4 2 1 1 222 90 201 431 +1970 4 2 1 1 101 443 410 468 +1971 4 2 1 1 102 443 157 455 +1972 4 2 1 1 221 197 347 422 +1973 4 2 1 1 65 156 225 444 +1974 4 2 1 1 102 70 123 415 +1975 4 2 1 1 330 415 322 448 +1976 4 2 1 1 96 50 228 235 +1977 4 2 1 1 414 437 372 445 +1978 4 2 1 1 245 66 177 450 +1979 4 2 1 1 293 336 24 440 +1980 4 2 1 1 9 74 10 397 +1981 4 2 1 1 237 69 55 425 +1982 4 2 1 1 31 295 123 70 +1983 4 2 1 1 298 84 22 335 +1984 4 2 1 1 302 19 171 339 +1985 4 2 1 1 262 256 273 428 +1986 4 2 1 1 178 195 231 427 +1987 4 2 1 1 191 82 166 396 +1988 4 2 1 1 134 133 174 420 +1989 4 2 1 1 302 340 71 20 +1990 4 2 1 1 55 160 274 425 +1991 4 2 1 1 226 64 158 470 +1992 4 2 1 1 343 340 298 418 +1993 4 2 1 1 344 339 318 392 +1994 4 2 1 1 227 348 95 25 +1995 4 2 1 1 159 71 203 418 +1996 4 2 1 1 56 69 237 176 +1997 4 2 1 1 131 155 72 402 +1998 4 2 1 1 333 322 330 415 +1999 4 2 1 1 277 85 47 126 +2000 4 2 1 1 187 224 121 419 +2001 4 2 1 1 390 423 360 463 +2002 4 2 1 1 8 68 7 423 +2003 4 2 1 1 258 266 265 424 +2004 4 2 1 1 259 238 280 444 +2005 4 2 1 1 233 91 94 440 +2006 4 2 1 1 30 332 77 295 +2007 4 2 1 1 202 166 82 431 +2008 4 2 1 1 305 301 345 398 +2009 4 2 1 1 253 257 258 407 +2010 4 2 1 1 166 192 191 396 +2011 4 2 1 1 207 233 85 391 +2012 4 2 1 1 327 334 320 465 +2013 4 2 1 1 30 77 123 295 +2014 4 2 1 1 157 106 116 455 +2015 4 2 1 1 44 244 152 72 +2016 4 2 1 1 225 146 153 444 +2017 4 2 1 1 25 227 348 293 +2018 4 2 1 1 296 338 17 63 +2019 4 2 1 1 5 73 6 433 +2020 4 2 1 1 103 106 157 443 +2021 4 2 1 1 330 332 295 415 +2022 4 2 1 1 6 7 163 457 +2023 4 2 1 1 297 305 304 470 +2024 4 2 1 1 111 108 115 452 +2025 4 2 1 1 304 305 306 449 +2026 4 2 1 1 245 239 58 66 +2027 4 2 1 1 317 316 350 459 +2028 4 2 1 1 239 246 247 450 +2029 4 2 1 1 245 177 57 176 +2030 4 2 1 1 44 244 72 281 +2031 4 2 1 1 84 159 298 21 +2032 4 2 1 1 370 447 396 467 +2033 4 2 1 1 171 18 172 339 +2034 4 2 1 1 157 102 103 443 +2035 4 2 1 1 218 150 149 412 +2036 4 2 1 1 268 263 278 435 +2037 4 2 1 1 260 281 286 402 +2038 4 2 1 1 58 177 245 66 +2039 4 2 1 1 87 198 197 422 +2040 4 2 1 1 312 320 314 389 +2041 4 2 1 1 91 336 23 440 +2042 4 2 1 1 215 153 81 444 +2043 4 2 1 1 33 303 158 64 +2044 4 2 1 1 347 79 300 459 +2045 4 2 1 1 234 86 208 393 +2046 4 2 1 1 113 166 165 447 +2047 4 2 1 1 240 277 47 126 +2048 4 2 1 1 244 260 285 462 +2049 4 2 1 1 384 452 365 453 +2050 4 2 1 1 200 289 39 81 +2051 4 2 1 1 176 237 56 275 +2052 4 2 1 1 217 120 209 454 +2053 4 2 1 1 373 441 410 471 +2054 4 2 1 1 264 248 246 436 +2055 4 2 1 1 333 295 31 70 +2056 4 2 1 1 185 210 154 463 +2057 4 2 1 1 280 156 42 65 +2058 4 2 1 1 375 449 398 470 +2059 4 2 1 1 3 236 271 429 +2060 4 2 1 1 115 192 211 427 +2061 4 2 1 1 69 160 55 425 +2062 4 2 1 1 176 177 178 409 +2063 4 2 1 1 287 270 236 431 +2064 4 2 1 1 134 132 133 420 +2065 4 2 1 1 236 279 287 431 +2066 4 2 1 1 266 289 271 429 +2067 4 2 1 1 70 157 158 455 +2068 4 2 1 1 347 329 221 422 +2069 4 2 1 1 158 157 116 455 +2070 4 2 1 1 257 253 255 407 +2071 4 2 1 1 194 154 210 463 +2072 4 2 1 1 307 308 306 449 +2073 4 2 1 1 4 188 5 433 +2074 4 2 1 1 57 245 176 275 +2075 4 2 1 1 307 305 345 449 +2076 4 2 1 1 243 279 82 431 +2077 4 2 1 1 101 410 100 468 +2078 4 2 1 1 101 103 443 468 +2079 4 2 1 1 358 434 448 471 +2080 4 2 1 1 24 336 91 440 +2081 4 2 1 1 108 110 107 452 +2082 4 2 1 1 347 350 422 459 +2083 4 2 1 1 101 100 230 468 +2084 4 2 1 1 17 172 296 63 +2085 4 2 1 1 208 393 334 465 +2086 4 2 1 1 201 82 279 431 +2087 4 2 1 1 262 254 256 428 +2088 4 2 1 1 389 448 434 471 +2089 4 2 1 1 259 242 292 444 +2090 4 2 1 1 103 102 101 443 +2091 4 2 1 1 67 167 8 423 +2092 4 2 1 1 70 102 157 455 +2093 4 2 1 1 300 189 341 459 +2094 4 2 1 1 165 164 113 447 +2095 4 2 1 1 36 337 80 199 +2096 4 2 1 1 130 132 131 438 +2097 4 2 1 1 147 146 138 469 +2098 4 2 1 1 325 326 321 405 +2099 4 2 1 1 220 3 271 429 +2100 4 2 1 1 35 216 80 301 +2101 4 2 1 1 113 111 211 406 +2102 4 2 1 1 9 167 74 430 +2103 4 2 1 1 122 114 112 421 +2104 4 2 1 1 36 80 337 301 +2105 4 2 1 1 238 156 42 280 +2106 4 2 1 1 408 443 358 455 +2107 4 2 1 1 167 151 168 430 +2108 4 2 1 1 143 154 194 463 +2109 4 2 1 1 398 451 375 470 +2110 4 2 1 1 79 347 14 197 +2111 4 2 1 1 102 99 101 410 +2112 4 2 1 1 358 401 434 471 +2113 4 2 1 1 343 302 340 418 +2114 4 2 1 1 59 284 191 66 +2115 4 2 1 1 176 178 180 409 +2116 4 2 1 1 297 34 342 470 +2117 4 2 1 1 362 406 447 467 +2118 4 2 1 1 145 135 138 432 +2119 4 2 1 1 347 350 324 422 +2120 4 2 1 1 246 245 275 450 +2121 4 2 1 1 268 291 261 437 +2122 4 2 1 1 271 3 2 236 +2123 4 2 1 1 294 12 1 329 +2124 4 2 1 1 148 153 146 469 +2125 4 2 1 1 406 396 447 467 +2126 4 2 1 1 106 103 105 443 +2127 4 2 1 1 268 261 267 437 +2128 4 2 1 1 51 228 276 92 +2129 4 2 1 1 206 129 127 439 +2130 4 2 1 1 296 172 18 339 +2131 4 2 1 1 5 188 73 433 +2132 4 2 1 1 116 106 109 408 +2133 4 2 1 1 242 39 289 81 +2134 4 2 1 1 251 252 250 456 +2135 4 2 1 1 330 295 333 415 +2136 4 2 1 1 370 466 447 467 +2137 4 2 1 1 260 255 261 414 +2138 4 2 1 1 170 79 198 459 +2139 4 2 1 1 164 165 75 447 +2140 4 2 1 1 362 447 466 467 +2141 4 2 1 1 38 220 289 200 +2142 4 2 1 1 271 270 266 429 +2143 4 2 1 1 189 15 300 341 +2144 4 2 1 1 216 342 34 470 +2145 4 2 1 1 136 138 135 432 +2146 4 2 1 1 279 201 61 82 +2147 4 2 1 1 232 144 174 413 +2148 4 2 1 1 125 114 122 421 +2149 4 2 1 1 202 201 90 431 +2150 4 2 1 1 279 61 243 82 +2151 4 2 1 1 4 3 89 429 +2152 4 2 1 1 259 283 242 444 +2153 4 2 1 1 144 137 174 413 +2154 4 2 1 1 165 181 75 447 +2155 4 2 1 1 303 158 70 32 +2156 4 2 1 1 303 70 333 32 +2157 4 2 1 1 221 87 197 422 +2158 4 2 1 1 197 347 13 221 +2159 4 2 1 1 101 99 100 410 +2160 4 2 1 1 1 12 294 219 +2161 4 2 1 1 220 3 2 271 +2162 4 2 1 1 329 12 1 221 +2163 4 2 1 1 222 2 3 236 +2164 4 2 1 1 219 337 37 199 +2165 4 2 1 1 187 121 217 419 +2166 4 2 1 1 195 177 66 450 +2167 4 2 1 1 130 128 129 438 +2168 4 2 1 1 143 141 151 446 +2169 4 2 1 1 280 65 283 444 +2170 4 2 1 1 143 139 141 446 +2171 4 2 1 1 26 348 95 465 +2172 4 2 1 1 14 300 347 79 +2173 4 2 1 1 209 76 217 454 +2174 4 2 1 1 235 278 263 435 +2175 4 2 1 1 283 40 242 215 +2176 4 2 1 1 149 148 147 469 +2177 4 2 1 1 122 163 68 457 +2178 4 2 1 1 79 170 189 459 +2179 4 2 1 1 271 236 270 429 +2180 4 2 1 1 252 251 254 456 +2181 4 2 1 1 160 69 204 425 +2182 4 2 1 1 327 293 348 465 +2183 4 2 1 1 297 64 34 470 +2184 4 2 1 1 8 7 67 423 +2185 4 2 1 1 74 167 168 430 +2186 4 2 1 1 43 156 238 72 +2187 4 2 1 1 201 62 222 279 +2188 4 2 1 1 195 192 115 427 +2189 4 2 1 1 282 78 45 462 +2190 4 2 1 1 72 238 43 281 +2191 4 2 1 1 341 189 16 338 +2192 4 2 1 1 269 235 263 435 +2193 4 2 1 1 76 209 186 454 +2194 4 2 1 1 26 334 348 465 +2195 4 2 1 1 300 341 317 459 +2196 4 2 1 1 128 130 131 438 +2197 4 2 1 1 119 117 118 451 +2198 4 2 1 1 426 466 376 467 +2199 4 2 1 1 79 189 300 459 +2200 4 2 1 1 337 37 294 219 +2201 4 2 1 1 124 117 119 451 +2202 4 2 1 1 283 65 215 444 +2203 4 2 1 1 220 89 3 429 +2204 4 2 1 1 347 329 13 221 +2205 4 2 1 1 362 466 426 467 +2206 4 2 1 1 38 220 271 289 +2207 4 2 1 1 215 40 242 81 +2208 4 2 1 1 216 34 64 470 +2209 4 2 1 1 208 26 95 465 +2210 4 2 1 1 236 222 62 279 +2211 4 2 1 1 110 108 111 452 +2212 4 2 1 1 52 53 93 241 +2213 4 2 1 1 244 282 45 462 +2214 4 2 1 1 104 230 180 468 +2215 4 2 1 1 162 206 127 439 +2216 4 2 1 1 280 41 283 65 +2217 4 2 1 1 208 334 26 465 +2218 4 2 1 1 86 27 299 28 +2219 4 2 1 1 244 45 152 462 +2220 4 2 1 1 78 128 152 462 +2221 4 2 1 1 68 163 7 457 +2222 4 2 1 1 347 300 350 459 +2223 4 2 1 1 101 104 103 468 +2224 4 2 1 1 251 248 264 436 +2225 4 2 1 1 274 272 237 425 +2226 4 2 1 1 338 189 16 63 +2227 4 2 1 1 305 307 306 449 +2228 4 2 1 1 22 84 298 21 +2229 4 2 1 1 152 45 78 462 +2230 4 2 1 1 45 44 244 152 +2231 4 2 1 1 24 23 91 336 +2232 4 2 1 1 189 300 15 79 +2233 4 2 1 1 215 283 41 65 +2234 4 2 1 1 347 324 329 422 +2235 4 2 1 1 202 82 201 431 +2236 4 2 1 1 314 322 309 448 +2237 4 2 1 1 239 59 58 66 +2238 4 2 1 1 287 279 243 431 +2239 4 2 1 1 305 297 342 470 +2240 4 2 1 1 289 39 38 200 +2241 4 2 1 1 77 29 332 30 +2242 4 2 1 1 317 350 300 459 +2243 4 2 1 1 256 264 272 458 +2244 4 2 1 1 330 322 314 448 +2245 4 2 1 1 71 19 302 20 +2246 4 2 1 1 47 46 240 126 +2247 4 2 1 1 176 56 57 275 +2248 4 2 1 1 35 80 36 301 +2249 4 2 1 1 22 94 23 335 +2250 4 2 1 1 295 123 30 31 +2251 4 2 1 1 85 47 48 277 +2252 4 2 1 1 207 48 49 278 +2253 4 2 1 1 64 226 124 470 +2254 4 2 1 1 274 55 54 160 +2255 4 2 1 1 13 14 347 197 +2256 4 2 1 1 83 53 54 288 +2257 4 2 1 1 18 171 19 339 +2258 4 2 1 1 46 45 282 78 +2259 4 2 1 1 231 195 115 427 +2260 4 2 1 1 96 49 50 235 +2261 4 2 1 1 65 225 153 444 +2262 4 2 1 1 239 245 246 450 +2263 4 2 1 1 297 33 34 64 +2264 4 2 1 1 337 36 37 199 +2265 4 2 1 1 148 146 147 469 +2266 4 2 1 1 61 60 243 82 +2267 4 2 1 1 18 17 172 296 +2268 4 2 1 1 70 31 333 32 +2269 4 2 1 1 159 20 340 21 +2270 4 2 1 1 32 303 158 33 +2271 4 2 1 1 259 280 283 444 +2272 4 2 1 1 244 285 282 462 +2273 4 2 1 1 273 256 272 458 +2274 4 2 1 1 346 28 29 97 +2275 4 2 1 1 201 61 62 279 +2276 4 2 1 1 42 43 156 238 +2277 4 2 1 1 62 2 222 236 +2278 4 2 1 1 294 37 1 219 +2279 4 2 1 1 153 215 65 444 +2280 4 2 1 1 55 56 69 237 +2281 4 2 1 1 348 334 327 465 +2282 4 2 1 1 230 104 101 468 +2283 4 2 1 1 242 40 39 81 +2284 4 2 1 1 338 16 17 63 +2285 4 2 1 1 1 13 329 221 +2286 4 2 1 1 220 2 38 271 +2287 4 2 1 1 64 124 216 470 +2288 4 2 1 1 57 58 177 245 +2289 4 2 1 1 300 14 15 79 +2290 4 2 1 1 26 95 348 25 +2291 4 2 1 1 284 60 59 191 +2292 4 2 1 1 42 41 280 65 +2293 4 2 1 1 72 43 44 281 +2294 4 2 1 1 52 51 276 92 +2295 4 2 1 1 24 227 25 293 +2296 4 2 1 1 16 15 189 341 +2297 4 2 1 1 216 34 342 35 +2298 4 2 1 1 26 208 27 334 +2299 4 2 1 1 283 41 40 215 +2300 4 2 1 1 228 50 51 290 +2301 4 2 1 1 407 286 444 374 +2302 4 2 1 1 407 444 286 257 +2303 4 2 1 1 422 316 411 361 +2304 4 2 1 1 422 411 316 324 +2305 4 2 1 1 391 94 440 233 +2306 4 2 1 1 391 440 94 388 +2307 4 2 1 1 362 453 442 365 +2308 4 2 1 1 442 453 362 426 +2309 4 2 1 1 173 413 196 232 +2310 4 2 1 1 196 413 173 392 +2311 4 2 1 1 448 304 449 375 +2312 4 2 1 1 448 449 304 322 +2313 4 2 1 1 452 184 421 110 +2314 4 2 1 1 452 421 184 365 +2315 4 2 1 1 436 247 249 248 +2316 4 2 1 1 436 249 247 396 +2317 4 2 1 1 393 97 161 86 +2318 4 2 1 1 393 161 97 373 +2319 4 2 1 1 425 468 409 180 +2320 4 2 1 1 409 468 425 364 +2321 4 2 1 1 162 391 126 85 +2322 4 2 1 1 126 391 162 439 +2323 4 2 1 1 414 456 407 255 +2324 4 2 1 1 407 456 414 363 +2325 4 2 1 1 444 257 258 259 +2326 4 2 1 1 444 258 257 407 +2327 4 2 1 1 448 331 389 314 +2328 4 2 1 1 448 389 331 373 +2329 4 2 1 1 439 203 418 206 +2330 4 2 1 1 439 418 203 367 +2331 4 2 1 1 326 388 319 349 +2332 4 2 1 1 319 388 326 405 +2333 4 2 1 1 179 468 105 104 +2334 4 2 1 1 105 468 179 384 +2335 4 2 1 1 423 186 9 8 +2336 4 2 1 1 423 9 186 369 +2337 4 2 1 1 424 250 249 265 +2338 4 2 1 1 424 249 250 376 +2339 4 2 1 1 444 258 292 259 +2340 4 2 1 1 444 292 258 382 +2341 4 2 1 1 469 213 412 148 +2342 4 2 1 1 469 412 213 382 +2343 4 2 1 1 150 412 213 148 +2344 4 2 1 1 150 213 412 382 +2345 4 2 1 1 435 207 440 96 +2346 4 2 1 1 435 440 207 391 +2347 4 2 1 1 463 183 446 383 +2348 4 2 1 1 463 446 183 143 +2349 4 2 1 1 408 118 184 109 +2350 4 2 1 1 408 184 118 403 +2351 4 2 1 1 93 86 393 161 +2352 4 2 1 1 393 86 93 234 +2353 4 2 1 1 94 85 391 162 +2354 4 2 1 1 391 85 94 233 +2355 4 2 1 1 191 243 60 82 +2356 4 2 1 1 191 60 243 284 +2357 4 2 1 1 451 121 120 119 +2358 4 2 1 1 451 120 121 419 +2359 4 2 1 1 448 312 379 309 +2360 4 2 1 1 448 379 312 389 +2361 4 2 1 1 288 93 385 83 +2362 4 2 1 1 288 385 93 241 +2363 4 2 1 1 462 127 126 78 +2364 4 2 1 1 462 126 127 372 +2365 4 2 1 1 428 241 273 262 +2366 4 2 1 1 428 273 241 385 +2367 4 2 1 1 431 166 447 202 +2368 4 2 1 1 431 447 166 396 +2369 4 2 1 1 419 214 224 121 +2370 4 2 1 1 419 224 214 398 +2371 4 2 1 1 299 97 28 346 +2372 4 2 1 1 28 97 299 86 +2373 4 2 1 1 462 281 260 402 +2374 4 2 1 1 462 260 281 244 +2375 4 2 1 1 247 431 249 287 +2376 4 2 1 1 249 431 247 396 +2377 4 2 1 1 237 409 272 275 +2378 4 2 1 1 272 409 237 425 +2379 4 2 1 1 284 66 450 191 +2380 4 2 1 1 450 66 284 239 +2381 4 2 1 1 64 303 470 297 +2382 4 2 1 1 64 470 303 158 +2383 4 2 1 1 301 216 470 342 +2384 4 2 1 1 301 470 216 80 +$EndElements +$Periodic +1 +2 3 2 +Affine 0.5000000000000001 -0.8660254037844386 0 0 0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1 +84 +308 250 +337 279 +342 284 +340 282 +345 287 +341 283 +309 251 +307 249 +344 286 +294 236 +339 281 +349 291 +347 289 +350 292 +348 290 +343 285 +310 252 +293 235 +298 240 +299 241 +301 243 +303 245 +302 244 +304 246 +305 247 +306 248 +325 267 +324 266 +333 275 +323 265 +300 242 +317 259 +318 260 +319 261 +320 262 +329 271 +295 237 +326 268 +322 264 +297 239 +328 270 +296 238 +327 269 +321 263 +316 258 +346 288 +314 256 +315 257 +311 253 +313 255 +312 254 +330 272 +331 273 +332 274 +338 280 +334 276 +335 277 +336 278 +13 38 +15 40 +36 61 +37 62 +17 42 +14 39 +18 43 +16 41 +19 44 +23 48 +22 47 +21 46 +20 45 +35 60 +34 59 +33 58 +32 57 +27 52 +26 51 +25 50 +24 49 +31 56 +30 55 +29 54 +28 53 +1 2 +$EndPeriodic diff --git a/examples/ex1.cpp b/examples/ex1.cpp index c5e240c1b6..f23fbb9e0a 100644 --- a/examples/ex1.cpp +++ b/examples/ex1.cpp @@ -9,6 +9,8 @@ // ex1 -m ../data/fichera.mesh // ex1 -m ../data/fichera-mixed.mesh // ex1 -m ../data/toroid-wedge.mesh +// ex1 -m ../data/annulus-pi-3.msh +// ex1 -m ../data/torus-pi-3.msh // ex1 -m ../data/square-disc-p2.vtk -o 2 // ex1 -m ../data/square-disc-p3.mesh -o 3 // ex1 -m ../data/square-disc-nurbs.mesh -o -1 diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp index 83ede5910a..7b7b33606b 100644 --- a/examples/ex1p.cpp +++ b/examples/ex1p.cpp @@ -9,6 +9,8 @@ // mpirun -np 4 ex1p -m ../data/fichera.mesh // mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh // mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh +// mpirun -np 4 ex1p -m ../data/annulus-pi-3.msh +// mpirun -np 4 ex1p -m ../data/torus-pi-3.msh // mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2 // mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3 // mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1 From 4571095d123f1b540b514bd1534c67a6f169825e Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 27 May 2020 08:50:45 -0700 Subject: [PATCH 407/535] Switch to using TetMemory data structure in ReadGmshMesh --- mesh/mesh_readers.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index 649488a52d..ca96fa806b 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1110,8 +1110,14 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) } case 4: // 4-node tetrahedron { +#ifdef MFEM_USE_MEMALLOC + elements_3D.push_back(TetMemory.Alloc()); + elements_3D.back()->SetVertices(&vert_indices[0]); + elements_3D.back()->SetAttribute(phys_domain); +#else elements_3D.push_back( new Tetrahedron(&vert_indices[0], phys_domain)); +#endif break; } case 5: // 8-node hexahedron @@ -1195,8 +1201,14 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) } case 4: // 4-node tetrahedron { +#ifdef MFEM_USE_MEMALLOC + elements_3D.push_back(TetMemory.Alloc()); + elements_3D.back()->SetVertices(&vert_indices[0]); + elements_3D.back()->SetAttribute(phys_domain); +#else elements_3D.push_back( new Tetrahedron(&vert_indices[0], phys_domain)); +#endif break; } case 5: // 8-node hexahedron From 101e5d948c78c31d7192fe7b10f05cce34ec9749 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 27 May 2020 10:42:23 -0700 Subject: [PATCH 408/535] Switching to TetMemory allocation in Cubit mesh reader --- mesh/mesh_readers.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index ca96fa806b..989a618ba8 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1950,7 +1950,14 @@ void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf) case (ELEMENT_TET4): case (ELEMENT_TET10): { - elements[elcount] = new Tetrahedron(renumberedVertID,ebprop[iblk]); +#ifdef MFEM_USE_MEMALLOC + elements[elcount] = TetMemory.Alloc()); + elements[elcount]->SetVertices(renumberedVertID); + elements[elcount]->SetAttribute(ebprop[iblk]); +#else + elements[elcount] = new Tetrahedron(renumberedVertID, + ebprop[iblk]); +#endif break; } case (ELEMENT_HEX8): From ff6e91113968969b637cd8e89c978022707dc180 Mon Sep 17 00:00:00 2001 From: Tomov Date: Wed, 27 May 2020 12:11:53 -0700 Subject: [PATCH 409/535] Review comments. --- fem/tmop.cpp | 2 +- fem/tmop.hpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index a3a08c13a2..e695454367 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1082,7 +1082,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, break; } default: - MFEM_ABORT("Incompatible target type for analytic adaptation!"); + MFEM_ABORT("Incompatible target type for discrete adaptation!"); } } diff --git a/fem/tmop.hpp b/fem/tmop.hpp index bc3879c2b2..9e9900761b 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -596,7 +596,8 @@ public: supports a set of algorithms chosen by the #TargetType enumeration. New target-matrix construction algorithms can be defined by deriving new - classes and overriding the method ComputeElementTargets(). */ + classes and overriding the methods ComputeElementTargets() and + ContainsVolumeInfo(). */ class TargetConstructor { public: @@ -665,7 +666,7 @@ public: void SetVolumeScale(double vol_scale) { volume_scale = vol_scale; } /// Checks if the target matrices contain non-trivial size specification. - bool ContainsVolumeInfo() const; + virtual bool ContainsVolumeInfo() const; /** @brief Given an element and quadrature rule, computes ref->target transformation Jacobians for each quadrature point in the element. From 41d508dacdb5118e1c8a9b02a0411692dd4b2817 Mon Sep 17 00:00:00 2001 From: Tomov Date: Wed, 27 May 2020 12:29:25 -0700 Subject: [PATCH 410/535] Moved a common function to mesh_optimizer.hpp. --- miniapps/meshing/mesh-optimizer.cpp | 28 +++++++--------------------- miniapps/meshing/mesh-optimizer.hpp | 13 +++++++++++++ miniapps/meshing/pmesh-optimizer.cpp | 28 +++++++--------------------- 3 files changed, 27 insertions(+), 42 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 242d9440dc..bae0ddca45 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -31,11 +31,6 @@ // // Compile with: make mesh-optimizer // -// Adaptive limiting: -// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 -// Adaptive limiting through FD (requires GSLIB): -// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 -// // Sample runs: // Adapted analytic Hessian: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 @@ -46,7 +41,7 @@ // Adapted discrete size: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor - +// // Adapted size+aspect ratio to discrete material indicator // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Adapted discrete size+orientation (requires GSLIB) @@ -55,7 +50,12 @@ // * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 // Adapted discrete aspect ratio (3D) // mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 - +// +// Adaptive limiting: +// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 +// Adaptive limiting through FD (requires GSLIB): +// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 +// // Blade shape: // mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: @@ -87,8 +87,6 @@ using namespace mfem; using namespace std; -double adapt_lim_fun(const Vector &x); - int main(int argc, char *argv[]) { // 0. Set the method's default parameters. @@ -848,15 +846,3 @@ int main(int argc, char *argv[]) return 0; } - -double adapt_lim_fun(const Vector &x) -{ - const double xc = x(0) - 0.1, yc = x(1) - 0.2; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.45; double r2 = 0.55; double sf=30.0; - double val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); - - val = std::max(0.,val); - val = std::min(1.,val); - return val; -} diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index b907897d4f..f710f0a2f6 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -180,6 +180,19 @@ double weight_fun(const Vector &x) return l2; } +// Used for the adaptive limiting examples. +double adapt_lim_fun(const Vector &x) +{ + const double xc = x(0) - 0.1, yc = x(1) - 0.2; + const double r = sqrt(xc*xc + yc*yc); + double r1 = 0.45; double r2 = 0.55; double sf=30.0; + double val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); + + val = std::max(0.,val); + val = std::min(1.,val); + return val; +} + void DiffuseField(GridFunction &field, int smooth_steps) { //Setup the Laplacian operator diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 8867043d94..93678c5668 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -31,11 +31,6 @@ // // Compile with: make pmesh-optimizer // -// Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 -// Adaptive limiting through FD (requires GSLIB): -// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 -// // Sample runs: // Adapted analytic Hessian: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 @@ -46,7 +41,7 @@ // Adapted discrete size: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor - +// // Adapted size+aspect ratio to discrete material indicator // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Adapted discrete size+orientation (requires GSLIB) @@ -55,7 +50,12 @@ // * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 // Adapted discrete aspect ratio (3D) // mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 - +// +// Adaptive limiting: +// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 +// Adaptive limiting through FD (requires GSLIB): +// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 +// // Blade shape: // mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: @@ -86,8 +86,6 @@ using namespace mfem; using namespace std; -double adapt_lim_fun(const Vector &x); - int main (int argc, char *argv[]) { // 0. Initialize MPI. @@ -910,15 +908,3 @@ int main (int argc, char *argv[]) MPI_Finalize(); return 0; } - -double adapt_lim_fun(const Vector &x) -{ - const double xc = x(0) - 0.1, yc = x(1) - 0.2; - const double r = sqrt(xc*xc + yc*yc); - double r1 = 0.45; double r2 = 0.55; double sf=30.0; - double val = 0.5*(1+std::tanh(sf*(r-r1))) - 0.5*(1+std::tanh(sf*(r-r2))); - - val = std::max(0.,val); - val = std::min(1.,val); - return val; -} From 24e16c5af4e4212df9706365199b0a8080c18114 Mon Sep 17 00:00:00 2001 From: Vladimir Tomov Date: Wed, 27 May 2020 15:04:37 -0700 Subject: [PATCH 411/535] Update CHANGELOG --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e46bff8531..db22e9a3f5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,7 +25,9 @@ Meshing improvements - Added support for r-adaptivity with more than one discrete field. This allows the user to specify different discrete functions for controlling the - size, aspect-ratio, orientation, and skew of elements in the mesh. + size, aspect-ratio, orientation, and skew of elements in the mesh. + +- Added TMOP capability for approximate tangential mesh relaxation. Performance improvements ------------------------ From 15e01b2021cb6cb1118db1a02e96b010ef58e9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Wed, 27 May 2020 16:45:55 -0700 Subject: [PATCH 412/535] Add option to ex28p to use block matrices or not. Some SLEPc options (e.g. shift-and-invert with direct solvers) don't support block matrices. --- examples/petsc/CMakeLists.txt | 2 +- examples/petsc/ex28p.cpp | 40 ++++++++++++++++++++---- examples/petsc/{rc_ex28p => rc_ex28p_jd} | 0 examples/petsc/rc_ex28p_sinvert | 1 + 4 files changed, 36 insertions(+), 7 deletions(-) rename examples/petsc/{rc_ex28p => rc_ex28p_jd} (100%) create mode 100644 examples/petsc/rc_ex28p_sinvert diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 06a517a7c5..21a40cfae4 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -33,7 +33,7 @@ if (MFEM_USE_MPI) rc_ex5p_bddc rc_ex5p_fieldsplit rc_ex9p_expl rc_ex9p_impl rc_ex10p - rc_ex28p + rc_ex28p_jd rc_ex28p_sinvert ) endif() diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index 8689859612..d3ec2b49a9 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -4,7 +4,8 @@ // Compile with: make ex28p // // Sample runs: -// mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p +// mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p_jd --block +// mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p_sinvert --no-block // // Description: This example code solves a simple 2D dielectric waveguide // problem corresponding to the generalized eigenvalue equation @@ -57,6 +58,7 @@ int main(int argc, char *argv[]) bool par_format = false; bool visualization = 1; const char *slepcrc_file = ""; + bool use_block = true; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", @@ -75,6 +77,9 @@ int main(int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts", "SlepcOptions file to use."); + args.AddOption(&use_block, "-block", "--block", "-no-block", + "--no-block", + "Enable or disable the use of block matrices"); args.Parse(); if (!args.Good()) { @@ -253,7 +258,20 @@ int main(int argc, char *argv[]) BlockOperator *tLHSOp = new BlockOperator(block_trueOffsets); tLHSOp->SetBlock(0,0,pAtt); tLHSOp->SetBlock(1,1,pAzz); - LHSOp = new PetscParMatrix(MPI_COMM_WORLD,tLHSOp,Operator::PETSC_MATAIJ); + if (use_block) + { + LHSOp = new PetscParMatrix(MPI_COMM_WORLD,tLHSOp,Operator::PETSC_MATAIJ); + } + else + { + // Converting from a BlockOperator creates a MATNEST which preserves the block structure + PetscParMatrix *LHSBlock = new PetscParMatrix(MPI_COMM_WORLD,tLHSOp, + Operator::PETSC_MATAIJ); + // Converting again to MATAIJ to get monolithic matrix + LHSOp = new PetscParMatrix(MPI_COMM_WORLD,LHSBlock,Operator::PETSC_MATAIJ); + delete LHSBlock; + + } delete tLHSOp; BlockOperator *tRHSOp = new BlockOperator(block_trueOffsets); @@ -261,7 +279,16 @@ int main(int argc, char *argv[]) tRHSOp->SetBlock(1,1,pBzz); tRHSOp->SetBlock(1,0,pBtz); tRHSOp->SetBlock(0,1,pBzt); - RHSOp = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp,Operator::PETSC_MATAIJ); + if (use_block) + { + RHSOp = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp,Operator::PETSC_MATAIJ); + } + else + { + PetscParMatrix *RHSBlock = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp, + Operator::PETSC_MATAIJ); + RHSOp = new PetscParMatrix(MPI_COMM_WORLD,RHSBlock,Operator::PETSC_MATAIJ); + } delete tRHSOp; // 12. Solve the eigenvalue problem with slepc. @@ -273,7 +300,8 @@ int main(int argc, char *argv[]) solver->SetOperators(*LHSOp,*RHSOp); solver->SetNumModes(nev); solver->SetWhichEigenpairs(SlepcEigenSolver::TARGET_MAGNITUDE); - solver->SetTarget(pow(k0,2)); + // The target is set with a small offset to prevent zero pivots in this example + solver->SetTarget(pow(k0,2)-1e-2); solver->Solve(); double re; solver->GetEigenvalue(0,re); @@ -328,7 +356,7 @@ int main(int argc, char *argv[]) socketstream u_sock(vishost, visport); u_sock << "parallel " << num_procs << " " << myid << "\n"; u_sock.precision(8); - u_sock << "solution\n" << *pmesh << *et << "window_title 'Velocity'" + u_sock << "solution\n" << *pmesh << *et << "window_title 'Transverse E field'" << endl; u_sock << "keys Rjl!\n"; // Make sure all ranks have sent their 'et' solution before initiating @@ -337,7 +365,7 @@ int main(int argc, char *argv[]) socketstream p_sock(vishost, visport); p_sock << "parallel " << num_procs << " " << myid << "\n"; p_sock.precision(8); - p_sock << "solution\n" << *pmesh << *ez << "window_title 'Pressure'" + p_sock << "solution\n" << *pmesh << *ez << "window_title 'Longitudinal E field'" << endl; p_sock << "keys Rjl!\n"; } diff --git a/examples/petsc/rc_ex28p b/examples/petsc/rc_ex28p_jd similarity index 100% rename from examples/petsc/rc_ex28p rename to examples/petsc/rc_ex28p_jd diff --git a/examples/petsc/rc_ex28p_sinvert b/examples/petsc/rc_ex28p_sinvert new file mode 100644 index 0000000000..85868a0b9f --- /dev/null +++ b/examples/petsc/rc_ex28p_sinvert @@ -0,0 +1 @@ +-st_type sinvert From abfc34d652c3ae48f9cc6b35f001a89280987332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Wed, 27 May 2020 17:00:35 -0700 Subject: [PATCH 413/535] Fix boundary condition typo in ex28p --- examples/petsc/ex28p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index d3ec2b49a9..7eeaaa15a4 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -233,7 +233,7 @@ int main(int argc, char *argv[]) bzz->AddDomainIntegrator(new DiffusionIntegrator(u_r_func)); bzz->AddDomainIntegrator(new MassIntegrator(e_r_func)); bzz->Assemble(); - btt->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); + bzz->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); bzz->Finalize(); bzz->ParallelAssemble(Bzzh); Bzzh.Get(pBzz); From c0879aaf7605c4fa3679a63f8e209f430698a0c5 Mon Sep 17 00:00:00 2001 From: Socratis Date: Wed, 27 May 2020 18:44:06 -0700 Subject: [PATCH 414/535] fixed valgrind leaks --- fem/lininteg.cpp | 5 ++--- fem/lininteg.hpp | 14 +++----------- tests/convergence/BAE.cpp | 39 +++++++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 48e2c9de3c..98151d1403 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -520,9 +520,8 @@ void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect( const IntegrationRule *ir = IntRule; if (ir == NULL) { - // ir = &IntRules.Get(el.GetGeomType(), - // oa * el.GetOrder() + ob + Tr.OrderW()); - ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob); + int intorder = 2 * el.GetOrder(); + ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index f1778f1c7e..a253b54b26 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -119,7 +119,7 @@ public: using LinearFormIntegrator::AssembleRHSElementVect; }; - +/// Class for domain integration L(v) := (f, grad v) class DomainLFGradIntegrator : public DeltaLFIntegrator { private: @@ -312,18 +312,10 @@ class VectorFEDomainLFDivIntegrator : public DeltaLFIntegrator private: Vector divshape; Coefficient &Q; - int oa, ob; - public: /// Constructs the domain integrator (Q, div v) - VectorFEDomainLFDivIntegrator(Coefficient &QF, int a = 2, int b = 0) - // the old default was a = 1, b = 1 - // for simple elliptic problems a = 2, b = -2 is OK - : DeltaLFIntegrator(QF), Q(QF), oa(a), ob(b) { } - - /// Constructs a domain integrator with a given Coefficient - VectorFEDomainLFDivIntegrator(Coefficient &QF, const IntegrationRule *ir) - : DeltaLFIntegrator(QF, ir), Q(QF), oa(1), ob(1) { } + VectorFEDomainLFDivIntegrator(Coefficient &QF) + : DeltaLFIntegrator(QF), Q(QF) { } /** Given a particular Finite Element and a transformation (Tr) computes the element right hand side element vector, elvect. */ diff --git a/tests/convergence/BAE.cpp b/tests/convergence/BAE.cpp index 5df1d6aa30..aee2796b2a 100644 --- a/tests/convergence/BAE.cpp +++ b/tests/convergence/BAE.cpp @@ -47,17 +47,13 @@ int main(int argc, char *argv[]) MPI_Comm_size(MPI_COMM_WORLD, &num_procs); MPI_Comm_rank(MPI_COMM_WORLD, &myid); - // geometry file + // 2. Parse command-line options. const char *mesh_file = "../data/inline-quad.mesh"; - // finite element order of approximation int order = 1; - // static condensation flag bool visualization = 1; - // number of initial ref int sr = 1; int pr = 1; - // optional command line inputs OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); @@ -73,7 +69,6 @@ int main(int argc, char *argv[]) "--no-visualization", "Enable or disable GLVis visualization."); args.Parse(); - // check if the inputs are correct if (!args.Good()) { if (myid == 0) @@ -88,22 +83,28 @@ int main(int argc, char *argv[]) args.PrintOptions(cout); } - // 3. Read the mesh from the given mesh file. + // 3. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. Mesh *mesh = new Mesh(mesh_file, 1, 1); dim = mesh->Dimension(); if (dim == 1 ) prob = 0; + // 4. Set up parameters for exact solution alpha.SetSize(dim); // x,y,z coefficients of the solution for (int i=0; iUniformRefinement(); } + // 6. Define a parallel mesh by a partitioning of the serial mesh. Once the + // parallel mesh is defined, the serial mesh can be deleted. ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; - // 6. Define a finite element space on the mesh. + // 7. Define a parallel finite element space on the parallel mesh. FiniteElementCollection *fec=nullptr; switch (prob) { @@ -115,12 +116,20 @@ int main(int argc, char *argv[]) ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); ParGridFunction u_gf(fespace); - FunctionCoefficient *u, *divU, *curlU2D; - VectorFunctionCoefficient *U, *gradu, *curlU; + + // 9. Set up the parallel linear form b(.) and the parallel + // bilinear form a(.,.) + FunctionCoefficient *u=nullptr; + FunctionCoefficient *divU=nullptr; + FunctionCoefficient *curlU2D=nullptr; + VectorFunctionCoefficient *U=nullptr; + VectorFunctionCoefficient *gradu=nullptr; + VectorFunctionCoefficient *curlU=nullptr; ConstantCoefficient one(1.0); ParLinearForm b(fespace); ParBilinearForm a(fespace); + switch (prob) { case 0: //(grad u_ex, grad v) + (u_ex,v) @@ -277,7 +286,13 @@ int main(int argc, char *argv[]) "window_title 'Numerical Pressure (real part)' " << keys << flush; } - + + delete u; + delete divU; + delete curlU2D; + delete U; + delete gradu; + delete curlU; delete fespace; delete fec; delete pmesh; From e74d501ac37828bab19cb8b179532897f9bdfcb5 Mon Sep 17 00:00:00 2001 From: Socratis Date: Wed, 27 May 2020 19:00:11 -0700 Subject: [PATCH 415/535] fixed comments in example --- tests/convergence/BAE.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/convergence/BAE.cpp b/tests/convergence/BAE.cpp index aee2796b2a..d4e9d932ca 100644 --- a/tests/convergence/BAE.cpp +++ b/tests/convergence/BAE.cpp @@ -16,6 +16,10 @@ // (Q,grad v), (Q,curl V), (Q, div v) // by solving the appropriate energy projection problems // +// prob 0: (grad u, grad v) + (u,v) = (grad u_exact, grad v) + (u_exact, v) +// prob 1: (curl u, curl v) + (u,v) = (curl u_exact, curl v) + (u_exact, v) +// prob 2: (div u, div v) + (u,v) = (div u_exact, div v) + (u_exact, v) + #include "mfem.hpp" #include #include @@ -115,10 +119,12 @@ int main(int argc, char *argv[]) } ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); + // 8. Define the solution vector u_gf as a parallel finite element grid function + // corresponding to fespace. ParGridFunction u_gf(fespace); // 9. Set up the parallel linear form b(.) and the parallel - // bilinear form a(.,.) + // bilinear form a(.,.). FunctionCoefficient *u=nullptr; FunctionCoefficient *divU=nullptr; FunctionCoefficient *curlU2D=nullptr; @@ -132,7 +138,8 @@ int main(int argc, char *argv[]) switch (prob) { - case 0: //(grad u_ex, grad v) + (u_ex,v) + case 0: + //(grad u_ex, grad v) + (u_ex,v) u = new FunctionCoefficient(u_exact); gradu = new VectorFunctionCoefficient(dim,gradu_exact); b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); @@ -143,7 +150,8 @@ int main(int argc, char *argv[]) a.AddDomainIntegrator(new MassIntegrator(one)); break; - case 1: //(curl u_ex, curl v + (u_ex,v) + case 1: + //(curl u_ex, curl v) + (u_ex,v) U = new VectorFunctionCoefficient(dim,U_exact); if (dim == 3) { @@ -156,12 +164,14 @@ int main(int argc, char *argv[]) b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); } b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); + // (curl u, curl v) + (u,v) a.AddDomainIntegrator(new CurlCurlIntegrator(one)); a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); break; - case 2: //(div u_ex, div v) + (u_ex,v) + case 2: + //(div u_ex, div v) + (u_ex,v) U = new VectorFunctionCoefficient(dim,U_exact); divU = new FunctionCoefficient(divU_exact); b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); @@ -176,6 +186,8 @@ int main(int argc, char *argv[]) break; } + // 10. Perform successive parallel refinements, compute the L2 error + // and the corresponding rate of convergence double L2err0 = 0.0; for (int l = 0; l <= pr; l++) { @@ -266,6 +278,7 @@ int main(int argc, char *argv[]) u_gf.Update(); } + // 11. Send the solution by socket to a GLVis server. if (visualization) { char vishost[] = "localhost"; @@ -287,6 +300,7 @@ int main(int argc, char *argv[]) << keys << flush; } + // 12. Free the used memory. delete u; delete divU; delete curlU2D; @@ -296,6 +310,7 @@ int main(int argc, char *argv[]) delete fespace; delete fec; delete pmesh; + MPI_Finalize(); return 0; From 32bdcb6ef23b1c5e6c619fde476e4adb4478876f Mon Sep 17 00:00:00 2001 From: Socratis Date: Wed, 27 May 2020 19:01:16 -0700 Subject: [PATCH 416/535] make style --- fem/lininteg.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index a253b54b26..542c3bf3f6 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -119,7 +119,7 @@ public: using LinearFormIntegrator::AssembleRHSElementVect; }; -/// Class for domain integration L(v) := (f, grad v) +/// Class for domain integrator L(v) := (f, grad v) class DomainLFGradIntegrator : public DeltaLFIntegrator { private: From da01fc0ed1940b655dd9622057c6b263e81c7bc3 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Thu, 28 May 2020 11:49:30 -0700 Subject: [PATCH 417/535] add docs --- linalg/densemat.cpp | 44 +++++++++----------------------------------- linalg/densemat.hpp | 27 +++++++++++++++++++++++++-- linalg/kernels.hpp | 16 +++++++++------- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index cfa3e7423c..77a5b04c71 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3502,18 +3502,17 @@ DenseTensor &DenseTensor::operator=(double c) return *this; } -void BatchLUFactor(DenseTensor &Minv, Array &P) +void BatchLUFactor(DenseTensor &Mlu, Array &P, const double TOL) { - const int m = Minv.SizeI(); - const int NE = Minv.SizeK(); + const int m = Mlu.SizeI(); + const int NE = Mlu.SizeK(); P.SetSize(m*NE); - auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE); + auto data_all = mfem::Reshape(Mlu.ReadWrite(), m, m, NE); auto ipiv_all = mfem::Reshape(P.Write(), m, NE); Array pivot_flag(1); pivot_flag[0] = true; bool *d_pivot_flag = pivot_flag.ReadWrite(); - const double TOL = 1.e-9; MFEM_FORALL(e, NE, { @@ -3570,44 +3569,19 @@ void BatchLUFactor(DenseTensor &Minv, Array &P) MFEM_ASSERT(pivot_flag.HostRead()[0], "Batch LU factorization failed \n"); } -void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X) +void BatchLUSolve(const DenseTensor &Mlu, const Array &P, Vector &X) { - const int m = Minv.SizeI(); - const int NE = Minv.SizeK(); + const int m = Mlu.SizeI(); + const int NE = Mlu.SizeK(); - auto data_all = mfem::Reshape(Minv.Read(), m, m, NE); + auto data_all = mfem::Reshape(Mlu.Read(), m, m, NE); auto piv_all = mfem::Reshape(P.Read(), m, NE); auto x_all = mfem::Reshape(X.ReadWrite(), m, NE); MFEM_FORALL(e, NE, { - - // X <- P X - for (int i = 0; i < m; i++) - { - mfem::kernels::internal::Swap(x_all(i,e), x_all(piv_all(i,e),e)); - } - - // X <- L^{-1} X - for (int j = 0; j < m; j++) - { - const double x_j = x_all(j,e); - for (int i = j+1; i < m; i++) - { - x_all(i,e) -= data_all(i,j,e) * x_j; - } - } - - // X <- U^{-1} X - for (int j = m-1; j >= 0; j--) - { - const double x_j = ( x_all(j,e) /= data_all(j,j,e) ); - for (int i = 0; i < j; i++) - { - x_all(i,e) -= data_all(i,j,e) * x_j; - } - } + kernels::LUSolve(&data_all(0, 0,e), m, &piv_all(0, e), &x_all(0,e)); }); } diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 594c99bd25..d42d7f6f7f 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -859,9 +859,32 @@ public: ~DenseTensor() { tdata.Delete(); } }; -void BatchLUFactor(DenseTensor &Minv, Array &P); +/** + * @brief Compute the LU factorization of a batch of matrices + * + * Factorize n matrices of size (m x m) stored in a dense tensor + * overwriting it with the LU factors. The factorization is such + * that L.U = Piv.A, where A is the original matrix and Piv is a + * permutation matrix represented by P. + * + * @param [in, out] Mlu batch of square matrices - dimension m x m x n. + * @param [out] P array storing pivot information - dimension m x n. + * @param [in] TOL optional fuzzy comparison tolerance. Defaults to 0.0. + */ +void BatchLUFactor(DenseTensor &Mlu, Array &P, const double TOL = 0.0); -void BatchLUSolve(const DenseTensor &Minv, const Array &P, Vector &X); +/** + * @brief Solve batch linear systems + * + * Assuming L.U = P.A for n factored matrices (m x m), + * compute x <- A x, for n companion vectors + * + * @param [in] Mlu batch of LU factors for matrix M - dimension m x m x n. + * @param [in] P array storing pivot information - dimension m x n. + * @param [in, out] X vector storing right handside and then solution + * - dimension m x n + */ +void BatchLUSolve(const DenseTensor &Mlu, const Array &P, Vector &X); // Inline methods diff --git a/linalg/kernels.hpp b/linalg/kernels.hpp index 814925aa19..dd39bd82c3 100644 --- a/linalg/kernels.hpp +++ b/linalg/kernels.hpp @@ -1377,15 +1377,17 @@ have_aa: } +/// Assuming L.U = P.A for a factored matrix (m x m), +// compute x <- A x +// +// @param [in] data LU factorization of A +// @param [in] m square matrix height +// @param [in] ipiv array storing pivot information +// @param [in, out] x vector storing right handside and then solution MFEM_HOST_DEVICE -inline void LUSolve(const double *data, const int m, int *ipiv, - const double *b, double *x) +inline void LUSolve(const double *data, const int m, const int *ipiv, + double *x) { - for (int t = 0; t < m; ++t) - { - x[t] = b[t]; - } - // X <- P X for (int i = 0; i < m; i++) { From 71377db2326c3b1f3b0847ff4c14ac026b0f00fc Mon Sep 17 00:00:00 2001 From: Vargas Date: Thu, 28 May 2020 11:50:45 -0700 Subject: [PATCH 418/535] make style --- linalg/densemat.cpp | 2 +- linalg/densemat.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 77a5b04c71..5ebecb56ed 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3581,7 +3581,7 @@ void BatchLUSolve(const DenseTensor &Mlu, const Array &P, Vector &X) MFEM_FORALL(e, NE, { - kernels::LUSolve(&data_all(0, 0,e), m, &piv_all(0, e), &x_all(0,e)); + kernels::LUSolve(&data_all(0, 0,e), m, &piv_all(0, e), &x_all(0,e)); }); } diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index d42d7f6f7f..39d1de8b20 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -864,7 +864,7 @@ public: * * Factorize n matrices of size (m x m) stored in a dense tensor * overwriting it with the LU factors. The factorization is such - * that L.U = Piv.A, where A is the original matrix and Piv is a + * that L.U = Piv.A, where A is the original matrix and Piv is a * permutation matrix represented by P. * * @param [in, out] Mlu batch of square matrices - dimension m x m x n. From 944dd26aa704efbbf9f0532a71e3f052057d4ddf Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 28 May 2020 12:15:48 -0700 Subject: [PATCH 419/535] Fixed the sample runs. --- miniapps/meshing/mesh-optimizer.cpp | 15 ++++++++------- miniapps/meshing/pmesh-optimizer.cpp | 15 ++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index bae0ddca45..68acdac864 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -35,9 +35,9 @@ // Adapted analytic Hessian: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Adapted analytic Hessian with size+orientation: -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Adapted analytic Hessian with shape+size+orientation -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Adapted discrete size: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor @@ -45,21 +45,21 @@ // Adapted size+aspect ratio to discrete material indicator // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Adapted discrete size+orientation (requires GSLIB) -// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 +// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect-ratio+orientation (requires GSLIB) -// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 +// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect ratio (3D) // mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // // Adaptive limiting: // mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 // Adaptive limiting through FD (requires GSLIB): -// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 +// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // // Blade shape: // mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: -// mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Blade limited shape: // mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 5000 // ICF shape and equal size: @@ -180,7 +180,8 @@ int main(int argc, char *argv[]) args.AddOption(&normalization, "-nor", "--normalization", "-no-nor", "--no-normalization", "Make all terms in the optimization functional unitless."); - args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", + args.AddOption(&fdscheme, "-fd", "--fd_approximation", + "-no-fd", "--no-fd-approx", "Enable finite difference based derivative computations."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 93678c5668..efdb2ccd72 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -35,9 +35,9 @@ // Adapted analytic Hessian: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Adapted analytic Hessian with size+orientation: -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Adapted analytic Hessian with Shape+size+orientation -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Adapted discrete size: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor @@ -45,21 +45,21 @@ // Adapted size+aspect ratio to discrete material indicator // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Adapted discrete size+orientation (requires GSLIB) -// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 +// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect-ratio+orientation (requires GSLIB) -// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 -ae 1 +// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect ratio (3D) // mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // // Adaptive limiting: // mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 // Adaptive limiting through FD (requires GSLIB): -// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // // Blade shape: // mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: -// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd 1 +// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Blade limited shape: // mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 5000 // ICF shape and equal size: @@ -187,7 +187,8 @@ int main (int argc, char *argv[]) args.AddOption(&normalization, "-nor", "--normalization", "-no-nor", "--no-normalization", "Make all terms in the optimization functional unitless."); - args.AddOption(&fdscheme, "-fd", "--fd_approximation", "no-fd", "no-fd-app", + args.AddOption(&fdscheme, "-fd", "--fd_approximation", + "-no-fd", "--no-fd-approx", "Enable finite difference based derivative computations."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", From 3c45d382505614a97c0333fe9f065675379edb7d Mon Sep 17 00:00:00 2001 From: Tomov Date: Thu, 28 May 2020 12:18:07 -0700 Subject: [PATCH 420/535] Fixed the makefile. --- miniapps/meshing/makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniapps/meshing/makefile b/miniapps/meshing/makefile index 28be87aa4f..dac14839dd 100644 --- a/miniapps/meshing/makefile +++ b/miniapps/meshing/makefile @@ -18,6 +18,10 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk # MFEM_INSTALL_DIR = ../../mfem # CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk +# Include defaults.mk to get XLINKER +DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk +include $(DEFAULTS_MK) + MFEM_LIB_FILE = mfem_is_not_built -include $(CONFIG_MK) From cadb9778a42ef9a3fb28b9dac353b1f6a30ec6c4 Mon Sep 17 00:00:00 2001 From: psocratis Date: Thu, 28 May 2020 15:13:31 -0700 Subject: [PATCH 421/535] Added the legal statement at the top. Corrected the mesh path --- tests/convergence/BAE.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/convergence/BAE.cpp b/tests/convergence/BAE.cpp index d4e9d932ca..6e87363e7e 100644 --- a/tests/convergence/BAE.cpp +++ b/tests/convergence/BAE.cpp @@ -1,4 +1,14 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. // +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + // Compile with: make BAE // // Sample runs: mpirun -np 4 BAE -m ../../data/inline-segment.mesh -sr 1 -pr 4 -prob 0 -o 1 @@ -52,7 +62,7 @@ int main(int argc, char *argv[]) MPI_Comm_rank(MPI_COMM_WORLD, &myid); // 2. Parse command-line options. - const char *mesh_file = "../data/inline-quad.mesh"; + const char *mesh_file = "../../data/inline-quad.mesh"; int order = 1; bool visualization = 1; int sr = 1; From 1855ec2993892ba4e5835bb3977278a93bfae852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Thu, 28 May 2020 16:04:55 -0700 Subject: [PATCH 422/535] Add conversion from EPS to PetscObject. Another typo in the boundary conditions of ex28p. --- examples/petsc/ex28p.cpp | 2 +- linalg/slepc.hpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index 7eeaaa15a4..80d6f8403e 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -182,7 +182,7 @@ int main(int argc, char *argv[]) if (pmesh->bdr_attributes.Size()) { ess_bdr.SetSize(pmesh->bdr_attributes.Max()); - ess_bdr = 0; + ess_bdr = 1; } // 10. Assemble the finite element matrices for the LHS and RHS diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index 8b118f9cad..6dd9025e21 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -102,6 +102,9 @@ public: /// Conversion function to SLEPc's EPS type. operator EPS() const { return eps; } + + /// Conversion function to PetscObject + operator PetscObject() const {return (PetscObject)eps; } }; } From ad0420e8128fe988bbb16e1b96d4a59b66472472 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Fri, 29 May 2020 09:05:27 -0700 Subject: [PATCH 423/535] minor --- mesh/pmesh.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 2487950a1c..220bc4d554 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -235,8 +235,8 @@ public: int GetNRanks() const { return NRanks; } int GetMyRank() const { return MyRank; } - /** Map a global element number to a local element number. If the - global element is not on this processor, return -1. */ + /** Map a global element number to a local element number. If the global + element is not on this processor, return -1. */ int GetLocalElementNum(long global_element_num) const; /// Map a local element number to a global element number. From 58a459ab661fb3726f48c7278c8b5d89c6253a51 Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 29 May 2020 13:53:42 -0700 Subject: [PATCH 424/535] Fixed an option string. --- miniapps/meshing/mesh-optimizer.cpp | 2 +- miniapps/meshing/pmesh-optimizer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 68acdac864..b3642f1242 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -188,7 +188,7 @@ int main(int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); - args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluator", + args.AddOption(&adapt_eval, "-ae", "--adaptivity-evaluator", "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index efdb2ccd72..c71f8bc8e4 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -195,7 +195,7 @@ int main (int argc, char *argv[]) "Enable or disable GLVis visualization."); args.AddOption(&verbosity_level, "-vl", "--verbosity-level", "Set the verbosity level - 0, 1, or 2."); - args.AddOption(&adapt_eval, "-ae", "--adaptivity evaluator", + args.AddOption(&adapt_eval, "-ae", "--adaptivity-evaluator", "0 - Advection based (DEFAULT), 1 - GSLIB."); args.Parse(); if (!args.Good()) From 9258314ac6c9d3de4e673ed49498d3eeb484bacd Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 29 May 2020 14:18:24 -0700 Subject: [PATCH 425/535] Remove trailing whitespace. --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index db22e9a3f5..81e62341dc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,9 +24,9 @@ Meshing improvements and orientation based metrics. - Added support for r-adaptivity with more than one discrete field. This allows - the user to specify different discrete functions for controlling the + the user to specify different discrete functions for controlling the size, aspect-ratio, orientation, and skew of elements in the mesh. - + - Added TMOP capability for approximate tangential mesh relaxation. Performance improvements From 582d49116f692c0d96f4cbdb5b46e57c10706868 Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 29 May 2020 15:46:24 -0700 Subject: [PATCH 426/535] Valgrind errors. --- fem/tmop.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index 9e268ff6f5..a8957ad99c 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -1209,7 +1209,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, ntspec_dofs = ndofs*ncomp; Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals, - par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs); + par_vals_c1, par_vals_c2, par_vals_c3; Array dofs; DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim); @@ -1250,9 +1250,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, { par_vals.SetDataAndSize(tspec_vals.GetData()+ aspectratioidx*ndofs, ndofs*3); - par_vals_c1.SetData(par_vals.GetData()); - par_vals_c2.SetData(par_vals.GetData()+ndofs); - par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs); + par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs); + par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs); const double rho1 = shape * par_vals_c1; const double rho2 = shape * par_vals_c2; @@ -1285,9 +1285,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, { par_vals.SetDataAndSize(tspec_vals.GetData()+ skewidx*ndofs, ndofs*3); - par_vals_c1.SetData(par_vals.GetData()); - par_vals_c2.SetData(par_vals.GetData()+ndofs); - par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs); + par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs); + par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs); const double phi12 = shape * par_vals_c1; const double phi13 = shape * par_vals_c2; @@ -1325,9 +1325,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe, { par_vals.SetDataAndSize(tspec_vals.GetData()+ orientationidx*ndofs, ndofs*3); - par_vals_c1.SetData(par_vals.GetData()); - par_vals_c2.SetData(par_vals.GetData()+ndofs); - par_vals_c3.SetData(par_vals.GetData()+2*ndofs); + par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs); + par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs); + par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs); const double theta = shape * par_vals_c1; const double psi = shape * par_vals_c2; From 47ae39dbf1099488cf966da9a2dcd512c93d2aee Mon Sep 17 00:00:00 2001 From: Tomov Date: Fri, 29 May 2020 17:12:29 -0700 Subject: [PATCH 427/535] Fixed an uninitialized variable. --- linalg/invariants.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linalg/invariants.hpp b/linalg/invariants.hpp index d491d2ba4b..4280ceda13 100644 --- a/linalg/invariants.hpp +++ b/linalg/invariants.hpp @@ -593,7 +593,8 @@ protected: if (dont(HAVE_I3b_p)) { eval_state |= HAVE_I3b_p; - I3b_p = sign_detJ*scalar_ops::pow(Get_I3b(), -2, 3); + const scalar_t i3b = Get_I3b(); + I3b_p = sign_detJ*scalar_ops::pow(i3b, -2, 3); } return I3b_p; } From bd14c65b69b171d5af2a4268cf5e17395fe0fea8 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 29 May 2020 18:41:28 -0700 Subject: [PATCH 428/535] In the top makefile, enforce building miniapps/meshing after miniapps/common -- without this the build may fail. --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 8a08847656..8cabd8b255 100644 --- a/makefile +++ b/makefile @@ -120,7 +120,7 @@ EXAMPLE_TEST_DIRS := examples MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS)) MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS)) -MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics tools toys) +MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools toys) EM_DIRS = $(EXAMPLE_DIRS) $(MINIAPP_DIRS) From 774cc3bd682739148842a43af65a5f63b2462e80 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 1 Jun 2020 09:28:46 -0700 Subject: [PATCH 429/535] Typo... oops --- mesh/mesh_readers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index 989a618ba8..5d3b472e2e 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1951,7 +1951,7 @@ void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf) case (ELEMENT_TET10): { #ifdef MFEM_USE_MEMALLOC - elements[elcount] = TetMemory.Alloc()); + elements[elcount] = TetMemory.Alloc(); elements[elcount]->SetVertices(renumberedVertID); elements[elcount]->SetAttribute(ebprop[iblk]); #else From c7fe398bd763a5e5b3458d6e39cd61f781382f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Mon, 1 Jun 2020 10:00:27 -0700 Subject: [PATCH 430/535] Build SLEPc examples only when MFEM_USE_SLEPC is defined. Make SLEPc detection more robust Fix typos in ex28p.cpp --- config/defaults.mk | 7 +++---- examples/petsc/CMakeLists.txt | 11 +++++++++-- examples/petsc/ex28p.cpp | 14 +++++++------- examples/petsc/makefile | 5 ++++- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/config/defaults.mk b/config/defaults.mk index 973759b666..323c9b07c8 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -277,8 +277,7 @@ ifeq ($(PETSC_FOUND),YES) -L$(abspath $(PETSC_DIR))/lib -lpetsc $(PETSC_LIB) endif -SLEPC_ARCH := arch-linux2-c-debug -SLEPC_DIR := $(MFEM_DIR)/../slepc/$(SLEPC_ARCH) +SLEPC_DIR := $(MFEM_DIR)/../slepc SLEPC_VARS := $(SLEPC_DIR)/lib/slepc/conf/slepc_variables SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,) SLEPC_INC_VAR = SLEPC_INCLUDE @@ -286,8 +285,8 @@ SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB ifeq ($(SLEPC_FOUND),YES) SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS)) SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS)) - SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/lib\ - -L$(abspath $(SLEPC_DIR))/lib -lslepc $(SLEPC_LIB) + SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\ + -L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB) endif # MPFR library configuration diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 21a40cfae4..d513c2e107 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -22,8 +22,6 @@ if (MFEM_USE_MPI) ex6p.cpp ex9p.cpp ex10p.cpp - ex11p.cpp - ex28p.cpp ) list(APPEND PETSC_RC_FILES rc_ex1p @@ -33,6 +31,15 @@ if (MFEM_USE_MPI) rc_ex5p_bddc rc_ex5p_fieldsplit rc_ex9p_expl rc_ex9p_impl rc_ex10p + ) +endif() + +if (MFEM_USE_SLEPC) + list(APPEND PETSC_EXAMPLES_SRCS + ex11p.cpp + ex28p.cpp + ) + list(APPEND PETSC_RC_FILES rc_ex28p_jd rc_ex28p_sinvert ) endif() diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index 80d6f8403e..ed22b2d36b 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -291,7 +291,7 @@ int main(int argc, char *argv[]) } delete tRHSOp; - // 12. Solve the eigenvalue problem with slepc. + // 11. Solve the eigenvalue problem with slepc. std::cout << "Solving...\n"; trueX = 0.0; @@ -309,7 +309,7 @@ int main(int argc, char *argv[]) solver->GetEigenvector(0,trueX); std::cout << "Effective index: " << sqrt(re)/k0 << "\n"; - // 13. Extract the parallel grid function corresponding to the finite element + // 12. Extract the parallel grid function corresponding to the finite element // approximation X. This is the local solution on each processor. ParGridFunction *et(new ParGridFunction); ParGridFunction *ez(new ParGridFunction); @@ -318,7 +318,7 @@ int main(int argc, char *argv[]) et->Distribute(&(trueX.GetBlock(0))); ez->Distribute(&(trueX.GetBlock(1))); - // 14. Save the refined mesh and the solution in parallel. This output can be + // 13. Save the refined mesh and the solution in parallel. This output can be // viewed later using GLVis: "glvis -np -m mesh -g sol_*". { ostringstream mesh_name, u_name, p_name; @@ -339,8 +339,8 @@ int main(int argc, char *argv[]) ez->Save(ez_ofs); } - // 15. Save data in the VisIt format - VisItDataCollection visit_dc("Example5-Parallel", pmesh); + // 14. Save data in the VisIt format + VisItDataCollection visit_dc("Example28-Parallel", pmesh); visit_dc.RegisterField("Exy", et); visit_dc.RegisterField("Ez", ez); visit_dc.SetFormat(!par_format ? @@ -348,7 +348,7 @@ int main(int argc, char *argv[]) DataCollection::PARALLEL_FORMAT); visit_dc.Save(); - // 16. Send the solution by socket to a GLVis server. + // 15. Send the solution by socket to a GLVis server. if (visualization) { char vishost[] = "localhost"; @@ -370,7 +370,7 @@ int main(int argc, char *argv[]) p_sock << "keys Rjl!\n"; } - // 17. Free the used memory. + // 16. Free the used memory. delete et; delete ez; delete N_space; diff --git a/examples/petsc/makefile b/examples/petsc/makefile index 65c30c624a..5f6a4d83c1 100644 --- a/examples/petsc/makefile +++ b/examples/petsc/makefile @@ -22,7 +22,10 @@ MFEM_LIB_FILE = mfem_is_not_built -include $(CONFIG_MK) SEQ_EXAMPLES = -PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p ex11p ex28p +PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p +ifeq ($(MFEM_USE_SLEPC),YES) + PAR_EXAMPLES += ex11p ex28p +endif ifeq ($(MFEM_USE_MPI),NO) EXAMPLES = $(SEQ_EXAMPLES) else From d27f3d683e041b3af4c488f1ad3a818185a8b09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Mon, 1 Jun 2020 10:35:10 -0700 Subject: [PATCH 431/535] Add second attribute to ex28p mesh to define a dielectric waveguide core --- .gitignore | 2 ++ examples/petsc/ex28p.cpp | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e78cf90054..4d755a13ad 100644 --- a/.gitignore +++ b/.gitignore @@ -136,6 +136,8 @@ examples/petsc/Example9* examples/petsc/deformed.* examples/petsc/velocity.* examples/petsc/elastic_energy.* +examples/petsc/mode_* +examples/petsc/Example28* examples/pumi/ex1 examples/pumi/ex[126]p diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index ed22b2d36b..3f00431925 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -115,6 +115,9 @@ int main(int argc, char *argv[]) // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine // this mesh further in parallel to increase the resolution. Once the // parallel mesh is defined, the serial mesh can be deleted. + // + // We also define a second attribute region in the middle of the mesh to + // represent the core of the dielectric waveguide. ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; for (int l = 0; l < par_ref_levels; l++) @@ -123,6 +126,16 @@ int main(int argc, char *argv[]) } pmesh->ReorientTetMesh(); + Vector cent(dim); + for (int i=0; iGetNE(); i++) + { + pmesh->GetElementCenter(i, cent); + if (fabs(cent[0]-0.5)<0.25 && fabs(cent[1]-0.5)<0.125) + { + pmesh->GetElement(i)->SetAttribute(2); + } + } + // 6. Define a parallel finite element space on the parallel mesh. Here we // use the Nedelec finite elements of the specified order. std::cout << "dim: " << dim << "\n"; @@ -169,7 +182,7 @@ int main(int argc, char *argv[]) // coefficient. The dielectric contsant is the square of the refractive // index. e_r(0) = -pow(k0*1.0,2); - // This is an example to use different refractive indices in mesh domains + // This is the refractive index used in the waveguide core e_r(1) = -pow(k0*2.0,2); PWConstCoefficient e_r_func(e_r); @@ -301,7 +314,7 @@ int main(int argc, char *argv[]) solver->SetNumModes(nev); solver->SetWhichEigenpairs(SlepcEigenSolver::TARGET_MAGNITUDE); // The target is set with a small offset to prevent zero pivots in this example - solver->SetTarget(pow(k0,2)-1e-2); + solver->SetTarget(pow(k0*2.0,2)-1e-2); solver->Solve(); double re; solver->GetEigenvalue(0,re); From 2ece39550c855a746e244addcf7e9fca1ef47953 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Tue, 2 Jun 2020 15:19:22 +0200 Subject: [PATCH 432/535] Avoid bdrElemdof table usage --- fem/fespace.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 9a98bc3dec..18c8ab0584 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1533,9 +1533,9 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() // MFEM_VERIFY(bdrElem_dof, "NURBSExt not defined."); // Find bdr to face mapping - face_to_be.SetSize(mesh->GetNumFaces()); + face_to_be.SetSize(GetNF()); face_to_be = -1; - for (int b = 0; b < bdrElem_dof->Size(); b++) + for (int b = 0; b < GetNBE(); b++) { int f = mesh->GetBdrElementEdgeIndex(b); face_to_be[f] = b; @@ -1545,7 +1545,7 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() // Sort will destroy orientation info in ordering of dofs Array face_dof_list; Array row; - for (int f = 0; f < mesh->GetNumFaces(); f++) + for (int f = 0; f < GetNF(); f++) { int b = face_to_be[f]; if (b == -1) { continue;} @@ -1557,7 +1557,7 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() face_dof_list.Append(conn); } } - face_dof = new Table(mesh->GetNumFaces(), face_dof_list); + face_dof = new Table(GetNF(), face_dof_list); } From cd81e6c51ad1e28eb0172fcd36292a27f586c17c Mon Sep 17 00:00:00 2001 From: jeremylt Date: Wed, 22 Apr 2020 12:00:03 -0600 Subject: [PATCH 433/535] libCEED - update restrictions for offsets change in API adjust size of L-vector for identity restriction update tensor offset array creation update nontensor offset array creation style Co-authored-by: Natalie Beams Update restriction API again (#1) * libCEED - update restrictions for offsets change in API * Install - update libCEED requirement to v0.7 * Install - update requirement to OCCA v1.0.10, required for libCEED compatibility * adjust size of L-vector for identity restriction * update tensor offset array creation * update nontensor offset array creation Co-authored-by: jeremylt Co-authored-by: Jeremy L Thompson --- fem/libceed/ceed.cpp | 65 +++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/fem/libceed/ceed.cpp b/fem/libceed/ceed.cpp index 01f0b58a8b..d91087bcfa 100644 --- a/fem/libceed/ceed.cpp +++ b/fem/libceed/ceed.cpp @@ -97,6 +97,12 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes, Vector qweight(Q); Vector shape_i(P); DenseMatrix grad_i(P, dim); + + CeedInt compstride = fes.GetNDofs(); + if (fes.GetOrdering()==Ordering::byVDIM) + { + compstride = 1; + } const Table &el_dof = fes.GetElementToDofTable(); Array tp_el_dof(el_dof.Size_of_connections()); const TensorBasisElement * tfe = @@ -128,7 +134,15 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes, const int el_offset = fe->GetDof() * i; for (int j = 0; j < fe->GetDof(); j++) { - tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset]; + if (compstride == 1) + { + tp_el_dof[j + el_offset] = fes.GetVDim()* + el_dof.GetJ()[dof_map[j] + el_offset]; + } + else + { + tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset]; + } } } } @@ -157,20 +171,23 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes, { for (int i = 0; i < P; i++) { - tp_el_dof[i + e*P] = el_dof.GetJ()[i + e*P]; + if (compstride == 1) + { + tp_el_dof[i + e*P] = fes.GetVDim()*el_dof.GetJ()[i + e*P]; + } + else + { + tp_el_dof[i + e*P] = el_dof.GetJ()[i + e*P]; + } } } } CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(), fe->GetDof(), ir.GetNPoints(), shape.GetData(), grad.GetData(), qref.GetData(), qweight.GetData(), basis); - CeedInterlaceMode imode = CEED_NONINTERLACED; - if (fes.GetOrdering()==Ordering::byVDIM) - { - imode = CEED_INTERLACED; - } - CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(), - fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES, + CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(), + compstride, (fes.GetVDim())*(fes.GetNDofs()), + CEED_MEM_HOST, CEED_COPY_VALUES, tp_el_dof.GetData(), restr); } @@ -215,6 +232,11 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes, grad1d.GetData(), qref1d.GetData(), qweight1d.GetData(), basis); + CeedInt compstride = fes.GetNDofs(); + if (fes.GetOrdering()==Ordering::byVDIM) + { + compstride = 1; + } const Table &el_dof = fes.GetElementToDofTable(); Array tp_el_dof(el_dof.Size_of_connections()); for (int i = 0; i < mesh->GetNE(); i++) @@ -222,16 +244,20 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes, const int el_offset = fe->GetDof() * i; for (int j = 0; j < fe->GetDof(); j++) { - tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset]; + if (compstride == 1) + { + tp_el_dof[j + el_offset] = fes.GetVDim()* + el_dof.GetJ()[dof_map[j] + el_offset]; + } + else + { + tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset]; + } } } - CeedInterlaceMode imode = CEED_NONINTERLACED; - if (fes.GetOrdering()==Ordering::byVDIM) - { - imode = CEED_INTERLACED; - } - CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(), - fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES, + CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(), + compstride, (fes.GetVDim())*(fes.GetNDofs()), + CEED_MEM_HOST, CEED_COPY_VALUES, tp_el_dof.GetData(), restr); } @@ -298,8 +324,9 @@ void CeedPAAssemble(const CeedPAOperator& op, CeedBasisGetNumQuadraturePoints(ceedData.basis, &nqpts); const int qdatasize = op.qdatasize; - CeedElemRestrictionCreateStrided(ceed, nelem, nqpts, nelem*nqpts, qdatasize, - CEED_STRIDES_BACKEND, &ceedData.restr_i); + CeedElemRestrictionCreateStrided(ceed, nelem, nqpts, qdatasize, + nelem*nqpts*qdatasize, CEED_STRIDES_BACKEND, + &ceedData.restr_i); CeedVectorCreate(ceed, mesh->GetNodes()->Size(), &ceedData.node_coords); CeedVectorSetArray(ceedData.node_coords, CEED_MEM_HOST, CEED_USE_POINTER, From 614b409d24e2f923b70a17d2bcc04eba00c53d00 Mon Sep 17 00:00:00 2001 From: Jeremy L Thompson Date: Fri, 24 Apr 2020 09:55:05 -0600 Subject: [PATCH 434/535] Install - update libCEED requirement to v0.7 --- INSTALL | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/INSTALL b/INSTALL index ddc911225b..57b12127ac 100644 --- a/INSTALL +++ b/INSTALL @@ -640,12 +640,11 @@ The specific libraries and their options are: Options: OCCA_DIR, OCCA_OPT, OCCA_LIB. Versions: OCCA >= 1.0.9. -- libCEED (optional), used when MFEM_USE_CEED = YES. Requires libCEED v0.6 - or later version, specifically, git-hash 3d05795 or later. +- libCEED (optional), used when MFEM_USE_CEED = YES. URL: https://github.com/CEED/libCEED https://ceed.exascaleproject.org/libceed Options: CEED_DIR, CEED_OPT, CEED_LIB. - Versions: libCEED >= 0.6. + Versions: libCEED >= 0.7. - RAJA (optional), used when MFEM_USE_RAJA = YES. Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported. From 97b785caf0ec8a58a8779105c5fb09a85eac325e Mon Sep 17 00:00:00 2001 From: jeremylt Date: Fri, 24 Apr 2020 12:52:45 -0600 Subject: [PATCH 435/535] Install - update requirement to OCCA v1.0.10, required for libCEED compatibility --- INSTALL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 57b12127ac..82c3346300 100644 --- a/INSTALL +++ b/INSTALL @@ -638,7 +638,7 @@ The specific libraries and their options are: - OCCA (optional), used when MFEM_USE_OCCA = YES. URL: https://libocca.org Options: OCCA_DIR, OCCA_OPT, OCCA_LIB. - Versions: OCCA >= 1.0.9. + Versions: OCCA >= 1.0.10. - libCEED (optional), used when MFEM_USE_CEED = YES. URL: https://github.com/CEED/libCEED From 6f9e3705230d5e0fbe2b1a1bc7dc8b4218c778fc Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 2 Jun 2020 12:06:23 -0700 Subject: [PATCH 436/535] Adding Gmsh geo files, smaller Gmsh meshes, and sample runs in ex11p --- data/annulus-pi-3.geo | 37 + data/annulus-pi-3.msh | 345 ++-- data/torus-pi-3.geo | 25 + data/torus-pi-3.msh | 4014 +++++++++++------------------------------ examples/ex11p.cpp | 2 + 5 files changed, 1254 insertions(+), 3169 deletions(-) create mode 100644 data/annulus-pi-3.geo create mode 100644 data/torus-pi-3.geo diff --git a/data/annulus-pi-3.geo b/data/annulus-pi-3.geo new file mode 100644 index 0000000000..6df1965af0 --- /dev/null +++ b/data/annulus-pi-3.geo @@ -0,0 +1,37 @@ +SetFactory("OpenCASCADE"); + +R1 = 1.0; +R2 = 2.0; + +Point(1) = {0.0, 0, 0, 1.0}; +Point(2) = {R1, 0, 0, 1.0}; +Point(3) = {R2, 0, 0, 1.0}; +Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0}; +Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0}; +Line(1) = {2, 3}; +Line(2) = {4, 5}; +Circle(3) = {2, 1, 4}; +Circle(4) = {3, 1, 5}; +Curve Loop(5) = {1, 4, -2, -3}; +Plane Surface(1) = {5}; + +Transfinite Curve{1} = 7; +Transfinite Curve{2} = 7; +Transfinite Curve{3} = 4; +Transfinite Curve{4} = 10; + +// Set a rotation periodicity constraint: +Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3}; + +// Tag surfaces and volumes with positive integers +Physical Curve(1) = {3}; +Physical Curve(2) = {4}; +Physical Curve(3) = {1}; +Physical Curve(4) = {2}; +Physical Surface(1) = {1}; + +// Generate 2D mesh +Mesh 2; +Mesh.MshFileVersion = 2.2; + +Save "annulus-pi-3.msh"; diff --git a/data/annulus-pi-3.msh b/data/annulus-pi-3.msh index 9366a5567f..8c70fef1f6 100644 --- a/data/annulus-pi-3.msh +++ b/data/annulus-pi-3.msh @@ -1,111 +1,66 @@ $MeshFormat 2.2 0 8 $EndMeshFormat -$Comment -//////////////////////////////////////////////////////////////////////////////// -This is an example of a 3D periodic mesh generated by Gmsh 4.5.6 using -the script: - -//////////////////////////////////////////////////////////////////////////////// -SetFactory("OpenCASCADE"); - -Point(1) = {0.0, 0, 0, 1.0}; -Point(2) = {0.5, 0, 0, 1.0}; -Point(3) = {1.5, 0, 0, 1.0}; -Point(4) = {0.5*Cos(Pi/3), 0.5*Sin(Pi/3), 0, 1.0}; -Point(5) = {1.5*Cos(Pi/3), 1.5*Sin(Pi/3), 0, 1.0}; -Line(1) = {2, 3}; -Line(2) = {4, 5}; -Circle(3) = {2, 1, 4}; -Circle(4) = {3, 1, 5}; -Curve Loop(5) = {1, 4, -2, -3}; -Plane Surface(1) = {5}; - -Transfinite Curve{1} = 7; -Transfinite Curve{2} = 7; -Transfinite Curve{3} = 4; -Transfinite Curve{4} = 10; - -// Set a rotation periodicity constraint: -Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3}; - -// Tag surfaces and volumes with positive integers -Physical Curve(1) = {3}; -Physical Curve(2) = {4}; -Physical Curve(3) = {1}; -Physical Curve(4) = {2}; -Physical Surface(1) = {1}; - -// Generate 2D mesh -Mesh 2; -Mesh.MshFileVersion = 2.2; - -Save "annulus-pi-3.msh"; -//////////////////////////////////////////////////////////////////////////////// -$EndComment $Nodes -58 -1 0.5 0 0 -2 1.5 0 0 -3 0.2500000000000001 0.4330127018922193 0 -4 0.7500000000000002 1.299038105676658 0 -5 0.6666666666666667 0 0 -6 0.8333333333333333 0 0 -7 1 0 0 -8 1.166666666666667 0 0 -9 1.333333333333333 0 0 -10 0.3333333333333334 0.5773502691896257 0 -11 0.4166666666666667 0.7216878364870322 0 -12 0.5000000000000002 0.8660254037844386 0 -13 0.5833333333333335 1.010362971081845 0 -14 0.6666666666666669 1.154700538379251 0 -15 0.4698463103929543 0.1710100716628341 0 -16 0.3830222215594893 0.3213938048432693 0 -17 1.489857536612915 0.1741393711878452 0 -18 1.459567305869736 0.3459238061136595 0 -19 1.409538931178863 0.5130302149885024 0 -20 1.340448960485119 0.6731987703006925 0 -21 1.253231717119405 0.8242634671062079 0 -22 1.149066664678468 0.9641814145298073 0 -23 1.029362456803102 1.091060462359572 0 -24 0.8957378875541815 1.203184789132564 0 -25 1.184124119469803 0.6608103551010475 0 -26 0.5562637595138884 0.3214512390923595 0 -27 0.9308820471914755 0.1491045483084179 0 -28 0.5833333333333335 0.7216878364870323 0 -29 0.9908713588166244 0.9254330604161887 0 -30 1.306574011075295 0.400897874306144 0 -31 0.7382433711320909 1.010999438281314 0 -32 1.251100814888701 0.1356586735371923 0 -33 0.4514589594438195 0.4598872000487043 0 -34 0.6196542456631401 0.4653889072226228 0 -35 0.7185833139470013 0.3138834998381275 0 -36 0.7983695404145397 0.4676807665456855 0 -37 0.880453986992947 0.3096187380232559 0 -38 0.9767392319645739 0.4683038433902925 0 -39 0.8641456853620439 0.6080729367737738 0 -40 1.03732284470747 0.302923118508485 0 -41 0.628820193941076 0.1639511722116236 0 -42 1.098221397346878 0.1439825951016894 0 -43 0.6666666666666669 0.8660254037844387 0 -44 0.7559765450579081 0.7310702822998748 0 -45 1.149172458135534 0.4699647837754962 0 -46 0.8324867696098854 0.8920763595074568 0 -47 1.094750898576393 0.7929083374477056 0 -48 0.9297946367501273 0.7590648072409287 0 -49 0.8833480450355555 1.041864842383078 0 -50 1.347606581519112 0.2450942159796899 0 -51 0.5060636140126749 0.6002905543163177 0 -52 0.7766222941605497 0.1482744252573178 0 -53 1.04053656307791 0.6048278670005733 0 -54 1.277971696068923 0.5435803996943765 0 -55 0.6819060373191272 0.6018743334085058 0 -56 1.203356010626955 0.2762092302560412 0 -57 0.7881283488918066 1.138689644312559 0 -58 1.374784569260408 0.1201569270856769 0 +55 +1 1 0 0 +2 2 0 0 +3 0.5000000000000001 0.8660254037844386 0 +4 1 1.732050807568877 0 +5 1.166666666666667 0 0 +6 1.333333333333333 0 0 +7 1.5 0 0 +8 1.666666666666667 0 0 +9 1.833333333333333 0 0 +10 0.5833333333333335 1.010362971081845 0 +11 0.6666666666666667 1.154700538379251 0 +12 0.7500000000000002 1.299038105676658 0 +13 0.8333333333333335 1.443375672974064 0 +14 0.9166666666666669 1.587713240271471 0 +15 0.9396926207859085 0.3420201433256683 0 +16 0.7660444431189786 0.6427876096865386 0 +17 1.986476715483886 0.2321858282504602 0 +18 1.946089741159648 0.4612317414848793 0 +19 1.879385241571817 0.6840402866513365 0 +20 1.787265280646825 0.8975983604009234 0 +21 1.670975622825874 1.09901795614161 0 +22 1.532088886237958 1.285575219373077 0 +23 1.372483275737469 1.454747283146095 0 +24 1.194317183405575 1.604246385510085 0 +25 1.425989114816062 0.1915326920916892 0 +26 0.8788667344146573 1.13917645290495 0 +27 1.630372059110754 0.7154531062316609 0 +28 1.436395769298814 1.053728612482506 0 +29 1.081023776188756 0.6241293681829633 0 +30 1.168737372335971 1.428012728596308 0 +31 1.821063986059922 0.298149890497067 0 +32 1.234707097211386 0.3469796339295647 0 +33 1.377747393186519 0.6200150626754309 0 +34 1.457047681210906 0.3890895843559762 0 +35 0.917846726184522 0.8957978954532204 0 +36 1.218335619030348 0.9017812086952638 0 +37 1.066623110765233 1.061857005744772 0 +38 1.587029716281926 0.1355955181472859 0 +39 1.744445799211916 0.1441515753740107 0 +40 1.25 0.1443375672974065 0 +41 1.453660070628011 0.8435769396609902 0 +42 1.741367044061892 0.499612708014486 0 +43 1.30550638526547 1.257610469847477 0 +44 1.118213276932792 0.1666674689105279 0 +45 0.9109440214958271 1.306610291787315 0 +46 0.9970618258753989 1.438658589955562 0 +47 0.7499999999999998 1.010362971081845 0 +48 0.7034449005273667 0.8850673702175776 0 +49 1.605449512513618 0.9269067082200894 0 +50 1.561654019115059 0.5298592532912715 0 +51 1.229782222487711 1.096820457143683 0 +52 1.617066998712459 0.3090202662210922 0 +53 1.079645953234324 1.246963713711438 0 +54 1.877063966817811 0.1348974588243076 0 +55 1.055356609656722 1.558136350380461 0 $EndNodes $Elements -114 +108 1 1 2 3 1 1 5 2 1 2 3 1 5 6 3 1 2 3 1 6 7 @@ -130,107 +85,101 @@ $Elements 22 1 2 2 4 22 23 23 1 2 2 4 23 24 24 1 2 2 4 24 4 -25 2 2 1 1 27 42 40 -26 2 2 1 1 27 40 37 -27 2 2 1 1 35 52 37 -28 2 2 1 1 39 55 36 -29 2 2 1 1 37 52 27 -30 2 2 1 1 44 55 39 -31 2 2 1 1 5 41 1 -32 2 2 1 1 3 33 10 -33 2 2 1 1 1 41 15 -34 2 2 1 1 16 33 3 -35 2 2 1 1 48 53 47 -36 2 2 1 1 47 53 25 -37 2 2 1 1 39 48 44 -38 2 2 1 1 44 48 46 -39 2 2 1 1 25 53 45 -40 2 2 1 1 41 52 35 -41 2 2 1 1 36 55 34 -42 2 2 1 1 45 54 25 -43 2 2 1 1 34 51 33 -44 2 2 1 1 40 56 45 -45 2 2 1 1 45 56 30 -46 2 2 1 1 34 55 51 -47 2 2 1 1 26 41 35 -48 2 2 1 1 15 41 26 -49 2 2 1 1 26 33 16 -50 2 2 1 1 21 25 20 -51 2 2 1 1 23 29 22 -52 2 2 1 1 19 30 18 -53 2 2 1 1 26 34 33 -54 2 2 1 1 35 37 36 -55 2 2 1 1 35 36 34 -56 2 2 1 1 39 53 48 -57 2 2 1 1 26 35 34 -58 2 2 1 1 37 40 38 -59 2 2 1 1 15 26 16 -60 2 2 1 1 37 38 36 -61 2 2 1 1 38 39 36 -62 2 2 1 1 46 49 31 -63 2 2 1 1 11 28 12 -64 2 2 1 1 7 27 6 -65 2 2 1 1 12 43 13 -66 2 2 1 1 8 42 7 -67 2 2 1 1 13 31 14 -68 2 2 1 1 9 32 8 -69 2 2 1 1 42 56 40 -70 2 2 1 1 7 42 27 -71 2 2 1 1 28 43 12 -72 2 2 1 1 13 43 31 -73 2 2 1 1 32 42 8 -74 2 2 1 1 28 44 43 -75 2 2 1 1 29 49 46 -76 2 2 1 1 43 46 31 -77 2 2 1 1 40 45 38 -78 2 2 1 1 5 52 41 -79 2 2 1 1 44 46 43 -80 2 2 1 1 32 56 42 -81 2 2 1 1 33 51 10 -82 2 2 1 1 6 52 5 -83 2 2 1 1 10 51 11 -84 2 2 1 1 4 57 24 -85 2 2 1 1 17 58 2 -86 2 2 1 1 21 47 25 -87 2 2 1 1 29 47 22 -88 2 2 1 1 14 57 4 -89 2 2 1 1 2 58 9 -90 2 2 1 1 22 47 21 -91 2 2 1 1 45 53 38 -92 2 2 1 1 18 50 17 -93 2 2 1 1 24 49 23 -94 2 2 1 1 25 54 20 -95 2 2 1 1 19 54 30 -96 2 2 1 1 30 54 45 -97 2 2 1 1 23 49 29 -98 2 2 1 1 30 50 18 -99 2 2 1 1 38 53 39 -100 2 2 1 1 20 54 19 -101 2 2 1 1 11 51 28 -102 2 2 1 1 27 52 6 -103 2 2 1 1 46 48 29 -104 2 2 1 1 28 55 44 -105 2 2 1 1 51 55 28 -106 2 2 1 1 29 48 47 -107 2 2 1 1 31 57 14 -108 2 2 1 1 9 58 32 -109 2 2 1 1 50 56 32 -110 2 2 1 1 50 58 17 -111 2 2 1 1 24 57 49 -112 2 2 1 1 30 56 50 -113 2 2 1 1 49 57 31 -114 2 2 1 1 32 58 50 +25 2 2 1 1 32 40 25 +26 2 2 1 1 25 34 32 +27 2 2 1 1 33 41 36 +28 2 2 1 1 38 52 25 +29 2 2 1 1 33 36 29 +30 2 2 1 1 26 47 35 +31 2 2 1 1 35 37 26 +32 2 2 1 1 25 52 34 +33 2 2 1 1 32 44 40 +34 2 2 1 1 15 32 29 +35 2 2 1 1 15 29 16 +36 2 2 1 1 36 41 28 +37 2 2 1 1 32 33 29 +38 2 2 1 1 50 52 42 +39 2 2 1 1 32 34 33 +40 2 2 1 1 42 52 31 +41 2 2 1 1 43 53 51 +42 2 2 1 1 27 41 33 +43 2 2 1 1 26 53 45 +44 2 2 1 1 18 31 17 +45 2 2 1 1 29 35 16 +46 2 2 1 1 29 36 35 +47 2 2 1 1 24 30 23 +48 2 2 1 1 30 53 43 +49 2 2 1 1 17 54 2 +50 2 2 1 1 4 55 24 +51 2 2 1 1 28 51 36 +52 2 2 1 1 47 48 35 +53 2 2 1 1 36 37 35 +54 2 2 1 1 37 53 26 +55 2 2 1 1 22 28 21 +56 2 2 1 1 20 27 19 +57 2 2 1 1 33 50 27 +58 2 2 1 1 15 44 32 +59 2 2 1 1 18 42 31 +60 2 2 1 1 30 43 23 +61 2 2 1 1 35 48 16 +62 2 2 1 1 31 54 17 +63 2 2 1 1 9 39 8 +64 2 2 1 1 8 38 7 +65 2 2 1 1 7 25 6 +66 2 2 1 1 22 43 28 +67 2 2 1 1 23 43 22 +68 2 2 1 1 39 54 31 +69 2 2 1 1 19 42 18 +70 2 2 1 1 24 55 30 +71 2 2 1 1 27 42 19 +72 2 2 1 1 13 46 14 +73 2 2 1 1 51 53 37 +74 2 2 1 1 39 52 38 +75 2 2 1 1 6 40 5 +76 2 2 1 1 34 52 50 +77 2 2 1 1 12 45 13 +78 2 2 1 1 30 55 46 +79 2 2 1 1 10 47 11 +80 2 2 1 1 8 39 38 +81 2 2 1 1 28 49 21 +82 2 2 1 1 7 38 25 +83 2 2 1 1 41 49 28 +84 2 2 1 1 20 49 27 +85 2 2 1 1 11 26 12 +86 2 2 1 1 27 49 41 +87 2 2 1 1 31 52 39 +88 2 2 1 1 25 40 6 +89 2 2 1 1 2 54 9 +90 2 2 1 1 14 55 4 +91 2 2 1 1 45 53 46 +92 2 2 1 1 45 46 13 +93 2 2 1 1 5 44 1 +94 2 2 1 1 21 49 20 +95 2 2 1 1 46 53 30 +96 2 2 1 1 3 48 10 +97 2 2 1 1 34 50 33 +98 2 2 1 1 36 51 37 +99 2 2 1 1 26 45 12 +100 2 2 1 1 11 47 26 +101 2 2 1 1 27 50 42 +102 2 2 1 1 40 44 5 +103 2 2 1 1 43 51 28 +104 2 2 1 1 10 48 47 +105 2 2 1 1 9 54 39 +106 2 2 1 1 46 55 14 +107 2 2 1 1 1 44 15 +108 2 2 1 1 16 48 3 $EndElements $Periodic 1 1 1 2 Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1 7 -1 3 -2 4 -5 10 -6 11 -7 12 -8 13 9 14 +6 11 +8 13 +5 10 +7 12 +2 4 +1 3 $EndPeriodic diff --git a/data/torus-pi-3.geo b/data/torus-pi-3.geo new file mode 100644 index 0000000000..56901a6f07 --- /dev/null +++ b/data/torus-pi-3.geo @@ -0,0 +1,25 @@ +SetFactory("OpenCASCADE"); + +R = 1.5; +r = 0.5; + +Torus(1) = {0,0,0, R, r, Pi/3}; + +pts() = PointsOf{ Volume{1}; }; + +Characteristic Length{ pts() } = 0.25; + +// Set a rotation periodicity constraint: +Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3}; + +// Tag surfaces and volumes with positive integers +Physical Surface(1) = {1}; +Physical Surface(2) = {2}; +Physical Surface(3) = {3}; +Physical Volume(1) = {1}; + +// Generate 3D mesh +Mesh 3; + +Mesh.MshFileVersion = 2.2; +Save "torus-pi-3.msh"; diff --git a/data/torus-pi-3.msh b/data/torus-pi-3.msh index c0664131d2..2bb34fd344 100644 --- a/data/torus-pi-3.msh +++ b/data/torus-pi-3.msh @@ -1,2984 +1,1056 @@ $MeshFormat 2.2 0 8 $EndMeshFormat -$Comments -//////////////////////////////////////////////////////////////////////////////// -This is an example of a 3D periodic mesh generated by Gmsh 4.5.6 using -the script: - -//////////////////////////////////////////////////////////////////////////////// -SetFactory("OpenCASCADE"); - -Torus(1) = {0,0,0, 1.5, 1, Pi/3}; - -pts() = PointsOf{ Volume{1}; }; - -Characteristic Length{ pts() } = 0.25; - -// Set a rotation periodicity constraint: -Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3}; - -// Tag surfaces and volumes with positive integers -Physical Surface(1) = {1}; -Physical Surface(2) = {2}; -Physical Surface(3) = {3}; -Physical Volume(1) = {1}; - -// Generate 3D mesh -Mesh 3; - -Mesh.MshFileVersion = 2.2; -Save "torus-pi-3.msh"; -//////////////////////////////////////////////////////////////////////////////// -$EndComments $Nodes -471 -1 1.25 2.165063509461096 -2.449293598294706e-16 -2 2.5 0 -2.449293598294706e-16 -3 2.488679806432712 0.237640108260457 -2.449293598294706e-16 -4 2.454821743156767 0.4731281109010261 -2.449293598294706e-16 -5 2.398732434036243 0.704331392103575 -2.449293598294706e-16 -6 2.320919832540181 0.9291561391508196 -2.449293598294706e-16 -7 2.222088621637308 1.145566304318527 -2.449293598294706e-16 -8 2.103133832077952 1.351602043638995 -2.449293598294706e-16 -9 1.965132736856968 1.545397465551513 -2.449293598294706e-16 -10 1.809335095262675 1.72519752870528 -2.449293598294706e-16 -11 1.637151834863212 1.889373935885646 -2.449293598294706e-16 -12 1.450142273927995 2.036439880125839 -2.449293598294706e-16 -13 1.235470908713021 2.139898385164242 0.2393156642875992 -14 1.192728012821542 2.065865517817574 0.4647231720630622 -15 1.124255373808909 1.94726742811937 0.6631226588653242 -16 1.034032368818138 1.790996599463815 0.8229838721713985 -17 0.9273024435212676 1.606134946161604 0.9350162426854153 -18 0.8102683401255636 1.403425932861976 0.9927088740985636 -19 0.6897316597286507 1.194650278238831 0.9927088740631602 -20 0.5726975541129594 0.9919412610940719 0.9350162408909761 -21 0.4659676266344224 0.8070796040131041 0.8229838658936566 -22 0.3757446259142614 0.650808782754462 0.6631226582403703 -23 0.3072719871531447 0.5322106934918979 0.4647231719666005 -24 0.2645290910297036 0.4581778257434591 0.239315662199983 -25 0.2500000000000001 0.4330127018922194 1.224646799147353e-16 -26 0.2645290912869792 0.4581778261890734 -0.2393156642875988 -27 0.3072719871784581 0.5322106935357419 -0.4647231720630619 -28 0.3757446261910917 0.6508087832339461 -0.6631226588653238 -29 0.465967631181862 0.8070796118895007 -0.8229838721713983 -30 0.5726975564787327 0.9919412651917113 -0.9350162426854151 -31 0.6897316598744364 1.19465027849134 -0.9927088740985635 -32 0.8102683402713494 1.403425933114484 -0.9927088740631603 -33 0.9273024458870408 1.606134950259244 -0.9350162408909763 -34 1.034032373365578 1.790996607340212 -0.8229838658936566 -35 1.124255374085739 1.947267428598854 -0.6631226582403708 -36 1.192728012846856 2.065865517861418 -0.464723171966601 -37 1.235470908970297 2.139898385609857 -0.2393156621999836 -38 2.470941817426052 0 0.2393156642875577 -39 2.38545602565321 0 0.4647231720437685 -40 2.248510748171101 0 0.6631226582407952 -41 2.068064746731156 0 0.8229838658936564 -42 1.854604887042536 0 0.9350162426854147 -43 1.620536680255323 0 0.992708874098054 -44 1.379463319744677 0 0.992708874098054 -45 1.145395112957464 0 0.9350162426854149 -46 0.9319352532688444 0 0.8229838658936566 -47 0.7514892518288991 0 0.6631226582407954 -48 0.6145439743467902 0 0.4647231720437687 -49 0.5290581825739481 0 0.2393156642875581 -50 0.5 0 1.224646799147353e-16 -51 0.5290581825739479 0 -0.2393156642875575 -52 0.6145439743467901 0 -0.4647231720437685 -53 0.7514892518288987 0 -0.663122658240795 -54 0.9319352532688441 0 -0.8229838658936564 -55 1.145395112957464 0 -0.9350162426854147 -56 1.379463319744676 0 -0.992708874098054 -57 1.620536680255322 0 -0.9927088740980541 -58 1.854604887042536 0 -0.9350162426854148 -59 2.068064746731156 0 -0.8229838658936566 -60 2.248510748171101 0 -0.6631226582407955 -61 2.38545602565321 0 -0.4647231720437692 -62 2.470941817426052 0 -0.2393156642875587 -63 1.161950520411713 1.595027107313167 0.8808567025634668 -64 1.16111495353952 1.631339134675958 -0.864657150131166 -65 1.993338608714705 0.1898855044486915 0.864657149241256 -66 1.962309259490651 0.2087651244602831 -0.8808566995508391 -67 2.143269427830786 1.235251366396636 0.2276108945998273 -68 2.144774983786486 1.239076746984393 -0.2133854546576661 -69 1.257163299677245 0.2056949521188911 -0.9740994282274332 -70 0.9306978626594941 1.194712146198956 -0.9998957038608219 -71 0.8067186995663457 0.9858878802543444 0.9740994279795938 -72 1.499999999999821 0.2086519190873416 0.9998957038631872 -73 2.340705550917026 0.815046814717805 0.2060155120167518 -74 1.873290363694945 1.623215340227059 0.2052080035217707 -75 2.342390902296706 0.8107093735108847 -0.20520800352177 -76 1.876204012167479 1.619587082207711 -0.206015487245415 -77 0.6956520153984462 0.7887050642846799 -0.8938627795124352 -78 1.030864624066582 0.2080997947850345 0.8938627777919494 -79 1.339111263725038 1.901858404757476 0.5636674802141222 -80 1.340063611529316 1.900556139880006 -0.5644229116404256 -81 2.315961703157284 0.2102510682052372 0.5644229121460563 -82 2.316613325045473 0.2087751701423494 -0.5636674798788656 -83 0.8257233900307956 0.2073786653528784 -0.7611009570103594 -84 0.5924568856662578 0.6114081008615074 0.7611009567525712 -85 0.6552631076664096 0.2199540300745461 0.5880759196713039 -86 0.518117332361219 0.4574974827803283 -0.5880759208938083 -87 1.532242043414882 1.948404256783631 0.2052080035217706 -88 1.534433561498189 1.950620672846501 -0.1898384713660102 -89 2.453488604923804 0.352758405952052 0.2052080035217711 -90 2.453488604923804 0.352758405952052 -0.2052080035217709 -91 0.4337477642844972 0.3581271528103677 0.3479515779329294 -92 0.5270210945461641 0.1965730066058266 -0.3479515789408426 -93 0.6514981143803358 0.2245342592436242 -0.5851914012243407 -94 0.5202014294249768 0.4519467876355929 0.5851914006358678 -95 0.4014403423552208 0.310054077259639 -0.1200778916456693 -96 0.4690743845310645 0.1937014713713605 0.122202935540906 -97 0.5801752991739216 0.6202829134728381 -0.7593569988644425 -98 0.7971906289338729 0.5725550546315054 -0.8550745202842129 -99 0.9299895953318537 0.7538050487583471 -0.953029551478182 -100 1.020807935619515 0.5609391978028184 -0.9421382258712735 -101 1.158775704398517 0.7331406603224976 -0.9916737595531294 -102 1.07079436896178 0.9395834763300965 -0.9971515774414794 -103 1.309688021011989 0.9072674962661023 -0.9956435646545561 -104 1.408580520839082 0.6577928881834649 -0.9985081419734843 -105 1.545871219796618 0.873285367854039 -0.9613055173471736 -106 1.451217818270691 1.10313640870309 -0.9464350828739435 -107 1.679105395582128 1.054804002495066 -0.8756596518832466 -108 1.77189593044693 0.8331112405270859 -0.8889619900552521 -109 1.581016579212857 1.272915440875944 -0.8481473660987684 -110 1.888803398279099 1.005484134934533 -0.7685740150485127 -111 1.983327592458931 0.7978554730297511 -0.7702072828570967 -112 2.077265785740169 0.9459551527661192 -0.6226346041973602 -113 2.164956684129825 0.724958584078208 -0.6218801439863675 -114 1.975636250565757 1.163059112399909 -0.6097900428701994 -115 1.857758850062941 0.6084947204092939 -0.8905556215828939 -116 1.355501724155206 1.313817462506936 -0.9217755874265015 -117 1.493084698535482 1.4798424031496 -0.7983469473822233 -118 1.690391730004402 1.432036463042488 -0.6986792066622279 -119 1.588938705312047 1.621449856179052 -0.6377977102936896 -120 1.763518611044919 1.561866114128629 -0.5174367243381106 -121 1.64228663731985 1.745234789011533 -0.4431544898946779 -122 2.136508707943542 1.092914485111334 -0.4362632868539859 -123 0.8286805041675077 0.9729264863222208 -0.9750478525559744 -124 1.379174264031979 1.683944246340221 -0.7363080526676612 -125 2.026141971161382 1.301985875131233 -0.4180895827224266 -126 0.8272684058174414 0.1923050883282038 0.7593569946991177 -127 0.8944425213507604 0.4041098171401778 0.8550745137555074 -128 1.117809107877708 0.4284921095499341 0.9530295502360074 -129 0.9961915489312382 0.6035760163814639 0.9421382235278785 -130 1.21430626806377 0.6369588939265005 0.9916737588091861 -131 1.349100332961367 0.4575434206294663 0.9971515774564784 -132 1.440560687544275 0.6805893880448953 0.9956435650232734 -133 1.273955587794313 0.8909700911730075 0.99850814240254 -134 1.529222889149096 0.9021211066699351 0.9613055194540464 -135 1.680953039386213 0.7052233381775018 0.9464350842720805 -136 1.753039724372543 0.9267459820847649 0.8756596550280391 -137 1.607443419141945 1.117951315400981 0.8889619950647425 -138 1.892885372103278 0.7327428635840514 0.8481473672235668 -139 1.815176456956073 1.133009716585031 0.7685740218936316 -140 1.682626870419913 1.318684379285022 0.7702072862702635 -141 1.857854037059084 1.325987417659986 0.6226346154414321 -142 1.710310878756236 1.512428237210446 0.6218801213956152 -143 1.995056816005703 1.129421694625275 0.6097900514039523 -144 1.455851259289336 1.304619036328911 0.8905556281968932 -145 1.815550145268847 0.5169902548551503 0.9217755869112219 -146 2.028123447205333 0.5531281399950182 0.7983469471672885 -147 2.085375793954983 0.7479040216119029 0.6986792077701024 -148 2.198686105353924 0.5653364207293526 0.6377977067994971 -149 2.23437500752076 0.7463189448006358 0.5174367272737342 -150 2.33256096421613 0.549644629861044 0.4431544886181681 -151 2.016526565486886 1.303539104797304 0.4334761314315916 -152 1.256919307065314 0.231195140997 0.9750478536177046 -153 2.147925624607719 0.3524278634459152 0.736308050043917 -154 2.139882952433509 1.103620904410053 0.4195932786269019 -155 1.591523049737069 0.4470789416753918 0.98820669030398 -156 1.773347685675709 0.2499958912548627 0.9567587985602205 -157 1.182943234960579 1.154759937221901 -0.9882066897501199 -158 1.103176619915856 1.410766211750977 -0.9567587986441293 -159 0.6776017770360423 0.7764200539868567 0.8829433125538813 -160 1.011200381154429 0.198610327009629 -0.8829433136803488 -161 0.7087970592418741 0.4129187978480285 -0.7334919842231511 -162 0.7119966957841659 0.4073768612880556 0.7334919825932171 -163 2.252206790904938 1.024469582375116 -0.225417828058159 -164 2.232156252238418 0.8801412111855693 -0.4371052509884357 -165 2.306767605586851 0.6518373635269503 -0.4418358896236437 -166 2.219803764229007 0.48638003809805 -0.6350581105711051 -167 2.012443905783075 1.431141498391836 0.2453584903487805 -168 1.879239263428174 1.491302075944445 0.4378112284475578 -169 1.718225273090827 1.671330573001638 0.4420157376406979 -170 1.531119330381165 1.679216534047617 0.6350580359177905 -171 0.9190640841350129 1.184629926085916 0.9999997836100309 -172 1.049798373764997 1.381807097473364 0.9719087402402153 -173 1.153985062431529 1.165116090062648 0.9901697289787016 -174 1.384115559403521 1.077909319314016 0.9671181980368939 -175 1.029024257768673 0.9508543119579772 0.9950950230568771 -176 1.48545165184756 0.2036178817765078 -0.9999997836098622 -177 1.721579236265735 0.2182485114955622 -0.9719087402873856 -178 1.58601266163587 0.4168223353949511 -0.9901697292149241 -179 1.625554649345303 0.6597246097044436 -0.9671181908258678 -180 1.337976111157614 0.4157340126351193 -0.9950950229733188 -181 2.402270425674217 0.5810915549862188 -0.2368252487583065 -182 1.70593749744366 1.786238502273994 0.243128554091969 -183 1.954857324880494 0.9431011777158674 0.7419435166184849 -184 1.794178202127611 1.221405580903979 -0.741943512037614 -185 2.249773424997405 1.029094771269818 0.2266865432150113 -186 2.018654063412176 1.433602746510706 -0.2181276558421402 -187 1.701538918701969 1.797051296027637 -0.2230867820887245 -188 2.406405674227529 0.5743726817581494 0.2265338911405251 -189 1.251235724142822 1.762855981959914 0.7497064068024704 -190 1.381739529336837 1.555447441778505 0.8142361531898541 -191 2.152295929686154 0.2021739354113657 -0.7497064030049929 -192 2.037926742934737 0.4188978626238546 -0.8142361604185483 -193 1.872905315244544 1.365480933874247 -0.5754670716221548 -194 2.119286420053609 0.9404301384966269 0.5744015822664972 -195 1.833535077728957 0.4057869027258597 -0.9258458224179789 -196 1.268189283192839 1.384994523680911 0.9258458227499975 -197 1.377265921278483 2.005430891725938 0.3603419747750946 -198 1.546795264550916 1.839873835551548 0.4281935989751613 -199 1.381891104564456 1.998857975709812 -0.3674781719964972 -200 2.422007337797244 0.1973238139516733 0.3674781720157486 -201 2.425387058454348 0.1900318299839833 -0.3603419746042364 -202 2.367058173220222 0.4190208657847906 -0.4278283619092008 -203 0.8899712834428033 0.7807261905059222 0.9487206789798943 -204 1.121114358662251 0.3803746373713242 -0.9487206789882416 -205 0.914757224585851 0.3892421606728923 -0.8626084842378261 -206 0.7944722043702587 0.5975819158712172 0.8626084813224804 -207 0.5437468686508761 0.1753948845348323 0.3709203029958322 -208 0.4236548317432472 0.3832096360207821 -0.37072088053857 -209 1.901148152895707 1.498470095187491 -0.3902767076285737 -210 2.247889479047726 0.8969112365780697 0.3914053943906234 -211 2.06115073291544 0.6149026421550068 -0.759148174490955 -212 1.563096665160738 1.477557608942776 0.7591481606873587 -213 2.293538770716872 0.3975684508448159 0.5611095359772014 -214 1.491073734293782 1.787478637883094 -0.5611095372128085 -215 2.160934921274194 0.1465662156768363 0.7460413036221629 -216 1.207397490267293 1.798141452453983 -0.7460413050692806 -217 1.77632091546844 1.662027374751479 -0.360854191128632 -218 2.327518353212576 0.7073254288138934 0.3608542136339237 -219 1.38808479900803 2.061575849627878 -0.1706492015269236 -220 2.478948087855883 0.1719191240847288 0.1731106987058312 -221 1.389096580246771 2.060356370273965 0.1732046903180589 -222 2.478869247629586 0.1728147416673262 -0.1732046903187114 -223 2.389519884070642 0.37518921408793 0.3947336057780582 -224 1.520122986826133 1.882489046625287 -0.3928198464625023 -225 1.94882169109996 0.3797502874104242 0.874249810509526 -226 1.303284213694452 1.497853971095424 -0.8742498110826699 -227 0.3626210387554522 0.3551456057285723 0.1227727244605137 -228 0.4888756360882149 0.1364662287623708 -0.1227727255505153 -229 1.086114096153235 0.7757817768037119 0.9862469172774405 -230 1.214903771215531 0.5527115271809405 -0.9862469179371743 -231 1.719469475572177 0.5273210164956065 -0.9544061143209133 -232 1.316408107079081 1.225443763275427 0.9544061152363752 -233 0.5422951238057707 0.3059592744937097 0.4798540144189912 -234 0.536079395155085 0.3166713490100215 -0.4798052395521509 -235 0.7234766020502333 0 0.06319084407049604 -236 2.276408697239476 0 -0.1038332116551961 -237 1.281564074160823 0 -0.7815450354819452 -238 1.687607499234412 0 0.7611535450957393 -239 1.864311932538833 0 -0.6941383931109288 -240 0.9824677737969774 0 0.6079094555764485 -241 0.8538614889377032 0 -0.4560869484954775 -242 2.14197338776787 0 0.4640993597096316 -243 2.145309988793692 0 -0.4501798711749596 -244 1.300634269303989 0 0.7623839983864482 -245 1.700240711187027 0 -0.8019064501110774 -246 1.675590523152915 0 -0.5791715422382202 -247 1.900023573701088 0 -0.454623482418549 -248 1.66468575399941 0 -0.3388653259535993 -249 1.861804827553214 0 -0.2063019587468402 -250 1.653303668642545 0 -0.0965510845269546 -251 1.447433111560146 0 -0.2223570746281137 -252 1.441646586126126 0 0.01885927027041822 -253 1.647765612163517 0 0.1432517193449556 -254 1.235106815066154 0 -0.1058278068838464 -255 1.436693623107965 0 0.2597162564404173 -256 1.248346455709191 0 -0.3418224077231802 -257 1.63881019087097 0 0.376463356021949 -258 1.846857487731521 0 0.2544945090792877 -259 1.861009725360342 0 0.5145051509153519 -260 1.421184826888508 0 0.5375048936337171 -261 1.22556002569893 0 0.376190528980096 -262 0.9970599615356726 0 -0.2524739698086225 -263 0.9785762007483654 0 0.03562131165296409 -264 1.468545234544223 0 -0.4598103596351082 -265 1.855705914185911 0 0.02608781117112623 -266 2.065126085550818 0 0.1510765117070129 -267 1.222783030310453 0 0.1393737718970882 -268 1.019114931115178 0 0.2516830709224802 -269 0.8265890464543634 0 -0.1136715848090973 -270 2.060779434825952 0 -0.06040484733817086 -271 2.279058019184917 0 0.1070695414119101 -272 1.266650491755973 0 -0.5625597545084002 -273 1.066881711342736 0 -0.4758711207039364 -274 1.104906898175 0 -0.6992855791290147 -275 1.484655862114423 0 -0.7386301271672655 -276 0.7254662717714151 0 -0.2893135921118692 -277 0.844397287769171 0 0.486542411644844 -278 0.8234459508503615 0 0.2809629482984198 -279 2.264224982218241 0 -0.3081051521832103 -280 1.904641258028338 0 0.731329411646097 -281 1.502652777570647 0 0.7884339610073496 -282 1.11883427047969 0 0.7409827498784481 -283 2.044839973211761 0 0.6392080892811064 -284 2.045244197987174 0 -0.617009654167778 -285 1.215590375596072 0 0.5760683567251723 -286 1.612856736166523 0 0.5788562441904899 -287 2.058223470199073 0 -0.2757078962364384 -288 0.9394638145164449 0 -0.6206622407006543 -289 2.227302932754278 0 0.2912169793454392 -290 0.6470285364900668 0 -0.1035694867313699 -291 1.018429390804448 0 0.4298927953579101 -292 2.021262260942802 0 0.321017626912755 -293 0.3617383010251167 0.6265491164191468 0.06319084407049604 -294 1.138204348619738 1.971427761205225 -0.1038332116551961 -295 0.6407820370804114 1.109867044800757 -0.7815450354819452 -296 0.8438037496172062 1.461510965954128 0.7611535450957393 -297 0.9321559662694168 1.61454149415709 -0.6941383931109288 -298 0.4912338868984888 0.8508420505077258 0.6079094555764485 -299 0.4269307444688517 0.7394657407332563 -0.4560869484954775 -300 1.070986693883935 1.855003368037192 0.4640993597096316 -301 1.072654994396846 1.857892949287847 -0.4501798711749596 -302 0.6503171346519945 1.126382318249865 0.7623839983864482 -303 0.8501203555935136 1.472451648436486 -0.8019064501110774 -304 0.8377952615764576 1.451103959390882 -0.5791715422382202 -305 0.9500117868505443 1.645468682614437 -0.454623482418549 -306 0.8323428769997053 1.441660152281542 -0.3388653259535993 -307 0.9309024137766072 1.612370277549589 -0.2063019587468402 -308 0.8266518343212725 1.431802977214453 -0.0965510845269546 -309 0.723716555780073 1.253513844889842 -0.2223570746281137 -310 0.720823293063063 1.248502566864335 0.01885927027041822 -311 0.8238828060817588 1.427006879616023 0.1432517193449556 -312 0.617553407533077 1.069633878234578 -0.1058278068838464 -313 0.7183468115539827 1.244213175066604 0.2597162564404173 -314 0.6241732278545958 1.081099743368425 -0.3418224077231802 -315 0.8194050954354855 1.419251257275085 0.376463356021949 -316 0.9234287438657607 1.599425501545004 0.2544945090792877 -317 0.9305048626801711 1.611681698851957 0.5145051509153519 -318 0.7105924134442541 1.230782163558438 0.5375048936337171 -319 0.6127800128494653 1.061366116117983 0.376190528980096 -320 0.4985299807678364 0.8634792557862276 -0.2524739698086225 -321 0.4892881003741828 0.847471849386945 0.03562131165296409 -322 0.7342726172721118 1.271797479721874 -0.4598103596351082 -323 0.9278529570929556 1.607088463638024 0.02608781117112623 -324 1.032563042775409 1.788451652104924 0.1510765117070129 -325 0.6113915151552265 1.058961167565369 0.1393737718970882 -326 0.5095574655575892 0.8825794197217725 0.2516830709224802 -327 0.4132945232271818 0.7158471127194341 -0.1136715848090973 -328 1.030389717412976 1.784687342155812 -0.06040484733817086 -329 1.139529009592459 1.973722141312781 0.1070695414119101 -330 0.6333252458779864 1.096951503576724 -0.5625597545084002 -331 0.5334408556713682 0.923946664855826 -0.4758711207039364 -332 0.5524534490875003 0.9568774426362162 -0.6992855791290147 -333 0.7423279310572114 1.285749692468577 -0.7386301271672655 -334 0.3627331358857076 0.628272220942831 -0.2893135921118692 -335 0.4221986438845857 0.7312695020947813 0.486542411644844 -336 0.4117229754251809 0.7131251120798453 0.2809629482984198 -337 1.13211249110912 1.960876354484365 -0.3081051521832103 -338 0.9523206290141693 1.649467714548493 0.731329411646097 -339 0.7513263887853235 1.301335478443427 0.7884339610073496 -340 0.5594171352398453 0.9689389008600416 0.7409827498784481 -341 1.022419986605881 1.770883363475276 0.6392080892811064 -342 1.022622098993587 1.771233432399622 -0.617009654167778 -343 0.607795187798036 1.052732145862065 0.5760683567251723 -344 0.8064283680832618 1.396774906185065 0.5788562441904899 -345 1.029111735099537 1.782473811857761 -0.2757078962364384 -346 0.4697319072582226 0.8135995293074731 -0.6206622407006543 -347 1.113651466377139 1.928900921688788 0.2912169793454392 -348 0.3235142682450334 0.5603431495738644 -0.1035694867313699 -349 0.5092146954022242 0.881985724397362 0.4298927953579101 -350 1.010631130471401 1.750464465687237 0.321017626912755 -351 1.418635001501272 0.8190492999985843 -0.1023703321158247 -352 1.006307913666113 0.5809921448427808 0.2632906758093849 -353 1.265327502315069 1.06533112816762 0.4110304201391338 -354 1.8108482485899 0.5573834805298281 0.2017017803896481 -355 1.380215925684095 1.340220657134674 -0.2334677620662884 -356 0.9913665364332176 0.5413074569027571 -0.2885030876157972 -357 1.612856969725634 0.4979937306821383 -0.45293802610268 -358 1.143916785727387 0.9765641491555823 -0.4974763498679757 -359 1.431014071730337 0.6129347670235737 0.5088098738940131 -360 1.699479877999052 1.018418464902874 0.2245161261321199 -361 1.366509217989849 1.473361213592895 0.2096048208646426 -362 1.862200179790552 0.7763841411086148 -0.1936516780784303 -363 1.392131171785957 0.4305669718356104 0.1076251504271724 -364 1.242345214149243 0.5075396430559113 -0.5934211709051677 -365 1.587621984957066 0.9666260696788359 -0.4669075217439702 -366 1.041060328494321 0.9595575993853922 0.05614026652743735 -367 1.058729532053908 0.7744221311360611 0.5975116678100523 -368 0.7294374265287789 0.5192318029393697 -0.002296726057127052 -369 1.730194889453991 1.163838789846815 -0.148045666975564 -370 2.044298702632946 0.4122923994887411 -0.1100148416481616 -371 1.322436651322489 0.3710779620407529 -0.254766099207305 -372 1.135530529689598 0.3742602834680934 0.5588259404205825 -373 0.8382517647831981 0.7450384683701989 -0.5422127333026093 -374 1.763158572846889 0.4468633779238019 0.5561796716402778 -375 1.192700534227963 1.34114988115434 -0.5551244559864699 -376 1.678726322631293 0.3670544075308987 -0.1149584378428671 -377 1.359220955957618 1.135678262863201 0.06666049099639326 -378 1.577215249631691 0.9561381396426961 0.5600324465840711 -379 1.065430367121712 1.199298878138994 -0.1937698051692187 -380 1.062294504610921 0.3452570106465946 0.001202393181407947 -381 1.35965500667398 1.661318642318972 -0.08883951555708131 -382 2.054747825331541 0.34323380961532 0.3182827628833362 -383 1.846084516030049 0.7750900966433136 0.4596090638257971 -384 1.488429466246604 0.7200613986226235 -0.6688437029431646 -385 1.000703927312493 0.3119825216587705 -0.5130404821839643 -386 1.299273693675256 0.7702466488539538 0.2240595613141949 -387 1.561448685218078 1.273279736306895 0.4173408748078854 -388 0.7635648558793097 0.6683314979305912 0.4780119661275764 -389 0.8595739642445496 0.8507493814656514 -0.2153376212242464 -390 1.978477439452769 0.8463593318541685 0.1218811845060402 -391 0.8313792036173077 0.3188255473345841 0.3355638674761983 -392 1.020855919956406 1.118325453266675 0.6574477121534414 -393 0.6832294399459129 0.5553575812073663 -0.3409721529927112 -394 1.253086756924487 1.394021993734984 0.5313127541741292 -395 0.8082327561325133 0.2981029812766474 -0.2110513803219472 -396 1.942182871711016 0.3560891485782794 -0.4491612347524943 -397 1.613694365036505 1.451747759436326 -0.01800591311493325 -398 1.289926859873265 1.601229732331073 -0.3955655286625344 -399 0.9339530554611122 0.9797370181660322 0.3691667658879731 -400 1.126678951239092 0.6607133075406245 -0.02322843206438263 -401 1.250778788798854 0.7145330589942874 -0.3517833801887749 -402 1.451765263880889 0.3127555354447675 0.666265928479598 -403 1.605053414392174 1.277430208547506 -0.4410216342941474 -404 1.086202065814923 1.244769321969722 0.2066762905501359 -405 0.7940822003319083 0.7872787771187758 0.1522709762555385 -406 1.878326137952758 0.6608170557985893 -0.5056996778120829 -407 1.637761487911216 0.2963357217251025 0.2596453211629388 -408 1.411018126178102 1.147284756395386 -0.6324199671085715 -409 1.488277492618901 0.32177571627524 -0.6955066325998237 -410 1.089673866546784 0.73921752083501 -0.7019376496748817 -411 1.171771511824859 1.428946797464596 -0.02201892070556395 -412 2.05466855499991 0.6328301538230341 0.3279502839160386 -413 1.353143674651522 1.128954649713943 0.6817060935447485 -414 1.353320018560723 0.2770211235786472 0.3684704776718821 -415 0.9070404862699556 1.00350823810525 -0.6841643163183184 -416 1.588187280033317 0.75127362290324 0.1381805442291818 -417 1.354311500310051 1.045101571939138 -0.2919839172335082 -418 0.8073330000041892 0.8769055635423104 0.6561063758264086 -419 1.539015621160407 1.560392971281782 -0.2694899107826355 -420 1.335739094857388 0.8349257453386124 0.6773841296580436 -421 1.856966769621279 1.033721526281692 -0.3765453788271407 -422 1.317808306372784 1.756547911079501 0.1819106358629041 -423 1.921753700420389 1.128289426655543 0.06979877893193551 -424 1.877839488866478 0.2837631284404755 0.09316597733410573 -425 1.211530198066868 0.2549303656898473 -0.7011263029425323 -426 1.613882796944428 0.6331152797895598 -0.2000168538857371 -427 1.731777323465674 0.4830144101577302 -0.6914560664620741 -428 1.068991343412805 0.2897189416432697 -0.2578923469342631 -429 2.215712428289467 0.2747068699434122 0.07030608531412151 -430 1.748804902741179 1.31965441206944 0.2014470425914964 -431 2.160972336241817 0.2578142594068452 -0.3091483571309573 -432 1.656998891131385 0.7004881423174387 0.6611974795081834 -433 2.135311785831417 0.6205070361134138 0.05761485799094201 -434 1.128872897166343 0.9125082420473587 -0.2019132117667884 -435 0.8065905731232743 0.2627003090228302 0.06219635997810313 -436 1.558579951737068 0.2543796712533649 -0.3359677314044994 -437 1.095300929684706 0.2668762697018797 0.26576342874253 -438 1.221850386488509 0.5846909618837201 0.7187134232149368 -439 0.9392598522401714 0.5390092060013327 0.6302275824396208 -440 0.6483332954363064 0.5215048636343409 0.2672692532571793 -441 1.00534759833767 0.5601117728552446 -0.5366970652009414 -442 1.669186083204167 0.9140987684193717 -0.06261302060885673 -443 1.300868157238982 0.912765896024329 -0.7217689151430906 -444 1.936410040849841 0.2454562465870731 0.6062747708512596 -445 1.261222079650665 0.5239216508313133 0.3216023378653879 -446 1.771114097121214 1.113687211388049 0.4641200874722527 -447 2.06605772633019 0.6163360316512467 -0.3016837250026109 -448 0.9077354499702041 1.068360147261763 -0.3821640919890156 -449 1.098341887804344 1.430722226382691 -0.3222640812714789 -450 1.740683266083933 0.2257228161438156 -0.6846991730401913 -451 1.431109538720755 1.440642807876566 -0.5412046315536471 -452 1.723438259361296 0.8234808519877937 -0.6346989579036486 -453 1.500847566861419 0.726092448023743 -0.4117874473610533 -454 1.72250839002415 1.391315141205534 -0.2518012658885989 -455 1.142474233200014 1.131876331068075 -0.7187971453772315 -456 1.452766288703132 0.2461665321109213 -0.066545663674481 -457 1.997114282263472 1.002217016533608 -0.152320737212002 -458 1.2335751749254 0.2310833922437358 -0.4483286610347972 -459 1.243509471602743 1.645634220311118 0.4218349305400673 -460 1.353154544950395 0.5723876900207028 -0.1009399294228396 -461 1.568151906445483 0.5451655206615679 0.297212198001392 -462 1.211912683108393 0.2238805188548799 0.7331781210365729 -463 1.939054772847803 0.9749516564389743 0.3358968291625145 -464 1.473108008187662 0.9365131111254542 0.3226364653260583 -465 0.5500086468869504 0.5304906880452636 -0.151031664317606 -466 1.839679917746078 0.5598091156524675 -0.05487762694700804 -467 1.81588422207515 0.521659312162986 -0.303848089847952 -468 1.292909852420306 0.6444747339717066 -0.7811755399907123 -469 1.968283335011498 0.5828894651298034 0.5529682806762651 -470 1.163116866805931 1.572087255828068 -0.6280053147816038 -471 1.015606540629819 0.7644234338809101 -0.3788243692674071 +178 +1 1 1.732050807568877 -1.224646799147353e-16 +2 2 0 -1.224646799147353e-16 +3 1.986476715483886 0.2321858282504604 -1.224646799147353e-16 +4 1.946089741159648 0.4612317414848803 -1.224646799147353e-16 +5 1.879385241571817 0.6840402866513373 -1.224646799147353e-16 +6 1.787265280646825 0.8975983604009242 -1.224646799147353e-16 +7 1.670975622825873 1.099017956141612 -1.224646799147353e-16 +8 1.532088886237956 1.285575219373079 -1.224646799147353e-16 +9 1.372483275737467 1.454747283146097 -1.224646799147353e-16 +10 1.194317183405573 1.604246385510087 -1.224646799147353e-16 +11 0.9713640064107713 1.682451811747116 0.2323615860315311 +12 0.8920161844090693 1.545017352570237 0.4114919360856992 +13 0.7801341700627819 1.351232019269317 0.4963544370492818 +14 0.6613487770564798 1.145489683385365 0.467508120445488 +15 0.5628723129571309 0.9749234442155601 0.3315613291201853 +16 0.5072645455148519 0.8786079657100585 0.1196578310999915 +17 0.5072645456434897 0.8786079659328657 -0.1196578321437994 +18 0.5628723130955459 0.9749234444553019 -0.3315613294326618 +19 0.6613487782393664 1.145489685434185 -0.4675081213427075 +20 0.7801341701356748 1.351232019395571 -0.4963544370315802 +21 0.8920161866827891 1.545017356508435 -0.4114919329468283 +22 0.9713640064234279 1.682451811769038 -0.2323615859833005 +23 1.942728012826605 0 0.2323615860218843 +24 1.784032373365578 0 0.4114919329468282 +25 1.560268340127662 0 0.496354437049027 +26 1.322697556478732 0 0.4675081213427075 +27 1.12574462591445 0 0.3315613291203977 +28 1.014529091286974 0 0.119657832143779 +29 1.014529091286974 0 -0.1196578321437787 +30 1.125744625914449 0 -0.3315613291203975 +31 1.322697556478732 0 -0.4675081213427074 +32 1.560268340127661 0 -0.496354437049027 +33 1.784032373365578 0 -0.4114919329468283 +34 1.942728012826605 0 -0.2323615860218846 +35 0.9094092833839373 1.140104827634976 0.4982645365438731 +36 0.9145403631597188 1.127554721496875 -0.4976726875517566 +37 1.439543163169036 0.2066277058988615 0.4979068470620236 +38 1.438046243463446 0.2043628722395764 -0.4977381412060781 +39 1.696686878481083 0.9795826260215588 0.1979072290649842 +40 1.705046974097277 0.9627338322458719 -0.2004271899713759 +41 1.425045163821982 1.344460771417579 0.1979072290649849 +42 1.426940472289519 1.3461283575362 -0.1919478807927782 +43 1.881724626638111 0.5593582007143618 -0.1885115572979801 +44 1.876859764350238 0.561894927701204 0.197907229064985 +45 0.6673803921678336 0.7447234565204733 0.002192541055854352 +46 1.050984583067059 0.1682970125584115 0.2454183754604045 +47 1.04172076116343 0.2047537321359636 -0.240523499060071 +48 1.113311450848127 1.513972982303749 0.3258377535851458 +49 1.113311453634618 1.513972982601351 -0.3258377513847104 +50 1.867794790374375 0.2071695099506198 0.3258377513964845 +51 1.867794790374375 0.2071695099506223 -0.3258377513964847 +52 0.699980884447671 0.7923257843216313 0.2322978976561902 +53 0.8143742402024221 0.6091370533569924 0.1292055331351144 +54 0.9234512163817853 0.6950259596839291 0.362644934140704 +55 0.8149471563398465 0.6014811214666318 -0.1127408743463922 +56 0.9089882740735398 0.4178664121885499 0.02087403616690475 +57 0.8036391734156695 0.9174735877750071 0.4140227221617467 +58 1.04528975873691 0.9197904008254907 0.488274495579655 +59 1.132701372162777 0.6901822877229037 0.4688993254694935 +60 1.277010042388928 0.8802828084812561 0.4973904977528614 +61 1.353438092664882 0.6544862687155961 0.4999885855347576 +62 1.206606309387528 1.137304388082402 0.4743397986991702 +63 1.203861688615928 0.4781648664665324 0.456198716333284 +64 1.420536892021458 1.019694143898059 0.4338017162656254 +65 0.9513629883317927 0.4940253704652492 0.2584636609340892 +66 0.706186918123033 0.8068591038835513 -0.258902571664125 +67 0.8997137668513249 0.6778946202619701 -0.332423851739337 +68 0.8754534158794457 0.8896155968337219 -0.431929083733448 +69 1.068014665374453 0.7835782676774907 -0.4682372295982862 +70 1.094885326848669 0.5587005809631567 -0.420314909746101 +71 1.278914902324639 0.6814395891060806 -0.4974057052434921 +72 1.253859094818866 0.9188999749034799 -0.4970184215451375 +73 1.467592256574374 0.8234236412687718 -0.4653816350826456 +74 1.493455917091833 0.5922523984885606 -0.4885036149289653 +75 1.427903945844154 1.053079485024634 -0.4180895076610792 +76 1.192654033939925 1.176482818815241 -0.468273221931405 +77 1.664532079158557 0.7347462962335058 -0.3846173119001672 +78 1.684193467076019 0.4966353289223597 -0.4295574916595252 +79 0.9581284611377014 0.4449942507914502 -0.2307371775066812 +80 1.060510603934137 1.323992179178645 0.4598289463295096 +81 1.20965670082534 0.1918462924921296 -0.4174342094103178 +82 1.306569861240723 0.4081890859478611 -0.4824924751602535 +83 1.222973879657449 0.2262967791144349 0.429334321634214 +84 1.804078223352526 0.7663783517359284 -0.1956990807188041 +85 1.57086252165904 1.155773912505517 -0.2174559627111528 +86 1.574823294802248 1.167621289969356 0.1948731313716022 +87 1.799061725861226 0.7760394771228164 0.1975920088688854 +88 1.736321519153448 0.6195058019401377 0.3633011133312876 +89 1.680111207596174 0.2053409065696982 0.4614111573472731 +90 1.585805226690124 0.4095866832898705 0.4806230171620565 +91 1.033769170861085 1.346420377509085 -0.4593379913029474 +92 1.686177954337897 0.2595089698405005 -0.4555780070333795 +93 0.9805825388808332 0.1961068189584932 0 +94 1.267064046804422 1.349831092695157 0.3557435462640699 +95 1.479801458923729 0.8235937501426396 0.4610179491301168 +96 1.806713163893442 0.41291149496386 0.3538099754989008 +97 1.660304769719565 0.8158013561953625 0.3571657671790813 +98 1.272522679585459 1.496027967309635 0.1862154784961512 +99 1.273193945142967 1.495820795927453 -0.1855231731675253 +100 1.262667463342245 1.368719575871037 -0.3447086919841124 +101 1.931859564293957 0.3540229855991108 0.1862154775733828 +102 1.934684648085233 0.3534998953881237 -0.1793804689566357 +103 1.044602110326715 0.9883306626754986 -0.496147496375881 +104 1.531662137703001 0.3834487538500693 -0.4937306551344234 +105 1.551796568960546 0.6139737231494753 0.4706294779813407 +106 1.581724214084509 0.9482897902504869 -0.3626575574879038 +107 1.096782839124086 0.35444480392985 -0.3596337488065346 +108 1.387291936348416 0.4077234230541955 0.497071738421552 +109 1.08924964123622 0.3634521195547355 0.355383901525496 +110 1.441115266930556 1.203974457102059 0.3274445044904424 +111 1.395080190203861 1.235707600010656 -0.3431511175769478 +112 1.133587364788978 1.610473031723204 -0.1721570661176043 +113 1.961520334484167 0.1716255200510413 0.1732789072467822 +114 1.961422513597609 0.1736228878529459 -0.1730685535438358 +115 1.82696920620189 0.4017949294223938 -0.3356092840765813 +116 1.131073087671027 1.61183028132059 0.1730685525791028 +117 1.580661987779667 0.9904905866376601 0.3413397946090942 +118 1.053798949591161 0.5492367868134354 0.3909838746147544 +119 0.7242610698965356 0.986066622565408 -0.4165714295663997 +120 1.776913423346694 0.6100558234668472 -0.3264522078233214 +121 0.976815381999997 0.3286770548430039 0.1723113781768278 +122 0.9684597721183544 0.3086573347446573 -0.1272227140227045 +123 1.598657272365354 0 -0.2601378477606267 +124 1.336856475131923 0 0.2435465079686098 +125 1.264366353304017 0 -0.1342496457412713 +126 1.708248762070371 0 0.1844923042412902 +127 1.770132970054707 0 -0.06658179719356594 +128 1.627974743938903 0 0.3374416670744554 +129 1.518381683403412 0 0.189367998345964 +130 1.388026045801723 0 0.02759910094603191 +131 1.57082733902861 0 -0.01324440776767719 +132 1.205770154876862 0 0.09185560579891296 +133 1.448748593218543 0 -0.1456951042254292 +134 1.386747123568126 0 -0.3059177475399098 +135 1.773887657153061 0 -0.2426432909807264 +136 1.855277436237921 0 0.08756802326740212 +137 1.456499046249551 0 0.3582625863623187 +138 0.7993286361826776 1.384477809813136 -0.2601378477606267 +139 0.6684282375659617 1.157751668677965 0.2435465079686098 +140 0.6321831766520087 1.09497338165157 -0.1342496457412713 +141 0.8541243810351855 1.47938682393626 0.1844923042412902 +142 0.885066485027354 1.532980120143776 -0.06658179719356594 +143 0.8139873719694519 1.409867484970557 0.3374416670744554 +144 0.7591908417017061 1.314957110468335 0.189367998345964 +145 0.6940130229008615 1.202065816778755 0.02759910094603191 +146 0.7854136695143054 1.360376380557887 -0.01324440776767719 +147 0.6028850774384313 1.04422758524846 0.09185560579891296 +148 0.7243742966092718 1.254653085424226 -0.1456951042254292 +149 0.6933735617840632 1.200958237634995 -0.3059177475399098 +150 0.8869438285765309 1.536231774554212 -0.2426432909807264 +151 0.9276387181189605 1.606717390850103 0.08756802326740212 +152 0.7282495231247758 1.261365174639917 0.3582625863623187 +153 1.411918130602168 0.496166241357142 -0.00157291651681768 +154 1.137417628047573 0.9720715936541285 -0.004558233820192492 +155 1.450923907048078 0.835854081603992 0.008303709726106997 +156 1.195281628759975 0.6892135661795487 0.1379139557683655 +157 1.667647997439524 0.3046155345731573 -0.01063985748379645 +158 1.095077566932522 1.30506262456116 0.008783669059526909 +159 1.449746181951948 0.2899752883377874 -0.2128942904574569 +160 1.425404656176498 0.2838646166858353 0.2090378240215375 +161 1.237422074642534 0.6934452933460877 -0.1740536126458837 +162 0.9265939870131148 1.089233825798041 0.146036662270623 +163 0.9141871309006279 1.035605401598253 -0.1819109563473867 +164 1.230559284884559 0.2965650718118637 -0.0489211473166503 +165 1.633700383529476 0.5873280387970766 -0.1078820007088586 +166 1.381887166693965 0.5422592078649243 0.2595533680109433 +167 1.628614112376115 0.5120437923677087 0.1405317590914031 +168 1.296790159421439 0.9296724900104604 0.2103100611208717 +169 1.43040652357321 0.5390860673292487 -0.2497801650023363 +170 1.187552760136346 0.4469311325853691 0.1497889600434833 +171 1.136555246481813 0.9253132713408032 -0.2607675417720481 +172 1.169875547734923 1.157176703594696 0.209783121723046 +173 1.252256239782287 1.161539312959809 -0.1396154626225087 +174 0.9854410532992778 1.295312212838649 0.232826117690098 +175 0.8998494176549744 0.8641570369932714 0.01526132714743774 +176 1.047849560177692 0.8788161627502054 0.2215760845022245 +177 1.402089433100673 1.077521710164203 0.04039637986273873 +178 1.03525188898502 1.249979305919021 -0.2281501268865102 $EndNodes $Elements -2384 -1 2 2 1 1 12 219 1 -2 2 2 1 1 1 221 12 -3 2 2 1 1 13 221 1 -4 2 2 1 1 1 219 37 -5 2 2 1 1 3 220 2 -6 2 2 1 1 2 222 3 -7 2 2 1 1 2 220 38 -8 2 2 1 1 62 222 2 -9 2 2 1 1 4 89 3 -10 2 2 1 1 3 90 4 -11 2 2 1 1 89 220 3 -12 2 2 1 1 3 222 90 -13 2 2 1 1 4 181 5 -14 2 2 1 1 5 188 4 -15 2 2 1 1 4 188 89 -16 2 2 1 1 90 181 4 -17 2 2 1 1 6 73 5 -18 2 2 1 1 5 75 6 -19 2 2 1 1 73 188 5 -20 2 2 1 1 5 181 75 -21 2 2 1 1 6 163 7 -22 2 2 1 1 7 185 6 -23 2 2 1 1 6 185 73 -24 2 2 1 1 75 163 6 -25 2 2 1 1 8 67 7 -26 2 2 1 1 7 68 8 -27 2 2 1 1 67 185 7 -28 2 2 1 1 7 163 68 -29 2 2 1 1 9 167 8 -30 2 2 1 1 8 186 9 -31 2 2 1 1 8 167 67 -32 2 2 1 1 68 186 8 -33 2 2 1 1 10 74 9 -34 2 2 1 1 9 76 10 -35 2 2 1 1 74 167 9 -36 2 2 1 1 9 186 76 -37 2 2 1 1 11 182 10 -38 2 2 1 1 10 187 11 -39 2 2 1 1 10 182 74 -40 2 2 1 1 76 187 10 -41 2 2 1 1 12 87 11 -42 2 2 1 1 11 88 12 -43 2 2 1 1 87 182 11 -44 2 2 1 1 11 187 88 -45 2 2 1 1 12 221 87 -46 2 2 1 1 88 219 12 -47 2 2 1 1 38 200 39 -48 2 2 1 1 38 220 200 -49 2 2 1 1 39 81 40 -50 2 2 1 1 39 200 81 -51 2 2 1 1 40 215 41 -52 2 2 1 1 81 215 40 -53 2 2 1 1 41 65 42 -54 2 2 1 1 41 215 65 -55 2 2 1 1 42 156 43 -56 2 2 1 1 65 156 42 -57 2 2 1 1 43 72 44 -58 2 2 1 1 43 156 72 -59 2 2 1 1 44 152 45 -60 2 2 1 1 72 152 44 -61 2 2 1 1 45 78 46 -62 2 2 1 1 45 152 78 -63 2 2 1 1 46 126 47 -64 2 2 1 1 78 126 46 -65 2 2 1 1 47 85 48 -66 2 2 1 1 47 126 85 -67 2 2 1 1 48 207 49 -68 2 2 1 1 85 207 48 -69 2 2 1 1 49 96 50 -70 2 2 1 1 49 207 96 -71 2 2 1 1 50 228 51 -72 2 2 1 1 96 228 50 -73 2 2 1 1 51 92 52 -74 2 2 1 1 51 228 92 -75 2 2 1 1 52 93 53 -76 2 2 1 1 92 93 52 -77 2 2 1 1 53 83 54 -78 2 2 1 1 53 93 83 -79 2 2 1 1 54 160 55 -80 2 2 1 1 83 160 54 -81 2 2 1 1 55 69 56 -82 2 2 1 1 55 160 69 -83 2 2 1 1 56 176 57 -84 2 2 1 1 69 176 56 -85 2 2 1 1 57 177 58 -86 2 2 1 1 176 177 57 -87 2 2 1 1 58 66 59 -88 2 2 1 1 58 177 66 -89 2 2 1 1 59 191 60 -90 2 2 1 1 66 191 59 -91 2 2 1 1 60 82 61 -92 2 2 1 1 60 191 82 -93 2 2 1 1 61 201 62 -94 2 2 1 1 82 201 61 -95 2 2 1 1 201 222 62 -96 2 2 1 1 14 197 13 -97 2 2 1 1 197 221 13 -98 2 2 1 1 15 79 14 -99 2 2 1 1 79 197 14 -100 2 2 1 1 16 189 15 -101 2 2 1 1 15 189 79 -102 2 2 1 1 17 63 16 -103 2 2 1 1 63 189 16 -104 2 2 1 1 18 172 17 -105 2 2 1 1 17 172 63 -106 2 2 1 1 19 171 18 -107 2 2 1 1 171 172 18 -108 2 2 1 1 20 71 19 -109 2 2 1 1 71 171 19 -110 2 2 1 1 21 159 20 -111 2 2 1 1 20 159 71 -112 2 2 1 1 22 84 21 -113 2 2 1 1 84 159 21 -114 2 2 1 1 23 94 22 -115 2 2 1 1 22 94 84 -116 2 2 1 1 24 91 23 -117 2 2 1 1 91 94 23 -118 2 2 1 1 25 227 24 -119 2 2 1 1 24 227 91 -120 2 2 1 1 26 95 25 -121 2 2 1 1 95 227 25 -122 2 2 1 1 27 208 26 -123 2 2 1 1 26 208 95 -124 2 2 1 1 28 86 27 -125 2 2 1 1 86 208 27 -126 2 2 1 1 29 97 28 -127 2 2 1 1 28 97 86 -128 2 2 1 1 30 77 29 -129 2 2 1 1 77 97 29 -130 2 2 1 1 31 123 30 -131 2 2 1 1 30 123 77 -132 2 2 1 1 32 70 31 -133 2 2 1 1 70 123 31 -134 2 2 1 1 33 158 32 -135 2 2 1 1 32 158 70 -136 2 2 1 1 34 64 33 -137 2 2 1 1 64 158 33 -138 2 2 1 1 35 216 34 -139 2 2 1 1 34 216 64 -140 2 2 1 1 36 80 35 -141 2 2 1 1 80 216 35 -142 2 2 1 1 37 199 36 -143 2 2 1 1 36 199 80 -144 2 2 1 1 37 219 199 -145 2 2 1 1 172 196 63 -146 2 2 1 1 63 190 189 -147 2 2 1 1 63 196 190 -148 2 2 1 1 64 216 124 -149 2 2 1 1 124 226 64 -150 2 2 1 1 64 226 158 -151 2 2 1 1 65 215 153 -152 2 2 1 1 153 225 65 -153 2 2 1 1 65 225 156 -154 2 2 1 1 177 195 66 -155 2 2 1 1 66 192 191 -156 2 2 1 1 66 195 192 -157 2 2 1 1 151 154 67 -158 2 2 1 1 67 167 151 -159 2 2 1 1 154 185 67 -160 2 2 1 1 122 125 68 -161 2 2 1 1 68 163 122 -162 2 2 1 1 125 186 68 -163 2 2 1 1 160 204 69 -164 2 2 1 1 69 180 176 -165 2 2 1 1 69 204 180 -166 2 2 1 1 102 123 70 -167 2 2 1 1 70 157 102 -168 2 2 1 1 70 158 157 -169 2 2 1 1 159 203 71 -170 2 2 1 1 71 175 171 -171 2 2 1 1 71 203 175 -172 2 2 1 1 131 152 72 -173 2 2 1 1 72 155 131 -174 2 2 1 1 72 156 155 -175 2 2 1 1 185 210 73 -176 2 2 1 1 73 218 188 -177 2 2 1 1 210 218 73 -178 2 2 1 1 74 168 167 -179 2 2 1 1 74 169 168 -180 2 2 1 1 74 182 169 -181 2 2 1 1 75 164 163 -182 2 2 1 1 75 165 164 -183 2 2 1 1 75 181 165 -184 2 2 1 1 186 209 76 -185 2 2 1 1 76 217 187 -186 2 2 1 1 209 217 76 -187 2 2 1 1 77 98 97 -188 2 2 1 1 77 99 98 -189 2 2 1 1 77 123 99 -190 2 2 1 1 78 127 126 -191 2 2 1 1 78 128 127 -192 2 2 1 1 78 152 128 -193 2 2 1 1 79 189 170 -194 2 2 1 1 170 198 79 -195 2 2 1 1 79 198 197 -196 2 2 1 1 80 214 124 -197 2 2 1 1 124 216 80 -198 2 2 1 1 199 224 80 -199 2 2 1 1 80 224 214 -200 2 2 1 1 81 213 153 -201 2 2 1 1 153 215 81 -202 2 2 1 1 200 223 81 -203 2 2 1 1 81 223 213 -204 2 2 1 1 82 191 166 -205 2 2 1 1 166 202 82 -206 2 2 1 1 82 202 201 -207 2 2 1 1 93 161 83 -208 2 2 1 1 83 205 160 -209 2 2 1 1 161 205 83 -210 2 2 1 1 94 162 84 -211 2 2 1 1 84 206 159 -212 2 2 1 1 162 206 84 -213 2 2 1 1 85 162 94 -214 2 2 1 1 94 233 85 -215 2 2 1 1 126 162 85 -216 2 2 1 1 85 233 207 -217 2 2 1 1 86 161 93 -218 2 2 1 1 93 234 86 -219 2 2 1 1 97 161 86 -220 2 2 1 1 86 234 208 -221 2 2 1 1 87 198 182 -222 2 2 1 1 197 198 87 -223 2 2 1 1 87 221 197 -224 2 2 1 1 187 224 88 -225 2 2 1 1 199 219 88 -226 2 2 1 1 88 224 199 -227 2 2 1 1 188 223 89 -228 2 2 1 1 200 220 89 -229 2 2 1 1 89 223 200 -230 2 2 1 1 90 202 181 -231 2 2 1 1 201 202 90 -232 2 2 1 1 90 222 201 -233 2 2 1 1 91 233 94 -234 2 2 1 1 96 207 91 -235 2 2 1 1 91 227 96 -236 2 2 1 1 207 233 91 -237 2 2 1 1 92 234 93 -238 2 2 1 1 95 208 92 -239 2 2 1 1 92 228 95 -240 2 2 1 1 208 234 92 -241 2 2 1 1 96 227 95 -242 2 2 1 1 95 228 96 -243 2 2 1 1 98 161 97 -244 2 2 1 1 99 100 98 -245 2 2 1 1 100 205 98 -246 2 2 1 1 98 205 161 -247 2 2 1 1 99 101 100 -248 2 2 1 1 99 102 101 -249 2 2 1 1 99 123 102 -250 2 2 1 1 101 230 100 -251 2 2 1 1 204 205 100 -252 2 2 1 1 100 230 204 -253 2 2 1 1 102 103 101 -254 2 2 1 1 103 104 101 -255 2 2 1 1 104 230 101 -256 2 2 1 1 102 157 103 -257 2 2 1 1 103 105 104 -258 2 2 1 1 103 106 105 -259 2 2 1 1 103 157 106 -260 2 2 1 1 105 179 104 -261 2 2 1 1 104 179 178 -262 2 2 1 1 178 180 104 -263 2 2 1 1 180 230 104 -264 2 2 1 1 106 107 105 -265 2 2 1 1 107 108 105 -266 2 2 1 1 108 179 105 -267 2 2 1 1 106 109 107 -268 2 2 1 1 106 116 109 -269 2 2 1 1 106 157 116 -270 2 2 1 1 107 110 108 -271 2 2 1 1 109 184 107 -272 2 2 1 1 107 184 110 -273 2 2 1 1 110 111 108 -274 2 2 1 1 111 115 108 -275 2 2 1 1 115 179 108 -276 2 2 1 1 116 117 109 -277 2 2 1 1 117 118 109 -278 2 2 1 1 118 184 109 -279 2 2 1 1 110 112 111 -280 2 2 1 1 110 114 112 -281 2 2 1 1 110 184 114 -282 2 2 1 1 112 113 111 -283 2 2 1 1 113 211 111 -284 2 2 1 1 111 211 115 -285 2 2 1 1 112 164 113 -286 2 2 1 1 114 122 112 -287 2 2 1 1 122 164 112 -288 2 2 1 1 164 165 113 -289 2 2 1 1 165 166 113 -290 2 2 1 1 166 211 113 -291 2 2 1 1 114 125 122 -292 2 2 1 1 114 193 125 -293 2 2 1 1 184 193 114 -294 2 2 1 1 115 231 179 -295 2 2 1 1 192 195 115 -296 2 2 1 1 115 211 192 -297 2 2 1 1 195 231 115 -298 2 2 1 1 116 226 117 -299 2 2 1 1 157 158 116 -300 2 2 1 1 158 226 116 -301 2 2 1 1 117 119 118 -302 2 2 1 1 117 124 119 -303 2 2 1 1 117 226 124 -304 2 2 1 1 119 120 118 -305 2 2 1 1 120 193 118 -306 2 2 1 1 118 193 184 -307 2 2 1 1 119 121 120 -308 2 2 1 1 119 214 121 -309 2 2 1 1 124 214 119 -310 2 2 1 1 121 217 120 -311 2 2 1 1 120 209 193 -312 2 2 1 1 120 217 209 -313 2 2 1 1 187 217 121 -314 2 2 1 1 121 224 187 -315 2 2 1 1 214 224 121 -316 2 2 1 1 163 164 122 -317 2 2 1 1 125 209 186 -318 2 2 1 1 193 209 125 -319 2 2 1 1 127 162 126 -320 2 2 1 1 128 129 127 -321 2 2 1 1 129 206 127 -322 2 2 1 1 127 206 162 -323 2 2 1 1 128 130 129 -324 2 2 1 1 128 131 130 -325 2 2 1 1 128 152 131 -326 2 2 1 1 130 229 129 -327 2 2 1 1 203 206 129 -328 2 2 1 1 129 229 203 -329 2 2 1 1 131 132 130 -330 2 2 1 1 132 133 130 -331 2 2 1 1 133 229 130 -332 2 2 1 1 131 155 132 -333 2 2 1 1 132 134 133 -334 2 2 1 1 132 135 134 -335 2 2 1 1 132 155 135 -336 2 2 1 1 134 174 133 -337 2 2 1 1 133 174 173 -338 2 2 1 1 173 175 133 -339 2 2 1 1 175 229 133 -340 2 2 1 1 135 136 134 -341 2 2 1 1 136 137 134 -342 2 2 1 1 137 174 134 -343 2 2 1 1 135 138 136 -344 2 2 1 1 135 145 138 -345 2 2 1 1 135 155 145 -346 2 2 1 1 136 139 137 -347 2 2 1 1 138 183 136 -348 2 2 1 1 136 183 139 -349 2 2 1 1 139 140 137 -350 2 2 1 1 140 144 137 -351 2 2 1 1 144 174 137 -352 2 2 1 1 145 146 138 -353 2 2 1 1 146 147 138 -354 2 2 1 1 147 183 138 -355 2 2 1 1 139 141 140 -356 2 2 1 1 139 143 141 -357 2 2 1 1 139 183 143 -358 2 2 1 1 141 142 140 -359 2 2 1 1 142 212 140 -360 2 2 1 1 140 212 144 -361 2 2 1 1 141 168 142 -362 2 2 1 1 143 151 141 -363 2 2 1 1 151 168 141 -364 2 2 1 1 168 169 142 -365 2 2 1 1 169 170 142 -366 2 2 1 1 170 212 142 -367 2 2 1 1 143 154 151 -368 2 2 1 1 143 194 154 -369 2 2 1 1 183 194 143 -370 2 2 1 1 144 232 174 -371 2 2 1 1 190 196 144 -372 2 2 1 1 144 212 190 -373 2 2 1 1 196 232 144 -374 2 2 1 1 145 225 146 -375 2 2 1 1 155 156 145 -376 2 2 1 1 156 225 145 -377 2 2 1 1 146 148 147 -378 2 2 1 1 146 153 148 -379 2 2 1 1 146 225 153 -380 2 2 1 1 148 149 147 -381 2 2 1 1 149 194 147 -382 2 2 1 1 147 194 183 -383 2 2 1 1 148 150 149 -384 2 2 1 1 148 213 150 -385 2 2 1 1 153 213 148 -386 2 2 1 1 150 218 149 -387 2 2 1 1 149 210 194 -388 2 2 1 1 149 218 210 -389 2 2 1 1 188 218 150 -390 2 2 1 1 150 223 188 -391 2 2 1 1 213 223 150 -392 2 2 1 1 167 168 151 -393 2 2 1 1 154 210 185 -394 2 2 1 1 194 210 154 -395 2 2 1 1 159 206 203 -396 2 2 1 1 160 205 204 -397 2 2 1 1 165 202 166 -398 2 2 1 1 181 202 165 -399 2 2 1 1 191 192 166 -400 2 2 1 1 192 211 166 -401 2 2 1 1 169 198 170 -402 2 2 1 1 182 198 169 -403 2 2 1 1 189 190 170 -404 2 2 1 1 190 212 170 -405 2 2 1 1 171 173 172 -406 2 2 1 1 171 175 173 -407 2 2 1 1 173 196 172 -408 2 2 1 1 174 232 173 -409 2 2 1 1 173 232 196 -410 2 2 1 1 203 229 175 -411 2 2 1 1 176 178 177 -412 2 2 1 1 176 180 178 -413 2 2 1 1 178 195 177 -414 2 2 1 1 179 231 178 -415 2 2 1 1 178 231 195 -416 2 2 1 1 204 230 180 -417 2 2 2 2 38 271 2 -418 2 2 2 2 2 236 62 -419 2 2 2 2 2 271 236 -420 2 2 2 2 39 289 38 -421 2 2 2 2 38 289 271 -422 2 2 2 2 40 242 39 -423 2 2 2 2 242 289 39 -424 2 2 2 2 41 283 40 -425 2 2 2 2 40 283 242 -426 2 2 2 2 42 280 41 -427 2 2 2 2 280 283 41 -428 2 2 2 2 43 238 42 -429 2 2 2 2 238 280 42 -430 2 2 2 2 44 281 43 -431 2 2 2 2 43 281 238 -432 2 2 2 2 45 244 44 -433 2 2 2 2 244 281 44 -434 2 2 2 2 46 282 45 -435 2 2 2 2 45 282 244 -436 2 2 2 2 47 240 46 -437 2 2 2 2 240 282 46 -438 2 2 2 2 48 277 47 -439 2 2 2 2 47 277 240 -440 2 2 2 2 49 278 48 -441 2 2 2 2 48 278 277 -442 2 2 2 2 50 235 49 -443 2 2 2 2 235 278 49 -444 2 2 2 2 51 290 50 -445 2 2 2 2 50 290 235 -446 2 2 2 2 52 276 51 -447 2 2 2 2 276 290 51 -448 2 2 2 2 53 241 52 -449 2 2 2 2 241 276 52 -450 2 2 2 2 54 288 53 -451 2 2 2 2 53 288 241 -452 2 2 2 2 55 274 54 -453 2 2 2 2 274 288 54 -454 2 2 2 2 56 237 55 -455 2 2 2 2 237 274 55 -456 2 2 2 2 57 275 56 -457 2 2 2 2 56 275 237 -458 2 2 2 2 58 245 57 -459 2 2 2 2 245 275 57 -460 2 2 2 2 59 239 58 -461 2 2 2 2 239 245 58 -462 2 2 2 2 60 284 59 -463 2 2 2 2 59 284 239 -464 2 2 2 2 61 243 60 -465 2 2 2 2 243 284 60 -466 2 2 2 2 62 279 61 -467 2 2 2 2 61 279 243 -468 2 2 2 2 236 279 62 -469 2 2 2 2 235 269 263 -470 2 2 2 2 263 278 235 -471 2 2 2 2 235 290 269 -472 2 2 2 2 236 271 270 -473 2 2 2 2 270 287 236 -474 2 2 2 2 236 287 279 -475 2 2 2 2 272 274 237 -476 2 2 2 2 237 275 272 -477 2 2 2 2 259 280 238 -478 2 2 2 2 238 286 259 -479 2 2 2 2 281 286 238 -480 2 2 2 2 239 246 245 -481 2 2 2 2 239 247 246 -482 2 2 2 2 239 284 247 -483 2 2 2 2 277 291 240 -484 2 2 2 2 240 285 282 -485 2 2 2 2 240 291 285 -486 2 2 2 2 241 273 262 -487 2 2 2 2 262 276 241 -488 2 2 2 2 241 288 273 -489 2 2 2 2 242 283 259 -490 2 2 2 2 259 292 242 -491 2 2 2 2 242 292 289 -492 2 2 2 2 247 284 243 -493 2 2 2 2 243 287 247 -494 2 2 2 2 279 287 243 -495 2 2 2 2 260 281 244 -496 2 2 2 2 244 285 260 -497 2 2 2 2 282 285 244 -498 2 2 2 2 246 275 245 -499 2 2 2 2 247 248 246 -500 2 2 2 2 248 264 246 -501 2 2 2 2 264 275 246 -502 2 2 2 2 247 249 248 -503 2 2 2 2 247 287 249 -504 2 2 2 2 249 250 248 -505 2 2 2 2 250 251 248 -506 2 2 2 2 251 264 248 -507 2 2 2 2 249 265 250 -508 2 2 2 2 249 270 265 -509 2 2 2 2 249 287 270 -510 2 2 2 2 250 252 251 -511 2 2 2 2 250 253 252 -512 2 2 2 2 250 265 253 -513 2 2 2 2 252 254 251 -514 2 2 2 2 254 256 251 -515 2 2 2 2 256 264 251 -516 2 2 2 2 253 255 252 -517 2 2 2 2 252 267 254 -518 2 2 2 2 255 267 252 -519 2 2 2 2 253 257 255 -520 2 2 2 2 253 258 257 -521 2 2 2 2 253 265 258 -522 2 2 2 2 254 262 256 -523 2 2 2 2 254 263 262 -524 2 2 2 2 254 267 263 -525 2 2 2 2 257 260 255 -526 2 2 2 2 260 261 255 -527 2 2 2 2 261 267 255 -528 2 2 2 2 262 273 256 -529 2 2 2 2 256 272 264 -530 2 2 2 2 256 273 272 -531 2 2 2 2 258 259 257 -532 2 2 2 2 259 286 257 -533 2 2 2 2 257 286 260 -534 2 2 2 2 258 292 259 -535 2 2 2 2 265 266 258 -536 2 2 2 2 266 292 258 -537 2 2 2 2 259 283 280 -538 2 2 2 2 260 285 261 -539 2 2 2 2 260 286 281 -540 2 2 2 2 261 268 267 -541 2 2 2 2 261 291 268 -542 2 2 2 2 285 291 261 -543 2 2 2 2 263 269 262 -544 2 2 2 2 269 276 262 -545 2 2 2 2 267 268 263 -546 2 2 2 2 268 278 263 -547 2 2 2 2 272 275 264 -548 2 2 2 2 265 270 266 -549 2 2 2 2 270 271 266 -550 2 2 2 2 271 289 266 -551 2 2 2 2 289 292 266 -552 2 2 2 2 268 291 278 -553 2 2 2 2 269 290 276 -554 2 2 2 2 273 274 272 -555 2 2 2 2 273 288 274 -556 2 2 2 2 278 291 277 -557 2 2 3 3 13 1 329 -558 2 2 3 3 1 37 294 -559 2 2 3 3 1 294 329 -560 2 2 3 3 14 13 347 -561 2 2 3 3 13 329 347 -562 2 2 3 3 15 14 300 -563 2 2 3 3 300 14 347 -564 2 2 3 3 16 15 341 -565 2 2 3 3 15 300 341 -566 2 2 3 3 17 16 338 -567 2 2 3 3 338 16 341 -568 2 2 3 3 18 17 296 -569 2 2 3 3 296 17 338 -570 2 2 3 3 19 18 339 -571 2 2 3 3 18 296 339 -572 2 2 3 3 20 19 302 -573 2 2 3 3 302 19 339 -574 2 2 3 3 21 20 340 -575 2 2 3 3 20 302 340 -576 2 2 3 3 22 21 298 -577 2 2 3 3 298 21 340 -578 2 2 3 3 23 22 335 -579 2 2 3 3 22 298 335 -580 2 2 3 3 24 23 336 -581 2 2 3 3 23 335 336 -582 2 2 3 3 25 24 293 -583 2 2 3 3 293 24 336 -584 2 2 3 3 26 25 348 -585 2 2 3 3 25 293 348 -586 2 2 3 3 27 26 334 -587 2 2 3 3 334 26 348 -588 2 2 3 3 28 27 299 -589 2 2 3 3 299 27 334 -590 2 2 3 3 29 28 346 -591 2 2 3 3 28 299 346 -592 2 2 3 3 30 29 332 -593 2 2 3 3 332 29 346 -594 2 2 3 3 31 30 295 -595 2 2 3 3 295 30 332 -596 2 2 3 3 32 31 333 -597 2 2 3 3 31 295 333 -598 2 2 3 3 33 32 303 -599 2 2 3 3 303 32 333 -600 2 2 3 3 34 33 297 -601 2 2 3 3 297 33 303 -602 2 2 3 3 35 34 342 -603 2 2 3 3 34 297 342 -604 2 2 3 3 36 35 301 -605 2 2 3 3 301 35 342 -606 2 2 3 3 37 36 337 -607 2 2 3 3 36 301 337 -608 2 2 3 3 294 37 337 -609 2 2 3 3 293 321 327 -610 2 2 3 3 321 293 336 -611 2 2 3 3 293 327 348 -612 2 2 3 3 294 328 329 -613 2 2 3 3 328 294 345 -614 2 2 3 3 294 337 345 -615 2 2 3 3 330 295 332 -616 2 2 3 3 295 330 333 -617 2 2 3 3 317 296 338 -618 2 2 3 3 296 317 344 -619 2 2 3 3 339 296 344 -620 2 2 3 3 297 303 304 -621 2 2 3 3 297 304 305 -622 2 2 3 3 297 305 342 -623 2 2 3 3 335 298 349 -624 2 2 3 3 298 340 343 -625 2 2 3 3 298 343 349 -626 2 2 3 3 299 320 331 -627 2 2 3 3 320 299 334 -628 2 2 3 3 299 331 346 -629 2 2 3 3 300 317 341 -630 2 2 3 3 317 300 350 -631 2 2 3 3 300 347 350 -632 2 2 3 3 305 301 342 -633 2 2 3 3 301 305 345 -634 2 2 3 3 337 301 345 -635 2 2 3 3 318 302 339 -636 2 2 3 3 302 318 343 -637 2 2 3 3 340 302 343 -638 2 2 3 3 304 303 333 -639 2 2 3 3 305 304 306 -640 2 2 3 3 306 304 322 -641 2 2 3 3 322 304 333 -642 2 2 3 3 305 306 307 -643 2 2 3 3 305 307 345 -644 2 2 3 3 307 306 308 -645 2 2 3 3 308 306 309 -646 2 2 3 3 309 306 322 -647 2 2 3 3 307 308 323 -648 2 2 3 3 307 323 328 -649 2 2 3 3 307 328 345 -650 2 2 3 3 308 309 310 -651 2 2 3 3 308 310 311 -652 2 2 3 3 308 311 323 -653 2 2 3 3 310 309 312 -654 2 2 3 3 312 309 314 -655 2 2 3 3 314 309 322 -656 2 2 3 3 311 310 313 -657 2 2 3 3 310 312 325 -658 2 2 3 3 313 310 325 -659 2 2 3 3 311 313 315 -660 2 2 3 3 311 315 316 -661 2 2 3 3 311 316 323 -662 2 2 3 3 312 314 320 -663 2 2 3 3 312 320 321 -664 2 2 3 3 312 321 325 -665 2 2 3 3 315 313 318 -666 2 2 3 3 318 313 319 -667 2 2 3 3 319 313 325 -668 2 2 3 3 320 314 331 -669 2 2 3 3 314 322 330 -670 2 2 3 3 314 330 331 -671 2 2 3 3 316 315 317 -672 2 2 3 3 317 315 344 -673 2 2 3 3 315 318 344 -674 2 2 3 3 316 317 350 -675 2 2 3 3 323 316 324 -676 2 2 3 3 324 316 350 -677 2 2 3 3 317 338 341 -678 2 2 3 3 318 319 343 -679 2 2 3 3 318 339 344 -680 2 2 3 3 319 325 326 -681 2 2 3 3 319 326 349 -682 2 2 3 3 343 319 349 -683 2 2 3 3 321 320 327 -684 2 2 3 3 327 320 334 -685 2 2 3 3 325 321 326 -686 2 2 3 3 326 321 336 -687 2 2 3 3 330 322 333 -688 2 2 3 3 323 324 328 -689 2 2 3 3 328 324 329 -690 2 2 3 3 329 324 347 -691 2 2 3 3 347 324 350 -692 2 2 3 3 326 336 349 -693 2 2 3 3 327 334 348 -694 2 2 3 3 331 330 332 -695 2 2 3 3 331 332 346 -696 2 2 3 3 336 335 349 -697 4 2 1 1 234 93 393 395 -698 4 2 1 1 161 393 385 441 -699 4 2 1 1 126 372 240 391 -700 4 2 1 1 182 361 397 430 -701 4 2 1 1 277 126 240 391 -702 4 2 1 1 367 386 352 399 -703 4 2 1 1 315 394 392 404 -704 4 2 1 1 381 397 182 422 -705 4 2 1 1 132 432 402 438 -706 4 2 1 1 199 381 337 398 -707 4 2 1 1 304 375 448 455 -708 4 2 1 1 249 376 370 396 -709 4 2 1 1 392 399 315 404 -710 4 2 1 1 402 432 359 438 -711 4 2 1 1 304 448 415 455 -712 4 2 1 1 356 389 368 400 -713 4 2 1 1 286 402 374 407 -714 4 2 1 1 310 366 312 379 -715 4 2 1 1 357 371 364 458 -716 4 2 1 1 376 396 249 436 -717 4 2 1 1 369 377 360 430 -718 4 2 1 1 385 393 93 395 -719 4 2 1 1 312 379 366 389 -720 4 2 1 1 299 97 346 373 -721 4 2 1 1 175 229 367 420 -722 4 2 1 1 11 381 182 422 -723 4 2 1 1 384 107 443 452 -724 4 2 1 1 219 337 199 381 -725 4 2 1 1 361 182 397 422 -726 4 2 1 1 182 169 361 430 -727 4 2 1 1 366 379 310 404 -728 4 2 1 1 132 155 402 432 -729 4 2 1 1 93 385 161 393 -730 4 2 1 1 291 240 372 391 -731 4 2 1 1 182 381 11 397 -732 4 2 1 1 378 383 359 464 -733 4 2 1 1 354 416 376 461 -734 4 2 1 1 303 375 304 455 -735 4 2 1 1 291 277 240 391 -736 4 2 1 1 366 352 386 399 -737 4 2 1 1 383 461 359 464 -738 4 2 1 1 344 392 315 394 -739 4 2 1 1 321 389 368 465 -740 4 2 1 1 373 389 331 393 -741 4 2 1 1 408 443 107 452 -742 4 2 1 1 369 397 377 430 -743 4 2 1 1 310 379 308 404 -744 4 2 1 1 376 416 363 461 -745 4 2 1 1 353 386 367 399 -746 4 2 1 1 355 369 377 417 -747 4 2 1 1 368 400 389 405 -748 4 2 1 1 304 322 415 448 -749 4 2 1 1 372 391 126 439 -750 4 2 1 1 258 382 407 444 -751 4 2 1 1 172 196 392 394 -752 4 2 1 1 364 371 357 453 -753 4 2 1 1 367 392 175 420 -754 4 2 1 1 309 310 312 379 -755 4 2 1 1 365 384 443 452 -756 4 2 1 1 357 364 409 458 -757 4 2 1 1 175 367 203 418 -758 4 2 1 1 363 416 376 426 -759 4 2 1 1 169 387 361 430 -760 4 2 1 1 364 401 371 453 -761 4 2 1 1 205 204 100 364 -762 4 2 1 1 370 376 249 424 -763 4 2 1 1 354 376 416 466 -764 4 2 1 1 364 356 385 428 -765 4 2 1 1 107 365 408 452 -766 4 2 1 1 204 364 205 425 -767 4 2 1 1 377 417 369 442 -768 4 2 1 1 365 443 408 452 -769 4 2 1 1 364 205 425 441 -770 4 2 1 1 164 406 362 421 -771 4 2 1 1 356 393 385 395 -772 4 2 1 1 367 386 353 420 -773 4 2 1 1 63 196 172 394 -774 4 2 1 1 249 396 370 431 -775 4 2 1 1 364 371 356 428 -776 4 2 1 1 315 316 394 404 -777 4 2 1 1 355 377 369 397 -778 4 2 1 1 100 205 364 441 -779 4 2 1 1 361 397 381 422 -780 4 2 1 1 161 373 393 441 -781 4 2 1 1 357 436 371 458 -782 4 2 1 1 267 380 363 456 -783 4 2 1 1 356 364 385 441 -784 4 2 1 1 355 377 397 411 -785 4 2 1 1 394 404 316 459 -786 4 2 1 1 182 397 74 430 -787 4 2 1 1 361 316 404 459 -788 4 2 1 1 364 401 384 468 -789 4 2 1 1 356 371 364 401 -790 4 2 1 1 361 387 170 394 -791 4 2 1 1 359 383 378 432 -792 4 2 1 1 311 310 308 404 -793 4 2 1 1 362 433 447 457 -794 4 2 1 1 286 402 407 414 -795 4 2 1 1 359 386 367 420 -796 4 2 1 1 365 406 362 453 -797 4 2 1 1 172 392 296 394 -798 4 2 1 1 416 461 383 464 -799 4 2 1 1 308 404 379 411 -800 4 2 1 1 131 132 402 438 -801 4 2 1 1 338 63 296 394 -802 4 2 1 1 367 386 359 445 -803 4 2 1 1 361 404 316 411 -804 4 2 1 1 385 425 205 441 -805 4 2 1 1 368 389 321 405 -806 4 2 1 1 360 377 369 442 -807 4 2 1 1 361 387 377 430 -808 4 2 1 1 238 374 286 402 -809 4 2 1 1 364 425 385 441 -810 4 2 1 1 369 397 9 454 -811 4 2 1 1 363 380 267 437 -812 4 2 1 1 352 386 367 445 -813 4 2 1 1 9 369 423 430 -814 4 2 1 1 368 380 356 400 -815 4 2 1 1 299 97 373 393 -816 4 2 1 1 364 410 401 468 -817 4 2 1 1 186 369 9 454 -818 4 2 1 1 353 377 361 387 -819 4 2 1 1 170 361 169 387 -820 4 2 1 1 313 366 310 404 -821 4 2 1 1 362 406 164 447 -822 4 2 1 1 327 320 321 465 -823 4 2 1 1 392 394 353 404 -824 4 2 1 1 175 392 367 418 -825 4 2 1 1 355 379 375 417 -826 4 2 1 1 352 367 439 445 -827 4 2 1 1 105 384 107 443 -828 4 2 1 1 363 414 267 456 -829 4 2 1 1 376 426 416 466 -830 4 2 1 1 385 393 356 441 -831 4 2 1 1 372 439 367 445 -832 4 2 1 1 63 172 296 394 -833 4 2 1 1 352 399 366 405 -834 4 2 1 1 203 175 229 367 -835 4 2 1 1 384 401 443 468 -836 4 2 1 1 9 397 369 430 -837 4 2 1 1 361 377 397 430 -838 4 2 1 1 318 315 392 399 -839 4 2 1 1 164 112 406 421 -840 4 2 1 1 248 436 247 450 -841 4 2 1 1 247 436 396 450 -842 4 2 1 1 219 294 337 381 -843 4 2 1 1 269 395 380 428 -844 4 2 1 1 313 399 366 404 -845 4 2 1 1 286 407 257 414 -846 4 2 1 1 357 409 436 458 -847 4 2 1 1 361 394 170 459 -848 4 2 1 1 241 385 93 395 -849 4 2 1 1 313 325 366 399 -850 4 2 1 1 75 447 433 457 -851 4 2 1 1 319 399 388 405 -852 4 2 1 1 310 313 325 366 -853 4 2 1 1 304 415 333 455 -854 4 2 1 1 377 387 360 430 -855 4 2 1 1 356 368 389 393 -856 4 2 1 1 286 374 238 444 -857 4 2 1 1 333 303 304 455 -858 4 2 1 1 156 374 238 402 -859 4 2 1 1 158 375 303 455 -860 4 2 1 1 364 428 385 458 -861 4 2 1 1 353 361 377 404 -862 4 2 1 1 320 389 321 465 -863 4 2 1 1 374 402 155 432 -864 4 2 1 1 361 397 377 411 -865 4 2 1 1 356 400 380 460 -866 4 2 1 1 351 377 366 386 -867 4 2 1 1 352 439 372 445 -868 4 2 1 1 184 107 365 408 -869 4 2 1 1 184 403 365 421 -870 4 2 1 1 131 132 155 402 -871 4 2 1 1 388 399 319 418 -872 4 2 1 1 353 399 392 404 -873 4 2 1 1 6 433 390 457 -874 4 2 1 1 410 443 401 468 -875 4 2 1 1 198 361 169 459 -876 4 2 1 1 182 361 198 422 -877 4 2 1 1 374 407 382 444 -878 4 2 1 1 325 366 399 405 -879 4 2 1 1 349 388 319 418 -880 4 2 1 1 312 389 366 405 -881 4 2 1 1 316 324 350 422 -882 4 2 1 1 362 406 365 421 -883 4 2 1 1 219 199 88 381 -884 4 2 1 1 358 443 365 453 -885 4 2 1 1 352 388 367 399 -886 4 2 1 1 364 371 428 458 -887 4 2 1 1 389 393 368 465 -888 4 2 1 1 95 368 395 465 -889 4 2 1 1 320 331 389 393 -890 4 2 1 1 369 417 365 442 -891 4 2 1 1 363 416 426 460 -892 4 2 1 1 182 74 169 430 -893 4 2 1 1 356 380 371 460 -894 4 2 1 1 253 407 376 456 -895 4 2 1 1 224 381 199 398 -896 4 2 1 1 352 400 368 405 -897 4 2 1 1 253 376 250 456 -898 4 2 1 1 107 184 365 452 -899 4 2 1 1 246 436 248 450 -900 4 2 1 1 316 323 324 411 -901 4 2 1 1 337 381 345 398 -902 4 2 1 1 374 407 402 461 -903 4 2 1 1 355 403 369 417 -904 4 2 1 1 353 366 386 399 -905 4 2 1 1 355 375 408 417 -906 4 2 1 1 107 384 105 452 -907 4 2 1 1 406 365 452 453 -908 4 2 1 1 383 390 354 416 -909 4 2 1 1 358 365 417 453 -910 4 2 1 1 353 366 377 386 -911 4 2 1 1 311 404 308 411 -912 4 2 1 1 360 390 383 416 -913 4 2 1 1 383 432 359 461 -914 4 2 1 1 407 414 402 461 -915 4 2 1 1 258 407 382 424 -916 4 2 1 1 338 341 189 394 -917 4 2 1 1 307 381 411 449 -918 4 2 1 1 6 75 433 457 -919 4 2 1 1 361 404 394 459 -920 4 2 1 1 253 250 376 424 -921 4 2 1 1 352 380 368 400 -922 4 2 1 1 363 267 414 437 -923 4 2 1 1 376 407 354 461 -924 4 2 1 1 346 97 332 373 -925 4 2 1 1 375 379 358 417 -926 4 2 1 1 238 374 156 444 -927 4 2 1 1 365 403 184 408 -928 4 2 1 1 316 361 422 459 -929 4 2 1 1 277 85 126 391 -930 4 2 1 1 246 248 247 450 -931 4 2 1 1 416 442 377 464 -932 4 2 1 1 375 379 355 449 -933 4 2 1 1 100 364 204 468 -934 4 2 1 1 312 366 325 405 -935 4 2 1 1 162 391 388 439 -936 4 2 1 1 376 407 253 424 -937 4 2 1 1 255 267 414 456 -938 4 2 1 1 303 375 158 470 -939 4 2 1 1 355 403 408 451 -940 4 2 1 1 360 377 442 464 -941 4 2 1 1 331 299 346 373 -942 4 2 1 1 362 390 433 457 -943 4 2 1 1 269 380 395 435 -944 4 2 1 1 365 421 406 452 -945 4 2 1 1 364 425 204 468 -946 4 2 1 1 100 364 410 441 -947 4 2 1 1 355 408 375 451 -948 4 2 1 1 363 407 376 461 -949 4 2 1 1 196 392 394 413 -950 4 2 1 1 304 375 303 470 -951 4 2 1 1 369 403 365 417 -952 4 2 1 1 133 175 392 420 -953 4 2 1 1 360 442 416 464 -954 4 2 1 1 351 377 416 442 -955 4 2 1 1 351 417 377 442 -956 4 2 1 1 299 86 97 393 -957 4 2 1 1 164 421 362 457 -958 4 2 1 1 187 397 381 419 -959 4 2 1 1 184 110 114 421 -960 4 2 1 1 178 384 179 468 -961 4 2 1 1 366 386 352 400 -962 4 2 1 1 354 382 374 407 -963 4 2 1 1 355 408 403 417 -964 4 2 1 1 133 392 413 420 -965 4 2 1 1 338 317 341 394 -966 4 2 1 1 95 395 368 435 -967 4 2 1 1 310 325 312 366 -968 4 2 1 1 356 380 368 395 -969 4 2 1 1 193 403 125 454 -970 4 2 1 1 353 394 361 404 -971 4 2 1 1 351 386 366 400 -972 4 2 1 1 155 374 156 402 -973 4 2 1 1 351 416 377 464 -974 4 2 1 1 212 394 387 413 -975 4 2 1 1 351 365 442 453 -976 4 2 1 1 353 387 361 394 -977 4 2 1 1 389 400 366 405 -978 4 2 1 1 140 387 378 413 -979 4 2 1 1 296 392 344 394 -980 4 2 1 1 178 409 384 468 -981 4 2 1 1 366 377 351 434 -982 4 2 1 1 367 438 372 445 -983 4 2 1 1 94 388 162 391 -984 4 2 1 1 320 393 389 465 -985 4 2 1 1 291 391 372 437 -986 4 2 1 1 95 228 395 435 -987 4 2 1 1 212 387 140 413 -988 4 2 1 1 169 198 182 361 -989 4 2 1 1 184 114 193 403 -990 4 2 1 1 286 259 257 444 -991 4 2 1 1 353 420 386 464 -992 4 2 1 1 249 270 370 424 -993 4 2 1 1 304 322 333 415 -994 4 2 1 1 406 426 362 453 -995 4 2 1 1 370 396 376 467 -996 4 2 1 1 107 110 184 452 -997 4 2 1 1 371 380 356 428 -998 4 2 1 1 360 387 377 464 -999 4 2 1 1 358 401 443 453 -1000 4 2 1 1 351 377 386 464 -1001 4 2 1 1 132 420 432 438 -1002 4 2 1 1 241 385 395 428 -1003 4 2 1 1 175 133 229 420 -1004 4 2 1 1 306 322 304 449 -1005 4 2 1 1 169 361 170 459 -1006 4 2 1 1 358 417 401 453 -1007 4 2 1 1 382 412 188 433 -1008 4 2 1 1 351 365 417 442 -1009 4 2 1 1 345 381 307 449 -1010 4 2 1 1 316 422 350 459 -1011 4 2 1 1 125 403 421 454 -1012 4 2 1 1 377 379 366 404 -1013 4 2 1 1 239 247 284 450 -1014 4 2 1 1 287 249 370 431 -1015 4 2 1 1 145 374 155 432 -1016 4 2 1 1 142 212 170 387 -1017 4 2 1 1 125 403 193 421 -1018 4 2 1 1 344 318 315 392 -1019 4 2 1 1 299 373 331 393 -1020 4 2 1 1 184 114 403 421 -1021 4 2 1 1 360 416 383 464 -1022 4 2 1 1 240 372 126 462 -1023 4 2 1 1 353 377 366 404 -1024 4 2 1 1 345 398 381 449 -1025 4 2 1 1 328 324 411 422 -1026 4 2 1 1 359 432 420 438 -1027 4 2 1 1 140 378 387 446 -1028 4 2 1 1 352 380 400 445 -1029 4 2 1 1 304 303 297 470 -1030 4 2 1 1 363 400 380 445 -1031 4 2 1 1 188 382 150 412 -1032 4 2 1 1 180 204 425 468 -1033 4 2 1 1 355 397 381 411 -1034 4 2 1 1 352 388 399 405 -1035 4 2 1 1 359 386 420 464 -1036 4 2 1 1 352 366 400 405 -1037 4 2 1 1 224 88 199 381 -1038 4 2 1 1 364 356 401 441 -1039 4 2 1 1 384 443 401 453 -1040 4 2 1 1 249 250 376 436 -1041 4 2 1 1 267 255 252 456 -1042 4 2 1 1 198 422 361 459 -1043 4 2 1 1 374 402 359 461 -1044 4 2 1 1 129 203 367 439 -1045 4 2 1 1 363 426 376 460 -1046 4 2 1 1 179 384 178 427 -1047 4 2 1 1 170 169 142 387 -1048 4 2 1 1 170 387 212 394 -1049 4 2 1 1 317 315 316 394 -1050 4 2 1 1 351 386 416 464 -1051 4 2 1 1 382 188 429 433 -1052 4 2 1 1 355 377 379 417 -1053 4 2 1 1 274 160 288 385 -1054 4 2 1 1 186 369 68 423 -1055 4 2 1 1 416 442 390 466 -1056 4 2 1 1 365 362 421 442 -1057 4 2 1 1 77 373 99 415 -1058 4 2 1 1 357 371 426 453 -1059 4 2 1 1 193 403 114 421 -1060 4 2 1 1 129 203 229 367 -1061 4 2 1 1 315 399 313 404 -1062 4 2 1 1 328 411 381 422 -1063 4 2 1 1 359 402 414 461 -1064 4 2 1 1 366 379 377 434 -1065 4 2 1 1 364 384 357 409 -1066 4 2 1 1 183 383 378 446 -1067 4 2 1 1 367 359 438 445 -1068 4 2 1 1 379 417 377 434 -1069 4 2 1 1 357 396 436 450 -1070 4 2 1 1 351 400 366 434 -1071 4 2 1 1 189 63 338 394 -1072 4 2 1 1 129 206 203 439 -1073 4 2 1 1 10 182 11 397 -1074 4 2 1 1 140 378 137 413 -1075 4 2 1 1 155 145 156 374 -1076 4 2 1 1 125 68 186 369 -1077 4 2 1 1 186 125 369 454 -1078 4 2 1 1 11 381 187 397 -1079 4 2 1 1 353 377 387 464 -1080 4 2 1 1 375 448 379 449 -1081 4 2 1 1 356 371 401 460 -1082 4 2 1 1 97 77 332 373 -1083 4 2 1 1 77 332 373 415 -1084 4 2 1 1 125 68 369 421 -1085 4 2 1 1 306 448 322 449 -1086 4 2 1 1 354 382 424 433 -1087 4 2 1 1 358 379 375 448 -1088 4 2 1 1 249 248 250 436 -1089 4 2 1 1 379 404 377 411 -1090 4 2 1 1 178 384 409 427 -1091 4 2 1 1 100 410 364 468 -1092 4 2 1 1 378 383 183 432 -1093 4 2 1 1 70 303 333 455 -1094 4 2 1 1 426 453 371 460 -1095 4 2 1 1 247 396 284 450 -1096 4 2 1 1 261 291 285 372 -1097 4 2 1 1 83 288 160 385 -1098 4 2 1 1 383 390 360 463 -1099 4 2 1 1 286 260 402 414 -1100 4 2 1 1 12 294 381 422 -1101 4 2 1 1 307 381 328 411 -1102 4 2 1 1 267 254 380 456 -1103 4 2 1 1 355 379 377 411 -1104 4 2 1 1 249 270 287 370 -1105 4 2 1 1 194 210 412 463 -1106 4 2 1 1 371 380 254 456 -1107 4 2 1 1 77 98 99 373 -1108 4 2 1 1 401 371 453 460 -1109 4 2 1 1 396 436 376 467 -1110 4 2 1 1 353 392 367 420 -1111 4 2 1 1 151 430 423 463 -1112 4 2 1 1 382 444 213 469 -1113 4 2 1 1 366 399 353 404 -1114 4 2 1 1 254 380 371 428 -1115 4 2 1 1 357 384 364 453 -1116 4 2 1 1 365 358 408 443 -1117 4 2 1 1 89 223 188 429 -1118 4 2 1 1 253 252 407 456 -1119 4 2 1 1 362 447 164 457 -1120 4 2 1 1 80 199 337 398 -1121 4 2 1 1 179 178 231 427 -1122 4 2 1 1 368 380 352 435 -1123 4 2 1 1 287 370 270 431 -1124 4 2 1 1 149 194 210 412 -1125 4 2 1 1 269 380 263 428 -1126 4 2 1 1 136 378 183 432 -1127 4 2 1 1 133 392 173 413 -1128 4 2 1 1 331 346 332 373 -1129 4 2 1 1 140 139 378 446 -1130 4 2 1 1 291 240 285 372 -1131 4 2 1 1 317 338 296 394 -1132 4 2 1 1 205 161 385 441 -1133 4 2 1 1 354 416 390 466 -1134 4 2 1 1 381 397 361 411 -1135 4 2 1 1 284 396 191 450 -1136 4 2 1 1 133 175 173 392 -1137 4 2 1 1 99 373 410 415 -1138 4 2 1 1 229 367 420 438 -1139 4 2 1 1 365 408 358 417 -1140 4 2 1 1 291 372 261 437 -1141 4 2 1 1 365 421 369 442 -1142 4 2 1 1 228 290 395 435 -1143 4 2 1 1 98 373 161 441 -1144 4 2 1 1 374 382 354 469 -1145 4 2 1 1 289 382 200 429 -1146 4 2 1 1 317 394 316 459 -1147 4 2 1 1 227 293 368 465 -1148 4 2 1 1 311 316 404 411 -1149 4 2 1 1 140 139 137 378 -1150 4 2 1 1 384 365 443 453 -1151 4 2 1 1 158 303 70 455 -1152 4 2 1 1 198 169 170 459 -1153 4 2 1 1 284 243 191 396 -1154 4 2 1 1 368 393 356 395 -1155 4 2 1 1 151 446 430 463 -1156 4 2 1 1 372 352 391 439 -1157 4 2 1 1 301 80 337 398 -1158 4 2 1 1 396 406 211 427 -1159 4 2 1 1 112 406 421 452 -1160 4 2 1 1 356 401 400 460 -1161 4 2 1 1 351 442 426 453 -1162 4 2 1 1 331 373 330 448 -1163 4 2 1 1 326 405 388 440 -1164 4 2 1 1 125 421 369 454 -1165 4 2 1 1 253 265 250 424 -1166 4 2 1 1 194 412 383 463 -1167 4 2 1 1 381 398 355 449 -1168 4 2 1 1 189 394 341 459 -1169 4 2 1 1 71 392 175 418 -1170 4 2 1 1 369 421 68 457 -1171 4 2 1 1 100 98 205 441 -1172 4 2 1 1 343 349 319 418 -1173 4 2 1 1 286 257 260 414 -1174 4 2 1 1 381 355 411 449 -1175 4 2 1 1 382 412 354 469 -1176 4 2 1 1 370 424 382 433 -1177 4 2 1 1 241 93 276 395 -1178 4 2 1 1 126 127 372 439 -1179 4 2 1 1 181 90 4 370 -1180 4 2 1 1 223 382 188 429 -1181 4 2 1 1 227 368 95 465 -1182 4 2 1 1 368 352 391 435 -1183 4 2 1 1 377 417 351 434 -1184 4 2 1 1 137 378 134 413 -1185 4 2 1 1 92 234 393 395 -1186 4 2 1 1 357 426 371 436 -1187 4 2 1 1 224 381 398 419 -1188 4 2 1 1 183 378 139 446 -1189 4 2 1 1 99 373 98 410 -1190 4 2 1 1 96 368 227 440 -1191 4 2 1 1 12 219 88 381 -1192 4 2 1 1 370 382 429 433 -1193 4 2 1 1 367 392 353 399 -1194 4 2 1 1 360 383 378 464 -1195 4 2 1 1 302 392 71 418 -1196 4 2 1 1 366 389 379 434 -1197 4 2 1 1 362 390 442 466 -1198 4 2 1 1 323 328 324 411 -1199 4 2 1 1 4 370 90 429 -1200 4 2 1 1 341 394 317 459 -1201 4 2 1 1 92 93 234 395 -1202 4 2 1 1 354 412 382 433 -1203 4 2 1 1 186 68 8 423 -1204 4 2 1 1 358 408 375 417 -1205 4 2 1 1 12 294 219 381 -1206 4 2 1 1 90 370 181 431 -1207 4 2 1 1 149 383 194 412 -1208 4 2 1 1 136 139 183 378 -1209 4 2 1 1 382 424 370 429 -1210 4 2 1 1 71 175 203 418 -1211 4 2 1 1 11 187 10 397 -1212 4 2 1 1 311 323 316 411 -1213 4 2 1 1 255 407 252 456 -1214 4 2 1 1 351 417 365 453 -1215 4 2 1 1 384 409 364 468 -1216 4 2 1 1 369 68 423 457 -1217 4 2 1 1 100 410 98 441 -1218 4 2 1 1 214 121 419 451 -1219 4 2 1 1 227 368 293 440 -1220 4 2 1 1 354 383 416 461 -1221 4 2 1 1 169 168 387 430 -1222 4 2 1 1 129 367 229 438 -1223 4 2 1 1 188 223 150 382 -1224 4 2 1 1 222 429 90 431 -1225 4 2 1 1 374 432 138 469 -1226 4 2 1 1 371 426 376 436 -1227 4 2 1 1 289 81 200 382 -1228 4 2 1 1 249 265 270 424 -1229 4 2 1 1 4 181 370 433 -1230 4 2 1 1 246 409 436 450 -1231 4 2 1 1 274 160 385 425 -1232 4 2 1 1 285 261 372 414 -1233 4 2 1 1 337 294 345 381 -1234 4 2 1 1 375 358 448 455 -1235 4 2 1 1 384 401 364 453 -1236 4 2 1 1 355 369 403 454 -1237 4 2 1 1 354 382 407 424 -1238 4 2 1 1 345 328 307 381 -1239 4 2 1 1 374 432 383 461 -1240 4 2 1 1 106 107 408 443 -1241 4 2 1 1 230 100 204 468 -1242 4 2 1 1 318 313 315 399 -1243 4 2 1 1 388 391 352 439 -1244 4 2 1 1 96 435 368 440 -1245 4 2 1 1 372 438 367 439 -1246 4 2 1 1 269 263 380 435 -1247 4 2 1 1 116 375 226 455 -1248 4 2 1 1 95 368 96 435 -1249 4 2 1 1 176 245 177 450 -1250 4 2 1 1 354 433 424 466 -1251 4 2 1 1 359 402 374 432 -1252 4 2 1 1 180 230 204 468 -1253 4 2 1 1 352 367 388 439 -1254 4 2 1 1 317 344 315 394 -1255 4 2 1 1 352 368 391 440 -1256 4 2 1 1 368 405 321 440 -1257 4 2 1 1 269 262 395 428 -1258 4 2 1 1 355 397 369 454 -1259 4 2 1 1 75 164 447 457 -1260 4 2 1 1 318 399 392 418 -1261 4 2 1 1 354 374 383 461 -1262 4 2 1 1 104 178 179 468 -1263 4 2 1 1 127 128 372 439 -1264 4 2 1 1 321 389 312 405 -1265 4 2 1 1 363 380 371 456 -1266 4 2 1 1 184 109 107 408 -1267 4 2 1 1 389 400 356 471 -1268 4 2 1 1 255 253 252 407 -1269 4 2 1 1 183 194 383 463 -1270 4 2 1 1 224 88 381 419 -1271 4 2 1 1 386 416 363 460 -1272 4 2 1 1 176 409 245 450 -1273 4 2 1 1 210 390 73 412 -1274 4 2 1 1 192 396 211 427 -1275 4 2 1 1 90 429 370 431 -1276 4 2 1 1 372 414 261 437 -1277 4 2 1 1 116 226 375 451 -1278 4 2 1 1 353 386 377 464 -1279 4 2 1 1 318 343 399 418 -1280 4 2 1 1 92 395 393 465 -1281 4 2 1 1 138 145 374 469 -1282 4 2 1 1 183 143 194 463 -1283 4 2 1 1 240 285 372 462 -1284 4 2 1 1 138 146 145 469 -1285 4 2 1 1 401 410 358 443 -1286 4 2 1 1 173 172 196 392 -1287 4 2 1 1 180 409 178 468 -1288 4 2 1 1 426 453 406 467 -1289 4 2 1 1 116 117 226 451 -1290 4 2 1 1 134 413 378 420 -1291 4 2 1 1 214 419 398 451 -1292 4 2 1 1 153 213 444 469 -1293 4 2 1 1 145 225 156 374 -1294 4 2 1 1 67 151 423 463 -1295 4 2 1 1 164 112 113 406 -1296 4 2 1 1 284 247 243 396 -1297 4 2 1 1 106 105 107 443 -1298 4 2 1 1 357 406 453 467 -1299 4 2 1 1 181 431 370 447 -1300 4 2 1 1 156 374 225 444 -1301 4 2 1 1 296 344 317 394 -1302 4 2 1 1 179 384 427 452 -1303 4 2 1 1 290 269 395 435 -1304 4 2 1 1 75 163 164 457 -1305 4 2 1 1 369 360 423 430 -1306 4 2 1 1 362 426 406 467 -1307 4 2 1 1 212 144 394 413 -1308 4 2 1 1 120 403 419 451 -1309 4 2 1 1 375 408 116 451 -1310 4 2 1 1 84 206 388 418 -1311 4 2 1 1 240 78 282 462 -1312 4 2 1 1 380 391 352 435 -1313 4 2 1 1 371 380 363 460 -1314 4 2 1 1 388 418 206 439 -1315 4 2 1 1 353 413 392 420 -1316 4 2 1 1 227 96 95 368 -1317 4 2 1 1 321 293 368 440 -1318 4 2 1 1 134 378 136 432 -1319 4 2 1 1 376 426 371 460 -1320 4 2 1 1 214 119 121 451 -1321 4 2 1 1 205 98 161 441 -1322 4 2 1 1 343 319 399 418 -1323 4 2 1 1 373 98 410 441 -1324 4 2 1 1 11 12 381 422 -1325 4 2 1 1 386 400 363 445 -1326 4 2 1 1 354 407 376 424 -1327 4 2 1 1 243 82 396 431 -1328 4 2 1 1 112 421 110 452 -1329 4 2 1 1 241 395 262 428 -1330 4 2 1 1 97 161 98 373 -1331 4 2 1 1 367 399 388 418 -1332 4 2 1 1 326 321 405 440 -1333 4 2 1 1 87 11 182 422 -1334 4 2 1 1 128 438 372 439 -1335 4 2 1 1 320 299 331 393 -1336 4 2 1 1 371 436 251 458 -1337 4 2 1 1 237 409 69 425 -1338 4 2 1 1 171 339 172 392 -1339 4 2 1 1 264 436 409 458 -1340 4 2 1 1 390 412 210 463 -1341 4 2 1 1 127 372 128 462 -1342 4 2 1 1 12 329 294 422 -1343 4 2 1 1 424 433 370 466 -1344 4 2 1 1 365 403 369 421 -1345 4 2 1 1 274 288 273 385 -1346 4 2 1 1 302 171 71 392 -1347 4 2 1 1 84 388 298 418 -1348 4 2 1 1 134 420 378 432 -1349 4 2 1 1 236 429 222 431 -1350 4 2 1 1 332 330 331 373 -1351 4 2 1 1 226 375 158 455 -1352 4 2 1 1 95 96 228 435 -1353 4 2 1 1 356 393 389 471 -1354 4 2 1 1 145 138 374 432 -1355 4 2 1 1 400 401 356 471 -1356 4 2 1 1 409 357 436 450 -1357 4 2 1 1 352 391 380 437 -1358 4 2 1 1 146 374 145 469 -1359 4 2 1 1 357 453 426 467 -1360 4 2 1 1 8 9 423 430 -1361 4 2 1 1 181 370 433 447 -1362 4 2 1 1 202 431 181 447 -1363 4 2 1 1 352 372 391 437 -1364 4 2 1 1 118 408 403 451 -1365 4 2 1 1 310 309 308 379 -1366 4 2 1 1 363 400 386 460 -1367 4 2 1 1 372 285 414 462 -1368 4 2 1 1 352 437 380 445 -1369 4 2 1 1 390 416 360 442 -1370 4 2 1 1 264 246 409 436 -1371 4 2 1 1 200 382 223 429 -1372 4 2 1 1 76 397 187 419 -1373 4 2 1 1 171 302 339 392 -1374 4 2 1 1 269 263 262 428 -1375 4 2 1 1 359 402 372 414 -1376 4 2 1 1 134 137 136 378 -1377 4 2 1 1 364 401 410 441 -1378 4 2 1 1 187 381 88 419 -1379 4 2 1 1 374 354 383 469 -1380 4 2 1 1 144 212 140 413 -1381 4 2 1 1 363 380 437 445 -1382 4 2 1 1 122 421 164 457 -1383 4 2 1 1 153 148 213 469 -1384 4 2 1 1 306 379 448 449 -1385 4 2 1 1 357 409 384 427 -1386 4 2 1 1 155 132 135 432 -1387 4 2 1 1 117 116 408 451 -1388 4 2 1 1 293 327 321 465 -1389 4 2 1 1 147 194 149 383 -1390 4 2 1 1 176 69 237 409 -1391 4 2 1 1 369 421 403 454 -1392 4 2 1 1 330 373 332 415 -1393 4 2 1 1 240 126 78 462 -1394 4 2 1 1 4 370 429 433 -1395 4 2 1 1 354 390 383 412 -1396 4 2 1 1 351 416 386 460 -1397 4 2 1 1 325 399 319 405 -1398 4 2 1 1 109 408 118 451 -1399 4 2 1 1 67 423 151 430 -1400 4 2 1 1 92 276 93 395 -1401 4 2 1 1 378 383 360 446 -1402 4 2 1 1 84 335 298 388 -1403 4 2 1 1 330 373 415 448 -1404 4 2 1 1 95 395 92 465 -1405 4 2 1 1 335 388 94 440 -1406 4 2 1 1 356 373 393 471 -1407 4 2 1 1 160 205 385 425 -1408 4 2 1 1 370 429 270 431 -1409 4 2 1 1 430 446 360 463 -1410 4 2 1 1 376 407 363 456 -1411 4 2 1 1 273 274 385 425 -1412 4 2 1 1 92 234 208 393 -1413 4 2 1 1 331 330 314 448 -1414 4 2 1 1 266 382 289 429 -1415 4 2 1 1 368 352 405 440 -1416 4 2 1 1 356 395 385 428 -1417 4 2 1 1 213 382 81 444 -1418 4 2 1 1 357 436 396 467 -1419 4 2 1 1 164 406 113 447 -1420 4 2 1 1 256 371 251 458 -1421 4 2 1 1 77 295 332 415 -1422 4 2 1 1 260 414 285 462 -1423 4 2 1 1 423 430 360 463 -1424 4 2 1 1 183 383 138 432 -1425 4 2 1 1 380 400 363 460 -1426 4 2 1 1 373 356 393 441 -1427 4 2 1 1 132 420 134 432 -1428 4 2 1 1 377 404 361 411 -1429 4 2 1 1 120 419 403 454 -1430 4 2 1 1 386 359 461 464 -1431 4 2 1 1 357 376 426 436 -1432 4 2 1 1 229 420 130 438 -1433 4 2 1 1 149 383 412 469 -1434 4 2 1 1 426 442 416 466 -1435 4 2 1 1 311 313 310 404 -1436 4 2 1 1 389 393 373 471 -1437 4 2 1 1 304 449 375 470 -1438 4 2 1 1 349 336 326 388 -1439 4 2 1 1 228 290 276 395 -1440 4 2 1 1 6 390 7 457 -1441 4 2 1 1 359 414 372 445 -1442 4 2 1 1 169 168 142 387 -1443 4 2 1 1 357 427 396 450 -1444 4 2 1 1 384 357 427 452 -1445 4 2 1 1 228 235 290 435 -1446 4 2 1 1 98 77 97 373 -1447 4 2 1 1 245 409 275 450 -1448 4 2 1 1 192 396 427 450 -1449 4 2 1 1 192 66 191 450 -1450 4 2 1 1 337 345 301 398 -1451 4 2 1 1 318 392 302 418 -1452 4 2 1 1 378 387 353 413 -1453 4 2 1 1 116 226 158 455 -1454 4 2 1 1 409 425 272 458 -1455 4 2 1 1 147 138 183 383 -1456 4 2 1 1 357 406 452 453 -1457 4 2 1 1 209 193 125 454 -1458 4 2 1 1 381 411 361 422 -1459 4 2 1 1 192 191 396 450 -1460 4 2 1 1 226 158 375 470 -1461 4 2 1 1 242 81 289 382 -1462 4 2 1 1 392 399 367 418 -1463 4 2 1 1 376 371 456 460 -1464 4 2 1 1 83 205 161 385 -1465 4 2 1 1 298 388 349 418 -1466 4 2 1 1 251 371 254 456 -1467 4 2 1 1 149 147 383 469 -1468 4 2 1 1 370 424 270 429 -1469 4 2 1 1 235 96 207 435 -1470 4 2 1 1 389 434 400 471 -1471 4 2 1 1 403 408 365 417 -1472 4 2 1 1 366 400 389 434 -1473 4 2 1 1 176 275 245 409 -1474 4 2 1 1 314 320 331 389 -1475 4 2 1 1 179 427 115 452 -1476 4 2 1 1 73 412 390 433 -1477 4 2 1 1 367 359 420 438 -1478 4 2 1 1 168 141 387 446 -1479 4 2 1 1 168 387 430 446 -1480 4 2 1 1 266 292 382 424 -1481 4 2 1 1 224 187 88 419 -1482 4 2 1 1 190 212 144 394 -1483 4 2 1 1 179 115 108 452 -1484 4 2 1 1 147 138 383 469 -1485 4 2 1 1 326 388 336 440 -1486 4 2 1 1 176 177 409 450 -1487 4 2 1 1 266 424 382 429 -1488 4 2 1 1 122 112 164 421 -1489 4 2 1 1 268 435 391 437 -1490 4 2 1 1 133 173 174 413 -1491 4 2 1 1 127 128 78 462 -1492 4 2 1 1 356 380 395 428 -1493 4 2 1 1 210 73 218 412 -1494 4 2 1 1 12 88 11 381 -1495 4 2 1 1 359 420 378 464 -1496 4 2 1 1 308 411 379 449 -1497 4 2 1 1 293 321 368 465 -1498 4 2 1 1 181 433 75 447 -1499 4 2 1 1 371 256 428 458 -1500 4 2 1 1 386 461 416 464 -1501 4 2 1 1 208 92 393 465 -1502 4 2 1 1 296 172 339 392 -1503 4 2 1 1 102 415 410 455 -1504 4 2 1 1 273 425 385 458 -1505 4 2 1 1 363 416 386 461 -1506 4 2 1 1 367 438 129 439 -1507 4 2 1 1 304 305 449 470 -1508 4 2 1 1 352 400 386 445 -1509 4 2 1 1 258 382 292 424 -1510 4 2 1 1 260 402 414 462 -1511 4 2 1 1 70 333 415 455 -1512 4 2 1 1 381 397 355 419 -1513 4 2 1 1 292 289 266 382 -1514 4 2 1 1 353 387 378 464 -1515 4 2 1 1 388 405 352 440 -1516 4 2 1 1 235 207 278 435 -1517 4 2 1 1 94 335 84 388 -1518 4 2 1 1 254 251 256 371 -1519 4 2 1 1 218 188 150 412 -1520 4 2 1 1 372 402 359 438 -1521 4 2 1 1 410 441 401 471 -1522 4 2 1 1 196 394 144 413 -1523 4 2 1 1 357 452 384 453 -1524 4 2 1 1 343 318 302 418 -1525 4 2 1 1 7 390 185 423 -1526 4 2 1 1 238 281 72 402 -1527 4 2 1 1 323 311 308 411 -1528 4 2 1 1 90 181 202 431 -1529 4 2 1 1 102 410 443 455 -1530 4 2 1 1 67 151 167 430 -1531 4 2 1 1 174 137 134 413 -1532 4 2 1 1 294 328 381 422 -1533 4 2 1 1 400 434 401 471 -1534 4 2 1 1 176 237 275 409 -1535 4 2 1 1 138 432 383 469 -1536 4 2 1 1 362 433 390 466 -1537 4 2 1 1 227 348 293 465 -1538 4 2 1 1 384 443 105 468 -1539 4 2 1 1 63 190 196 394 -1540 4 2 1 1 351 386 400 460 -1541 4 2 1 1 391 435 380 437 -1542 4 2 1 1 104 180 178 468 -1543 4 2 1 1 351 401 400 434 -1544 4 2 1 1 114 110 112 421 -1545 4 2 1 1 254 371 256 428 -1546 4 2 1 1 362 447 433 466 -1547 4 2 1 1 7 6 185 390 -1548 4 2 1 1 7 390 423 457 -1549 4 2 1 1 264 409 272 458 -1550 4 2 1 1 351 401 417 453 -1551 4 2 1 1 212 142 140 387 -1552 4 2 1 1 406 427 357 452 -1553 4 2 1 1 243 396 247 431 -1554 4 2 1 1 233 391 207 440 -1555 4 2 1 1 131 438 402 462 -1556 4 2 1 1 82 191 243 396 -1557 4 2 1 1 352 391 388 440 -1558 4 2 1 1 354 412 383 469 -1559 4 2 1 1 160 205 83 385 -1560 4 2 1 1 182 10 74 397 -1561 4 2 1 1 375 398 355 451 -1562 4 2 1 1 390 442 423 457 -1563 4 2 1 1 80 398 301 470 -1564 4 2 1 1 6 163 75 457 -1565 4 2 1 1 139 136 137 378 -1566 4 2 1 1 89 200 223 429 -1567 4 2 1 1 84 388 206 439 -1568 4 2 1 1 374 359 432 461 -1569 4 2 1 1 363 376 456 460 -1570 4 2 1 1 360 423 390 442 -1571 4 2 1 1 67 167 423 430 -1572 4 2 1 1 11 87 12 422 -1573 4 2 1 1 387 394 353 413 -1574 4 2 1 1 156 238 72 402 -1575 4 2 1 1 369 423 360 442 -1576 4 2 1 1 188 412 218 433 -1577 4 2 1 1 375 451 226 470 -1578 4 2 1 1 81 382 242 444 -1579 4 2 1 1 263 380 254 428 -1580 4 2 1 1 4 429 188 433 -1581 4 2 1 1 326 336 321 440 -1582 4 2 1 1 351 426 416 460 -1583 4 2 1 1 236 270 429 431 -1584 4 2 1 1 76 10 187 397 -1585 4 2 1 1 352 372 437 445 -1586 4 2 1 1 140 387 141 446 -1587 4 2 1 1 126 162 127 439 -1588 4 2 1 1 368 395 380 435 -1589 4 2 1 1 354 407 374 461 -1590 4 2 1 1 335 336 349 388 -1591 4 2 1 1 415 448 358 455 -1592 4 2 1 1 92 95 228 395 -1593 4 2 1 1 116 408 375 455 -1594 4 2 1 1 127 129 128 439 -1595 4 2 1 1 134 174 413 420 -1596 4 2 1 1 207 391 278 435 -1597 4 2 1 1 168 430 151 446 -1598 4 2 1 1 364 425 409 458 -1599 4 2 1 1 73 218 412 433 -1600 4 2 1 1 185 73 210 390 -1601 4 2 1 1 3 90 222 429 -1602 4 2 1 1 65 280 156 444 -1603 4 2 1 1 397 419 76 454 -1604 4 2 1 1 73 390 6 433 -1605 4 2 1 1 353 394 392 413 -1606 4 2 1 1 379 434 389 448 -1607 4 2 1 1 340 159 298 418 -1608 4 2 1 1 368 435 391 440 -1609 4 2 1 1 250 376 436 456 -1610 4 2 1 1 223 200 81 382 -1611 4 2 1 1 312 321 320 389 -1612 4 2 1 1 211 396 166 406 -1613 4 2 1 1 400 401 351 460 -1614 4 2 1 1 94 23 335 440 -1615 4 2 1 1 372 438 359 445 -1616 4 2 1 1 128 372 438 462 -1617 4 2 1 1 282 240 46 78 -1618 4 2 1 1 93 83 161 385 -1619 4 2 1 1 289 200 220 429 -1620 4 2 1 1 136 183 138 432 -1621 4 2 1 1 144 196 190 394 -1622 4 2 1 1 358 448 373 471 -1623 4 2 1 1 375 355 398 449 -1624 4 2 1 1 80 224 199 398 -1625 4 2 1 1 179 108 384 452 -1626 4 2 1 1 125 193 114 421 -1627 4 2 1 1 129 438 128 439 -1628 4 2 1 1 185 423 390 463 -1629 4 2 1 1 123 295 77 415 -1630 4 2 1 1 171 175 71 392 -1631 4 2 1 1 128 438 131 462 -1632 4 2 1 1 306 379 309 448 -1633 4 2 1 1 209 120 193 454 -1634 4 2 1 1 251 436 371 456 -1635 4 2 1 1 308 307 411 449 -1636 4 2 1 1 325 319 326 405 -1637 4 2 1 1 355 398 381 419 -1638 4 2 1 1 93 53 83 288 -1639 4 2 1 1 53 93 241 288 -1640 4 2 1 1 84 162 388 439 -1641 4 2 1 1 264 251 436 458 -1642 4 2 1 1 117 109 118 451 -1643 4 2 1 1 85 277 207 391 -1644 4 2 1 1 187 11 88 381 -1645 4 2 1 1 63 189 190 394 -1646 4 2 1 1 358 410 401 471 -1647 4 2 1 1 354 424 376 466 -1648 4 2 1 1 111 406 112 452 -1649 4 2 1 1 120 403 193 454 -1650 4 2 1 1 71 340 302 418 -1651 4 2 1 1 358 415 373 448 -1652 4 2 1 1 115 427 406 452 -1653 4 2 1 1 362 442 390 457 -1654 4 2 1 1 358 417 379 434 -1655 4 2 1 1 72 281 244 462 -1656 4 2 1 1 117 408 109 451 -1657 4 2 1 1 266 270 424 429 -1658 4 2 1 1 298 349 343 418 -1659 4 2 1 1 166 406 396 447 -1660 4 2 1 1 225 374 146 444 -1661 4 2 1 1 197 347 422 459 -1662 4 2 1 1 335 336 388 440 -1663 4 2 1 1 113 406 166 447 -1664 4 2 1 1 358 410 373 415 -1665 4 2 1 1 316 315 311 404 -1666 4 2 1 1 169 74 168 430 -1667 4 2 1 1 362 442 426 466 -1668 4 2 1 1 142 168 141 387 -1669 4 2 1 1 84 298 159 418 -1670 4 2 1 1 374 444 382 469 -1671 4 2 1 1 355 419 403 451 -1672 4 2 1 1 369 442 421 457 -1673 4 2 1 1 132 134 135 432 -1674 4 2 1 1 185 390 210 463 -1675 4 2 1 1 72 402 281 462 -1676 4 2 1 1 242 382 292 444 -1677 4 2 1 1 146 444 374 469 -1678 4 2 1 1 353 378 420 464 -1679 4 2 1 1 354 390 433 466 -1680 4 2 1 1 9 397 76 454 -1681 4 2 1 1 225 145 146 374 -1682 4 2 1 1 253 250 252 456 -1683 4 2 1 1 72 155 156 402 -1684 4 2 1 1 358 373 410 471 -1685 4 2 1 1 295 123 70 415 -1686 4 2 1 1 72 244 152 462 -1687 4 2 1 1 273 288 241 385 -1688 4 2 1 1 291 268 391 437 -1689 4 2 1 1 111 115 406 452 -1690 4 2 1 1 108 107 105 452 -1691 4 2 1 1 232 174 173 413 -1692 4 2 1 1 197 422 198 459 -1693 4 2 1 1 387 446 378 464 -1694 4 2 1 1 91 207 96 440 -1695 4 2 1 1 4 5 181 433 -1696 4 2 1 1 238 156 280 444 -1697 4 2 1 1 360 446 387 464 -1698 4 2 1 1 229 133 130 420 -1699 4 2 1 1 319 318 343 399 -1700 4 2 1 1 321 336 293 440 -1701 4 2 1 1 87 182 198 422 -1702 4 2 1 1 383 360 446 463 -1703 4 2 1 1 181 5 75 433 -1704 4 2 1 1 96 207 49 235 -1705 4 2 1 1 145 155 135 432 -1706 4 2 1 1 393 395 368 465 -1707 4 2 1 1 71 159 340 418 -1708 4 2 1 1 313 319 325 399 -1709 4 2 1 1 67 423 185 463 -1710 4 2 1 1 222 201 279 431 -1711 4 2 1 1 363 386 445 461 -1712 4 2 1 1 351 401 453 460 -1713 4 2 1 1 120 118 403 451 -1714 4 2 1 1 264 256 251 458 -1715 4 2 1 1 354 390 412 433 -1716 4 2 1 1 323 307 328 411 -1717 4 2 1 1 140 142 141 387 -1718 4 2 1 1 108 105 384 452 -1719 4 2 1 1 168 151 141 446 -1720 4 2 1 1 268 278 391 435 -1721 4 2 1 1 421 442 362 457 -1722 4 2 1 1 372 414 402 462 -1723 4 2 1 1 328 345 294 381 -1724 4 2 1 1 266 258 292 424 -1725 4 2 1 1 267 380 263 437 -1726 4 2 1 1 290 228 50 235 -1727 4 2 1 1 227 95 348 465 -1728 4 2 1 1 294 329 328 422 -1729 4 2 1 1 185 6 73 390 -1730 4 2 1 1 102 99 410 415 -1731 4 2 1 1 217 419 120 454 -1732 4 2 1 1 385 428 273 458 -1733 4 2 1 1 103 105 443 468 -1734 4 2 1 1 268 263 435 437 -1735 4 2 1 1 290 269 276 395 -1736 4 2 1 1 309 306 308 379 -1737 4 2 1 1 77 99 123 415 -1738 4 2 1 1 115 179 231 427 -1739 4 2 1 1 321 312 325 405 -1740 4 2 1 1 367 418 388 439 -1741 4 2 1 1 91 233 207 440 -1742 4 2 1 1 253 407 258 424 -1743 4 2 1 1 179 108 105 384 -1744 4 2 1 1 86 299 208 393 -1745 4 2 1 1 84 206 162 439 -1746 4 2 1 1 133 413 174 420 -1747 4 2 1 1 410 415 358 455 -1748 4 2 1 1 357 406 396 427 -1749 4 2 1 1 403 419 355 454 -1750 4 2 1 1 8 423 167 430 -1751 4 2 1 1 383 412 390 463 -1752 4 2 1 1 89 188 4 429 -1753 4 2 1 1 222 279 236 431 -1754 4 2 1 1 287 243 247 431 -1755 4 2 1 1 171 172 173 392 -1756 4 2 1 1 115 211 406 427 -1757 4 2 1 1 147 183 194 383 -1758 4 2 1 1 263 267 254 380 -1759 4 2 1 1 355 379 411 449 -1760 4 2 1 1 262 263 254 428 -1761 4 2 1 1 410 358 443 455 -1762 4 2 1 1 351 453 426 460 -1763 4 2 1 1 240 282 285 462 -1764 4 2 1 1 190 170 212 394 -1765 4 2 1 1 8 167 9 430 -1766 4 2 1 1 84 159 206 418 -1767 4 2 1 1 180 69 409 425 -1768 4 2 1 1 196 144 232 413 -1769 4 2 1 1 308 379 306 449 -1770 4 2 1 1 166 211 192 396 -1771 4 2 1 1 254 267 252 456 -1772 4 2 1 1 211 166 113 406 -1773 4 2 1 1 207 277 278 391 -1774 4 2 1 1 29 332 346 97 -1775 4 2 1 1 292 242 289 382 -1776 4 2 1 1 409 427 357 450 -1777 4 2 1 1 299 334 208 393 -1778 4 2 1 1 397 355 419 454 -1779 4 2 1 1 371 436 376 456 -1780 4 2 1 1 373 448 389 471 -1781 4 2 1 1 72 152 402 462 -1782 4 2 1 1 190 170 394 459 -1783 4 2 1 1 295 70 333 415 -1784 4 2 1 1 207 85 48 277 -1785 4 2 1 1 250 436 251 456 -1786 4 2 1 1 67 154 151 463 -1787 4 2 1 1 183 139 143 446 -1788 4 2 1 1 190 394 189 459 -1789 4 2 1 1 380 435 263 437 -1790 4 2 1 1 221 329 12 422 -1791 4 2 1 1 223 81 213 382 -1792 4 2 1 1 373 356 441 471 -1793 4 2 1 1 211 111 115 406 -1794 4 2 1 1 375 408 358 455 -1795 4 2 1 1 223 213 150 382 -1796 4 2 1 1 241 276 262 395 -1797 4 2 1 1 335 23 336 440 -1798 4 2 1 1 257 407 255 414 -1799 4 2 1 1 378 413 353 420 -1800 4 2 1 1 118 184 193 403 -1801 4 2 1 1 276 52 93 241 -1802 4 2 1 1 96 235 228 435 -1803 4 2 1 1 402 438 372 462 -1804 4 2 1 1 86 27 208 299 -1805 4 2 1 1 213 81 153 444 -1806 4 2 1 1 363 456 371 460 -1807 4 2 1 1 423 442 369 457 -1808 4 2 1 1 414 445 359 461 -1809 4 2 1 1 117 116 109 408 -1810 4 2 1 1 235 207 49 278 -1811 4 2 1 1 126 46 240 78 -1812 4 2 1 1 84 162 94 388 -1813 4 2 1 1 140 141 139 446 -1814 4 2 1 1 351 417 401 434 -1815 4 2 1 1 433 447 370 466 -1816 4 2 1 1 272 264 275 409 -1817 4 2 1 1 275 264 246 409 -1818 4 2 1 1 323 308 307 411 -1819 4 2 1 1 357 396 406 467 -1820 4 2 1 1 305 301 398 470 -1821 4 2 1 1 355 398 419 451 -1822 4 2 1 1 76 419 217 454 -1823 4 2 1 1 236 3 222 429 -1824 4 2 1 1 73 188 218 433 -1825 4 2 1 1 261 414 267 437 -1826 4 2 1 1 9 74 397 430 -1827 4 2 1 1 227 293 24 440 -1828 4 2 1 1 186 9 76 454 -1829 4 2 1 1 130 420 132 438 -1830 4 2 1 1 99 98 100 410 -1831 4 2 1 1 349 298 335 388 -1832 4 2 1 1 140 137 144 413 -1833 4 2 1 1 312 314 309 448 -1834 4 2 1 1 124 214 398 451 -1835 4 2 1 1 312 389 314 448 -1836 4 2 1 1 242 283 215 444 -1837 4 2 1 1 305 342 301 470 -1838 4 2 1 1 401 441 356 471 -1839 4 2 1 1 160 204 205 425 -1840 4 2 1 1 76 187 217 419 -1841 4 2 1 1 106 443 408 455 -1842 4 2 1 1 363 437 414 445 -1843 4 2 1 1 125 122 68 421 -1844 4 2 1 1 299 27 208 334 -1845 4 2 1 1 149 150 148 412 -1846 4 2 1 1 220 200 89 429 -1847 4 2 1 1 256 273 428 458 -1848 4 2 1 1 228 276 92 395 -1849 4 2 1 1 6 75 5 433 -1850 4 2 1 1 358 434 379 448 -1851 4 2 1 1 131 402 152 462 -1852 4 2 1 1 178 195 427 450 -1853 4 2 1 1 124 398 80 470 -1854 4 2 1 1 290 235 269 435 -1855 4 2 1 1 186 209 125 454 -1856 4 2 1 1 166 396 82 431 -1857 4 2 1 1 357 376 436 467 -1858 4 2 1 1 192 427 195 450 -1859 4 2 1 1 120 119 118 451 -1860 4 2 1 1 122 164 163 457 -1861 4 2 1 1 271 289 220 429 -1862 4 2 1 1 273 272 274 425 -1863 4 2 1 1 178 427 409 450 -1864 4 2 1 1 351 416 426 442 -1865 4 2 1 1 111 112 110 452 -1866 4 2 1 1 385 425 364 458 -1867 4 2 1 1 378 420 359 432 -1868 4 2 1 1 224 80 214 398 -1869 4 2 1 1 313 318 319 399 -1870 4 2 1 1 91 96 227 440 -1871 4 2 1 1 124 226 451 470 -1872 4 2 1 1 238 286 281 402 -1873 4 2 1 1 197 79 347 459 -1874 4 2 1 1 70 415 102 455 -1875 4 2 1 1 386 359 445 461 -1876 4 2 1 1 318 339 302 392 -1877 4 2 1 1 106 408 116 455 -1878 4 2 1 1 291 268 278 391 -1879 4 2 1 1 178 177 195 450 -1880 4 2 1 1 214 80 124 398 -1881 4 2 1 1 297 303 33 64 -1882 4 2 1 1 206 159 203 418 -1883 4 2 1 1 121 120 217 419 -1884 4 2 1 1 257 255 260 414 -1885 4 2 1 1 265 253 258 424 -1886 4 2 1 1 357 426 376 467 -1887 4 2 1 1 122 68 421 457 -1888 4 2 1 1 311 315 313 404 -1889 4 2 1 1 94 91 23 440 -1890 4 2 1 1 237 55 274 425 -1891 4 2 1 1 273 272 425 458 -1892 4 2 1 1 278 207 48 277 -1893 4 2 1 1 4 90 3 429 -1894 4 2 1 1 134 136 135 432 -1895 4 2 1 1 358 401 417 434 -1896 4 2 1 1 370 376 466 467 -1897 4 2 1 1 120 118 193 403 -1898 4 2 1 1 106 157 443 455 -1899 4 2 1 1 278 277 291 391 -1900 4 2 1 1 97 29 332 77 -1901 4 2 1 1 173 175 171 392 -1902 4 2 1 1 103 104 105 468 -1903 4 2 1 1 266 270 265 424 -1904 4 2 1 1 360 378 446 464 -1905 4 2 1 1 246 275 409 450 -1906 4 2 1 1 106 107 109 408 -1907 4 2 1 1 176 180 69 409 -1908 4 2 1 1 334 393 320 465 -1909 4 2 1 1 7 185 67 423 -1910 4 2 1 1 143 151 154 463 -1911 4 2 1 1 215 81 242 444 -1912 4 2 1 1 178 409 177 450 -1913 4 2 1 1 276 93 52 92 -1914 4 2 1 1 111 113 112 406 -1915 4 2 1 1 296 339 344 392 -1916 4 2 1 1 197 198 79 459 -1917 4 2 1 1 208 95 92 465 -1918 4 2 1 1 129 229 130 438 -1919 4 2 1 1 160 54 274 288 -1920 4 2 1 1 102 410 101 443 -1921 4 2 1 1 284 59 239 66 -1922 4 2 1 1 202 165 166 447 -1923 4 2 1 1 329 324 328 422 -1924 4 2 1 1 363 414 407 461 -1925 4 2 1 1 305 398 345 449 -1926 4 2 1 1 153 444 146 469 -1927 4 2 1 1 370 431 396 447 -1928 4 2 1 1 128 131 152 462 -1929 4 2 1 1 124 226 117 451 -1930 4 2 1 1 218 149 210 412 -1931 4 2 1 1 143 446 151 463 -1932 4 2 1 1 10 76 9 397 -1933 4 2 1 1 159 340 298 21 -1934 4 2 1 1 376 424 370 466 -1935 4 2 1 1 68 7 423 457 -1936 4 2 1 1 305 398 449 470 -1937 4 2 1 1 306 309 322 448 -1938 4 2 1 1 221 12 87 422 -1939 4 2 1 1 276 269 262 395 -1940 4 2 1 1 360 430 387 446 -1941 4 2 1 1 192 195 66 450 -1942 4 2 1 1 259 286 238 444 -1943 4 2 1 1 363 445 414 461 -1944 4 2 1 1 227 24 91 440 -1945 4 2 1 1 35 342 216 301 -1946 4 2 1 1 51 228 290 276 -1947 4 2 1 1 124 119 214 451 -1948 4 2 1 1 160 83 54 288 -1949 4 2 1 1 124 451 398 470 -1950 4 2 1 1 180 204 69 425 -1951 4 2 1 1 268 267 263 437 -1952 4 2 1 1 149 412 148 469 -1953 4 2 1 1 190 189 170 459 -1954 4 2 1 1 152 131 72 402 -1955 4 2 1 1 102 123 99 415 -1956 4 2 1 1 261 255 267 414 -1957 4 2 1 1 94 22 84 335 -1958 4 2 1 1 245 239 66 450 -1959 4 2 1 1 216 124 80 470 -1960 4 2 1 1 383 432 374 469 -1961 4 2 1 1 299 320 334 393 -1962 4 2 1 1 285 260 261 414 -1963 4 2 1 1 340 71 20 159 -1964 4 2 1 1 67 185 154 463 -1965 4 2 1 1 171 19 302 71 -1966 4 2 1 1 133 132 130 420 -1967 4 2 1 1 165 202 181 447 -1968 4 2 1 1 250 248 251 436 -1969 4 2 1 1 222 90 201 431 -1970 4 2 1 1 101 443 410 468 -1971 4 2 1 1 102 443 157 455 -1972 4 2 1 1 221 197 347 422 -1973 4 2 1 1 65 156 225 444 -1974 4 2 1 1 102 70 123 415 -1975 4 2 1 1 330 415 322 448 -1976 4 2 1 1 96 50 228 235 -1977 4 2 1 1 414 437 372 445 -1978 4 2 1 1 245 66 177 450 -1979 4 2 1 1 293 336 24 440 -1980 4 2 1 1 9 74 10 397 -1981 4 2 1 1 237 69 55 425 -1982 4 2 1 1 31 295 123 70 -1983 4 2 1 1 298 84 22 335 -1984 4 2 1 1 302 19 171 339 -1985 4 2 1 1 262 256 273 428 -1986 4 2 1 1 178 195 231 427 -1987 4 2 1 1 191 82 166 396 -1988 4 2 1 1 134 133 174 420 -1989 4 2 1 1 302 340 71 20 -1990 4 2 1 1 55 160 274 425 -1991 4 2 1 1 226 64 158 470 -1992 4 2 1 1 343 340 298 418 -1993 4 2 1 1 344 339 318 392 -1994 4 2 1 1 227 348 95 25 -1995 4 2 1 1 159 71 203 418 -1996 4 2 1 1 56 69 237 176 -1997 4 2 1 1 131 155 72 402 -1998 4 2 1 1 333 322 330 415 -1999 4 2 1 1 277 85 47 126 -2000 4 2 1 1 187 224 121 419 -2001 4 2 1 1 390 423 360 463 -2002 4 2 1 1 8 68 7 423 -2003 4 2 1 1 258 266 265 424 -2004 4 2 1 1 259 238 280 444 -2005 4 2 1 1 233 91 94 440 -2006 4 2 1 1 30 332 77 295 -2007 4 2 1 1 202 166 82 431 -2008 4 2 1 1 305 301 345 398 -2009 4 2 1 1 253 257 258 407 -2010 4 2 1 1 166 192 191 396 -2011 4 2 1 1 207 233 85 391 -2012 4 2 1 1 327 334 320 465 -2013 4 2 1 1 30 77 123 295 -2014 4 2 1 1 157 106 116 455 -2015 4 2 1 1 44 244 152 72 -2016 4 2 1 1 225 146 153 444 -2017 4 2 1 1 25 227 348 293 -2018 4 2 1 1 296 338 17 63 -2019 4 2 1 1 5 73 6 433 -2020 4 2 1 1 103 106 157 443 -2021 4 2 1 1 330 332 295 415 -2022 4 2 1 1 6 7 163 457 -2023 4 2 1 1 297 305 304 470 -2024 4 2 1 1 111 108 115 452 -2025 4 2 1 1 304 305 306 449 -2026 4 2 1 1 245 239 58 66 -2027 4 2 1 1 317 316 350 459 -2028 4 2 1 1 239 246 247 450 -2029 4 2 1 1 245 177 57 176 -2030 4 2 1 1 44 244 72 281 -2031 4 2 1 1 84 159 298 21 -2032 4 2 1 1 370 447 396 467 -2033 4 2 1 1 171 18 172 339 -2034 4 2 1 1 157 102 103 443 -2035 4 2 1 1 218 150 149 412 -2036 4 2 1 1 268 263 278 435 -2037 4 2 1 1 260 281 286 402 -2038 4 2 1 1 58 177 245 66 -2039 4 2 1 1 87 198 197 422 -2040 4 2 1 1 312 320 314 389 -2041 4 2 1 1 91 336 23 440 -2042 4 2 1 1 215 153 81 444 -2043 4 2 1 1 33 303 158 64 -2044 4 2 1 1 347 79 300 459 -2045 4 2 1 1 234 86 208 393 -2046 4 2 1 1 113 166 165 447 -2047 4 2 1 1 240 277 47 126 -2048 4 2 1 1 244 260 285 462 -2049 4 2 1 1 384 452 365 453 -2050 4 2 1 1 200 289 39 81 -2051 4 2 1 1 176 237 56 275 -2052 4 2 1 1 217 120 209 454 -2053 4 2 1 1 373 441 410 471 -2054 4 2 1 1 264 248 246 436 -2055 4 2 1 1 333 295 31 70 -2056 4 2 1 1 185 210 154 463 -2057 4 2 1 1 280 156 42 65 -2058 4 2 1 1 375 449 398 470 -2059 4 2 1 1 3 236 271 429 -2060 4 2 1 1 115 192 211 427 -2061 4 2 1 1 69 160 55 425 -2062 4 2 1 1 176 177 178 409 -2063 4 2 1 1 287 270 236 431 -2064 4 2 1 1 134 132 133 420 -2065 4 2 1 1 236 279 287 431 -2066 4 2 1 1 266 289 271 429 -2067 4 2 1 1 70 157 158 455 -2068 4 2 1 1 347 329 221 422 -2069 4 2 1 1 158 157 116 455 -2070 4 2 1 1 257 253 255 407 -2071 4 2 1 1 194 154 210 463 -2072 4 2 1 1 307 308 306 449 -2073 4 2 1 1 4 188 5 433 -2074 4 2 1 1 57 245 176 275 -2075 4 2 1 1 307 305 345 449 -2076 4 2 1 1 243 279 82 431 -2077 4 2 1 1 101 410 100 468 -2078 4 2 1 1 101 103 443 468 -2079 4 2 1 1 358 434 448 471 -2080 4 2 1 1 24 336 91 440 -2081 4 2 1 1 108 110 107 452 -2082 4 2 1 1 347 350 422 459 -2083 4 2 1 1 101 100 230 468 -2084 4 2 1 1 17 172 296 63 -2085 4 2 1 1 208 393 334 465 -2086 4 2 1 1 201 82 279 431 -2087 4 2 1 1 262 254 256 428 -2088 4 2 1 1 389 448 434 471 -2089 4 2 1 1 259 242 292 444 -2090 4 2 1 1 103 102 101 443 -2091 4 2 1 1 67 167 8 423 -2092 4 2 1 1 70 102 157 455 -2093 4 2 1 1 300 189 341 459 -2094 4 2 1 1 165 164 113 447 -2095 4 2 1 1 36 337 80 199 -2096 4 2 1 1 130 132 131 438 -2097 4 2 1 1 147 146 138 469 -2098 4 2 1 1 325 326 321 405 -2099 4 2 1 1 220 3 271 429 -2100 4 2 1 1 35 216 80 301 -2101 4 2 1 1 113 111 211 406 -2102 4 2 1 1 9 167 74 430 -2103 4 2 1 1 122 114 112 421 -2104 4 2 1 1 36 80 337 301 -2105 4 2 1 1 238 156 42 280 -2106 4 2 1 1 408 443 358 455 -2107 4 2 1 1 167 151 168 430 -2108 4 2 1 1 143 154 194 463 -2109 4 2 1 1 398 451 375 470 -2110 4 2 1 1 79 347 14 197 -2111 4 2 1 1 102 99 101 410 -2112 4 2 1 1 358 401 434 471 -2113 4 2 1 1 343 302 340 418 -2114 4 2 1 1 59 284 191 66 -2115 4 2 1 1 176 178 180 409 -2116 4 2 1 1 297 34 342 470 -2117 4 2 1 1 362 406 447 467 -2118 4 2 1 1 145 135 138 432 -2119 4 2 1 1 347 350 324 422 -2120 4 2 1 1 246 245 275 450 -2121 4 2 1 1 268 291 261 437 -2122 4 2 1 1 271 3 2 236 -2123 4 2 1 1 294 12 1 329 -2124 4 2 1 1 148 153 146 469 -2125 4 2 1 1 406 396 447 467 -2126 4 2 1 1 106 103 105 443 -2127 4 2 1 1 268 261 267 437 -2128 4 2 1 1 51 228 276 92 -2129 4 2 1 1 206 129 127 439 -2130 4 2 1 1 296 172 18 339 -2131 4 2 1 1 5 188 73 433 -2132 4 2 1 1 116 106 109 408 -2133 4 2 1 1 242 39 289 81 -2134 4 2 1 1 251 252 250 456 -2135 4 2 1 1 330 295 333 415 -2136 4 2 1 1 370 466 447 467 -2137 4 2 1 1 260 255 261 414 -2138 4 2 1 1 170 79 198 459 -2139 4 2 1 1 164 165 75 447 -2140 4 2 1 1 362 447 466 467 -2141 4 2 1 1 38 220 289 200 -2142 4 2 1 1 271 270 266 429 -2143 4 2 1 1 189 15 300 341 -2144 4 2 1 1 216 342 34 470 -2145 4 2 1 1 136 138 135 432 -2146 4 2 1 1 279 201 61 82 -2147 4 2 1 1 232 144 174 413 -2148 4 2 1 1 125 114 122 421 -2149 4 2 1 1 202 201 90 431 -2150 4 2 1 1 279 61 243 82 -2151 4 2 1 1 4 3 89 429 -2152 4 2 1 1 259 283 242 444 -2153 4 2 1 1 144 137 174 413 -2154 4 2 1 1 165 181 75 447 -2155 4 2 1 1 303 158 70 32 -2156 4 2 1 1 303 70 333 32 -2157 4 2 1 1 221 87 197 422 -2158 4 2 1 1 197 347 13 221 -2159 4 2 1 1 101 99 100 410 -2160 4 2 1 1 1 12 294 219 -2161 4 2 1 1 220 3 2 271 -2162 4 2 1 1 329 12 1 221 -2163 4 2 1 1 222 2 3 236 -2164 4 2 1 1 219 337 37 199 -2165 4 2 1 1 187 121 217 419 -2166 4 2 1 1 195 177 66 450 -2167 4 2 1 1 130 128 129 438 -2168 4 2 1 1 143 141 151 446 -2169 4 2 1 1 280 65 283 444 -2170 4 2 1 1 143 139 141 446 -2171 4 2 1 1 26 348 95 465 -2172 4 2 1 1 14 300 347 79 -2173 4 2 1 1 209 76 217 454 -2174 4 2 1 1 235 278 263 435 -2175 4 2 1 1 283 40 242 215 -2176 4 2 1 1 149 148 147 469 -2177 4 2 1 1 122 163 68 457 -2178 4 2 1 1 79 170 189 459 -2179 4 2 1 1 271 236 270 429 -2180 4 2 1 1 252 251 254 456 -2181 4 2 1 1 160 69 204 425 -2182 4 2 1 1 327 293 348 465 -2183 4 2 1 1 297 64 34 470 -2184 4 2 1 1 8 7 67 423 -2185 4 2 1 1 74 167 168 430 -2186 4 2 1 1 43 156 238 72 -2187 4 2 1 1 201 62 222 279 -2188 4 2 1 1 195 192 115 427 -2189 4 2 1 1 282 78 45 462 -2190 4 2 1 1 72 238 43 281 -2191 4 2 1 1 341 189 16 338 -2192 4 2 1 1 269 235 263 435 -2193 4 2 1 1 76 209 186 454 -2194 4 2 1 1 26 334 348 465 -2195 4 2 1 1 300 341 317 459 -2196 4 2 1 1 128 130 131 438 -2197 4 2 1 1 119 117 118 451 -2198 4 2 1 1 426 466 376 467 -2199 4 2 1 1 79 189 300 459 -2200 4 2 1 1 337 37 294 219 -2201 4 2 1 1 124 117 119 451 -2202 4 2 1 1 283 65 215 444 -2203 4 2 1 1 220 89 3 429 -2204 4 2 1 1 347 329 13 221 -2205 4 2 1 1 362 466 426 467 -2206 4 2 1 1 38 220 271 289 -2207 4 2 1 1 215 40 242 81 -2208 4 2 1 1 216 34 64 470 -2209 4 2 1 1 208 26 95 465 -2210 4 2 1 1 236 222 62 279 -2211 4 2 1 1 110 108 111 452 -2212 4 2 1 1 52 53 93 241 -2213 4 2 1 1 244 282 45 462 -2214 4 2 1 1 104 230 180 468 -2215 4 2 1 1 162 206 127 439 -2216 4 2 1 1 280 41 283 65 -2217 4 2 1 1 208 334 26 465 -2218 4 2 1 1 86 27 299 28 -2219 4 2 1 1 244 45 152 462 -2220 4 2 1 1 78 128 152 462 -2221 4 2 1 1 68 163 7 457 -2222 4 2 1 1 347 300 350 459 -2223 4 2 1 1 101 104 103 468 -2224 4 2 1 1 251 248 264 436 -2225 4 2 1 1 274 272 237 425 -2226 4 2 1 1 338 189 16 63 -2227 4 2 1 1 305 307 306 449 -2228 4 2 1 1 22 84 298 21 -2229 4 2 1 1 152 45 78 462 -2230 4 2 1 1 45 44 244 152 -2231 4 2 1 1 24 23 91 336 -2232 4 2 1 1 189 300 15 79 -2233 4 2 1 1 215 283 41 65 -2234 4 2 1 1 347 324 329 422 -2235 4 2 1 1 202 82 201 431 -2236 4 2 1 1 314 322 309 448 -2237 4 2 1 1 239 59 58 66 -2238 4 2 1 1 287 279 243 431 -2239 4 2 1 1 305 297 342 470 -2240 4 2 1 1 289 39 38 200 -2241 4 2 1 1 77 29 332 30 -2242 4 2 1 1 317 350 300 459 -2243 4 2 1 1 256 264 272 458 -2244 4 2 1 1 330 322 314 448 -2245 4 2 1 1 71 19 302 20 -2246 4 2 1 1 47 46 240 126 -2247 4 2 1 1 176 56 57 275 -2248 4 2 1 1 35 80 36 301 -2249 4 2 1 1 22 94 23 335 -2250 4 2 1 1 295 123 30 31 -2251 4 2 1 1 85 47 48 277 -2252 4 2 1 1 207 48 49 278 -2253 4 2 1 1 64 226 124 470 -2254 4 2 1 1 274 55 54 160 -2255 4 2 1 1 13 14 347 197 -2256 4 2 1 1 83 53 54 288 -2257 4 2 1 1 18 171 19 339 -2258 4 2 1 1 46 45 282 78 -2259 4 2 1 1 231 195 115 427 -2260 4 2 1 1 96 49 50 235 -2261 4 2 1 1 65 225 153 444 -2262 4 2 1 1 239 245 246 450 -2263 4 2 1 1 297 33 34 64 -2264 4 2 1 1 337 36 37 199 -2265 4 2 1 1 148 146 147 469 -2266 4 2 1 1 61 60 243 82 -2267 4 2 1 1 18 17 172 296 -2268 4 2 1 1 70 31 333 32 -2269 4 2 1 1 159 20 340 21 -2270 4 2 1 1 32 303 158 33 -2271 4 2 1 1 259 280 283 444 -2272 4 2 1 1 244 285 282 462 -2273 4 2 1 1 273 256 272 458 -2274 4 2 1 1 346 28 29 97 -2275 4 2 1 1 201 61 62 279 -2276 4 2 1 1 42 43 156 238 -2277 4 2 1 1 62 2 222 236 -2278 4 2 1 1 294 37 1 219 -2279 4 2 1 1 153 215 65 444 -2280 4 2 1 1 55 56 69 237 -2281 4 2 1 1 348 334 327 465 -2282 4 2 1 1 230 104 101 468 -2283 4 2 1 1 242 40 39 81 -2284 4 2 1 1 338 16 17 63 -2285 4 2 1 1 1 13 329 221 -2286 4 2 1 1 220 2 38 271 -2287 4 2 1 1 64 124 216 470 -2288 4 2 1 1 57 58 177 245 -2289 4 2 1 1 300 14 15 79 -2290 4 2 1 1 26 95 348 25 -2291 4 2 1 1 284 60 59 191 -2292 4 2 1 1 42 41 280 65 -2293 4 2 1 1 72 43 44 281 -2294 4 2 1 1 52 51 276 92 -2295 4 2 1 1 24 227 25 293 -2296 4 2 1 1 16 15 189 341 -2297 4 2 1 1 216 34 342 35 -2298 4 2 1 1 26 208 27 334 -2299 4 2 1 1 283 41 40 215 -2300 4 2 1 1 228 50 51 290 -2301 4 2 1 1 407 286 444 374 -2302 4 2 1 1 407 444 286 257 -2303 4 2 1 1 422 316 411 361 -2304 4 2 1 1 422 411 316 324 -2305 4 2 1 1 391 94 440 233 -2306 4 2 1 1 391 440 94 388 -2307 4 2 1 1 362 453 442 365 -2308 4 2 1 1 442 453 362 426 -2309 4 2 1 1 173 413 196 232 -2310 4 2 1 1 196 413 173 392 -2311 4 2 1 1 448 304 449 375 -2312 4 2 1 1 448 449 304 322 -2313 4 2 1 1 452 184 421 110 -2314 4 2 1 1 452 421 184 365 -2315 4 2 1 1 436 247 249 248 -2316 4 2 1 1 436 249 247 396 -2317 4 2 1 1 393 97 161 86 -2318 4 2 1 1 393 161 97 373 -2319 4 2 1 1 425 468 409 180 -2320 4 2 1 1 409 468 425 364 -2321 4 2 1 1 162 391 126 85 -2322 4 2 1 1 126 391 162 439 -2323 4 2 1 1 414 456 407 255 -2324 4 2 1 1 407 456 414 363 -2325 4 2 1 1 444 257 258 259 -2326 4 2 1 1 444 258 257 407 -2327 4 2 1 1 448 331 389 314 -2328 4 2 1 1 448 389 331 373 -2329 4 2 1 1 439 203 418 206 -2330 4 2 1 1 439 418 203 367 -2331 4 2 1 1 326 388 319 349 -2332 4 2 1 1 319 388 326 405 -2333 4 2 1 1 179 468 105 104 -2334 4 2 1 1 105 468 179 384 -2335 4 2 1 1 423 186 9 8 -2336 4 2 1 1 423 9 186 369 -2337 4 2 1 1 424 250 249 265 -2338 4 2 1 1 424 249 250 376 -2339 4 2 1 1 444 258 292 259 -2340 4 2 1 1 444 292 258 382 -2341 4 2 1 1 469 213 412 148 -2342 4 2 1 1 469 412 213 382 -2343 4 2 1 1 150 412 213 148 -2344 4 2 1 1 150 213 412 382 -2345 4 2 1 1 435 207 440 96 -2346 4 2 1 1 435 440 207 391 -2347 4 2 1 1 463 183 446 383 -2348 4 2 1 1 463 446 183 143 -2349 4 2 1 1 408 118 184 109 -2350 4 2 1 1 408 184 118 403 -2351 4 2 1 1 93 86 393 161 -2352 4 2 1 1 393 86 93 234 -2353 4 2 1 1 94 85 391 162 -2354 4 2 1 1 391 85 94 233 -2355 4 2 1 1 191 243 60 82 -2356 4 2 1 1 191 60 243 284 -2357 4 2 1 1 451 121 120 119 -2358 4 2 1 1 451 120 121 419 -2359 4 2 1 1 448 312 379 309 -2360 4 2 1 1 448 379 312 389 -2361 4 2 1 1 288 93 385 83 -2362 4 2 1 1 288 385 93 241 -2363 4 2 1 1 462 127 126 78 -2364 4 2 1 1 462 126 127 372 -2365 4 2 1 1 428 241 273 262 -2366 4 2 1 1 428 273 241 385 -2367 4 2 1 1 431 166 447 202 -2368 4 2 1 1 431 447 166 396 -2369 4 2 1 1 419 214 224 121 -2370 4 2 1 1 419 224 214 398 -2371 4 2 1 1 299 97 28 346 -2372 4 2 1 1 28 97 299 86 -2373 4 2 1 1 462 281 260 402 -2374 4 2 1 1 462 260 281 244 -2375 4 2 1 1 247 431 249 287 -2376 4 2 1 1 249 431 247 396 -2377 4 2 1 1 237 409 272 275 -2378 4 2 1 1 272 409 237 425 -2379 4 2 1 1 284 66 450 191 -2380 4 2 1 1 450 66 284 239 -2381 4 2 1 1 64 303 470 297 -2382 4 2 1 1 64 470 303 158 -2383 4 2 1 1 301 216 470 342 -2384 4 2 1 1 301 470 216 80 +835 +1 2 2 1 1 10 112 1 +2 2 2 1 1 1 116 10 +3 2 2 1 1 11 116 1 +4 2 2 1 1 1 112 22 +5 2 2 1 1 3 113 2 +6 2 2 1 1 2 114 3 +7 2 2 1 1 2 113 23 +8 2 2 1 1 34 114 2 +9 2 2 1 1 4 101 3 +10 2 2 1 1 3 102 4 +11 2 2 1 1 101 113 3 +12 2 2 1 1 3 114 102 +13 2 2 1 1 4 43 5 +14 2 2 1 1 5 44 4 +15 2 2 1 1 4 102 43 +16 2 2 1 1 44 101 4 +17 2 2 1 1 5 84 6 +18 2 2 1 1 6 87 5 +19 2 2 1 1 43 84 5 +20 2 2 1 1 5 87 44 +21 2 2 1 1 7 39 6 +22 2 2 1 1 6 40 7 +23 2 2 1 1 39 87 6 +24 2 2 1 1 6 84 40 +25 2 2 1 1 7 85 8 +26 2 2 1 1 8 86 7 +27 2 2 1 1 7 86 39 +28 2 2 1 1 40 85 7 +29 2 2 1 1 9 41 8 +30 2 2 1 1 8 42 9 +31 2 2 1 1 41 86 8 +32 2 2 1 1 8 85 42 +33 2 2 1 1 10 98 9 +34 2 2 1 1 9 99 10 +35 2 2 1 1 9 98 41 +36 2 2 1 1 42 99 9 +37 2 2 1 1 10 116 98 +38 2 2 1 1 99 112 10 +39 2 2 1 1 23 50 24 +40 2 2 1 1 23 113 50 +41 2 2 1 1 24 89 25 +42 2 2 1 1 50 89 24 +43 2 2 1 1 25 37 26 +44 2 2 1 1 25 89 37 +45 2 2 1 1 26 83 27 +46 2 2 1 1 37 83 26 +47 2 2 1 1 27 46 28 +48 2 2 1 1 27 83 46 +49 2 2 1 1 28 93 29 +50 2 2 1 1 46 93 28 +51 2 2 1 1 29 47 30 +52 2 2 1 1 29 93 47 +53 2 2 1 1 30 81 31 +54 2 2 1 1 47 81 30 +55 2 2 1 1 31 38 32 +56 2 2 1 1 31 81 38 +57 2 2 1 1 32 92 33 +58 2 2 1 1 38 92 32 +59 2 2 1 1 33 51 34 +60 2 2 1 1 33 92 51 +61 2 2 1 1 51 114 34 +62 2 2 1 1 12 48 11 +63 2 2 1 1 48 116 11 +64 2 2 1 1 13 80 12 +65 2 2 1 1 12 80 48 +66 2 2 1 1 14 35 13 +67 2 2 1 1 35 80 13 +68 2 2 1 1 15 57 14 +69 2 2 1 1 14 57 35 +70 2 2 1 1 16 52 15 +71 2 2 1 1 52 57 15 +72 2 2 1 1 17 45 16 +73 2 2 1 1 45 52 16 +74 2 2 1 1 18 66 17 +75 2 2 1 1 17 66 45 +76 2 2 1 1 19 119 18 +77 2 2 1 1 18 119 66 +78 2 2 1 1 20 36 19 +79 2 2 1 1 36 119 19 +80 2 2 1 1 21 91 20 +81 2 2 1 1 20 91 36 +82 2 2 1 1 22 49 21 +83 2 2 1 1 49 91 21 +84 2 2 1 1 22 112 49 +85 2 2 1 1 57 58 35 +86 2 2 1 1 58 62 35 +87 2 2 1 1 62 80 35 +88 2 2 1 1 36 103 68 +89 2 2 1 1 68 119 36 +90 2 2 1 1 36 91 76 +91 2 2 1 1 76 103 36 +92 2 2 1 1 37 108 83 +93 2 2 1 1 89 90 37 +94 2 2 1 1 90 108 37 +95 2 2 1 1 81 82 38 +96 2 2 1 1 82 104 38 +97 2 2 1 1 38 104 92 +98 2 2 1 1 86 117 39 +99 2 2 1 1 39 97 87 +100 2 2 1 1 39 117 97 +101 2 2 1 1 40 84 77 +102 2 2 1 1 77 106 40 +103 2 2 1 1 40 106 85 +104 2 2 1 1 41 110 86 +105 2 2 1 1 41 98 94 +106 2 2 1 1 94 110 41 +107 2 2 1 1 85 111 42 +108 2 2 1 1 42 100 99 +109 2 2 1 1 42 111 100 +110 2 2 1 1 43 120 84 +111 2 2 1 1 102 115 43 +112 2 2 1 1 115 120 43 +113 2 2 1 1 87 88 44 +114 2 2 1 1 88 96 44 +115 2 2 1 1 96 101 44 +116 2 2 1 1 45 53 52 +117 2 2 1 1 45 55 53 +118 2 2 1 1 45 66 55 +119 2 2 1 1 83 109 46 +120 2 2 1 1 46 121 93 +121 2 2 1 1 109 121 46 +122 2 2 1 1 79 107 47 +123 2 2 1 1 47 122 79 +124 2 2 1 1 47 107 81 +125 2 2 1 1 93 122 47 +126 2 2 1 1 80 94 48 +127 2 2 1 1 94 98 48 +128 2 2 1 1 98 116 48 +129 2 2 1 1 49 100 91 +130 2 2 1 1 99 100 49 +131 2 2 1 1 49 112 99 +132 2 2 1 1 50 96 89 +133 2 2 1 1 50 101 96 +134 2 2 1 1 50 113 101 +135 2 2 1 1 92 115 51 +136 2 2 1 1 102 114 51 +137 2 2 1 1 51 115 102 +138 2 2 1 1 53 54 52 +139 2 2 1 1 54 57 52 +140 2 2 1 1 53 65 54 +141 2 2 1 1 55 56 53 +142 2 2 1 1 56 65 53 +143 2 2 1 1 54 58 57 +144 2 2 1 1 54 59 58 +145 2 2 1 1 54 118 59 +146 2 2 1 1 65 118 54 +147 2 2 1 1 55 79 56 +148 2 2 1 1 66 67 55 +149 2 2 1 1 67 79 55 +150 2 2 1 1 56 121 65 +151 2 2 1 1 79 122 56 +152 2 2 1 1 93 121 56 +153 2 2 1 1 56 122 93 +154 2 2 1 1 59 60 58 +155 2 2 1 1 60 62 58 +156 2 2 1 1 59 61 60 +157 2 2 1 1 59 63 61 +158 2 2 1 1 59 118 63 +159 2 2 1 1 61 95 60 +160 2 2 1 1 60 64 62 +161 2 2 1 1 60 95 64 +162 2 2 1 1 63 108 61 +163 2 2 1 1 61 105 95 +164 2 2 1 1 61 108 105 +165 2 2 1 1 64 110 62 +166 2 2 1 1 62 94 80 +167 2 2 1 1 62 110 94 +168 2 2 1 1 83 108 63 +169 2 2 1 1 63 109 83 +170 2 2 1 1 63 118 109 +171 2 2 1 1 95 117 64 +172 2 2 1 1 64 117 110 +173 2 2 1 1 109 118 65 +174 2 2 1 1 65 121 109 +175 2 2 1 1 66 68 67 +176 2 2 1 1 66 119 68 +177 2 2 1 1 68 69 67 +178 2 2 1 1 69 70 67 +179 2 2 1 1 70 79 67 +180 2 2 1 1 68 103 69 +181 2 2 1 1 69 71 70 +182 2 2 1 1 69 72 71 +183 2 2 1 1 69 103 72 +184 2 2 1 1 71 82 70 +185 2 2 1 1 70 107 79 +186 2 2 1 1 82 107 70 +187 2 2 1 1 72 73 71 +188 2 2 1 1 73 74 71 +189 2 2 1 1 74 82 71 +190 2 2 1 1 72 75 73 +191 2 2 1 1 72 76 75 +192 2 2 1 1 72 103 76 +193 2 2 1 1 73 77 74 +194 2 2 1 1 75 106 73 +195 2 2 1 1 73 106 77 +196 2 2 1 1 77 78 74 +197 2 2 1 1 78 104 74 +198 2 2 1 1 74 104 82 +199 2 2 1 1 76 111 75 +200 2 2 1 1 85 106 75 +201 2 2 1 1 75 111 85 +202 2 2 1 1 91 100 76 +203 2 2 1 1 100 111 76 +204 2 2 1 1 77 120 78 +205 2 2 1 1 84 120 77 +206 2 2 1 1 92 104 78 +207 2 2 1 1 78 115 92 +208 2 2 1 1 78 120 115 +209 2 2 1 1 81 107 82 +210 2 2 1 1 110 117 86 +211 2 2 1 1 87 97 88 +212 2 2 1 1 90 96 88 +213 2 2 1 1 88 105 90 +214 2 2 1 1 97 105 88 +215 2 2 1 1 89 96 90 +216 2 2 1 1 105 108 90 +217 2 2 1 1 95 105 97 +218 2 2 1 1 97 117 95 +219 2 2 2 2 23 136 2 +220 2 2 2 2 2 127 34 +221 2 2 2 2 2 136 127 +222 2 2 2 2 24 126 23 +223 2 2 2 2 126 136 23 +224 2 2 2 2 25 128 24 +225 2 2 2 2 24 128 126 +226 2 2 2 2 26 137 25 +227 2 2 2 2 25 137 128 +228 2 2 2 2 27 124 26 +229 2 2 2 2 124 137 26 +230 2 2 2 2 28 132 27 +231 2 2 2 2 27 132 124 +232 2 2 2 2 29 132 28 +233 2 2 2 2 30 125 29 +234 2 2 2 2 125 132 29 +235 2 2 2 2 31 134 30 +236 2 2 2 2 30 134 125 +237 2 2 2 2 32 134 31 +238 2 2 2 2 33 123 32 +239 2 2 2 2 123 134 32 +240 2 2 2 2 34 135 33 +241 2 2 2 2 33 135 123 +242 2 2 2 2 127 135 34 +243 2 2 2 2 127 131 123 +244 2 2 2 2 123 135 127 +245 2 2 2 2 131 133 123 +246 2 2 2 2 133 134 123 +247 2 2 2 2 124 130 129 +248 2 2 2 2 129 137 124 +249 2 2 2 2 124 132 130 +250 2 2 2 2 130 132 125 +251 2 2 2 2 125 133 130 +252 2 2 2 2 125 134 133 +253 2 2 2 2 126 131 127 +254 2 2 2 2 127 136 126 +255 2 2 2 2 128 129 126 +256 2 2 2 2 129 131 126 +257 2 2 2 2 128 137 129 +258 2 2 2 2 130 131 129 +259 2 2 2 2 130 133 131 +260 2 2 3 3 11 1 151 +261 2 2 3 3 1 22 142 +262 2 2 3 3 1 142 151 +263 2 2 3 3 12 11 141 +264 2 2 3 3 141 11 151 +265 2 2 3 3 13 12 143 +266 2 2 3 3 12 141 143 +267 2 2 3 3 14 13 152 +268 2 2 3 3 13 143 152 +269 2 2 3 3 15 14 139 +270 2 2 3 3 139 14 152 +271 2 2 3 3 16 15 147 +272 2 2 3 3 15 139 147 +273 2 2 3 3 17 16 147 +274 2 2 3 3 18 17 140 +275 2 2 3 3 140 17 147 +276 2 2 3 3 19 18 149 +277 2 2 3 3 18 140 149 +278 2 2 3 3 20 19 149 +279 2 2 3 3 21 20 138 +280 2 2 3 3 138 20 149 +281 2 2 3 3 22 21 150 +282 2 2 3 3 21 138 150 +283 2 2 3 3 142 22 150 +284 2 2 3 3 142 138 146 +285 2 2 3 3 138 142 150 +286 2 2 3 3 146 138 148 +287 2 2 3 3 148 138 149 +288 2 2 3 3 139 144 145 +289 2 2 3 3 144 139 152 +290 2 2 3 3 139 145 147 +291 2 2 3 3 145 140 147 +292 2 2 3 3 140 145 148 +293 2 2 3 3 140 148 149 +294 2 2 3 3 141 142 146 +295 2 2 3 3 142 141 151 +296 2 2 3 3 143 141 144 +297 2 2 3 3 144 141 146 +298 2 2 3 3 143 144 152 +299 2 2 3 3 145 144 146 +300 2 2 3 3 145 146 148 +301 4 2 1 1 106 161 155 171 +302 4 2 1 1 50 157 126 160 +303 4 2 1 1 56 161 156 170 +304 4 2 1 1 157 159 130 160 +305 4 2 1 1 50 96 157 160 +306 4 2 1 1 106 73 161 171 +307 4 2 1 1 106 155 75 171 +308 4 2 1 1 75 171 155 173 +309 4 2 1 1 126 129 128 160 +310 4 2 1 1 79 164 161 170 +311 4 2 1 1 55 156 56 161 +312 4 2 1 1 130 160 159 164 +313 4 2 1 1 56 79 161 170 +314 4 2 1 1 85 173 155 177 +315 4 2 1 1 126 128 89 160 +316 4 2 1 1 97 166 155 167 +317 4 2 1 1 106 75 73 171 +318 4 2 1 1 115 159 157 165 +319 4 2 1 1 50 126 89 160 +320 4 2 1 1 96 157 160 167 +321 4 2 1 1 75 155 85 173 +322 4 2 1 1 156 161 55 175 +323 4 2 1 1 50 89 96 160 +324 4 2 1 1 131 130 157 159 +325 4 2 1 1 75 106 85 155 +326 4 2 1 1 155 77 165 169 +327 4 2 1 1 115 78 159 165 +328 4 2 1 1 56 164 79 170 +329 4 2 1 1 106 77 155 169 +330 4 2 1 1 137 128 129 160 +331 4 2 1 1 106 73 77 169 +332 4 2 1 1 131 157 130 160 +333 4 2 1 1 107 161 164 169 +334 4 2 1 1 87 155 6 165 +335 4 2 1 1 87 155 165 167 +336 4 2 1 1 131 133 130 159 +337 4 2 1 1 97 155 87 167 +338 4 2 1 1 153 159 157 160 +339 4 2 1 1 161 164 153 170 +340 4 2 1 1 129 126 157 160 +341 4 2 1 1 56 122 79 164 +342 4 2 1 1 145 148 146 163 +343 4 2 1 1 79 55 56 161 +344 4 2 1 1 137 89 128 160 +345 4 2 1 1 159 160 153 164 +346 4 2 1 1 107 161 79 164 +347 4 2 1 1 127 51 135 157 +348 4 2 1 1 55 53 56 156 +349 4 2 1 1 159 165 78 169 +350 4 2 1 1 130 159 133 164 +351 4 2 1 1 107 164 159 169 +352 4 2 1 1 55 53 156 175 +353 4 2 1 1 61 166 156 168 +354 4 2 1 1 114 135 127 51 +355 4 2 1 1 67 161 171 175 +356 4 2 1 1 127 135 123 157 +357 4 2 1 1 61 95 166 168 +358 4 2 1 1 148 146 163 178 +359 4 2 1 1 156 166 155 168 +360 4 2 1 1 136 126 113 157 +361 4 2 1 1 153 155 166 167 +362 4 2 1 1 87 6 5 165 +363 4 2 1 1 153 164 161 169 +364 4 2 1 1 9 41 158 177 +365 4 2 1 1 129 157 131 160 +366 4 2 1 1 67 55 161 175 +367 4 2 1 1 101 50 96 157 +368 4 2 1 1 156 161 153 170 +369 4 2 1 1 155 171 154 173 +370 4 2 1 1 46 160 164 170 +371 4 2 1 1 59 61 156 168 +372 4 2 1 1 3 136 113 157 +373 4 2 1 1 150 49 112 178 +374 4 2 1 1 115 157 43 165 +375 4 2 1 1 158 162 146 163 +376 4 2 1 1 97 39 87 155 +377 4 2 1 1 145 146 162 163 +378 4 2 1 1 102 43 115 157 +379 4 2 1 1 117 155 97 168 +380 4 2 1 1 154 155 173 177 +381 4 2 1 1 155 156 153 166 +382 4 2 1 1 77 40 155 165 +383 4 2 1 1 129 131 130 160 +384 4 2 1 1 9 158 173 177 +385 4 2 1 1 158 163 146 178 +386 4 2 1 1 150 112 142 178 +387 4 2 1 1 154 161 156 175 +388 4 2 1 1 41 172 158 177 +389 4 2 1 1 133 131 123 159 +390 4 2 1 1 126 50 113 157 +391 4 2 1 1 117 97 95 168 +392 4 2 1 1 56 156 65 170 +393 4 2 1 1 3 127 136 157 +394 4 2 1 1 125 130 133 164 +395 4 2 1 1 101 113 50 157 +396 4 2 1 1 51 102 115 157 +397 4 2 1 1 125 159 81 164 +398 4 2 1 1 153 155 165 169 +399 4 2 1 1 153 165 155 167 +400 4 2 1 1 87 165 5 167 +401 4 2 1 1 87 39 6 155 +402 4 2 1 1 37 89 137 160 +403 4 2 1 1 107 70 161 169 +404 4 2 1 1 46 160 132 164 +405 4 2 1 1 40 106 77 155 +406 4 2 1 1 125 133 159 164 +407 4 2 1 1 67 171 163 175 +408 4 2 1 1 59 60 61 168 +409 4 2 1 1 131 157 123 159 +410 4 2 1 1 127 114 51 157 +411 4 2 1 1 118 156 59 166 +412 4 2 1 1 117 39 97 155 +413 4 2 1 1 116 141 151 158 +414 4 2 1 1 101 157 96 167 +415 4 2 1 1 72 161 73 171 +416 4 2 1 1 53 65 56 156 +417 4 2 1 1 67 55 79 161 +418 4 2 1 1 96 160 90 167 +419 4 2 1 1 126 131 129 157 +420 4 2 1 1 43 157 4 165 +421 4 2 1 1 105 166 97 167 +422 4 2 1 1 157 159 153 165 +423 4 2 1 1 153 156 155 161 +424 4 2 1 1 59 156 61 166 +425 4 2 1 1 155 161 154 171 +426 4 2 1 1 107 159 82 169 +427 4 2 1 1 72 73 75 171 +428 4 2 1 1 107 81 159 164 +429 4 2 1 1 145 140 163 175 +430 4 2 1 1 95 97 105 166 +431 4 2 1 1 153 161 155 169 +432 4 2 1 1 156 166 118 170 +433 4 2 1 1 115 78 92 159 +434 4 2 1 1 10 116 151 158 +435 4 2 1 1 63 166 160 170 +436 4 2 1 1 96 89 90 160 +437 4 2 1 1 43 102 4 157 +438 4 2 1 1 124 132 46 160 +439 4 2 1 1 102 51 114 157 +440 4 2 1 1 4 165 157 167 +441 4 2 1 1 124 46 83 160 +442 4 2 1 1 145 163 162 175 +443 4 2 1 1 130 132 160 164 +444 4 2 1 1 61 60 95 168 +445 4 2 1 1 85 106 40 155 +446 4 2 1 1 154 171 161 175 +447 4 2 1 1 151 142 10 158 +448 4 2 1 1 83 160 46 170 +449 4 2 1 1 137 124 83 160 +450 4 2 1 1 47 125 81 164 +451 4 2 1 1 136 127 126 157 +452 4 2 1 1 107 70 79 161 +453 4 2 1 1 85 155 7 177 +454 4 2 1 1 9 41 98 158 +455 4 2 1 1 77 84 40 165 +456 4 2 1 1 39 155 117 177 +457 4 2 1 1 58 162 172 176 +458 4 2 1 1 5 165 4 167 +459 4 2 1 1 104 159 78 169 +460 4 2 1 1 9 8 41 177 +461 4 2 1 1 59 168 156 176 +462 4 2 1 1 98 158 41 172 +463 4 2 1 1 155 156 154 161 +464 4 2 1 1 78 115 120 165 +465 4 2 1 1 112 158 142 178 +466 4 2 1 1 109 83 46 170 +467 4 2 1 1 112 99 158 178 +468 4 2 1 1 112 49 99 178 +469 4 2 1 1 125 134 81 159 +470 4 2 1 1 63 118 59 166 +471 4 2 1 1 101 4 157 167 +472 4 2 1 1 154 162 158 163 +473 4 2 1 1 156 175 53 176 +474 4 2 1 1 71 73 72 161 +475 4 2 1 1 123 131 127 157 +476 4 2 1 1 155 168 117 177 +477 4 2 1 1 153 165 159 169 +478 4 2 1 1 137 83 37 160 +479 4 2 1 1 73 161 71 169 +480 4 2 1 1 66 67 163 175 +481 4 2 1 1 9 173 8 177 +482 4 2 1 1 46 164 121 170 +483 4 2 1 1 153 159 164 169 +484 4 2 1 1 48 116 98 174 +485 4 2 1 1 88 105 97 167 +486 4 2 1 1 116 158 98 174 +487 4 2 1 1 139 57 52 162 +488 4 2 1 1 160 166 90 167 +489 4 2 1 1 103 163 171 178 +490 4 2 1 1 145 147 140 175 +491 4 2 1 1 153 160 157 167 +492 4 2 1 1 104 92 78 159 +493 4 2 1 1 140 66 163 175 +494 4 2 1 1 101 44 4 167 +495 4 2 1 1 124 130 132 160 +496 4 2 1 1 113 101 3 157 +497 4 2 1 1 158 172 98 174 +498 4 2 1 1 154 163 158 178 +499 4 2 1 1 58 162 35 172 +500 4 2 1 1 67 68 163 171 +501 4 2 1 1 141 158 116 174 +502 4 2 1 1 118 166 63 170 +503 4 2 1 1 152 162 144 174 +504 4 2 1 1 3 114 127 157 +505 4 2 1 1 107 82 70 169 +506 4 2 1 1 120 115 43 165 +507 4 2 1 1 107 47 81 164 +508 4 2 1 1 108 160 63 166 +509 4 2 1 1 85 40 7 155 +510 4 2 1 1 35 162 152 174 +511 4 2 1 1 172 173 158 177 +512 4 2 1 1 139 52 147 162 +513 4 2 1 1 44 5 4 167 +514 4 2 1 1 107 81 82 159 +515 4 2 1 1 78 165 120 169 +516 4 2 1 1 6 84 5 165 +517 4 2 1 1 144 152 139 162 +518 4 2 1 1 54 156 53 176 +519 4 2 1 1 35 172 162 174 +520 4 2 1 1 98 172 94 174 +521 4 2 1 1 99 9 158 173 +522 4 2 1 1 7 6 39 155 +523 4 2 1 1 140 45 66 175 +524 4 2 1 1 151 141 142 158 +525 4 2 1 1 124 129 130 160 +526 4 2 1 1 5 43 4 165 +527 4 2 1 1 54 65 53 156 +528 4 2 1 1 145 162 147 175 +529 4 2 1 1 69 67 161 171 +530 4 2 1 1 129 124 137 160 +531 4 2 1 1 86 39 117 177 +532 4 2 1 1 148 145 140 163 +533 4 2 1 1 102 114 3 157 +534 4 2 1 1 143 35 152 174 +535 4 2 1 1 154 156 155 168 +536 4 2 1 1 149 148 163 178 +537 4 2 1 1 70 67 79 161 +538 4 2 1 1 153 164 160 170 +539 4 2 1 1 54 59 118 156 +540 4 2 1 1 7 155 39 177 +541 4 2 1 1 101 4 3 157 +542 4 2 1 1 59 60 168 176 +543 4 2 1 1 152 139 57 14 +544 4 2 1 1 125 133 134 159 +545 4 2 1 1 99 173 158 178 +546 4 2 1 1 56 121 164 170 +547 4 2 1 1 142 138 150 178 +548 4 2 1 1 146 162 158 174 +549 4 2 1 1 99 42 9 173 +550 4 2 1 1 112 10 142 158 +551 4 2 1 1 58 57 162 176 +552 4 2 1 1 49 150 91 178 +553 4 2 1 1 144 162 146 174 +554 4 2 1 1 4 102 3 157 +555 4 2 1 1 46 93 121 164 +556 4 2 1 1 38 123 92 159 +557 4 2 1 1 103 36 163 178 +558 4 2 1 1 83 63 108 160 +559 4 2 1 1 65 156 118 170 +560 4 2 1 1 68 66 67 163 +561 4 2 1 1 147 45 140 175 +562 4 2 1 1 54 118 65 156 +563 4 2 1 1 154 158 173 178 +564 4 2 1 1 128 137 25 89 +565 4 2 1 1 71 161 72 171 +566 4 2 1 1 52 175 162 176 +567 4 2 1 1 48 98 94 174 +568 4 2 1 1 69 67 70 161 +569 4 2 1 1 52 162 57 176 +570 4 2 1 1 103 171 76 178 +571 4 2 1 1 123 38 134 159 +572 4 2 1 1 142 158 146 178 +573 4 2 1 1 86 117 168 177 +574 4 2 1 1 98 41 94 172 +575 4 2 1 1 131 126 127 157 +576 4 2 1 1 88 97 87 167 +577 4 2 1 1 112 99 10 158 +578 4 2 1 1 56 93 122 164 +579 4 2 1 1 9 42 8 173 +580 4 2 1 1 91 150 138 178 +581 4 2 1 1 147 162 52 175 +582 4 2 1 1 99 100 173 178 +583 4 2 1 1 75 76 171 173 +584 4 2 1 1 138 146 148 178 +585 4 2 1 1 10 99 9 158 +586 4 2 1 1 157 165 153 167 +587 4 2 1 1 144 145 146 162 +588 4 2 1 1 77 120 165 169 +589 4 2 1 1 149 138 148 178 +590 4 2 1 1 137 26 83 124 +591 4 2 1 1 149 163 36 178 +592 4 2 1 1 87 5 44 167 +593 4 2 1 1 153 166 160 167 +594 4 2 1 1 154 173 163 178 +595 4 2 1 1 71 69 161 171 +596 4 2 1 1 70 71 161 169 +597 4 2 1 1 153 160 166 170 +598 4 2 1 1 154 175 156 176 +599 4 2 1 1 61 95 105 166 +600 4 2 1 1 48 141 116 174 +601 4 2 1 1 10 98 116 158 +602 4 2 1 1 66 55 67 175 +603 4 2 1 1 90 166 105 167 +604 4 2 1 1 56 121 93 164 +605 4 2 1 1 156 153 166 170 +606 4 2 1 1 9 98 10 158 +607 4 2 1 1 7 40 6 155 +608 4 2 1 1 58 57 35 162 +609 4 2 1 1 163 173 171 178 +610 4 2 1 1 46 132 93 164 +611 4 2 1 1 111 75 85 173 +612 4 2 1 1 139 57 15 52 +613 4 2 1 1 171 173 76 178 +614 4 2 1 1 62 58 35 172 +615 4 2 1 1 29 125 47 164 +616 4 2 1 1 80 172 35 174 +617 4 2 1 1 17 66 140 45 +618 4 2 1 1 77 78 120 169 +619 4 2 1 1 138 142 146 178 +620 4 2 1 1 119 140 66 163 +621 4 2 1 1 90 89 37 160 +622 4 2 1 1 86 7 39 177 +623 4 2 1 1 73 71 74 169 +624 4 2 1 1 134 38 81 159 +625 4 2 1 1 149 36 138 178 +626 4 2 1 1 59 156 54 176 +627 4 2 1 1 154 171 163 173 +628 4 2 1 1 117 110 86 168 +629 4 2 1 1 63 59 61 166 +630 4 2 1 1 123 134 133 159 +631 4 2 1 1 141 146 158 174 +632 4 2 1 1 75 111 76 173 +633 4 2 1 1 86 168 110 177 +634 4 2 1 1 36 91 138 178 +635 4 2 1 1 82 159 104 169 +636 4 2 1 1 93 29 47 164 +637 4 2 1 1 158 172 154 173 +638 4 2 1 1 81 47 30 125 +639 4 2 1 1 37 26 83 137 +640 4 2 1 1 52 53 175 176 +641 4 2 1 1 154 173 172 177 +642 4 2 1 1 146 142 141 158 +643 4 2 1 1 90 160 108 166 +644 4 2 1 1 70 82 71 169 +645 4 2 1 1 163 171 154 175 +646 4 2 1 1 44 101 96 167 +647 4 2 1 1 73 74 77 169 +648 4 2 1 1 158 162 154 172 +649 4 2 1 1 152 57 35 14 +650 4 2 1 1 71 72 69 171 +651 4 2 1 1 143 152 144 174 +652 4 2 1 1 62 60 58 168 +653 4 2 1 1 92 51 135 33 +654 4 2 1 1 48 143 141 174 +655 4 2 1 1 91 49 21 150 +656 4 2 1 1 42 85 8 173 +657 4 2 1 1 99 49 100 178 +658 4 2 1 1 130 125 132 164 +659 4 2 1 1 41 110 172 177 +660 4 2 1 1 15 147 139 52 +661 4 2 1 1 64 117 95 168 +662 4 2 1 1 13 143 35 152 +663 4 2 1 1 136 3 2 127 +664 4 2 1 1 58 168 60 176 +665 4 2 1 1 103 76 36 178 +666 4 2 1 1 10 1 142 151 +667 4 2 1 1 64 110 168 172 +668 4 2 1 1 138 91 21 150 +669 4 2 1 1 52 54 53 176 +670 4 2 1 1 38 82 81 159 +671 4 2 1 1 67 69 68 171 +672 4 2 1 1 138 91 36 20 +673 4 2 1 1 92 135 123 33 +674 4 2 1 1 48 80 143 174 +675 4 2 1 1 8 173 85 177 +676 4 2 1 1 27 46 83 124 +677 4 2 1 1 70 71 69 161 +678 4 2 1 1 103 163 68 171 +679 4 2 1 1 119 149 140 163 +680 4 2 1 1 147 17 140 45 +681 4 2 1 1 137 37 25 89 +682 4 2 1 1 168 172 110 177 +683 4 2 1 1 46 121 109 170 +684 4 2 1 1 149 119 36 163 +685 4 2 1 1 154 168 155 177 +686 4 2 1 1 64 168 62 172 +687 4 2 1 1 38 92 104 159 +688 4 2 1 1 109 118 63 170 +689 4 2 1 1 59 58 60 176 +690 4 2 1 1 75 76 72 171 +691 4 2 1 1 38 104 82 159 +692 4 2 1 1 99 100 42 173 +693 4 2 1 1 143 80 35 174 +694 4 2 1 1 162 163 154 175 +695 4 2 1 1 138 36 149 20 +696 4 2 1 1 117 64 110 168 +697 4 2 1 1 36 68 103 163 +698 4 2 1 1 90 105 88 167 +699 4 2 1 1 80 62 35 172 +700 4 2 1 1 139 145 144 162 +701 4 2 1 1 147 52 45 175 +702 4 2 1 1 141 144 146 174 +703 4 2 1 1 56 65 121 170 +704 4 2 1 1 108 90 37 160 +705 4 2 1 1 134 81 30 125 +706 4 2 1 1 154 156 168 176 +707 4 2 1 1 148 140 149 163 +708 4 2 1 1 123 32 38 92 +709 4 2 1 1 116 11 151 141 +710 4 2 1 1 119 18 66 140 +711 4 2 1 1 113 136 23 126 +712 4 2 1 1 83 108 37 160 +713 4 2 1 1 145 139 147 162 +714 4 2 1 1 96 90 88 167 +715 4 2 1 1 68 36 119 163 +716 4 2 1 1 76 173 100 178 +717 4 2 1 1 64 62 110 172 +718 4 2 1 1 64 60 62 168 +719 4 2 1 1 64 95 60 168 +720 4 2 1 1 12 143 141 48 +721 4 2 1 1 74 104 78 169 +722 4 2 1 1 48 12 143 80 +723 4 2 1 1 154 172 168 177 +724 4 2 1 1 52 57 54 176 +725 4 2 1 1 77 74 78 169 +726 4 2 1 1 119 66 68 163 +727 4 2 1 1 43 5 84 165 +728 4 2 1 1 162 154 172 176 +729 4 2 1 1 77 120 84 165 +730 4 2 1 1 38 32 123 134 +731 4 2 1 1 47 122 93 164 +732 4 2 1 1 42 111 85 173 +733 4 2 1 1 100 76 111 173 +734 4 2 1 1 66 45 55 175 +735 4 2 1 1 127 3 2 114 +736 4 2 1 1 162 172 158 174 +737 4 2 1 1 168 172 154 176 +738 4 2 1 1 41 86 110 177 +739 4 2 1 1 109 65 118 170 +740 4 2 1 1 1 10 142 112 +741 4 2 1 1 87 44 88 167 +742 4 2 1 1 74 71 82 169 +743 4 2 1 1 41 8 86 177 +744 4 2 1 1 46 27 132 124 +745 4 2 1 1 43 84 120 165 +746 4 2 1 1 13 143 80 35 +747 4 2 1 1 8 85 7 177 +748 4 2 1 1 82 104 74 169 +749 4 2 1 1 91 36 76 178 +750 4 2 1 1 103 72 76 171 +751 4 2 1 1 80 94 172 174 +752 4 2 1 1 132 93 28 46 +753 4 2 1 1 116 11 141 48 +754 4 2 1 1 126 23 113 50 +755 4 2 1 1 94 41 110 172 +756 4 2 1 1 69 103 68 171 +757 4 2 1 1 45 147 16 52 +758 4 2 1 1 26 27 83 124 +759 4 2 1 1 80 48 94 174 +760 4 2 1 1 15 57 139 14 +761 4 2 1 1 24 23 126 50 +762 4 2 1 1 90 108 105 166 +763 4 2 1 1 91 100 49 178 +764 4 2 1 1 38 81 31 134 +765 4 2 1 1 105 108 61 166 +766 4 2 1 1 150 22 142 112 +767 4 2 1 1 138 21 91 20 +768 4 2 1 1 59 54 58 176 +769 4 2 1 1 114 127 135 34 +770 4 2 1 1 2 3 136 113 +771 4 2 1 1 1 10 116 151 +772 4 2 1 1 154 162 175 176 +773 4 2 1 1 119 149 18 140 +774 4 2 1 1 17 147 16 45 +775 4 2 1 1 61 108 63 166 +776 4 2 1 1 29 30 47 125 +777 4 2 1 1 92 123 32 33 +778 4 2 1 1 76 100 91 178 +779 4 2 1 1 93 28 29 132 +780 4 2 1 1 121 65 109 170 +781 4 2 1 1 58 54 57 176 +782 4 2 1 1 100 111 42 173 +783 4 2 1 1 140 18 66 17 +784 4 2 1 1 21 49 22 150 +785 4 2 1 1 8 7 86 177 +786 4 2 1 1 94 110 62 172 +787 4 2 1 1 12 141 11 48 +788 4 2 1 1 96 88 44 167 +789 4 2 1 1 80 94 62 172 +790 4 2 1 1 49 22 150 112 +791 4 2 1 1 45 53 55 175 +792 4 2 1 1 135 114 34 51 +793 4 2 1 1 45 52 53 175 +794 4 2 1 1 13 143 12 80 +795 4 2 1 1 22 1 142 112 +796 4 2 1 1 37 25 26 137 +797 4 2 1 1 114 2 127 34 +798 4 2 1 1 19 149 36 20 +799 4 2 1 1 81 30 31 134 +800 4 2 1 1 119 19 149 36 +801 4 2 1 1 69 72 103 171 +802 4 2 1 1 15 16 147 52 +803 4 2 1 1 128 25 24 89 +804 4 2 1 1 51 34 135 33 +805 4 2 1 1 144 141 143 174 +806 4 2 1 1 11 1 116 151 +807 4 2 1 1 38 31 32 134 +808 4 2 1 1 136 23 2 113 +809 4 2 1 1 28 27 132 46 +810 4 2 1 1 35 13 152 14 +811 4 2 1 1 149 18 19 119 +812 4 2 1 1 161 106 169 73 +813 4 2 1 1 161 169 106 155 +814 4 2 1 1 168 97 166 155 +815 4 2 1 1 168 166 97 95 +816 4 2 1 1 159 51 115 157 +817 4 2 1 1 159 115 51 92 +818 4 2 1 1 165 40 6 84 +819 4 2 1 1 165 6 40 155 +820 4 2 1 1 126 89 24 50 +821 4 2 1 1 24 89 126 128 +822 4 2 1 1 170 83 63 109 +823 4 2 1 1 170 63 83 160 +824 4 2 1 1 135 92 159 51 +825 4 2 1 1 159 92 135 123 +826 4 2 1 1 159 157 135 51 +827 4 2 1 1 135 157 159 123 +828 4 2 1 1 152 57 162 35 +829 4 2 1 1 152 162 57 139 +830 4 2 1 1 164 29 132 93 +831 4 2 1 1 164 132 29 125 +832 4 2 1 1 172 58 168 62 +833 4 2 1 1 172 168 58 176 +834 4 2 1 1 79 47 164 122 +835 4 2 1 1 79 164 47 107 $EndElements $Periodic 1 2 3 2 Affine 0.5000000000000001 -0.8660254037844386 0 0 0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1 -84 -308 250 -337 279 -342 284 -340 282 -345 287 -341 283 -309 251 -307 249 -344 286 -294 236 -339 281 -349 291 -347 289 -350 292 -348 290 -343 285 -310 252 -293 235 -298 240 -299 241 -301 243 -303 245 -302 244 -304 246 -305 247 -306 248 -325 267 -324 266 -333 275 -323 265 -300 242 -317 259 -318 260 -319 261 -320 262 -329 271 -295 237 -326 268 -322 264 -297 239 -328 270 -296 238 -327 269 -321 263 -316 258 -346 288 -314 256 -315 257 -311 253 -313 255 -312 254 -330 272 -331 273 -332 274 -338 280 -334 276 -335 277 -336 278 -13 38 -15 40 -36 61 -37 62 -17 42 -14 39 -18 43 -16 41 -19 44 -23 48 -22 47 -21 46 -20 45 -35 60 -34 59 -33 58 -32 57 -27 52 -26 51 -25 50 -24 49 -31 56 -30 55 -29 54 -28 53 +28 +152 137 +141 126 +147 132 +150 135 +149 134 +145 130 +139 124 +144 129 +143 128 +140 125 +138 123 +148 133 +142 127 +151 136 +146 131 +11 23 +12 24 +13 25 +16 28 +14 26 +17 29 +15 27 +18 30 +21 33 +19 31 +22 34 +20 32 1 2 $EndPeriodic diff --git a/examples/ex11p.cpp b/examples/ex11p.cpp index 1dc807f859..5b89a46524 100644 --- a/examples/ex11p.cpp +++ b/examples/ex11p.cpp @@ -8,6 +8,8 @@ // mpirun -np 4 ex11p -m ../data/escher.mesh // mpirun -np 4 ex11p -m ../data/fichera.mesh // mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh +// mpirun -np 4 ex11p -m ../data/annulus-pi-3.msh +// mpirun -np 4 ex11p -m ../data/torus-pi-3.msh -rs 1 // mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2 // mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2 // mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3 From 4c4aeaeec3d0288a8e2827e8cbd7eaf61e3afce6 Mon Sep 17 00:00:00 2001 From: psocratis Date: Tue, 2 Jun 2020 15:51:28 -0700 Subject: [PATCH 437/535] renamed example --- tests/convergence/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/convergence/makefile b/tests/convergence/makefile index b723de9dc1..3c11042d98 100644 --- a/tests/convergence/makefile +++ b/tests/convergence/makefile @@ -22,7 +22,7 @@ MFEM_LIB_FILE = mfem_is_not_built -include $(CONFIG_MK) SEQ_EXAMPLES = -PAR_EXAMPLES = BAE +PAR_EXAMPLES = bae ifeq ($(MFEM_USE_MPI),NO) EXAMPLES = $(SEQ_EXAMPLES) From 20849249cd39c64798cc10b481719bd3e4896c0d Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 2 Jun 2020 15:52:13 -0700 Subject: [PATCH 438/535] Remove duplicate CHANGELOG entry. --- CHANGELOG | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c46978d523..8790a411f6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -68,6 +68,8 @@ Discretization improvements Additionaly, new LinearForm integrators were also added which make use of these new QuadratureFunction coefficient classes. +- Added support face integrals on the boundaries of NURBS meshes. + Linear and nonlinear solvers ---------------------------- - Added power method to iteratively estimate the largest eigenvalue and the @@ -90,12 +92,6 @@ Linear and nonlinear solvers New and updated examples and miniapps ------------------------------------- -- Adding a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of - stitching together opposite surfaces of a mesh to create a topologically - periodic mesh. - -- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp. - - Added a new example, Example 25/25p, to demonstrate the use of a Perfectly Matched Layer (PML) for the simulation of electromagnetic wave propagation. The example defines and solves several indefinite Maxwell problems. @@ -116,14 +112,14 @@ New and updated examples and miniapps - Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem: the Dirichlet problem for the minimal surface equation. -- Added support face integrals on the boundaries of NURBS meshes. - - Added partial assembly support to examples 4/4p and 5/5p, with diagonal preconditioning. - Added a new test problem in example 24/24p, demonstrating a mixed bilinear form for H(div) and L_2, with partial assembly support. +- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp. + Improved testing ---------------- - Added a GitLab pipeline that automates PR testing on supercomputing systems From fb1de283a77187615d09969877d8642653733e34 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 2 Jun 2020 15:53:47 -0700 Subject: [PATCH 439/535] Remove extra empty line from CHANGELOG. --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 8790a411f6..87db5b5726 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,7 +91,6 @@ Linear and nonlinear solvers New and updated examples and miniapps ------------------------------------- - - Added a new example, Example 25/25p, to demonstrate the use of a Perfectly Matched Layer (PML) for the simulation of electromagnetic wave propagation. The example defines and solves several indefinite Maxwell problems. From df3d0b51c2825f25ce44b848a73aac0c053469da Mon Sep 17 00:00:00 2001 From: psocratis Date: Tue, 2 Jun 2020 15:54:36 -0700 Subject: [PATCH 440/535] renamed example name --- tests/convergence/{BAE.cpp => bae.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/convergence/{BAE.cpp => bae.cpp} (100%) diff --git a/tests/convergence/BAE.cpp b/tests/convergence/bae.cpp similarity index 100% rename from tests/convergence/BAE.cpp rename to tests/convergence/bae.cpp From 53a8346c956cd458926d778ee7b73c72a0fee7cb Mon Sep 17 00:00:00 2001 From: Arturo Date: Tue, 2 Jun 2020 22:16:16 -0700 Subject: [PATCH 441/535] fix dtensor header --- tests/unit/linalg/test_matrix_dense.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index 5bc2ec25ce..14fce4f686 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -11,7 +11,7 @@ #include "mfem.hpp" #include "catch.hpp" -#include "../../../linalg/dtensor.hpp" +#include "linalg/dtensor.hpp" using namespace mfem; From 68908783d8c4c88b13d30cbc1e95c19439672a1b Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Wed, 3 Jun 2020 16:53:07 +0200 Subject: [PATCH 442/535] Adding tests to GNU make file --- miniapps/nurbs/makefile | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/miniapps/nurbs/makefile b/miniapps/nurbs/makefile index 91732de66a..3c75a3596a 100644 --- a/miniapps/nurbs/makefile +++ b/miniapps/nurbs/makefile @@ -54,10 +54,47 @@ RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP) @$(call mfem-test,$<,, NURBS miniapp) # Additional tests -EX1_ARGS_2 := -m ../../data/beam-hex-nurbs.mesh -pm 1 -ps 2 +EX1_ARGS_2 := -no-vis -r 0 -o 4 +EX1_ARGS_3 := -no-vis -r 2 +EX1_ARGS_4 := -no-vis -m ../../data/beam-hex-nurbs.mesh -pm 1 -ps 2 +EX1_ARGS_5 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0 +EX1_ARGS_6 := -no-vis -m ../..//data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2 +EX1_ARGS_7 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0 +EX1_ARGS_8 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2 +EX1_ARGS_9 := -no-vis -m ../../data/ball-nurbs.mesh -o 2 --weak-bc -r 0 +EX1_ARGS_10 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0 +EX1_ARGS_11 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1 + ex1-test-seq: ex1 @$(call mfem-test,$<,, NURBS miniapp) @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_2)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_3)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_4)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_5)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_6)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_7)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_8)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_9)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_10)) + @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_11)) + +EX1P_ARGS_1 := -no-vis +EX1P_ARGS_2 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp +EX1P_ARGS_3 := -no-vis -m ../../data/ball-nurbs.mesh -o 2 --weak-bc -r 0 +EX1P_ARGS_4 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0 +EX1P_ARGS_5 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1 + +ex1p-test-par: % + @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_1)) + @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_2)) + @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_3)) + @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_4)) + @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_5)) + +EX11P_ARGS_1 := -no-vis + +ex11p-test-par: % + @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX11P_ARGS_1)) # Testing: "test" target and mfem-test* variables are defined in config/test.mk From f4eeb1d34ef4d576dcc922b51cf5d52ec85185cd Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Wed, 3 Jun 2020 22:27:39 -0700 Subject: [PATCH 443/535] In cmake builds, the unit tests need the 'data' directory to be copied. --- tests/unit/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 31c0b22419..b20c3a6deb 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -58,6 +58,8 @@ endif() # All serial non-device unit tests are built into a single executable 'unit_tests'. add_executable(unit_tests unit_test_main.cpp ${UNIT_TESTS_SRCS}) +# Unit tests need the ../../data directory. +add_dependencies(unit_tests copy_data) target_link_libraries(unit_tests mfem) # All device unit tests are built into another executable, in order to be able From 88261ed314c3316a8e93fde9ac4e606ba7c35da0 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Thu, 4 Jun 2020 13:43:13 -0700 Subject: [PATCH 444/535] Two small bugfixes. --- general/mem_manager.hpp | 8 ++++---- miniapps/navier/makefile | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index eb830e06b1..a3b2ccf78a 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -450,16 +450,16 @@ private: template struct Alloc { +#if __cplusplus < 201703L static inline T *New(std::size_t) { -#if __cplusplus < 201703L // Generate an error in debug mode MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST"); return nullptr; -#else - return new T[size]; -#endif } +#else + static inline T *New(std::size_t size) { return new T[size]; } +#endif }; #if __cplusplus < 201703L diff --git a/miniapps/navier/makefile b/miniapps/navier/makefile index fefd1622a0..e6f85900bd 100644 --- a/miniapps/navier/makefile +++ b/miniapps/navier/makefile @@ -12,7 +12,7 @@ # Use the MFEM build directory MFEM_DIR ?= ../.. MFEM_BUILD_DIR ?= ../.. -# SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/navier/,) +SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/navier/,) CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk # Use the MFEM install directory # MFEM_INSTALL_DIR = ../../mfem @@ -40,10 +40,10 @@ endif %: %.cpp %.o: %.cpp -%: %.cpp $(NAVIER_COMMON_OBJ) +%: $(SRC)%.cpp $(NAVIER_COMMON_OBJ) $(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(NAVIER_COMMON_OBJ) $(MFEM_LIBS) -%.o: %.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) +%.o: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) $(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@ all: $(MINIAPPS) From b8811828aaf500ccbbfb89ea431fb4142e654375 Mon Sep 17 00:00:00 2001 From: Dylan Copeland Date: Thu, 4 Jun 2020 15:37:28 -0700 Subject: [PATCH 445/535] Fixing big integer issue with recent versions of hypre, in HypreParMatrixFromBlocks. --- linalg/hypre.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index 02ff6b6c56..3edd15dcd4 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -20,6 +20,7 @@ #include #include #include +#include // INT_MAX using namespace std; @@ -1856,6 +1857,11 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, (*(blocks(i, j))); MFEM_ASSERT(parcsr_op != NULL, "const_cast failed"); csr_blocks(i, j) = hypre_MergeDiagAndOffd(parcsr_op); +#if MFEM_HYPRE_VERSION >= 21600 + MFEM_VERIFY(csr_blocks(i, j)->num_rows < INT_MAX,"Number of " + "local rows is too large to store as an integer."); + hypre_CSRMatrixBigJtoJ(csr_blocks(i, j)); +#endif } for (int k = 0; k < csr_blocks(i, j)->num_rows; ++k) From 1e1cb2d842b02ff6e9d77c4d6154389cfbf6aac9 Mon Sep 17 00:00:00 2001 From: Ido Akkerman Date: Fri, 5 Jun 2020 18:14:46 +0200 Subject: [PATCH 446/535] small corrections to makefile --- miniapps/nurbs/makefile | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/miniapps/nurbs/makefile b/miniapps/nurbs/makefile index 3c75a3596a..b400c136af 100644 --- a/miniapps/nurbs/makefile +++ b/miniapps/nurbs/makefile @@ -54,18 +54,18 @@ RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP) @$(call mfem-test,$<,, NURBS miniapp) # Additional tests -EX1_ARGS_2 := -no-vis -r 0 -o 4 -EX1_ARGS_3 := -no-vis -r 2 -EX1_ARGS_4 := -no-vis -m ../../data/beam-hex-nurbs.mesh -pm 1 -ps 2 -EX1_ARGS_5 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0 -EX1_ARGS_6 := -no-vis -m ../..//data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2 -EX1_ARGS_7 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0 -EX1_ARGS_8 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2 -EX1_ARGS_9 := -no-vis -m ../../data/ball-nurbs.mesh -o 2 --weak-bc -r 0 -EX1_ARGS_10 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0 -EX1_ARGS_11 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1 +EX1_ARGS_2 := -r 0 -o 4 +EX1_ARGS_3 := -r 2 +EX1_ARGS_4 := -m ../../data/beam-hex-nurbs.mesh -pm 1 -ps 2 +EX1_ARGS_5 := -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 0 +EX1_ARGS_6 := -m ../..//data/pipe-nurbs-2d.mesh -o 2 -no-ibp -r 2 +EX1_ARGS_7 := -m ../../data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 0 +EX1_ARGS_8 := -m ../../data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2 +EX1_ARGS_9 := -m ../../data/ball-nurbs.mesh -o 2 --weak-bc -r 0 +EX1_ARGS_10 := -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0 +EX1_ARGS_11 := -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1 -ex1-test-seq: ex1 +nurbs_ex1-test-seq: nurbs_ex1 @$(call mfem-test,$<,, NURBS miniapp) @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_2)) @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_3)) @@ -78,22 +78,22 @@ ex1-test-seq: ex1 @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_10)) @$(call mfem-test,$<,, NURBS miniapp,$(EX1_ARGS_11)) -EX1P_ARGS_1 := -no-vis -EX1P_ARGS_2 := -no-vis -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp -EX1P_ARGS_3 := -no-vis -m ../../data/ball-nurbs.mesh -o 2 --weak-bc -r 0 -EX1P_ARGS_4 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0 -EX1P_ARGS_5 := -no-vis -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1 +EX1P_ARGS_1 := +EX1P_ARGS_2 := -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp +EX1P_ARGS_3 := -m ../../data/ball-nurbs.mesh -o 2 --weak-bc -r 0 +EX1P_ARGS_4 := -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 0 +EX1P_ARGS_5 := -m ../../data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1 -ex1p-test-par: % +nurbs_ex1p-test-par: nurbs_ex1p @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_1)) @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_2)) @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_3)) @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_4)) @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX1P_ARGS_5)) -EX11P_ARGS_1 := -no-vis +EX11P_ARGS_1 := -ex11p-test-par: % +nurbs_ex11p-test-par: nurbs_ex11p @$(call mfem-test,$<, $(RUN_MPI), NURBS miniapp,$(EX11P_ARGS_1)) # Testing: "test" target and mfem-test* variables are defined in config/test.mk From e89fb16c4275a63311825b01d138d4acd7ee8185 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 5 Jun 2020 20:29:09 -0700 Subject: [PATCH 447/535] In class FiniteElementSpace: * Add protected methods BuildBdrElementToDofTable() and BuildFaceToDofTable(). * Return 'const Table &' instead of 'const Table *' from the methods GetBdrElementToDofTable() and GetFaceToDofTable() -- these methods will now build their respective tables if they are not already built. * Renamed GenerateFaceDofsFromBdr() to BuildNURBSFaceToDofTable() and made it a protected method. This method no longer needs to be called explicitly outside of the class to allow calling GetFaceDofs() and GetFaceElement() with NURBS spaces -- these two methods will automatically call BuildNURBSFaceToDofTable() when needed. * The Table face_dof is no longer generated by the constructor for NURBS meshes -- it will be auto-generated when needed by other methods. * Added a check in BuildNURBSFaceToDofTable() to see if a boundary element and its corresponding face element have the same orientation, i.e. their vertices are ordered the same. In some cases this assumption does not hold, so we may need to generalize the code to support such cases. * Added documentation to several methods. In class Mesh: * Removed the method BdrInfoAvailable() -- it should always return true. * Removed explicit calls to Nodes->FESpace()->GenerateFaceDofsFromBdr() in the case of NURBS meshes -- they are no longer required. --- fem/fespace.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++----- fem/fespace.hpp | 46 +++++++++++++++++++------- mesh/mesh.cpp | 17 ---------- mesh/mesh.hpp | 4 --- 4 files changed, 113 insertions(+), 41 deletions(-) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 554c4a769a..fd9894d201 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -233,6 +233,54 @@ void FiniteElementSpace::BuildElementToDofTable() const elem_dof = el_dof; } +void FiniteElementSpace::BuildBdrElementToDofTable() const +{ + if (bdrElem_dof) { return; } + + Table *bel_dof = new Table; + Array dofs; + bel_dof->MakeI(mesh->GetNBE()); + for (int i = 0; i < mesh->GetNBE(); i++) + { + GetBdrElementDofs(i, dofs); + bel_dof->AddColumnsInRow(i, dofs.Size()); + } + bel_dof->MakeJ(); + for (int i = 0; i < mesh->GetNBE(); i++) + { + GetBdrElementDofs(i, dofs); + bel_dof->AddConnections(i, (int *)dofs, dofs.Size()); + } + bel_dof->ShiftUpI(); + bdrElem_dof = bel_dof; +} + +void FiniteElementSpace::BuildFaceToDofTable() const +{ + // Here, "face" == (dim-1)-dimensional mesh entity. + + if (face_dof) { return; } + + if (NURBSext) { BuildNURBSFaceToDofTable(); return; } + + Table *fc_dof = new Table; + Array dofs; + fc_dof->MakeI(mesh->GetNumFaces()); + for (int i = 0; i < fc_dof->Size(); i++) + { + GetFaceDofs(i, dofs); + fc_dof->AddColumnsInRow(i, dofs.Size()); + } + fc_dof->MakeJ(); + for (int i = 0; i < fc_dof->Size(); i++) + { + GetFaceDofs(i, dofs); + fc_dof->AddConnections(i, (int *)dofs, dofs.Size()); + } + fc_dof->ShiftUpI(); + face_dof = fc_dof; +} + void FiniteElementSpace::RebuildElementToDofTable() { delete elem_dof; @@ -1481,7 +1529,6 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext, own_ext = 1; } UpdateNURBS(); - GenerateFaceDofsFromBdr(); cP = cR = NULL; cP_is_set = false; } @@ -1516,21 +1563,22 @@ void FiniteElementSpace::UpdateNURBS() fdofs = NULL; bdofs = NULL; + delete face_dof; + face_dof = NULL; + face_to_be.DeleteAll(); + dynamic_cast(fec)->Reset(); ndofs = NURBSext->GetNDof(); elem_dof = NURBSext->GetElementDofTable(); bdrElem_dof = NURBSext->GetBdrElementDofTable(); - delete face_dof; - face_dof = NULL; } -void FiniteElementSpace::GenerateFaceDofsFromBdr() +void FiniteElementSpace::BuildNURBSFaceToDofTable() const { if (face_dof) { return; } - if (!mesh->BdrInfoAvailable()) { return; } - // MFEM_VERIFY(bdrElem_dof, "NURBSExt not defined."); + const int dim = mesh->Dimension(); // Find bdr to face mapping face_to_be.SetSize(GetNF()); @@ -1548,7 +1596,22 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() for (int f = 0; f < GetNF(); f++) { int b = face_to_be[f]; - if (b == -1) { continue;} + if (b == -1) { continue; } + // FIXME: this assumes the boundary element and the face element have the + // same orientation. + if (dim > 1) + { + const Element *fe = mesh->GetFace(f); + const Element *be = mesh->GetBdrElement(b); + const int nv = be->GetNVertices(); + const int *fv = fe->GetVertices(); + const int *bv = be->GetVertices(); + for (int i = 0; i < nv; i++) + { + MFEM_VERIFY(fv[i] == bv[i], + "non-matching face and boundary elements detected!"); + } + } GetBdrElementDofs(b, row); Connection conn(f,0); for (int i = 0; i < row.Size(); i++) @@ -1558,7 +1621,6 @@ void FiniteElementSpace::GenerateFaceDofsFromBdr() } } face_dof = new Table(GetNF(), face_dof_list); - } void FiniteElementSpace::Construct() @@ -1831,7 +1893,9 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const { - if (face_dof) + // If face_dof is already built, use it. + // If it is not and we have a NURBS space, build the face_dof and use it. + if (face_dof || (NURBSext && (BuildNURBSFaceToDofTable(), true))) { face_dof->GetRow(i, dofs); } @@ -2021,6 +2085,10 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const if (NURBSext) { + // Ensure 'face_to_be' is built: + if (!face_dof) { BuildNURBSFaceToDofTable(); } + MFEM_ASSERT(face_to_be[i] >= 0, + "NURBS mesh: only boundary faces are supported!"); NURBSext->LoadBE(face_to_be[i], fe); } @@ -2077,6 +2145,7 @@ void FiniteElementSpace::Destroy() { if (own_ext) { delete NURBSext; } delete face_dof; + face_to_be.DeleteAll(); } else { diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 5c99c2fca2..96515dea76 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -111,9 +111,9 @@ protected: int *fdofs, *bdofs; mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned. - Table *bdrElem_dof; // used only with NURBS FE spaces; not owned. - Table *face_dof; // used only with NURBS FE spaces; owned. - Array face_to_be; // used only with NURBS FE spaces; owned. + mutable Table *bdrElem_dof; // not owned only if NURBS FE space. + mutable Table *face_dof; // owned + mutable Array face_to_be; // used only with NURBS FE spaces; owned. Array dof_elem_array, dof_ldof_array; @@ -160,6 +160,14 @@ protected: void Destroy(); void BuildElementToDofTable() const; + void BuildBdrElementToDofTable() const; + void BuildFaceToDofTable() const; + + /** @brief Generates partial face_dof table for a NURBS space. + + The table is only defined for exterior faces that coincide with a + boundary. */ + void BuildNURBSFaceToDofTable() const; /// Helpers to remove encoded sign from a DOF static inline int DecodeDof(int dof) @@ -528,19 +536,35 @@ public: is preserved. */ void ReorderElementToDofTable(); - /** @brief Generates partial face_dof table. + /** @brief Return a reference to the internal Table that stores the lists of + scalar dofs, for each mesh element, as returned by GetElementDofs(). */ + const Table &GetElementToDofTable() const { return *elem_dof; } - The table is only defined for exterior faces that coincide with a boundary. - The routine uses the bdrElem_dof table and the mesh boundary information.*/ - void GenerateFaceDofsFromBdr(); + /** @brief Return a reference to the internal Table that stores the lists of + scalar dofs, for each boundary mesh element, as returned by + GetBdrElementDofs(). */ + const Table &GetBdrElementToDofTable() const + { if (!bdrElem_dof) { BuildBdrElementToDofTable(); } return *bdrElem_dof; } + /** @brief Return a reference to the internal Table that stores the lists of + scalar dofs, for each face in the mesh, as returned by GetFaceDofs(). In + this context, "face" refers to a (dim-1)-dimensional mesh entity. */ + /** @note In the case of a NURBS space, the rows corresponding to interior + faces will be empty. */ + const Table &GetFaceToDofTable() const + { if (!face_dof) { BuildFaceToDofTable(); } return *face_dof; } + + /** @brief Initialize internal data that enables the use of the methods + GetElementForDof() and GetLocalDofForDof(). */ void BuildDofToArrays(); - const Table &GetElementToDofTable() const { return *elem_dof; } - const Table *GetBdrElementToDofTable() const { return bdrElem_dof; } - const Table *GetFaceToDofTable() const { return face_dof; } - + /// Return the index of the first element that contains dof @a i. + /** This method can be called only after setup is performed using the method + BuildDofToArrays(). */ int GetElementForDof(int i) const { return dof_elem_array[i]; } + /// Return the local dof index in the first element that contains dof @a i. + /** This method can be called only after setup is performed using the method + BuildDofToArrays(). */ int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; } /// Returns pointer to the FiniteElement associated with i'th element. diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index ba205deeef..4c301cf6f5 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -3359,10 +3359,6 @@ void Mesh::Loader(std::istream &input, int generate_edges, } } } - else if (NURBSext) - { - Nodes->FESpace()->GenerateFaceDofsFromBdr(); - } // If a parse tag was supplied, keep reading the stream until the tag is // encountered. @@ -3833,7 +3829,6 @@ void Mesh::UpdateNURBS() GetElementToFaceTable(); GenerateFaces(); } - Nodes->FESpace()->GenerateFaceDofsFromBdr(); } void Mesh::LoadPatchTopo(std::istream &input, Array &edge_to_knot) @@ -4804,18 +4799,6 @@ void Mesh::GetBdrElementFace(int i, int *f, int *o) const } } -bool Mesh::BdrInfoAvailable() const -{ - switch (Dim) - { - case 1: return (boundary != NULL); - case 2: return (be_to_edge != NULL); - case 3: return (be_to_face != NULL); - default: mfem_error("Mesh::GetBdrElementEdgeIndex: invalid dimension!"); - } - return false; -} - int Mesh::GetBdrElementEdgeIndex(int i) const { switch (Dim) diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index f5f519de2a..c67c9982fe 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -896,10 +896,6 @@ public: Return the face index of boundary element i. (3D) */ int GetBdrElementEdgeIndex(int i) const; - /** Checks if the boundary data structures required - for GetBdrElementFace() are available.*/ - bool BdrInfoAvailable() const; - /** @brief For the given boundary element, bdr_el, return its adjacent element and its info, i.e. 64*local_bdr_index+bdr_orientation. */ void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const; From 762a258cf1ccc07019b6c1ccab9d7030c45164ad Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 11:37:53 -0700 Subject: [PATCH 448/535] Renaming Gmsh files --- data/{annulus-pi-3.geo => periodic-annulus-sector.geo} | 2 +- data/{annulus-pi-3.msh => periodic-annulus-sector.msh} | 0 data/{torus-pi-3.geo => periodic-torus-sector.geo} | 2 +- data/{torus-pi-3.msh => periodic-torus-sector.msh} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename data/{annulus-pi-3.geo => periodic-annulus-sector.geo} (95%) rename data/{annulus-pi-3.msh => periodic-annulus-sector.msh} (100%) rename data/{torus-pi-3.geo => periodic-torus-sector.geo} (93%) rename data/{torus-pi-3.msh => periodic-torus-sector.msh} (100%) diff --git a/data/annulus-pi-3.geo b/data/periodic-annulus-sector.geo similarity index 95% rename from data/annulus-pi-3.geo rename to data/periodic-annulus-sector.geo index 6df1965af0..655b41bddf 100644 --- a/data/annulus-pi-3.geo +++ b/data/periodic-annulus-sector.geo @@ -34,4 +34,4 @@ Physical Surface(1) = {1}; Mesh 2; Mesh.MshFileVersion = 2.2; -Save "annulus-pi-3.msh"; +Save "periodic-annulus-sector.msh"; diff --git a/data/annulus-pi-3.msh b/data/periodic-annulus-sector.msh similarity index 100% rename from data/annulus-pi-3.msh rename to data/periodic-annulus-sector.msh diff --git a/data/torus-pi-3.geo b/data/periodic-torus-sector.geo similarity index 93% rename from data/torus-pi-3.geo rename to data/periodic-torus-sector.geo index 56901a6f07..05eacae908 100644 --- a/data/torus-pi-3.geo +++ b/data/periodic-torus-sector.geo @@ -22,4 +22,4 @@ Physical Volume(1) = {1}; Mesh 3; Mesh.MshFileVersion = 2.2; -Save "torus-pi-3.msh"; +Save "periodic-torus-sector.msh"; diff --git a/data/torus-pi-3.msh b/data/periodic-torus-sector.msh similarity index 100% rename from data/torus-pi-3.msh rename to data/periodic-torus-sector.msh From d00d9008e8826cef639c28cc34ef67ef63b3f939 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 11:44:52 -0700 Subject: [PATCH 449/535] Updating CHANGELOG --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 720e879a86..ab1a64ead4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,10 @@ Meshing improvements Hessian for r-adaptivity using discrete fields, and allows use of skewness and orientation based metrics. +- Added support for reading periodic meshes written in Gmsh's version 2.2 file + format. Also, including two Gmsh input files and corresponding ".msh" output + files for validating this new functionality. + Improved GPU capabilities ------------------------- - Added support for Chebyshev accelerated polynomial smoother on GPU. From fbcd11dfef52f8e2979dcafa4b1e213ffecf735e Mon Sep 17 00:00:00 2001 From: "Mark L. Stowell" Date: Sun, 7 Jun 2020 12:03:07 -0700 Subject: [PATCH 450/535] Update CHANGELOG Co-authored-by: Tzanio Kolev --- CHANGELOG | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f101b83196..8d5d626105 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,9 +29,9 @@ Meshing improvements - Added TMOP capability for approximate tangential mesh relaxation. -- Added support for reading periodic meshes written in Gmsh's version 2.2 file - format. Also, including two Gmsh input files and corresponding ".msh" output - files for validating this new functionality. +- Added support for reading periodic meshes in Gmsh format (version 2.2). See + for example the periodic-annulus-sector and periodic-torus-sector files in + the data directory. Performance improvements ------------------------ From 43d20869d2ae18ad345e331d504d781326fa690d Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 12:08:58 -0700 Subject: [PATCH 451/535] Modifying new mesh names in sample runs --- examples/ex1.cpp | 4 ++-- examples/ex11p.cpp | 4 ++-- examples/ex1p.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/ex1.cpp b/examples/ex1.cpp index f23fbb9e0a..50bbd175c5 100644 --- a/examples/ex1.cpp +++ b/examples/ex1.cpp @@ -9,8 +9,8 @@ // ex1 -m ../data/fichera.mesh // ex1 -m ../data/fichera-mixed.mesh // ex1 -m ../data/toroid-wedge.mesh -// ex1 -m ../data/annulus-pi-3.msh -// ex1 -m ../data/torus-pi-3.msh +// ex1 -m ../data/periodic-annulus-sector.msh +// ex1 -m ../data/periodic-torus-sector.msh // ex1 -m ../data/square-disc-p2.vtk -o 2 // ex1 -m ../data/square-disc-p3.mesh -o 3 // ex1 -m ../data/square-disc-nurbs.mesh -o -1 diff --git a/examples/ex11p.cpp b/examples/ex11p.cpp index 5b89a46524..de1e7ce689 100644 --- a/examples/ex11p.cpp +++ b/examples/ex11p.cpp @@ -8,8 +8,8 @@ // mpirun -np 4 ex11p -m ../data/escher.mesh // mpirun -np 4 ex11p -m ../data/fichera.mesh // mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh -// mpirun -np 4 ex11p -m ../data/annulus-pi-3.msh -// mpirun -np 4 ex11p -m ../data/torus-pi-3.msh -rs 1 +// mpirun -np 4 ex11p -m ../data/periodic-annulus-sector.msh +// mpirun -np 4 ex11p -m ../data/periodic-torus-sector.msh -rs 1 // mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2 // mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2 // mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3 diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp index 7b7b33606b..649ecbf117 100644 --- a/examples/ex1p.cpp +++ b/examples/ex1p.cpp @@ -9,8 +9,8 @@ // mpirun -np 4 ex1p -m ../data/fichera.mesh // mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh // mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh -// mpirun -np 4 ex1p -m ../data/annulus-pi-3.msh -// mpirun -np 4 ex1p -m ../data/torus-pi-3.msh +// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh +// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh // mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2 // mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3 // mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1 From 51a7703b485fc34795104c870b2fe3c233d318fa Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sun, 7 Jun 2020 13:02:31 -0700 Subject: [PATCH 452/535] minor editing --- miniapps/meshing/trimmer.cpp | 43 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp index 083563c777..65475f8364 100644 --- a/miniapps/meshing/trimmer.cpp +++ b/miniapps/meshing/trimmer.cpp @@ -9,18 +9,18 @@ // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. // -// ----------------------------------------------------------------------- -// Trimmer Miniap: Trim away elements according to their attribute numbers -// ----------------------------------------------------------------------- +// ------------------------------------------------------------------------ +// Trimmer Miniapp: Trim away elements according to their attribute numbers +// ------------------------------------------------------------------------ // -// This miniapp creates a new mesh consisting of all the elements not -// possessing a given set of attribute numbers. The new boundary elements -// are created with boundary attribute numbers related to the trimmed elements' -// attribute numbers. +// This miniapp creates a new mesh consisting of all the elements not possessing +// a given set of attribute numbers. The new boundary elements are created with +// boundary attribute numbers related to the trimmed elements' attribute +// numbers. // -// By default the new boundary elements will have new attribute -// numbers so as not to interfere with existing boundaries. For -// example, consider a mesh with attriutes given by: +// By default the new boundary elements will have new attribute numbers so as +// not to interfere with existing boundaries. For example, consider a mesh with +// attributes given by: // // attributes = {a1, a2, a3, a4, a5, a6, ..., amax} // bdr_attributes = {b1, b2, ..., bmax} @@ -31,19 +31,18 @@ // attributes: {a1, a3, a5, a6, ..., amax} // bdr_attributes = {b1, b2, ..., bmax, bmax + a2, bmax + a4} // -// The user has the option of providing new attribute numbers for each group -// of elements to be trimmed. In this case the new boundary elements may have -// the same attribute numbers as existing boundary elements. +// The user has the option of providing new attribute numbers for each group of +// elements to be trimmed. In this case the new boundary elements may have the +// same attribute numbers as existing boundary elements. // // The resulting mesh is displayed with GLVis (unless explicitly disabled) and // is also written to the file "trimmer.mesh" // // Compile with: make trimmer // -// Sample runs: -// trimmer -a '2' -b '2' -// trimmer -m ../../data/beam-hex.mesh -a '2' -// trimmer -m ../../data/beam-hex.mesh -a '2' -b '2' +// Sample runs: trimmer -a '2' -b '2' +// trimmer -m ../../data/beam-hex.mesh -a '2' +// trimmer -m ../../data/beam-hex.mesh -a '2' -b '2' #include "mfem.hpp" #include @@ -63,10 +62,10 @@ int main(int argc, char *argv[]) OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); - args.AddOption(&attr, "-a", "-attr", "Set of attributes to remove from " - "the mesh."); - args.AddOption(&bdr_attr, "-b", "-bdr-attr", "Set of boundary attributes " - "to assign to the new boundary elements."); + args.AddOption(&attr, "-a", "--attr", + "Set of attributes to remove from the mesh."); + args.AddOption(&bdr_attr, "-b", "--bdr-attr", + "Set of attributes to assign to the new boundary elements."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -76,6 +75,7 @@ int main(int argc, char *argv[]) args.PrintUsage(cout); return 1; } + args.PrintOptions(cout); Mesh mesh(mesh_file, 0, 0); @@ -218,5 +218,4 @@ int main(int argc, char *argv[]) sol_sock.precision(8); sol_sock << "mesh\n" << trimmed_mesh << flush; } - } From fb3b943cf07d40ca3c24fd353f767e7a8ee8a1e6 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 13:53:24 -0700 Subject: [PATCH 453/535] Adding/improving comments --- fem/coefficient.hpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 99dfb28fbd..2b24518fd5 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -759,10 +759,16 @@ private: Coefficient * b; public: + /** Initialize a coefficient which returns A / B where @a A is a + constant and @a B is a scalar coefficient */ RatioCoefficient(double A, Coefficient &B) : aConst(A), bConst(1.0), a(NULL), b(&B) { } + /** Initialize a coefficient which returns A / B where @a A and @a B are both + scalar coefficients */ RatioCoefficient(Coefficient &A, Coefficient &B) : aConst(0.0), bConst(1.0), a(&A), b(&B) { } + /** Initialize a coefficient which returns A / B where @a A is a + scalar coefficient and @a B is a constant */ RatioCoefficient(Coefficient &A, double B) : aConst(0.0), bConst(B), a(&A), b(NULL) { } @@ -782,8 +788,9 @@ public: virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip) { - return ((a == NULL ) ? aConst : a->Eval(T, ip) ) / - ((b == NULL ) ? bConst : b->Eval(T, ip) ); + double den = (b == NULL ) ? bConst : b->Eval(T, ip); + MFEM_ASSERT(den != 0.0, "Division by zero in RatioCoefficient"); + return ((a == NULL ) ? aConst : a->Eval(T, ip) ) / den; } }; @@ -796,7 +803,7 @@ private: double p; public: - // Result is A^p + /// Result is A^p PowerCoefficient(Coefficient &A, double _p) : a(&A), p(_p) { } @@ -972,6 +979,12 @@ private: double tol; public: + /** @brief Return a vector normalized to a length of one + + This class evaluates the vector coefficient @a A and, if |A| > @a tol, + returns the normalized vector A / |A|. If |A| <= @a tol, the zero + vector is returned. + */ NormalizedVectorCoefficient(VectorCoefficient &A, double tol = 1e-6); void SetACoef(VectorCoefficient &A) { a = &A; } @@ -1158,7 +1171,13 @@ public: const IntegrationPoint &ip); }; -/// Matrix coefficient defined as -a k x k x, for a vector k and scalar a +/** @brief Matrix coefficient defined as -a k x k x, for a vector k and scalar a + + This coefficient returns a * (|k|^2 I - k \otimes k), where I is + the identity matrix and \otimes indicates the outer product. This + can be evaluated for vectors of any dimension but in three + dimensions it corresponds to computing the cross product with k twice. +*/ class CrossCrossCoefficient : public MatrixCoefficient { private: From bf54fc6b3fd027863906c51f0703fe1ef051ff3a Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 13:59:16 -0700 Subject: [PATCH 454/535] Expanding name of MatVecCoefficient to conform to standard set by other product coefficients --- fem/coefficient.cpp | 11 ++++++----- fem/coefficient.hpp | 6 ++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index cc529f1511..d0e3cf2a6a 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -522,17 +522,18 @@ void VectorCrossProductCoefficient::Eval(Vector &V, ElementTransformation &T, V[2] = va[0] * vb[1] - va[1] * vb[0]; } -MatVecCoefficient::MatVecCoefficient(MatrixCoefficient &A, - VectorCoefficient &B) +MatrixVectorProductCoefficient::MatrixVectorProductCoefficient( + MatrixCoefficient &A, VectorCoefficient &B) : VectorCoefficient(A.GetHeight()), a(&A), b(&B), ma(A.GetHeight(), A.GetWidth()), vb(B.GetVDim()) { MFEM_ASSERT(A.GetWidth() == B.GetVDim(), - "MatVecCoefficient: Arguments have incompatible dimensions."); + "MatrixVectorProductCoefficient: " + "Arguments have incompatible dimensions."); } -void MatVecCoefficient::Eval(Vector &V, ElementTransformation &T, - const IntegrationPoint &ip) +void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T, + const IntegrationPoint &ip) { a->Eval(ma, T, ip); b->Eval(vb, T, ip); diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 2b24518fd5..b27f5420b9 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -1020,7 +1020,7 @@ public: }; /// Vector coefficient defined as a matrix vector product -class MatVecCoefficient : public VectorCoefficient +class MatrixVectorProductCoefficient : public VectorCoefficient { private: MatrixCoefficient * a; @@ -1030,7 +1030,7 @@ private: mutable Vector vb; public: - MatVecCoefficient(MatrixCoefficient &A, VectorCoefficient &B); + MatrixVectorProductCoefficient(MatrixCoefficient &A, VectorCoefficient &B); void SetACoef(MatrixCoefficient &A) { a = &A; } MatrixCoefficient * GetACoef() const { return a; } @@ -1043,6 +1043,8 @@ public: using VectorCoefficient::Eval; }; +typedef MatrixVectorProductCoefficient MatVecCoefficient; + /// Matrix coefficient defined as the identity of dimension d class IdentityMatrixCoefficient : public MatrixCoefficient { From 345f87f42e8ff82a4bb8ef9e79efb132e154415b Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 14:55:58 -0700 Subject: [PATCH 455/535] Adding mesh-trimmer to CHANGELOG --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 8d5d626105..faf6093d63 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -121,6 +121,10 @@ New and updated examples and miniapps - Added a new test problem in example 24/24p, demonstrating a mixed bilinear form for H(div) and L_2, with partial assembly support. +- Added a simple mesh editing miniapp, mesh-trimmer, which trims away portions + of a mesh based on element attributes. Any newly exposed boundary elements + are assigned attribute numbers related to the trimmed element attributes. + Improved testing ---------------- - Added a GitLab pipeline that automates PR testing on supercomputing systems From cfcf05b6f95698922f3786bf96cf13877a84ed00 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sun, 7 Jun 2020 14:58:39 -0700 Subject: [PATCH 456/535] Adding mesh-trimmer to CodeDocumentation.dox --- doc/CodeDocumentation.dox | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/CodeDocumentation.dox b/doc/CodeDocumentation.dox index 6007ea7080..cdd42bd9e8 100644 --- a/doc/CodeDocumentation.dox +++ b/doc/CodeDocumentation.dox @@ -149,6 +149,7 @@ namespace mfem { * - Extruder: extrude a low-dimensional mesh into a higher dimension * - Mesh Explorer: visualize and manipulate meshes * - Mesh Optimizer: optimize high-order meshes, serial and parallel versions + * - Mesh Trimmer: trim elements from existing meshes * - Display Basis: visualize finite element basis functions * - Get Values: extract field values via DataCollection classes * - Load DC: visualize fields saved via DataCollection classes From ca5a4dff6f5b9e2b72ab72fac7c75772128916e2 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sun, 7 Jun 2020 15:56:56 -0700 Subject: [PATCH 457/535] Various documentation adjustments --- doc/CodeDocumentation.conf.in | 4 +- doc/web/{small-logo.png => logo-small.png} | Bin fem/bilinearform.hpp | 14 +- fem/bilininteg.hpp | 6 +- fem/coefficient.hpp | 141 +++++++++++---------- fem/estimators.hpp | 2 +- fem/fe.hpp | 82 ++++++------ fem/fe_coll.hpp | 103 ++++++++------- fem/gridfunc.hpp | 4 +- fem/linearform.hpp | 2 +- fem/nonlininteg.hpp | 7 +- fem/tbilinearform.hpp | 8 +- fem/tbilininteg.hpp | 5 +- fem/teltrans.hpp | 4 +- general/communication.hpp | 35 ++--- general/mem_manager.hpp | 9 +- general/optparser.hpp | 27 ++-- general/sets.hpp | 10 +- general/socketstream.hpp | 20 ++- general/stable3d.hpp | 37 +++--- general/text.hpp | 3 +- general/tic_toc.hpp | 9 +- general/version.hpp | 12 +- linalg/vector.hpp | 48 +++---- 24 files changed, 308 insertions(+), 284 deletions(-) rename doc/web/{small-logo.png => logo-small.png} (100%) diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in index 4476775f2e..20bd4d2b10 100644 --- a/doc/CodeDocumentation.conf.in +++ b/doc/CodeDocumentation.conf.in @@ -51,7 +51,7 @@ PROJECT_BRIEF = "Finite element discretization library" # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = web/small-logo.png +PROJECT_LOGO = web/logo-small.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -698,7 +698,7 @@ CITE_BIB_FILES = # messages are off. # The default value is: NO. -QUIET = YES +QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES diff --git a/doc/web/small-logo.png b/doc/web/logo-small.png similarity index 100% rename from doc/web/small-logo.png rename to doc/web/logo-small.png diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index 02effa0ab8..179ff64f59 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -25,8 +25,8 @@ namespace mfem { -/** @brief Enumeration defining the assembly level for bilinear and nonlinear form - classes derived from Operator. */ +/** @brief Enumeration defining the assembly level for bilinear and nonlinear + form classes derived from Operator. */ enum class AssemblyLevel { /// Fully assembled form, i.e. a global sparse matrix in MFEM, Hypre or PETSC @@ -44,8 +44,10 @@ enum class AssemblyLevel }; -/** @brief Used to form a matrix given the associated FE space and BLFIntegrators - The sum of all the BLFIntegrators will be used form the matrix M. */ +/** @brief A "square matrix" operator for the associated FE space and + BLFIntegrators The sum of all the BLFIntegrators can be used form the matrix + M. This class also supports other assembly levels specified via the + SetAssemblyLevel() function. */ class BilinearForm : public Matrix { protected: @@ -68,8 +70,8 @@ protected: Partial Assembly (PA), or Matrix Free assembly (MF). */ BilinearFormExtension *ext; - /** @brief Indicates the Mesh::sequence corresponding to the current state of the - BilinearForm. */ + /** @brief Indicates the Mesh::sequence corresponding to the current state of + the BilinearForm. */ long sequence; /** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi, diff --git a/fem/bilininteg.hpp b/fem/bilininteg.hpp index 862967ae64..a7469fe438 100644 --- a/fem/bilininteg.hpp +++ b/fem/bilininteg.hpp @@ -199,10 +199,8 @@ public: virtual ~BilinearFormIntegrator() { } }; -/** Wraps a given @a BilinearFormIntegrator and transposes the resulting - element matrices. - - See for example ex9, ex9p. */ +/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element + matrices. See for example ex9, ex9p. */ class TransposeIntegrator : public BilinearFormIntegrator { private: diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 97c46f1ed6..ccae771d37 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -27,10 +27,10 @@ class ParMesh; #endif -/** @brief Base class Coefficients that optionally depend on space and - time. These are used by the BilinearFormIntegrator, - LinearFormIntegrator, and NonlinearFormIntegrator classes to represent - the physical coeffiencients in the PDEs that are being discretized. */ +/** @brief Base class Coefficients that optionally depend on space and time. + These are used by the BilinearFormIntegrator, LinearFormIntegrator, and + NonlinearFormIntegrator classes to represent the physical coefficients in + the PDEs that are being discretized. */ class Coefficient { protected: @@ -289,7 +289,8 @@ public: integral of the projection is exactly equal to the Scale(). */ void SetWeight(Coefficient *w) { weight = w; } - /// Return a pointer to a c-array representing the center of the delta function. + /// Return a pointer to a c-array representing the center of the delta + /// function. const double *Center() { return center; } /** @brief Return the scale factor times the optional time dependent @@ -343,7 +344,7 @@ protected: double time; public: - /// Initilize the VectorCoefficient with vector dimension @a vd. + /// Initialize the VectorCoefficient with vector dimension @a vd. VectorCoefficient(int vd) { vdim = vd; time = 0.; } /// Set the time for time dependent coefficients @@ -438,9 +439,9 @@ public: }; /** @brief Vector coefficient defined by an array of scalar coefficients. - Coefficients that are not set will evaluate to zero in the vector. - This object takes ownership of the array of coefficients inside it and - deletes them at object destruction. */ + Coefficients that are not set will evaluate to zero in the vector. This + object takes ownership of the array of coefficients inside it and deletes + them at object destruction. */ class VectorArrayCoefficient : public VectorCoefficient { private: @@ -461,12 +462,13 @@ public: /// Sets coefficient in the vector. void Set(int i, Coefficient *c, bool own=true); - /// Evaluates i'th component of the vector of coefficients and returns the value. + /// Evaluates i'th component of the vector of coefficients and returns the + /// value. double Eval(int i, ElementTransformation &T, const IntegrationPoint &ip) { return Coeff[i] ? Coeff[i]->Eval(T, ip, GetTime()) : 0.0; } using VectorCoefficient::Eval; - /** @brief Evaluate the coefficient. Each element of vector V comes from the + /** @brief Evaluate the coefficient. Each element of vector V comes from the associated array of scalar coefficients. */ virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); @@ -490,7 +492,7 @@ public: grid function is not owned by the coefficient. */ VectorGridFunctionCoefficient(const GridFunction *gf); - /** @brief Set the grid function for this coefficient. Also sets the Vector + /** @brief Set the grid function for this coefficient. Also sets the Vector dimension to match that of the @a gf. */ void SetGridFunction(const GridFunction *gf); @@ -502,8 +504,8 @@ public: const IntegrationPoint &ip); /** @brief Evaluate the vector coefficients at all of the locations in the - integration rule and write the vectors into the - columns of matrix @a M. */ + integration rule and write the vectors into the columns of matrix @a + M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -518,8 +520,8 @@ protected: public: - /** @brief Construct the coefficient with a scalar grid function - @a gf. The grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with a scalar grid function @a gf. The + grid function is not owned by the coefficient. */ GradientGridFunctionCoefficient(const GridFunction *gf); ///Set the scalar grid function. @@ -532,9 +534,9 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - /** @brief Evaluate the gradient vector coefficient at all of the - locations in the integration rule and write the vectors into - columns of matrix @a M. */ + /** @brief Evaluate the gradient vector coefficient at all of the locations + in the integration rule and write the vectors into columns of matrix @a + M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); @@ -548,8 +550,8 @@ protected: const GridFunction *GridFunc; public: - /** @brief Construct the coefficient with a vector grid function - @a gf. The grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with a vector grid function @a gf. The + grid function is not owned by the coefficient. */ CurlGridFunctionCoefficient(const GridFunction *gf); /// Set the vector grid function. @@ -573,8 +575,8 @@ protected: const GridFunction *GridFunc; public: - /** @brief Construct the coefficient with a vector grid function - @a gf. The grid function is not owned by the coefficient. */ + /** @brief Construct the coefficient with a vector grid function @a gf. The + grid function is not owned by the coefficient. */ DivergenceGridFunctionCoefficient(const GridFunction *gf); /// Set the vector grid function. @@ -593,8 +595,8 @@ public: /** @brief Vector coefficient defined by a scalar DeltaCoefficient and a constant vector direction. - WARNING this cannot be used as a normal coefficient. The usual Eval - method is disabled. */ + WARNING this cannot be used as a normal coefficient. The usual Eval method + is disabled. */ class VectorDeltaCoefficient : public VectorCoefficient { protected: @@ -606,23 +608,23 @@ public: VectorDeltaCoefficient(int _vdim) : VectorCoefficient(_vdim), dir(_vdim), d() { } - /** @brief Construct with a Vector object representing the direction and - a unit delta function centered at (0.0,0.0,0.0) */ + /** @brief Construct with a Vector object representing the direction and a + unit delta function centered at (0.0,0.0,0.0) */ VectorDeltaCoefficient(const Vector& _dir) : VectorCoefficient(_dir.Size()), dir(_dir), d() { } - /** @brief Construct with a Vector object representing the direction and - a delta function scaled by @a s and centered at (x,0.0,0.0) */ + /** @brief Construct with a Vector object representing the direction and a + delta function scaled by @a s and centered at (x,0.0,0.0) */ VectorDeltaCoefficient(const Vector& _dir, double x, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,s) { } - /** @brief Construct with a Vector object representing the direction and - a delta function scaled by @a s and centered at (x,y,0.0) */ + /** @brief Construct with a Vector object representing the direction and a + delta function scaled by @a s and centered at (x,y,0.0) */ VectorDeltaCoefficient(const Vector& _dir, double x, double y, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,s) { } - /** @brief Construct with a Vector object representing the direction and - a delta function scaled by @a s and centered at (x,y,z) */ + /** @brief Construct with a Vector object representing the direction and a + delta function scaled by @a s and centered at (x,y,z) */ VectorDeltaCoefficient(const Vector& _dir, double x, double y, double z, double s) : VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,z,s) { } @@ -665,8 +667,9 @@ private: Array active_attr; public: - /** @brief Construct with a parent vector coefficient and an array of zeros and - ones representing the attributes for which this coefficient should be active. */ + /** @brief Construct with a parent vector coefficient and an array of zeros + and ones representing the attributes for which this coefficient should be + active. */ VectorRestrictedCoefficient(VectorCoefficient &vc, Array &attr) : VectorCoefficient(vc.GetVDim()) { c = &vc; attr.Copy(active_attr); } @@ -675,9 +678,9 @@ public: virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); - /** @brief Evaluate the vector coefficient at all of the - locations in the integration rule and write the vectors into - the columns of matrix @a M. */ + /** @brief Evaluate the vector coefficient at all of the locations in the + integration rule and write the vectors into the columns of matrix @a + M. */ virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir); }; @@ -740,10 +743,9 @@ public: }; -/** @brief A matrix coefficient with an optional scalar coefficient - multiplier \a q. The matrix function can either be represented by a - C-function or a constant matrix provided when constructiong this - object. */ +/** @brief A matrix coefficient with an optional scalar coefficient multiplier + \a q. The matrix function can either be represented by a C-function or a + constant matrix provided when constructing this object. */ class MatrixFunctionCoefficient : public MatrixCoefficient { private: @@ -753,7 +755,8 @@ private: DenseMatrix mat; public: - /// Construct a square matrix coefficient from a C-function without time dependence. + /// Construct a square matrix coefficient from a C-function without time + /// dependence. MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, DenseMatrix &), Coefficient *q = NULL) : MatrixCoefficient(dim), Q(q) @@ -772,7 +775,8 @@ public: mat = m; } - /// Construct a square matrix coefficient from a C-function with time-dependence. + /// Construct a square matrix coefficient from a C-function with + /// time-dependence. MatrixFunctionCoefficient(int dim, void (*TDF)(const Vector &, double, DenseMatrix &), Coefficient *q = NULL) @@ -793,9 +797,8 @@ public: /** @brief Matrix coefficient defined by a matrix of scalar coefficients. - Coefficients that are not set will evaluate to zero in the vector. The - coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. - */ + Coefficients that are not set will evaluate to zero in the vector. The + coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. */ class MatrixArrayCoefficient : public MatrixCoefficient { private: @@ -803,19 +806,20 @@ private: Array ownCoeff; public: - /** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. - The actual coefficients still need to be added with Set(). */ + /** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. The + actual coefficients still need to be added with Set(). */ explicit MatrixArrayCoefficient (int dim); /// Get the coefficient located at (i,j) in the matrix. Coefficient* GetCoeff (int i, int j) { return Coeff[i*width+j]; } - /** @brief Set the coefficient located at (i,j) in the matrix. By default - by default this will take ownership of the Coefficient passed in, but this - can be overrided with the @a own parameter. */ + /** @brief Set the coefficient located at (i,j) in the matrix. By default by + default this will take ownership of the Coefficient passed in, but this + can be overridden with the @a own parameter. */ void Set(int i, int j, Coefficient * c, bool own=true); - /// Evaluate coefficient located at (i,j) in the matrix using integration point @a ip. + /// Evaluate coefficient located at (i,j) in the matrix using integration + /// point @a ip. double Eval(int i, int j, ElementTransformation &T, const IntegrationPoint &ip) { return Coeff[i*width+j] ? Coeff[i*width+j] -> Eval(T, ip, GetTime()) : 0.0; } @@ -827,8 +831,8 @@ public: }; -/** @brief Derived matrix coefficient that has the value of the parent - matrix coefficient where it is active and is zero otherwise. */ +/** @brief Derived matrix coefficient that has the value of the parent matrix + coefficient where it is active and is zero otherwise. */ class MatrixRestrictedCoefficient : public MatrixCoefficient { private: @@ -836,8 +840,9 @@ private: Array active_attr; public: - /** @brief Construct with a parent matrix coefficient and an array of zeros and - ones representing the attributes for which this coefficient should be active. */ + /** @brief Construct with a parent matrix coefficient and an array of zeros + and ones representing the attributes for which this coefficient should be + active. */ MatrixRestrictedCoefficient(MatrixCoefficient &mc, Array &attr) : MatrixCoefficient(mc.GetHeight(), mc.GetWidth()) { c = &mc; attr.Copy(active_attr); } @@ -860,7 +865,7 @@ private: double beta; public: - /// Construct with the two coefficeints. Result is _alpha * A + _beta * B. + /// Construct with the two coefficients. Result is _alpha * A + _beta * B. SumCoefficient(Coefficient &A, Coefficient &B, double _alpha = 1.0, double _beta = 1.0) : a(&A), b(&B), alpha(_alpha), beta(_beta) { } @@ -1023,7 +1028,7 @@ public: using VectorCoefficient::Eval; }; -/** @brief Vector coefficient defined as a product of a matrix coeffiecient and +/** @brief Vector coefficient defined as a product of a matrix coefficient and a vector coefficient. */ class MatVecCoefficient : public VectorCoefficient { @@ -1082,8 +1087,8 @@ public: const IntegrationPoint &ip); }; -/** @brief Matrix coefficient defined as a product of a scalar - coefficient and a matrix coefficient.*/ +/** @brief Matrix coefficient defined as a product of a scalar coefficient and a + matrix coefficient.*/ class ScalarMatrixProductCoefficient : public MatrixCoefficient { private: @@ -1152,8 +1157,8 @@ public: class QuadratureFunction; /** @brief Vector quadrature function coefficient which requires that the - quadrature rules used for this vector coefficient be the same as those that - live within the supplied QuadratureFunction. */ + quadrature rules used for this vector coefficient be the same as those that + live within the supplied QuadratureFunction. */ class VectorQuadratureFunctionCoefficient : public VectorCoefficient { private: @@ -1164,9 +1169,9 @@ public: /// Constructor with a quadrature function as input VectorQuadratureFunctionCoefficient(QuadratureFunction &qf); - /** Set the starting index within the QuadFunc that'll be used to - project outwards as well as the corresponding length. The projected length - should have the bounds of 1 <= length <= (length QuadFunc - index). */ + /** Set the starting index within the QuadFunc that'll be used to project + outwards as well as the corresponding length. The projected length should + have the bounds of 1 <= length <= (length QuadFunc - index). */ void SetComponent(int _index, int _length); const QuadratureFunction& GetQuadFunction() const { return QuadF; } @@ -1179,8 +1184,8 @@ public: }; /** @brief Quadrature function coefficient which requires that the quadrature - rules used for this coefficient be the same as those that live within the - supplied QuadratureFunction. */ + rules used for this coefficient be the same as those that live within the + supplied QuadratureFunction. */ class QuadratureFunctionCoefficient : public Coefficient { private: diff --git a/fem/estimators.hpp b/fem/estimators.hpp index 7baddd1cda..16f66024de 100644 --- a/fem/estimators.hpp +++ b/fem/estimators.hpp @@ -226,7 +226,7 @@ protected: class when needed.*/ bool own_flux_fes; ///< Ownership flag for flux_space and smooth_flux_space. - /// Initilize with the integrator, solution, and flux finite element spaces. + /// Initialize with the integrator, solution, and flux finite element spaces. void Init(BilinearFormIntegrator &integ, ParGridFunction &sol, ParFiniteElementSpace *flux_fes, diff --git a/fem/fe.hpp b/fem/fe.hpp index e0418a8865..e5bd910d8e 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -510,10 +510,10 @@ public: virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; - /** @brief Given a matrix coefficient and a transformation, compute an approximation - ("projection") in the local finite dimensional space in terms of the - degrees of freedom. For VectorFiniteElements, the rows of the coefficient - are projected in the vector space. */ + /** @brief Given a matrix coefficient and a transformation, compute an + approximation ("projection") in the local finite dimensional space in + terms of the degrees of freedom. For VectorFiniteElements, the rows of + the coefficient are projected in the vector space. */ virtual void ProjectMatrixCoefficient( MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const; @@ -521,15 +521,15 @@ public: the local finite dimensional space represented by the @a dofs. */ virtual void ProjectDelta(int vertex, Vector &dofs) const; - /** @brief Compute the embedding/projection matrix from the given FiniteElement - onto 'this' FiniteElement. The ElementTransformation is included to - support cases when the projection depends on it. */ + /** @brief Compute the embedding/projection matrix from the given + FiniteElement onto 'this' FiniteElement. The ElementTransformation is + included to support cases when the projection depends on it. */ virtual void Project(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const; - /** @brief Compute the discrete gradient matrix from the given FiniteElement onto - 'this' FiniteElement. The ElementTransformation is included to support - cases when the matrix depends on it. */ + /** @brief Compute the discrete gradient matrix from the given FiniteElement + onto 'this' FiniteElement. The ElementTransformation is included to + support cases when the matrix depends on it. */ virtual void ProjectGrad(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const; @@ -541,15 +541,15 @@ public: ElementTransformation &Trans, DenseMatrix &curl) const; - /** @brief Compute the discrete divergence matrix from the given FiniteElement onto - 'this' FiniteElement. The ElementTransformation is included to support - cases when the matrix depends on it. */ + /** @brief Compute the discrete divergence matrix from the given + FiniteElement onto 'this' FiniteElement. The ElementTransformation is + included to support cases when the matrix depends on it. */ virtual void ProjectDiv(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const; - /** @brief Return a DofToQuad structure corresponding to the given IntegrationRule - using the given DofToQuad::Mode. */ + /** @brief Return a DofToQuad structure corresponding to the given + IntegrationRule using the given DofToQuad::Mode. */ /** See the documentation for DofToQuad for more details. */ virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const; @@ -638,8 +638,9 @@ public: { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; } #endif - /** @brief Set the FiniteElement::MapType of the element to either VALUE or INTEGRAL. - Also sets the FiniteElement::DerivType to GRAD if the FiniteElement::MapType is VALUE. */ + /** @brief Set the FiniteElement::MapType of the element to either VALUE or + INTEGRAL. Also sets the FiniteElement::DerivType to GRAD if the + FiniteElement::MapType is VALUE. */ void SetMapType(int M) { MFEM_VERIFY(M == VALUE || M == INTEGRAL, "unknown MapType"); @@ -1086,7 +1087,8 @@ public: }; -/// A 2D positive bi-quadratic element on a square utilizing the 2nd order Bernstein basis +/// A 2D positive bi-quadratic element on a square utilizing the 2nd order +/// Bernstein basis class BiQuadPos2DFiniteElement : public PositiveFiniteElement { public: @@ -1163,7 +1165,8 @@ public: DenseMatrix &h) const; }; -/// A 3D cubic element on a tetrahedron with 20 nodes at the thirds of the tetrahedron +/// A 3D cubic element on a tetrahedron with 20 nodes at the thirds of the +/// tetrahedron class Cubic3DFiniteElement : public NodalFiniteElement { public: @@ -1819,7 +1822,8 @@ public: }; -/// Class for computing 1D special polynomials and their associated basis functions +/// Class for computing 1D special polynomials and their associated basis +/// functions class Poly_1D { public: @@ -1972,7 +1976,8 @@ public: extern Poly_1D poly1d; -/// An element defined as an ND tensor product of 1D elements on a segement, square, or cube +/// An element defined as an ND tensor product of 1D elements on a segment, +/// square, or cube class TensorBasisElement { protected: @@ -2146,11 +2151,11 @@ class H1Pos_SegmentElement : public PositiveTensorFiniteElement { private: #ifndef MFEM_THREAD_SAFE - // This is to share scratch space between invocations, which helps - // speed things up, but with OpenMP, we need one copy per thread. - // Right now, we solve this by allocating this space within each function - // call every time we call it. Alternatively, we should do some sort - // thread private thing. Brunner, Jan 2014 + // This is to share scratch space between invocations, which helps speed + // things up, but with OpenMP, we need one copy per thread. Right now, we + // solve this by allocating this space within each function call every time + // we call it. Alternatively, we should do some sort thread private thing. + // Brunner, Jan 2014 mutable Vector shape_x, dshape_x; #endif @@ -2290,7 +2295,8 @@ public: }; -/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a tetrahedron +/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a +/// tetrahedron class H1Pos_TetrahedronElement : public PositiveFiniteElement { protected: @@ -2562,7 +2568,8 @@ public: }; -/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a tetrahedron +/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a +/// tetrahedron class L2Pos_TetrahedronElement : public PositiveFiniteElement { private: @@ -2645,8 +2652,8 @@ private: Array dof2nk; public: - /** @brief Construct the RT_QuadrilateralElement of order @a p and closed and open - BasisType @a cb_type and @a ob_type */ + /** @brief Construct the RT_QuadrilateralElement of order @a p and closed and + open BasisType @a cb_type and @a ob_type */ RT_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2702,8 +2709,8 @@ class RT_HexahedronElement : public VectorTensorFiniteElement Array dof2nk; public: - /** @brief Construct the RT_HexahedronElement of order @a p and closed and open - BasisType @a cb_type and @a ob_type */ + /** @brief Construct the RT_HexahedronElement of order @a p and closed and + open BasisType @a cb_type and @a ob_type */ RT_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2861,8 +2868,8 @@ class ND_HexahedronElement : public VectorTensorFiniteElement Array dof2tk; public: - /** @brief Construct the ND_HexahedronElement of order @a p and closed and open - BasisType @a cb_type and @a ob_type */ + /** @brief Construct the ND_HexahedronElement of order @a p and closed and + open BasisType @a cb_type and @a ob_type */ ND_HexahedronElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -2929,8 +2936,8 @@ class ND_QuadrilateralElement : public VectorTensorFiniteElement Array dof2tk; public: - /** @brief Construct the ND_QuadrilateralElement of order @a p and closed and open - BasisType @a cb_type and @a ob_type */ + /** @brief Construct the ND_QuadrilateralElement of order @a p and closed and + open BasisType @a cb_type and @a ob_type */ ND_QuadrilateralElement(const int p, const int cb_type = BasisType::GaussLobatto, const int ob_type = BasisType::GaussLegendre); @@ -3236,7 +3243,8 @@ public: d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3) { orders[0] = orders[1] = orders[2] = p; } - /// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py and z-order @a pz + /// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py + /// and z-order @a pz NURBS3DFiniteElement(int px, int py, int pz) : NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1), std::max(std::max(px,py),pz), FunctionSpace::Qk), diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index e0c6cdf737..13de7cd562 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -19,10 +19,10 @@ namespace mfem { -/** @brief Collection of finite elements from the same family in multiple dimensions. - This class is used to match the degrees of freedom of a FiniteElementSpace - between elements, and to provide the finite element restriction from an - element to its boundary. */ +/** @brief Collection of finite elements from the same family in multiple + dimensions. This class is used to match the degrees of freedom of a + FiniteElementSpace between elements, and to provide the finite element + restriction from an element to its boundary. */ class FiniteElementCollection { protected: @@ -41,8 +41,7 @@ protected: public: /** @brief Enumeration for ContType: defines the continuity of the field - across element interfaces. - */ + across element interfaces. */ enum { CONTINUOUS, ///< Field is continuous across element interfaces TANGENTIAL, ///< Tangential components of vector field NORMAL, ///< Normal component of vector field @@ -147,11 +146,11 @@ public: /** @brief Get the local dofs for a given sub-manifold. - Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex, - 1D - edge, 2D - face) including those on its boundary. The local index of - the sub-manifold (inside Geom) and its orientation are given by the - parameter Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed - that 0 <= SDim <= Dim(Geom). */ + Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex, 1D + - edge, 2D - face) including those on its boundary. The local index of the + sub-manifold (inside Geom) and its orientation are given by the parameter + Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed that 0 <= + SDim <= Dim(Geom). */ void SubDofOrder(Geometry::Type Geom, int SDim, int Info, Array &dofs) const; }; @@ -189,8 +188,8 @@ public: virtual ~H1_FECollection(); }; -/** @brief Arbitrary order H1-conforming (continuous) finite elements with positive - basis functions. */ +/** @brief Arbitrary order H1-conforming (continuous) finite elements with + positive basis functions. */ class H1Pos_FECollection : public H1_FECollection { public: @@ -208,9 +207,9 @@ public: : H1_FECollection(p, dim, BasisType::Serendipity) { }; }; -/** @brief Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the - interface between mesh elements (faces,edges,vertices); these are the trace - FEs of the H1-conforming FEs. */ +/** @brief Arbitrary order "H^{1/2}-conforming" trace finite elements defined on + the interface between mesh elements (faces,edges,vertices); these are the + trace FEs of the H1-conforming FEs. */ class H1_Trace_FECollection : public H1_FECollection { public: @@ -308,9 +307,9 @@ public: virtual ~RT_FECollection(); }; -/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the - interface between mesh elements (faces); these are the normal trace FEs of - the H(div)-conforming FEs. */ +/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on + the interface between mesh elements (faces); these are the normal trace FEs + of the H(div)-conforming FEs. */ class RT_Trace_FECollection : public RT_FECollection { public: @@ -358,9 +357,9 @@ public: virtual ~ND_FECollection(); }; -/** @brief Arbitrary order H(curl)-trace finite elements defined on the interface - between mesh elements (faces,edges); these are the tangential trace FEs of - the H(curl)-conforming FEs. */ +/** @brief Arbitrary order H(curl)-trace finite elements defined on the + interface between mesh elements (faces,edges); these are the tangential + trace FEs of the H(curl)-conforming FEs. */ class ND_Trace_FECollection : public ND_FECollection { public: @@ -581,8 +580,8 @@ public: }; -/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept only - for backward compatibility, consider using RT_FECollection instead. */ +/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept + only for backward compatibility, consider using RT_FECollection instead. */ class RT0_2DFECollection : public FiniteElementCollection { private: @@ -605,8 +604,8 @@ public: virtual int GetContType() const { return NORMAL; } }; -/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept only - for backward compatibility, consider using RT_FECollection instead. */ +/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept + only for backward compatibility, consider using RT_FECollection instead. */ class RT1_2DFECollection : public FiniteElementCollection { private: @@ -629,8 +628,8 @@ public: virtual int GetContType() const { return NORMAL; } }; -/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept only - for backward compatibility, consider using RT_FECollection instead. */ +/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept + only for backward compatibility, consider using RT_FECollection instead. */ class RT2_2DFECollection : public FiniteElementCollection { private: @@ -653,8 +652,9 @@ public: virtual int GetContType() const { return NORMAL; } }; -/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is + kept only for backward compatibility, consider using L2_FECollection + instead. */ class Const2DFECollection : public FiniteElementCollection { private: @@ -676,8 +676,9 @@ public: virtual int GetContType() const { return DISCONTINUOUS; } }; -/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is + kept only for backward compatibility, consider using L2_FECollection + instead. */ class LinearDiscont2DFECollection : public FiniteElementCollection { private: @@ -740,8 +741,9 @@ public: virtual int GetContType() const { return DISCONTINUOUS; } }; -/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class + is kept only for backward compatibility, consider using L2_FECollection + instead. */ class QuadraticDiscont2DFECollection : public FiniteElementCollection { private: @@ -804,8 +806,9 @@ public: virtual int GetContType() const { return DISCONTINUOUS; } }; -/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is + kept only for backward compatibility, consider using L2_FECollection + instead. */ class CubicDiscont2DFECollection : public FiniteElementCollection { private: @@ -827,8 +830,9 @@ public: virtual int GetContType() const { return DISCONTINUOUS; } }; -/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is + kept only for backward compatibility, consider using L2_FECollection + instead. */ class Const3DFECollection : public FiniteElementCollection { private: @@ -851,8 +855,9 @@ public: virtual int GetContType() const { return DISCONTINUOUS; } }; -/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is + kept only for backward compatibility, consider using L2_FECollection + instead. */ class LinearDiscont3DFECollection : public FiniteElementCollection { private: @@ -874,8 +879,9 @@ public: virtual int GetContType() const { return DISCONTINUOUS; } }; -/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class is kept - only for backward compatibility, consider using L2_FECollection instead. */ +/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class + is kept only for backward compatibility, consider using L2_FECollection + instead. */ class QuadraticDiscont3DFECollection : public FiniteElementCollection { private: @@ -923,8 +929,9 @@ public: virtual int GetContType() const { return CONTINUOUS; } }; -/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only for - backward compatibility, consider using the new ND_FECollection instead. */ +/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only + for backward compatibility, consider using the new ND_FECollection + instead. */ class ND1_3DFECollection : public FiniteElementCollection { private: @@ -946,8 +953,8 @@ public: virtual int GetContType() const { return TANGENTIAL; } }; -/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept only - for backward compatibility, consider using RT_FECollection instead. */ +/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept + only for backward compatibility, consider using RT_FECollection instead. */ class RT0_3DFECollection : public FiniteElementCollection { private: @@ -970,8 +977,8 @@ public: virtual int GetContType() const { return NORMAL; } }; -/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept only - for backward compatibility, consider using RT_FECollection instead. */ +/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept + only for backward compatibility, consider using RT_FECollection instead. */ class RT1_3DFECollection : public FiniteElementCollection { private: diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 20fc303072..9687514b59 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -598,8 +598,8 @@ public: type = adios2stream::data_type::point_data) const; #endif - /** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be - called first. The parameter ref > 0 must match the one used in + /** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK + must be called first. The parameter ref > 0 must match the one used in Mesh::PrintVTK. */ void SaveVTK(std::ostream &out, const std::string &field_name, int ref); diff --git a/fem/linearform.hpp b/fem/linearform.hpp index d12d173efb..1ab80eb3fd 100644 --- a/fem/linearform.hpp +++ b/fem/linearform.hpp @@ -19,7 +19,7 @@ namespace mfem { -///Vector with associated FE space and LinearFormIntegrator. +/// Vector with associated FE space and LinearFormIntegrators. class LinearForm : public Vector { protected: diff --git a/fem/nonlininteg.hpp b/fem/nonlininteg.hpp index 655affe1e3..5c9975455d 100644 --- a/fem/nonlininteg.hpp +++ b/fem/nonlininteg.hpp @@ -20,10 +20,9 @@ namespace mfem { -/** @brief This class is used to express the - local action of a general nonlinear finite element operator. In addition - it may provide the capability to assemble the local gradient operator - and to compute the local energy. */ +/** @brief This class is used to express the local action of a general nonlinear + finite element operator. In addition it may provide the capability to + assemble the local gradient operator and to compute the local energy. */ class NonlinearFormIntegrator { protected: diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp index 85724e2785..1fa2fd896e 100644 --- a/fem/tbilinearform.hpp +++ b/fem/tbilinearform.hpp @@ -101,8 +101,8 @@ protected: typedef FieldEvaluator solFieldEval; - /** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated on - a kernel, eg. ElementMatrix::Compute may be AssembleGradGrad()).*/ + /** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated + on a kernel, e.g. ElementMatrix::Compute may be AssembleGradGrad()). */ struct S_spec { typedef typename solFieldEval::template Spec Spec; @@ -299,8 +299,8 @@ public: typedef TTensor3 lnodes_t; const int NE = mesh.GetNE(); - // TODO: How do we make sure that this array is aligned properly, AND - // the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready + // TODO: How do we make sure that this array is aligned properly, AND the + // compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready const int NVE = (NE+TE-1)/TE; vreal_t *vsNodes = new vreal_t[lnodes_t::size*NVE]; sNodes.NewDataAndSize(vsNodes[0].vec, (lnodes_t::size*SS)*NVE); diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp index dee0660b58..177bb10e72 100644 --- a/fem/tbilininteg.hpp +++ b/fem/tbilininteg.hpp @@ -60,8 +60,9 @@ struct TMassKernel template struct p_asm_data { typedef TVector type; }; - /** @brief Partially assembled data type for one element with the given number of - quadrature points. This type is used in full element matrix assembly. */ + /** @brief Partially assembled data type for one element with the given + number of quadrature points. This type is used in full element matrix + assembly. */ template struct f_asm_data { typedef TVector type; }; diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp index f0414bf35d..c0f3cb41ec 100644 --- a/fem/teltrans.hpp +++ b/fem/teltrans.hpp @@ -53,8 +53,8 @@ public: LoadElementIdxs = 8 }; - /// Determines at compile-time the operations needed for given coefficient and - /// kernel + /// Determines at compile-time the operations needed for given coefficient + /// and kernel template struct Get { static const int EvalOps = diff --git a/general/communication.hpp b/general/communication.hpp index 570535e23c..8542420822 100644 --- a/general/communication.hpp +++ b/general/communication.hpp @@ -48,9 +48,9 @@ public: }; -/** The shared entities (e.g. vertices, faces and edges) are split into - groups, each group determined by the set of participating processors. - They are numbered locally in lproc. Assumptions: +/** The shared entities (e.g. vertices, faces and edges) are split into groups, + each group determined by the set of participating processors. They are + numbered locally in lproc. Assumptions: - group 0 is the 'local' group - groupmaster_lproc[0] = 0 - lproc_proc[0] = MyRank */ @@ -108,7 +108,7 @@ public: bool IAmMaster(int g) const { return (groupmaster_lproc[g] == 0); } /** @brief Return the neighbor index of the group master for a given group. - * Neighbor 0 is the local processor. */ + Neighbor 0 is the local processor. */ int GetGroupMaster(int g) const { return groupmaster_lproc[g]; } /// Return the rank of the group master for group 'g'. @@ -122,7 +122,7 @@ public: int GetGroupSize(int g) const { return group_lproc.RowSize(g); } /** @brief Return a pointer to a list of neighbors for a given group. - * Neighbor 0 is the local processor */ + Neighbor 0 is the local processor */ const int *GetGroup(int g) const { return group_lproc.GetRow(g); } /// Save the data in a stream. @@ -208,9 +208,8 @@ public: void GetNeighborLDofTable(Table &nbr_ldof) const; /** @brief Data structure on which we define reduce operations. - - The data is associated with (and the operation is performed on) one group - at a time. */ + The data is associated with (and the operation is performed on) one + group at a time. */ template struct OpData { int nldofs, nb; @@ -344,9 +343,10 @@ struct VarMessage std::string data; MPI_Request send_request; - /** @brief Non-blocking send to processor 'rank'. Returns immediately. Completion - (as tested by MPI_Wait/Test) does not mean the message was received -- - it may be on its way or just buffered locally. */ + /** @brief Non-blocking send to processor 'rank'. + Returns immediately. Completion (as tested by MPI_Wait/Test) does not + mean the message was received -- it may be on its way or just buffered + locally. */ void Isend(int rank, MPI_Comm comm) { Encode(rank); @@ -354,8 +354,9 @@ struct VarMessage &send_request); } - /** @brief Non-blocking synchronous send to processor 'rank'. Returns immediately. - Completion (MPI_Wait/Test) means that the message was received. */ + /** @brief Non-blocking synchronous send to processor 'rank'. + Returns immediately. Completion (MPI_Wait/Test) means that the message + was received. */ void Issend(int rank, MPI_Comm comm) { Encode(rank); @@ -413,9 +414,9 @@ struct VarMessage MPI_Get_count(&status, MPI_BYTE, &size); } - /** @brief Non-blocking probe for incoming message of this type from any rank. - If there is an incoming message, returns true and sets 'rank' and 'size'. - Otherwise returns false. */ + /** @brief Non-blocking probe for incoming message of this type from any + rank. If there is an incoming message, returns true and sets 'rank' and + 'size'. Otherwise returns false. */ static bool IProbe(int &rank, int &size, MPI_Comm comm) { int flag; @@ -443,7 +444,7 @@ struct VarMessage Decode(rank); } - /// Like Recv(), but throw away the messsage. + /// Like Recv(), but throw away the message. void RecvDrop(int rank, int size, MPI_Comm comm) { data.resize(size); diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index 4b652d9f08..3022cb6599 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -471,9 +471,9 @@ private: }; -/** The memory manager class. Host side pointers are inserted into this - manager which keeps track of the associated device pointer, and where - the data currently resides. */ +/** The MFEM memory manager class. Host-side pointers are inserted into this + manager which keeps track of the associated device pointer, and where the + data currently resides. */ class MemoryManager { private: @@ -580,7 +580,8 @@ private: // Static methods used by the Memory class private: - /// Insert a host address @a h_ptr and size *a bytes in the memory map to be managed + /// Insert a host address @a h_ptr and size *a bytes in the memory map to be + /// managed. void Insert(void *h_ptr, size_t bytes, MemoryType h_mt, MemoryType d_mt); /// Insert a device and the host addresses in the memory map diff --git a/general/optparser.hpp b/general/optparser.hpp index 4a9ab69627..00c68da136 100644 --- a/general/optparser.hpp +++ b/general/optparser.hpp @@ -76,8 +76,9 @@ public: error_type = error_idx = 0; } - /** @brief Add a boolean option and set 'var' to recieve the value. - Enable/disable tags are used to set the bool to true/false respectively. */ + /** @brief Add a boolean option and set 'var' to receive the value. + Enable/disable tags are used to set the bool to true/false + respectively. */ void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, @@ -89,7 +90,7 @@ public: description, required)); } - /// Add an integer option and set 'var' to recieve the value. + /// Add an integer option and set 'var' to receive the value. void AddOption(int *var, const char *short_name, const char *long_name, const char *description, bool required = false) { @@ -97,7 +98,7 @@ public: required)); } - /// Add a double option and set 'var' to recieve the value. + /// Add a double option and set 'var' to receive the value. void AddOption(double *var, const char *short_name, const char *long_name, const char *description, bool required = false) { @@ -105,7 +106,7 @@ public: required)); } - /// Add a string (char*) option and set 'var' to recieve the value. + /// Add a string (char*) option and set 'var' to receive the value. void AddOption(const char **var, const char *short_name, const char *long_name, const char *description, bool required = false) @@ -114,7 +115,8 @@ public: required)); } - /// Add an integer array (seperated by spaces) option and set 'var' to recieve the values. + /** Add an integer array (separated by spaces) option and set 'var' to + receive the values. */ void AddOption(Array * var, const char *short_name, const char *long_name, const char *description, bool required = false) @@ -123,7 +125,8 @@ public: required)); } - /// Add a vector (doubles seperated by spaces) option and set 'var' to recieve the values. + /** Add a vector (doubles separated by spaces) option and set 'var' to + receive the values. */ void AddOption(Vector * var, const char *short_name, const char *long_name, const char *description, bool required = false) @@ -133,14 +136,12 @@ public: } /** @brief Parse the command-line options. - - Note that this function expects all the - options provided through the command line to have a corresponding - AddOption. In particular, this function cannot be used for partial - parsing. */ + Note that this function expects all the options provided through the + command line to have a corresponding AddOption. In particular, this + function cannot be used for partial parsing. */ void Parse(); - /// Return true if the command line options were parsed sucessfully. + /// Return true if the command line options were parsed successfully. bool Good() const { return (error_type == 0); } /// Return true if we are flagged to print the help message. diff --git a/general/sets.hpp b/general/sets.hpp index 33f5ee7874..b3e92b8521 100644 --- a/general/sets.hpp +++ b/general/sets.hpp @@ -44,7 +44,7 @@ public: /// Return the value of the lowest element of the set. int PickElement() { return me[0]; } - /// Return the value of a random element of the sest. + /// Return the value of a random element of the set. int PickRandomElement(); /// Return 1 if the sets are equal and 0 otherwise. @@ -72,11 +72,13 @@ public: /// Return a random value from the ith set in the list. int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); } - /** @brief Check to see if set 's' is in the list. If not append it to the end of the - list. Returns the index of the list where set 's' can be found. */ + /** @brief Check to see if set 's' is in the list. If not append it to the + end of the list. Returns the index of the list where set 's' can be + found. */ int Insert(IntegerSet &s); - /// Return the index of the list where set 's' can be found. Returns -1 if not found. + /** Return the index of the list where set 's' can be found. Returns -1 if + not found. */ int Lookup(IntegerSet &s); /// Write the list of sets into table 't'. diff --git a/general/socketstream.hpp b/general/socketstream.hpp index f0bbd55029..8397948730 100644 --- a/general/socketstream.hpp +++ b/general/socketstream.hpp @@ -36,7 +36,6 @@ protected: char ibuf[buflen], obuf[buflen]; public: - socketbuf() { socket_descriptor = -1; @@ -54,16 +53,15 @@ public: open(hostname, port); } - /** @brief Attach a new socket descriptor to the socketbuf. - Returns the old socket descriptor which is NOT closed. */ + /** @brief Attach a new socket descriptor to the socketbuf. Returns the old + socket descriptor which is NOT closed. */ virtual int attach(int sd); - /// Detatch the current socket descriptor from the socketbuf. + /// Detach the current socket descriptor from the socketbuf. int detach() { return attach(-1); } - /** @brief Open a socket on the 'port' at 'hostname' and store the - socket descriptor. Returns 0 if there is no error, - otherwise returns -1. */ + /** @brief Open a socket on the 'port' at 'hostname' and store the socket + descriptor. Returns 0 if there is no error, otherwise returns -1. */ virtual int open(const char hostname[], int port); /// Close the current socket descriptor. @@ -72,8 +70,8 @@ public: /// Returns the attached socket descriptor. int getsocketdescriptor() { return socket_descriptor; } - /** @brief Returns true if the socket is open and has a valid - socket descriptor. Otherwise returns false. */ + /** @brief Returns true if the socket is open and has a valid socket + descriptor. Otherwise returns false. */ bool is_open() { return (socket_descriptor >= 0); } virtual ~socketbuf() { close(); } @@ -186,8 +184,8 @@ public: bool gnutls_good() const { return status.good(); } - /** Attach a new socket descriptor to the socketbuf. - Returns the old socket descriptor which is NOT closed. */ + /** Attach a new socket descriptor to the socketbuf. Returns the old socket + descriptor which is NOT closed. */ virtual int attach(int sd); virtual int open(const char hostname[], int port); diff --git a/general/stable3d.hpp b/general/stable3d.hpp index 2c191d6505..c1380003a2 100644 --- a/general/stable3d.hpp +++ b/general/stable3d.hpp @@ -25,14 +25,12 @@ public: int Column, Floor, Number; }; -/** @brief Symmetric 3D Table stored as an array of rows each of which has - a stack of column, floor, number nodes. The number of the node - is assigned by counting the nodes from zero as they are pushed - into the table. Diagonals of any kind are not allowed so the row, - column and floor must all be different for each node. Only one - node is stored for all 6 symmetric entries that are indexable by - unique triplets of row, column, and floor. -*/ +/** @brief Symmetric 3D Table stored as an array of rows each of which has a + stack of column, floor, number nodes. The number of the node is assigned by + counting the nodes from zero as they are pushed into the table. Diagonals of + any kind are not allowed so the row, column and floor must all be different + for each node. Only one node is stored for all 6 symmetric entries that are + indexable by unique triplets of row, column, and floor. */ class STable3D { private: @@ -47,26 +45,25 @@ public: /// Construct the table with a total of 'nr' rows. explicit STable3D (int nr); - /** @brief Check to see if this entry is in the table and add it to - the table if it is not there. Returns the number assigned to the - table entry. */ + /** @brief Check to see if this entry is in the table and add it to the table + if it is not there. Returns the number assigned to the table entry. */ int Push (int r, int c, int f); - /// Return the number assigned to the table entry. Abort if it's not there. + /// Return the number assigned to the table entry. Abort if it's not there. int operator() (int r, int c, int f) const; - /// Return the number assigned to the table entry. Return -1 if it's not there. + /** Return the number assigned to the table entry. Return -1 if it's not + there. */ int Index (int r, int c, int f) const; - /** @brief Check to see if this entry is in the table and add it to - the table if it is not there. The entry is addressed by the three - smallest values of (r,c,f,t). Returns the number assigned to the - table entry. */ + /** @brief Check to see if this entry is in the table and add it to the table + if it is not there. The entry is addressed by the three smallest values + of (r,c,f,t). Returns the number assigned to the table entry. */ int Push4 (int r, int c, int f, int t); - /** @brief Return the number assigned to the table entry. The entry is - addressed by the three smallest values of (r,c,f,t). Return -1 if - it is not there. */ + /** @brief Return the number assigned to the table entry. The entry is + addressed by the three smallest values of (r,c,f,t). Return -1 if it is + not there. */ int operator() (int r, int c, int f, int t) const; /// Return the number of elements added to the table. diff --git a/general/text.hpp b/general/text.hpp index db66df8a96..32684ee38d 100644 --- a/general/text.hpp +++ b/general/text.hpp @@ -23,7 +23,8 @@ namespace mfem { // Utilities for text parsing -/// Check to see if the in the stream starts with @a comment_char. If so skip it. + +/// Check if the stream starts with @a comment_char. If so skip it. inline void skip_comment_lines(std::istream &is, const char comment_char) { while (1) diff --git a/general/tic_toc.hpp b/general/tic_toc.hpp index 110b945c96..36a06697ad 100644 --- a/general/tic_toc.hpp +++ b/general/tic_toc.hpp @@ -51,13 +51,16 @@ public: /// Return the time resolution available to the stopwatch. double Resolution(); - /// Return the number of real seconds elapsed since the stopwatch was started. + /** Return the number of real seconds elapsed since the stopwatch was + started. */ double RealTime(); - /// Return the number of user seconds elapsed since the stopwatch was started. + /** Return the number of user seconds elapsed since the stopwatch was + started. */ double UserTime(); - /// Return the number of system seconds elapsed since the stopwatch was started. + /** Return the number of system seconds elapsed since the stopwatch was + started. */ double SystTime(); ~StopWatch(); }; diff --git a/general/version.hpp b/general/version.hpp index df5ae672a3..85905e4531 100644 --- a/general/version.hpp +++ b/general/version.hpp @@ -15,22 +15,22 @@ namespace mfem { -/// Return the version number as a single integer. +/// Return the MFEM version number as a single integer. int GetVersion(); -/// Return the major version number as an integer. +/// Return the MFEM major version number as an integer. int GetVersionMajor(); -/// Return the minor version number as an integer. +/// Return the MFEM minor version number as an integer. int GetVersionMinor(); -/// Return the version patch number as an integer. +/// Return the MFEM version patch number as an integer. int GetVersionPatch(); -/// Return the version number as a string. +/// Return the MFEM version number as a string. const char *GetVersionStr(); -/// Return the Git hash as a string. +/// Return the MFEM Git hash as a string. const char *GetGitStr(); /// Return the MFEM configuration as a string. diff --git a/linalg/vector.hpp b/linalg/vector.hpp index 9fd517445f..eabe335b6a 100644 --- a/linalg/vector.hpp +++ b/linalg/vector.hpp @@ -281,44 +281,44 @@ public: /// v = median(v,lo,hi) entrywise. Implementation assumes lo <= hi. void median(const Vector &lo, const Vector &hi); - /** @brief Extract entries listed in @a dofs to the output Vector @a elemvect. - Negative dof values cause the -dof-1 position in @a elemvect to recieve - the -val in from this Vector. */ + /// Extract entries listed in @a dofs to the output Vector @a elemvect. + /** Negative dof values cause the -dof-1 position in @a elemvect to receive + the -val in from this Vector. */ void GetSubVector(const Array &dofs, Vector &elemvect) const; - /** @brief Extract entries listed in @a dofs to the output array @a elem_data. - Negative dof values cause the -dof-1 position in @a elem_data to recieve - the -val in from this Vector. */ + /// Extract entries listed in @a dofs to the output array @a elem_data. + /** Negative dof values cause the -dof-1 position in @a elem_data to receive + the -val in from this Vector. */ void GetSubVector(const Array &dofs, double *elem_data) const; - /** @brief Set the entries listed in @a dofs to the given @a value. - Negative dof values cause the -dof-1 position in this Vector to recieve - the -value. */ + /// Set the entries listed in @a dofs to the given @a value. + /** Negative dof values cause the -dof-1 position in this Vector to receive + the -value. */ void SetSubVector(const Array &dofs, const double value); - /** @brief Set the entries listed in @a dofs to the values given in the @a elemvect Vector. - Negative dof values cause the -dof-1 position in this Vector to recieve - the -val from @a elemvect. */ + /** @brief Set the entries listed in @a dofs to the values given in the @a + elemvect Vector. Negative dof values cause the -dof-1 position in this + Vector to receive the -val from @a elemvect. */ void SetSubVector(const Array &dofs, const Vector &elemvect); - /** @brief Set the entries listed in @a dofs to the values given the @a elem_data array. - Negative dof values cause the -dof-1 position in this Vector to recieve - the -val from @a elem_data. */ + /** @brief Set the entries listed in @a dofs to the values given the @a , + elem_data array. Negative dof values cause the -dof-1 position in this + Vector to receive the -val from @a elem_data. */ void SetSubVector(const Array &dofs, double *elem_data); - /** @brief Add elements of the @a elemvect Vector to the entries listed in @a dofs. - Negative dof values cause the -dof-1 position in this Vector to add - the -val from @a elemvect. */ + /** @brief Add elements of the @a elemvect Vector to the entries listed in @a + dofs. Negative dof values cause the -dof-1 position in this Vector to add + the -val from @a elemvect. */ void AddElementVector(const Array & dofs, const Vector & elemvect); - /** @brief Add elements of the @a elem_data array to the entries listed in @a dofs. - Negative dof values cause the -dof-1 position in this Vector to add - the -val from @a elem_data. */ + /** @brief Add elements of the @a elem_data array to the entries listed in @a + dofs. Negative dof values cause the -dof-1 position in this Vector to add + the -val from @a elem_data. */ void AddElementVector(const Array & dofs, double *elem_data); - /** @brief Add @a times the elements of the @a elemvect Vector to the entries listed in - @a dofs. Negative dof values cause the -dof-1 position in this Vector to add - the -a*val from @a elemvect. */ + /** @brief Add @a times the elements of the @a elemvect Vector to the entries + listed in @a dofs. Negative dof values cause the -dof-1 position in this + Vector to add the -a*val from @a elemvect. */ void AddElementVector(const Array & dofs, const double a, const Vector & elemvect); From 8d33bbde0e5c997e1be45c3b60d6e5ca98c420bc Mon Sep 17 00:00:00 2001 From: Tomov Date: Sun, 7 Jun 2020 17:25:32 -0700 Subject: [PATCH 458/535] Minor. --- fem/gslib.cpp | 4 ++-- fem/tmop_tools.cpp | 2 +- linalg/solvers.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index b7b671402b..0fb0eb7655 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -192,8 +192,8 @@ void FindPointsGSLIB::Interpolate(Array &codes, const int ncomp = field_in.FESpace()->GetVDim(), points_fld = field_in.Size() / ncomp, points_cnt = codes.Size(); - MFEM_VERIFY(field_out.Size() >= points_cnt*ncomp, - " Increase size of field_out in FindPointsGSLIB::Interpolate."); + MFEM_ASSERT(field_out.Size() >= points_cnt*ncomp, + "Increase size of field_out in FindPointsGSLIB::Interpolate."); for (int i = 0; i < ncomp; i++) { diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index d60b0897f4..3083140f38 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -404,7 +404,6 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, double scale = 1.0, energy_out = 0.0; double norm0 = Norm(r); - // Decreases the scaling of the update until the new mesh is valid. for (int i = 0; i < 12; i++) { add(x, -scale, c, x_out); @@ -422,6 +421,7 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, } #endif + // Check det(Jpr) > 0. if (!untangling) { int jac_ok = 1; diff --git a/linalg/solvers.cpp b/linalg/solvers.cpp index 8ddc58a0df..47def50f73 100644 --- a/linalg/solvers.cpp +++ b/linalg/solvers.cpp @@ -1643,7 +1643,7 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const void LBFGSSolver::Mult(const Vector &b, Vector &x) const { - MFEM_ASSERT(oper != NULL, "the Operator is not set (use SetOperator)."); + MFEM_VERIFY(oper != NULL, "the Operator is not set (use SetOperator)."); // Quadrature points that are checked for negative Jacobians etc. Vector sk, rk, yk, skt, ykt, rho, alpha; @@ -1722,10 +1722,10 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const int klim; subtract(r, rk, yk); // yk = r_{k+1} - r_{k} sk = c; sk *= -c_scale; //sk = x_{k+1} - x_{k} = -c_scale*c - double gamma = Dot(sk, yk)/Dot(yk, yk); + const double gamma = Dot(sk, yk)/Dot(yk, yk); // Save last m vectors - if ( it < m) + if (it < m) { skM.SetCol(it, sk); ykM.SetCol(it, yk); From 7de36b40bbb7edc5d1493db9d5cf43e17bcaccaf Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 12:27:59 -0700 Subject: [PATCH 459/535] Wrapping math formulae in \f$ --- fem/coefficient.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index b27f5420b9..e3544b19c8 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -1175,8 +1175,8 @@ public: /** @brief Matrix coefficient defined as -a k x k x, for a vector k and scalar a - This coefficient returns a * (|k|^2 I - k \otimes k), where I is - the identity matrix and \otimes indicates the outer product. This + This coefficient returns \f$a * (|k|^2 I - k \otimes k)\f$, where I is + the identity matrix and \f$\otimes\f$ indicates the outer product. This can be evaluated for vectors of any dimension but in three dimensions it corresponds to computing the cross product with k twice. */ From ac426c336b706c5a02fcae7b1eeb4fe56b6c202c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 12:35:49 -0700 Subject: [PATCH 460/535] Adding check for valid dimension --- fem/coefficient.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 4734b7d7dd..c62e3aa154 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -215,11 +215,25 @@ CurlGridFunctionCoefficient::CurlGridFunctionCoefficient ( (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() - 3) : 0) { + if (gf) + { + int sdim = gf -> FESpace() -> GetMesh() -> SpaceDimension(); + MFEM_VERIFY(sdim == 2 || sdim == 3, + "CurlGridFunctionCoefficient " + "only defind for spaces of dimension 2 or 3."); + } GridFunc = gf; } void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) { + if (gf) + { + int sdim = gf -> FESpace() -> GetMesh() -> SpaceDimension(); + MFEM_VERIFY(sdim == 2 || sdim == 3, + "CurlGridFunctionCoefficient " + "only defind for spaces of dimension 2 or 3."); + } GridFunc = gf; vdim = (gf) ? (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() - 3) : 0; } From ac1bc5f2ab178a185adc775dabddeb1440cb9db6 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 12:40:31 -0700 Subject: [PATCH 461/535] Clarifying comment --- fem/gridfunc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index a5d3d3a4cf..3206ea76f0 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1545,8 +1545,9 @@ void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const break; case ElementTransformation::BDR_ELEMENT: { - // In order to capture the normal component of the gradient we - // must evaluate it in the neighboring element. + // In order to properly capture the normal component of the gradient + // as well as its tangential components we must evaluate it in the + // neighboring element. FaceElementTransformations * FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); From b542fcd25b8c22bd90a5261f49dddfae731bcd3c Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 12:44:15 -0700 Subject: [PATCH 462/535] Clarifying comment in GetDivergence --- fem/gridfunc.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 3206ea76f0..b14ae4ffcf 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1377,8 +1377,10 @@ double GridFunction::GetDivergence(ElementTransformation &T) const break; case ElementTransformation::BDR_ELEMENT: { - // In order to capture the derivative of the normal component of - // the field we must evaluate it in the neighboring element. + // In order to properly capture the derivative of the normal component + // of the field (as well as the transverse divergence of the + // tangential compoents) we must evaluate it in the neighboring + // element. FaceElementTransformations * FET = fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo); From 8461df3d67795efb9015460f0539dd7b4789cb7a Mon Sep 17 00:00:00 2001 From: Pieter Ghysels Date: Mon, 8 Jun 2020 13:05:43 -0700 Subject: [PATCH 463/535] Fix for superlu_dist 6.3. --- linalg/superlu.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linalg/superlu.cpp b/linalg/superlu.cpp index a22cbe64e1..88de900059 100644 --- a/linalg/superlu.cpp +++ b/linalg/superlu.cpp @@ -24,6 +24,18 @@ #error "SuperLUDist has been built with 64bit integers. This is not supported" #endif +#if SUPERLU_DIST_MAJOR_VERSION > 6 || \ + (SUPERLU_DIST_MAJOR_VERSION == 6 && SUPERLU_DIST_MINOR_VERSION > 2) +#define ScalePermstruct_t dScalePermstruct_t +#define LUstruct_t dLUstruct_t +#define SOLVEstruct_t dSOLVEstruct_t +#define ScalePermstructFree dScalePermstructFree +#define Destroy_LU dDestroy_LU +#define LUstructFree dLUstructFree +#define LUstructInit dLUstructInit +#endif + + using namespace std; namespace mfem From 5ab8dfc15ca331432b42a2fb8df59880cf88ee59 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 13:16:27 -0700 Subject: [PATCH 464/535] Creating overrides to GetValue and GetVectorValue for face neighbor elements --- fem/gridfunc.hpp | 9 ++-- fem/pgridfunc.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++ fem/pgridfunc.hpp | 9 ++++ 3 files changed, 118 insertions(+), 4 deletions(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 9687514b59..643e54d586 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -208,13 +208,14 @@ public: ///@{ /** Return a scalar value from within the element indicated by the ElementTransformation Object. */ - double GetValue(ElementTransformation &T, const IntegrationPoint &ip, - int comp = 0, Vector *tr = NULL) const; + virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip, + int comp = 0, Vector *tr = NULL) const; /** Return a vector value from within the element indicated by the ElementTransformation Object. */ - void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, - Vector &val, Vector *tr = NULL) const; + virtual void GetVectorValue(ElementTransformation &T, + const IntegrationPoint &ip, + Vector &val, Vector *tr = NULL) const; ///@} /** @name ElementTransformation Get Values Methods diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp index dac6728bf2..7883c70ab2 100644 --- a/fem/pgridfunc.cpp +++ b/fem/pgridfunc.cpp @@ -299,6 +299,110 @@ const return (DofVal * LocVec); } +double ParGridFunction::GetValue(ElementTransformation &T, + const IntegrationPoint &ip, + int comp, Vector *tr) const +{ + // We can assume faces and edges are local + if (T.ElementType != ElementTransformation::ELEMENT) + { + return GridFunction::GetValue(T, ip, comp, tr); + } + + // Check for evaluation in a local element + int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE(); + if (nbr_el_no < 0) + { + return GridFunction::GetValue(T, ip, comp, tr); + } + + // Evaluate using DoFs from a neighboring element + if (tr) + { + T.SetIntPoint(&ip); + T.Transform(ip, *tr); + } + + Array dofs; + Vector DofVal, LocVec; + int fes_vdim = pfes->GetVDim(); + pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs); + if (fes_vdim > 1) + { + int s = dofs.Size()/fes_vdim; + Array _dofs(&dofs[(comp-1)*s], s); + face_nbr_data.GetSubVector(_dofs, LocVec); + DofVal.SetSize(s); + } + else + { + face_nbr_data.GetSubVector(dofs, LocVec); + DofVal.SetSize(dofs.Size()); + } + pfes->GetFaceNbrFE(nbr_el_no)->CalcShape(ip, DofVal); + + return (DofVal * LocVec); +} + +void ParGridFunction::GetVectorValue(ElementTransformation &T, + const IntegrationPoint &ip, + Vector &val, Vector *tr) const +{ + // We can assume faces and edges are local + if (T.ElementType != ElementTransformation::ELEMENT) + { + return GridFunction::GetVectorValue(T, ip, val, tr); + } + + // Check for evaluation in a local element + int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE(); + if (nbr_el_no < 0) + { + return GridFunction::GetVectorValue(T, ip, val, tr); + } + + // Evaluate using DoFs from a neighboring element + if (tr) + { + T.SetIntPoint(&ip); + T.Transform(ip, *tr); + } + + Array vdofs; + pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs); + const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no); + + int dof = fe->GetDof(); + Vector loc_data; + face_nbr_data.GetSubVector(vdofs, loc_data); + if (fe->GetRangeType() == FiniteElement::SCALAR) + { + Vector shape(dof); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, shape); + } + else + { + fe->CalcPhysShape(T, shape); + } + int vdim = pfes->GetVDim(); + val.SetSize(vdim); + for (int k = 0; k < vdim; k++) + { + val(k) = shape * ((const double *)loc_data + dof * k); + } + } + else + { + int spaceDim = pfes->GetMesh()->SpaceDimension(); + DenseMatrix vshape(dof, spaceDim); + fe->CalcVShape(T, vshape); + val.SetSize(spaceDim); + vshape.MultTranspose(loc_data, val); + } +} + void ParGridFunction::ProjectCoefficient(Coefficient &coeff) { DeltaCoefficient *delta_c = dynamic_cast(&coeff); diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp index d8f153a32e..e5e1922aaf 100644 --- a/fem/pgridfunc.hpp +++ b/fem/pgridfunc.hpp @@ -204,6 +204,15 @@ public: double GetValue(ElementTransformation &T) { return GetValue(T.ElementNo, T.GetIntPoint()); } + // Redefine to handle the case when T describes a face-neighbor element + virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip, + int comp = 0, Vector *tr = NULL) const; + + // Redefine to handle the case when T describes a face-neighbor element + virtual void GetVectorValue(ElementTransformation &T, + const IntegrationPoint &ip, + Vector &val, Vector *tr = NULL) const; + using GridFunction::ProjectCoefficient; virtual void ProjectCoefficient(Coefficient &coeff); From dce355c41bf9967505e35e2ae9429294ceaa4b63 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Mon, 8 Jun 2020 14:14:20 -0700 Subject: [PATCH 465/535] reviewer comments --- fem/gslib.cpp | 3 +-- fem/tmop_tools.cpp | 2 +- linalg/solvers.cpp | 22 ++++++++++------------ linalg/solvers.hpp | 2 +- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 0fb0eb7655..1ab15f2bdd 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -192,8 +192,7 @@ void FindPointsGSLIB::Interpolate(Array &codes, const int ncomp = field_in.FESpace()->GetVDim(), points_fld = field_in.Size() / ncomp, points_cnt = codes.Size(); - MFEM_ASSERT(field_out.Size() >= points_cnt*ncomp, - "Increase size of field_out in FindPointsGSLIB::Interpolate."); + field_out.SetSize(points_cnt*ncomp); for (int i = 0; i < ncomp; i++) { diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 3083140f38..943b9734fc 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -451,7 +451,7 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, { if (print_level >= 0) { mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; } - scale *= 0.25; continue; + scale *= 0.5; continue; } } // endif(!untangling) diff --git a/linalg/solvers.cpp b/linalg/solvers.cpp index 47def50f73..6fc8e3873d 100644 --- a/linalg/solvers.cpp +++ b/linalg/solvers.cpp @@ -1646,15 +1646,13 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const MFEM_VERIFY(oper != NULL, "the Operator is not set (use SetOperator)."); // Quadrature points that are checked for negative Jacobians etc. - Vector sk, rk, yk, skt, ykt, rho, alpha; + Vector sk, rk, yk, rho, alpha; DenseMatrix skM(width, m), ykM(width, m); //r - r_{k+1}, c - descent direction sk.SetSize(width); //x_{k+1}-x_k rk.SetSize(width); //nabla(f(x_{k})) yk.SetSize(width); //r_{k+1}-r_{k} - skt.SetSize(width); //work vector - ykt.SetSize(width); //work vector rho.SetSize(m); //1/(dot(yk,sk) alpha.SetSize(m); //rhok*sk'*c @@ -1746,20 +1744,20 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const c = r; for (int i = klim-1; i > -1; i--) { - skM.GetColumn(i, skt); - ykM.GetColumn(i, ykt); - rho(i) = 1./Dot(skt, ykt); - alpha(i) = rho(i)*Dot(skt,c); - add(c, -alpha(i), ykt, c); + skM.GetColumn(i, sk); + ykM.GetColumn(i, yk); + rho(i) = 1./Dot(sk, yk); + alpha(i) = rho(i)*Dot(sk,c); + add(c, -alpha(i), yk, c); } c *= gamma; // scale search direction for (int i = 0; i < klim ; i++) { - skM.GetColumn(i,skt); - ykM.GetColumn(i,ykt); - double betai = rho(i)*Dot(ykt, c); - add(c, alpha(i)-betai, skt, c); + skM.GetColumn(i,sk); + ykM.GetColumn(i,yk); + double betai = rho(i)*Dot(yk, c); + add(c, alpha(i)-betai, sk, c); } norm = Norm(r); diff --git a/linalg/solvers.hpp b/linalg/solvers.hpp index a31f2d983b..2d817625ad 100644 --- a/linalg/solvers.hpp +++ b/linalg/solvers.hpp @@ -430,7 +430,7 @@ public: LBFGSSolver(MPI_Comm _comm) : NewtonSolver(_comm) { } #endif - void SetKDim(int dim) { m = dim; } + void SetHistorySize(int dim) { m = dim; } /// Solve the nonlinear system with right-hand side @a b. /** If `b.Size() != Height()`, then @a b is assumed to be zero. */ From 039adec0fc4ead94c025db47da608e562f25dc28 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 16:31:07 -0700 Subject: [PATCH 466/535] Mimicking the serial GetValue in parallel --- fem/pgridfunc.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp index 7883c70ab2..ad3bf7ea5a 100644 --- a/fem/pgridfunc.cpp +++ b/fem/pgridfunc.cpp @@ -324,22 +324,20 @@ double ParGridFunction::GetValue(ElementTransformation &T, } Array dofs; - Vector DofVal, LocVec; - int fes_vdim = pfes->GetVDim(); + const FiniteElement * fe = pfes->GetFaceNbrFE(nbr_el_no); pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs); - if (fes_vdim > 1) + + pfes->DofsToVDofs(comp-1, dofs); + Vector DofVal(dofs.Size()), LocVec; + if (fe->GetMapType() == FiniteElement::VALUE) { - int s = dofs.Size()/fes_vdim; - Array _dofs(&dofs[(comp-1)*s], s); - face_nbr_data.GetSubVector(_dofs, LocVec); - DofVal.SetSize(s); + fe->CalcShape(ip, DofVal); } else { - face_nbr_data.GetSubVector(dofs, LocVec); - DofVal.SetSize(dofs.Size()); + fe->CalcPhysShape(T, DofVal); } - pfes->GetFaceNbrFE(nbr_el_no)->CalcShape(ip, DofVal); + face_nbr_data.GetSubVector(dofs, LocVec); return (DofVal * LocVec); } From e026fa6c26c3d340b1e4cf3566bffaf2a6135f70 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 16:31:56 -0700 Subject: [PATCH 467/535] Setting ElementType member data in GetFaceNbrElementTransformation --- mesh/pmesh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index bcb22a621b..f6f902e8b6 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -1690,6 +1690,7 @@ void ParMesh::GetFaceNbrElementTransformation( ElTr->Attribute = elem->GetAttribute(); ElTr->ElementNo = NumOfElements + i; + ElTr->ElementType = ElementTransformation::ELEMENT; if (Nodes == NULL) { From 60db6756cb23a82cf3aaba1db57d790a057d4077 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 8 Jun 2020 16:32:26 -0700 Subject: [PATCH 468/535] Adding parallel unit tests to test_get_value --- tests/unit/fem/test_get_value.cpp | 613 +++++++++++++++++++++++++++++- 1 file changed, 611 insertions(+), 2 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index af225bb675..9b01c1e3e6 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -104,8 +104,8 @@ TEST_CASE("1D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[1]; - Vector tip(tip_data, 1); + double tip_data[dim]; + Vector tip(tip_data, dim); for (int j=0; jGetElement2Transformation(); + int e = FET->Elem2No; + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_1D_lin(tip); + + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << my_rank << ": Checked GridFunction::GetValue at " + << npts << " 1D points" << std::endl; +} + +TEST_CASE("2D GetValue in Parallel", + "[ParGridFunction]" + "[GridFunctionCoefficient]" + "[Parallel]") +{ + int num_procs; + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + + int my_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); + + int log = 1; + int n = 2 * num_procs; + int dim = 2; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh *mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + ParMesh pmesh(MPI_COMM_WORLD, *mesh); + pmesh.ExchangeFaceNbrData(); + delete mesh; + + FunctionCoefficient linCoef(func_2D_lin); + + SECTION("2D GetValue tests for element type " + std::to_string(type)) + { + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); + ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); + + dgv_fespace.ExchangeFaceNbrData(); + dgi_fespace.ExchangeFaceNbrData(); + + ParGridFunction dgv_x(&dgv_fespace); + ParGridFunction dgi_x(&dgi_fespace); + + GridFunctionCoefficient dgv_xCoef(&dgv_x); + GridFunctionCoefficient dgi_xCoef(&dgi_x); + + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + dgv_x.ExchangeFaceNbrData(); + dgi_x.ExchangeFaceNbrData(); + + SECTION("Shared Face Evaluation 2D") + { + if (my_rank == 0) + { + std::cout << "Shared Face Evaluation 2D" << std::endl; + } + for (int sf = 0; sf < pmesh.GetNSharedFaces(); sf++) + { + FaceElementTransformations *FET = + pmesh.GetSharedFaceTransformations(sf); + ElementTransformation *T = &FET->GetElement2Transformation(); + int e = FET->Elem2No; + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_2D_lin(tip); + + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << my_rank << ": Checked GridFunction::GetValue at " + << npts << " 2D points" << std::endl; +} + +TEST_CASE("3D GetValue in Parallel", + "[ParGridFunction]" + "[GridFunctionCoefficient]" + "[Parallel]") +{ + int num_procs; + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + + int my_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); + + int log = 1; + int n = 2 * num_procs; + int dim = 3; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::WEDGE; type++) + { + Mesh *mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + ParMesh pmesh(MPI_COMM_WORLD, *mesh); + pmesh.ExchangeFaceNbrData(); + delete mesh; + + FunctionCoefficient linCoef(func_3D_lin); + + SECTION("3D GetValue tests for element type " + std::to_string(type)) + { + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); + ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); + + dgv_fespace.ExchangeFaceNbrData(); + dgi_fespace.ExchangeFaceNbrData(); + + ParGridFunction dgv_x(&dgv_fespace); + ParGridFunction dgi_x(&dgi_fespace); + + GridFunctionCoefficient dgv_xCoef(&dgv_x); + GridFunctionCoefficient dgi_xCoef(&dgi_x); + + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + dgv_x.ExchangeFaceNbrData(); + dgi_x.ExchangeFaceNbrData(); + + SECTION("Shared Face Evaluation 3D") + { + if (my_rank == 0) + { + std::cout << "Domain Evaluation 3D" << std::endl; + } + for (int sf = 0; sf < pmesh.GetNSharedFaces(); sf++) + { + FaceElementTransformations *FET = + pmesh.GetSharedFaceTransformations(sf); + ElementTransformation *T = &FET->GetElement2Transformation(); + int e = FET->Elem2No; + const FiniteElement *fe = dgv_fespace.GetFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double h1_err = 0.0; + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + double f_val = func_3D_lin(tip); + + double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + + dgv_err += fabs(f_val - dgv_gf_val); + dgi_err += fabs(f_val - dgi_gf_val); + + if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + { + std::cout << e << ":" << j << " dgv " << f_val << " " + << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + { + std::cout << e << ":" << j << " dgi " << f_val << " " + << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << std::endl; + } + } + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << my_rank << ": Checked GridFunction::GetValue at " + << npts << " 3D points" << std::endl; +} + +TEST_CASE("2D GetVectorValue in Parallel", + "[ParGridFunction]" + "[VectorGridFunctionCoefficient]" + "[Parallel]") +{ + int num_procs; + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + + int my_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); + + int log = 1; + int n = 2 * num_procs; + int dim = 2; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TRIANGLE; + type <= (int)Element::QUADRILATERAL; type++) + { + Mesh *mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + ParMesh pmesh(MPI_COMM_WORLD, *mesh); + pmesh.ExchangeFaceNbrData(); + delete mesh; + + VectorFunctionCoefficient linCoef(dim, Func_2D_lin); + + SECTION("2D GetVectorValue tests for element type " + + std::to_string(type)) + { + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec, dim); + ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec, dim); + + dgv_fespace.ExchangeFaceNbrData(); + dgi_fespace.ExchangeFaceNbrData(); + + ParGridFunction dgv_x(&dgv_fespace); + ParGridFunction dgi_x(&dgi_fespace); + + VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); + VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); + + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + dgv_x.ExchangeFaceNbrData(); + dgi_x.ExchangeFaceNbrData(); + + Vector f_val(dim); f_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector dgi_gf_val(dim); dgi_gf_val = 0.0; + + SECTION("Shared Face Evaluation 2D") + { + if (my_rank == 0) + { + std::cout << "Shared Face Evaluation 2D" << std::endl; + } + for (int sf = 0; sf < pmesh.GetNSharedFaces(); sf++) + { + FaceElementTransformations *FET = + pmesh.GetSharedFaceTransformations(sf); + ElementTransformation *T = &FET->GetElement2Transformation(); + int e = FET->Elem2No; + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_2D_lin(tip, f_val); + + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double dgv_dist = Distance(f_val, dgv_gf_val, 2); + double dgi_dist = Distance(f_val, dgi_gf_val, 2); + + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_dist << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << e << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_dist << std::endl; + } + } + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << my_rank << ": Checked GridFunction::GetVectorValue at " + << npts << " 2D points" << std::endl; +} + +TEST_CASE("3D GetVectorValue in Parallel", + "[ParGridFunction]" + "[VectorGridFunctionCoefficient]" + "[Parallel]") +{ + int num_procs; + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + + int my_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); + + int log = 1; + int n = 2 * num_procs; + int dim = 3; + int order = 1; + int npts = 0; + + double tol = 1e-6; + + for (int type = (int)Element::TETRAHEDRON; + type <= (int)Element::HEXAHEDRON; type++) + { + Mesh *mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + ParMesh pmesh(MPI_COMM_WORLD, *mesh); + pmesh.ExchangeFaceNbrData(); + delete mesh; + + VectorFunctionCoefficient linCoef(dim, Func_3D_lin); + + SECTION("3D GetVectorValue tests for element type " + + std::to_string(type)) + { + DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::VALUE); + DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + + ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec, dim); + ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec, dim); + + dgv_fespace.ExchangeFaceNbrData(); + dgi_fespace.ExchangeFaceNbrData(); + + ParGridFunction dgv_x(&dgv_fespace); + ParGridFunction dgi_x(&dgi_fespace); + + VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); + VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); + + dgv_x.ProjectCoefficient(linCoef); + dgi_x.ProjectCoefficient(linCoef); + + dgv_x.ExchangeFaceNbrData(); + dgi_x.ExchangeFaceNbrData(); + + Vector f_val(dim); f_val = 0.0; + Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector dgi_gf_val(dim); dgi_gf_val = 0.0; + + SECTION("Shared Face Evaluation 3D") + { + if (my_rank == 0) + { + std::cout << "Shared Face Evaluation 3D" << std::endl; + } + for (int sf = 0; sf < pmesh.GetNSharedFaces(); sf++) + { + FaceElementTransformations *FET = + pmesh.GetSharedFaceTransformations(sf); + ElementTransformation *T = &FET->GetElement2Transformation(); + int e = FET->Elem2No; + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), + 2*order + 2); + + double dgv_err = 0.0; + double dgi_err = 0.0; + + double tip_data[dim]; + Vector tip(tip_data, dim); + for (int j=0; jSetIntPoint(&ip); + T->Transform(ip, tip); + + Func_3D_lin(tip, f_val); + + dgv_xCoef.Eval(dgv_gf_val, *T, ip); + dgi_xCoef.Eval(dgi_gf_val, *T, ip); + + double dgv_dist = Distance(f_val, dgv_gf_val, 2); + double dgi_dist = Distance(f_val, dgi_gf_val, 2); + + dgv_err += dgv_dist; + dgi_err += dgi_dist; + + if (log > 0 && dgv_dist > tol) + { + std::cout << e << ":" << j << " dgv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," + << dgv_gf_val[2] << ") " << dgv_dist + << std::endl; + } + if (log > 0 && dgi_dist > tol) + { + std::cout << e << ":" << j << " dgi (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," + << dgi_gf_val[2] << ") " << dgi_dist + << std::endl; + } + } + dgv_err /= ir.GetNPoints(); + dgi_err /= ir.GetNPoints(); + + REQUIRE(dgv_err == Approx(0.0)); + REQUIRE(dgi_err == Approx(0.0)); + } + } + } + } + std::cout << my_rank << ": Checked GridFunction::GetVectorValue at " + << npts << " 3D points" << std::endl; +} + +#endif // MFEM_USE_MPI + } // namespace get_value From 5802774a284b77a1300b5716a9066c450e99bb98 Mon Sep 17 00:00:00 2001 From: Ketan Mittal Date: Mon, 8 Jun 2020 16:32:43 -0700 Subject: [PATCH 469/535] removed copy of past history to reduce ops --- linalg/solvers.cpp | 47 ++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/linalg/solvers.cpp b/linalg/solvers.cpp index 6fc8e3873d..7397ebc9dc 100644 --- a/linalg/solvers.cpp +++ b/linalg/solvers.cpp @@ -1655,6 +1655,7 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const yk.SetSize(width); //r_{k+1}-r_{k} rho.SetSize(m); //1/(dot(yk,sk) alpha.SetSize(m); //rhok*sk'*c + int last_saved_id = -1; int it; double norm0, norm, norm_goal; @@ -1717,32 +1718,17 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const } // LBFGS - construct descent direction - int klim; subtract(r, rk, yk); // yk = r_{k+1} - r_{k} sk = c; sk *= -c_scale; //sk = x_{k+1} - x_{k} = -c_scale*c const double gamma = Dot(sk, yk)/Dot(yk, yk); // Save last m vectors - if (it < m) - { - skM.SetCol(it, sk); - ykM.SetCol(it, yk); - klim = it+1; - } - else - { - for (int i = 0; i < m-1; i++) - { - skM.SetCol(i, skM.GetColumn(i+1)); //shift columns - ykM.SetCol(i, ykM.GetColumn(i+1)); //shift columns - } - skM.SetCol(m-1, sk); // copy new column - ykM.SetCol(m-1, yk); // copy new colum - klim = m; - } + last_saved_id = (last_saved_id == m-1) ? 0 : last_saved_id+1; + skM.SetCol(last_saved_id, sk); + ykM.SetCol(last_saved_id, yk); c = r; - for (int i = klim-1; i > -1; i--) + for (int i = last_saved_id; i > -1; i--) { skM.GetColumn(i, sk); ykM.GetColumn(i, yk); @@ -1750,9 +1736,30 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const alpha(i) = rho(i)*Dot(sk,c); add(c, -alpha(i), yk, c); } + if (it > m-1) + { + for (int i = m-1; i > last_saved_id; i--) + { + skM.GetColumn(i, sk); + ykM.GetColumn(i, yk); + rho(i) = 1./Dot(sk, yk); + alpha(i) = rho(i)*Dot(sk,c); + add(c, -alpha(i), yk, c); + } + } c *= gamma; // scale search direction - for (int i = 0; i < klim ; i++) + if (it > m-1) + { + for (int i = last_saved_id+1; i < m ; i++) + { + skM.GetColumn(i,sk); + ykM.GetColumn(i,yk); + double betai = rho(i)*Dot(yk, c); + add(c, alpha(i)-betai, sk, c); + } + } + for (int i = 0; i < last_saved_id+1 ; i++) { skM.GetColumn(i,sk); ykM.GetColumn(i,yk); From f9418576252a63e7046ad48eadb38ef51c94ed37 Mon Sep 17 00:00:00 2001 From: Tomov Date: Mon, 8 Jun 2020 17:02:10 -0700 Subject: [PATCH 470/535] Added a sample run and minor edits. --- fem/tmop_tools.cpp | 4 +++- miniapps/meshing/mesh-optimizer.cpp | 18 ++++++++++-------- miniapps/meshing/pmesh-optimizer.cpp | 18 ++++++++++-------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index 943b9734fc..8550bcb3d5 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -404,6 +404,8 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, double scale = 1.0, energy_out = 0.0; double norm0 = Norm(r); + const double detJ_factor = (solver_type == 1) ? 0.25 : 0.5; + for (int i = 0; i < 12; i++) { add(x, -scale, c, x_out); @@ -451,7 +453,7 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, { if (print_level >= 0) { mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; } - scale *= 0.5; continue; + scale *= detJ_factor; continue; } } // endif(!untangling) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 0287da85cb..36996efaac 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -32,27 +32,29 @@ // Compile with: make mesh-optimizer // // Sample runs: -// Adapted analytic Hessian: +// Adapted analytic shape: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -// Adapted analytic Hessian with size+orientation: +// Adapted analytic size+orientation: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -// Adapted analytic Hessian with shape+size+orientation +// Adapted analytic shape+orientation: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// // Adapted discrete size: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor -// -// Adapted size+aspect ratio to discrete material indicator +// Adapted discrete size+aspect_ratio: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -// Adapted discrete size+orientation (requires GSLIB) +// Adapted discrete size+orientation (requires GSLIB): // * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 -// Adapted discrete aspect-ratio+orientation (requires GSLIB) +// Adapted discrete aspect-ratio+orientation (requires GSLIB): // * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 -// Adapted discrete aspect ratio (3D) +// Adapted discrete aspect ratio (3D): // mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // // Adaptive limiting: // mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 +// Adaptive limiting through the L-BFGS solver: +// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -ae 1 -st 1 // Adaptive limiting through FD (requires GSLIB): // * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index ff5f15b888..7cb09d89e8 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -32,27 +32,29 @@ // Compile with: make pmesh-optimizer // // Sample runs: -// Adapted analytic Hessian: +// Adapted analytic shape: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -// Adapted analytic Hessian with size+orientation: +// Adapted analytic size+orientation: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -// Adapted analytic Hessian with Shape+size+orientation +// Adapted analytic shape+orientation: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// // Adapted discrete size: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor -// -// Adapted size+aspect ratio to discrete material indicator +// Adapted discrete size+aspect_ratio: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -// Adapted discrete size+orientation (requires GSLIB) +// Adapted discrete size+orientation (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 -// Adapted discrete aspect-ratio+orientation (requires GSLIB) +// Adapted discrete aspect_ratio+orientation (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 -// Adapted discrete aspect ratio (3D) +// Adapted discrete aspect ratio (3D): // mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // // Adaptive limiting: // mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 +// Adaptive limiting through the L-BFGS solver: +// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -ae 1 -st 1 // Adaptive limiting through FD (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // From 46f80874dca2756a2915ca292d08dc29f1af9ec2 Mon Sep 17 00:00:00 2001 From: Tomov Date: Mon, 8 Jun 2020 17:12:49 -0700 Subject: [PATCH 471/535] Renamed a metric. --- fem/tmop.cpp | 36 ++++++++++++++-------------- fem/tmop.hpp | 30 +++++++++++------------ miniapps/meshing/mesh-optimizer.cpp | 8 +++---- miniapps/meshing/mesh-optimizer.hpp | 4 ++-- miniapps/meshing/pmesh-optimizer.cpp | 8 +++---- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/fem/tmop.cpp b/fem/tmop.cpp index a8957ad99c..a17dc9d95d 100644 --- a/fem/tmop.cpp +++ b/fem/tmop.cpp @@ -177,24 +177,6 @@ double TMOP_Metric_SSA2D::EvalW(const DenseMatrix &Jpt) const return Mat.FNorm2(); } -// mu_85 = |T-T'|^2, where T'= |T|*I/sqrt(2) -double TMOP_Metric_SS2D::EvalW(const DenseMatrix &Jpt) const -{ - MFEM_VERIFY(Jtr != NULL, - "Requires a target Jacobian, use SetTargetJacobian()."); - - DenseMatrix Id(2,2); - DenseMatrix Mat(2,2); - Mat = Jpt; - - Id(0,0) = 1; Id(0,1) = 0; - Id(1,0) = 0; Id(1,1) = 1; - Id *= Mat.FNorm()/pow(2,0.5); - - Mat.Add(-1.,Id); - return Mat.FNorm2(); -} - double TMOP_Metric_002::EvalW(const DenseMatrix &Jpt) const { ie.SetJacobian(Jpt.GetData()); @@ -484,6 +466,24 @@ void TMOP_Metric_077::AssembleH(const DenseMatrix &Jpt, ie.Assemble_TProd(weight * I2inv_sq / I2, ie.Get_dI2(), A.GetData()); } +// mu_85 = |T-T'|^2, where T'= |T|*I/sqrt(2) +double TMOP_Metric_085::EvalW(const DenseMatrix &Jpt) const +{ + MFEM_VERIFY(Jtr != NULL, + "Requires a target Jacobian, use SetTargetJacobian()."); + + DenseMatrix Id(2,2); + DenseMatrix Mat(2,2); + Mat = Jpt; + + Id(0,0) = 1; Id(0,1) = 0; + Id(1,0) = 0; Id(1,1) = 1; + Id *= Mat.FNorm()/pow(2,0.5); + + Mat.Add(-1.,Id); + return Mat.FNorm2(); +} + double TMOP_Metric_211::EvalW(const DenseMatrix &Jpt) const { // mu_211 = (det(J) - 1)^2 - det(J) + (det(J)^2 + eps)^{1/2} diff --git a/fem/tmop.hpp b/fem/tmop.hpp index e5d0e58d00..fbdf5c1a7e 100644 --- a/fem/tmop.hpp +++ b/fem/tmop.hpp @@ -162,21 +162,6 @@ public: { MFEM_ABORT("Not implemented"); } }; -/// Shape+Size metric, 2D. -class TMOP_Metric_SS2D : public TMOP_QualityMetric -{ -public: - // W = 0.5 (1 - cos(theta_Jpr - theta_Jtr)). - virtual double EvalW(const DenseMatrix &Jpt) const; - - virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const - { MFEM_ABORT("Not implemented"); } - - virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS, - const double weight, DenseMatrix &A) const - { MFEM_ABORT("Not implemented"); } -}; - /// Shape, ideal barrier metric, 2D class TMOP_Metric_002 : public TMOP_QualityMetric { @@ -331,6 +316,21 @@ public: }; +/// Shape & orientation metric, 2D. +class TMOP_Metric_085 : public TMOP_QualityMetric +{ +public: + // W = |T-T'|^2, where T'= |T|*I/sqrt(2). + virtual double EvalW(const DenseMatrix &Jpt) const; + + virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const + { MFEM_ABORT("Not implemented"); } + + virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS, + const double weight, DenseMatrix &A) const + { MFEM_ABORT("Not implemented"); } +}; + /// Untangling metric, 2D class TMOP_Metric_211 : public TMOP_QualityMetric { diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 36996efaac..608a91ca26 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -37,7 +37,7 @@ // Adapted analytic size+orientation: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Adapted analytic shape+orientation: -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // // Adapted discrete size: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 @@ -47,7 +47,7 @@ // Adapted discrete size+orientation (requires GSLIB): // * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect-ratio+orientation (requires GSLIB): -// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 +// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect ratio (3D): // mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // @@ -318,7 +318,7 @@ int main(int argc, char *argv[]) case 56: metric = new TMOP_Metric_056; break; case 58: metric = new TMOP_Metric_058; break; case 77: metric = new TMOP_Metric_077; break; - case 87: metric = new TMOP_Metric_SS2D; break; + case 85: metric = new TMOP_Metric_085; break; case 211: metric = new TMOP_Metric_211; break; case 252: metric = new TMOP_Metric_252(tauval); break; case 301: metric = new TMOP_Metric_301; break; @@ -516,7 +516,7 @@ int main(int argc, char *argv[]) tc->SetSerialDiscreteTargetSize(size); } - if (metric_id == 87) + if (metric_id == 85) { FunctionCoefficient aspr_coeff(discrete_aspr_2d); aspr.ProjectCoefficient(aspr_coeff); diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index f710f0a2f6..765db59eb2 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -103,7 +103,7 @@ public: { Vector pos(3); T.Transform(ip, pos); - if (metric != 14 && metric != 87) + if (metric != 14 && metric != 85) { const double xc = pos(0) - 0.5, yc = pos(1) - 0.5; const double r = sqrt(xc*xc + yc*yc); @@ -131,7 +131,7 @@ public: K *= alpha_bar; } - else if (metric == 87) // Shape + Alignment + else if (metric == 85) // Shape + Alignment { Vector x = pos; double xc = x(0)-0.5, yc = x(1)-0.5; diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 7cb09d89e8..dba76c19a5 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -37,7 +37,7 @@ // Adapted analytic size+orientation: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // Adapted analytic shape+orientation: -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd // // Adapted discrete size: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 @@ -47,7 +47,7 @@ // Adapted discrete size+orientation (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 8 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect_ratio+orientation (requires GSLIB): -// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 87 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect ratio (3D): // mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // @@ -346,7 +346,7 @@ int main (int argc, char *argv[]) case 56: metric = new TMOP_Metric_056; break; case 58: metric = new TMOP_Metric_058; break; case 77: metric = new TMOP_Metric_077; break; - case 87: metric = new TMOP_Metric_SS2D; break; + case 85: metric = new TMOP_Metric_085; break; case 211: metric = new TMOP_Metric_211; break; case 252: metric = new TMOP_Metric_252(tauval); break; case 301: metric = new TMOP_Metric_301; break; @@ -553,7 +553,7 @@ int main (int argc, char *argv[]) tc->SetParDiscreteTargetSize(size); } - if (metric_id == 87) + if (metric_id == 85) { FunctionCoefficient aspr_coeff(discrete_aspr_2d); aspr.ProjectCoefficient(aspr_coeff); From 6fc9562ae45195eec6b555d97f6d82c4a7b32d8a Mon Sep 17 00:00:00 2001 From: Tomov Date: Mon, 8 Jun 2020 17:21:15 -0700 Subject: [PATCH 472/535] Minor. --- miniapps/meshing/mesh-optimizer.cpp | 4 ++-- miniapps/meshing/pmesh-optimizer.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 608a91ca26..4230e43360 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -52,9 +52,9 @@ // mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // // Adaptive limiting: -// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 +// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 // Adaptive limiting through the L-BFGS solver: -// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -ae 1 -st 1 +// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -st 1 // Adaptive limiting through FD (requires GSLIB): // * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index dba76c19a5..5a4ad11ef7 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -52,9 +52,9 @@ // mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 // // Adaptive limiting: -// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -ae 0 +// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 // Adaptive limiting through the L-BFGS solver: -// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -ae 1 -st 1 +// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -st 1 // Adaptive limiting through FD (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // From 99bcdec9edd5db48a2d1fc205c4b3f56641cb5c7 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 9 Jun 2020 09:16:22 -0700 Subject: [PATCH 473/535] Using the new GetVectorValue interface in Joule miniapp --- miniapps/electromagnetics/joule_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniapps/electromagnetics/joule_solver.cpp b/miniapps/electromagnetics/joule_solver.cpp index c0209a8803..90d4c1b8c9 100644 --- a/miniapps/electromagnetics/joule_solver.cpp +++ b/miniapps/electromagnetics/joule_solver.cpp @@ -906,7 +906,7 @@ double JouleHeatingCoefficient::Eval(ElementTransformation &T, { Vector E; double thisSigma; - E_gf.GetVectorValue(T.ElementNo, ip, E); + E_gf.GetVectorValue(T, ip, E); thisSigma = sigma.Eval(T, ip); return thisSigma*(E*E); } From 635ac55e77c50eeb1b561b4a4c178482f96e9cfd Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 9 Jun 2020 09:41:44 -0700 Subject: [PATCH 474/535] Creating Doxygen group for compound coefficient --- fem/coefficient.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 9b4ad02f34..49131b2cb5 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -852,8 +852,8 @@ public: const IntegrationPoint &ip); }; -/// Coefficients based on sums and products of other coefficients - +/// Coefficients based on sums, products, or other functions of coefficients. +///@{ /** Scalar coefficient defined as the linear combination of two scalar coefficients or a scalar and a scalar coefficient */ class SumCoefficient : public Coefficient @@ -1421,7 +1421,7 @@ public: virtual void Eval(DenseMatrix &M, ElementTransformation &T, const IntegrationPoint &ip); }; - +///@} class QuadratureFunction; From f34493eb0d8161432763513c994aa66b92cab8f9 Mon Sep 17 00:00:00 2001 From: Tomov Date: Tue, 9 Jun 2020 10:35:15 -0700 Subject: [PATCH 475/535] Cleanup. --- miniapps/meshing/mesh-optimizer.cpp | 47 ++++++++------------------- miniapps/meshing/pmesh-optimizer.cpp | 48 +++++++--------------------- 2 files changed, 26 insertions(+), 69 deletions(-) diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 4230e43360..17af889c28 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -744,42 +744,24 @@ int main(int argc, char *argv[]) cout << "Minimum det(J) of the original mesh is " << tauval << endl; tauval -= 0.01 * h0.Min(); // Slightly below minJ0 to avoid div by 0. - // 19. Finally, perform the nonlinear optimization. - NewtonSolver *solver = NULL; + // Perform the nonlinear optimization. + TMOPNewtonSolver solver(*ir, solver_type); if (solver_type == 0) { - TMOPNewtonSolver *tns = new TMOPNewtonSolver(*ir); - solver = tns; - solver->SetPreconditioner(*S); - solver->SetMaxIter(solver_iter); - solver->SetRelTol(solver_rtol); - solver->SetAbsTol(0.0); - solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); - solver->SetOperator(a); - solver->Mult(b, x.GetTrueVector()); - if (solver->GetConverged() == false) - { - cout << "NewtonIteration: rtol = " << solver_rtol << " not achieved." - << endl; - } - } - else - { - TMOPNewtonSolver *tns = new TMOPNewtonSolver(*ir, 1); - solver = tns; - solver->SetMaxIter(solver_iter); - solver->SetRelTol(solver_rtol); - solver->SetAbsTol(0.0); - solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); - solver->SetOperator(a); - solver->Mult(b, x.GetTrueVector()); - if (solver->GetConverged() == false) - { - cout << "LBFGSIteration: rtol = " << solver_rtol << " not achieved." - << endl; - } + // Specify linear solver when we use a Newton-based solver. + solver.SetPreconditioner(*S); } + solver.SetMaxIter(solver_iter); + solver.SetRelTol(solver_rtol); + solver.SetAbsTol(0.0); + solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1); + solver.SetOperator(a); + solver.Mult(b, x.GetTrueVector()); x.SetFromTrueVector(); + if (solver.GetConverged() == false) + { + cout << "Nonlinear solver: rtol = " << solver_rtol << " not achieved.\n"; + } // 20. Save the optimized mesh to a file. This output can be viewed later // using GLVis: "glvis -m optimized.mesh". @@ -839,7 +821,6 @@ int main(int argc, char *argv[]) } // 24. Free the used memory. - delete solver; delete S; delete target_c2; delete metric2; diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 5a4ad11ef7..6c9172579f 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -792,46 +792,23 @@ int main (int argc, char *argv[]) MPI_Allreduce(&h0min, &h0min_all, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); tauval -= 0.01 * h0min_all; // Slightly below minJ0 to avoid div by 0. - // 20. Finally, perform the nonlinear optimization. - NewtonSolver *solver = NULL; + // Perform the nonlinear optimization. + TMOPNewtonSolver solver(pfespace->GetComm(), *ir, solver_type); if (solver_type == 0) { - TMOPNewtonSolver *tns = new TMOPNewtonSolver(pfespace->GetComm(), *ir); - solver = tns; - solver->SetPreconditioner(*S); - solver->SetMaxIter(solver_iter); - solver->SetRelTol(solver_rtol); - solver->SetAbsTol(0.0); - solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); - solver->SetOperator(a); - solver->Mult(b, x.GetTrueVector()); - if (solver->GetConverged() == false) - { - cout << "NewtonIteration: rtol = " << solver_rtol << " not achieved." - << endl; - } - } - else - { - TMOPNewtonSolver *tns = new TMOPNewtonSolver(pfespace->GetComm(), *ir, 1); - solver = tns; - solver->SetMaxIter(solver_iter); - solver->SetRelTol(solver_rtol); - solver->SetAbsTol(0.0); - solver->SetPrintLevel(verbosity_level >= 1 ? 1 : -1); - solver->SetOperator(a); - solver->Mult(b, x.GetTrueVector()); - if (solver->GetConverged() == false) - { - cout << "LBFGSIteration: rtol = " << solver_rtol << " not achieved." - << endl; - } + // Specify linear solver when we use a Newton-based solver. + solver.SetPreconditioner(*S); } + solver.SetMaxIter(solver_iter); + solver.SetRelTol(solver_rtol); + solver.SetAbsTol(0.0); + solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1); + solver.SetOperator(a); + solver.Mult(b, x.GetTrueVector()); x.SetFromTrueVector(); - if (myid == 0 && solver->GetConverged() == false) + if (myid == 0 && solver.GetConverged() == false) { - cout << "NewtonIteration: rtol = " << solver_rtol << " not achieved." - << endl; + cout << "Nonlinear solver: rtol = " << solver_rtol << " not achieved.\n"; } // 21. Save the optimized mesh to a file. This output can be viewed later @@ -903,7 +880,6 @@ int main (int argc, char *argv[]) } // 24. Free the used memory. - delete solver; delete S; delete target_c2; delete metric2; From f58decb4215d104c9f51b0f8f6d3819e3ff55f94 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 9 Jun 2020 13:51:46 -0700 Subject: [PATCH 476/535] Adding Doxygen comments for the new accessor methods --- fem/coefficient.hpp | 109 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 49131b2cb5..55e8ebbf30 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -877,19 +877,29 @@ public: double _alpha = 1.0, double _beta = 1.0) : aConst(0.0), a(&A), b(&B), alpha(_alpha), beta(_beta) { } + /// Reset the first term in the linear combination as a constant void SetAConst(double A) { a = NULL; aConst = A; } + /// Return the first term in the linear combination double GetAConst() const { return aConst; } + /// Reset the first term in the linear combination void SetACoef(Coefficient &A) { a = &A; } + /// Return the first term in the linear combination Coefficient * GetACoef() const { return a; } + /// Reset the second term in the linear combination void SetBCoef(Coefficient &B) { b = &B; } + /// Return the second term in the linear combination Coefficient * GetBCoef() const { return b; } + /// Reset the factor in front of the first term in the linear combination void SetAlpha(double _alpha) { alpha = _alpha; } + /// Return the factor in front of the first term in the linear combination double GetAlpha() const { return alpha; } + /// Reset the factor in front of the second term in the linear combination void SetBeta(double _beta) { beta = _beta; } + /// Return the factor in front of the second term in the linear combination double GetBeta() const { return beta; } /// Evaluate the coefficient at @a ip. @@ -919,13 +929,19 @@ public: ProductCoefficient(Coefficient &A, Coefficient &B) : aConst(0.0), a(&A), b(&B) { } + /// Reset the first term in the product as a constant void SetAConst(double A) { a = NULL; aConst = A; } + /// Return the first term in the product double GetAConst() const { return aConst; } + /// Reset the first term in the product void SetACoef(Coefficient &A) { a = &A; } + /// Return the first term in the product Coefficient * GetACoef() const { return a; } + /// Reset the second term in the product void SetBCoef(Coefficient &B) { b = &B; } + /// Return the second term in the product Coefficient * GetBCoef() const { return b; } /// Evaluate the coefficient at @a ip. @@ -958,16 +974,24 @@ public: RatioCoefficient(Coefficient &A, double B) : aConst(0.0), bConst(B), a(&A), b(NULL) { } + /// Reset the numerator in the ratio as a constant void SetAConst(double A) { a = NULL; aConst = A; } + /// Return the numerator of the ratio double GetAConst() const { return aConst; } + /// Reset the denominator in the ratio as a constant void SetBConst(double B) { b = NULL; bConst = B; } + /// Return the denominator of the ratio double GetBConst() const { return bConst; } + /// Reset the numerator in the ratio void SetACoef(Coefficient &A) { a = &A; } + /// Return the numerator of the ratio Coefficient * GetACoef() const { return a; } + /// Reset the denominator in the ratio void SetBCoef(Coefficient &B) { b = &B; } + /// Return the denominator of the ratio Coefficient * GetBCoef() const { return b; } /// Evaluate the coefficient @@ -993,10 +1017,14 @@ public: PowerCoefficient(Coefficient &A, double _p) : a(&A), p(_p) { } + /// Reset the base coefficient void SetACoef(Coefficient &A) { a = &A; } + /// Return the base coefficient Coefficient * GetACoef() const { return a; } + /// Reset the exponent void SetExponent(double _p) { p = _p; } + /// Return the exponent double GetExponent() const { return p; } /// Evaluate the coefficient at @a ip. @@ -1019,10 +1047,14 @@ public: /// Construct with the two vector coefficients. Result is \f$ A \cdot B \f$. InnerProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Reset the first vector in the inner product void SetACoef(VectorCoefficient &A) { a = &A; } + /// Return the first vector coefficient in the inner product VectorCoefficient * GetACoef() const { return a; } + /// Reset the second vector in the inner product void SetBCoef(VectorCoefficient &B) { b = &B; } + /// Return the second vector coefficient in the inner product VectorCoefficient * GetBCoef() const { return b; } /// Evaluate the coefficient at @a ip. @@ -1044,10 +1076,14 @@ public: /// Constructor with two vector coefficients. Result is \f$ A_x B_y - A_y * B_x; \f$. VectorRotProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Reset the first vector in the product void SetACoef(VectorCoefficient &A) { a = &A; } + /// Return the first vector of the product VectorCoefficient * GetACoef() const { return a; } + /// Reset the second vector in the product void SetBCoef(VectorCoefficient &B) { b = &B; } + /// Return the second vector of the product VectorCoefficient * GetBCoef() const { return b; } /// Evaluate the coefficient at @a ip. @@ -1067,7 +1103,9 @@ public: /// Construct with the matrix. DeterminantCoefficient(MatrixCoefficient &A); + /// Reset the matrix coefficient void SetACoef(MatrixCoefficient &A) { a = &A; } + /// Return the matrix coefficient MatrixCoefficient * GetACoef() const { return a; } /// Evaluate the determinant coefficient at @a ip. @@ -1094,39 +1132,58 @@ private: mutable Vector va; public: - /// Constructor with no coefficients. To be used with the various "Set" methods + /** Constructor with no coefficients. + To be used with the various "Set" methods */ VectorSumCoefficient(int dim); - /// Constructor with two vector coefficients. Result is _alpha * A + _beta * B + /** Constructor with two vector coefficients. + Result is _alpha * A + _beta * B */ VectorSumCoefficient(VectorCoefficient &A, VectorCoefficient &B, double _alpha = 1.0, double _beta = 1.0); - /// Constructor with scalar coefficients. Result is _alpha * _A + _beta * _B + /** Constructor with scalar coefficients. + Result is _alpha * _A + _beta * _B */ VectorSumCoefficient(VectorCoefficient &_A, VectorCoefficient &_B, Coefficient &_alpha, Coefficient &_beta); + /// Reset the first vector coefficient void SetACoef(VectorCoefficient &A) { ACoef = &A; } + /// Return the first vector coefficient VectorCoefficient * GetACoef() const { return ACoef; } + /// Reset the second vector coefficient void SetBCoef(VectorCoefficient &B) { BCoef = &B; } + /// Return the second vector coefficient VectorCoefficient * GetBCoef() const { return BCoef; } + /// Reset the factor in front of the first vector coefficient void SetAlphaCoef(Coefficient &A) { alphaCoef = &A; } + /// Return the factor in front of the first vector coefficient Coefficient * GetAlphaCoef() const { return alphaCoef; } + /// Reset the factor in front of the second vector coefficient void SetBetaCoef(Coefficient &B) { betaCoef = &B; } + /// Return the factor in front of the second vector coefficient Coefficient * GetBetaCoef() const { return betaCoef; } + /// Reset the first vector as a constant void SetA(const Vector &_A) { A = _A; ACoef = NULL; } + /// Return the first vector constant const Vector & GetA() const { return A; } + /// Reset the second vector as a constant void SetB(const Vector &_B) { B = _B; BCoef = NULL; } + /// Return the second vector constant const Vector & GetB() const { return B; } + /// Reset the factor in front of the first vector coefficient as a constant void SetAlpha(double _alpha) { alpha = _alpha; alphaCoef = NULL; } + /// Return the factor in front of the first vector coefficient double GetAlpha() const { return alpha; } + /// Reset the factor in front of the second vector coefficient as a constant void SetBeta(double _beta) { beta = _beta; betaCoef = NULL; } + /// Return the factor in front of the second vector coefficient double GetBeta() const { return beta; } /// Evaluate the coefficient at @a ip. @@ -1150,16 +1207,22 @@ public: /// Constructor with two coefficients. Result is A * B. ScalarVectorProductCoefficient(Coefficient &A, VectorCoefficient &B); - + /// Reset the scalar factor as a constant void SetAConst(double A) { a = NULL; aConst = A; } + /// Return the scalar factor double GetAConst() const { return aConst; } + /// Reset the scalar factor void SetACoef(Coefficient &A) { a = &A; } + /// Return the scalar factor Coefficient * GetACoef() const { return a; } + /// Reset the vector factor void SetBCoef(VectorCoefficient &B) { b = &B; } + /// Return the vector factor VectorCoefficient * GetBCoef() const { return b; } + /// Evaluate the coefficient at @a ip. virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip); using VectorCoefficient::Eval; @@ -1182,7 +1245,9 @@ public: */ NormalizedVectorCoefficient(VectorCoefficient &A, double tol = 1e-6); + /// Reset the vector coefficient void SetACoef(VectorCoefficient &A) { a = &A; } + /// Return the vector coefficient VectorCoefficient * GetACoef() const { return a; } /// Evaluate the coefficient at @a ip. @@ -1205,10 +1270,14 @@ public: /// Construct with the two coefficients. Result is A x B. VectorCrossProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Reset the first term in the product void SetACoef(VectorCoefficient &A) { a = &A; } + /// Return the first term in the product VectorCoefficient * GetACoef() const { return a; } + /// Reset the second term in the product void SetBCoef(VectorCoefficient &B) { b = &B; } + /// Return the second term in the product VectorCoefficient * GetBCoef() const { return b; } /// Evaluate the coefficient at @a ip. @@ -1232,10 +1301,14 @@ public: /// Constructor with two coefficients. Result is A*B. MatrixVectorProductCoefficient(MatrixCoefficient &A, VectorCoefficient &B); + /// Reset the matrix coefficient void SetACoef(MatrixCoefficient &A) { a = &A; } + /// Return the matrix coefficient MatrixCoefficient * GetACoef() const { return a; } + /// Reset the vector coefficient void SetBCoef(VectorCoefficient &B) { b = &B; } + /// Return the vector coefficient VectorCoefficient * GetBCoef() const { return b; } /// Evaluate the vector coefficient at @a ip. @@ -1280,16 +1353,24 @@ public: MatrixSumCoefficient(MatrixCoefficient &A, MatrixCoefficient &B, double _alpha = 1.0, double _beta = 1.0); + /// Reset the first matrix coefficient void SetACoef(MatrixCoefficient &A) { a = &A; } + /// Return the first matrix coefficient MatrixCoefficient * GetACoef() const { return a; } + /// Reset the second matrix coefficient void SetBCoef(MatrixCoefficient &B) { b = &B; } + /// Return the second matrix coefficient MatrixCoefficient * GetBCoef() const { return b; } + /// Reset the factor in front of the first matrix coefficient void SetAlpha(double _alpha) { alpha = _alpha; } + /// Return the factor in front of the first matrix coefficient double GetAlpha() const { return alpha; } + /// Reset the factor in front of the second matrix coefficient void SetBeta(double _beta) { beta = _beta; } + /// Return the factor in front of the second matrix coefficient double GetBeta() const { return beta; } /// Evaluate the matrix coefficient at @a ip. @@ -1313,13 +1394,19 @@ public: /// Constructor with two coefficients. Result is A*B. ScalarMatrixProductCoefficient(Coefficient &A, MatrixCoefficient &B); + /// Reset the scalar factor as a constant void SetAConst(double A) { a = NULL; aConst = A; } + /// Return the scalar factor double GetAConst() const { return aConst; } + /// Reset the scalar factor void SetACoef(Coefficient &A) { a = &A; } + /// Return the scalar factor Coefficient * GetACoef() const { return a; } + /// Reset the matrix factor void SetBCoef(MatrixCoefficient &B) { b = &B; } + /// Return the matrix factor MatrixCoefficient * GetBCoef() const { return b; } /// Evaluate the matrix coefficient at @a ip. @@ -1337,7 +1424,9 @@ public: /// Construct with the matrix coefficient. Result is \f$ A^T \f$. TransposeMatrixCoefficient(MatrixCoefficient &A); + /// Reset the matrix coefficient void SetACoef(MatrixCoefficient &A) { a = &A; } + /// Return the matrix coefficient MatrixCoefficient * GetACoef() const { return a; } /// Evaluate the matrix coefficient at @a ip. @@ -1355,7 +1444,9 @@ public: /// Construct with the matrix coefficient. Result is \f$ A^{-1} \f$. InverseMatrixCoefficient(MatrixCoefficient &A); + /// Reset the matrix coefficient void SetACoef(MatrixCoefficient &A) { a = &A; } + /// Return the matrix coefficient MatrixCoefficient * GetACoef() const { return a; } /// Evaluate the matrix coefficient at @a ip. @@ -1377,10 +1468,14 @@ public: /// Construct with two vector coefficients. Result is \f$ A B^T \f$. OuterProductCoefficient(VectorCoefficient &A, VectorCoefficient &B); + /// Reset the first vector in the outer product void SetACoef(VectorCoefficient &A) { a = &A; } + /// Return the first vector coefficient in the outer product VectorCoefficient * GetACoef() const { return a; } + /// Reset the second vector in the outer product void SetBCoef(VectorCoefficient &B) { b = &B; } + /// Return the second vector coefficient in the outer product VectorCoefficient * GetBCoef() const { return b; } /// Evaluate the matrix coefficient at @a ip. @@ -1408,13 +1503,19 @@ public: CrossCrossCoefficient(double A, VectorCoefficient &K); CrossCrossCoefficient(Coefficient &A, VectorCoefficient &K); + /// Reset the scalar factor as a constant void SetAConst(double A) { a = NULL; aConst = A; } + /// Return the scalar factor double GetAConst() const { return aConst; } + /// Reset the scalar factor void SetACoef(Coefficient &A) { a = &A; } + /// Return the scalar factor Coefficient * GetACoef() const { return a; } + /// Reset the vector factor void SetKCoef(VectorCoefficient &K) { k = &K; } + /// Return the vector factor VectorCoefficient * GetKCoef() const { return k; } /// Evaluate the matrix coefficient at @a ip. From 23078ff76ca9cfc45bed770bc08ad006a7d85a0f Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 9 Jun 2020 14:32:42 -0700 Subject: [PATCH 477/535] In tests/unit/fem/test_get_value.cpp, add constexpr to some 'dim' variables to avoid the use VLAs -- this generated warnings when building with -pedantic flag. --- tests/unit/fem/test_get_value.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index af225bb675..2432d11520 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -287,7 +287,7 @@ TEST_CASE("2D GetValue", { int log = 1; int n = 1; - int dim = 2; + constexpr int dim = 2; int order = 1; int npts = 0; @@ -560,7 +560,7 @@ TEST_CASE("3D GetValue", { int log = 1; int n = 1; - int dim = 3; + constexpr int dim = 3; int order = 1; int npts = 0; @@ -872,7 +872,7 @@ TEST_CASE("2D GetVectorValue", { int log = 1; int n = 1; - int dim = 2; + constexpr int dim = 2; int order = 1; int npts = 0; @@ -1312,7 +1312,7 @@ TEST_CASE("3D GetVectorValue", { int log = 1; int n = 1; - int dim = 3; + constexpr int dim = 3; int order = 1; int npts = 0; From 27f720ac20849e7806c7a2ed287468496f571e51 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 9 Jun 2020 15:07:45 -0700 Subject: [PATCH 478/535] Removing unneeded calls to ExchangeFaceNbrData and decreasing parallel mesh sizes --- tests/unit/fem/test_get_value.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 9b01c1e3e6..1d980f5191 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -1855,7 +1855,6 @@ TEST_CASE("1D GetValue in Parallel", { Mesh *mesh = new Mesh(n, 2.0); ParMesh pmesh(MPI_COMM_WORLD, *mesh); - pmesh.ExchangeFaceNbrData(); delete mesh; FunctionCoefficient linCoef(func_1D_lin); @@ -1870,9 +1869,6 @@ TEST_CASE("1D GetValue in Parallel", ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); - dgv_fespace.ExchangeFaceNbrData(); - dgi_fespace.ExchangeFaceNbrData(); - ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); @@ -1959,7 +1955,7 @@ TEST_CASE("2D GetValue in Parallel", MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); int log = 1; - int n = 2 * num_procs; + int n = num_procs; int dim = 2; int order = 1; int npts = 0; @@ -1971,7 +1967,6 @@ TEST_CASE("2D GetValue in Parallel", { Mesh *mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); ParMesh pmesh(MPI_COMM_WORLD, *mesh); - pmesh.ExchangeFaceNbrData(); delete mesh; FunctionCoefficient linCoef(func_2D_lin); @@ -1986,9 +1981,6 @@ TEST_CASE("2D GetValue in Parallel", ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); - dgv_fespace.ExchangeFaceNbrData(); - dgi_fespace.ExchangeFaceNbrData(); - ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); @@ -2075,7 +2067,7 @@ TEST_CASE("3D GetValue in Parallel", MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); int log = 1; - int n = 2 * num_procs; + int n = num_procs; int dim = 3; int order = 1; int npts = 0; @@ -2087,7 +2079,6 @@ TEST_CASE("3D GetValue in Parallel", { Mesh *mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); ParMesh pmesh(MPI_COMM_WORLD, *mesh); - pmesh.ExchangeFaceNbrData(); delete mesh; FunctionCoefficient linCoef(func_3D_lin); @@ -2102,9 +2093,6 @@ TEST_CASE("3D GetValue in Parallel", ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); - dgv_fespace.ExchangeFaceNbrData(); - dgi_fespace.ExchangeFaceNbrData(); - ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); From cebce14371be6e03d52eb3e5e7d6e984e7feae93 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 9 Jun 2020 15:18:36 -0700 Subject: [PATCH 479/535] Further reducing the mesh size in 2D and 3D. --- tests/unit/fem/test_get_value.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 1d980f5191..ae889f36a8 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -1955,7 +1955,7 @@ TEST_CASE("2D GetValue in Parallel", MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); int log = 1; - int n = num_procs; + int n = (int)ceil(sqrt(2*num_procs)); int dim = 2; int order = 1; int npts = 0; @@ -2067,7 +2067,7 @@ TEST_CASE("3D GetValue in Parallel", MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); int log = 1; - int n = num_procs; + int n = (int)ceil(pow(2*num_procs, 1.0 / 3.0)); int dim = 3; int order = 1; int npts = 0; From 39f26a201f7ab1de61f2d4abd1605ac06b283176 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Tue, 9 Jun 2020 15:18:50 -0700 Subject: [PATCH 480/535] Bugfix in unit test --- tests/unit/fem/test_get_value.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index ae889f36a8..2f3d57dacb 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -2117,7 +2117,7 @@ TEST_CASE("3D GetValue in Parallel", pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); int e = FET->Elem2No; - const FiniteElement *fe = dgv_fespace.GetFE(e); + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); From 4e235c421a34f92248de7d6bd1f23e5741b5cd63 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 9 Jun 2020 20:14:16 -0700 Subject: [PATCH 481/535] Fix a bug/typo in tests/unit/fem/test_get_value.cpp --- tests/unit/fem/test_get_value.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 2432d11520..76eccc3e02 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -531,7 +531,7 @@ TEST_CASE("2D GetValue", T->SetIntPoint(&ip); T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + double f_val = func_2D_lin(tip); double h1_gf_val = h1_xCoef.Eval(*T, ip); h1_err += fabs(f_val - h1_gf_val); From 86178916e7954ccdc194102f15663671844a82b6 Mon Sep 17 00:00:00 2001 From: Dylan Copeland Date: Wed, 10 Jun 2020 15:05:38 -0700 Subject: [PATCH 482/535] Adding checks for whether big_j is used. --- linalg/hypre.cpp | 11 +++++++---- linalg/superlu.cpp | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index 3edd15dcd4..20489f7c36 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1858,9 +1858,9 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, MFEM_ASSERT(parcsr_op != NULL, "const_cast failed"); csr_blocks(i, j) = hypre_MergeDiagAndOffd(parcsr_op); #if MFEM_HYPRE_VERSION >= 21600 - MFEM_VERIFY(csr_blocks(i, j)->num_rows < INT_MAX,"Number of " - "local rows is too large to store as an integer."); - hypre_CSRMatrixBigJtoJ(csr_blocks(i, j)); + MFEM_VERIFY(csr_blocks(i, j)->big_j != NULL || + csr_blocks(i, j)->num_cols < INT_MAX,"Number of " + "columns is too large to store as an integer."); #endif } @@ -1894,6 +1894,8 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, const int nrows = csr_blocks(i, j)->num_rows; const double cij = blockCoeff ? (*blockCoeff)(i, j) : 1.0; + const bool usingBigJ = (csr_blocks(i, j)->big_j != NULL); + for (int k = 0; k < nrows; ++k) { const int rowg = rowOffsets[i] + k; // process-local row @@ -1903,7 +1905,8 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, for (int l = 0; l < nnz_k; ++l) { // Find the column process offset for the block. - const int bcol = csr_blocks(i, j)->j[osk + l]; + const int bcol = usingBigJ ? csr_blocks(i, j)->big_j[osk + l] + : csr_blocks(i, j)->j[osk + l]; int bcolproc = 0; for (int p = 1; p < nprocs; ++p) diff --git a/linalg/superlu.cpp b/linalg/superlu.cpp index a22cbe64e1..bb6b438275 100644 --- a/linalg/superlu.cpp +++ b/linalg/superlu.cpp @@ -135,8 +135,8 @@ SuperLURowLocMatrix::SuperLURowLocMatrix( const HypreParMatrix & hypParMat ) hypre_CSRMatrix * csr_op = hypre_MergeDiagAndOffd(parcsr_op); hypre_CSRMatrixSetDataOwner(csr_op,0); #if MFEM_HYPRE_VERSION >= 21600 - MFEM_VERIFY(csr_op->num_rows < INT_MAX,"SuperLU: number of local rows " - "is too large to store as an integer."); + MFEM_VERIFY(csr_blocks(i, j)->big_j != NULL || csr_op->num_cols < INT_MAX, + "SuperLU: number of columns is too large to store as an integer."); hypre_CSRMatrixBigJtoJ(csr_op); #endif From 5aa36b19de9b83deec02592a253161b1f3977af5 Mon Sep 17 00:00:00 2001 From: Dylan Copeland Date: Wed, 10 Jun 2020 15:30:26 -0700 Subject: [PATCH 483/535] Adding hypre version checks. --- linalg/hypre.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index 20489f7c36..7ddc8ffdda 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1893,8 +1893,9 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, { const int nrows = csr_blocks(i, j)->num_rows; const double cij = blockCoeff ? (*blockCoeff)(i, j) : 1.0; - +#if MFEM_HYPRE_VERSION >= 21600 const bool usingBigJ = (csr_blocks(i, j)->big_j != NULL); +#endif for (int k = 0; k < nrows; ++k) { @@ -1905,8 +1906,12 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, for (int l = 0; l < nnz_k; ++l) { // Find the column process offset for the block. +#if MFEM_HYPRE_VERSION >= 21600 const int bcol = usingBigJ ? csr_blocks(i, j)->big_j[osk + l] : csr_blocks(i, j)->j[osk + l]; +#else + const int bcol = csr_blocks(i, j)->j[osk + l]; +#endif int bcolproc = 0; for (int p = 1; p < nprocs; ++p) From 8ad33458e189360ea7bc562e6b2d0362d1d887ef Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 10 Jun 2020 16:02:58 -0700 Subject: [PATCH 484/535] Setting configuration mask for FaceElementTransformations in GetSharedFaceTransformations --- mesh/pmesh.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index f6f902e8b6..87a266a0d0 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2404,6 +2404,11 @@ GetSharedFaceTransformations(int sf, bool fill2) bool is_slave = Nonconforming() && IsSlaveFace(face_info); bool is_ghost = Nonconforming() && FaceNo >= GetNumFaces(); + int mask = 0; + FaceElemTr.SetConfigurationMask(0); + FaceElemTr.Elem1 = NULL; + FaceElemTr.Elem2 = NULL; + NCFaceInfo* nc_info = NULL; if (is_slave) { nc_info = &nc_faces_info[face_info.NCFace]; } @@ -2415,6 +2420,7 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem1No = face_info.Elem1No; GetElementTransformation(FaceElemTr.Elem1No, &Transformation); FaceElemTr.Elem1 = &Transformation; + mask += 1; // setup the transformation for the second (neighbor) element if (fill2) @@ -2422,6 +2428,7 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem2No = -1 - face_info.Elem2No; GetFaceNbrElementTransformation(FaceElemTr.Elem2No, &Transformation2); FaceElemTr.Elem2 = &Transformation2; + mask += 2; } else { @@ -2433,6 +2440,7 @@ GetSharedFaceTransformations(int sf, bool fill2) { GetFaceTransformation(FaceNo, &FaceElemTr); // NOTE: The above call overwrites FaceElemTr.Loc1 + mask += 16; } else { @@ -2443,12 +2451,14 @@ GetSharedFaceTransformations(int sf, bool fill2) int elem_type = GetElementType(face_info.Elem1No); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc1.Transf, face_info.Elem1Inf); + mask += 4; if (fill2) { elem_type = face_nbr_elements[FaceElemTr.Elem2No]->GetType(); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc2.Transf, face_info.Elem2Inf); + mask += 8; } // adjust Loc1 or Loc2 of the master face if this is a slave face @@ -2479,6 +2489,8 @@ GetSharedFaceTransformations(int sf, bool fill2) GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); } + FaceElemTr.SetConfigurationMask(mask); + return &FaceElemTr; } From 371a5cc714533d838a4e43920419030658237eb7 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 10 Jun 2020 16:18:53 -0700 Subject: [PATCH 485/535] Changing function calls to coefficient evaluations --- tests/unit/fem/test_get_value.cpp | 162 ++++++------------------------ 1 file changed, 30 insertions(+), 132 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 2f3d57dacb..29c7912900 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -53,7 +53,7 @@ TEST_CASE("1D GetValue", { int log = 1; int n = 1; - int dim = 1; + const int dim = 1; int order = 1; int npts = 0; @@ -104,17 +104,13 @@ TEST_CASE("1D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_1D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -166,16 +162,13 @@ TEST_CASE("1D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[1]; - Vector tip(tip_data, 1); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - double f_val = func_1D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -227,18 +220,14 @@ TEST_CASE("1D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[1]; - Vector tip(tip_data, 1); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_1D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -338,17 +327,13 @@ TEST_CASE("2D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_2D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -400,16 +385,13 @@ TEST_CASE("2D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - double f_val = func_2D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -461,18 +443,14 @@ TEST_CASE("2D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_2D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -522,16 +500,13 @@ TEST_CASE("2D GetValue", double h1_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); h1_err += fabs(f_val - h1_gf_val); @@ -611,17 +586,13 @@ TEST_CASE("3D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -673,16 +644,13 @@ TEST_CASE("3D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -734,18 +702,14 @@ TEST_CASE("3D GetValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -795,16 +759,13 @@ TEST_CASE("3D GetValue", double h1_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); h1_err += fabs(f_val - h1_gf_val); @@ -834,16 +795,13 @@ TEST_CASE("3D GetValue", double h1_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double h1_gf_val = h1_xCoef.Eval(*T, ip); h1_err += fabs(f_val - h1_gf_val); @@ -950,17 +908,13 @@ TEST_CASE("2D GetVectorValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_2D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); nd_xCoef.Eval(nd_gf_val, *T, ip); rt_xCoef.Eval(rt_gf_val, *T, ip); @@ -1058,17 +1012,13 @@ TEST_CASE("2D GetVectorValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_2D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); nd_xCoef.Eval(nd_gf_val, *T, ip); rt_xCoef.Eval(rt_gf_val, *T, ip); @@ -1166,18 +1116,14 @@ TEST_CASE("2D GetVectorValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_2D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); nd_xCoef.Eval(nd_gf_val, *T, ip); rt_xCoef.Eval(rt_gf_val, *T, ip); @@ -1270,17 +1216,13 @@ TEST_CASE("2D GetVectorValue", double h1_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_2D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); double h1_dist = Distance(f_val, h1_gf_val, 2); @@ -1390,17 +1332,13 @@ TEST_CASE("3D GetVectorValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); nd_xCoef.Eval(nd_gf_val, *T, ip); rt_xCoef.Eval(rt_gf_val, *T, ip); @@ -1510,17 +1448,13 @@ TEST_CASE("3D GetVectorValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); nd_xCoef.Eval(nd_gf_val, *T, ip); rt_xCoef.Eval(rt_gf_val, *T, ip); @@ -1630,18 +1564,14 @@ TEST_CASE("3D GetVectorValue", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); nd_xCoef.Eval(nd_gf_val, *T, ip); rt_xCoef.Eval(rt_gf_val, *T, ip); @@ -1746,17 +1676,13 @@ TEST_CASE("3D GetVectorValue", double h1_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); double h1_dist = Distance(f_val, h1_gf_val, dim); @@ -1791,17 +1717,13 @@ TEST_CASE("3D GetVectorValue", double h1_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); h1_xCoef.Eval(h1_gf_val, *T, ip); double h1_dist = Distance(f_val, h1_gf_val, dim); @@ -1844,7 +1766,7 @@ TEST_CASE("1D GetValue in Parallel", int log = 1; int n = 2 * num_procs; - int dim = 1; + const int dim = 1; int order = 1; int npts = 0; @@ -1900,16 +1822,11 @@ TEST_CASE("1D GetValue in Parallel", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_1D_lin(tip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -1956,7 +1873,7 @@ TEST_CASE("2D GetValue in Parallel", int log = 1; int n = (int)ceil(sqrt(2*num_procs)); - int dim = 2; + const int dim = 2; int order = 1; int npts = 0; @@ -2012,16 +1929,11 @@ TEST_CASE("2D GetValue in Parallel", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_2D_lin(tip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -2125,17 +2037,13 @@ TEST_CASE("3D GetValue in Parallel", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - double f_val = func_3D_lin(tip); + double f_val = linCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); @@ -2180,8 +2088,8 @@ TEST_CASE("2D GetVectorValue in Parallel", MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); int log = 1; - int n = 2 * num_procs; - int dim = 2; + int n = (int)ceil(sqrt(2*num_procs)); + const int dim = 2; int order = 1; int npts = 0; @@ -2192,7 +2100,6 @@ TEST_CASE("2D GetVectorValue in Parallel", { Mesh *mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); ParMesh pmesh(MPI_COMM_WORLD, *mesh); - pmesh.ExchangeFaceNbrData(); delete mesh; VectorFunctionCoefficient linCoef(dim, Func_2D_lin); @@ -2246,16 +2153,11 @@ TEST_CASE("2D GetVectorValue in Parallel", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_2D_lin(tip, f_val); dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); @@ -2372,22 +2274,18 @@ TEST_CASE("3D GetVectorValue in Parallel", double dgv_err = 0.0; double dgi_err = 0.0; - double tip_data[dim]; - Vector tip(tip_data, dim); for (int j=0; jSetIntPoint(&ip); - T->Transform(ip, tip); - - Func_3D_lin(tip, f_val); + linCoef.Eval(f_val, *T, ip); dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double dgv_dist = Distance(f_val, dgv_gf_val, 2); - double dgi_dist = Distance(f_val, dgi_gf_val, 2); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double dgi_dist = Distance(f_val, dgi_gf_val, dim); dgv_err += dgv_dist; dgi_err += dgi_dist; From defc3378c6e15279b168de2282546062adfe45d3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Wed, 10 Jun 2020 16:36:04 -0700 Subject: [PATCH 486/535] Expanding GetVectorValue tests in parallel --- tests/unit/fem/test_get_value.cpp | 305 ++++++++++++++++++++++++++---- 1 file changed, 270 insertions(+), 35 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 29c7912900..847935dcf5 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -53,7 +53,7 @@ TEST_CASE("1D GetValue", { int log = 1; int n = 1; - const int dim = 1; + int dim = 1; int order = 1; int npts = 0; @@ -922,12 +922,12 @@ TEST_CASE("2D GetVectorValue", dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2); - double nd_dist = Distance(f_val, nd_gf_val, 2); - double rt_dist = Distance(f_val, rt_gf_val, 2); - double l2_dist = Distance(f_val, l2_gf_val, 2); - double dgv_dist = Distance(f_val, dgv_gf_val, 2); - double dgi_dist = Distance(f_val, dgi_gf_val, 2); + double h1_dist = Distance(f_val, h1_gf_val, dim); + double nd_dist = Distance(f_val, nd_gf_val, dim); + double rt_dist = Distance(f_val, rt_gf_val, dim); + double l2_dist = Distance(f_val, l2_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double dgi_dist = Distance(f_val, dgi_gf_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -1026,12 +1026,12 @@ TEST_CASE("2D GetVectorValue", dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2); - double nd_dist = Distance(f_val, nd_gf_val, 2); - double rt_dist = Distance(f_val, rt_gf_val, 2); - double l2_dist = Distance(f_val, l2_gf_val, 2); - double dgv_dist = Distance(f_val, dgv_gf_val, 2); - double dgi_dist = Distance(f_val, dgi_gf_val, 2); + double h1_dist = Distance(f_val, h1_gf_val, dim); + double nd_dist = Distance(f_val, nd_gf_val, dim); + double rt_dist = Distance(f_val, rt_gf_val, dim); + double l2_dist = Distance(f_val, l2_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double dgi_dist = Distance(f_val, dgi_gf_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -1131,12 +1131,12 @@ TEST_CASE("2D GetVectorValue", dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2); - double nd_dist = Distance(f_val, nd_gf_val, 2); - double rt_dist = Distance(f_val, rt_gf_val, 2); - double l2_dist = Distance(f_val, l2_gf_val, 2); - double dgv_dist = Distance(f_val, dgv_gf_val, 2); - double dgi_dist = Distance(f_val, dgi_gf_val, 2); + double h1_dist = Distance(f_val, h1_gf_val, dim); + double nd_dist = Distance(f_val, nd_gf_val, dim); + double rt_dist = Distance(f_val, rt_gf_val, dim); + double l2_dist = Distance(f_val, l2_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double dgi_dist = Distance(f_val, dgi_gf_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -1766,7 +1766,7 @@ TEST_CASE("1D GetValue in Parallel", int log = 1; int n = 2 * num_procs; - const int dim = 1; + int dim = 1; int order = 1; int npts = 0; @@ -1783,23 +1783,29 @@ TEST_CASE("1D GetValue in Parallel", SECTION("1D GetValue tests for element type " + std::to_string(type)) { + H1_FECollection h1_fec(order, dim); DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, FiniteElement::VALUE); DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, FiniteElement::INTEGRAL); + ParFiniteElementSpace h1_fespace(&pmesh, &h1_fec); ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); + ParGridFunction h1_x(&h1_fespace); ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); + GridFunctionCoefficient h1_xCoef(&h1_x); GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); + h1_x.ProjectCoefficient(linCoef); dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); + h1_x.ExchangeFaceNbrData(); dgv_x.ExchangeFaceNbrData(); dgi_x.ExchangeFaceNbrData(); @@ -1819,6 +1825,7 @@ TEST_CASE("1D GetValue in Parallel", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); + double h1_err = 0.0; double dgv_err = 0.0; double dgi_err = 0.0; @@ -1828,12 +1835,21 @@ TEST_CASE("1D GetValue in Parallel", const IntegrationPoint &ip = ir.IntPoint(j); T->SetIntPoint(&ip); + double f_val = linCoef.Eval(*T, ip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + h1_err += fabs(f_val - h1_gf_val); dgv_err += fabs(f_val - dgv_gf_val); dgi_err += fabs(f_val - dgi_gf_val); + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } if (log > 0 && fabs(f_val - dgv_gf_val) > tol) { std::cout << e << ":" << j << " dgv " << f_val << " " @@ -1847,9 +1863,11 @@ TEST_CASE("1D GetValue in Parallel", << std::endl; } } + h1_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); dgi_err /= ir.GetNPoints(); + REQUIRE(h1_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); REQUIRE(dgi_err == Approx(0.0)); } @@ -1873,7 +1891,7 @@ TEST_CASE("2D GetValue in Parallel", int log = 1; int n = (int)ceil(sqrt(2*num_procs)); - const int dim = 2; + int dim = 2; int order = 1; int npts = 0; @@ -1890,23 +1908,29 @@ TEST_CASE("2D GetValue in Parallel", SECTION("2D GetValue tests for element type " + std::to_string(type)) { + H1_FECollection h1_fec(order, dim); DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, FiniteElement::VALUE); DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, FiniteElement::INTEGRAL); + ParFiniteElementSpace h1_fespace(&pmesh, &h1_fec); ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); + ParGridFunction h1_x(&h1_fespace); ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); + GridFunctionCoefficient h1_xCoef(&h1_x); GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); + h1_x.ProjectCoefficient(linCoef); dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); + h1_x.ExchangeFaceNbrData(); dgv_x.ExchangeFaceNbrData(); dgi_x.ExchangeFaceNbrData(); @@ -1926,6 +1950,7 @@ TEST_CASE("2D GetValue in Parallel", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); + double h1_err = 0.0; double dgv_err = 0.0; double dgi_err = 0.0; @@ -1935,12 +1960,21 @@ TEST_CASE("2D GetValue in Parallel", const IntegrationPoint &ip = ir.IntPoint(j); T->SetIntPoint(&ip); + double f_val = linCoef.Eval(*T, ip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + h1_err += fabs(f_val - h1_gf_val); dgv_err += fabs(f_val - dgv_gf_val); dgi_err += fabs(f_val - dgi_gf_val); + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } if (log > 0 && fabs(f_val - dgv_gf_val) > tol) { std::cout << e << ":" << j << " dgv " << f_val << " " @@ -1954,9 +1988,11 @@ TEST_CASE("2D GetValue in Parallel", << std::endl; } } + h1_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); dgi_err /= ir.GetNPoints(); + REQUIRE(h1_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); REQUIRE(dgi_err == Approx(0.0)); } @@ -1997,23 +2033,35 @@ TEST_CASE("3D GetValue in Parallel", SECTION("3D GetValue tests for element type " + std::to_string(type)) { + H1_FECollection h1_fec(order, dim); + L2_FECollection l2_fec(order, dim); DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, FiniteElement::VALUE); DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, FiniteElement::INTEGRAL); + ParFiniteElementSpace h1_fespace(&pmesh, &h1_fec); + ParFiniteElementSpace l2_fespace(&pmesh, &l2_fec); ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec); + ParGridFunction h1_x( &h1_fespace); + ParGridFunction l2_x( &l2_fespace); ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); + GridFunctionCoefficient h1_xCoef( &h1_x); + GridFunctionCoefficient l2_xCoef( &l2_x); GridFunctionCoefficient dgv_xCoef(&dgv_x); GridFunctionCoefficient dgi_xCoef(&dgi_x); + h1_x.ProjectCoefficient(linCoef); + l2_x.ProjectCoefficient(linCoef); dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); + h1_x.ExchangeFaceNbrData(); + l2_x.ExchangeFaceNbrData(); dgv_x.ExchangeFaceNbrData(); dgi_x.ExchangeFaceNbrData(); @@ -2021,7 +2069,7 @@ TEST_CASE("3D GetValue in Parallel", { if (my_rank == 0) { - std::cout << "Domain Evaluation 3D" << std::endl; + std::cout << "Shared Face Evaluation 3D" << std::endl; } for (int sf = 0; sf < pmesh.GetNSharedFaces(); sf++) { @@ -2033,7 +2081,8 @@ TEST_CASE("3D GetValue in Parallel", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; + double h1_err = 0.0; + double l2_err = 0.0; double dgv_err = 0.0; double dgi_err = 0.0; @@ -2043,13 +2092,29 @@ TEST_CASE("3D GetValue in Parallel", const IntegrationPoint &ip = ir.IntPoint(j); T->SetIntPoint(&ip); - double f_val = linCoef.Eval(*T, ip); + double f_val = linCoef.Eval(*T, ip); + double h1_gf_val = h1_xCoef.Eval(*T, ip); + double l2_gf_val = l2_xCoef.Eval(*T, ip); double dgv_gf_val = dgv_xCoef.Eval(*T, ip); double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + h1_err += fabs(f_val - h1_gf_val); + l2_err += fabs(f_val - l2_gf_val); dgv_err += fabs(f_val - dgv_gf_val); dgi_err += fabs(f_val - dgi_gf_val); + if (log > 0 && fabs(f_val - h1_gf_val) > tol) + { + std::cout << e << ":" << j << " h1 " << f_val << " " + << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << std::endl; + } + if (log > 0 && fabs(f_val - l2_gf_val) > tol) + { + std::cout << e << ":" << j << " l2 " << f_val << " " + << l2_gf_val << " " << fabs(f_val - l2_gf_val) + << std::endl; + } if (log > 0 && fabs(f_val - dgv_gf_val) > tol) { std::cout << e << ":" << j << " dgv " << f_val << " " @@ -2063,9 +2128,13 @@ TEST_CASE("3D GetValue in Parallel", << std::endl; } } + h1_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); dgi_err /= ir.GetNPoints(); + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); REQUIRE(dgi_err == Approx(0.0)); } @@ -2089,7 +2158,7 @@ TEST_CASE("2D GetVectorValue in Parallel", int log = 1; int n = (int)ceil(sqrt(2*num_procs)); - const int dim = 2; + int dim = 2; int order = 1; int npts = 0; @@ -2107,30 +2176,55 @@ TEST_CASE("2D GetVectorValue in Parallel", SECTION("2D GetVectorValue tests for element type " + std::to_string(type)) { + H1_FECollection h1_fec(order, dim); + ND_FECollection nd_fec(order+1, dim); + RT_FECollection rt_fec(order+1, dim); + L2_FECollection l2_fec(order, dim); DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, FiniteElement::VALUE); DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, FiniteElement::INTEGRAL); + ParFiniteElementSpace h1_fespace(&pmesh, &h1_fec, dim); + ParFiniteElementSpace nd_fespace(&pmesh, &nd_fec); + ParFiniteElementSpace rt_fespace(&pmesh, &rt_fec); + ParFiniteElementSpace l2_fespace(&pmesh, &l2_fec, dim); ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec, dim); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec, dim); - dgv_fespace.ExchangeFaceNbrData(); - dgi_fespace.ExchangeFaceNbrData(); - + ParGridFunction h1_x( &h1_fespace); + ParGridFunction nd_x( &nd_fespace); + ParGridFunction rt_x( &rt_fespace); + ParGridFunction l2_x( &l2_fespace); ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); + VectorGridFunctionCoefficient h1_xCoef( &h1_x); + VectorGridFunctionCoefficient nd_xCoef( &nd_x); + VectorGridFunctionCoefficient rt_xCoef( &rt_x); + VectorGridFunctionCoefficient l2_xCoef( &l2_x); VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); + h1_x.ProjectCoefficient(linCoef); + nd_x.ProjectCoefficient(linCoef); + rt_x.ProjectCoefficient(linCoef); + l2_x.ProjectCoefficient(linCoef); dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); + h1_x.ExchangeFaceNbrData(); + nd_x.ExchangeFaceNbrData(); + rt_x.ExchangeFaceNbrData(); + l2_x.ExchangeFaceNbrData(); dgv_x.ExchangeFaceNbrData(); dgi_x.ExchangeFaceNbrData(); Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector nd_gf_val(dim); nd_gf_val = 0.0; + Vector rt_gf_val(dim); rt_gf_val = 0.0; + Vector l2_gf_val(dim); l2_gf_val = 0.0; Vector dgv_gf_val(dim); dgv_gf_val = 0.0; Vector dgi_gf_val(dim); dgi_gf_val = 0.0; @@ -2150,6 +2244,10 @@ TEST_CASE("2D GetVectorValue in Parallel", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; double dgv_err = 0.0; double dgi_err = 0.0; @@ -2159,15 +2257,56 @@ TEST_CASE("2D GetVectorValue in Parallel", const IntegrationPoint &ip = ir.IntPoint(j); T->SetIntPoint(&ip); + linCoef.Eval(f_val, *T, ip); + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double dgv_dist = Distance(f_val, dgv_gf_val, 2); - double dgi_dist = Distance(f_val, dgi_gf_val, 2); + double h1_dist = Distance(f_val, h1_gf_val, dim); + double nd_dist = Distance(f_val, nd_gf_val, dim); + double rt_dist = Distance(f_val, rt_gf_val, dim); + double l2_dist = Distance(f_val, l2_gf_val, dim); + double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double dgi_dist = Distance(f_val, dgi_gf_val, dim); + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; dgv_err += dgv_dist; dgi_err += dgi_dist; + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_dist << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_dist << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << e << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_dist << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << e << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_dist << std::endl; + } if (log > 0 && dgv_dist > tol) { std::cout << e << ":" << j << " dgv (" @@ -2183,9 +2322,17 @@ TEST_CASE("2D GetVectorValue in Parallel", << dgi_dist << std::endl; } } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); dgi_err /= ir.GetNPoints(); + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); REQUIRE(dgi_err == Approx(0.0)); } @@ -2208,7 +2355,7 @@ TEST_CASE("3D GetVectorValue in Parallel", MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); int log = 1; - int n = 2 * num_procs; + int n = (int)ceil(pow(2*num_procs, 1.0 / 3.0)); int dim = 3; int order = 1; int npts = 0; @@ -2220,7 +2367,10 @@ TEST_CASE("3D GetVectorValue in Parallel", { Mesh *mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); ParMesh pmesh(MPI_COMM_WORLD, *mesh); - pmesh.ExchangeFaceNbrData(); + if (type == Element::TETRAHEDRON) + { + pmesh.ReorientTetMesh(); + } delete mesh; VectorFunctionCoefficient linCoef(dim, Func_3D_lin); @@ -2228,30 +2378,55 @@ TEST_CASE("3D GetVectorValue in Parallel", SECTION("3D GetVectorValue tests for element type " + std::to_string(type)) { + H1_FECollection h1_fec(order, dim); + ND_FECollection nd_fec(order+1, dim); + RT_FECollection rt_fec(order+1, dim); + L2_FECollection l2_fec(order, dim); DG_FECollection dgv_fec(order, dim, BasisType::GaussLegendre, FiniteElement::VALUE); DG_FECollection dgi_fec(order, dim, BasisType::GaussLegendre, FiniteElement::INTEGRAL); + ParFiniteElementSpace h1_fespace(&pmesh, &h1_fec, dim); + ParFiniteElementSpace nd_fespace(&pmesh, &nd_fec); + ParFiniteElementSpace rt_fespace(&pmesh, &rt_fec); + ParFiniteElementSpace l2_fespace(&pmesh, &l2_fec, dim); ParFiniteElementSpace dgv_fespace(&pmesh, &dgv_fec, dim); ParFiniteElementSpace dgi_fespace(&pmesh, &dgi_fec, dim); - dgv_fespace.ExchangeFaceNbrData(); - dgi_fespace.ExchangeFaceNbrData(); - + ParGridFunction h1_x( &h1_fespace); + ParGridFunction nd_x( &nd_fespace); + ParGridFunction rt_x( &rt_fespace); + ParGridFunction l2_x( &l2_fespace); ParGridFunction dgv_x(&dgv_fespace); ParGridFunction dgi_x(&dgi_fespace); + VectorGridFunctionCoefficient h1_xCoef( &h1_x); + VectorGridFunctionCoefficient nd_xCoef( &nd_x); + VectorGridFunctionCoefficient rt_xCoef( &rt_x); + VectorGridFunctionCoefficient l2_xCoef( &l2_x); VectorGridFunctionCoefficient dgv_xCoef(&dgv_x); VectorGridFunctionCoefficient dgi_xCoef(&dgi_x); + h1_x.ProjectCoefficient(linCoef); + nd_x.ProjectCoefficient(linCoef); + rt_x.ProjectCoefficient(linCoef); + l2_x.ProjectCoefficient(linCoef); dgv_x.ProjectCoefficient(linCoef); dgi_x.ProjectCoefficient(linCoef); + h1_x.ExchangeFaceNbrData(); + nd_x.ExchangeFaceNbrData(); + rt_x.ExchangeFaceNbrData(); + l2_x.ExchangeFaceNbrData(); dgv_x.ExchangeFaceNbrData(); dgi_x.ExchangeFaceNbrData(); Vector f_val(dim); f_val = 0.0; + Vector h1_gf_val(dim); h1_gf_val = 0.0; + Vector nd_gf_val(dim); nd_gf_val = 0.0; + Vector rt_gf_val(dim); rt_gf_val = 0.0; + Vector l2_gf_val(dim); l2_gf_val = 0.0; Vector dgv_gf_val(dim); dgv_gf_val = 0.0; Vector dgi_gf_val(dim); dgi_gf_val = 0.0; @@ -2271,6 +2446,10 @@ TEST_CASE("3D GetVectorValue in Parallel", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); + double h1_err = 0.0; + double nd_err = 0.0; + double rt_err = 0.0; + double l2_err = 0.0; double dgv_err = 0.0; double dgi_err = 0.0; @@ -2281,15 +2460,63 @@ TEST_CASE("3D GetVectorValue in Parallel", T->SetIntPoint(&ip); linCoef.Eval(f_val, *T, ip); + h1_xCoef.Eval(h1_gf_val, *T, ip); + nd_xCoef.Eval(nd_gf_val, *T, ip); + rt_xCoef.Eval(rt_gf_val, *T, ip); + l2_xCoef.Eval(l2_gf_val, *T, ip); dgv_xCoef.Eval(dgv_gf_val, *T, ip); dgi_xCoef.Eval(dgi_gf_val, *T, ip); + double h1_dist = Distance(f_val, h1_gf_val, dim); + double nd_dist = Distance(f_val, nd_gf_val, dim); + double rt_dist = Distance(f_val, rt_gf_val, dim); + double l2_dist = Distance(f_val, l2_gf_val, dim); double dgv_dist = Distance(f_val, dgv_gf_val, dim); double dgi_dist = Distance(f_val, dgi_gf_val, dim); + h1_err += h1_dist; + nd_err += nd_dist; + rt_err += rt_dist; + l2_err += l2_dist; dgv_err += dgv_dist; dgi_err += dgi_dist; + if (log > 0 && h1_dist > tol) + { + std::cout << e << ":" << j << " h1 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gf_val[0] << "," << h1_gf_val[1] << "," + << h1_gf_val[2] << ") " << h1_dist + << std::endl; + } + if (log > 0 && nd_dist > tol) + { + std::cout << e << ":" << j << " nd (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gf_val[0] << "," << nd_gf_val[1] << "," + << nd_gf_val[2] << ") " << nd_dist + << std::endl; + } + if (log > 0 && rt_dist > tol) + { + std::cout << e << ":" << j << " rt (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gf_val[0] << "," << rt_gf_val[1] << "," + << rt_gf_val[2] << ") " << rt_dist + << std::endl; + } + if (log > 0 && l2_dist > tol) + { + std::cout << e << ":" << j << " l2 (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gf_val[0] << "," << l2_gf_val[1] << "," + << l2_gf_val[2] << ") " << l2_dist + << std::endl; + } if (log > 0 && dgv_dist > tol) { std::cout << e << ":" << j << " dgv (" @@ -2309,9 +2536,17 @@ TEST_CASE("3D GetVectorValue in Parallel", << std::endl; } } + h1_err /= ir.GetNPoints(); + nd_err /= ir.GetNPoints(); + rt_err /= ir.GetNPoints(); + l2_err /= ir.GetNPoints(); dgv_err /= ir.GetNPoints(); dgi_err /= ir.GetNPoints(); + REQUIRE( h1_err == Approx(0.0)); + REQUIRE( nd_err == Approx(0.0)); + REQUIRE( rt_err == Approx(0.0)); + REQUIRE( l2_err == Approx(0.0)); REQUIRE(dgv_err == Approx(0.0)); REQUIRE(dgi_err == Approx(0.0)); } From a6db609f67ef07abc7c349cd798f53713857c51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Thu, 11 Jun 2020 12:47:39 -0700 Subject: [PATCH 487/535] make style --- examples/petsc/ex28p.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp index 3f00431925..67868ac2ad 100644 --- a/examples/petsc/ex28p.cpp +++ b/examples/petsc/ex28p.cpp @@ -129,11 +129,11 @@ int main(int argc, char *argv[]) Vector cent(dim); for (int i=0; iGetNE(); i++) { - pmesh->GetElementCenter(i, cent); - if (fabs(cent[0]-0.5)<0.25 && fabs(cent[1]-0.5)<0.125) - { - pmesh->GetElement(i)->SetAttribute(2); - } + pmesh->GetElementCenter(i, cent); + if (fabs(cent[0]-0.5)<0.25 && fabs(cent[1]-0.5)<0.125) + { + pmesh->GetElement(i)->SetAttribute(2); + } } // 6. Define a parallel finite element space on the parallel mesh. Here we From 1875c34055f7a92202e28b6392eadfd326836bab Mon Sep 17 00:00:00 2001 From: Julian Andrej Date: Fri, 12 Jun 2020 11:20:07 -0700 Subject: [PATCH 488/535] Add move constructor to custom types --- miniapps/navier/navier_solver.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/miniapps/navier/navier_solver.hpp b/miniapps/navier/navier_solver.hpp index a4799442ba..56a867e234 100644 --- a/miniapps/navier/navier_solver.hpp +++ b/miniapps/navier/navier_solver.hpp @@ -32,6 +32,16 @@ public: : attr(attr), coeff(coeff) {} + VelDirichletBC_T(VelDirichletBC_T &&obj) + { + // Deep copy the attribute array + this->attr = obj.attr; + + // Move the coefficient pointer + this->coeff = obj.coeff; + obj.coeff = nullptr; + } + ~VelDirichletBC_T() { delete coeff; } Array attr; @@ -46,6 +56,16 @@ public: : attr(attr), coeff(coeff) {} + PresDirichletBC_T(PresDirichletBC_T &&obj) + { + // Deep copy the attribute array + this->attr = obj.attr; + + // Move the coefficient pointer + this->coeff = obj.coeff; + obj.coeff = nullptr; + } + ~PresDirichletBC_T() { delete coeff; } Array attr; @@ -60,6 +80,16 @@ public: : attr(attr), coeff(coeff) {} + AccelTerm_T(AccelTerm_T &&obj) + { + // Deep copy the attribute array + this->attr = obj.attr; + + // Move the coefficient pointer + this->coeff = obj.coeff; + obj.coeff = nullptr; + } + ~AccelTerm_T() { delete coeff; } Array attr; From efd5b9f0192c439546213c42b122e9179d7a6d9c Mon Sep 17 00:00:00 2001 From: Tzanio Date: Fri, 12 Jun 2020 18:05:23 -0700 Subject: [PATCH 489/535] minor --- linalg/densemat.cpp | 6 ++-- linalg/densemat.hpp | 41 +++++++++++-------------- linalg/kernels.hpp | 3 +- tests/unit/linalg/test_matrix_dense.cpp | 3 +- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 5ebecb56ed..9a5019a1b1 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -3540,7 +3540,7 @@ void BatchLUFactor(DenseTensor &Mlu, Array &P, const double TOL) mfem::kernels::internal::Swap(data_all(i,j,e), data_all(piv,j,e)); } } - }//pivot end + } // pivot end if (abs(data_all(i,i,e)) <= TOL) { @@ -3562,7 +3562,7 @@ void BatchLUFactor(DenseTensor &Mlu, Array &P, const double TOL) } } - }//m loop + } // m loop }); @@ -3586,4 +3586,4 @@ void BatchLUSolve(const DenseTensor &Mlu, const Array &P, Vector &X) } -} //namespace +} // namespace mfem diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 39d1de8b20..8383bb7594 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -859,31 +859,26 @@ public: ~DenseTensor() { tdata.Delete(); } }; -/** - * @brief Compute the LU factorization of a batch of matrices - * - * Factorize n matrices of size (m x m) stored in a dense tensor - * overwriting it with the LU factors. The factorization is such - * that L.U = Piv.A, where A is the original matrix and Piv is a - * permutation matrix represented by P. - * - * @param [in, out] Mlu batch of square matrices - dimension m x m x n. - * @param [out] P array storing pivot information - dimension m x n. - * @param [in] TOL optional fuzzy comparison tolerance. Defaults to 0.0. - */ +/** @brief Compute the LU factorization of a batch of matrices + + Factorize n matrices of size (m x m) stored in a dense tensor overwriting it + with the LU factors. The factorization is such that L.U = Piv.A, where A is + the original matrix and Piv is a permutation matrix represented by P. + + @param [in, out] Mlu batch of square matrices - dimension m x m x n. + @param [out] P array storing pivot information - dimension m x n. + @param [in] TOL optional fuzzy comparison tolerance. Defaults to 0.0. */ void BatchLUFactor(DenseTensor &Mlu, Array &P, const double TOL = 0.0); -/** - * @brief Solve batch linear systems - * - * Assuming L.U = P.A for n factored matrices (m x m), - * compute x <- A x, for n companion vectors - * - * @param [in] Mlu batch of LU factors for matrix M - dimension m x m x n. - * @param [in] P array storing pivot information - dimension m x n. - * @param [in, out] X vector storing right handside and then solution - * - dimension m x n - */ +/** @brief Solve batch linear systems + + Assuming L.U = P.A for n factored matrices (m x m), compute x <- A x, for n + companion vectors. + + @param [in] Mlu batch of LU factors for matrix M - dimension m x m x n. + @param [in] P array storing pivot information - dimension m x n. + @param [in, out] X vector storing right-hand side and then solution - + dimension m x n. */ void BatchLUSolve(const DenseTensor &Mlu, const Array &P, Vector &X); diff --git a/linalg/kernels.hpp b/linalg/kernels.hpp index 65ebc6e26f..8b3b8fa88a 100644 --- a/linalg/kernels.hpp +++ b/linalg/kernels.hpp @@ -1383,7 +1383,7 @@ have_aa: // @param [in] data LU factorization of A // @param [in] m square matrix height // @param [in] ipiv array storing pivot information -// @param [in, out] x vector storing right handside and then solution +// @param [in, out] x vector storing right-hand side and then solution MFEM_HOST_DEVICE inline void LUSolve(const double *data, const int m, const int *ipiv, double *x) @@ -1415,7 +1415,6 @@ inline void LUSolve(const double *data, const int m, const int *ipiv, } } - } // namespace kernels } // namespace mfem diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index 14fce4f686..a9c698d60c 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -265,7 +265,7 @@ TEST_CASE("DenseTensor LinearSolve methods", auto a_batch = mfem::Reshape(A_batch.HostWrite(),N,N,NE); auto x_batch = mfem::Reshape(X_batch.HostWrite(),N,NE); - //Column major + // Column major for (int e=0; e Date: Fri, 12 Jun 2020 18:14:26 -0700 Subject: [PATCH 490/535] Bugfixes in ParMesh::GetGhostFaceTransformation and GridFunction::GetFaceVectorValues. --- fem/gridfunc.cpp | 4 ++-- mesh/pmesh.cpp | 9 ++++----- mesh/pmesh.hpp | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 1264b3a217..61f18d3fd1 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1031,13 +1031,13 @@ int GridFunction::GetFaceVectorValues( } if (di == 0) { - Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4); + Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5); Transf->Loc1.Transform(ir, eir); GetVectorValues(*Transf->Elem1, eir, vals, &tr); } else { - Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8); + Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10); Transf->Loc2.Transform(ir, eir); GetVectorValues(*Transf->Elem2, eir, vals, &tr); } diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 87a266a0d0..771460cc4b 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2364,16 +2364,16 @@ Table *ParMesh::GetFaceToAllElementTable() const return face_elem; } -ElementTransformation* ParMesh::GetGhostFaceTransformation( +void ParMesh::GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom) { // calculate composition of FETr->Loc1 and FETr->Elem1 - DenseMatrix &face_pm = FaceTransformation.GetPointMat(); + DenseMatrix &face_pm = FETr->GetPointMat(); if (Nodes == NULL) { FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm); - FaceTransformation.SetFE(GetTransformationFEforElementType(face_type)); + FETr->SetFE(GetTransformationFEforElementType(face_type)); } else { @@ -2389,9 +2389,8 @@ ElementTransformation* ParMesh::GetGhostFaceTransformation( FETr->Loc1.Transform(face_el->GetNodes(), eir); Nodes->GetVectorValues(*FETr->Elem1, eir, face_pm); #endif - FaceTransformation.SetFE(face_el); + FETr->SetFE(face_el); } - return &FaceTransformation; } FaceElementTransformations *ParMesh:: diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 220bc4d554..616ca36a1d 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -107,7 +107,7 @@ protected: void GetFaceNbrElementTransformation( int i, IsoparametricTransformation *ElTr); - ElementTransformation* GetGhostFaceTransformation( + void GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom); From 2fda14b373dadfb30e09a048ab2ec368f1c84af1 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Sat, 13 Jun 2020 09:58:03 -0700 Subject: [PATCH 491/535] Adding a missing contribution to the FaceElementTransformations creation mask --- mesh/pmesh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 771460cc4b..e7c2ab2025 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2486,6 +2486,7 @@ GetSharedFaceTransformations(int sf, bool fill2) if (is_ghost) { GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); + mask += 16; } FaceElemTr.SetConfigurationMask(mask); From 664216ca9b588c9f659942cf42d65478e0d4211b Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Sat, 13 Jun 2020 21:51:11 -0700 Subject: [PATCH 492/535] memory optimization - avoid cuda mallocs --- fem/pgridfunc.cpp | 2 +- fem/pgridfunc.hpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp index dac6728bf2..ab765502b1 100644 --- a/fem/pgridfunc.cpp +++ b/fem/pgridfunc.cpp @@ -214,7 +214,7 @@ void ParGridFunction::ExchangeFaceNbrData() ParMesh *pmesh = pfes->GetParMesh(); face_nbr_data.SetSize(pfes->GetFaceNbrVSize()); - Vector send_data(pfes->send_face_nbr_ldof.Size_of_connections()); + send_data.SetSize(pfes->send_face_nbr_ldof.Size_of_connections()); int *send_offset = pfes->send_face_nbr_ldof.GetI(); const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(), diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp index d8f153a32e..722d28b343 100644 --- a/fem/pgridfunc.hpp +++ b/fem/pgridfunc.hpp @@ -38,6 +38,11 @@ protected: initialized by ExchangeFaceNbrData(). */ Vector face_nbr_data; + /** @brief Vector used to store connections from face-neighbor processors, + initialized by ExchangeFaceNbrData(). */ + //TODO: Use temporary memory to avoid CUDA malloc allocation cost. + Vector send_data; + void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff, Array &attr); From ec9f1a62242edd36934504bebb66d1ab1b111721 Mon Sep 17 00:00:00 2001 From: Arturo Vargas Date: Sat, 13 Jun 2020 21:58:14 -0700 Subject: [PATCH 493/535] update docs --- fem/pgridfunc.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp index 722d28b343..75e5c77a6f 100644 --- a/fem/pgridfunc.hpp +++ b/fem/pgridfunc.hpp @@ -38,8 +38,8 @@ protected: initialized by ExchangeFaceNbrData(). */ Vector face_nbr_data; - /** @brief Vector used to store connections from face-neighbor processors, - initialized by ExchangeFaceNbrData(). */ + /** @brief Vector used as an MPI buffer to send face-neighbor data + in ExchangeFaceNbrData() to neighboring processors. */ //TODO: Use temporary memory to avoid CUDA malloc allocation cost. Vector send_data; From b89f29c4b5b32b101e911fb87c2404cab8fa88b2 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Mon, 15 Jun 2020 07:20:56 -0700 Subject: [PATCH 494/535] minor --- CHANGELOG | 15 +++++++-------- doc/CodeDocumentation.dox | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index faf6093d63..69410a7e25 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -102,11 +102,10 @@ New and updated examples and miniapps - Added a new Example 26/26p to demonstrate the construction of a matrix-free geometric and p-multigrid preconditioner for the Laplace problem. -- Added a new example, Example 27/27p, to demonstrate the enforcement of - various boundary conditions with the Laplace operator. The example shows the - procedures for applying Dirichlet, Neumann (both homogeneous and - inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG - discretizations. +- Added a new example, Example 27/27p, to demonstrate the enforcement of various + boundary conditions with the Laplace operator. The example shows the procedure + for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin, + and periodic boundary conditions with either H1 or DG discretizations. - Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of stitching together opposite surfaces of a mesh to create a topologically @@ -121,9 +120,9 @@ New and updated examples and miniapps - Added a new test problem in example 24/24p, demonstrating a mixed bilinear form for H(div) and L_2, with partial assembly support. -- Added a simple mesh editing miniapp, mesh-trimmer, which trims away portions - of a mesh based on element attributes. Any newly exposed boundary elements - are assigned attribute numbers related to the trimmed element attributes. +- Added a simple mesh editing miniapp, Trimmer, which trims away portions of a + mesh based on element attributes. Any newly exposed boundary elements are + assigned attribute numbers related to the trimmed element attributes. Improved testing ---------------- diff --git a/doc/CodeDocumentation.dox b/doc/CodeDocumentation.dox index cdd42bd9e8..55d674c434 100644 --- a/doc/CodeDocumentation.dox +++ b/doc/CodeDocumentation.dox @@ -149,7 +149,7 @@ namespace mfem { * - Extruder: extrude a low-dimensional mesh into a higher dimension * - Mesh Explorer: visualize and manipulate meshes * - Mesh Optimizer: optimize high-order meshes, serial and parallel versions - * - Mesh Trimmer: trim elements from existing meshes + * - Trimmer: trim elements from existing meshes * - Display Basis: visualize finite element basis functions * - Get Values: extract field values via DataCollection classes * - Load DC: visualize fields saved via DataCollection classes From bf62d2923cc7390c0c78035dcebf3a6789187264 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Mon, 15 Jun 2020 20:54:17 -0700 Subject: [PATCH 495/535] Small code simplification. --- fem/coefficient.cpp | 15 +++------------ fem/gridfunc.cpp | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index 4fa41005a9..b29c7ab96b 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -209,20 +209,11 @@ void GradientGridFunctionCoefficient::Eval( GridFunc->GetGradients(T, ir, M); } -CurlGridFunctionCoefficient::CurlGridFunctionCoefficient ( +CurlGridFunctionCoefficient::CurlGridFunctionCoefficient( const GridFunction *gf) - : VectorCoefficient ((gf) ? - (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() - - 3) : 0) + : VectorCoefficient(0) { - if (gf) - { - int sdim = gf -> FESpace() -> GetMesh() -> SpaceDimension(); - MFEM_VERIFY(sdim == 2 || sdim == 3, - "CurlGridFunctionCoefficient " - "only defind for spaces of dimension 2 or 3."); - } - GridFunc = gf; + SetGridFunction(gf); } void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 2e43374977..4ce791301e 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1419,7 +1419,7 @@ double GridFunction::GetDivergence(ElementTransformation &T) const << T.ElementType << "\""); } } - return NAN; + return 0.0; // never reached } void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const From ec634749cf59230bdc2177a2cee4b1b28bc00a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Tue, 16 Jun 2020 13:07:32 -0700 Subject: [PATCH 496/535] Work around zero pivot in serial LU for ex28p --- examples/petsc/rc_ex28p_sinvert | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/petsc/rc_ex28p_sinvert b/examples/petsc/rc_ex28p_sinvert index 85868a0b9f..a7c0cf8820 100644 --- a/examples/petsc/rc_ex28p_sinvert +++ b/examples/petsc/rc_ex28p_sinvert @@ -1 +1,2 @@ -st_type sinvert +-st_pc_factor_shift_type NONZERO From 6604ba702cde99ab9100ecc5034455e76cef83b4 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 16 Jun 2020 21:09:48 -0700 Subject: [PATCH 497/535] WIP: debugging and bugfix for the issue with hybridization on 2D nonconforming meshes, see issue #1105 on github. --- fem/eltrans.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ fem/eltrans.hpp | 6 ++++ fem/gridfunc.cpp | 4 +-- fem/pfespace.cpp | 2 ++ mesh/mesh.cpp | 61 +++++++++++++++++++++++++++++++++++++++- mesh/mesh.hpp | 8 ++++++ mesh/pmesh.cpp | 41 +++++++++++++++++++++++---- mesh/pmesh.hpp | 2 +- mesh/pncmesh.cpp | 10 +++++++ 9 files changed, 197 insertions(+), 9 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index a0b1c5dda9..02b302550d 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -624,4 +624,76 @@ void FaceElementTransformations::Transform(const DenseMatrix &matrix, IsoparametricTransformation::Transform(matrix, result); } +double FaceElementTransformations::CheckConsistency(int print_level) +{ + // Check that the face vertices are mapped to the same physical location + // when using the following three transformations: + // - the face transformation, *this + // - Loc1 + Elem1 + // - Loc2 + Elem2, if present. + + const bool have_face = (mask & 16); + const bool have_el1 = (mask & 1) && (mask & 4); + const bool have_el2 = (mask & 2) && (mask & 8) && (Elem2No >= 0); + if (int(have_face) + int(have_el1) + int(have_el2) < 2) + { + // need at least two different transformations to perform a check + return 0.0; + } + + const IntegrationRule &v_ir = *Geometries.GetVertices(GetGeometryType()); + + double max_dist = 0.0; + Vector dist(v_ir.GetNPoints()); + DenseMatrix coords_base, coords_el; + IntegrationRule v_eir(v_ir.GetNPoints()); + if (have_face) + { + Transform(v_ir, coords_base); + if (print_level > 0) + { + mfem::out << "\nface vertex coordinates (from face transform):\n" + << "----------------------------------------------\n"; + coords_base.PrintT(mfem::out, coords_base.Height()); + } + } + if (have_el1) + { + Loc1.Transform(v_ir, v_eir); + Elem1->Transform(v_eir, coords_el); + if (print_level > 0) + { + mfem::out << "\nface vertex coordinates (from element 1 transform):\n" + << "---------------------------------------------------\n"; + coords_el.PrintT(mfem::out, coords_el.Height()); + } + if (have_face) + { + coords_el -= coords_base; + coords_el.Norm2(dist); + max_dist = std::max(max_dist, dist.Normlinf()); + } + else + { + coords_base = coords_el; + } + } + if (have_el2) + { + Loc2.Transform(v_ir, v_eir); + Elem2->Transform(v_eir, coords_el); + if (print_level > 0) + { + mfem::out << "\nface vertex coordinates (from element 2 transform):\n" + << "---------------------------------------------------\n"; + coords_el.PrintT(mfem::out, coords_el.Height()); + } + coords_el -= coords_base; + coords_el.Norm2(dist); + max_dist = std::max(max_dist, dist.Normlinf()); + } + + return max_dist; +} + } diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 6fe35ee25f..e7cffc1f82 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -492,6 +492,12 @@ public: ElementTransformation & GetElement2Transformation(); IntegrationPointTransformation & GetIntPoint1Transformation(); IntegrationPointTransformation & GetIntPoint2Transformation(); + + /** @brief Check for self-consistency. Returns a maximal distance between + physical points that should coincide. A successful check should return + a small number relative to the mesh extents. */ + /** @note This check will generally fail on periodic boundary faces. */ + double CheckConsistency(int print_level = 0); }; /** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 1264b3a217..61f18d3fd1 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1031,13 +1031,13 @@ int GridFunction::GetFaceVectorValues( } if (di == 0) { - Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4); + Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5); Transf->Loc1.Transform(ir, eir); GetVectorValues(*Transf->Elem1, eir, vals, &tr); } else { - Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8); + Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10); Transf->Loc2.Transform(ir, eir); GetVectorValues(*Transf->Elem2, eir, vals, &tr); } diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp index 88f97ceaaa..2144f8d3c2 100644 --- a/fem/pfespace.cpp +++ b/fem/pfespace.cpp @@ -1212,6 +1212,8 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFE(int i) const const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const { + // FIXME: triangle faces + // Works in tandem with GetFaceNbrFaceVDofs() defined above. MFEM_ASSERT(Nonconforming() && !NURBSext, ""); Geometry::Type geom = (pmesh->Dimension() == 2) ? diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 4afc25232c..9777e87db2 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -911,6 +911,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, // NC meshes: prepend slave edge/face transformation to Loc2 if (Nonconforming() && IsSlaveFace(face_info)) { +#if 0 ApplyLocalSlaveTransformation(FaceElemTr.Loc2.Transf, face_info); if (face_type == Element::SEGMENT) @@ -920,11 +921,29 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, std::swap(pm(0,0), pm(0,1)); std::swap(pm(1,0), pm(1,1)); } +#else + ApplyLocalSlaveTransformation(FaceElemTr, face_info, false); +#endif } } FaceElemTr.SetConfigurationMask(mask); + // This check can be useful for internal debugging, however it will fail on + // periodic boundary faces. +#if 1 +#ifdef MFEM_DEBUG + double dist = FaceElemTr.CheckConsistency(); + if (dist >= 1e-12) + { + mfem::out << "\nInternal error: face id = " << FaceNo + << ", dist = " << dist << '\n'; + FaceElemTr.CheckConsistency(1); + MFEM_ABORT("internal error"); + } +#endif +#endif + return &FaceElemTr; } @@ -946,6 +965,45 @@ void Mesh::ApplyLocalSlaveTransformation(IsoparametricTransformation &transf, transf.SetPointMat(composition); } +void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT, + const FaceInfo &fi, bool is_ghost) +{ +#ifdef MFEM_THREAD_SAFE + DenseMatrix composition; +#else + static DenseMatrix composition; +#endif + MFEM_ASSERT(fi.NCFace >= 0, ""); + MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error"); + if (!is_ghost) + { + // side 1 -> child side, side 2 -> parent side + IsoparametricTransformation < = FT.Loc2.Transf; + LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition); + // In 2D, we need to flip the point matrix since it is aligned with the + // parent side. + if (Dim == 2) + { + // swap points (columns) 0 and 1 + std::swap(composition(0,0), composition(0,1)); + std::swap(composition(1,0), composition(1,1)); + } + LT.SetPointMat(composition); + } + else // is_ghost == true + { + // side 1 -> parent side, side 2 -> child side + IsoparametricTransformation < = FT.Loc1.Transf; + LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition); + // In 2D, there is no need to flip the point matrix since it is already + // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors. + // In 3D the point matrix was flipped during construction in + // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with + // the parent side. + LT.SetPointMat(composition); + } +} + FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) { FaceElementTransformations *tr; @@ -5261,7 +5319,8 @@ void Mesh::GenerateNCFaceInfo() slave_fi.Elem2No = master_fi.Elem1No; slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above - // NOTE: orientation part of Elem2Inf is encoded in the point matrix + // NOTE: orientation part of Elem2Inf is encoded in the point matrix; + // the above is not true in 2D. } } diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 4303776d64..a8128528d1 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -131,11 +131,16 @@ protected: // face. Elem2No is < 0 and -1-Elem2No is the index of the ghost // face-neighbor element that generated this slave ghost face. In this // case, Elem2Inf >= 0. + // Relevant methods: GenerateFaces(), GenerateNCFaceInfo(), + // ParNCMesh::GetFaceNeighbors(), + // ParMesh::ExchangeFaceNbrData() struct NCFaceInfo { bool Slave; // true if this is a slave face, false if master face int MasterFace; // if Slave, this is the index of the master face + // If not Slave, 'MasterFace' is the local face index of this master face + // as a face in the unique adjacent element. const DenseMatrix* PointMatrix; // if Slave, position within master face // (NOTE: PointMatrix points to a matrix owned by NCMesh.) @@ -365,6 +370,9 @@ protected: slave face occupies only a portion of its master face. */ void ApplyLocalSlaveTransformation(IsoparametricTransformation &transf, const FaceInfo &fi); + /// TODO: Add documentation. + void ApplyLocalSlaveTransformation(FaceElementTransformations &FT, + const FaceInfo &fi, bool is_ghost); bool IsSlaveFace(const FaceInfo &fi) const; /// Returns the orientation of "test" relative to "base" diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index bcb22a621b..6b48c74c9b 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2363,16 +2363,16 @@ Table *ParMesh::GetFaceToAllElementTable() const return face_elem; } -ElementTransformation* ParMesh::GetGhostFaceTransformation( +void ParMesh::GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom) { // calculate composition of FETr->Loc1 and FETr->Elem1 - DenseMatrix &face_pm = FaceTransformation.GetPointMat(); + DenseMatrix &face_pm = FETr->GetPointMat(); if (Nodes == NULL) { FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm); - FaceTransformation.SetFE(GetTransformationFEforElementType(face_type)); + FETr->SetFE(GetTransformationFEforElementType(face_type)); } else { @@ -2388,9 +2388,8 @@ ElementTransformation* ParMesh::GetGhostFaceTransformation( FETr->Loc1.Transform(face_el->GetNodes(), eir); Nodes->GetVectorValues(*FETr->Elem1, eir, face_pm); #endif - FaceTransformation.SetFE(face_el); + FETr->SetFE(face_el); } - return &FaceTransformation; } FaceElementTransformations *ParMesh:: @@ -2453,6 +2452,7 @@ GetSharedFaceTransformations(int sf, bool fill2) // adjust Loc1 or Loc2 of the master face if this is a slave face if (is_slave) { +#if 0 // is a ghost slave? -> master not a ghost -> choose Elem1 local transf // not a ghost slave? -> master is a ghost -> choose Elem2 local transf IsoparametricTransformation &loctr = @@ -2470,14 +2470,45 @@ GetSharedFaceTransformations(int sf, bool fill2) std::swap(pm(0,0), pm(0,1)); std::swap(pm(1,0), pm(1,1)); } +#else + if (is_ghost || fill2) + { + // is_ghost -> modify side 1, otherwise -> modify side 2: + ApplyLocalSlaveTransformation(FaceElemTr, face_info, is_ghost); + } +#endif } // for ghost faces we need a special version of GetFaceTransformation if (is_ghost) { GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); + +#if 1 + MFEM_ASSERT(is_slave, "internal error"); + mfem::out << "\n[rank " << MyRank << "]: processed child ghost face" + << ", face id = " << FaceNo + << MFEM_LOCATION << std::flush; +#endif } + FaceElemTr.SetConfigurationMask(fill2 ? 31 : 21); + + // This check can be useful for internal debugging, however it will fail on + // periodic boundary faces. +#if 1 +#ifdef MFEM_DEBUG + double dist = FaceElemTr.CheckConsistency(); + if (dist >= 1e-12) + { + mfem::out << "\nInternal error: face id = " << FaceNo + << ", dist = " << dist << ", rank = " << MyRank << '\n'; + FaceElemTr.CheckConsistency(1); + MFEM_ABORT("internal error"); + } +#endif +#endif + return &FaceElemTr; } diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 220bc4d554..616ca36a1d 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -107,7 +107,7 @@ protected: void GetFaceNbrElementTransformation( int i, IsoparametricTransformation *ElTr); - ElementTransformation* GetGhostFaceTransformation( + void GetGhostFaceTransformation( FaceElementTransformations* FETr, Element::Type face_type, Geometry::Type face_geom); diff --git a/mesh/pncmesh.cpp b/mesh/pncmesh.cpp index 93d9ef475b..761e4da0c4 100644 --- a/mesh/pncmesh.cpp +++ b/mesh/pncmesh.cpp @@ -1263,6 +1263,8 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh) const DenseMatrix* pm = &sf.point_matrix; if (!sloc && Dim == 3) { + // TODO: does this handle triangle faces correctly? + // ghost slave in 3D needs flipping orientation DenseMatrix* pm2 = new DenseMatrix(*pm); std::swap((*pm2)(0,1), (*pm2)(0,3)); @@ -1282,6 +1284,14 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh) // processor, but on the other it is the element containing the // master face. In the latter case we need to flip the pm. } + else if (!sloc && Dim == 2) + { + fi.Elem2Inf ^= 1; // set orientation to 1 + // The point matrix (used to define "side 1" which is the same as + // "parent side" in this case) does not require a flip since it + // is aligned with the parent side, so NO flip is performed in + // Mesh::ApplyLocalSlaveTransformation. + } MFEM_ASSERT(fi.NCFace < 0, ""); fi.NCFace = pmesh.nc_faces_info.Size(); From 2a72bfcd5c5e77a18719f4d7f2c9515254ec17b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Wed, 17 Jun 2020 08:32:51 -0700 Subject: [PATCH 498/535] Check for vector size in SlepcEigenSolver::GetEigenVector, and distribute eigenvector correctly in SLEPc ex11p --- examples/petsc/ex11p.cpp | 7 +++++-- linalg/slepc.cpp | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index 4157b54783..2e744beec7 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -345,6 +345,7 @@ int main(int argc, char *argv[]) slepc->GetEigenvalue(i,eigenvalues[i]); } } + Vector temp(fespace->GetTrueVSize()); ParGridFunction x(fespace); // 10. Save the refined mesh and the modes in parallel. This output can be @@ -366,7 +367,8 @@ int main(int argc, char *argv[]) } else { - slepc->GetEigenvector(i,x); + slepc->GetEigenvector(i,temp); + x.Distribute(temp); } @@ -403,7 +405,8 @@ int main(int argc, char *argv[]) } else { - slepc->GetEigenvector(i,x); + slepc->GetEigenvector(i,temp); + x.Distribute(temp); } mode_sock << "parallel " << num_procs << " " << myid << "\n" diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index e327ed350e..34fb0575b2 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -149,6 +149,9 @@ void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr) const { MFEM_VERIFY(VR,"Missing real vector"); + MFEM_ASSERT(vr.Size() == VR->Size(), "invalid vr.Size() = " << vr.Size() + << ", expected size = " << VR->Size()); + VR->PlaceArray(vr.GetData()); ierr = EPSGetEigenvector(eps,i,*VR,NULL); PCHKERRQ(eps,ierr); VR->ResetArray(); @@ -160,6 +163,10 @@ void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr, { MFEM_VERIFY(VR,"Missing real vector"); MFEM_VERIFY(VC,"Missing imaginary vector"); + MFEM_ASSERT(vr.Size() == VR->Size(), "invalid vr.Size() = " << vr.Size() + << ", expected size = " << VR->Size()); + MFEM_ASSERT(vc.Size() == VC->Size(), "invalid vc.Size() = " << vc.Size() + << ", expected size = " << VC->Size()); VR->PlaceArray(vr.GetData()); VC->PlaceArray(vc.GetData()); From dd23ccddb3483d983552f187abc28fd736662cf3 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Wed, 17 Jun 2020 22:39:16 -0700 Subject: [PATCH 499/535] In ex4p, added a sample run that tests hybridization in 2D when there are ghost shared faces using amr-quad.mesh on 3 processors. In ex9p, added a sample run on amr-hex.mesh on 3 processors so have a test case with ghost shared faces in 3D. --- examples/ex4p.cpp | 1 + examples/ex9p.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/ex4p.cpp b/examples/ex4p.cpp index 282ebb4fa3..afcbc23bca 100644 --- a/examples/ex4p.cpp +++ b/examples/ex4p.cpp @@ -16,6 +16,7 @@ // mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc // mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc // mpirun -np 4 ex4p -m ../data/amr-quad.mesh +// mpirun -np 3 ex4p -m ../data/amr-quad.mesh -o 2 -hb // mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc // mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb // mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb diff --git a/examples/ex9p.cpp b/examples/ex9p.cpp index 68143e1861..cbbff953a2 100644 --- a/examples/ex9p.cpp +++ b/examples/ex9p.cpp @@ -16,6 +16,7 @@ // mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 2 -rp 1 -dt 0.005 -tf 9 // mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 3 -rp 2 -dt 0.0025 -tf 9 -vs 20 // mpirun -np 4 ex9p -m ../data/periodic-cube.mesh -p 0 -o 2 -rp 1 -dt 0.01 -tf 8 +// mpirun -np 3 ex9p -m ../data/amr-hex.mesh -p 1 -rs 1 -rp 0 -dt 0.005 -tf 0.5 // // Device sample runs: // mpirun -np 4 ex9p -pa From 56066f9cac9e5cbb40e1db02cef9b786303893f3 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 18 Jun 2020 10:44:35 -0700 Subject: [PATCH 500/535] Modifying `mask` variable as a mask (with |=) rather than an integer (with +=) --- mesh/pmesh.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index e7c2ab2025..9fca1ee94f 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2419,7 +2419,7 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem1No = face_info.Elem1No; GetElementTransformation(FaceElemTr.Elem1No, &Transformation); FaceElemTr.Elem1 = &Transformation; - mask += 1; + mask |= 1; // setup the transformation for the second (neighbor) element if (fill2) @@ -2427,7 +2427,7 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem2No = -1 - face_info.Elem2No; GetFaceNbrElementTransformation(FaceElemTr.Elem2No, &Transformation2); FaceElemTr.Elem2 = &Transformation2; - mask += 2; + mask |= 2; } else { @@ -2439,7 +2439,7 @@ GetSharedFaceTransformations(int sf, bool fill2) { GetFaceTransformation(FaceNo, &FaceElemTr); // NOTE: The above call overwrites FaceElemTr.Loc1 - mask += 16; + mask |= 16; } else { @@ -2450,14 +2450,14 @@ GetSharedFaceTransformations(int sf, bool fill2) int elem_type = GetElementType(face_info.Elem1No); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc1.Transf, face_info.Elem1Inf); - mask += 4; + mask |= 4; if (fill2) { elem_type = face_nbr_elements[FaceElemTr.Elem2No]->GetType(); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc2.Transf, face_info.Elem2Inf); - mask += 8; + mask |= 8; } // adjust Loc1 or Loc2 of the master face if this is a slave face @@ -2486,7 +2486,7 @@ GetSharedFaceTransformations(int sf, bool fill2) if (is_ghost) { GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); - mask += 16; + mask |= 16; } FaceElemTr.SetConfigurationMask(mask); From bed918ad779e79c36eadfc451f89d7c77cfac8ee Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 18 Jun 2020 15:15:54 -0700 Subject: [PATCH 501/535] Fixing preservation of pre-existing boundary attributes --- miniapps/meshing/trimmer.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp index 65475f8364..4eed2920a9 100644 --- a/miniapps/meshing/trimmer.cpp +++ b/miniapps/meshing/trimmer.cpp @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) // Count the number of boundary elements in the final mesh int num_bdr_elements = 0; - for (int f=0; fGetAttribute(); + if (!marker[elem_attr-1]) + { + Element * nbel = mesh.GetBdrElement(be)->Duplicate(&trimmed_mesh); + trimmed_mesh.AddBdrElement(nbel); + } + } + + // Create new boundary elements + for (int f=0; f Date: Thu, 18 Jun 2020 15:16:10 -0700 Subject: [PATCH 502/535] Supporting 1D meshes. --- miniapps/meshing/trimmer.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp index 4eed2920a9..929dea2541 100644 --- a/miniapps/meshing/trimmer.cpp +++ b/miniapps/meshing/trimmer.cpp @@ -189,25 +189,21 @@ int main(int argc, char *argv[]) if (e1 >= 0) { a1 = mesh.GetElement(e1)->GetAttribute(); } if (e2 >= 0) { a2 = mesh.GetElement(e2)->GetAttribute(); } - if (a1 == 0 || a2 == 0) - { - if ((a1 == 0 && !marker[a2-1]) || (a2 == 0 && !marker[a1-1])) - { - Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); - trimmed_mesh.AddBdrElement(bel); - } - } - else + if (a1 != 0 && a2 != 0) { if (marker[a1-1] && !marker[a2-1]) { - Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); + Element * bel = (mesh.Dimension() == 1) ? + (Element*)new Point(&f) : + mesh.GetFace(f)->Duplicate(&trimmed_mesh); bel->SetAttribute(bdr_attr[attr_inv[a1-1]]); trimmed_mesh.AddBdrElement(bel); } else if (!marker[a1-1] && marker[a2-1]) { - Element * bel = mesh.GetFace(f)->Duplicate(&trimmed_mesh); + Element * bel = (mesh.Dimension() == 1) ? + (Element*)new Point(&f) : + mesh.GetFace(f)->Duplicate(&trimmed_mesh); bel->SetAttribute(bdr_attr[attr_inv[a2-1]]); trimmed_mesh.AddBdrElement(bel); } From d72ff9948b9fbb6b1227c4147b7986866c5fb9f5 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Thu, 18 Jun 2020 16:34:59 -0700 Subject: [PATCH 503/535] Adding an enumeration for the FaceElementTransformations mask values --- fem/eltrans.cpp | 14 +++++++------- fem/eltrans.hpp | 12 ++++++++++++ mesh/mesh.cpp | 15 +++++++++------ mesh/pmesh.cpp | 12 ++++++------ 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index a0b1c5dda9..da0c74a72d 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -571,7 +571,7 @@ void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) ElementTransformation & FaceElementTransformations::GetElement1Transformation() { - MFEM_VERIFY(mask & 1 && Elem1 != NULL, "The ElementTransformation " + MFEM_VERIFY(mask & HAVE_ELEM1 && Elem1 != NULL, "The ElementTransformation " "for the element has not been configured for side 1."); return *Elem1; } @@ -579,7 +579,7 @@ FaceElementTransformations::GetElement1Transformation() ElementTransformation & FaceElementTransformations::GetElement2Transformation() { - MFEM_VERIFY(mask & 2 && Elem2 != NULL, "The ElementTransformation " + MFEM_VERIFY(mask & HAVE_ELEM2 && Elem2 != NULL, "The ElementTransformation " "for the element has not been configured for side 2."); return *Elem2; } @@ -587,7 +587,7 @@ FaceElementTransformations::GetElement2Transformation() IntegrationPointTransformation & FaceElementTransformations::GetIntPoint1Transformation() { - MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation " + MFEM_VERIFY(mask & HAVE_LOC1, "The IntegrationPointTransformation " "for the element has not been configured for side 1."); return Loc1; } @@ -595,7 +595,7 @@ FaceElementTransformations::GetIntPoint1Transformation() IntegrationPointTransformation & FaceElementTransformations::GetIntPoint2Transformation() { - MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation " + MFEM_VERIFY(mask & HAVE_LOC2, "The IntegrationPointTransformation " "for the element has not been configured for side 2."); return Loc2; } @@ -603,7 +603,7 @@ FaceElementTransformations::GetIntPoint2Transformation() void FaceElementTransformations::Transform(const IntegrationPoint &ip, Vector &trans) { - MFEM_VERIFY(mask & 16, "The ElementTransformation " + MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation " "for the face has not been configured."); IsoparametricTransformation::Transform(ip, trans); } @@ -611,7 +611,7 @@ void FaceElementTransformations::Transform(const IntegrationPoint &ip, void FaceElementTransformations::Transform(const IntegrationRule &ir, DenseMatrix &tr) { - MFEM_VERIFY(mask & 16, "The ElementTransformation " + MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation " "for the face has not been configured."); IsoparametricTransformation::Transform(ir, tr); } @@ -619,7 +619,7 @@ void FaceElementTransformations::Transform(const IntegrationRule &ir, void FaceElementTransformations::Transform(const DenseMatrix &matrix, DenseMatrix &result) { - MFEM_VERIFY(mask & 16, "The ElementTransformation " + MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation " "for the face has not been configured."); IsoparametricTransformation::Transform(matrix, result); } diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 6fe35ee25f..9a46f5e27b 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -443,11 +443,23 @@ public: class FaceElementTransformations : public IsoparametricTransformation { private: + + // Bitwise OR of ConfigMasks int mask; IntegrationPoint eip1, eip2; public: + + enum ConfigMasks + { + HAVE_ELEM1 = 1, // Element on side 1 is configured + HAVE_ELEM2 = 2, // Element on side 2 is configured + HAVE_LOC1 = 4, // Point transformation for side 1 is configured + HAVE_LOC2 = 8, // Point transformation for side 2 is configured + HAVE_FACE = 16 // Face transformation is configured + }; + int Elem1No, Elem2No; Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead ElementTransformation *Elem1, *Elem2; diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 7de13c750e..6288bb4129 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -865,7 +865,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, // setup the transformation for the first element FaceElemTr.Elem1No = face_info.Elem1No; - if (mask & 1) + if (mask & FaceElementTransformations::HAVE_ELEM1) { GetElementTransformation(FaceElemTr.Elem1No, &Transformation); FaceElemTr.Elem1 = &Transformation; @@ -875,17 +875,19 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, // return NULL in the Elem2 field if there's no second element, i.e. // the face is on the "boundary" FaceElemTr.Elem2No = face_info.Elem2No; - if ((mask & 2) && FaceElemTr.Elem2No >= 0) + if ((mask & FaceElementTransformations::HAVE_ELEM2) && + FaceElemTr.Elem2No >= 0) { #ifdef MFEM_DEBUG - if (NURBSext && (mask & 1)) { MFEM_ABORT("NURBS mesh not supported!"); } + if (NURBSext && (mask & FaceElementTransformations::HAVE_ELEM1)) + { MFEM_ABORT("NURBS mesh not supported!"); } #endif GetElementTransformation(FaceElemTr.Elem2No, &Transformation2); FaceElemTr.Elem2 = &Transformation2; } // setup the face transformation - if (mask & 16) + if (mask & FaceElementTransformations::HAVE_FACE) { GetFaceTransformation(FaceNo, &FaceElemTr); } @@ -896,13 +898,14 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, // setup Loc1 & Loc2 int face_type = GetFaceElementType(FaceNo); - if (mask & 4) + if (mask & FaceElementTransformations::HAVE_LOC1) { int elem_type = GetElementType(face_info.Elem1No); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc1.Transf, face_info.Elem1Inf); } - if ((mask & 8) && FaceElemTr.Elem2No >= 0) + if ((mask & FaceElementTransformations::HAVE_LOC2) && + FaceElemTr.Elem2No >= 0) { int elem_type = GetElementType(face_info.Elem2No); GetLocalFaceTransformation(face_type, elem_type, diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 9fca1ee94f..4968ec9f4d 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2419,7 +2419,7 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem1No = face_info.Elem1No; GetElementTransformation(FaceElemTr.Elem1No, &Transformation); FaceElemTr.Elem1 = &Transformation; - mask |= 1; + mask |= FaceElementTransformations::HAVE_ELEM1; // setup the transformation for the second (neighbor) element if (fill2) @@ -2427,7 +2427,7 @@ GetSharedFaceTransformations(int sf, bool fill2) FaceElemTr.Elem2No = -1 - face_info.Elem2No; GetFaceNbrElementTransformation(FaceElemTr.Elem2No, &Transformation2); FaceElemTr.Elem2 = &Transformation2; - mask |= 2; + mask |= FaceElementTransformations::HAVE_ELEM2; } else { @@ -2439,7 +2439,7 @@ GetSharedFaceTransformations(int sf, bool fill2) { GetFaceTransformation(FaceNo, &FaceElemTr); // NOTE: The above call overwrites FaceElemTr.Loc1 - mask |= 16; + mask |= FaceElementTransformations::HAVE_FACE; } else { @@ -2450,14 +2450,14 @@ GetSharedFaceTransformations(int sf, bool fill2) int elem_type = GetElementType(face_info.Elem1No); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc1.Transf, face_info.Elem1Inf); - mask |= 4; + mask |= FaceElementTransformations::HAVE_LOC1; if (fill2) { elem_type = face_nbr_elements[FaceElemTr.Elem2No]->GetType(); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc2.Transf, face_info.Elem2Inf); - mask |= 8; + mask |= FaceElementTransformations::HAVE_LOC2; } // adjust Loc1 or Loc2 of the master face if this is a slave face @@ -2486,7 +2486,7 @@ GetSharedFaceTransformations(int sf, bool fill2) if (is_ghost) { GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); - mask |= 16; + mask |= FaceElementTransformations::HAVE_FACE; } FaceElemTr.SetConfigurationMask(mask); From 8e00ae03e427b43031ee887224cbe2c63604c5ae Mon Sep 17 00:00:00 2001 From: Tzanio Date: Thu, 18 Jun 2020 18:49:12 -0700 Subject: [PATCH 504/535] Removed convergence/bae.cpp, this will be handled in another PR. --- fem/lininteg.cpp | 1 - fem/lininteg.hpp | 3 +- tests/convergence/bae.cpp | 393 ------------------------------------- tests/convergence/makefile | 77 -------- 4 files changed, 2 insertions(+), 472 deletions(-) delete mode 100644 tests/convergence/bae.cpp delete mode 100644 tests/convergence/makefile diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 22af65fdaf..e871520935 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -507,7 +507,6 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect( default: break; // This should be unreachable } - } void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect( diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index 645e7fc58e..43f6e980af 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -329,6 +329,7 @@ public: using LinearFormIntegrator::AssembleRHSElementVect; }; + /** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function v=(v1,...,vn) where all vi are in the same scalar FE space and f is a scalar function. */ @@ -359,7 +360,7 @@ class VectorFEBoundaryFluxLFIntegrator : public LinearFormIntegrator private: Coefficient *F; Vector shape; - int oa, ob; // these contol the quadrature order, see DomainLFIntegrator + int oa, ob; // these control the quadrature order, see DomainLFIntegrator public: VectorFEBoundaryFluxLFIntegrator(int a = 1, int b = -1) diff --git a/tests/convergence/bae.cpp b/tests/convergence/bae.cpp deleted file mode 100644 index 6e87363e7e..0000000000 --- a/tests/convergence/bae.cpp +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced -// at the Lawrence Livermore National Laboratory. All Rights reserved. See files -// LICENSE and NOTICE for details. LLNL-CODE-806117. -// -// This file is part of the MFEM library. For more information and source code -// availability visit https://mfem.org. -// -// MFEM is free software; you can redistribute it and/or modify it under the -// terms of the BSD-3 license. We welcome feedback and contributions, see file -// CONTRIBUTING.md for details. - -// Compile with: make BAE -// -// Sample runs: mpirun -np 4 BAE -m ../../data/inline-segment.mesh -sr 1 -pr 4 -prob 0 -o 1 -// mpirun -np 4 BAE -m ../../data/inline-quad.mesh -sr 1 -pr 3 -prob 0 -o 2 -// mpirun -np 4 BAE -m ../../data/inline-quad.mesh -sr 1 -pr 3 -prob 1 -o 2 -// mpirun -np 4 BAE -m ../../data/inline-quad.mesh -sr 1 -pr 3 -prob 2 -o 2 -// mpirun -np 4 BAE -m ../../data/inline-tri.mesh -sr 1 -pr 3 -prob 2 -o 3 -// mpirun -np 4 BAE -m ../../data/star.mesh -sr 1 -pr 2 -prob 1 -o 4 -// mpirun -np 4 BAE -m ../../data/fichera.mesh -sr 1 -pr 2 -prob 2 -o 2 -// mpirun -np 4 BAE -m ../../data/inline-wedge.mesh -sr 0 -pr 2 -prob 0 -o 2 -// mpirun -np 4 BAE -m ../../data/inline-hex.mesh -sr 0 -pr 1 -prob 1 -o 3 -// mpirun -np 4 BAE -m ../../data/square-disc.mesh -sr 1 -pr 2 -prob 1 -o 2 -// -// Description: This example code is used for testing the LF-integrators -// (Q,grad v), (Q,curl V), (Q, div v) -// by solving the appropriate energy projection problems -// -// prob 0: (grad u, grad v) + (u,v) = (grad u_exact, grad v) + (u_exact, v) -// prob 1: (curl u, curl v) + (u,v) = (curl u_exact, curl v) + (u_exact, v) -// prob 2: (div u, div v) + (u,v) = (div u_exact, div v) + (u_exact, v) - -#include "mfem.hpp" -#include -#include - -using namespace std; -using namespace mfem; - -// H1 -double u_exact(const Vector &x); -void gradu_exact(const Vector &x, Vector &gradu); - -// Vector FE -void U_exact(const Vector &x, Vector & U); -// H(curl) -void curlU_exact(const Vector &x, Vector &curlU); -double curlU2D_exact(const Vector &x); -// H(div) -double divU_exact(const Vector &x); - -int dim; -int prob=0; -Vector alpha; - -int main(int argc, char *argv[]) -{ - // 1. Initialize MPI. - int num_procs, myid; - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - MPI_Comm_rank(MPI_COMM_WORLD, &myid); - - // 2. Parse command-line options. - const char *mesh_file = "../../data/inline-quad.mesh"; - int order = 1; - bool visualization = 1; - int sr = 1; - int pr = 1; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree)"); - args.AddOption(&prob, "-prob", "--problem", - "Problem kind: 0: H1, 1: H(curl), 2: H(div)"); - args.AddOption(&sr, "-sr", "--serial_ref", - "Number of serial refinements."); - args.AddOption(&pr, "-pr", "--parallel_ref", - "Number of parallel refinements."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.Parse(); - if (!args.Good()) - { - if (myid == 0) - { - args.PrintUsage(cout); - } - MPI_Finalize(); - return 1; - } - if (myid == 0) - { - args.PrintOptions(cout); - } - - // 3. Read the (serial) mesh from the given mesh file on all processors. We - // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface - // and volume meshes with the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - dim = mesh->Dimension(); if (dim == 1 ) prob = 0; - - // 4. Set up parameters for exact solution - alpha.SetSize(dim); // x,y,z coefficients of the solution - for (int i=0; iUniformRefinement(); - } - - // 6. Define a parallel mesh by a partitioning of the serial mesh. Once the - // parallel mesh is defined, the serial mesh can be deleted. - ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); - delete mesh; - - // 7. Define a parallel finite element space on the parallel mesh. - FiniteElementCollection *fec=nullptr; - switch (prob) - { - case 0: fec = new H1_FECollection(order,dim); break; - case 1: fec = new ND_FECollection(order,dim); break; - case 2: fec = new RT_FECollection(order-1,dim); break; - default: break; - } - ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); - - // 8. Define the solution vector u_gf as a parallel finite element grid function - // corresponding to fespace. - ParGridFunction u_gf(fespace); - - // 9. Set up the parallel linear form b(.) and the parallel - // bilinear form a(.,.). - FunctionCoefficient *u=nullptr; - FunctionCoefficient *divU=nullptr; - FunctionCoefficient *curlU2D=nullptr; - VectorFunctionCoefficient *U=nullptr; - VectorFunctionCoefficient *gradu=nullptr; - VectorFunctionCoefficient *curlU=nullptr; - - ConstantCoefficient one(1.0); - ParLinearForm b(fespace); - ParBilinearForm a(fespace); - - switch (prob) - { - case 0: - //(grad u_ex, grad v) + (u_ex,v) - u = new FunctionCoefficient(u_exact); - gradu = new VectorFunctionCoefficient(dim,gradu_exact); - b.AddDomainIntegrator(new DomainLFGradIntegrator(*gradu)); - b.AddDomainIntegrator(new DomainLFIntegrator(*u)); - - // (grad u, grad v) + (u,v) - a.AddDomainIntegrator(new DiffusionIntegrator(one)); - a.AddDomainIntegrator(new MassIntegrator(one)); - - break; - case 1: - //(curl u_ex, curl v) + (u_ex,v) - U = new VectorFunctionCoefficient(dim,U_exact); - if (dim == 3) - { - curlU = new VectorFunctionCoefficient(dim,curlU_exact); - b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU)); - } - else if (dim == 2) - { - curlU2D = new FunctionCoefficient(curlU2D_exact); - b.AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(*curlU2D)); - } - b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); - - // (curl u, curl v) + (u,v) - a.AddDomainIntegrator(new CurlCurlIntegrator(one)); - a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); - break; - - case 2: - //(div u_ex, div v) + (u_ex,v) - U = new VectorFunctionCoefficient(dim,U_exact); - divU = new FunctionCoefficient(divU_exact); - b.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(*divU)); - b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(*U)); - - // (div u, div v) + (u,v) - a.AddDomainIntegrator(new DivDivIntegrator(one)); - a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); - break; - - default: - break; - } - - // 10. Perform successive parallel refinements, compute the L2 error - // and the corresponding rate of convergence - double L2err0 = 0.0; - for (int l = 0; l <= pr; l++) - { - b.Assemble(); - a.Assemble(); - Array ess_tdof_list; - if (pmesh->bdr_attributes.Size()) - { - Array ess_bdr(pmesh->bdr_attributes.Max()); - ess_bdr = 0; - fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - } - OperatorPtr A; - Vector X, B; - a.FormLinearSystem(ess_tdof_list, u_gf, b, A, X,B); - - Solver *prec = NULL; - switch (prob) - { - case 0: - prec = new HypreBoomerAMG(*A.As()); - dynamic_cast(prec)->SetPrintLevel(0); - break; - case 1: - prec = new HypreAMS(*A.As(), fespace); - dynamic_cast(prec)->SetPrintLevel(0); - break; - case 2: - if (dim == 2) - { - prec = new HypreAMS(*A.As(), fespace); - dynamic_cast(prec)->SetPrintLevel(0); - } - else - { - prec = new HypreADS(*A.As(), fespace); - dynamic_cast(prec)->SetPrintLevel(0); - } - break; - default: - break; - } - - CGSolver cg(MPI_COMM_WORLD); - cg.SetRelTol(1e-12); - cg.SetMaxIter(2000); - cg.SetPrintLevel(0); - if (prec) { cg.SetPreconditioner(*prec); } - cg.SetOperator(*A); - cg.Mult(B, X); - delete prec; - - a.RecoverFEMSolution(X,B,u_gf); - - double L2err = 0.0; - switch (prob) - { - case 0: - L2err = u_gf.ComputeL2Error(*u); - break; - case 1: - case 2: - L2err = u_gf.ComputeL2Error(*U); - break; - default: - break; - } - if (myid == 0) - { - double rate=0.0; - if (l>0) - { - rate = log(L2err0/L2err)/log(2.0); - } - cout << setprecision(3); - - cout << "|| u_h - u ||_{L^2} = " << scientific - << L2err << ", rate: " << fixed << rate << endl; - L2err0 = L2err; - } - - if (l==pr) break; - - pmesh->UniformRefinement(); - fespace->Update(); - a.Update(); - b.Update(); - u_gf.Update(); - } - - // 11. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - string keys; - if (dim ==2 ) - { - keys = "keys UUmrRljc\n"; - } - else - { - keys = "keys mc\n"; - } - socketstream sol_sock(vishost, visport); - sol_sock << "parallel " << num_procs << " " << myid << "\n"; - sol_sock.precision(8); - sol_sock << "solution\n" << *pmesh << u_gf << - "window_title 'Numerical Pressure (real part)' " - << keys << flush; - } - - // 12. Free the used memory. - delete u; - delete divU; - delete curlU2D; - delete U; - delete gradu; - delete curlU; - delete fespace; - delete fec; - delete pmesh; - - MPI_Finalize(); - - return 0; -} - -double u_exact(const Vector &x) -{ - double u; - double y=0; - for (int i=0; i Date: Fri, 19 Jun 2020 09:53:09 -0700 Subject: [PATCH 505/535] Remove SLEPc ex28p for now, will add later as a miniapp --- .gitignore | 2 - examples/petsc/CMakeLists.txt | 2 - examples/petsc/ex28p.cpp | 401 -------------------------------- examples/petsc/makefile | 2 +- examples/petsc/rc_ex28p_jd | 3 - examples/petsc/rc_ex28p_sinvert | 2 - 6 files changed, 1 insertion(+), 411 deletions(-) delete mode 100644 examples/petsc/ex28p.cpp delete mode 100644 examples/petsc/rc_ex28p_jd delete mode 100644 examples/petsc/rc_ex28p_sinvert diff --git a/.gitignore b/.gitignore index 4d755a13ad..5e539c59aa 100644 --- a/.gitignore +++ b/.gitignore @@ -121,7 +121,6 @@ examples/sundials/Example16* examples/petsc/ex[1-69]p examples/petsc/ex1[0-1]p -examples/petsc/ex28p examples/petsc/mesh.* examples/petsc/sol.* @@ -137,7 +136,6 @@ examples/petsc/deformed.* examples/petsc/velocity.* examples/petsc/elastic_energy.* examples/petsc/mode_* -examples/petsc/Example28* examples/pumi/ex1 examples/pumi/ex[126]p diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index d513c2e107..07216783d6 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -37,10 +37,8 @@ endif() if (MFEM_USE_SLEPC) list(APPEND PETSC_EXAMPLES_SRCS ex11p.cpp - ex28p.cpp ) list(APPEND PETSC_RC_FILES - rc_ex28p_jd rc_ex28p_sinvert ) endif() diff --git a/examples/petsc/ex28p.cpp b/examples/petsc/ex28p.cpp deleted file mode 100644 index 67868ac2ad..0000000000 --- a/examples/petsc/ex28p.cpp +++ /dev/null @@ -1,401 +0,0 @@ -// MFEM Example 28 - Parallel Version -// SLEPc Modification -// -// Compile with: make ex28p -// -// Sample runs: -// mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p_jd --block -// mpirun -np 4 ex28p -m ../../data/inline-tri.mesh --slepcopts rc_ex28p_sinvert --no-block -// -// Description: This example code solves a simple 2D dielectric waveguide -// problem corresponding to the generalized eigenvalue equation -// curl curl et - beta^2 (grad ez - et) = k^2 epsilon et -// div (grad ez - et) = k^2 epsilon ez -// with essential boundary condition (corresponding to metallic -// walls), where k is the wavenumber and epsilon is the material -// dielectric constant. We are searching for the eigenvalue beta -// which corresponds to the propagation constant. We assume the -// material relative permeability (mu) is 1. -// -// We discretize with Nedelec edge elements (transverse field et) -// and piecewise continuous polynomials (longitudinal field ez). -// -// The example demonstrates the use of the BlockMatrix class, as -// well as the collective saving of several grid functions in a -// VisIt (visit.llnl.gov) visualization format. -// -// This specific example needs SLEPc compiled. The default options -// file uses the Jacobi-Davidson method with Jacobi -// preconditioner. -// - -#include "mfem.hpp" -#include -#include - -#ifndef MFEM_USE_PETSC -#error This example requires that MFEM is built with MFEM_USE_PETSC=YES -#endif - -using namespace std; -using namespace mfem; - -int main(int argc, char *argv[]) -{ - // 1. Initialize MPI. - int num_procs, myid; - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - MPI_Comm_rank(MPI_COMM_WORLD, &myid); - bool verbose = (myid == 0); - - // 2. Parse command-line options. - const char *mesh_file = "../../data/inline-tri.mesh"; - int ser_ref_levels = 1; - int par_ref_levels = 1; - int order = 2; - int nev = 1; - bool par_format = false; - bool visualization = 1; - const char *slepcrc_file = ""; - bool use_block = true; - - OptionsParser args(argc, argv); - args.AddOption(&mesh_file, "-m", "--mesh", - "Mesh file to use."); - args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", - "Number of times to refine the mesh uniformly in serial."); - args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", - "Number of times to refine the mesh uniformly in parallel."); - args.AddOption(&order, "-o", "--order", - "Finite element order (polynomial degree)."); - args.AddOption(&par_format, "-pf", "--parallel-format", "-sf", - "--serial-format", - "Format to use when saving the results for VisIt."); - args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", - "--no-visualization", - "Enable or disable GLVis visualization."); - args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts", - "SlepcOptions file to use."); - args.AddOption(&use_block, "-block", "--block", "-no-block", - "--no-block", - "Enable or disable the use of block matrices"); - args.Parse(); - if (!args.Good()) - { - if (verbose) - { - args.PrintUsage(cout); - } - MPI_Finalize(); - return 1; - } - if (verbose) - { - args.PrintOptions(cout); - } - // 2b. We initialize SLEPc - MFEMInitializeSlepc(NULL,NULL,slepcrc_file,NULL); - - // 3. Read the (serial) mesh from the given mesh file on all processors. We - // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface - // and volume meshes with the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - int dim = mesh->Dimension(); - - // 4. Refine the serial mesh on all processors to increase the resolution. In - // this example we do 'ref_levels' of uniform refinement. We choose - // 'ref_levels' to be the largest number that gives a final mesh with no - // more than 10,000 elements. - for (int lev = 0; lev < ser_ref_levels; lev++) - { - mesh->UniformRefinement(); - } - - // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine - // this mesh further in parallel to increase the resolution. Once the - // parallel mesh is defined, the serial mesh can be deleted. - // - // We also define a second attribute region in the middle of the mesh to - // represent the core of the dielectric waveguide. - ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); - delete mesh; - for (int l = 0; l < par_ref_levels; l++) - { - pmesh->UniformRefinement(); - } - pmesh->ReorientTetMesh(); - - Vector cent(dim); - for (int i=0; iGetNE(); i++) - { - pmesh->GetElementCenter(i, cent); - if (fabs(cent[0]-0.5)<0.25 && fabs(cent[1]-0.5)<0.125) - { - pmesh->GetElement(i)->SetAttribute(2); - } - } - - // 6. Define a parallel finite element space on the parallel mesh. Here we - // use the Nedelec finite elements of the specified order. - std::cout << "dim: " << dim << "\n"; - FiniteElementCollection *hcurl_coll = new ND_FECollection(order, dim); - FiniteElementCollection *h1_coll = new H1_FECollection(order, dim); - - ParFiniteElementSpace *N_space = new ParFiniteElementSpace(pmesh, hcurl_coll); - ParFiniteElementSpace *L_space = new ParFiniteElementSpace(pmesh, h1_coll); - - HYPRE_Int dimN = N_space->GlobalTrueVSize(); - HYPRE_Int dimL = L_space->GlobalTrueVSize(); - - if (verbose) - { - std::cout << "***********************************************************\n"; - std::cout << "dim(N) = " << dimN << "\n"; - std::cout << "dim(L) = " << dimL << "\n"; - std::cout << "dim(N+L) = " << dimN + dimL << "\n"; - std::cout << "***********************************************************\n"; - } - - // 7. Define the two BlockStructure of the problem. block_offsets is used - // for Vector based on dof (like ParGridFunction or ParLinearForm), - // block_trueOffstes is used for Vector based on trueDof (HypreParVector - // for the rhs and solution of the linear system). The offsets computed - // here are local to the processor. - Array block_offsets(3); // number of variables + 1 - block_offsets[0] = 0; - block_offsets[1] = N_space->GetVSize(); - block_offsets[2] = L_space->GetVSize(); - block_offsets.PartialSum(); - - Array block_trueOffsets(3); // number of variables + 1 - block_trueOffsets[0] = 0; - block_trueOffsets[1] = N_space->TrueVSize(); - block_trueOffsets[2] = L_space->TrueVSize(); - block_trueOffsets.PartialSum(); - - // 8. Define the coefficients of the PDE. - ConstantCoefficient u_r_func(1.0); - Vector e_r(2); - double k0 = M_PI*2/1.0; - // We lump the sign, the wavenumber and the dielectric constant into one - // coefficient. The dielectric contsant is the square of the refractive - // index. - e_r(0) = -pow(k0*1.0,2); - // This is the refractive index used in the waveguide core - e_r(1) = -pow(k0*2.0,2); - PWConstCoefficient e_r_func(e_r); - - // 9. Define the parallel grid function and parallel linear forms. - BlockVector x(block_offsets); - BlockVector trueX(block_trueOffsets); - - // Define the boundary attributes - Array ess_bdr; - if (pmesh->bdr_attributes.Size()) - { - ess_bdr.SetSize(pmesh->bdr_attributes.Max()); - ess_bdr = 1; - } - - // 10. Assemble the finite element matrices for the LHS and RHS - // - // A = [ Att 0 ] - // [ 0 0 ] - // - // B = [ Btt Bzt ] - // [ Btz Bzz ] - ParBilinearForm *att = new ParBilinearForm(N_space); - ParBilinearForm *btt = new ParBilinearForm(N_space); - ParBilinearForm *azz = new ParBilinearForm(L_space); - ParBilinearForm *bzz = new ParBilinearForm(L_space); - ParMixedBilinearForm *btz = new ParMixedBilinearForm(N_space, L_space); - - PetscParMatrix *pAtt = NULL, *pBtt = NULL, *pBzz = NULL; - PetscParMatrix *pAzz = NULL, *pBtz = NULL, *pBzt = NULL; - Operator::Type tid = Operator::PETSC_MATAIJ; - OperatorHandle Atth(tid), Btth(tid), Bzzh(tid), Btzh(tid), Azzh(tid); - - att->AddDomainIntegrator(new CurlCurlIntegrator(u_r_func)); - att->AddDomainIntegrator(new VectorFEMassIntegrator(e_r_func)); - att->Assemble(); - att->EliminateEssentialBCDiag(ess_bdr, 1.0); - att->Finalize(); - att->ParallelAssemble(Atth); - Atth.Get(pAtt); - Atth.SetOperatorOwner(false); - - // A dummy Azz is required to set the block size and apply the essential - // boundary condition - azz->Assemble(); - azz->EliminateEssentialBCDiag(ess_bdr, 1.0); - azz->Finalize(); - azz->ParallelAssemble(Azzh); - Azzh.Get(pAzz); - Azzh.SetOperatorOwner(false); - - btt->AddDomainIntegrator(new VectorFEMassIntegrator(u_r_func)); - btt->Assemble(); - btt->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); - btt->Finalize(); - btt->ParallelAssemble(Btth); - Btth.Get(pBtt); - Btth.SetOperatorOwner(false); - (*pBtt) *= -1; - - bzz->AddDomainIntegrator(new DiffusionIntegrator(u_r_func)); - bzz->AddDomainIntegrator(new MassIntegrator(e_r_func)); - bzz->Assemble(); - bzz->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min()); - bzz->Finalize(); - bzz->ParallelAssemble(Bzzh); - Bzzh.Get(pBzz); - Bzzh.SetOperatorOwner(false); - (*pBzz) *= -1; - - ParLinearForm dummy(N_space); - btz->AddDomainIntegrator(new MixedVectorWeakDivergenceIntegrator(u_r_func)); - btz->Assemble(); - btz->EliminateTestDofs(ess_bdr); - btz->EliminateTrialDofs(ess_bdr,x.GetBlock(0),dummy); - btz->Finalize(); - btz->ParallelAssemble(Btzh); - Btzh.Get(pBtz); - Btzh.SetOperatorOwner(false); - - pBzt = pBtz->Transpose(); - - PetscParMatrix *LHSOp = NULL, *RHSOp = NULL; - // We construct the BlockOperator and we then convert it to a - // PetscParMatrix. - BlockOperator *tLHSOp = new BlockOperator(block_trueOffsets); - tLHSOp->SetBlock(0,0,pAtt); - tLHSOp->SetBlock(1,1,pAzz); - if (use_block) - { - LHSOp = new PetscParMatrix(MPI_COMM_WORLD,tLHSOp,Operator::PETSC_MATAIJ); - } - else - { - // Converting from a BlockOperator creates a MATNEST which preserves the block structure - PetscParMatrix *LHSBlock = new PetscParMatrix(MPI_COMM_WORLD,tLHSOp, - Operator::PETSC_MATAIJ); - // Converting again to MATAIJ to get monolithic matrix - LHSOp = new PetscParMatrix(MPI_COMM_WORLD,LHSBlock,Operator::PETSC_MATAIJ); - delete LHSBlock; - - } - delete tLHSOp; - - BlockOperator *tRHSOp = new BlockOperator(block_trueOffsets); - tRHSOp->SetBlock(0,0,pBtt); - tRHSOp->SetBlock(1,1,pBzz); - tRHSOp->SetBlock(1,0,pBtz); - tRHSOp->SetBlock(0,1,pBzt); - if (use_block) - { - RHSOp = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp,Operator::PETSC_MATAIJ); - } - else - { - PetscParMatrix *RHSBlock = new PetscParMatrix(MPI_COMM_WORLD,tRHSOp, - Operator::PETSC_MATAIJ); - RHSOp = new PetscParMatrix(MPI_COMM_WORLD,RHSBlock,Operator::PETSC_MATAIJ); - } - delete tRHSOp; - - // 11. Solve the eigenvalue problem with slepc. - std::cout << "Solving...\n"; - - trueX = 0.0; - - SlepcEigenSolver *solver = new SlepcEigenSolver(MPI_COMM_WORLD); - solver->SetOperators(*LHSOp,*RHSOp); - solver->SetNumModes(nev); - solver->SetWhichEigenpairs(SlepcEigenSolver::TARGET_MAGNITUDE); - // The target is set with a small offset to prevent zero pivots in this example - solver->SetTarget(pow(k0*2.0,2)-1e-2); - solver->Solve(); - double re; - solver->GetEigenvalue(0,re); - Vector dummy2(block_trueOffsets[2]); - solver->GetEigenvector(0,trueX); - std::cout << "Effective index: " << sqrt(re)/k0 << "\n"; - - // 12. Extract the parallel grid function corresponding to the finite element - // approximation X. This is the local solution on each processor. - ParGridFunction *et(new ParGridFunction); - ParGridFunction *ez(new ParGridFunction); - et->MakeRef(N_space, x.GetBlock(0), 0); - ez->MakeRef(L_space, x.GetBlock(1), 0); - et->Distribute(&(trueX.GetBlock(0))); - ez->Distribute(&(trueX.GetBlock(1))); - - // 13. Save the refined mesh and the solution in parallel. This output can be - // viewed later using GLVis: "glvis -np -m mesh -g sol_*". - { - ostringstream mesh_name, u_name, p_name; - mesh_name << "mesh." << setfill('0') << setw(6) << myid; - u_name << "sol_u." << setfill('0') << setw(6) << myid; - p_name << "sol_p." << setfill('0') << setw(6) << myid; - - ofstream mesh_ofs(mesh_name.str().c_str()); - mesh_ofs.precision(8); - pmesh->Print(mesh_ofs); - - ofstream et_ofs(u_name.str().c_str()); - et_ofs.precision(8); - et->Save(et_ofs); - - ofstream ez_ofs(p_name.str().c_str()); - ez_ofs.precision(8); - ez->Save(ez_ofs); - } - - // 14. Save data in the VisIt format - VisItDataCollection visit_dc("Example28-Parallel", pmesh); - visit_dc.RegisterField("Exy", et); - visit_dc.RegisterField("Ez", ez); - visit_dc.SetFormat(!par_format ? - DataCollection::SERIAL_FORMAT : - DataCollection::PARALLEL_FORMAT); - visit_dc.Save(); - - // 15. Send the solution by socket to a GLVis server. - if (visualization) - { - char vishost[] = "localhost"; - int visport = 19916; - socketstream u_sock(vishost, visport); - u_sock << "parallel " << num_procs << " " << myid << "\n"; - u_sock.precision(8); - u_sock << "solution\n" << *pmesh << *et << "window_title 'Transverse E field'" - << endl; - u_sock << "keys Rjl!\n"; - // Make sure all ranks have sent their 'et' solution before initiating - // another set of GLVis connections (one from each rank): - MPI_Barrier(pmesh->GetComm()); - socketstream p_sock(vishost, visport); - p_sock << "parallel " << num_procs << " " << myid << "\n"; - p_sock.precision(8); - p_sock << "solution\n" << *pmesh << *ez << "window_title 'Longitudinal E field'" - << endl; - p_sock << "keys Rjl!\n"; - } - - // 16. Free the used memory. - delete et; - delete ez; - delete N_space; - delete L_space; - delete h1_coll; - delete hcurl_coll; - delete pmesh; - - // We finalize SLEPc - MFEMFinalizeSlepc(); - MPI_Finalize(); - - return 0; -} - diff --git a/examples/petsc/makefile b/examples/petsc/makefile index 5f6a4d83c1..32900a6230 100644 --- a/examples/petsc/makefile +++ b/examples/petsc/makefile @@ -24,7 +24,7 @@ MFEM_LIB_FILE = mfem_is_not_built SEQ_EXAMPLES = PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p ifeq ($(MFEM_USE_SLEPC),YES) - PAR_EXAMPLES += ex11p ex28p + PAR_EXAMPLES += ex11p endif ifeq ($(MFEM_USE_MPI),NO) EXAMPLES = $(SEQ_EXAMPLES) diff --git a/examples/petsc/rc_ex28p_jd b/examples/petsc/rc_ex28p_jd deleted file mode 100644 index 0265304c31..0000000000 --- a/examples/petsc/rc_ex28p_jd +++ /dev/null @@ -1,3 +0,0 @@ --eps_type jd --st_ksp_type gmres --st_pc_type jacobi diff --git a/examples/petsc/rc_ex28p_sinvert b/examples/petsc/rc_ex28p_sinvert deleted file mode 100644 index a7c0cf8820..0000000000 --- a/examples/petsc/rc_ex28p_sinvert +++ /dev/null @@ -1,2 +0,0 @@ --st_type sinvert --st_pc_factor_shift_type NONZERO From 0acdc5dcd524738c07fcf4bdfa69fab6539c2f3f Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 19 Jun 2020 13:15:48 -0700 Subject: [PATCH 506/535] Adding Doxygen comments for the new ConfigMasks enumeration --- fem/eltrans.hpp | 10 +++++----- mesh/mesh.hpp | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 9a46f5e27b..3e4697defb 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -453,11 +453,11 @@ public: enum ConfigMasks { - HAVE_ELEM1 = 1, // Element on side 1 is configured - HAVE_ELEM2 = 2, // Element on side 2 is configured - HAVE_LOC1 = 4, // Point transformation for side 1 is configured - HAVE_LOC2 = 8, // Point transformation for side 2 is configured - HAVE_FACE = 16 // Face transformation is configured + HAVE_ELEM1 = 1, ///< Element on side 1 is configured + HAVE_ELEM2 = 2, ///< Element on side 2 is configured + HAVE_LOC1 = 4, ///< Point transformation for side 1 is configured + HAVE_LOC2 = 8, ///< Point transformation for side 2 is configured + HAVE_FACE = 16 ///< Face transformation is configured }; int Elem1No, Elem2No; diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 4303776d64..7a2da5612c 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -955,7 +955,7 @@ public: /// Returns the transformation defining the given face element ElementTransformation *GetEdgeTransformation(int EdgeNo); - /// Returns (a pointer to a structure containing) the following data: + /// Returns (a pointer to an object containing) the following data: /// /// 1) Elem1No - the index of the first element that contains this face this /// is the element that has the same outward unit normal vector as the @@ -983,6 +983,9 @@ public: /// The mask specifies which fields in the structure to return: /// mask & 1 - Elem1, mask & 2 - Elem2 /// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face. + /// These mask values are defined in the + /// FaceElementTransformations::ConfigMasks enumeration. + /// FaceElementTransformations *GetFaceElementTransformations(int FaceNo, int mask = 31); From f225d35ef65fb74cbfaab6292e68cd7d2a3522c5 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 19 Jun 2020 14:06:45 -0700 Subject: [PATCH 507/535] Added a brief CHANGELOG entry for the navier miniapp. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 69410a7e25..a6cd9f34e8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -107,6 +107,9 @@ New and updated examples and miniapps for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG discretizations. +- Added a new miniapp, navier, that solves the time-dependent Navier-Stokes + equations of incompressible fluid dynamics. + - Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of stitching together opposite surfaces of a mesh to create a topologically periodic mesh. From f7aa1d9972b07bf4af7b2bf69ac0e7cadbb77a89 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 19 Jun 2020 15:32:50 -0700 Subject: [PATCH 508/535] Adding FaceElementTransformations::SetAllIntPoints method --- fem/eltrans.cpp | 14 +++++++--- fem/eltrans.hpp | 71 ++++++++++++++++++++++++++++++++++++++++++++---- fem/gridfunc.cpp | 36 ++++++++++++++++-------- 3 files changed, 99 insertions(+), 22 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index a0b1c5dda9..5572962723 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -556,15 +556,21 @@ void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) { IsoparametricTransformation::SetIntPoint(ip); - if (Elem1) + if (mask & 4) { Loc1.Transform(*ip, eip1); - Elem1->SetIntPoint(&eip1); + if (Elem1) + { + Elem1->SetIntPoint(&eip1); + } } - if (Elem2) + if (mask & 8) { Loc2.Transform(*ip, eip2); - Elem2->SetIntPoint(&eip2); + if (Elem2) + { + Elem2->SetIntPoint(&eip2); + } } } diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 6fe35ee25f..6e37cb9b74 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -439,7 +439,17 @@ public: void Transform (const IntegrationRule &, IntegrationRule &); }; +/** @brief A specialized ElementTransformation class representing a face and + its two neighboring elements. + This class can be used as a container for the element transformation data + needed for integrating discontinuous fields on element interfaces in a + Discontinuous Galerkin (DG) context. + + The secondary purpose of this class is to enable the + GridFunction::GetValue function, and various related functions, to properly + evaluate fields with limited continuity on boundary elements. +*/ class FaceElementTransformations : public IsoparametricTransformation { private: @@ -447,6 +457,23 @@ private: IntegrationPoint eip1, eip2; +protected: // interface for Mesh to be able to configure this object. + + friend class Mesh; + + /// Set the mask indicating which portions of the object have been setup + /** The argument @a m is a bitmask used in + Mesh::GetFaceElementTransformations to indicate which portions of the + FaceElementTransformations object have been configured. + + mask & 1: Elem1 is configured + mask & 2: Elem2 is configured + mask & 4: Loc1 is configured + mask & 8: Loc2 is configured + mask & 16: The Face transformation itself is configured + */ + void SetConfigurationMask(int m) { mask = m; } + public: int Elem1No, Elem2No; Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead @@ -466,10 +493,10 @@ public: */ void SetGeometryType(Geometry::Type g) { geom = g; } - /// Set the mask indicating which portions of the object have been setup - /** The argument @a m is a bitmask used in - Mesh::GetFaceElementTransformations to indicate which portions of the - FaceElement Transformations object have been configured. + /** @brief Return the mask defining the configuration state. + + The mask value indicates which portions of FaceElementTransformations + object have been configured. mask & 1: Elem1 is configured mask & 2: Elem2 is configured @@ -477,13 +504,45 @@ public: mask & 8: Loc2 is configured mask & 16: The Face transformation itself is configured */ - void SetConfigurationMask(int m) { mask = m; } int GetConfigurationMask() const { return mask; } /** @brief Set the integration point in the Face and the two neighboring - elements, if present. */ + elements, if present. + + The point @a ip must be in the reference coordinate system of the face. + */ void SetIntPoint(const IntegrationPoint *ip); + /** @brief Set the integration point in the Face and the two neighboring + elements, if present. + + This is a more expressive member function name than SetIntPoint, which + in this special case, does the same thing. This function can be used for + greater code clarity. + */ + inline void SetAllIntPoints(const IntegrationPoint *ip) + { FaceElementTransformations::SetIntPoint(ip); } + + /** @brief Get a const reference to the integration point in neighboring + element 1 corresponding to the currently set integration point on the + face. + + This IntegrationPoint object will only contain up-to-date data if + SetIntPoint or SetAllIntPoints has been called with the latest + integration point for the face and the appropriate point transformation + has been configured. */ + const IntegrationPoint &GetElement1IntPoint() { return eip1; } + + /** @brief Get a const reference to the integration point in neighboring + element 2 corresponding to the currently set integration point on the + face. + + This IntegrationPoint object will only contain up-to-date data if + SetIntPoint or SetAllIntPoints has been called with the latest + integration point for the face and the appropriate point transformation + has been configured. */ + const IntegrationPoint &GetElement2IntPoint() { return eip2; } + virtual void Transform(const IntegrationPoint &, Vector &); virtual void Transform(const IntegrationRule &, DenseMatrix &); virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result); diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 4ce791301e..7eb856c017 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -752,7 +752,8 @@ double GridFunction::GetValue(ElementTransformation &T, IntegrationPoint fip; be_to_bfe(FET->GetGeometryType(), o, ip, fip); - FET->SetIntPoint(&fip); + // Compute and set the point in element 1 from fip + FET->SetAllIntPoints(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); return GetValue(T1, T1.GetIntPoint(), comp); } @@ -764,7 +765,8 @@ double GridFunction::GetValue(ElementTransformation &T, dynamic_cast(&T); // Evaluate in neighboring element for both continuous and - // discontinuous fields. + // discontinuous fields (the integration point in T1 should have + // already been set). ElementTransformation & T1 = FET->GetElement1Transformation(); return GetValue(T1, T1.GetIntPoint(), comp); } @@ -888,7 +890,8 @@ void GridFunction::GetVectorValue(ElementTransformation &T, IntegrationPoint fip; be_to_bfe(FET->GetGeometryType(), o, ip, fip); - FET->SetIntPoint(&fip); + // Compute and set the point in element 1 from fip + FET->SetAllIntPoints(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); return GetVectorValue(T1, T1.GetIntPoint(), val); } @@ -900,7 +903,8 @@ void GridFunction::GetVectorValue(ElementTransformation &T, dynamic_cast(&T); // Evaluate in neighboring element for both continuous and - // discontinuous fields. + // discontinuous fields (the integration point in T1 should have + // already been set). ElementTransformation & T1 = FET->GetElement1Transformation(); return GetVectorValue(T1, T1.GetIntPoint(), val); } @@ -1396,7 +1400,8 @@ double GridFunction::GetDivergence(ElementTransformation &T) const IntegrationPoint fip; be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); - FET->SetIntPoint(&fip); + // Compute and set the point in element 1 from fip + FET->SetAllIntPoints(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); return GetDivergence(T1); @@ -1408,7 +1413,8 @@ double GridFunction::GetDivergence(ElementTransformation &T) const FaceElementTransformations * FET = dynamic_cast(&T); - // Evaluate in neighboring element + // Evaluate in neighboring element (the integration point in T1 should + // have already been set). ElementTransformation & T1 = FET->GetElement1Transformation(); return GetDivergence(T1); } @@ -1497,7 +1503,8 @@ void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const IntegrationPoint fip; be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); - FET->SetIntPoint(&fip); + // Compute and set the point in element 1 from fip + FET->SetAllIntPoints(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); GetCurl(T1, curl); @@ -1509,7 +1516,8 @@ void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const FaceElementTransformations * FET = dynamic_cast(&T); - // Evaluate in neighboring element + // Evaluate in neighboring element (the integration point in T1 should + // have already been set). ElementTransformation & T1 = FET->GetElement1Transformation(); GetCurl(T1, curl); } @@ -1565,7 +1573,8 @@ void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const IntegrationPoint fip; be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); - FET->SetIntPoint(&fip); + // Compute and set the point in element 1 from fip + FET->SetAllIntPoints(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); GetGradient(T1, grad); @@ -1577,7 +1586,8 @@ void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const FaceElementTransformations * FET = dynamic_cast(&T); - // Evaluate in neighboring element + // Evaluate in neighboring element (the integration point in T1 should + // have already been set). ElementTransformation & T1 = FET->GetElement1Transformation(); GetGradient(T1, grad); } @@ -1650,7 +1660,8 @@ void GridFunction::GetVectorGradient( IntegrationPoint fip; be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip); - FET->SetIntPoint(&fip); + // Compute and set the point in element 1 from fip + FET->SetAllIntPoints(&fip); ElementTransformation & T1 = FET->GetElement1Transformation(); GetVectorGradient(T1, grad); @@ -1662,7 +1673,8 @@ void GridFunction::GetVectorGradient( FaceElementTransformations * FET = dynamic_cast(&T); - // Evaluate in neighboring element + // Evaluate in neighboring element (the integration point in T1 should + // have already been set). ElementTransformation & T1 = FET->GetElement1Transformation(); GetVectorGradient(T1, grad); } From 88ac2efaad4601e5aeca7563a9f8eb08b817540b Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 19 Jun 2020 15:33:37 -0700 Subject: [PATCH 509/535] Setting FaceElementTransformations config mask based on configured pieces rather than input argument --- mesh/mesh.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 7de13c750e..ea1ccf3737 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -859,7 +859,8 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, { FaceInfo &face_info = faces_info[FaceNo]; - FaceElemTr.SetConfigurationMask(0); + int cmask = 0; + FaceElemTr.SetConfigurationMask(cmask); FaceElemTr.Elem1 = NULL; FaceElemTr.Elem2 = NULL; @@ -869,6 +870,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, { GetElementTransformation(FaceElemTr.Elem1No, &Transformation); FaceElemTr.Elem1 = &Transformation; + cmask |= 1; } // setup the transformation for the second element @@ -882,12 +884,14 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, #endif GetElementTransformation(FaceElemTr.Elem2No, &Transformation2); FaceElemTr.Elem2 = &Transformation2; + cmask |= 2; } // setup the face transformation if (mask & 16) { GetFaceTransformation(FaceNo, &FaceElemTr); + cmask |= 16; } else { @@ -901,6 +905,7 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, int elem_type = GetElementType(face_info.Elem1No); GetLocalFaceTransformation(face_type, elem_type, FaceElemTr.Loc1.Transf, face_info.Elem1Inf); + cmask |= 4; } if ((mask & 8) && FaceElemTr.Elem2No >= 0) { @@ -921,9 +926,10 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, std::swap(pm(1,0), pm(1,1)); } } + cmask |= 8; } - FaceElemTr.SetConfigurationMask(mask); + FaceElemTr.SetConfigurationMask(cmask); return &FaceElemTr; } @@ -967,7 +973,7 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) { return NULL; } - tr = GetFaceElementTransformations(fn); + tr = GetFaceElementTransformations(fn, 21); tr->Attribute = boundary[BdrElemNo]->GetAttribute(); tr->ElementNo = BdrElemNo; tr->ElementType = ElementTransformation::BDR_FACE; From 7e3766eb021f9313ea90ee9fa5ec4e250e9e6190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Fri, 19 Jun 2020 15:58:52 -0700 Subject: [PATCH 510/535] Remove ex28p mention from CHANGELOG Update sample runs for SLEPc ex11p Add rc_ex11p to test slepcopts parameter --- CHANGELOG | 4 ---- examples/petsc/CMakeLists.txt | 1 + examples/petsc/ex11p.cpp | 27 ++------------------------- examples/petsc/rc_ex11p | 6 ++++++ 4 files changed, 9 insertions(+), 29 deletions(-) create mode 100644 examples/petsc/rc_ex11p diff --git a/CHANGELOG b/CHANGELOG index 6fe3fdd262..f12f5c6a43 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -101,10 +101,6 @@ New and updated examples and miniapps - Ported example 11p to SLEPc, to demonstrate solving the Laplace eigenvalue equation with the shift-and-invert spectral transformation method. -- Added a new example, Example 28p, to demonstrate the solution of the 2D - Maxwell eigenvalue problem in a dielectric waveguide. This examples shows the - use of the SLEPc eigensolvers with mixed finite elements and block operators. - - Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of stitching together opposite surfaces of a mesh to create a topologically periodic mesh. diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 07216783d6..eaf1d26a8e 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -39,6 +39,7 @@ if (MFEM_USE_SLEPC) ex11p.cpp ) list(APPEND PETSC_RC_FILES + rc_ex11p ) endif() diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index 2e744beec7..a298ab864a 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -2,31 +2,8 @@ // // Compile with: make ex11p // -// Sample runs: mpirun -np 4 ex11p -m ../../data/square-disc.mesh -// mpirun -np 4 ex11p -m ../../data/star.mesh -// mpirun -np 4 ex11p -m ../../data/star-mixed.mesh -// mpirun -np 4 ex11p -m ../../data/escher.mesh -// mpirun -np 4 ex11p -m ../../data/fichera.mesh -// mpirun -np 4 ex11p -m ../../data/fichera-mixed.mesh -// mpirun -np 4 ex11p -m ../../data/toroid-wedge.mesh -o 2 -// mpirun -np 4 ex11p -m ../../data/square-disc-p2.vtk -o 2 -// mpirun -np 4 ex11p -m ../../data/square-disc-p3.mesh -o 3 -// mpirun -np 4 ex11p -m ../../data/square-disc-nurbs.mesh -o -1 -// mpirun -np 4 ex11p -m ../../data/disc-nurbs.mesh -o -1 -n 20 -// mpirun -np 4 ex11p -m ../../data/pipe-nurbs.mesh -o -1 -// mpirun -np 4 ex11p -m ../../data/ball-nurbs.mesh -o 2 -// mpirun -np 4 ex11p -m ../../data/star-surf.mesh -// mpirun -np 4 ex11p -m ../../data/square-disc-surf.mesh -// mpirun -np 4 ex11p -m ../../data/inline-segment.mesh -// mpirun -np 4 ex11p -m ../../data/inline-quad.mesh -// mpirun -np 4 ex11p -m ../../data/inline-tri.mesh -// mpirun -np 4 ex11p -m ../../data/inline-hex.mesh -// mpirun -np 4 ex11p -m ../../data/inline-tet.mesh -// mpirun -np 4 ex11p -m ../../data/inline-wedge.mesh -s 83 -// mpirun -np 4 ex11p -m ../../data/amr-quad.mesh -// mpirun -np 4 ex11p -m ../../data/amr-hex.mesh -// mpirun -np 4 ex11p -m ../../data/mobius-strip.mesh -n 8 -// mpirun -np 4 ex11p -m ../../data/klein-bottle.mesh -n 10 +// Sample runs: mpirun -np 4 ex11p -m ../../data/star.mesh +// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p // // Description: This example code demonstrates the use of MFEM to solve the // eigenvalue problem -Delta u = lambda u with homogeneous diff --git a/examples/petsc/rc_ex11p b/examples/petsc/rc_ex11p new file mode 100644 index 0000000000..21a111b935 --- /dev/null +++ b/examples/petsc/rc_ex11p @@ -0,0 +1,6 @@ +# Options for the eigenvalue solver +-eps_view +-eps_converged_reason +-eps_type gd +# Options for the spectral transform +-st_type precond From 7eee66e015b696013873749837f2d4897820d8a5 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Fri, 19 Jun 2020 17:26:04 -0700 Subject: [PATCH 511/535] Switching to FaceElementTransformations::SetAllIntPoints in applicable integrators --- fem/bilininteg.cpp | 63 +++++++++++++++++++++++++++++----------------- fem/lininteg.cpp | 45 +++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp index f10e14959a..c2f2f887ad 100644 --- a/fem/bilininteg.cpp +++ b/fem/bilininteg.cpp @@ -926,11 +926,14 @@ void BoundaryMassIntegrator::AssembleFaceMatrix( for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); - IntegrationPoint eip; - Trans.Loc1.Transform(ip, eip); + + // Set the integration point in the face and the neighboring element + Trans.SetAllIntPoints(&ip); + + // Access the neighboring element's integration point + const IntegrationPoint &eip = Trans.GetElement1IntPoint(); el1.CalcShape(eip, shape); - Trans.SetIntPoint(&ip); w = Trans.Weight() * ip.weight; if (Q) { @@ -2571,15 +2574,16 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1, for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); - IntegrationPoint eip1, eip2; - Trans.Loc1.Transform(ip, eip1); - if (ndof2) - { - Trans.Loc2.Transform(ip, eip2); - } - el1.CalcShape(eip1, shape1); - Trans.SetIntPoint(&ip); + // Set the integration point in the face and the neighboring elements + Trans.SetAllIntPoints(&ip); + + // Access the neighboring elements' integration points + // Note: eip2 will only contain valid data if Elem2 exists + const IntegrationPoint &eip1 = Trans.GetElement1IntPoint(); + const IntegrationPoint &eip2 = Trans.GetElement2IntPoint(); + + el1.CalcShape(eip1, shape1); u->Eval(vu, *Trans.Elem1, eip1); @@ -2727,10 +2731,15 @@ void DGDiffusionIntegrator::AssembleFaceMatrix( for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); - IntegrationPoint eip1, eip2; - Trans.Loc1.Transform(ip, eip1); - Trans.SetIntPoint(&ip); + // Set the integration point in the face and the neighboring elements + Trans.SetAllIntPoints(&ip); + + // Access the neighboring elements' integration points + // Note: eip2 will only contain valid data if Elem2 exists + const IntegrationPoint &eip1 = Trans.GetElement1IntPoint(); + const IntegrationPoint &eip2 = Trans.GetElement2IntPoint(); + if (dim == 1) { nor(0) = 2*eip1.x - 1.0; @@ -2787,7 +2796,6 @@ void DGDiffusionIntegrator::AssembleFaceMatrix( if (ndof2) { - Trans.Loc2.Transform(ip, eip2); el2.CalcShape(eip2, shape2); el2.CalcDShape(eip2, dshape2); w = ip.weight/2/Trans.Elem2->Weight(); @@ -3005,9 +3013,14 @@ void DGElasticityIntegrator::AssembleFaceMatrix( for (int pind = 0; pind < ir->GetNPoints(); ++pind) { const IntegrationPoint &ip = ir->IntPoint(pind); - IntegrationPoint eip1, eip2; // integration point in the reference space - Trans.Loc1.Transform(ip, eip1); - Trans.SetIntPoint(&ip); + + // Set the integration point in the face and the neighboring elements + Trans.SetAllIntPoints(&ip); + + // Access the neighboring elements' integration points + // Note: eip2 will only contain valid data if Elem2 exists + const IntegrationPoint &eip1 = Trans.GetElement1IntPoint(); + const IntegrationPoint &eip2 = Trans.GetElement2IntPoint(); el1.CalcShape(eip1, shape1); el1.CalcDShape(eip1, dshape1); @@ -3027,7 +3040,6 @@ void DGElasticityIntegrator::AssembleFaceMatrix( double w, wLM; if (ndofs2) { - Trans.Loc2.Transform(ip, eip2); el2.CalcShape(eip2, shape2); el2.CalcDShape(eip2, dshape2); CalcAdjugate(Trans.Elem2->Jacobian(), adjJ); @@ -3165,17 +3177,22 @@ void TraceJumpIntegrator::AssembleFaceMatrix( for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); - IntegrationPoint eip1, eip2; + + // Set the integration point in the face and the neighboring elements + Trans.SetAllIntPoints(&ip); + + // Access the neighboring elements' integration points + // Note: eip2 will only contain valid data if Elem2 exists + const IntegrationPoint &eip1 = Trans.GetElement1IntPoint(); + const IntegrationPoint &eip2 = Trans.GetElement2IntPoint(); + // Trace finite element shape function - Trans.SetIntPoint(&ip); trial_face_fe.CalcShape(ip, face_shape); // Side 1 finite element shape function - Trans.Loc1.Transform(ip, eip1); test_fe1.CalcShape(eip1, shape1); if (ndof2) { // Side 2 finite element shape function - Trans.Loc2.Transform(ip, eip2); test_fe2.CalcShape(eip2, shape2); } w = ip.weight; diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 98dbd6213c..c537691e01 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -112,10 +112,13 @@ void BoundaryLFIntegrator::AssembleRHSElementVect( for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); - IntegrationPoint eip; - Tr.Loc1.Transform(ip, eip); - Tr.Face->SetIntPoint (&ip); + // Set the integration point in the face and the neighboring element + Tr.SetAllIntPoints(&ip); + + // Access the neighboring element's integration point + const IntegrationPoint &eip = Tr.GetElement1IntPoint(); + double val = Tr.Face->Weight() * ip.weight * Q.Eval(*Tr.Face, ip); el.CalcShape(eip, shape); @@ -313,10 +316,12 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect( for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); - IntegrationPoint eip; - Tr.Loc1.Transform(ip, eip); - Tr.SetIntPoint(&ip); + // Set the integration point in the face and the neighboring element + Tr.SetAllIntPoints(&ip); + + // Access the neighboring element's integration point + const IntegrationPoint &eip = Tr.GetElement1IntPoint(); // Use Tr transformation in case Q depends on boundary attribute Q.Eval(vec, Tr, ip); @@ -522,11 +527,13 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect( for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); - IntegrationPoint eip; - Tr.Loc1.Transform(ip, eip); - el.CalcShape(eip, shape); - Tr.SetIntPoint(&ip); + // Set the integration point in the face and the neighboring element + Tr.SetAllIntPoints(&ip); + + // Access the neighboring element's integration point + const IntegrationPoint &eip = Tr.GetElement1IntPoint(); + el.CalcShape(eip, shape); // Use Tr.Elem1 transformation for u so that it matches the coefficient // used with the ConvectionIntegrator and/or the DGTraceIntegrator. @@ -592,10 +599,13 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); - IntegrationPoint eip; - Tr.Loc1.Transform(ip, eip); - Tr.SetIntPoint(&ip); + // Set the integration point in the face and the neighboring element + Tr.SetAllIntPoints(&ip); + + // Access the neighboring element's integration point + const IntegrationPoint &eip = Tr.GetElement1IntPoint(); + if (dim == 1) { nor(0) = 2*eip.x - 1.0; @@ -686,9 +696,12 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( for (int pi = 0; pi < ir->GetNPoints(); ++pi) { const IntegrationPoint &ip = ir->IntPoint(pi); - IntegrationPoint eip; - Tr.Loc1.Transform(ip, eip); - Tr.SetIntPoint(&ip); + + // Set the integration point in the face and the neighboring element + Tr.SetAllIntPoints(&ip); + + // Access the neighboring element's integration point + const IntegrationPoint &eip = Tr.GetElement1IntPoint(); // Evaluate the Dirichlet b.c. using the face transformation. uD.Eval(u_dir, Tr, ip); From a25138e61179753291e0a128a94fae4e540e2bf9 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 19 Jun 2020 20:43:47 -0700 Subject: [PATCH 512/535] Add an optional output stream parameter to the new method FaceElementTransformations::CheckConsistency and improved its documentation. Extended Mesh::GetFaceGeometryType to support ghost child faces and use this to generalize ParFiniteElementSpace::GetFaceNbrFaceFE to support all face types. Cleanup some old and debug code. --- fem/eltrans.cpp | 21 ++++++++++--------- fem/eltrans.hpp | 24 +++++++++++++++++----- fem/pfespace.cpp | 13 ++++++------ mesh/mesh.cpp | 53 ++++++++++++++++++++---------------------------- mesh/mesh.hpp | 4 +--- mesh/pmesh.cpp | 33 +++--------------------------- 6 files changed, 63 insertions(+), 85 deletions(-) diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index 02b302550d..ed7c3913d3 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -624,7 +624,8 @@ void FaceElementTransformations::Transform(const DenseMatrix &matrix, IsoparametricTransformation::Transform(matrix, result); } -double FaceElementTransformations::CheckConsistency(int print_level) +double FaceElementTransformations::CheckConsistency(int print_level, + std::ostream &out) { // Check that the face vertices are mapped to the same physical location // when using the following three transformations: @@ -652,9 +653,9 @@ double FaceElementTransformations::CheckConsistency(int print_level) Transform(v_ir, coords_base); if (print_level > 0) { - mfem::out << "\nface vertex coordinates (from face transform):\n" - << "----------------------------------------------\n"; - coords_base.PrintT(mfem::out, coords_base.Height()); + out << "\nface vertex coordinates (from face transform):\n" + << "----------------------------------------------\n"; + coords_base.PrintT(out, coords_base.Height()); } } if (have_el1) @@ -663,9 +664,9 @@ double FaceElementTransformations::CheckConsistency(int print_level) Elem1->Transform(v_eir, coords_el); if (print_level > 0) { - mfem::out << "\nface vertex coordinates (from element 1 transform):\n" - << "---------------------------------------------------\n"; - coords_el.PrintT(mfem::out, coords_el.Height()); + out << "\nface vertex coordinates (from element 1 transform):\n" + << "---------------------------------------------------\n"; + coords_el.PrintT(out, coords_el.Height()); } if (have_face) { @@ -684,9 +685,9 @@ double FaceElementTransformations::CheckConsistency(int print_level) Elem2->Transform(v_eir, coords_el); if (print_level > 0) { - mfem::out << "\nface vertex coordinates (from element 2 transform):\n" - << "---------------------------------------------------\n"; - coords_el.PrintT(mfem::out, coords_el.Height()); + out << "\nface vertex coordinates (from element 2 transform):\n" + << "---------------------------------------------------\n"; + coords_el.PrintT(out, coords_el.Height()); } coords_el -= coords_base; coords_el.Norm2(dist); diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index e7cffc1f82..d8afba6b55 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -493,11 +493,25 @@ public: IntegrationPointTransformation & GetIntPoint1Transformation(); IntegrationPointTransformation & GetIntPoint2Transformation(); - /** @brief Check for self-consistency. Returns a maximal distance between - physical points that should coincide. A successful check should return - a small number relative to the mesh extents. */ - /** @note This check will generally fail on periodic boundary faces. */ - double CheckConsistency(int print_level = 0); + /** @brief Check for self-consistency: compares the result of mapping the + reference face vertices to physical coordinates using the three + transformations: face, element 1, and element 2. + + @param[in] print_level If set to a positive number, print the physical + coordinates of the face vertices computed through + all available transformations: face, element 1, + and/or element 2. + @param[in,out] out The output stream to use for printing. + + @returns A maximal distance between physical coordinates of face vertices + that should coincide. A successful check should return a small + number relative to the mesh extents. If less than 2 of the three + transformations are set, returns 0. + + @warning This check will generally fail on periodic boundary faces. + */ + double CheckConsistency(int print_level = 0, + std::ostream &out = mfem::out); }; /** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x)) diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp index 2144f8d3c2..1768e2bcaa 100644 --- a/fem/pfespace.cpp +++ b/fem/pfespace.cpp @@ -1172,7 +1172,7 @@ void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array &vdofs) const { // Works for NC mesh where 'i' is an index returned by // ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is - // the index of a ghost. + // the index of a ghost face. MFEM_ASSERT(Nonconforming() && i >= pmesh->GetNumFaces(), ""); int el1, el2, inf1, inf2; pmesh->GetFaceElements(i, &el1, &el2); @@ -1212,13 +1212,14 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFE(int i) const const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const { - // FIXME: triangle faces - + // Works for NC mesh where 'i' is an index returned by + // ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is + // the index of a ghost face. // Works in tandem with GetFaceNbrFaceVDofs() defined above. + MFEM_ASSERT(Nonconforming() && !NURBSext, ""); - Geometry::Type geom = (pmesh->Dimension() == 2) ? - Geometry::SEGMENT : Geometry::SQUARE; - return fec->FiniteElementForGeometry(geom); + Geometry::Type face_geom = pmesh->GetFaceGeometryType(i); + return fec->FiniteElementForGeometry(face_geom); } void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix() diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index 9777e87db2..262408013e 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -911,34 +911,22 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, // NC meshes: prepend slave edge/face transformation to Loc2 if (Nonconforming() && IsSlaveFace(face_info)) { -#if 0 - ApplyLocalSlaveTransformation(FaceElemTr.Loc2.Transf, face_info); - - if (face_type == Element::SEGMENT) - { - // flip Loc2 to match Loc1 and Face - DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat(); - std::swap(pm(0,0), pm(0,1)); - std::swap(pm(1,0), pm(1,1)); - } -#else ApplyLocalSlaveTransformation(FaceElemTr, face_info, false); -#endif } } FaceElemTr.SetConfigurationMask(mask); // This check can be useful for internal debugging, however it will fail on - // periodic boundary faces. -#if 1 + // periodic boundary faces, so we keep it disabled in general. +#if 0 #ifdef MFEM_DEBUG double dist = FaceElemTr.CheckConsistency(); if (dist >= 1e-12) { mfem::out << "\nInternal error: face id = " << FaceNo << ", dist = " << dist << '\n'; - FaceElemTr.CheckConsistency(1); + FaceElemTr.CheckConsistency(1); // print coordinates MFEM_ABORT("internal error"); } #endif @@ -952,19 +940,6 @@ bool Mesh::IsSlaveFace(const FaceInfo &fi) const return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave; } -void Mesh::ApplyLocalSlaveTransformation(IsoparametricTransformation &transf, - const FaceInfo &fi) -{ -#ifdef MFEM_THREAD_SAFE - DenseMatrix composition; -#else - static DenseMatrix composition; -#endif - MFEM_ASSERT(fi.NCFace >= 0, ""); - transf.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition); - transf.SetPointMat(composition); -} - void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT, const FaceInfo &fi, bool is_ghost) { @@ -1046,7 +1021,21 @@ void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const Geometry::Type Mesh::GetFaceGeometryType(int Face) const { - return (Dim == 1) ? Geometry::POINT : faces[Face]->GetGeometryType(); + switch (Dim) + { + case 1: return Geometry::POINT; + case 2: return Geometry::SEGMENT; + case 3: + if (Face < NumOfFaces) // local (non-ghost) face + { + return faces[Face]->GetGeometryType(); + } + // ghost face + const int nc_face_id = faces_info[Face].NCFace; + MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported"); + return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType(); + } + return Geometry::INVALID; } Element::Type Mesh::GetFaceElementType(int Face) const @@ -5319,8 +5308,10 @@ void Mesh::GenerateNCFaceInfo() slave_fi.Elem2No = master_fi.Elem1No; slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above - // NOTE: orientation part of Elem2Inf is encoded in the point matrix; - // the above is not true in 2D. + // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point + // matrix. In 2D, the point matrix has the orientation of the parent + // edge, so its columns need to be flipped when applying it, see + // ApplyLocalSlaveTransformation. } } diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index a8128528d1..dd2c4bcd2f 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -368,11 +368,9 @@ protected: /** Used in GetFaceElementTransformations to account for the fact that a slave face occupies only a portion of its master face. */ - void ApplyLocalSlaveTransformation(IsoparametricTransformation &transf, - const FaceInfo &fi); - /// TODO: Add documentation. void ApplyLocalSlaveTransformation(FaceElementTransformations &FT, const FaceInfo &fi, bool is_ghost); + bool IsSlaveFace(const FaceInfo &fi) const; /// Returns the orientation of "test" relative to "base" diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index 6b48c74c9b..d39beb355a 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -2452,58 +2452,31 @@ GetSharedFaceTransformations(int sf, bool fill2) // adjust Loc1 or Loc2 of the master face if this is a slave face if (is_slave) { -#if 0 - // is a ghost slave? -> master not a ghost -> choose Elem1 local transf - // not a ghost slave? -> master is a ghost -> choose Elem2 local transf - IsoparametricTransformation &loctr = - is_ghost ? FaceElemTr.Loc1.Transf : FaceElemTr.Loc2.Transf; - - if (is_ghost || fill2) - { - ApplyLocalSlaveTransformation(loctr, face_info); - } - - if (face_type == Element::SEGMENT && fill2) - { - // fix slave orientation in 2D: flip Loc2 to match Loc1 and Face - DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat(); - std::swap(pm(0,0), pm(0,1)); - std::swap(pm(1,0), pm(1,1)); - } -#else if (is_ghost || fill2) { // is_ghost -> modify side 1, otherwise -> modify side 2: ApplyLocalSlaveTransformation(FaceElemTr, face_info, is_ghost); } -#endif } // for ghost faces we need a special version of GetFaceTransformation if (is_ghost) { GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom); - -#if 1 - MFEM_ASSERT(is_slave, "internal error"); - mfem::out << "\n[rank " << MyRank << "]: processed child ghost face" - << ", face id = " << FaceNo - << MFEM_LOCATION << std::flush; -#endif } FaceElemTr.SetConfigurationMask(fill2 ? 31 : 21); // This check can be useful for internal debugging, however it will fail on - // periodic boundary faces. -#if 1 + // periodic boundary faces, so we keep it disabled in general. +#if 0 #ifdef MFEM_DEBUG double dist = FaceElemTr.CheckConsistency(); if (dist >= 1e-12) { mfem::out << "\nInternal error: face id = " << FaceNo << ", dist = " << dist << ", rank = " << MyRank << '\n'; - FaceElemTr.CheckConsistency(1); + FaceElemTr.CheckConsistency(1); // print coordinates MFEM_ABORT("internal error"); } #endif From 5f34f7f9a96a456c2f041a1d89f0c56fa9375811 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Mon, 22 Jun 2020 14:08:47 -0700 Subject: [PATCH 513/535] In class FaceElementTransformations, rename the parameter 'ip' in the methods SetIntPoint and SetAllIntPoints to 'face_ip'. In ex18.hpp, use FaceElementTransformations::SetAllIntPoints instead of FaceElementTransformations::SetIntPoint. In class DGDirichletLFIntegrator, evaluate the diffusivity coefficient (Q or MQ) through the volume transformation to support use cases where it is defined based on the volume attributes. --- examples/ex18.hpp | 11 +++-------- fem/eltrans.cpp | 8 ++++---- fem/eltrans.hpp | 11 ++++++----- fem/lininteg.cpp | 4 ++-- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/examples/ex18.hpp b/examples/ex18.hpp index 75fa5e885b..88ed7adadd 100644 --- a/examples/ex18.hpp +++ b/examples/ex18.hpp @@ -88,8 +88,6 @@ private: Vector funval2; Vector nor; Vector fluxN; - IntegrationPoint eip1; - IntegrationPoint eip2; public: FaceIntegrator(RiemannSolver &rsolver_, const int dim); @@ -424,19 +422,16 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, { const IntegrationPoint &ip = ir->IntPoint(i); - Tr.Loc1.Transform(ip, eip1); - Tr.Loc2.Transform(ip, eip2); + Tr.SetAllIntPoints(&ip); // set face and element int. points // Calculate basis functions on both elements at the face - el1.CalcShape(eip1, shape1); - el2.CalcShape(eip2, shape2); + el1.CalcShape(Tr.GetElement1IntPoint(), shape1); + el2.CalcShape(Tr.GetElement2IntPoint(), shape2); // Interpolate elfun at the point elfun1_mat.MultTranspose(shape1, funval1); elfun2_mat.MultTranspose(shape2, funval2); - Tr.SetIntPoint(&ip); - // Get the normal vector and the flux on the face CalcOrtho(Tr.Jacobian(), nor); const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN); diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index 5572962723..9b6f19fe36 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -552,13 +552,13 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1, } } -void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) +void FaceElementTransformations::SetIntPoint(const IntegrationPoint *face_ip) { - IsoparametricTransformation::SetIntPoint(ip); + IsoparametricTransformation::SetIntPoint(face_ip); if (mask & 4) { - Loc1.Transform(*ip, eip1); + Loc1.Transform(*face_ip, eip1); if (Elem1) { Elem1->SetIntPoint(&eip1); @@ -566,7 +566,7 @@ void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip) } if (mask & 8) { - Loc2.Transform(*ip, eip2); + Loc2.Transform(*face_ip, eip2); if (Elem2) { Elem2->SetIntPoint(&eip2); diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 6e37cb9b74..af54b028e7 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -504,14 +504,15 @@ public: mask & 8: Loc2 is configured mask & 16: The Face transformation itself is configured */ - int GetConfigurationMask() const { return mask; } + int GetConfigurationMask() const { return mask; } /** @brief Set the integration point in the Face and the two neighboring elements, if present. - The point @a ip must be in the reference coordinate system of the face. + The point @a face_ip must be in the reference coordinate system of the + face. */ - void SetIntPoint(const IntegrationPoint *ip); + void SetIntPoint(const IntegrationPoint *face_ip); /** @brief Set the integration point in the Face and the two neighboring elements, if present. @@ -520,8 +521,8 @@ public: in this special case, does the same thing. This function can be used for greater code clarity. */ - inline void SetAllIntPoints(const IntegrationPoint *ip) - { FaceElementTransformations::SetIntPoint(ip); } + inline void SetAllIntPoints(const IntegrationPoint *face_ip) + { FaceElementTransformations::SetIntPoint(face_ip); } /** @brief Get a const reference to the integration point in neighboring element 1 corresponding to the currently set integration point on the diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index c537691e01..f9658b881c 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -624,14 +624,14 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect( { if (Q) { - w *= Q->Eval(Tr, ip); + w *= Q->Eval(*Tr.Elem1, eip); } ni.Set(w, nor); } else { nh.Set(w, nor); - MQ->Eval(mq, Tr, ip); + MQ->Eval(mq, *Tr.Elem1, eip); mq.MultTranspose(nh, ni); } CalcAdjugate(Tr.Elem1->Jacobian(), adjJ); From f104e783109450eff0c79e7f694fee58f7160087 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Mon, 22 Jun 2020 15:26:39 -0700 Subject: [PATCH 514/535] Make class ParMesh a friend of class FaceElementTransformations. --- fem/eltrans.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 258f87c38e..6c66a26380 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -460,6 +460,9 @@ private: protected: // interface for Mesh to be able to configure this object. friend class Mesh; +#ifdef MFEM_USE_MPI + friend class ParMesh; +#endif /// Set the mask indicating which portions of the object have been setup /** The argument @a m is a bitmask used in From 68ecd01b9a72c6ef8c68838554eb914ec626163f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-=C3=89tienne=20Tremblay?= Date: Mon, 22 Jun 2020 20:13:10 -0700 Subject: [PATCH 515/535] cmake: Simplify FindSLEPc.cmake make: Source slepcvariables for external libraries (tested with e.g. ARPACK) Both cmake and make: Add test targets for ex11p ex11p: Fix unitialized rc_ex11p_*: add LOBPCG example --- CMakeLists.txt | 3 +- config/cmake/modules/FindSLEPc.cmake | 284 ++--------------------- config/defaults.mk | 10 +- examples/petsc/CMakeLists.txt | 20 +- examples/petsc/ex11p.cpp | 7 +- examples/petsc/makefile | 9 + examples/petsc/{rc_ex11p => rc_ex11p_gd} | 0 examples/petsc/rc_ex11p_lobpcg | 11 + 8 files changed, 71 insertions(+), 273 deletions(-) rename examples/petsc/{rc_ex11p => rc_ex11p_gd} (100%) create mode 100644 examples/petsc/rc_ex11p_lobpcg diff --git a/CMakeLists.txt b/CMakeLists.txt index b88156478c..e407e5f95a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,9 +150,8 @@ if (MFEM_USE_MPI) endif() set(PETSC_INCLUDE_DIRS ${PETSC_INCLUDES}) if (MFEM_USE_SLEPC) - find_package(SLEPc REQUIRED) + find_package(SLEPc REQUIRED config) message(STATUS "Found SLEPc version ${SLEPC_VERSION}") - set(SLEPC_INCLUDE_DIRS ${SLEPC_INCLUDES}) endif() endif() else() diff --git a/config/cmake/modules/FindSLEPc.cmake b/config/cmake/modules/FindSLEPc.cmake index 93ba853fab..fa02139910 100644 --- a/config/cmake/modules/FindSLEPc.cmake +++ b/config/cmake/modules/FindSLEPc.cmake @@ -1,210 +1,31 @@ -# - Try to find SLEPC -# Once done this will define +# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# at the Lawrence Livermore National Laboratory. All Rights reserved. See files +# LICENSE and NOTICE for details. LLNL-CODE-806117. # -# SLEPC_FOUND - system has SLEPc -# SLEPC_INCLUDE_DIR - include directories for SLEPc -# SLEPC_LIBARIES - libraries for SLEPc -# SLEPC_DIR - directory where SLEPc is built -# SLEPC_VERSION - version of SLEPc -# SLEPC_VERSION_MAJOR - First number in SLEPC_VERSION -# SLEPC_VERSION_MINOR - Second number in SLEPC_VERSION -# SLEPC_VERSION_SUBMINOR - Third number in SLEPC_VERSION +# This file is part of the MFEM library. For more information and source code +# availability visit https://mfem.org. # -# Assumes that PETSC_DIR and PETSC_ARCH has been set by -# alredy calling find_package(PETSc) +# MFEM is free software; you can redistribute it and/or modify it under the +# terms of the BSD-3 license. We welcome feedback and contributions, see file +# CONTRIBUTING.md for details. -#============================================================================= -# Copyright (C) 2010-2012 Garth N. Wells, Anders Logg and Johannes Ring -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -#============================================================================= +# Sets the following variables: +# - SLEPC_FOUND +# - SLEPC_INCLUDE_DIRS +# - SLEPC_LIBRARIES -message(STATUS "Checking for package 'SLEPc'") +set(SLEPc_REQUIRED_PACKAGES "PETSC" CACHE STRING + "Additional packages required by SLEPc") -# Set debian_arches (PETSC_ARCH for Debian-style installations) -foreach (debian_arches linux kfreebsd) - if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(DEBIAN_FLAVORS ${debian_arches}-gnu-c-debug ${debian_arches}-gnu-c-opt ${DEBIAN_FLAVORS}) - else() - set(DEBIAN_FLAVORS ${debian_arches}-gnu-c-opt ${debian_arches}-gnu-c-debug ${DEBIAN_FLAVORS}) - endif() -endforeach() - -# List of possible locations for SLEPC_DIR -set(slepc_dir_locations "") -list(APPEND slepc_dir_locations "/usr/lib/slepc") -list(APPEND slepc_dir_locations "/opt/local/lib/petsc") # Macports -list(APPEND slepc_dir_locations "/usr/local/lib/slepc") -list(APPEND slepc_dir_locations "$ENV{HOME}/slepc") - -# Add other possible locations for SLEPC_DIR -set(_SYSTEM_LIB_PATHS "${CMAKE_SYSTEM_LIBRARY_PATH};${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES}") -string(REGEX REPLACE ":" ";" libdirs ${_SYSTEM_LIB_PATHS}) -foreach (libdir ${libdirs}) - get_filename_component(slepc_dir_location "${libdir}/" PATH) - list(APPEND slepc_dir_locations ${slepc_dir_location}) -endforeach() - -# Try to figure out SLEPC_DIR by finding slepc.h -find_path(SLEPC_DIR include/slepc.h - HINTS ${SLEPC_DIR} $ENV{SLEPC_DIR} - PATHS ${slepc_dir_locations} - DOC "SLEPc directory") - -# Report result of search for SLEPC_DIR -if (DEFINED SLEPC_DIR) - message(STATUS "SLEPC_DIR is ${SLEPC_DIR}") -else() - message(STATUS "SLEPC_DIR is empty") -endif() - -# Get variables from SLEPc configuration -if (SLEPC_DIR) - - find_library(SLEPC_LIBRARY - NAMES slepc - HINTS ${SLEPC_DIR}/lib $ENV{SLEPC_DIR}/lib ${SLEPC_DIR}/${PETSC_ARCH}/lib $ENV{SLEPC_DIR}/$ENV{PETSC_ARCH}/lib - NO_DEFAULT_PATH - DOC "The SLEPc library") - find_library(SLEPC_LIBRARY - NAMES slepc - DOC "The SLEPc library") - mark_as_advanced(SLEPC_LIBRARY) - - # Find SLEPc config file - find_file(SLEPC_CONFIG_FILE NAMES slepc_common PATHS - ${SLEPC_DIR}/lib/slepc/conf - ${SLEPC_DIR}/lib/slepc-conf ${SLEPC_DIR}/conf) - - # Create a temporary Makefile to probe the SLEPc configuration - set(slepc_config_makefile ${PROJECT_BINARY_DIR}/Makefile.slepc) - file(WRITE ${slepc_config_makefile} -"# This file was autogenerated by FindSLEPc.cmake -SLEPC_DIR = ${SLEPC_DIR} -PETSC_ARCH = ${PETSC_ARCH} -PETSC_DIR = ${PETSC_DIR} -include ${SLEPC_CONFIG_FILE} -show : - -@echo -n \${\${VARIABLE}} -") - - # Define macro for getting SLEPc variables from Makefile - macro(SLEPC_GET_VARIABLE var name) - set(${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) - execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} --no-print-directory -f ${slepc_config_makefile} show VARIABLE=${name} - OUTPUT_VARIABLE ${var} - RESULT_VARIABLE slepc_return) - endmacro() - - # Call macro to get the SLEPc variables - slepc_get_variable(SLEPC_INCLUDE SLEPC_INCLUDE) - slepc_get_variable(SLEPC_EXTERNAL_LIB SLEPC_EXTERNAL_LIB) - - # Remove temporary Makefile - file(REMOVE ${slepc_config_makefile}) - - # Extract include paths and libraries from compile command line - include(ResolveCompilerPaths) - resolve_includes(SLEPC_INCLUDE_DIRS "${SLEPC_INCLUDE}") - resolve_libraries(SLEPC_EXTERNAL_LIBRARIES "${SLEPC_EXTERNAL_LIB}") - - # Add variables to CMake cache and mark as advanced - set(SLEPC_INCLUDE_DIRS ${SLEPC_INCLUDE_DIRS} CACHE STRING "SLEPc include paths." FORCE) - set(SLEPC_LIBRARIES ${SLEPC_LIBRARY} CACHE STRING "SLEPc libraries." FORCE) - mark_as_advanced(SLEPC_INCLUDE_DIRS SLEPC_LIBRARIES) -endif() - -if (DOLFIN_SKIP_BUILD_TESTS) - set(SLEPC_TEST_RUNS TRUE) - set(SLEPC_VERSION "UNKNOWN") - set(SLEPC_VERSION_OK TRUE) -elseif (SLEPC_LIBRARIES AND SLEPC_INCLUDE_DIRS) - - # Set flags for building test program - set(CMAKE_REQUIRED_INCLUDES ${SLEPC_INCLUDE_DIRS} ${PETSC_INCLUDE_DIRS}) - set(CMAKE_REQUIRED_LIBRARIES ${SLEPC_LIBRARIES} ${PETSC_LIBRARIES}) - - # Add MPI variables if MPI has been found - if (MPI_C_FOUND) - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MPI_C_INCLUDE_PATH}) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${MPI_C_LIBRARIES}) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${MPI_C_COMPILE_FLAGS}") - endif() - - # Check SLEPc version - set(SLEPC_CONFIG_TEST_VERSION_CPP - "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/slepc_config_test_version.cpp") - file(WRITE ${SLEPC_CONFIG_TEST_VERSION_CPP} " -#include -#include \"slepcversion.h\" - -int main() { - std::cout << SLEPC_VERSION_MAJOR << \".\" - << SLEPC_VERSION_MINOR << \".\" - << SLEPC_VERSION_SUBMINOR; - return 0; -} -") - - try_run( - SLEPC_CONFIG_TEST_VERSION_EXITCODE - SLEPC_CONFIG_TEST_VERSION_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${SLEPC_CONFIG_TEST_VERSION_CPP} - CMAKE_FLAGS - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" - COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT - RUN_OUTPUT_VARIABLE OUTPUT - ) - - if (SLEPC_CONFIG_TEST_VERSION_EXITCODE EQUAL 0) - set(SLEPC_VERSION ${OUTPUT} CACHE STRING STRING) - string(REPLACE "." ";" SLEPC_VERSION_LIST ${SLEPC_VERSION}) - list(GET SLEPC_VERSION_LIST 0 SLEPC_VERSION_MAJOR) - list(GET SLEPC_VERSION_LIST 1 SLEPC_VERSION_MINOR) - list(GET SLEPC_VERSION_LIST 2 SLEPC_VERSION_SUBMINOR) - mark_as_advanced(SLEPC_VERSION) - mark_as_advanced(SLEPC_VERSION_MAJOR, SLEPC_VERSION_MINOR, SLEPC_VERSION_SUBMINOR) - endif() - - if (SLEPc_FIND_VERSION) - # Check if version found is >= required version - if (NOT "${SLEPC_VERSION}" VERSION_LESS "${SLEPc_FIND_VERSION}") - set(SLEPC_VERSION_OK TRUE) - endif() - else() - # No specific version requested - set(SLEPC_VERSION_OK TRUE) - endif() - mark_as_advanced(SLEPC_VERSION_OK) - - # Run SLEPc test program - set(SLEPC_TEST_LIB_CPP - "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/slepc_test_lib.cpp") - file(WRITE ${SLEPC_TEST_LIB_CPP} " +include(MfemCmakeUtilities) +mfem_find_package(SLEPc SLEPC SLEPC_DIR + "include" "slepceps.h" + "${PETSC_ARCH}/lib" "slepc" # add NAMES_PER_DIR? + "Paths to headers required by SLEPc." + "Libraries required by SLEPc." + ADD_COMPONENT "config" "${PETSC_ARCH}/include" "slepcconf.h" "" "" + CHECK_BUILD SLEPC_VERSION_OK TRUE +" #include \"petsc.h\" #include \"slepceps.h\" int main() @@ -215,64 +36,9 @@ int main() ierr = SlepcInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL); EPS eps; ierr = EPSCreate(PETSC_COMM_SELF, &eps); CHKERRQ(ierr); - //ierr = EPSSetFromOptions(eps); CHKERRQ(ierr); -#if PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR <= 1 - ierr = EPSDestroy(eps); CHKERRQ(ierr); -#else ierr = EPSDestroy(&eps); CHKERRQ(ierr); -#endif ierr = SlepcFinalize(); CHKERRQ(ierr); return 0; } -") - - try_run( - SLEPC_TEST_LIB_EXITCODE - SLEPC_TEST_LIB_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${SLEPC_TEST_LIB_CPP} - CMAKE_FLAGS - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}" - COMPILE_OUTPUT_VARIABLE SLEPC_TEST_LIB_COMPILE_OUTPUT - RUN_OUTPUT_VARIABLE SLEPC_TEST_LIB_OUTPUT - ) - - if (SLEPC_TEST_LIB_COMPILED AND SLEPC_TEST_LIB_EXITCODE EQUAL 0) - message(STATUS "Performing test SLEPC_TEST_RUNS - Success") - set(SLEPC_TEST_RUNS TRUE) - else() - message(STATUS "Performing test SLEPC_TEST_RUNS - Failed") - - # Test program does not run - try adding SLEPc 3rd party libs and test again - list(APPEND CMAKE_REQUIRED_LIBRARIES ${SLEPC_EXTERNAL_LIBRARIES}) - - try_run( - SLEPC_TEST_3RD_PARTY_LIBS_EXITCODE - SLEPC_TEST_3RD_PARTY_LIBS_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${SLEPC_TEST_LIB_CPP} - CMAKE_FLAGS - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}" - COMPILE_OUTPUT_VARIABLE SLEPC_TEST_3RD_PARTY_LIBS_COMPILE_OUTPUT - RUN_OUTPUT_VARIABLE SLEPC_TEST_3RD_PARTY_LIBS_OUTPUT - ) - - if (SLEPC_TEST_3RD_PARTY_LIBS_COMPILED AND SLEPC_TEST_3RD_PARTY_LIBS_EXITCODE EQUAL 0) - message(STATUS "Performing test SLEPC_TEST_3RD_PARTY_LIBS_RUNS - Success") - set(SLEPC_LIBRARIES ${SLEPC_LIBRARIES} ${SLEPC_EXTERNAL_LIBRARIES} - CACHE STRING "SLEPc libraries." FORCE) - set(SLEPC_TEST_RUNS TRUE) - else() - message(STATUS "Performing test SLEPC_TEST_3RD_PARTY_LIBS_RUNS - Failed") - endif() - endif() -endif() - -# Standard package handling -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SLEPc - "SLEPc could not be found. Be sure to set SLEPC_DIR, PETSC_DIR, and PETSC_ARCH." - SLEPC_LIBRARIES SLEPC_DIR SLEPC_INCLUDE_DIRS SLEPC_TEST_RUNS - SLEPC_VERSION SLEPC_VERSION_OK) +" + ) diff --git a/config/defaults.mk b/config/defaults.mk index 323c9b07c8..2c4b027be7 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -283,10 +283,12 @@ SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,) SLEPC_INC_VAR = SLEPC_INCLUDE SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB ifeq ($(SLEPC_FOUND),YES) - SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS)) - SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS)) - SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\ - -L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB) + SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS)) + # Some additional external libraries might be defined in this file + -include ${SLEPC_DIR}/${PETSC_ARCH}/lib/slepc/conf/slepcvariables + SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS)) + SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\ + -L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB) endif # MPFR library configuration diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index eaf1d26a8e..66b8f7839c 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -39,7 +39,7 @@ if (MFEM_USE_SLEPC) ex11p.cpp ) list(APPEND PETSC_RC_FILES - rc_ex11p + rc_ex11p_lobpcg rc_ex11p_gd ) endif() @@ -87,12 +87,22 @@ set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step) set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5) set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3) +if (MFEM_USE_SLEPC) + set(EX11_ARGS_SINV -m ../../data/star.mesh --useslepc) + set(EX11_ARGS_LOBPCG -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg) + set(EX11_ARGS_GD -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd) +endif() # Add the tests: one test per command-line-variable. -foreach(TEST_OPTIONS_VAR - EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS - EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS - EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS) +set(TEST_OPTIONS_VARS + EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS + EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS + EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS) +if (MFEM_USE_SLEPC) + list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD) +endif() + +foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS}) string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR}) string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC}) string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL) diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index a298ab864a..4ea735abad 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -3,7 +3,8 @@ // Compile with: make ex11p // // Sample runs: mpirun -np 4 ex11p -m ../../data/star.mesh -// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p +// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p_lobpcg +// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p_gd // // Description: This example code demonstrates the use of MFEM to solve the // eigenvalue problem -Delta u = lambda u with homogeneous @@ -278,8 +279,8 @@ int main(int argc, char *argv[]) } } - HypreLOBPCG * lobpcg; - SlepcEigenSolver * slepc; + HypreLOBPCG * lobpcg = NULL; + SlepcEigenSolver * slepc = NULL; if (!use_slepc) { diff --git a/examples/petsc/makefile b/examples/petsc/makefile index 32900a6230..93a68188d9 100644 --- a/examples/petsc/makefile +++ b/examples/petsc/makefile @@ -90,6 +90,9 @@ EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p EX10_MF_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3 EX10_MFOP_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mfop -tf 6 -s 3 -rs 0 -dt 3 EX10_JFNK_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3 +EX11_ARGS_SINV := -m ../../data/star.mesh --useslepc +EX11_ARGS_LOBPCG := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg +EX11_ARGS_GD := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd ex1p-test-par: ex1p @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W)) @@ -117,6 +120,12 @@ ex10p-test-par: ex10p @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MF_ARGS)) @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MFOP_ARGS)) @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_JFNK_ARGS)) +ifeq ($(MFEM_USE_SLEPC),YES) +ex11p-test-par: ex11p + @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_SINV)) + @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG)) + @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_GD)) +endif # Testing: "test" target and mfem-test* variables are defined in config/test.mk diff --git a/examples/petsc/rc_ex11p b/examples/petsc/rc_ex11p_gd similarity index 100% rename from examples/petsc/rc_ex11p rename to examples/petsc/rc_ex11p_gd diff --git a/examples/petsc/rc_ex11p_lobpcg b/examples/petsc/rc_ex11p_lobpcg new file mode 100644 index 0000000000..57440caab0 --- /dev/null +++ b/examples/petsc/rc_ex11p_lobpcg @@ -0,0 +1,11 @@ +# Options for the eigenvalue solver +-eps_monitor +-eps_converged_reason +-eps_view_values +-eps_type lobpcg +-eps_gen_hermitian +-eps_smallest_real +-eps_lobpcg_blocksize 5 +# Options for the spectral transform +-st_type precond +-st_pc_type gamg From d533b98501055bc6be0ff029fc2b32837b2456d1 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 23 Jun 2020 20:53:02 -0700 Subject: [PATCH 516/535] Revert "In tests/unit/fem/test_get_value.cpp, add constexpr to some" This reverts commit 23078ff76ca9cfc45bed770bc08ad006a7d85a0f. --- tests/unit/fem/test_get_value.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 76eccc3e02..55d2597a2f 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -287,7 +287,7 @@ TEST_CASE("2D GetValue", { int log = 1; int n = 1; - constexpr int dim = 2; + int dim = 2; int order = 1; int npts = 0; @@ -560,7 +560,7 @@ TEST_CASE("3D GetValue", { int log = 1; int n = 1; - constexpr int dim = 3; + int dim = 3; int order = 1; int npts = 0; @@ -872,7 +872,7 @@ TEST_CASE("2D GetVectorValue", { int log = 1; int n = 1; - constexpr int dim = 2; + int dim = 2; int order = 1; int npts = 0; @@ -1312,7 +1312,7 @@ TEST_CASE("3D GetVectorValue", { int log = 1; int n = 1; - constexpr int dim = 3; + int dim = 3; int order = 1; int npts = 0; From 8798a933f30a4ff9d365a0f268baf91bbb487c68 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Thu, 25 Jun 2020 01:17:30 -0700 Subject: [PATCH 517/535] Add support for 64bit HYPRE_Int in HypreParMatrixFromBlocks() and GatherBlockOffsetData(). Add overflow check in GatherBlockOffsetData(). In the SuperLURowLocMatrix constructor from HypreParMatrix, remove the check for the number of columns and add a note why it is not necessary at the moment. Add a compile-time check when building with SuperLU_DIST support that HYPRE_Int is int which is required by the current implementation. --- linalg/hypre.cpp | 54 ++++++++++++++---------------- linalg/hypre.hpp | 2 +- linalg/superlu.cpp | 11 ++++-- tests/unit/miniapps/test_sedov.cpp | 2 +- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index 7ddc8ffdda..8dfe77631f 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -20,7 +20,6 @@ #include #include #include -#include // INT_MAX using namespace std; @@ -1668,12 +1667,12 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A, // Helper function for HypreParMatrixFromBlocks. Note that scalability to // extremely large processor counts is limited by the use of MPI_Allgather. void GatherBlockOffsetData(MPI_Comm comm, const int rank, const int nprocs, - const int num_loc, Array &offsets, + const int num_loc, const Array &offsets, std::vector &all_num_loc, const int numBlocks, - std::vector> &blockProcOffsets, - std::vector &procOffsets, + std::vector> &blockProcOffsets, + std::vector &procOffsets, std::vector> &procBlockOffsets, - int &firstLocal, int &globalNum) + HYPRE_Int &firstLocal, HYPRE_Int &globalNum) { std::vector> all_block_num_loc(numBlocks); @@ -1701,6 +1700,10 @@ void GatherBlockOffsetData(MPI_Comm comm, const int rank, const int nprocs, for (int i = 0; i < nprocs; ++i) { globalNum += all_num_loc[i]; + if (rank == 0) + { + MFEM_VERIFY(globalNum >= 0, "overflow in global size"); + } if (i < rank) { firstLocal += all_num_loc[i]; @@ -1809,14 +1812,14 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, std::vector all_num_loc_rows(nprocs); std::vector all_num_loc_cols(nprocs); - std::vector procRowOffsets(nprocs); - std::vector procColOffsets(nprocs); - std::vector> blockRowProcOffsets(numBlockRows); - std::vector> blockColProcOffsets(numBlockCols); + std::vector procRowOffsets(nprocs); + std::vector procColOffsets(nprocs); + std::vector> blockRowProcOffsets(numBlockRows); + std::vector> blockColProcOffsets(numBlockCols); std::vector> procBlockRowOffsets(nprocs); std::vector> procBlockColOffsets(nprocs); - int first_loc_row, glob_nrows, first_loc_col, glob_ncols; + HYPRE_Int first_loc_row, glob_nrows, first_loc_col, glob_ncols; GatherBlockOffsetData(comm, rank, nprocs, num_loc_rows, rowOffsets, all_num_loc_rows, numBlockRows, blockRowProcOffsets, procRowOffsets, procBlockRowOffsets, first_loc_row, @@ -1851,18 +1854,7 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, } else { - { - hypre_ParCSRMatrix *parcsr_op = (hypre_ParCSRMatrix*) - const_cast - (*(blocks(i, j))); - MFEM_ASSERT(parcsr_op != NULL, "const_cast failed"); - csr_blocks(i, j) = hypre_MergeDiagAndOffd(parcsr_op); -#if MFEM_HYPRE_VERSION >= 21600 - MFEM_VERIFY(csr_blocks(i, j)->big_j != NULL || - csr_blocks(i, j)->num_cols < INT_MAX,"Number of " - "columns is too large to store as an integer."); -#endif - } + csr_blocks(i, j) = hypre_MergeDiagAndOffd(*blocks(i, j)); for (int k = 0; k < csr_blocks(i, j)->num_rows; ++k) { @@ -1907,13 +1899,16 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, { // Find the column process offset for the block. #if MFEM_HYPRE_VERSION >= 21600 - const int bcol = usingBigJ ? csr_blocks(i, j)->big_j[osk + l] - : csr_blocks(i, j)->j[osk + l]; + const HYPRE_Int bcol = usingBigJ ? + csr_blocks(i, j)->big_j[osk + l] : + csr_blocks(i, j)->j[osk + l]; #else - const int bcol = csr_blocks(i, j)->j[osk + l]; + const HYPRE_Int bcol = csr_blocks(i, j)->j[osk + l]; #endif int bcolproc = 0; + // TODO: use binary search to find bcolproc, e.g. using + // std::upper_bound. for (int p = 1; p < nprocs; ++p) { if (blockColProcOffsets[j][p] > bcol) @@ -1958,11 +1953,12 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, colStarts2[0] = first_loc_col; colStarts2[1] = first_loc_col + all_num_loc_cols[rank]; + MFEM_VERIFY(HYPRE_AssumedPartitionCheck(), + "only 'assumed partition' mode is supported"); + return new HypreParMatrix(comm, num_loc_rows, glob_nrows, glob_ncols, - (int *)opI.data(), (HYPRE_Int *)opJ.data(), - (double *)data.data(), - (HYPRE_Int *)rowStarts2.data(), - (HYPRE_Int *)colStarts2.data()); + opI.data(), opJ.data(), data.data(), + rowStarts2.data(), colStarts2.data()); } void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae, diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp index b742825bcd..b098865ac8 100644 --- a/linalg/hypre.hpp +++ b/linalg/hypre.hpp @@ -577,7 +577,7 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A, each process remain on that process in the resulting matrix. Some blocks can be NULL. Each block and the entire system can be rectangular. Scalability to extremely large processor counts is limited by global MPI communication, see - GatherBlockOffsetData in hypre.cpp. */ + GatherBlockOffsetData() in hypre.cpp. */ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, Array2D *blockCoeff=NULL); diff --git a/linalg/superlu.cpp b/linalg/superlu.cpp index bb6b438275..04877e87d2 100644 --- a/linalg/superlu.cpp +++ b/linalg/superlu.cpp @@ -24,6 +24,11 @@ #error "SuperLUDist has been built with 64bit integers. This is not supported" #endif +// For now, it is assumed that HYPRE_Int is int. +#ifdef HYPRE_BIGINT +#error "SuperLUDist support requires HYPRE_Int == int, for now." +#endif + using namespace std; namespace mfem @@ -135,8 +140,10 @@ SuperLURowLocMatrix::SuperLURowLocMatrix( const HypreParMatrix & hypParMat ) hypre_CSRMatrix * csr_op = hypre_MergeDiagAndOffd(parcsr_op); hypre_CSRMatrixSetDataOwner(csr_op,0); #if MFEM_HYPRE_VERSION >= 21600 - MFEM_VERIFY(csr_blocks(i, j)->big_j != NULL || csr_op->num_cols < INT_MAX, - "SuperLU: number of columns is too large to store as an integer."); + // For now, this method assumes that HYPRE_Int is int. Also, csr_op->num_cols + // is of type HYPRE_Int, so if we want to check for big indices in + // csr_op->big_j, we'll have to check all entries and that check will only be + // necessary in HYPRE_MIXEDINT mode which is not supported at the moment. hypre_CSRMatrixBigJtoJ(csr_op); #endif diff --git a/tests/unit/miniapps/test_sedov.cpp b/tests/unit/miniapps/test_sedov.cpp index 9f5410feae..14d825c9c4 100644 --- a/tests/unit/miniapps/test_sedov.cpp +++ b/tests/unit/miniapps/test_sedov.cpp @@ -26,7 +26,7 @@ extern mfem::MPI_Session *GlobalMPISession; #define PFesGetParMeshGetComm(pfes) pfes.GetParMesh()->GetComm() #define PFesGetParMeshGetComm0(pfes) pfes.GetParMesh()->GetComm() #else -typedef int HYPRE_Int; +#define HYPRE_Int int typedef int MPI_Session; #define ParMesh Mesh #define GetParMesh GetMesh From c0e8b29d07de87957aff7e51dc130831de1c89c6 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Thu, 25 Jun 2020 02:15:16 -0700 Subject: [PATCH 518/535] Add test runs with SuperLU_DIST when it is enabled. --- examples/CMakeLists.txt | 13 +++++++++++-- examples/makefile | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6e7afdc1ad..6f5a1de336 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -91,7 +91,7 @@ foreach(SRC_FILE ${ALL_EXE_SRCS}) add_test(NAME ${TEST_NAME}_ser COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS}) else() - add_test(NAME ${TEST_NAME}_np=4 + add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP} COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} ${MPIEXEC_PREFLAGS} $ ${THIS_TEST_OPTIONS} @@ -101,13 +101,22 @@ endforeach() # If STRUMPACK is enabled, add a test run that uses it. if (MFEM_USE_STRUMPACK) - add_test(NAME ex11p_strumpack_np=4 + add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP} COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} ${MPIEXEC_PREFLAGS} $ "-no-vis" "--strumpack" ${MPIEXEC_POSTFLAGS}) endif() +# If SuperLU_DIST is enabled, add a test run that uses it. +if (MFEM_USE_SUPERLU) + add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP} + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} + ${MPIEXEC_PREFLAGS} + $ "-no-vis" "--superlu" + ${MPIEXEC_POSTFLAGS}) +endif() + # Include the examples/sundials directory if SUNDIALS is enabled. if (MFEM_USE_SUNDIALS) add_subdirectory(sundials) diff --git a/examples/makefile b/examples/makefile index 5e677a5529..8b402a49a6 100644 --- a/examples/makefile +++ b/examples/makefile @@ -114,6 +114,11 @@ ex11p-test-strumpack: ex11p @$(call mfem-test,$<, $(RUN_MPI), STRUMPACK example,--strumpack) test-par-YES: ex11p-test-strumpack endif +ifeq ($(MFEM_USE_SUPERLU),YES) +ex11p-test-superlu: ex11p + @$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu) +test-par-YES: ex11p-test-superlu +endif # Testing: "test" target and mfem-test* variables are defined in config/test.mk From 63abc65aa09179f425bf479aea9ac8a498802aee Mon Sep 17 00:00:00 2001 From: Yohann Dudouit Date: Thu, 25 Jun 2020 15:19:36 -0700 Subject: [PATCH 519/535] Use cuda-shared in ex1p to avoid differences in autotest. --- examples/ex1p.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp index 649ecbf117..d0000e6cc9 100644 --- a/examples/ex1p.cpp +++ b/examples/ex1p.cpp @@ -32,7 +32,8 @@ // mpirun -np 4 ex1p -pa -d occa-cuda // mpirun -np 4 ex1p -pa -d raja-omp // mpirun -np 4 ex1p -pa -d ceed-cpu -// mpirun -np 4 ex1p -pa -d ceed-cuda +// * mpirun -np 4 ex1p -pa -d ceed-cuda +// mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared // mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu // // Description: This example code demonstrates the use of MFEM to define a From 9b73c3c47bba225675112dd66c58bd94a81dfe87 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Thu, 25 Jun 2020 20:32:44 -0700 Subject: [PATCH 520/535] In HypreParMatrixFromBlocks, use O(log(P)) binary search instead of O(P) linear search, where P is the number of processors. --- linalg/hypre.cpp | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index 0e1bdc1ab9..65a4c81c0d 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1905,22 +1905,12 @@ HypreParMatrix * HypreParMatrixFromBlocks(Array2D &blocks, #else const HYPRE_Int bcol = csr_blocks(i, j)->j[osk + l]; #endif - int bcolproc = 0; - // TODO: use binary search to find bcolproc, e.g. using - // std::upper_bound. - for (int p = 1; p < nprocs; ++p) - { - if (blockColProcOffsets[j][p] > bcol) - { - bcolproc = p - 1; - break; - } - } - if (blockColProcOffsets[j][nprocs - 1] <= bcol) - { - bcolproc = nprocs - 1; - } + // find the processor 'bcolproc' that holds column 'bcol': + const auto &offs = blockColProcOffsets[j]; + const int bcolproc = + std::upper_bound(offs.begin() + 1, offs.end(), bcol) + - offs.begin() - 1; opJ[opI[rowg] + cnt[rowg]] = procColOffsets[bcolproc] + procBlockColOffsets[bcolproc][j] From ab019493f2a097c79b5c8d97ab9585b9bfb13263 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Fri, 26 Jun 2020 17:53:00 -0700 Subject: [PATCH 521/535] Fix integration issue with the concurrent PR #1429. --- tests/unit/fem/test_get_value.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 98395ead04..00092d4a32 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -414,7 +414,7 @@ TEST_CASE("1D GetValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No; + int e = FET->Elem2No - pmesh.GetNE(); const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); @@ -802,7 +802,7 @@ TEST_CASE("2D GetValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No; + int e = FET->Elem2No - pmesh.GetNE(); const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); @@ -1232,7 +1232,7 @@ TEST_CASE("3D GetValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No; + int e = FET->Elem2No - pmesh.GetNE(); const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); @@ -1823,7 +1823,7 @@ TEST_CASE("2D GetVectorValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No; + int e = FET->Elem2No - pmesh.GetNE(); const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); @@ -2532,7 +2532,7 @@ TEST_CASE("3D GetVectorValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No; + int e = FET->Elem2No - pmesh.GetNE(); const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); From ea7495b5a6f4b5ba6e825e9493f34fe8bce9683f Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sat, 27 Jun 2020 18:03:41 -0700 Subject: [PATCH 522/535] Small adjustment in CHANGELOG --- CHANGELOG | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1549e2ba00..bdd851e097 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -109,8 +109,9 @@ New and updated examples and miniapps for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG discretizations. -- Added a new miniapp, navier, that solves the time-dependent Navier-Stokes - equations of incompressible fluid dynamics. +- Added a new miniapp, Navier, that solves the time-dependent Navier-Stokes + equations of incompressible fluid dynamics. See the miniapps/navier directory + for more details. - Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of stitching together opposite surfaces of a mesh to create a topologically From 4a2449d87f55444cf55b1f2e8da170227f267128 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sat, 27 Jun 2020 18:15:43 -0700 Subject: [PATCH 523/535] Small adjustment in ceed-cuda skipped sample runs --- examples/ex1p.cpp | 2 +- examples/ex6.cpp | 2 +- examples/ex6p.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp index d0000e6cc9..759b73cd79 100644 --- a/examples/ex1p.cpp +++ b/examples/ex1p.cpp @@ -32,7 +32,7 @@ // mpirun -np 4 ex1p -pa -d occa-cuda // mpirun -np 4 ex1p -pa -d raja-omp // mpirun -np 4 ex1p -pa -d ceed-cpu -// * mpirun -np 4 ex1p -pa -d ceed-cuda +// * mpirun -np 4 ex1p -pa -d ceed-cuda // mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared // mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu // diff --git a/examples/ex6.cpp b/examples/ex6.cpp index 991d216454..e189e6f6ea 100644 --- a/examples/ex6.cpp +++ b/examples/ex6.cpp @@ -20,7 +20,7 @@ // ex6 -pa -d occa-cuda // ex6 -pa -d raja-omp // ex6 -pa -d ceed-cpu -// * ex6 -pa -d ceed-cuda +// * ex6 -pa -d ceed-cuda // ex6 -pa -d ceed-cuda:/gpu/cuda/shared // // Description: This is a version of Example 1 with a simple adaptive mesh diff --git a/examples/ex6p.cpp b/examples/ex6p.cpp index 072e9a0cd6..0bbc8eec9f 100644 --- a/examples/ex6p.cpp +++ b/examples/ex6p.cpp @@ -20,7 +20,7 @@ // mpirun -np 4 ex6p -pa -d occa-cuda // mpirun -np 4 ex6p -pa -d raja-omp // mpirun -np 4 ex6p -pa -d ceed-cpu -// * mpirun -np 4 ex6p -pa -d ceed-cuda +// * mpirun -np 4 ex6p -pa -d ceed-cuda // mpirun -np 4 ex6p -pa -d ceed-cuda:/gpu/cuda/shared // // Description: This is a version of Example 1 with a simple adaptive mesh From 87e11ed0b941408e197394e5a9836b06fc9bed48 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sun, 28 Jun 2020 08:15:27 -0700 Subject: [PATCH 524/535] minor --- mesh/mesh.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 93ab9ed170..c86e88d13a 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -989,9 +989,8 @@ public: /// The mask specifies which fields in the structure to return: /// mask & 1 - Elem1, mask & 2 - Elem2 /// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face. - /// These mask values are defined in the - /// FaceElementTransformations::ConfigMasks enumeration. - /// + /// These mask values are defined in the ConfigMasks enum type as part of the + /// FaceElementTransformations class in fem/eltrans.hpp. FaceElementTransformations *GetFaceElementTransformations(int FaceNo, int mask = 31); From 011b035540d5312c202def542515bbf2e9dce470 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 29 Jun 2020 20:02:07 -0700 Subject: [PATCH 525/535] Supporting INTEGRAL map type in GridFunction::GetValue --- fem/gridfunc.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 6e6bfc1efe..081afa0795 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -397,8 +397,16 @@ const fes->DofsToVDofs(vdim-1, dofs); Vector DofVal(dofs.Size()), LocVec; const FiniteElement *fe = fes->GetFE(i); - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); - fe->CalcShape(ip, DofVal); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, DofVal); + } + else + { + ElementTransformation *Tr = fes->GetElementTransformation(i); + Tr->SetIntPoint(&ip); + fe->CalcPhysShape(*Tr, DofVal); + } GetSubVector(dofs, LocVec); return (DofVal * LocVec); From e6beb268e785306607ba8fdf8271e9997e76cd79 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 29 Jun 2020 20:02:40 -0700 Subject: [PATCH 526/535] Supporting INTEGRAL map type in GridFunction::GetVectorValue --- fem/gridfunc.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index 081afa0795..3f1acc56be 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -423,10 +423,17 @@ void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip, GetSubVector(vdofs, loc_data); if (FElem->GetRangeType() == FiniteElement::SCALAR) { - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); Vector shape(dof); - FElem->CalcShape(ip, shape); + if (FElem->GetMapType() == FiniteElement::VALUE) + { + FElem->CalcShape(ip, shape); + } + else + { + ElementTransformation *Tr = fes->GetElementTransformation(i); + Tr->SetIntPoint(&ip); + FElem->CalcPhysShape(*Tr, shape); + } int vdim = fes->GetVDim(); val.SetSize(vdim); for (int k = 0; k < vdim; k++) From 7247b1fdc1ef592aaf43a20fab580e3d5e782bc7 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 29 Jun 2020 20:51:36 -0700 Subject: [PATCH 527/535] Adding access to the face neighbor `ElementTransformation` object through `ParFiniteElementSpace` and `ParMesh`. --- fem/pfespace.hpp | 2 ++ mesh/pmesh.hpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/fem/pfespace.hpp b/fem/pfespace.hpp index 1afe0ab818..d4716260a4 100644 --- a/fem/pfespace.hpp +++ b/fem/pfespace.hpp @@ -347,6 +347,8 @@ public: const FiniteElement *GetFaceNbrFE(int i) const; const FiniteElement *GetFaceNbrFaceFE(int i) const; const HYPRE_Int *GetFaceNbrGlobalDofMap() { return face_nbr_glob_dof_map; } + ElementTransformation *GetFaceNbrElementTransformation(int i) const + { return pmesh->GetFaceNbrElementTransformation(i); } void Lose_Dof_TrueDof_Matrix(); void LoseDofOffsets() { dof_offsets.LoseData(); } diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp index 616ca36a1d..0ac1a8315a 100644 --- a/mesh/pmesh.hpp +++ b/mesh/pmesh.hpp @@ -78,6 +78,8 @@ protected: // sface ids: all triangles first, then all quads Array sface_lface; + IsoparametricTransformation FaceNbrTransformation; + // glob_elem_offset + local element number defines a global element numbering mutable long glob_elem_offset, glob_offset_sequence; void ComputeGlobalElementOffset() const; @@ -295,6 +297,14 @@ public: FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2 = true); + ElementTransformation * + GetFaceNbrElementTransformation(int i) + { + GetFaceNbrElementTransformation(i, &FaceNbrTransformation); + + return &FaceNbrTransformation; + } + /// Return the number of shared faces (3D), edges (2D), vertices (1D) int GetNSharedFaces() const; From 86af594baae147122293443ddf12df97e2a5a332 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 29 Jun 2020 20:53:08 -0700 Subject: [PATCH 528/535] Adding `ParGridFunction::GetVectorValue` override with element index argument --- fem/gridfunc.hpp | 3 ++- fem/pgridfunc.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++ fem/pgridfunc.hpp | 3 +++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 643e54d586..6638d93ee6 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -162,7 +162,8 @@ public: int vdim = 1) const; /** Return a vector value from within the given element. */ - void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const; + virtual void GetVectorValue(int i, const IntegrationPoint &ip, + Vector &val) const; ///@} /** @name Element Index Get Values Methods diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp index 4df49a34ac..e2aca152de 100644 --- a/fem/pgridfunc.cpp +++ b/fem/pgridfunc.cpp @@ -299,6 +299,57 @@ const return (DofVal * LocVec); } +void ParGridFunction::GetVectorValue(int i, const IntegrationPoint &ip, + Vector &val) const +{ + int nbr_el_no = i - pfes->GetParMesh()->GetNE(); + if (nbr_el_no >= 0) + { + Array dofs; + pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs); + Vector loc_data; + face_nbr_data.GetSubVector(dofs, loc_data); + const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no); + int dof = FElem->GetDof(); + if (FElem->GetRangeType() == FiniteElement::SCALAR) + { + Vector shape(dof); + if (FElem->GetMapType() == FiniteElement::VALUE) + { + FElem->CalcShape(ip, shape); + } + else + { + ElementTransformation *Tr = + pfes->GetParMesh()->GetFaceNbrElementTransformation(nbr_el_no); + Tr->SetIntPoint(&ip); + FElem->CalcPhysShape(*Tr, shape); + } + int vdim = fes->GetVDim(); + val.SetSize(vdim); + for (int k = 0; k < vdim; k++) + { + val(k) = shape * ((const double *)loc_data + dof * k); + } + } + else + { + int spaceDim = fes->GetMesh()->SpaceDimension(); + DenseMatrix vshape(dof, spaceDim); + ElementTransformation *Tr = + pfes->GetParMesh()->GetFaceNbrElementTransformation(nbr_el_no); + Tr->SetIntPoint(&ip); + FElem->CalcVShape(*Tr, vshape); + val.SetSize(spaceDim); + vshape.MultTranspose(loc_data, val); + } + } + else + { + GridFunction::GetVectorValue(i, ip, val); + } +} + double ParGridFunction::GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp, Vector *tr) const diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp index 87fec4fae5..071299325d 100644 --- a/fem/pgridfunc.hpp +++ b/fem/pgridfunc.hpp @@ -213,6 +213,9 @@ public: virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip, int comp = 0, Vector *tr = NULL) const; + virtual void GetVectorValue(int i, const IntegrationPoint &ip, + Vector &val) const; + // Redefine to handle the case when T describes a face-neighbor element virtual void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip, From 052f04a645826aca05947336cb619ae451d96a6f Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 29 Jun 2020 20:53:54 -0700 Subject: [PATCH 529/535] Adding support for INTEGRAL map type in GetValue and GetVectorValue with element index arguments --- fem/pgridfunc.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp index e2aca152de..dc8dc20237 100644 --- a/fem/pgridfunc.cpp +++ b/fem/pgridfunc.cpp @@ -271,6 +271,7 @@ const { int fes_vdim = pfes->GetVDim(); pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs); + const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no); if (fes_vdim > 1) { int s = dofs.Size()/fes_vdim; @@ -283,7 +284,17 @@ const face_nbr_data.GetSubVector(dofs, LocVec); DofVal.SetSize(dofs.Size()); } - pfes->GetFaceNbrFE(nbr_el_no)->CalcShape(ip, DofVal); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, DofVal); + } + else + { + ElementTransformation *Tr = + pfes->GetFaceNbrElementTransformation(nbr_el_no); + Tr->SetIntPoint(&ip); + fe->CalcPhysShape(*Tr, DofVal); + } } else { @@ -291,8 +302,16 @@ const fes->DofsToVDofs(vdim-1, dofs); DofVal.SetSize(dofs.Size()); const FiniteElement *fe = fes->GetFE(i); - MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); - fe->CalcShape(ip, DofVal); + if (fe->GetMapType() == FiniteElement::VALUE) + { + fe->CalcShape(ip, DofVal); + } + else + { + ElementTransformation *Tr = fes->GetElementTransformation(i); + Tr->SetIntPoint(&ip); + fe->CalcPhysShape(*Tr, DofVal); + } GetSubVector(dofs, LocVec); } From b0f72994441a4713548ab378714b96a33563d865 Mon Sep 17 00:00:00 2001 From: "Stowell, Mark L" Date: Mon, 29 Jun 2020 20:55:05 -0700 Subject: [PATCH 530/535] Adding serial and parallel unit tests for the `GetValue` and `GetVectorValue` methods with element index arguments --- tests/unit/fem/test_get_value.cpp | 2373 +++++++++++++++++++---------- 1 file changed, 1553 insertions(+), 820 deletions(-) diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 00092d4a32..0957814ff1 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -175,9 +175,13 @@ TEST_CASE("1D GetValue", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gv_err = 0.0; + double dgv_gv_err = 0.0; + double dgi_gv_err = 0.0; for (int j=0; jSetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + double h1_gv_val = h1_x.GetValue(e, ip); + double dgv_gv_val = dgv_x.GetValue(e, ip); + double dgi_gv_val = dgi_x.GetValue(e, ip); + + h1_gfc_err += fabs(f_val - h1_gfc_val); + dgv_gfc_err += fabs(f_val - dgv_gfc_val); + dgi_gfc_err += fabs(f_val - dgi_gfc_val); + + h1_gv_err += fabs(f_val - h1_gv_val); + dgv_gv_err += fabs(f_val - dgv_gv_val); + dgi_gv_err += fabs(f_val - dgi_gv_val); + + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + std::cout << e << ":" << j << " h1 gfc " << f_val << " " + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + std::cout << e << ":" << j << " dgv gfc " << f_val << " " + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << e << ":" << j << " dgi gfc " << f_val << " " + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) + << std::endl; + } + if (log > 0 && fabs(f_val - h1_gv_val) > tol) + { + std::cout << e << ":" << j << " h1 gv " << f_val << " " + << h1_gv_val << " " << fabs(f_val - h1_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gv_val) > tol) + { + std::cout << e << ":" << j << " dgv gv " << f_val << " " + << dgv_gv_val << " " + << fabs(f_val - dgv_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gv_val) > tol) + { + std::cout << e << ":" << j << " dgi gv " << f_val << " " + << dgi_gv_val << " " + << fabs(f_val - dgi_gv_val) << std::endl; } } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gv_err /= ir.GetNPoints(); + dgv_gv_err /= ir.GetNPoints(); + dgi_gv_err /= ir.GetNPoints(); + + REQUIRE(h1_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE(h1_gv_err == Approx(0.0)); + REQUIRE(dgv_gv_err == Approx(0.0)); + REQUIRE(dgi_gv_err == Approx(0.0)); } } @@ -244,30 +288,33 @@ TEST_CASE("1D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); + dgi_err += fabs(f_val - dgi_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } } @@ -303,30 +350,33 @@ TEST_CASE("1D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); + dgi_err += fabs(f_val - dgi_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } } @@ -414,14 +464,19 @@ TEST_CASE("1D GetValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No - pmesh.GetNE(); - const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + int e = FET->Elem2No; + int e_nbr = e - pmesh.GetNE(); + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e_nbr); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gv_err = 0.0; + double dgv_gv_err = 0.0; + double dgi_gv_err = 0.0; for (int j=0; jSetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + double h1_gv_val = h1_x.GetValue(e, ip); + double dgv_gv_val = dgv_x.GetValue(e, ip); + double dgi_gv_val = dgi_x.GetValue(e, ip); + + h1_gfc_err += fabs(f_val - h1_gfc_val); + dgv_gfc_err += fabs(f_val - dgv_gfc_val); + dgi_gfc_err += fabs(f_val - dgi_gfc_val); + + h1_gv_err += fabs(f_val - h1_gv_val); + dgv_gv_err += fabs(f_val - dgv_gv_val); + dgi_gv_err += fabs(f_val - dgi_gv_val); + + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + std::cout << e << ":" << j << " h1 gfc " << f_val << " " + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + std::cout << e << ":" << j << " dgv gfc " << f_val << " " + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << e << ":" << j << " dgi gfc " << f_val << " " + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) + << std::endl; + } + if (log > 0 && fabs(f_val - h1_gv_val) > tol) + { + std::cout << e << ":" << j << " h1 gv " << f_val << " " + << h1_gv_val << " " << fabs(f_val - h1_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gv_val) > tol) + { + std::cout << e << ":" << j << " dgv gv " << f_val << " " + << dgv_gv_val << " " + << fabs(f_val - dgv_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gv_val) > tol) + { + std::cout << e << ":" << j << " dgi gv " << f_val << " " + << dgi_gv_val << " " + << fabs(f_val - dgi_gv_val) << std::endl; } } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gv_err /= ir.GetNPoints(); + dgv_gv_err /= ir.GetNPoints(); + dgi_gv_err /= ir.GetNPoints(); + + REQUIRE(h1_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE(h1_gv_err == Approx(0.0)); + REQUIRE(dgv_gv_err == Approx(0.0)); + REQUIRE(dgi_gv_err == Approx(0.0)); } } } @@ -527,9 +622,13 @@ TEST_CASE("2D GetValue", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gv_err = 0.0; + double dgv_gv_err = 0.0; + double dgi_gv_err = 0.0; for (int j=0; jSetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + double h1_gv_val = h1_x.GetValue(e, ip); + double dgv_gv_val = dgv_x.GetValue(e, ip); + double dgi_gv_val = dgi_x.GetValue(e, ip); + + h1_gfc_err += fabs(f_val - h1_gfc_val); + dgv_gfc_err += fabs(f_val - dgv_gfc_val); + dgi_gfc_err += fabs(f_val - dgi_gfc_val); + + h1_gv_err += fabs(f_val - h1_gv_val); + dgv_gv_err += fabs(f_val - dgv_gv_val); + dgi_gv_err += fabs(f_val - dgi_gv_val); + + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + std::cout << e << ":" << j << " h1 gfc " << f_val << " " + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + std::cout << e << ":" << j << " dgv gfc " << f_val << " " + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << e << ":" << j << " dgi gfc " << f_val << " " + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) + << std::endl; + } + if (log > 0 && fabs(f_val - h1_gv_val) > tol) + { + std::cout << e << ":" << j << " h1 gv " << f_val << " " + << h1_gv_val << " " << fabs(f_val - h1_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gv_val) > tol) + { + std::cout << e << ":" << j << " dgv gv " << f_val << " " + << dgv_gv_val << " " + << fabs(f_val - dgv_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gv_val) > tol) + { + std::cout << e << ":" << j << " dgi gv " << f_val << " " + << dgi_gv_val << " " + << fabs(f_val - dgi_gv_val) << std::endl; } } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gv_err /= ir.GetNPoints(); + dgv_gv_err /= ir.GetNPoints(); + dgi_gv_err /= ir.GetNPoints(); + + REQUIRE(h1_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE(h1_gv_err == Approx(0.0)); + REQUIRE(dgv_gv_err == Approx(0.0)); + REQUIRE(dgi_gv_err == Approx(0.0)); } } @@ -596,30 +735,33 @@ TEST_CASE("2D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); + dgi_err += fabs(f_val - dgi_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } } @@ -655,30 +797,33 @@ TEST_CASE("2D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); + dgi_err += fabs(f_val - dgi_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } } @@ -711,14 +856,14 @@ TEST_CASE("2D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); + h1_err += fabs(f_val - h1_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } } @@ -802,14 +947,19 @@ TEST_CASE("2D GetValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No - pmesh.GetNE(); - const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + int e = FET->Elem2No; + int e_nbr = e - pmesh.GetNE(); + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e_nbr); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gv_err = 0.0; + double dgv_gv_err = 0.0; + double dgi_gv_err = 0.0; for (int j=0; jSetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_gv_val = h1_x.GetValue(e, ip); + double dgv_gv_val = dgv_x.GetValue(e, ip); + double dgi_gv_val = dgi_x.GetValue(e, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + h1_gfc_err += fabs(f_val - h1_gfc_val); + dgv_gfc_err += fabs(f_val - dgv_gfc_val); + dgi_gfc_err += fabs(f_val - dgi_gfc_val); + + h1_gv_err += fabs(f_val - h1_gv_val); + dgv_gv_err += fabs(f_val - dgv_gv_val); + dgi_gv_err += fabs(f_val - dgi_gv_val); + + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + std::cout << e << ":" << j << " h1 gfc " << f_val << " " + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + std::cout << e << ":" << j << " dgv gfc " << f_val << " " + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << e << ":" << j << " dgi gfc " << f_val << " " + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) + << std::endl; + } + if (log > 0 && fabs(f_val - h1_gv_val) > tol) + { + std::cout << e << ":" << j << " h1 gv " << f_val << " " + << h1_gv_val << " " << fabs(f_val - h1_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gv_val) > tol) + { + std::cout << e << ":" << j << " dgv gv " << f_val << " " + << dgv_gv_val << " " + << fabs(f_val - dgv_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gv_val) > tol) + { + std::cout << e << ":" << j << " dgi gv " << f_val << " " + << dgi_gv_val << " " + << fabs(f_val - dgi_gv_val) << std::endl; } } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gv_err /= ir.GetNPoints(); + dgv_gv_err /= ir.GetNPoints(); + dgi_gv_err /= ir.GetNPoints(); + + REQUIRE(h1_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE(h1_gv_err == Approx(0.0)); + REQUIRE(dgv_gv_err == Approx(0.0)); + REQUIRE(dgi_gv_err == Approx(0.0)); } } } @@ -915,9 +1104,13 @@ TEST_CASE("3D GetValue", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gv_err = 0.0; + double dgv_gv_err = 0.0; + double dgi_gv_err = 0.0; for (int j=0; jSetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + double h1_gv_val = h1_x.GetValue(e, ip); + double dgv_gv_val = dgv_x.GetValue(e, ip); + double dgi_gv_val = dgi_x.GetValue(e, ip); + + h1_gfc_err += fabs(f_val - h1_gfc_val); + dgv_gfc_err += fabs(f_val - dgv_gfc_val); + dgi_gfc_err += fabs(f_val - dgi_gfc_val); + + h1_gv_err += fabs(f_val - h1_gv_val); + dgv_gv_err += fabs(f_val - dgv_gv_val); + dgi_gv_err += fabs(f_val - dgi_gv_val); + + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + std::cout << e << ":" << j << " h1 gfc " << f_val << " " + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + std::cout << e << ":" << j << " dgv gfc " << f_val << " " + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << e << ":" << j << " dgi gfc " << f_val << " " + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) + << std::endl; + } + if (log > 0 && fabs(f_val - h1_gv_val) > tol) + { + std::cout << e << ":" << j << " h1 gv " << f_val << " " + << h1_gv_val << " " << fabs(f_val - h1_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gv_val) > tol) + { + std::cout << e << ":" << j << " dgv gv " << f_val << " " + << dgv_gv_val << " " + << fabs(f_val - dgv_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gv_val) > tol) + { + std::cout << e << ":" << j << " dgi gv " << f_val << " " + << dgi_gv_val << " " + << fabs(f_val - dgi_gv_val) << std::endl; } } - h1_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE(h1_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gv_err /= ir.GetNPoints(); + dgv_gv_err /= ir.GetNPoints(); + dgi_gv_err /= ir.GetNPoints(); + + REQUIRE(h1_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE(h1_gv_err == Approx(0.0)); + REQUIRE(dgv_gv_err == Approx(0.0)); + REQUIRE(dgi_gv_err == Approx(0.0)); } } @@ -984,30 +1217,33 @@ TEST_CASE("3D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); + dgi_err += fabs(f_val - dgi_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } } @@ -1043,30 +1279,33 @@ TEST_CASE("3D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); + dgi_err += fabs(f_val - dgi_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { std::cout << be << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } } @@ -1099,14 +1338,14 @@ TEST_CASE("3D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); + h1_err += fabs(f_val - h1_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } } @@ -1135,14 +1374,14 @@ TEST_CASE("3D GetValue", T->SetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); + h1_err += fabs(f_val - h1_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << f << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } } @@ -1232,15 +1471,19 @@ TEST_CASE("3D GetValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No - pmesh.GetNE(); - const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + int e = FET->Elem2No; + int e_nbr = e - pmesh.GetNE(); + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e_nbr); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gv_err = 0.0; + double dgv_gv_err = 0.0; + double dgi_gv_err = 0.0; for (int j=0; jSetIntPoint(&ip); double f_val = funcCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double l2_gf_val = l2_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); - double dgi_gf_val = dgi_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - l2_err += fabs(f_val - l2_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); - dgi_err += fabs(f_val - dgi_gf_val); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); + double dgi_gfc_val = dgi_xCoef.Eval(*T, ip); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + double h1_gv_val = h1_x.GetValue(e, ip); + double dgv_gv_val = dgv_x.GetValue(e, ip); + double dgi_gv_val = dgi_x.GetValue(e, ip); + + h1_gfc_err += fabs(f_val - h1_gfc_val); + dgv_gfc_err += fabs(f_val - dgv_gfc_val); + dgi_gfc_err += fabs(f_val - dgi_gfc_val); + + h1_gv_err += fabs(f_val - h1_gv_val); + dgv_gv_err += fabs(f_val - dgv_gv_val); + dgi_gv_err += fabs(f_val - dgi_gv_val); + + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { - std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + std::cout << e << ":" << j << " h1 gfc " << f_val << " " + << h1_gfc_val << " " << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - l2_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { - std::cout << e << ":" << j << " l2 " << f_val << " " - << l2_gf_val << " " << fabs(f_val - l2_gf_val) + std::cout << e << ":" << j << " dgv gfc " << f_val << " " + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgi_gfc_val) > tol) { - std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + std::cout << e << ":" << j << " dgi gfc " << f_val << " " + << dgi_gfc_val << " " + << fabs(f_val - dgi_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgi_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gv_val) > tol) { - std::cout << e << ":" << j << " dgi " << f_val << " " - << dgi_gf_val << " " << fabs(f_val - dgi_gf_val) + std::cout << e << ":" << j << " h1 gv " << f_val << " " + << h1_gv_val << " " << fabs(f_val - h1_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgv_gv_val) > tol) + { + std::cout << e << ":" << j << " dgv gv " << f_val << " " + << dgv_gv_val << " " + << fabs(f_val - dgv_gv_val) + << std::endl; + } + if (log > 0 && fabs(f_val - dgi_gv_val) > tol) + { + std::cout << e << ":" << j << " dgi gv " << f_val << " " + << dgi_gv_val << " " + << fabs(f_val - dgi_gv_val) << std::endl; } } - h1_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gv_err /= ir.GetNPoints(); + dgv_gv_err /= ir.GetNPoints(); + dgi_gv_err /= ir.GetNPoints(); + + REQUIRE(h1_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE(h1_gv_err == Approx(0.0)); + REQUIRE(dgv_gv_err == Approx(0.0)); + REQUIRE(dgi_gv_err == Approx(0.0)); } } } @@ -1362,13 +1635,21 @@ TEST_CASE("2D GetVectorValue", dgv_x.ProjectCoefficient(funcCoef); dgi_x.ProjectCoefficient(funcCoef); - Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector nd_gf_val(dim); nd_gf_val = 0.0; - Vector rt_gf_val(dim); rt_gf_val = 0.0; - Vector l2_gf_val(dim); l2_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; - Vector dgi_gf_val(dim); dgi_gf_val = 0.0; + Vector f_val(dim); f_val = 0.0; + + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector nd_gfc_val(dim); nd_gfc_val = 0.0; + Vector rt_gfc_val(dim); rt_gfc_val = 0.0; + Vector l2_gfc_val(dim); l2_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; + Vector dgi_gfc_val(dim); dgi_gfc_val = 0.0; + + Vector h1_gvv_val(dim); h1_gvv_val = 0.0; + Vector nd_gvv_val(dim); nd_gvv_val = 0.0; + Vector rt_gvv_val(dim); rt_gvv_val = 0.0; + Vector l2_gvv_val(dim); l2_gvv_val = 0.0; + Vector dgv_gvv_val(dim); dgv_gvv_val = 0.0; + Vector dgi_gvv_val(dim); dgi_gvv_val = 0.0; SECTION("Domain Evaluation 2D") { @@ -1380,12 +1661,19 @@ TEST_CASE("2D GetVectorValue", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double nd_err = 0.0; - double rt_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double nd_gfc_err = 0.0; + double rt_gfc_err = 0.0; + double l2_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gvv_err = 0.0; + double nd_gvv_err = 0.0; + double rt_gvv_err = 0.0; + double l2_gvv_err = 0.0; + double dgv_gvv_err = 0.0; + double dgi_gvv_err = 0.0; for (int j=0; jSetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - h1_err += h1_dist; - nd_err += nd_dist; - rt_err += rt_dist; - l2_err += l2_dist; - dgv_err += dgv_dist; - dgi_err += dgi_dist; + h1_x.GetVectorValue(e, ip, h1_gvv_val); + nd_x.GetVectorValue(e, ip, nd_gvv_val); + rt_x.GetVectorValue(e, ip, rt_gvv_val); + l2_x.GetVectorValue(e, ip, l2_gvv_val); + dgv_x.GetVectorValue(e, ip, dgv_gvv_val); + dgi_x.GetVectorValue(e, ip, dgi_gvv_val); - if (log > 0 && h1_dist > tol) + double h1_gfc_dist = Distance(f_val, h1_gfc_val, dim); + double nd_gfc_dist = Distance(f_val, nd_gfc_val, dim); + double rt_gfc_dist = Distance(f_val, rt_gfc_val, dim); + double l2_gfc_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_gfc_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_gfc_dist = Distance(f_val, dgi_gfc_val, dim); + + double h1_gvv_dist = Distance(f_val, h1_gvv_val, dim); + double nd_gvv_dist = Distance(f_val, nd_gvv_val, dim); + double rt_gvv_dist = Distance(f_val, rt_gvv_val, dim); + double l2_gvv_dist = Distance(f_val, l2_gvv_val, dim); + double dgv_gvv_dist = Distance(f_val, dgv_gvv_val, dim); + double dgi_gvv_dist = Distance(f_val, dgi_gvv_val, dim); + + h1_gfc_err += h1_gfc_dist; + nd_gfc_err += nd_gfc_dist; + rt_gfc_err += rt_gfc_dist; + l2_gfc_err += l2_gfc_dist; + dgv_gfc_err += dgv_gfc_dist; + dgi_gfc_err += dgi_gfc_dist; + + h1_gvv_err += h1_gvv_dist; + nd_gvv_err += nd_gvv_dist; + rt_gvv_err += rt_gvv_dist; + l2_gvv_err += l2_gvv_dist; + dgv_gvv_err += dgv_gvv_dist; + dgi_gvv_err += dgi_gvv_dist; + + if (log > 0 && h1_gfc_dist > tol) { - std::cout << e << ":" << j << " h1 (" + std::cout << e << ":" << j << " h1 gfc (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " - << h1_dist << std::endl; + << h1_gfc_val[0] << "," << h1_gfc_val[1] << ") " + << h1_gfc_dist << std::endl; } - if (log > 0 && nd_dist > tol) + if (log > 0 && nd_gfc_dist > tol) { - std::cout << e << ":" << j << " nd (" + std::cout << e << ":" << j << " nd gfc (" << f_val[0] << "," << f_val[1] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << ") " - << nd_dist << std::endl; + << nd_gfc_val[0] << "," << nd_gfc_val[1] << ") " + << nd_gfc_dist << std::endl; } - if (log > 0 && rt_dist > tol) + if (log > 0 && rt_gfc_dist > tol) { - std::cout << e << ":" << j << " rt (" + std::cout << e << ":" << j << " rt gfc (" << f_val[0] << "," << f_val[1] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << ") " - << rt_dist << std::endl; + << rt_gfc_val[0] << "," << rt_gfc_val[1] << ") " + << rt_gfc_dist << std::endl; } - if (log > 0 && l2_dist > tol) + if (log > 0 && l2_gfc_dist > tol) { - std::cout << e << ":" << j << " l2 (" + std::cout << e << ":" << j << " l2 gfc (" << f_val[0] << "," << f_val[1] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << ") " - << l2_dist << std::endl; + << l2_gfc_val[0] << "," << l2_gfc_val[1] << ") " + << l2_gfc_dist << std::endl; } - if (log > 0 && dgv_dist > tol) + if (log > 0 && dgv_gfc_dist > tol) { - std::cout << e << ":" << j << " dgv (" + std::cout << e << ":" << j << " dgv gfc (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " - << dgv_dist << std::endl; + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " + << dgv_gfc_dist << std::endl; } - if (log > 0 && dgi_dist > tol) + if (log > 0 && dgi_gfc_dist > tol) { - std::cout << e << ":" << j << " dgi (" + std::cout << e << ":" << j << " dgi gfc (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " - << dgi_dist << std::endl; + << dgi_gfc_val[0] << "," + << dgi_gfc_val[1] << ") " + << dgi_gfc_dist << std::endl; + } + if (log > 0 && h1_gvv_dist > tol) + { + std::cout << e << ":" << j << " h1 gvv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << h1_gvv_val[0] << "," << h1_gvv_val[1] << ") " + << h1_gvv_dist << std::endl; + } + if (log > 0 && nd_gvv_dist > tol) + { + std::cout << e << ":" << j << " nd gvv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << nd_gvv_val[0] << "," << nd_gvv_val[1] << ") " + << nd_gvv_dist << std::endl; + } + if (log > 0 && rt_gvv_dist > tol) + { + std::cout << e << ":" << j << " rt gvv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << rt_gvv_val[0] << "," << rt_gvv_val[1] << ") " + << rt_gvv_dist << std::endl; + } + if (log > 0 && l2_gvv_dist > tol) + { + std::cout << e << ":" << j << " l2 gvv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << l2_gvv_val[0] << "," << l2_gvv_val[1] << ") " + << l2_gvv_dist << std::endl; + } + if (log > 0 && dgv_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgv gvv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgv_gvv_val[0] << "," + << dgv_gvv_val[1] << ") " + << dgv_gvv_dist << std::endl; + } + if (log > 0 && dgi_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgi gvv (" + << f_val[0] << "," << f_val[1] << ") vs. (" + << dgi_gvv_val[0] << "," + << dgi_gvv_val[1] << ") " + << dgi_gvv_dist << std::endl; } } - h1_err /= ir.GetNPoints(); - nd_err /= ir.GetNPoints(); - rt_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( nd_err == Approx(0.0)); - REQUIRE( rt_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + nd_gfc_err /= ir.GetNPoints(); + rt_gfc_err /= ir.GetNPoints(); + l2_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gvv_err /= ir.GetNPoints(); + nd_gvv_err /= ir.GetNPoints(); + rt_gvv_err /= ir.GetNPoints(); + l2_gvv_err /= ir.GetNPoints(); + dgv_gvv_err /= ir.GetNPoints(); + dgi_gvv_err /= ir.GetNPoints(); + + REQUIRE( h1_gfc_err == Approx(0.0)); + REQUIRE( nd_gfc_err == Approx(0.0)); + REQUIRE( rt_gfc_err == Approx(0.0)); + REQUIRE( l2_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE( h1_gvv_err == Approx(0.0)); + REQUIRE( nd_gvv_err == Approx(0.0)); + REQUIRE( rt_gvv_err == Approx(0.0)); + REQUIRE( l2_gvv_err == Approx(0.0)); + REQUIRE(dgv_gvv_err == Approx(0.0)); + REQUIRE(dgi_gvv_err == Approx(0.0)); } } @@ -1498,19 +1869,19 @@ TEST_CASE("2D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double nd_dist = Distance(f_val, nd_gfc_val, dim); + double rt_dist = Distance(f_val, rt_gfc_val, dim); + double l2_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_dist = Distance(f_val, dgi_gfc_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -1523,42 +1894,44 @@ TEST_CASE("2D GetVectorValue", { std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_gfc_val[0] << "," << h1_gfc_val[1] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) { std::cout << be << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_gfc_val[0] << "," << nd_gfc_val[1] << ") " << nd_dist << std::endl; } if (log > 0 && rt_dist > tol) { std::cout << be << ":" << j << " rt (" << f_val[0] << "," << f_val[1] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_gfc_val[0] << "," << rt_gfc_val[1] << ") " << rt_dist << std::endl; } if (log > 0 && l2_dist > tol) { std::cout << be << ":" << j << " l2 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_gfc_val[0] << "," << l2_gfc_val[1] << ") " << l2_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " << dgv_dist << std::endl; } if (log > 0 && dgi_dist > tol) { std::cout << be << ":" << j << " dgi (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_gfc_val[0] << "," + << dgi_gfc_val[1] << ") " << dgi_dist << std::endl; } } @@ -1603,19 +1976,19 @@ TEST_CASE("2D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double nd_dist = Distance(f_val, nd_gfc_val, dim); + double rt_dist = Distance(f_val, rt_gfc_val, dim); + double l2_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_dist = Distance(f_val, dgi_gfc_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -1628,42 +2001,48 @@ TEST_CASE("2D GetVectorValue", { std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_gfc_val[0] << "," + << h1_gfc_val[1] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) { std::cout << be << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << ") " + << nd_gfc_val[0] << "," + << nd_gfc_val[1] << ") " << nd_dist << std::endl; } if (log > 0 && rt_dist > tol) { std::cout << be << ":" << j << " rt (" << f_val[0] << "," << f_val[1] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << ") " + << rt_gfc_val[0] << "," + << rt_gfc_val[1] << ") " << rt_dist << std::endl; } if (log > 0 && l2_dist > tol) { std::cout << be << ":" << j << " l2 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << ") " + << l2_gfc_val[0] << "," + << l2_gfc_val[1] << ") " << l2_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " << dgv_dist << std::endl; } if (log > 0 && dgi_dist > tol) { std::cout << be << ":" << j << " dgi (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " + << dgi_gfc_val[0] << "," + << dgi_gfc_val[1] << ") " << dgi_dist << std::endl; } } @@ -1702,9 +2081,9 @@ TEST_CASE("2D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2); + double h1_dist = Distance(f_val, h1_gfc_val, 2); h1_err += h1_dist; @@ -1712,7 +2091,7 @@ TEST_CASE("2D GetVectorValue", { std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_gfc_val[0] << "," << h1_gfc_val[1] << ") " << h1_dist << std::endl; } } @@ -1805,12 +2184,20 @@ TEST_CASE("2D GetVectorValue in Parallel", dgi_x.ExchangeFaceNbrData(); Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector nd_gf_val(dim); nd_gf_val = 0.0; - Vector rt_gf_val(dim); rt_gf_val = 0.0; - Vector l2_gf_val(dim); l2_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; - Vector dgi_gf_val(dim); dgi_gf_val = 0.0; + + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector nd_gfc_val(dim); nd_gfc_val = 0.0; + Vector rt_gfc_val(dim); rt_gfc_val = 0.0; + Vector l2_gfc_val(dim); l2_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; + Vector dgi_gfc_val(dim); dgi_gfc_val = 0.0; + + Vector h1_gvv_val(dim); h1_gvv_val = 0.0; + Vector nd_gvv_val(dim); nd_gvv_val = 0.0; + Vector rt_gvv_val(dim); rt_gvv_val = 0.0; + Vector l2_gvv_val(dim); l2_gvv_val = 0.0; + Vector dgv_gvv_val(dim); dgv_gvv_val = 0.0; + Vector dgi_gvv_val(dim); dgi_gvv_val = 0.0; SECTION("Shared Face Evaluation 2D") { @@ -1823,17 +2210,25 @@ TEST_CASE("2D GetVectorValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No - pmesh.GetNE(); - const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + int e = FET->Elem2No; + int e_nbr = e - pmesh.GetNE(); + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e_nbr); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double nd_err = 0.0; - double rt_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double nd_gfc_err = 0.0; + double rt_gfc_err = 0.0; + double l2_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gvv_err = 0.0; + double nd_gvv_err = 0.0; + double rt_gvv_err = 0.0; + double l2_gvv_err = 0.0; + double dgv_gvv_err = 0.0; + double dgi_gvv_err = 0.0; for (int j=0; jSetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - h1_err += h1_dist; - nd_err += nd_dist; - rt_err += rt_dist; - l2_err += l2_dist; - dgv_err += dgv_dist; - dgi_err += dgi_dist; + h1_x.GetVectorValue(e, ip, h1_gvv_val); + nd_x.GetVectorValue(e, ip, nd_gvv_val); + rt_x.GetVectorValue(e, ip, rt_gvv_val); + l2_x.GetVectorValue(e, ip, l2_gvv_val); + dgv_x.GetVectorValue(e, ip, dgv_gvv_val); + dgi_x.GetVectorValue(e, ip, dgi_gvv_val); - if (log > 0 && h1_dist > tol) + double h1_gfc_dist = Distance(f_val, h1_gfc_val, dim); + double nd_gfc_dist = Distance(f_val, nd_gfc_val, dim); + double rt_gfc_dist = Distance(f_val, rt_gfc_val, dim); + double l2_gfc_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_gfc_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_gfc_dist = Distance(f_val, dgi_gfc_val, dim); + + double h1_gvv_dist = Distance(f_val, h1_gvv_val, dim); + double nd_gvv_dist = Distance(f_val, nd_gvv_val, dim); + double rt_gvv_dist = Distance(f_val, rt_gvv_val, dim); + double l2_gvv_dist = Distance(f_val, l2_gvv_val, dim); + double dgv_gvv_dist = Distance(f_val, dgv_gvv_val, dim); + double dgi_gvv_dist = Distance(f_val, dgi_gvv_val, dim); + + h1_gfc_err += h1_gfc_dist; + nd_gfc_err += nd_gfc_dist; + rt_gfc_err += rt_gfc_dist; + l2_gfc_err += l2_gfc_dist; + dgv_gfc_err += dgv_gfc_dist; + dgi_gfc_err += dgi_gfc_dist; + + h1_gvv_err += h1_gvv_dist; + nd_gvv_err += nd_gvv_dist; + rt_gvv_err += rt_gvv_dist; + l2_gvv_err += l2_gvv_dist; + dgv_gvv_err += dgv_gvv_dist; + dgi_gvv_err += dgi_gvv_dist; + + if (log > 0 && h1_gfc_dist > tol) { std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " - << h1_dist << std::endl; + << h1_gfc_val[0] << "," + << h1_gfc_val[1] << ") " + << h1_gfc_dist << std::endl; } - if (log > 0 && nd_dist > tol) + if (log > 0 && nd_gfc_dist > tol) { std::cout << e << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << ") " - << nd_dist << std::endl; + << nd_gfc_val[0] << "," + << nd_gfc_val[1] << ") " + << nd_gfc_dist << std::endl; } - if (log > 0 && rt_dist > tol) + if (log > 0 && rt_gfc_dist > tol) { std::cout << e << ":" << j << " rt (" << f_val[0] << "," << f_val[1] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << ") " - << rt_dist << std::endl; + << rt_gfc_val[0] << "," + << rt_gfc_val[1] << ") " + << rt_gfc_dist << std::endl; } - if (log > 0 && l2_dist > tol) + if (log > 0 && l2_gfc_dist > tol) { std::cout << e << ":" << j << " l2 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << ") " - << l2_dist << std::endl; + << l2_gfc_val[0] << "," + << l2_gfc_val[1] << ") " + << l2_gfc_dist << std::endl; } - if (log > 0 && dgv_dist > tol) + if (log > 0 && dgv_gfc_dist > tol) { std::cout << e << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " - << dgv_dist << std::endl; + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " + << dgv_gfc_dist << std::endl; } - if (log > 0 && dgi_dist > tol) + if (log > 0 && dgi_gfc_dist > tol) { std::cout << e << ":" << j << " dgi (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << ") " - << dgi_dist << std::endl; + << dgi_gfc_val[0] << "," + << dgi_gfc_val[1] << ") " + << dgi_gfc_dist << std::endl; + } + if (log > 0 && h1_gvv_dist > tol) + { + std::cout << e << ":" << j << " h1 gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gvv_val[0] << "," << h1_gvv_val[1] << ") " + << h1_gvv_dist << std::endl; + } + if (log > 0 && nd_gvv_dist > tol) + { + std::cout << e << ":" << j << " nd gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gvv_val[0] << "," << nd_gvv_val[1] << ") " + << nd_gvv_dist << std::endl; + } + if (log > 0 && rt_gvv_dist > tol) + { + std::cout << e << ":" << j << " rt gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gvv_val[0] << "," << rt_gvv_val[1] << ") " + << rt_gvv_dist << std::endl; + } + if (log > 0 && l2_gvv_dist > tol) + { + std::cout << e << ":" << j << " l2 gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gvv_val[0] << "," << l2_gvv_val[1] << ") " + << l2_gvv_dist << std::endl; + } + if (log > 0 && dgv_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgv gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gvv_val[0] << "," + << dgv_gvv_val[1] << ") " + << dgv_gvv_dist << std::endl; + } + if (log > 0 && dgi_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgi gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gvv_val[0] << "," + << dgi_gvv_val[1] << ") " + << dgi_gvv_dist << std::endl; } } - h1_err /= ir.GetNPoints(); - nd_err /= ir.GetNPoints(); - rt_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( nd_err == Approx(0.0)); - REQUIRE( rt_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + nd_gfc_err /= ir.GetNPoints(); + rt_gfc_err /= ir.GetNPoints(); + l2_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gvv_err /= ir.GetNPoints(); + nd_gvv_err /= ir.GetNPoints(); + rt_gvv_err /= ir.GetNPoints(); + l2_gvv_err /= ir.GetNPoints(); + dgv_gvv_err /= ir.GetNPoints(); + dgi_gvv_err /= ir.GetNPoints(); + + REQUIRE( h1_gfc_err == Approx(0.0)); + REQUIRE( nd_gfc_err == Approx(0.0)); + REQUIRE( rt_gfc_err == Approx(0.0)); + REQUIRE( l2_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE( h1_gvv_err == Approx(0.0)); + REQUIRE( nd_gvv_err == Approx(0.0)); + REQUIRE( rt_gvv_err == Approx(0.0)); + REQUIRE( l2_gvv_err == Approx(0.0)); + REQUIRE(dgv_gvv_err == Approx(0.0)); + REQUIRE(dgi_gvv_err == Approx(0.0)); } } } @@ -1989,12 +2477,20 @@ TEST_CASE("3D GetVectorValue", dgi_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector nd_gf_val(dim); nd_gf_val = 0.0; - Vector rt_gf_val(dim); rt_gf_val = 0.0; - Vector l2_gf_val(dim); l2_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; - Vector dgi_gf_val(dim); dgi_gf_val = 0.0; + + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector nd_gfc_val(dim); nd_gfc_val = 0.0; + Vector rt_gfc_val(dim); rt_gfc_val = 0.0; + Vector l2_gfc_val(dim); l2_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; + Vector dgi_gfc_val(dim); dgi_gfc_val = 0.0; + + Vector h1_gvv_val(dim); h1_gvv_val = 0.0; + Vector nd_gvv_val(dim); nd_gvv_val = 0.0; + Vector rt_gvv_val(dim); rt_gvv_val = 0.0; + Vector l2_gvv_val(dim); l2_gvv_val = 0.0; + Vector dgv_gvv_val(dim); dgv_gvv_val = 0.0; + Vector dgi_gvv_val(dim); dgi_gvv_val = 0.0; SECTION("Domain Evaluation 3D") { @@ -2006,12 +2502,19 @@ TEST_CASE("3D GetVectorValue", const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double nd_err = 0.0; - double rt_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double nd_gfc_err = 0.0; + double rt_gfc_err = 0.0; + double l2_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gvv_err = 0.0; + double nd_gvv_err = 0.0; + double rt_gvv_err = 0.0; + double l2_gvv_err = 0.0; + double dgv_gvv_err = 0.0; + double dgi_gvv_err = 0.0; for (int j=0; jSetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - h1_err += h1_dist; - nd_err += nd_dist; - rt_err += rt_dist; - l2_err += l2_dist; - dgv_err += dgv_dist; - dgi_err += dgi_dist; + h1_x.GetVectorValue(e, ip, h1_gvv_val); + nd_x.GetVectorValue(e, ip, nd_gvv_val); + rt_x.GetVectorValue(e, ip, rt_gvv_val); + l2_x.GetVectorValue(e, ip, l2_gvv_val); + dgv_x.GetVectorValue(e, ip, dgv_gvv_val); + dgi_x.GetVectorValue(e, ip, dgi_gvv_val); - if (log > 0 && h1_dist > tol) + double h1_gfc_dist = Distance(f_val, h1_gfc_val, dim); + double nd_gfc_dist = Distance(f_val, nd_gfc_val, dim); + double rt_gfc_dist = Distance(f_val, rt_gfc_val, dim); + double l2_gfc_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_gfc_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_gfc_dist = Distance(f_val, dgi_gfc_val, dim); + + double h1_gvv_dist = Distance(f_val, h1_gvv_val, dim); + double nd_gvv_dist = Distance(f_val, nd_gvv_val, dim); + double rt_gvv_dist = Distance(f_val, rt_gvv_val, dim); + double l2_gvv_dist = Distance(f_val, l2_gvv_val, dim); + double dgv_gvv_dist = Distance(f_val, dgv_gvv_val, dim); + double dgi_gvv_dist = Distance(f_val, dgi_gvv_val, dim); + + h1_gfc_err += h1_gfc_dist; + nd_gfc_err += nd_gfc_dist; + rt_gfc_err += rt_gfc_dist; + l2_gfc_err += l2_gfc_dist; + dgv_gfc_err += dgv_gfc_dist; + dgi_gfc_err += dgi_gfc_dist; + + h1_gvv_err += h1_gvv_dist; + nd_gvv_err += nd_gvv_dist; + rt_gvv_err += rt_gvv_dist; + l2_gvv_err += l2_gvv_dist; + dgv_gvv_err += dgv_gvv_dist; + dgi_gvv_err += dgi_gvv_dist; + + if (log > 0 && h1_gfc_dist > tol) { - std::cout << e << ":" << j << " h1 (" + std::cout << e << ":" << j << " h1 gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist - << std::endl; + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " + << h1_gfc_dist << std::endl; } - if (log > 0 && nd_dist > tol) + if (log > 0 && nd_gfc_dist > tol) { - std::cout << e << ":" << j << " nd (" + std::cout << e << ":" << j << " nd gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist - << std::endl; + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " + << nd_gfc_dist << std::endl; } - if (log > 0 && rt_dist > tol) + if (log > 0 && rt_gfc_dist > tol) { - std::cout << e << ":" << j << " rt (" + std::cout << e << ":" << j << " rt gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << "," - << rt_gf_val[2] << ") " << rt_dist - << std::endl; + << rt_gfc_val[0] << "," << rt_gfc_val[1] << "," + << rt_gfc_val[2] << ") " + << rt_gfc_dist << std::endl; } - if (log > 0 && l2_dist > tol) + if (log > 0 && l2_gfc_dist > tol) { - std::cout << e << ":" << j << " l2 (" + std::cout << e << ":" << j << " l2 gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << "," - << l2_gf_val[2] << ") " << l2_dist - << std::endl; + << l2_gfc_val[0] << "," << l2_gfc_val[1] << "," + << l2_gfc_val[2] << ") " + << l2_gfc_dist << std::endl; } - if (log > 0 && dgv_dist > tol) + if (log > 0 && dgv_gfc_dist > tol) { - std::cout << e << ":" << j << " dgv (" + std::cout << e << ":" << j << " dgv gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist - << std::endl; + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " + << dgv_gfc_dist << std::endl; } - if (log > 0 && dgi_dist > tol) + if (log > 0 && dgi_gfc_dist > tol) { - std::cout << e << ":" << j << " dgi (" + std::cout << e << ":" << j << " dgi gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," - << dgi_gf_val[2] << ") " << dgi_dist - << std::endl; + << dgi_gfc_val[0] << "," + << dgi_gfc_val[1] << "," + << dgi_gfc_val[2] << ") " + << dgi_gfc_dist << std::endl; + } + if (log > 0 && h1_gvv_dist > tol) + { + std::cout << e << ":" << j << " h1 gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gvv_val[0] << "," << h1_gvv_val[1] << "," + << h1_gvv_val[2] << ") " + << h1_gvv_dist << std::endl; + } + if (log > 0 && nd_gvv_dist > tol) + { + std::cout << e << ":" << j << " nd gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gvv_val[0] << "," << nd_gvv_val[1] << "," + << nd_gvv_val[2] << ") " + << nd_gvv_dist << std::endl; + } + if (log > 0 && rt_gvv_dist > tol) + { + std::cout << e << ":" << j << " rt gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gvv_val[0] << "," << rt_gvv_val[1] << "," + << rt_gvv_val[2] << ") " + << rt_gvv_dist << std::endl; + } + if (log > 0 && l2_gvv_dist > tol) + { + std::cout << e << ":" << j << " l2 gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gvv_val[0] << "," << l2_gvv_val[1] << "," + << l2_gvv_val[2] << ") " + << l2_gvv_dist << std::endl; + } + if (log > 0 && dgv_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgv gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gvv_val[0] << "," + << dgv_gvv_val[1] << "," + << dgv_gvv_val[2] << ") " + << dgv_gvv_dist << std::endl; + } + if (log > 0 && dgi_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgi gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gvv_val[0] << "," + << dgi_gvv_val[1] << "," + << dgi_gvv_val[2] << ") " + << dgi_gvv_dist << std::endl; } } - h1_err /= ir.GetNPoints(); - nd_err /= ir.GetNPoints(); - rt_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( nd_err == Approx(0.0)); - REQUIRE( rt_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + nd_gfc_err /= ir.GetNPoints(); + rt_gfc_err /= ir.GetNPoints(); + l2_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gvv_err /= ir.GetNPoints(); + nd_gvv_err /= ir.GetNPoints(); + rt_gvv_err /= ir.GetNPoints(); + l2_gvv_err /= ir.GetNPoints(); + dgv_gvv_err /= ir.GetNPoints(); + dgi_gvv_err /= ir.GetNPoints(); + + REQUIRE( h1_gfc_err == Approx(0.0)); + REQUIRE( nd_gfc_err == Approx(0.0)); + REQUIRE( rt_gfc_err == Approx(0.0)); + REQUIRE( l2_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE( h1_gvv_err == Approx(0.0)); + REQUIRE( nd_gvv_err == Approx(0.0)); + REQUIRE( rt_gvv_err == Approx(0.0)); + REQUIRE( l2_gvv_err == Approx(0.0)); + REQUIRE(dgv_gvv_err == Approx(0.0)); + REQUIRE(dgi_gvv_err == Approx(0.0)); } } @@ -2136,19 +2734,19 @@ TEST_CASE("3D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double nd_dist = Distance(f_val, nd_gfc_val, dim); + double rt_dist = Distance(f_val, rt_gfc_val, dim); + double l2_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_dist = Distance(f_val, dgi_gfc_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -2162,8 +2760,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) @@ -2171,8 +2769,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " << nd_dist << std::endl; } if (log > 0 && rt_dist > tol) @@ -2180,8 +2778,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " rt (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << "," - << rt_gf_val[2] << ") " << rt_dist + << rt_gfc_val[0] << "," << rt_gfc_val[1] << "," + << rt_gfc_val[2] << ") " << rt_dist << std::endl; } if (log > 0 && l2_dist > tol) @@ -2189,8 +2787,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " l2 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << "," - << l2_gf_val[2] << ") " << l2_dist + << l2_gfc_val[0] << "," << l2_gfc_val[1] << "," + << l2_gfc_val[2] << ") " << l2_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -2198,8 +2796,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } if (log > 0 && dgi_dist > tol) @@ -2207,8 +2805,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " dgi (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," - << dgi_gf_val[2] << ") " << dgi_dist + << dgi_gfc_val[0] << "," << dgi_gfc_val[1] << "," + << dgi_gfc_val[2] << ") " << dgi_dist << std::endl; } } @@ -2253,19 +2851,19 @@ TEST_CASE("3D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double nd_dist = Distance(f_val, nd_gfc_val, dim); + double rt_dist = Distance(f_val, rt_gfc_val, dim); + double l2_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_dist = Distance(f_val, dgi_gfc_val, dim); h1_err += h1_dist; nd_err += nd_dist; @@ -2279,8 +2877,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) @@ -2288,8 +2886,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " << nd_dist << std::endl; } if (log > 0 && rt_dist > tol) @@ -2297,8 +2895,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " rt (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << "," - << rt_gf_val[2] << ") " << rt_dist + << rt_gfc_val[0] << "," << rt_gfc_val[1] << "," + << rt_gfc_val[2] << ") " << rt_dist << std::endl; } if (log > 0 && l2_dist > tol) @@ -2306,8 +2904,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " l2 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << "," - << l2_gf_val[2] << ") " << l2_dist + << l2_gfc_val[0] << "," << l2_gfc_val[1] << "," + << l2_gfc_val[2] << ") " << l2_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -2315,8 +2913,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } if (log > 0 && dgi_dist > tol) @@ -2324,8 +2922,8 @@ TEST_CASE("3D GetVectorValue", std::cout << be << ":" << j << " dgi (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," - << dgi_gf_val[2] << ") " << dgi_dist + << dgi_gfc_val[0] << "," << dgi_gfc_val[1] << "," + << dgi_gfc_val[2] << ") " << dgi_dist << std::endl; } } @@ -2364,9 +2962,9 @@ TEST_CASE("3D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); h1_err += h1_dist; @@ -2375,8 +2973,8 @@ TEST_CASE("3D GetVectorValue", std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } } @@ -2405,9 +3003,9 @@ TEST_CASE("3D GetVectorValue", T->SetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); h1_err += h1_dist; @@ -2416,8 +3014,8 @@ TEST_CASE("3D GetVectorValue", std::cout << f << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } } @@ -2513,13 +3111,21 @@ TEST_CASE("3D GetVectorValue in Parallel", dgv_x.ExchangeFaceNbrData(); dgi_x.ExchangeFaceNbrData(); - Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector nd_gf_val(dim); nd_gf_val = 0.0; - Vector rt_gf_val(dim); rt_gf_val = 0.0; - Vector l2_gf_val(dim); l2_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; - Vector dgi_gf_val(dim); dgi_gf_val = 0.0; + Vector f_val(dim); f_val = 0.0; + + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector nd_gfc_val(dim); nd_gfc_val = 0.0; + Vector rt_gfc_val(dim); rt_gfc_val = 0.0; + Vector l2_gfc_val(dim); l2_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; + Vector dgi_gfc_val(dim); dgi_gfc_val = 0.0; + + Vector h1_gvv_val(dim); h1_gvv_val = 0.0; + Vector nd_gvv_val(dim); nd_gvv_val = 0.0; + Vector rt_gvv_val(dim); rt_gvv_val = 0.0; + Vector l2_gvv_val(dim); l2_gvv_val = 0.0; + Vector dgv_gvv_val(dim); dgv_gvv_val = 0.0; + Vector dgi_gvv_val(dim); dgi_gvv_val = 0.0; SECTION("Shared Face Evaluation 3D") { @@ -2532,17 +3138,25 @@ TEST_CASE("3D GetVectorValue in Parallel", FaceElementTransformations *FET = pmesh.GetSharedFaceTransformations(sf); ElementTransformation *T = &FET->GetElement2Transformation(); - int e = FET->Elem2No - pmesh.GetNE(); - const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e); + int e = FET->Elem2No; + int e_nbr = e - pmesh.GetNE(); + const FiniteElement *fe = dgv_fespace.GetFaceNbrFE(e_nbr); const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), 2*order + 2); - double h1_err = 0.0; - double nd_err = 0.0; - double rt_err = 0.0; - double l2_err = 0.0; - double dgv_err = 0.0; - double dgi_err = 0.0; + double h1_gfc_err = 0.0; + double nd_gfc_err = 0.0; + double rt_gfc_err = 0.0; + double l2_gfc_err = 0.0; + double dgv_gfc_err = 0.0; + double dgi_gfc_err = 0.0; + + double h1_gvv_err = 0.0; + double nd_gvv_err = 0.0; + double rt_gvv_err = 0.0; + double l2_gvv_err = 0.0; + double dgv_gvv_err = 0.0; + double dgi_gvv_err = 0.0; for (int j=0; jSetIntPoint(&ip); funcCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - rt_xCoef.Eval(rt_gf_val, *T, ip); - l2_xCoef.Eval(l2_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); - dgi_xCoef.Eval(dgi_gf_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double nd_dist = Distance(f_val, nd_gf_val, dim); - double rt_dist = Distance(f_val, rt_gf_val, dim); - double l2_dist = Distance(f_val, l2_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); - double dgi_dist = Distance(f_val, dgi_gf_val, dim); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + rt_xCoef.Eval(rt_gfc_val, *T, ip); + l2_xCoef.Eval(l2_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); + dgi_xCoef.Eval(dgi_gfc_val, *T, ip); - h1_err += h1_dist; - nd_err += nd_dist; - rt_err += rt_dist; - l2_err += l2_dist; - dgv_err += dgv_dist; - dgi_err += dgi_dist; + h1_x.GetVectorValue(e, ip, h1_gvv_val); + nd_x.GetVectorValue(e, ip, nd_gvv_val); + rt_x.GetVectorValue(e, ip, rt_gvv_val); + l2_x.GetVectorValue(e, ip, l2_gvv_val); + dgv_x.GetVectorValue(e, ip, dgv_gvv_val); + dgi_x.GetVectorValue(e, ip, dgi_gvv_val); - if (log > 0 && h1_dist > tol) + double h1_gfc_dist = Distance(f_val, h1_gfc_val, dim); + double nd_gfc_dist = Distance(f_val, nd_gfc_val, dim); + double rt_gfc_dist = Distance(f_val, rt_gfc_val, dim); + double l2_gfc_dist = Distance(f_val, l2_gfc_val, dim); + double dgv_gfc_dist = Distance(f_val, dgv_gfc_val, dim); + double dgi_gfc_dist = Distance(f_val, dgi_gfc_val, dim); + + double h1_gvv_dist = Distance(f_val, h1_gvv_val, dim); + double nd_gvv_dist = Distance(f_val, nd_gvv_val, dim); + double rt_gvv_dist = Distance(f_val, rt_gvv_val, dim); + double l2_gvv_dist = Distance(f_val, l2_gvv_val, dim); + double dgv_gvv_dist = Distance(f_val, dgv_gvv_val, dim); + double dgi_gvv_dist = Distance(f_val, dgi_gvv_val, dim); + + h1_gfc_err += h1_gfc_dist; + nd_gfc_err += nd_gfc_dist; + rt_gfc_err += rt_gfc_dist; + l2_gfc_err += l2_gfc_dist; + dgv_gfc_err += dgv_gfc_dist; + dgi_gfc_err += dgi_gfc_dist; + + h1_gvv_err += h1_gvv_dist; + nd_gvv_err += nd_gvv_dist; + rt_gvv_err += rt_gvv_dist; + l2_gvv_err += l2_gvv_dist; + dgv_gvv_err += dgv_gvv_dist; + dgi_gvv_err += dgi_gvv_dist; + + if (log > 0 && h1_gfc_dist > tol) { - std::cout << e << ":" << j << " h1 (" + std::cout << e << ":" << j << " h1 gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist - << std::endl; + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " + << h1_gfc_dist << std::endl; } - if (log > 0 && nd_dist > tol) + if (log > 0 && nd_gfc_dist > tol) { - std::cout << e << ":" << j << " nd (" + std::cout << e << ":" << j << " nd gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist - << std::endl; + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " + << nd_gfc_dist << std::endl; } - if (log > 0 && rt_dist > tol) + if (log > 0 && rt_gfc_dist > tol) { - std::cout << e << ":" << j << " rt (" + std::cout << e << ":" << j << " rt gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << rt_gf_val[0] << "," << rt_gf_val[1] << "," - << rt_gf_val[2] << ") " << rt_dist - << std::endl; + << rt_gfc_val[0] << "," << rt_gfc_val[1] << "," + << rt_gfc_val[2] << ") " + << rt_gfc_dist << std::endl; } - if (log > 0 && l2_dist > tol) + if (log > 0 && l2_gfc_dist > tol) { - std::cout << e << ":" << j << " l2 (" + std::cout << e << ":" << j << " l2 gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << l2_gf_val[0] << "," << l2_gf_val[1] << "," - << l2_gf_val[2] << ") " << l2_dist - << std::endl; + << l2_gfc_val[0] << "," << l2_gfc_val[1] << "," + << l2_gfc_val[2] << ") " + << l2_gfc_dist << std::endl; } - if (log > 0 && dgv_dist > tol) + if (log > 0 && dgv_gfc_dist > tol) { - std::cout << e << ":" << j << " dgv (" + std::cout << e << ":" << j << " dgv gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist - << std::endl; + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " + << dgv_gfc_dist << std::endl; } - if (log > 0 && dgi_dist > tol) + if (log > 0 && dgi_gfc_dist > tol) { - std::cout << e << ":" << j << " dgi (" + std::cout << e << ":" << j << " dgi gfc (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgi_gf_val[0] << "," << dgi_gf_val[1] << "," - << dgi_gf_val[2] << ") " << dgi_dist - << std::endl; + << dgi_gfc_val[0] << "," + << dgi_gfc_val[1] << "," + << dgi_gfc_val[2] << ") " + << dgi_gfc_dist << std::endl; + } + if (log > 0 && h1_gvv_dist > tol) + { + std::cout << e << ":" << j << " h1 gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << h1_gvv_val[0] << "," << h1_gvv_val[1] << "," + << h1_gvv_val[2] << ") " + << h1_gvv_dist << std::endl; + } + if (log > 0 && nd_gvv_dist > tol) + { + std::cout << e << ":" << j << " nd gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << nd_gvv_val[0] << "," << nd_gvv_val[1] << "," + << nd_gvv_val[2] << ") " + << nd_gvv_dist << std::endl; + } + if (log > 0 && rt_gvv_dist > tol) + { + std::cout << e << ":" << j << " rt gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << rt_gvv_val[0] << "," << rt_gvv_val[1] << "," + << rt_gvv_val[2] << ") " + << rt_gvv_dist << std::endl; + } + if (log > 0 && l2_gvv_dist > tol) + { + std::cout << e << ":" << j << " l2 gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << l2_gvv_val[0] << "," << l2_gvv_val[1] << "," + << l2_gvv_val[2] << ") " + << l2_gvv_dist << std::endl; + } + if (log > 0 && dgv_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgv gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgv_gvv_val[0] << "," + << dgv_gvv_val[1] << "," + << dgv_gvv_val[2] << ") " + << dgv_gvv_dist << std::endl; + } + if (log > 0 && dgi_gvv_dist > tol) + { + std::cout << e << ":" << j << " dgi gvv (" + << f_val[0] << "," << f_val[1] << "," + << f_val[2] << ") vs. (" + << dgi_gvv_val[0] << "," + << dgi_gvv_val[1] << "," + << dgi_gvv_val[2] << ") " + << dgi_gvv_dist << std::endl; } } - h1_err /= ir.GetNPoints(); - nd_err /= ir.GetNPoints(); - rt_err /= ir.GetNPoints(); - l2_err /= ir.GetNPoints(); - dgv_err /= ir.GetNPoints(); - dgi_err /= ir.GetNPoints(); - REQUIRE( h1_err == Approx(0.0)); - REQUIRE( nd_err == Approx(0.0)); - REQUIRE( rt_err == Approx(0.0)); - REQUIRE( l2_err == Approx(0.0)); - REQUIRE(dgv_err == Approx(0.0)); - REQUIRE(dgi_err == Approx(0.0)); + h1_gfc_err /= ir.GetNPoints(); + nd_gfc_err /= ir.GetNPoints(); + rt_gfc_err /= ir.GetNPoints(); + l2_gfc_err /= ir.GetNPoints(); + dgv_gfc_err /= ir.GetNPoints(); + dgi_gfc_err /= ir.GetNPoints(); + + h1_gvv_err /= ir.GetNPoints(); + nd_gvv_err /= ir.GetNPoints(); + rt_gvv_err /= ir.GetNPoints(); + l2_gvv_err /= ir.GetNPoints(); + dgv_gvv_err /= ir.GetNPoints(); + dgi_gvv_err /= ir.GetNPoints(); + + REQUIRE( h1_gfc_err == Approx(0.0)); + REQUIRE( nd_gfc_err == Approx(0.0)); + REQUIRE( rt_gfc_err == Approx(0.0)); + REQUIRE( l2_gfc_err == Approx(0.0)); + REQUIRE(dgv_gfc_err == Approx(0.0)); + REQUIRE(dgi_gfc_err == Approx(0.0)); + + REQUIRE( h1_gvv_err == Approx(0.0)); + REQUIRE( nd_gvv_err == Approx(0.0)); + REQUIRE( rt_gvv_err == Approx(0.0)); + REQUIRE( l2_gvv_err == Approx(0.0)); + REQUIRE(dgv_gvv_err == Approx(0.0)); + REQUIRE(dgi_gvv_err == Approx(0.0)); } } } @@ -2689,8 +3398,8 @@ TEST_CASE("1D GetGradient", dgv_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; SECTION("Domain Evaluation 1D") { @@ -2712,11 +3421,11 @@ TEST_CASE("1D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -2725,14 +3434,14 @@ TEST_CASE("1D GetGradient", { std::cout << e << ":" << j << " h1 (" << f_val[0] << ") vs. (" - << h1_gf_val[0] << ") " + << h1_gfc_val[0] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << e << ":" << j << " dgv (" << f_val[0] << ") vs. (" - << dgv_gf_val[0] << ") " + << dgv_gfc_val[0] << ") " << dgv_dist << std::endl; } } @@ -2764,11 +3473,11 @@ TEST_CASE("1D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -2777,14 +3486,14 @@ TEST_CASE("1D GetGradient", { std::cout << be << ":" << j << " h1 (" << f_val[0] << ") vs. (" - << h1_gf_val[0] << ") " + << h1_gfc_val[0] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << ") vs. (" - << dgv_gf_val[0] << ") " + << dgv_gfc_val[0] << ") " << dgv_dist << std::endl; } } @@ -2817,11 +3526,11 @@ TEST_CASE("1D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -2830,14 +3539,14 @@ TEST_CASE("1D GetGradient", { std::cout << be << ":" << j << " h1 (" << f_val[0] << ") vs. (" - << h1_gf_val[0] << ") " + << h1_gfc_val[0] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << ") vs. (" - << dgv_gf_val[0] << ") " + << dgv_gfc_val[0] << ") " << dgv_dist << std::endl; } } @@ -2893,8 +3602,8 @@ TEST_CASE("2D GetGradient", dgv_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; SECTION("Domain Evaluation 2D") { @@ -2916,11 +3625,11 @@ TEST_CASE("2D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -2929,14 +3638,16 @@ TEST_CASE("2D GetGradient", { std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_gfc_val[0] << "," + << h1_gfc_val[1] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << e << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " << dgv_dist << std::endl; } } @@ -2968,11 +3679,11 @@ TEST_CASE("2D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -2981,14 +3692,16 @@ TEST_CASE("2D GetGradient", { std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_gfc_val[0] << "," + << h1_gfc_val[1] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " << dgv_dist << std::endl; } } @@ -3021,11 +3734,11 @@ TEST_CASE("2D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -3034,14 +3747,16 @@ TEST_CASE("2D GetGradient", { std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << ") " + << h1_gfc_val[0] << "," + << h1_gfc_val[1] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << ") " + << dgv_gfc_val[0] << "," + << dgv_gfc_val[1] << ") " << dgv_dist << std::endl; } } @@ -3097,8 +3812,8 @@ TEST_CASE("3D GetGradient", dgv_x.ProjectCoefficient(funcCoef); Vector f_val(dim); f_val = 0.0; - Vector h1_gf_val(dim); h1_gf_val = 0.0; - Vector dgv_gf_val(dim); dgv_gf_val = 0.0; + Vector h1_gfc_val(dim); h1_gfc_val = 0.0; + Vector dgv_gfc_val(dim); dgv_gfc_val = 0.0; SECTION("Domain Evaluation 3D") { @@ -3120,11 +3835,11 @@ TEST_CASE("3D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -3134,8 +3849,8 @@ TEST_CASE("3D GetGradient", std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -3143,8 +3858,8 @@ TEST_CASE("3D GetGradient", std::cout << e << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } } @@ -3176,11 +3891,11 @@ TEST_CASE("3D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -3190,8 +3905,8 @@ TEST_CASE("3D GetGradient", std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -3199,8 +3914,8 @@ TEST_CASE("3D GetGradient", std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } } @@ -3233,11 +3948,11 @@ TEST_CASE("3D GetGradient", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, dim); - double dgv_dist = Distance(f_val, dgv_gf_val, dim); + double h1_dist = Distance(f_val, h1_gfc_val, dim); + double dgv_dist = Distance(f_val, dgv_gfc_val, dim); h1_err += h1_dist; dgv_err += dgv_dist; @@ -3247,8 +3962,8 @@ TEST_CASE("3D GetGradient", std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -3256,8 +3971,8 @@ TEST_CASE("3D GetGradient", std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } } @@ -3319,9 +4034,9 @@ TEST_CASE("2D GetCurl", dgv_x.ProjectCoefficient(funcCoef); Vector f_val(2*dim-3); f_val = 0.0; - Vector h1_gf_val(2*dim-3); h1_gf_val = 0.0; - Vector nd_gf_val(2*dim-3); nd_gf_val = 0.0; - Vector dgv_gf_val(2*dim-3); dgv_gf_val = 0.0; + Vector h1_gfc_val(2*dim-3); h1_gfc_val = 0.0; + Vector nd_gfc_val(2*dim-3); nd_gfc_val = 0.0; + Vector dgv_gfc_val(2*dim-3); dgv_gfc_val = 0.0; SECTION("Domain Evaluation 2D") { @@ -3344,13 +4059,13 @@ TEST_CASE("2D GetCurl", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); - double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); - double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + double h1_dist = Distance(f_val, h1_gfc_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gfc_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gfc_val, 2*dim-3); h1_err += h1_dist; nd_err += nd_dist; @@ -3360,21 +4075,21 @@ TEST_CASE("2D GetCurl", { std::cout << e << ":" << j << " h1 (" << f_val[0] << ") vs. (" - << h1_gf_val[0] << ") " << h1_dist + << h1_gfc_val[0] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) { std::cout << e << ":" << j << " nd (" << f_val[0] << ") vs. (" - << nd_gf_val[0] << ") " << nd_dist + << nd_gfc_val[0] << ") " << nd_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << e << ":" << j << " dgv (" << f_val[0] << ") vs. (" - << dgv_gf_val[0] << ") " << dgv_dist + << dgv_gfc_val[0] << ") " << dgv_dist << std::endl; } } @@ -3409,13 +4124,13 @@ TEST_CASE("2D GetCurl", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); - double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); - double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + double h1_dist = Distance(f_val, h1_gfc_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gfc_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gfc_val, 2*dim-3); h1_err += h1_dist; nd_err += nd_dist; @@ -3425,21 +4140,21 @@ TEST_CASE("2D GetCurl", { std::cout << be << ":" << j << " h1 (" << f_val[0] << ") vs. (" - << h1_gf_val[0] << ") " << h1_dist + << h1_gfc_val[0] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) { std::cout << be << ":" << j << " nd (" << f_val[0] << ") vs. (" - << nd_gf_val[0] << ") " << nd_dist + << nd_gfc_val[0] << ") " << nd_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << ") vs. (" - << dgv_gf_val[0] << ") " << dgv_dist + << dgv_gfc_val[0] << ") " << dgv_dist << std::endl; } } @@ -3475,13 +4190,13 @@ TEST_CASE("2D GetCurl", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); - double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); - double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + double h1_dist = Distance(f_val, h1_gfc_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gfc_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gfc_val, 2*dim-3); h1_err += h1_dist; nd_err += nd_dist; @@ -3491,21 +4206,21 @@ TEST_CASE("2D GetCurl", { std::cout << be << ":" << j << " h1 (" << f_val[0] << ") vs. (" - << h1_gf_val[0] << ") " << h1_dist + << h1_gfc_val[0] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) { std::cout << be << ":" << j << " nd (" << f_val[0] << ") vs. (" - << nd_gf_val[0] << ") " << nd_dist + << nd_gfc_val[0] << ") " << nd_dist << std::endl; } if (log > 0 && dgv_dist > tol) { std::cout << be << ":" << j << " dgv (" << f_val[0] << ") vs. (" - << dgv_gf_val[0] << ") " << dgv_dist + << dgv_gfc_val[0] << ") " << dgv_dist << std::endl; } } @@ -3569,9 +4284,9 @@ TEST_CASE("3D GetCurl", dgv_x.ProjectCoefficient(funcCoef); Vector f_val(2*dim-3); f_val = 0.0; - Vector h1_gf_val(2*dim-3); h1_gf_val = 0.0; - Vector nd_gf_val(2*dim-3); nd_gf_val = 0.0; - Vector dgv_gf_val(2*dim-3); dgv_gf_val = 0.0; + Vector h1_gfc_val(2*dim-3); h1_gfc_val = 0.0; + Vector nd_gfc_val(2*dim-3); nd_gfc_val = 0.0; + Vector dgv_gfc_val(2*dim-3); dgv_gfc_val = 0.0; SECTION("Domain Evaluation 3D") { @@ -3594,13 +4309,13 @@ TEST_CASE("3D GetCurl", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); - double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); - double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + double h1_dist = Distance(f_val, h1_gfc_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gfc_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gfc_val, 2*dim-3); h1_err += h1_dist; nd_err += nd_dist; @@ -3611,8 +4326,8 @@ TEST_CASE("3D GetCurl", std::cout << e << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) @@ -3620,8 +4335,8 @@ TEST_CASE("3D GetCurl", std::cout << e << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " << nd_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -3629,8 +4344,8 @@ TEST_CASE("3D GetCurl", std::cout << e << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } } @@ -3665,13 +4380,13 @@ TEST_CASE("3D GetCurl", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); - double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); - double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + double h1_dist = Distance(f_val, h1_gfc_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gfc_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gfc_val, 2*dim-3); h1_err += h1_dist; nd_err += nd_dist; @@ -3682,8 +4397,8 @@ TEST_CASE("3D GetCurl", std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) @@ -3691,8 +4406,8 @@ TEST_CASE("3D GetCurl", std::cout << be << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " << nd_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -3700,8 +4415,8 @@ TEST_CASE("3D GetCurl", std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } } @@ -3737,13 +4452,13 @@ TEST_CASE("3D GetCurl", T->SetIntPoint(&ip); dFuncCoef.Eval(f_val, *T, ip); - h1_xCoef.Eval(h1_gf_val, *T, ip); - nd_xCoef.Eval(nd_gf_val, *T, ip); - dgv_xCoef.Eval(dgv_gf_val, *T, ip); + h1_xCoef.Eval(h1_gfc_val, *T, ip); + nd_xCoef.Eval(nd_gfc_val, *T, ip); + dgv_xCoef.Eval(dgv_gfc_val, *T, ip); - double h1_dist = Distance(f_val, h1_gf_val, 2*dim-3); - double nd_dist = Distance(f_val, nd_gf_val, 2*dim-3); - double dgv_dist = Distance(f_val, dgv_gf_val, 2*dim-3); + double h1_dist = Distance(f_val, h1_gfc_val, 2*dim-3); + double nd_dist = Distance(f_val, nd_gfc_val, 2*dim-3); + double dgv_dist = Distance(f_val, dgv_gfc_val, 2*dim-3); h1_err += h1_dist; nd_err += nd_dist; @@ -3754,8 +4469,8 @@ TEST_CASE("3D GetCurl", std::cout << be << ":" << j << " h1 (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << h1_gf_val[0] << "," << h1_gf_val[1] << "," - << h1_gf_val[2] << ") " << h1_dist + << h1_gfc_val[0] << "," << h1_gfc_val[1] << "," + << h1_gfc_val[2] << ") " << h1_dist << std::endl; } if (log > 0 && nd_dist > tol) @@ -3763,8 +4478,8 @@ TEST_CASE("3D GetCurl", std::cout << be << ":" << j << " nd (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << nd_gf_val[0] << "," << nd_gf_val[1] << "," - << nd_gf_val[2] << ") " << nd_dist + << nd_gfc_val[0] << "," << nd_gfc_val[1] << "," + << nd_gfc_val[2] << ") " << nd_dist << std::endl; } if (log > 0 && dgv_dist > tol) @@ -3772,8 +4487,8 @@ TEST_CASE("3D GetCurl", std::cout << be << ":" << j << " dgv (" << f_val[0] << "," << f_val[1] << "," << f_val[2] << ") vs. (" - << dgv_gf_val[0] << "," << dgv_gf_val[1] << "," - << dgv_gf_val[2] << ") " << dgv_dist + << dgv_gfc_val[0] << "," << dgv_gfc_val[1] << "," + << dgv_gfc_val[2] << ") " << dgv_dist << std::endl; } } @@ -3856,30 +4571,33 @@ TEST_CASE("2D GetDivergence", T->SetIntPoint(&ip); double f_val = dFuncCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double rt_gf_val = rt_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double rt_gfc_val = rt_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - rt_err += fabs(f_val - rt_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + rt_err += fabs(f_val - rt_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - rt_gf_val) > tol) + if (log > 0 && fabs(f_val - rt_gfc_val) > tol) { std::cout << e << ":" << j << " rt " << f_val << " " - << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << rt_gfc_val << " " + << fabs(f_val - rt_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } } @@ -3914,30 +4632,33 @@ TEST_CASE("2D GetDivergence", T->SetIntPoint(&ip); double f_val = dFuncCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double rt_gf_val = rt_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double rt_gfc_val = rt_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - rt_err += fabs(f_val - rt_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + rt_err += fabs(f_val - rt_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - rt_gf_val) > tol) + if (log > 0 && fabs(f_val - rt_gfc_val) > tol) { std::cout << be << ":" << j << " rt " << f_val << " " - << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << rt_gfc_val << " " + << fabs(f_val - rt_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } } @@ -3973,30 +4694,33 @@ TEST_CASE("2D GetDivergence", T->SetIntPoint(&ip); double f_val = dFuncCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double rt_gf_val = rt_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double rt_gfc_val = rt_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - rt_err += fabs(f_val - rt_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + rt_err += fabs(f_val - rt_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - rt_gf_val) > tol) + if (log > 0 && fabs(f_val - rt_gfc_val) > tol) { std::cout << be << ":" << j << " rt " << f_val << " " - << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << rt_gfc_val << " " + << fabs(f_val - rt_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } } @@ -4079,30 +4803,33 @@ TEST_CASE("3D GetDivergence", T->SetIntPoint(&ip); double f_val = dFuncCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double rt_gf_val = rt_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double rt_gfc_val = rt_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - rt_err += fabs(f_val - rt_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + rt_err += fabs(f_val - rt_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << e << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - rt_gf_val) > tol) + if (log > 0 && fabs(f_val - rt_gfc_val) > tol) { std::cout << e << ":" << j << " rt " << f_val << " " - << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << rt_gfc_val << " " + << fabs(f_val - rt_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << e << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } } @@ -4137,30 +4864,33 @@ TEST_CASE("3D GetDivergence", T->SetIntPoint(&ip); double f_val = dFuncCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double rt_gf_val = rt_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double rt_gfc_val = rt_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - rt_err += fabs(f_val - rt_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + rt_err += fabs(f_val - rt_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - rt_gf_val) > tol) + if (log > 0 && fabs(f_val - rt_gfc_val) > tol) { std::cout << be << ":" << j << " rt " << f_val << " " - << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << rt_gfc_val << " " + << fabs(f_val - rt_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } } @@ -4196,30 +4926,33 @@ TEST_CASE("3D GetDivergence", T->SetIntPoint(&ip); double f_val = dFuncCoef.Eval(*T, ip); - double h1_gf_val = h1_xCoef.Eval(*T, ip); - double rt_gf_val = rt_xCoef.Eval(*T, ip); - double dgv_gf_val = dgv_xCoef.Eval(*T, ip); + double h1_gfc_val = h1_xCoef.Eval(*T, ip); + double rt_gfc_val = rt_xCoef.Eval(*T, ip); + double dgv_gfc_val = dgv_xCoef.Eval(*T, ip); - h1_err += fabs(f_val - h1_gf_val); - rt_err += fabs(f_val - rt_gf_val); - dgv_err += fabs(f_val - dgv_gf_val); + h1_err += fabs(f_val - h1_gfc_val); + rt_err += fabs(f_val - rt_gfc_val); + dgv_err += fabs(f_val - dgv_gfc_val); - if (log > 0 && fabs(f_val - h1_gf_val) > tol) + if (log > 0 && fabs(f_val - h1_gfc_val) > tol) { std::cout << be << ":" << j << " h1 " << f_val << " " - << h1_gf_val << " " << fabs(f_val - h1_gf_val) + << h1_gfc_val << " " + << fabs(f_val - h1_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - rt_gf_val) > tol) + if (log > 0 && fabs(f_val - rt_gfc_val) > tol) { std::cout << be << ":" << j << " rt " << f_val << " " - << rt_gf_val << " " << fabs(f_val - rt_gf_val) + << rt_gfc_val << " " + << fabs(f_val - rt_gfc_val) << std::endl; } - if (log > 0 && fabs(f_val - dgv_gf_val) > tol) + if (log > 0 && fabs(f_val - dgv_gfc_val) > tol) { std::cout << be << ":" << j << " dgv " << f_val << " " - << dgv_gf_val << " " << fabs(f_val - dgv_gf_val) + << dgv_gfc_val << " " + << fabs(f_val - dgv_gfc_val) << std::endl; } } From 346f92e4e48b46e64514329578a070c2d0107510 Mon Sep 17 00:00:00 2001 From: Jeremy L Thompson Date: Tue, 30 Jun 2020 11:07:16 -0600 Subject: [PATCH 531/535] Install - use libCEED in between releases until new OCCA backend is finished --- INSTALL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index 82c3346300..42a1047bda 100644 --- a/INSTALL +++ b/INSTALL @@ -638,13 +638,13 @@ The specific libraries and their options are: - OCCA (optional), used when MFEM_USE_OCCA = YES. URL: https://libocca.org Options: OCCA_DIR, OCCA_OPT, OCCA_LIB. - Versions: OCCA >= 1.0.10. + Versions: OCCA >= 1.0.9. - libCEED (optional), used when MFEM_USE_CEED = YES. URL: https://github.com/CEED/libCEED https://ceed.exascaleproject.org/libceed Options: CEED_DIR, CEED_OPT, CEED_LIB. - Versions: libCEED >= 0.7. + Versions: libCEED >= 0.6, git-hash a970f63. - RAJA (optional), used when MFEM_USE_RAJA = YES. Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported. From 607b15741b78bc632a5cefa832b3f439feff84ea Mon Sep 17 00:00:00 2001 From: Jeremy L Thompson <25011573+jeremylt@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:09:34 -0600 Subject: [PATCH 532/535] Update compstride calculation Co-authored-by: Yohann --- fem/libceed/ceed.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fem/libceed/ceed.cpp b/fem/libceed/ceed.cpp index d91087bcfa..2f7abe5b80 100644 --- a/fem/libceed/ceed.cpp +++ b/fem/libceed/ceed.cpp @@ -232,11 +232,7 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes, grad1d.GetData(), qref1d.GetData(), qweight1d.GetData(), basis); - CeedInt compstride = fes.GetNDofs(); - if (fes.GetOrdering()==Ordering::byVDIM) - { - compstride = 1; - } + CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs(); const Table &el_dof = fes.GetElementToDofTable(); Array tp_el_dof(el_dof.Size_of_connections()); for (int i = 0; i < mesh->GetNE(); i++) From 7fc4ab47eb6867028c7dac22406e80ce257ad6ca Mon Sep 17 00:00:00 2001 From: Jeremy L Thompson <25011573+jeremylt@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:09:47 -0600 Subject: [PATCH 533/535] Update compstride calculation Co-authored-by: Yohann --- fem/libceed/ceed.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fem/libceed/ceed.cpp b/fem/libceed/ceed.cpp index 2f7abe5b80..e2ea93aac5 100644 --- a/fem/libceed/ceed.cpp +++ b/fem/libceed/ceed.cpp @@ -98,11 +98,7 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes, Vector shape_i(P); DenseMatrix grad_i(P, dim); - CeedInt compstride = fes.GetNDofs(); - if (fes.GetOrdering()==Ordering::byVDIM) - { - compstride = 1; - } + CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs(); const Table &el_dof = fes.GetElementToDofTable(); Array tp_el_dof(el_dof.Size_of_connections()); const TensorBasisElement * tfe = From dc29574cfbc5880e01851867065d4383e4fddcd5 Mon Sep 17 00:00:00 2001 From: Yohann Dudouit Date: Tue, 30 Jun 2020 11:37:36 -0700 Subject: [PATCH 534/535] Add fix to ex1 too. --- examples/ex1.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/ex1.cpp b/examples/ex1.cpp index 50bbd175c5..4f2f511b1b 100644 --- a/examples/ex1.cpp +++ b/examples/ex1.cpp @@ -34,7 +34,8 @@ // ex1 -pa -d raja-omp // ex1 -pa -d occa-omp // ex1 -pa -d ceed-cpu -// ex1 -pa -d ceed-cuda +// * ex1 -pa -d ceed-cuda +// ex1 -pa -d ceed-cuda:/gpu/cuda/shared // ex1 -m ../data/beam-hex.mesh -pa -d cuda // ex1 -m ../data/beam-tet.mesh -pa -d ceed-cpu // ex1 -m ../data/beam-tet.mesh -pa -d ceed-cuda:/gpu/cuda/ref From 703eae8d2ca83da2ada7fc4f03e4ade80bd13bc4 Mon Sep 17 00:00:00 2001 From: Tzanio Date: Sat, 4 Jul 2020 18:52:45 -0700 Subject: [PATCH 535/535] minor --- CHANGELOG | 2 +- INSTALL | 4 ++-- examples/petsc/ex11p.cpp | 1 + linalg/slepc.cpp | 2 +- linalg/slepc.hpp | 4 +++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d5d71fd628..e3ceab1f21 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -115,7 +115,7 @@ New and updated examples and miniapps equations of incompressible fluid dynamics. See the miniapps/navier directory for more details. -- Ported example 11p to SLEPc, to demonstrate solving the Laplace eigenvalue +- Ported Example 11p to SLEPc, to demonstrate solving the Laplace eigenvalue equation with the shift-and-invert spectral transformation method. - Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of diff --git a/INSTALL b/INSTALL index 7ac6accdc9..6fdc5c4360 100644 --- a/INSTALL +++ b/INSTALL @@ -604,8 +604,8 @@ The specific libraries and their options are: - SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and uses some of the PETSc options when compiled. URL: https://slepc.upv.es/ - Options: SLEPC_OPT, SLEPC_LIB - Versions: SLEPc >= 3.8.0 + Options: SLEPC_OPT, SLEPC_LIB. + Versions: SLEPc >= 3.8.0. - Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES. Starting with MFEM v4.1, Axom version 0.3.1 or later is required. diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp index 4ea735abad..b5ed4a1acc 100644 --- a/examples/petsc/ex11p.cpp +++ b/examples/petsc/ex11p.cpp @@ -1,4 +1,5 @@ // MFEM Example 11 - Parallel Version +// PETSc Modification // // Compile with: make ex11p // diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index 34fb0575b2..d2bdc4f722 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -25,6 +25,7 @@ static PetscErrorCode ierr; namespace mfem { + void MFEMInitializeSlepc() { MFEMInitializeSlepc(NULL,NULL,NULL,NULL); @@ -182,7 +183,6 @@ int SlepcEigenSolver::GetNumConverged() return num_conv; } - void SlepcEigenSolver::SetWhichEigenpairs(SlepcEigenSolver::Which which) { switch (which) diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index 6dd9025e21..7f8911ba21 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -77,7 +77,8 @@ public: void GetEigenvector(unsigned int i, Vector & vr) const; void GetEigenvector(unsigned int i, Vector & vr, Vector & vc) const; - /// Target spectrum for the eigensolver. Target imaginary is not supported without complex support in SLEPc, and intervals are not implemented. + /// Target spectrum for the eigensolver. Target imaginary is not supported + /// without complex support in SLEPc, and intervals are not implemented. enum Which { LARGEST_MAGNITUDE, @@ -108,6 +109,7 @@ public: }; } + #endif // MFEM_USE_MPI #endif // MFEM_USE_SLEPC