[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Getfem-commits] (no subject)
From: |
Konstantinos Poulios |
Subject: |
[Getfem-commits] (no subject) |
Date: |
Mon, 11 Jun 2018 11:06:38 -0400 (EDT) |
branch: master
commit b7ba5d1120f1fbdddc284439c081a81ebf83d774
Author: Konstantinos Poulios <address@hidden>
Date: Mon Jun 11 17:06:25 2018 +0200
Improve support for incomplete (serendipity) elements and add discontinuous
versions
---
interface/src/gf_mesh_fem_set.cc | 35 ++++--
src/getfem/getfem_fem.h | 16 ++-
src/getfem/getfem_mesh_fem.h | 44 +++++---
src/getfem_export.cc | 16 +--
src/getfem_fem.cc | 223 ++++++++++++++++++++++++++-------------
src/getfem_mesh_fem.cc | 65 +++++++-----
6 files changed, 261 insertions(+), 138 deletions(-)
diff --git a/interface/src/gf_mesh_fem_set.cc b/interface/src/gf_mesh_fem_set.cc
index d681ef1..6072cdb 100644
--- a/interface/src/gf_mesh_fem_set.cc
+++ b/interface/src/gf_mesh_fem_set.cc
@@ -66,6 +66,15 @@ static void set_classical_fem(getfem::mesh_fem *mf,
getfemint::mexargs_in& in,
bool discontinuous) {
dim_type K = dim_type(in.pop().to_integer(0,255));
+ bool complete(false);
+ if (in.remaining() && in.front().is_string()) {
+ std::string s = in.pop().to_string();
+ if (cmd_strmatch(s, "complete"))
+ complete = true;
+ else
+ { THROW_BADARG("Invalid option" << s); }
+ }
+
scalar_type alpha = 0.0;
if (discontinuous && in.remaining()) alpha = in.pop().to_scalar();
@@ -74,15 +83,15 @@ static void set_classical_fem(getfem::mesh_fem *mf,
getfemint::mexargs_in& in,
bv = in.pop().to_bit_vector(&mf->linked_mesh().convex_index(),
-config::base_index());
if (!discontinuous) {
- mf->set_classical_finite_element(bv, K);
+ mf->set_classical_finite_element(bv, K, complete);
} else {
- mf->set_classical_discontinuous_finite_element(bv, K, alpha);
+ mf->set_classical_discontinuous_finite_element(bv, K, alpha, complete);
}
} else {
if (!discontinuous) {
- mf->set_classical_finite_element(K);
+ mf->set_classical_finite_element(K, complete);
} else {
- mf->set_classical_discontinuous_finite_element(K, alpha);
+ mf->set_classical_discontinuous_finite_element(K, alpha, complete);
}
}
}
@@ -145,26 +154,32 @@ void gf_mesh_fem_set(getfemint::mexargs_in& m_in,
);
- /address@hidden ('classical fem', @int k[, @ivec CVids])
+ /address@hidden ('classical fem', @int k[[, 'complete'], @ivec CVids])
Assign a classical (Lagrange polynomial) fem of order `k` to the @tmf.
+ The option 'complete' requests complete Langrange polynomial elements,
+ even if the element geometric transformation is an incomplete one
+ (e.g. 8-node quadrilateral or 20-node hexahedral).
Uses FEM_PK for simplexes, FEM_QK for parallelepipeds address@hidden/
sub_command
- ("classical fem", 1, 2, 0, 0,
+ ("classical fem", 1, 3, 0, 0,
set_classical_fem(mf, in, false);
);
- /address@hidden ('classical discontinuous fem', @int K[, @tscalar alpha[,
@ivec CVIDX]])
- Assigns a classical (Lagrange polynomial) discontinuous fem or order K.
+ /address@hidden ('classical discontinuous fem', @int k[[, 'complete'],
@tscalar alpha[, @ivec CVIDX]])
+ Assigns a classical (Lagrange polynomial) discontinuous fem of order k.
Similar to MESH_FEM:SET('set classical fem') except that
FEM_PK_DISCONTINUOUS is used. Param `alpha` the node inset,
:math:`0 \leq alpha < 1`, where 0 implies usual dof nodes, greater values
move the nodes toward the center of gravity, and 1 means that all
- degrees of freedom collapse on the center of address@hidden/
+ degrees of freedom collapse on the center of gravity.
+ The option 'complete' requests complete Langrange polynomial elements,
+ even if the element geometric transformation is an incomplete one
+ (e.g. 8-node quadrilateral or 20-node hexahedral)address@hidden/
sub_command
- ("classical discontinuous fem", 1, 3, 0, 0,
+ ("classical discontinuous fem", 1, 4, 0, 0,
set_classical_fem(mf, in, true);
);
diff --git a/src/getfem/getfem_fem.h b/src/getfem/getfem_fem.h
index 9fa0042..a6e1a95 100644
--- a/src/getfem/getfem_fem.h
+++ b/src/getfem/getfem_fem.h
@@ -52,6 +52,9 @@
- "FEM_Q2_INCOMPLETE(N)" : incomplete Q2 elements with 8 and 20 dof
(serendipity Quad 8 and Hexa 20 elements)
+ - "FEM_Q2_INCOMPLETE_DISCONTINUOUS(N)" : discontinuous incomplete Q2
+ elements with 8 and 20 dof (serendipity Quad 8 and Hexa 20 elements)
+
- "FEM_PRISM_PK(N,K)" : classical Lagrange element PK on a prism.
- "FEM_PRISM_PK_DISCONTINUOUS(N,K,alpha)" : classical discontinuous
@@ -599,9 +602,13 @@ namespace getfem {
@param pgt the geometric transformation (which defines the convex type).
@param k the degree of the fem.
+ @param complete a flag which requests complete Langrange polynomial
+ elements even if the provided pgt is an incomplete one (e.g. 8-node
+ quadrilateral or 20-node hexahedral).
@return a ppolyfem.
*/
- pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k);
+ pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k,
+ bool complete=false);
/** Give a pointer on the structures describing the classical
polynomial discontinuous fem of degree k on a given convex type.
@@ -614,9 +621,14 @@ namespace getfem {
0, the nodes are located as usual (i.e. with node on the convex border),
and for 0 < alpha < 1, they converge to the center of gravity of the
convex.
+ @param complete a flag which requests complete Langrange polynomial
+ elements even if the provided pgt is an incomplete one (e.g. 8-node
+ quadrilateral or 20-node hexahedral).
+
@return a ppolyfem.
*/
- pfem classical_discontinuous_fem(bgeot::pgeometric_trans pg, short_type k,
scalar_type alpha=0);
+ pfem classical_discontinuous_fem(bgeot::pgeometric_trans pg, short_type k,
+ scalar_type alpha=0, bool complete=false);
/** get a fem descriptor from its string name. */
pfem fem_descriptor(const std::string &name);
diff --git a/src/getfem/getfem_mesh_fem.h b/src/getfem/getfem_mesh_fem.h
index 90cd7e2..9482d50 100644
--- a/src/getfem/getfem_mesh_fem.h
+++ b/src/getfem/getfem_mesh_fem.h
@@ -166,7 +166,7 @@ namespace getfem {
/* of element option. (0 = no automatic addition) */
dim_type auto_add_elt_K; /* Degree of the fem for automatic addition */
/* of element option. (-1 = no automatic addition) */
- bool auto_add_elt_disc;
+ bool auto_add_elt_disc, auto_add_elt_complete;
scalar_type auto_add_elt_alpha;
dim_type Qdim; /* this is the "total" target_dim. */
bgeot::multi_index mi; /* multi dimensions for matrix/tensor field. */
@@ -284,16 +284,25 @@ namespace getfem {
* of element option. K=-1 disables the automatic addition.
*/
void set_auto_add(dim_type K, bool disc = false,
- scalar_type alpha = scalar_type(0)) {
- auto_add_elt_K = K; auto_add_elt_disc = disc;
- auto_add_elt_alpha = alpha; auto_add_elt_pf = 0;
+ scalar_type alpha = scalar_type(0),
+ bool complete=false) {
+ auto_add_elt_K = K;
+ auto_add_elt_disc = disc;
+ auto_add_elt_alpha = alpha;
+ auto_add_elt_complete = complete;
+ auto_add_elt_pf = 0;
}
/** Set the fem for automatic addition
* of element option. pf=0 disables the automatic addition.
*/
- void set_auto_add(pfem pf)
- { auto_add_elt_pf = pf; auto_add_elt_K = dim_type(-1);}
+ void set_auto_add(pfem pf) {
+ auto_add_elt_pf = pf;
+ auto_add_elt_K = dim_type(-1);
+ auto_add_elt_disc = false;
+ auto_add_elt_alpha = scalar_type(0);
+ auto_add_elt_complete = false;
+ }
/** Return the Q dimension. A mesh_fem used for scalar fields has
Q=1, for vector fields, Q is typically equal to
@@ -372,15 +381,19 @@ namespace getfem {
a convex.
@param cv is the convex number.
@param fem_degree the polynomial degree of the finite element.
+ @param complete is a flag for excluding incomplete element
+ irrespective of the element geometric transformation.
*/
- void set_classical_finite_element(size_type cv, dim_type fem_degree);
+ void set_classical_finite_element(size_type cv, dim_type fem_degree,
+ bool complete=false);
/** Set a classical (i.e. lagrange polynomial) finite element on
a set of convexes.
@param cvs the set of convexes, as a dal::bit_vector.
@param fem_degree the polynomial degree of the finite element.
*/
void set_classical_finite_element(const dal::bit_vector &cvs,
- dim_type fem_degree);
+ dim_type fem_degree,
+ bool complete=false);
/** Similar to set_classical_finite_element, but uses
discontinuous lagrange elements.
@@ -393,7 +406,8 @@ namespace getfem {
*/
void set_classical_discontinuous_finite_element(size_type cv,
dim_type fem_degree,
- scalar_type alpha=0);
+ scalar_type alpha=0,
+ bool complete=false);
/** Similar to set_classical_finite_element, but uses
discontinuous lagrange elements.
@@ -406,17 +420,20 @@ namespace getfem {
*/
void set_classical_discontinuous_finite_element(const dal::bit_vector &cvs,
dim_type fem_degree,
- scalar_type alpha=0);
+ scalar_type alpha=0,
+ bool complete=false);
/** Shortcut for
* set_classical_finite_element(linked_mesh().convex_index(),...)
*/
- void set_classical_finite_element(dim_type fem_degree);
+ void set_classical_finite_element(dim_type fem_degree,
+ bool complete=false);
/** Shortcut for
* set_classical_discontinuous_finite_element(linked_mesh().convex_index()
* ,...)
*/
void set_classical_discontinuous_finite_element(dim_type fem_degree,
- scalar_type alpha=0);
+ scalar_type alpha=0,
+ bool complete=false);
/** Return the basic fem associated with an element (if no fem is
* associated, the function will crash! use the convex_index() of
* the mesh_fem to check that a fem is associated to a given
@@ -623,7 +640,8 @@ namespace getfem {
the same arguments will return the same mesh_fem object. A
consequence is that you should NEVER modify this mesh_fem!
*/
- const mesh_fem &classical_mesh_fem(const mesh &mesh, dim_type degree,
dim_type qdim = 1);
+ const mesh_fem &classical_mesh_fem(const mesh &mesh, dim_type degree,
+ dim_type qdim=1, bool complete=false);
/** Dummy mesh_fem for default parameter of functions. */
const mesh_fem &dummy_mesh_fem();
diff --git a/src/getfem_export.cc b/src/getfem_export.cc
index 855dac0..1fe2980 100644
--- a/src/getfem_export.cc
+++ b/src/getfem_export.cc
@@ -206,17 +206,7 @@ namespace getfem
pmf = std::make_unique<mesh_fem>(const_cast<mesh&>(m), dim_type(1));
for (dal::bv_visitor cv(m.convex_index()); !cv.finished(); ++cv) {
bgeot::pgeometric_trans pgt = m.trans_of_convex(cv);
- pfem pf;
- if (pgt == bgeot::geometric_trans_descriptor("GT_Q2_INCOMPLETE(2)"))
- pf = fem_descriptor("FEM_Q2_INCOMPLETE(2)");
- else if (pgt == bgeot::geometric_trans_descriptor("GT_Q2_INCOMPLETE(3)"))
- pf = fem_descriptor("FEM_Q2_INCOMPLETE(3)");
- else if (pgt ==
bgeot::geometric_trans_descriptor("GT_PYRAMID_Q2_INCOMPLETE"))
- pf = fem_descriptor("FEM_PYRAMID_Q2_INCOMPLETE");
- else if (pgt ==
bgeot::geometric_trans_descriptor("GT_PRISM_INCOMPLETE_P2"))
- pf = fem_descriptor("FEM_PRISM_INCOMPLETE_P2");
- else
- pf = getfem::classical_fem(pgt, pgt->complexity() > 1 ? 2 : 1);
+ pfem pf = getfem::classical_fem(pgt, pgt->complexity() > 1 ? 2 : 1);
pmf->set_finite_element(cv, pf);
}
exporting(*pmf);
@@ -257,8 +247,8 @@ namespace getfem
degree = 2;
pmf->set_finite_element(cv, discontinuous ?
- classical_discontinuous_fem(pgt, degree) :
- classical_fem(pgt, degree));
+ classical_discontinuous_fem(pgt, degree, 0,
true) :
+ classical_fem(pgt, degree, true));
}
}
/* find out which dof will be exported to VTK */
diff --git a/src/getfem_fem.cc b/src/getfem_fem.cc
index 9c883ed..3b45e9e 100644
--- a/src/getfem_fem.cc
+++ b/src/getfem_fem.cc
@@ -1135,8 +1135,9 @@ namespace getfem {
// 0----1----2
static pfem
- Q2_incomplete_fem(fem_param_list ¶ms,
- std::vector<dal::pstatic_stored_object> &deps) {
+ build_Q2_incomplete_fem(fem_param_list ¶ms,
+ std::vector<dal::pstatic_stored_object> &deps,
+ bool discontinuous) {
GMM_ASSERT1(params.size() <= 1, "Bad number of parameters");
dim_type n = 2;
if (params.size() > 0) {
@@ -1152,6 +1153,8 @@ namespace getfem {
p->estimated_degree() = 2;
p->init_cvs_node();
p->base().resize(n == 2 ? 8 : 20);
+ auto lag_dof = discontinuous ? lagrange_nonconforming_dof(n)
+ : lagrange_dof(n);
if (n == 2) {
std::stringstream s
@@ -1166,14 +1169,14 @@ namespace getfem {
for (int i = 0; i < 8; ++i) p->base()[i] = read_base_poly(2, s);
- p->add_node(lagrange_dof(2), base_small_vector(0.0, 0.0));
- p->add_node(lagrange_dof(2), base_small_vector(0.5, 0.0));
- p->add_node(lagrange_dof(2), base_small_vector(1.0, 0.0));
- p->add_node(lagrange_dof(2), base_small_vector(0.0, 0.5));
- p->add_node(lagrange_dof(2), base_small_vector(1.0, 0.5));
- p->add_node(lagrange_dof(2), base_small_vector(0.0, 1.0));
- p->add_node(lagrange_dof(2), base_small_vector(0.5, 1.0));
- p->add_node(lagrange_dof(2), base_small_vector(1.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(0.5, 0.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 0.5));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.5));
+ p->add_node(lag_dof, base_small_vector(0.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.5, 1.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 1.0));
} else {
std::stringstream s
("1 + 2*x^2*y*z + 2*x*y^2*z + 2*x*y*z^2"
@@ -1204,28 +1207,28 @@ namespace getfem {
for (int i = 0; i < 20; ++i) p->base()[i] = read_base_poly(3, s);
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 0.0, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.5, 0.0, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 0.0, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 0.5, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 0.5, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 1.0, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.5, 1.0, 0.0));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 1.0, 0.0));
-
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 0.0, 0.5));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 0.0, 0.5));
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 1.0, 0.5));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 1.0, 0.5));
-
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 0.0, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.5, 0.0, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 0.0, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 0.5, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 0.5, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.0, 1.0, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(0.5, 1.0, 1.0));
- p->add_node(lagrange_dof(3), base_small_vector(1.0, 1.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 0.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(0.5, 0.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 0.5, 0.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.5, 0.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 1.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(0.5, 1.0, 0.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 1.0, 0.0));
+
+ p->add_node(lag_dof, base_small_vector(0.0, 0.0, 0.5));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.0, 0.5));
+ p->add_node(lag_dof, base_small_vector(0.0, 1.0, 0.5));
+ p->add_node(lag_dof, base_small_vector(1.0, 1.0, 0.5));
+
+ p->add_node(lag_dof, base_small_vector(0.0, 0.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.5, 0.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 0.5, 1.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 0.5, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.0, 1.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(0.5, 1.0, 1.0));
+ p->add_node(lag_dof, base_small_vector(1.0, 1.0, 1.0));
}
deps.push_back(p->ref_convex(0));
deps.push_back(p->node_tab(0));
@@ -1233,6 +1236,13 @@ namespace getfem {
return pfem(p);
}
+ static pfem Q2_incomplete_fem
+ (fem_param_list ¶ms, std::vector<dal::pstatic_stored_object> &deps)
+ { return build_Q2_incomplete_fem(params, deps, false); }
+
+ static pfem Q2_incomplete_discontinuous_fem
+ (fem_param_list ¶ms, std::vector<dal::pstatic_stored_object> &deps)
+ { return build_Q2_incomplete_fem(params, deps, true); }
/* ******************************************************************** */
/* Lagrange Pyramidal element of degree 0, 1 and 2 */
@@ -1262,7 +1272,8 @@ namespace getfem {
// | |
// 0---1---2
- static pfem build_pyramid_QK_fem(short_type k, bool disc) {
+ static pfem
+ build_pyramid_QK_fem(short_type k, bool disc, scalar_type alpha=0) {
auto p = std::make_shared<fem<base_rational_fraction>>();
p->mref_convex() = bgeot::pyramid_QK_of_reference(1);
p->dim() = 3;
@@ -1305,6 +1316,41 @@ namespace getfem {
base_poly z = read_base_poly(3, "z");
base_poly ones = read_base_poly(3, "1");
base_poly un_z = read_base_poly(3, "1-z");
+
+ std::vector<base_node> points = { base_node(-1.0, -1.0, 0.0),
+ base_node( 0.0, -1.0, 0.0),
+ base_node( 1.0, -1.0, 0.0),
+ base_node(-1.0, 0.0, 0.0),
+ base_node( 0.0, 0.0, 0.0),
+ base_node( 1.0, 0.0, 0.0),
+ base_node(-1.0, 1.0, 0.0),
+ base_node( 0.0, 1.0, 0.0),
+ base_node( 1.0, 1.0, 0.0),
+ base_node(-0.5, -0.5, 0.5),
+ base_node( 0.5, -0.5, 0.5),
+ base_node(-0.5, 0.5, 0.5),
+ base_node( 0.5, 0.5, 0.5),
+ base_node( 0.0, 0.0, 1.0) };
+
+ if (disc && alpha != scalar_type(0)) {
+ base_node G =
+ gmm::mean_value(points.begin(), points.end());
+ for (auto && pt : points)
+ pt = (1-alpha)*pt + alpha*G;
+ for (size_type d = 0; d < 3; ++d) {
+ base_poly S(1,2);
+ S[0] = -alpha * G[d] / (1-alpha);
+ S[1] = 1. / (1-alpha);
+ xi0 = bgeot::poly_substitute_var(xi0, S, d);
+ xi1 = bgeot::poly_substitute_var(xi1, S, d);
+ xi2 = bgeot::poly_substitute_var(xi2, S, d);
+ xi3 = bgeot::poly_substitute_var(xi3, S, d);
+ x = bgeot::poly_substitute_var(x, S, d);
+ y = bgeot::poly_substitute_var(y, S, d);
+ z = bgeot::poly_substitute_var(z, S, d);
+ un_z = bgeot::poly_substitute_var(un_z, S, d);
+ }
+ }
base_rational_fraction Q(read_base_poly(3, "1"), un_z);
p->base()[ 0] = Q*Q*xi0*xi1*(x*y-z*un_z);
@@ -1320,22 +1366,10 @@ namespace getfem {
p->base()[10] = Q*z*xi1*xi2*4.;
p->base()[11] = Q*z*xi3*xi0*4.;
p->base()[12] = Q*z*xi2*xi3*4.;
- p->base()[13] = read_base_poly(3, "z*(2*z-1)");
+ p->base()[13] = z*(z*2-ones);
- p->add_node(lag_dof, base_small_vector(-1.0, -1.0, 0.0));
- p->add_node(lag_dof, base_small_vector( 0.0, -1.0, 0.0));
- p->add_node(lag_dof, base_small_vector( 1.0, -1.0, 0.0));
- p->add_node(lag_dof, base_small_vector(-1.0, 0.0, 0.0));
- p->add_node(lag_dof, base_small_vector( 0.0, 0.0, 0.0));
- p->add_node(lag_dof, base_small_vector( 1.0, 0.0, 0.0));
- p->add_node(lag_dof, base_small_vector(-1.0, 1.0, 0.0));
- p->add_node(lag_dof, base_small_vector( 0.0, 1.0, 0.0));
- p->add_node(lag_dof, base_small_vector( 1.0, 1.0, 0.0));
- p->add_node(lag_dof, base_small_vector(-0.5, -0.5, 0.5));
- p->add_node(lag_dof, base_small_vector( 0.5, -0.5, 0.5));
- p->add_node(lag_dof, base_small_vector(-0.5, 0.5, 0.5));
- p->add_node(lag_dof, base_small_vector( 0.5, 0.5, 0.5));
- p->add_node(lag_dof, base_small_vector( 0.0, 0.0, 1.0));
+ for (const auto &pt : points)
+ p->add_node(lag_dof, pt);
} else GMM_ASSERT1(false, "Sorry, pyramidal Lagrange fem "
"implemented only for degree 0, 1 or 2");
@@ -1360,13 +1394,18 @@ namespace getfem {
static pfem pyramid_QK_disc_fem
(fem_param_list ¶ms, std::vector<dal::pstatic_stored_object> &deps) {
- GMM_ASSERT1(params.size() <= 1, "Bad number of parameters");
+ GMM_ASSERT1(params.size() <= 2, "Bad number of parameters");
short_type k = 2;
if (params.size() > 0) {
GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
k = dim_type(::floor(params[0].num() + 0.01));
}
- pfem p = build_pyramid_QK_fem(k, true);
+ scalar_type alpha(0);
+ if (params.size() > 1) {
+ GMM_ASSERT1(params[1].type() == 0, "Bad type of parameters");
+ alpha = params[1].num();
+ }
+ pfem p = build_pyramid_QK_fem(k, true, alpha);
deps.push_back(p->ref_convex(0));
deps.push_back(p->node_tab(0));
return p;
@@ -1468,7 +1507,7 @@ namespace getfem {
static pfem pyramid_Q2_incomplete_disc_fem
(fem_param_list ¶ms, std::vector<dal::pstatic_stored_object> &deps) {
- GMM_ASSERT1(params.size() <= 1, "Bad number of parameters");
+ GMM_ASSERT1(params.size() == 0, "Bad number of parameters");
pfem p = build_pyramid_Q2_incomplete_fem(true);
deps.push_back(p->ref_convex(0));
deps.push_back(p->node_tab(0));
@@ -1558,7 +1597,7 @@ namespace getfem {
static pfem prism_incomplete_P2_disc_fem
(fem_param_list ¶ms, std::vector<dal::pstatic_stored_object> &deps) {
- GMM_ASSERT1(params.size() <= 1, "Bad number of parameters");
+ GMM_ASSERT1(params.size() == 0, "Bad number of parameters");
pfem p = build_prism_incomplete_P2_fem(true);
deps.push_back(p->ref_convex(0));
deps.push_back(p->node_tab(0));
@@ -3735,23 +3774,31 @@ namespace getfem {
/* classical fem
*/
/* ******************************************************************** */
- static pfem classical_fem_(const char *suffix, const char *arg,
- bgeot::pgeometric_trans pgt,
- short_type k) {
+ static pfem classical_fem_(bgeot::pgeometric_trans pgt,
+ short_type k, bool complete=false,
+ bool discont=false, scalar_type alpha=0) {
DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(bgeot::pgeometric_trans,
pgt_last,0);
DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(short_type, k_last, short_type(-1));
- DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pfem, fm_last, 0);
- DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(char, isuffix_last, 0);
- bool found = false, isuffix = suffix[0];
-
- if (pgt_last == pgt && k_last == k && isuffix == isuffix_last)
- return fm_last;
+ DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pfem, fem_last, 0);
+ DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(char, complete_last, 0);
+ DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(char, discont_last, 0);
+ DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(scalar_type, alpha_last, 0);
- isuffix_last = isuffix;
+ bool found = false;
+ if (pgt_last == pgt && k_last == k && complete_last == complete &&
+ discont_last == discont && alpha_last == alpha)
+ return fem_last;
dim_type n = pgt->structure()->dim();
dim_type nbp = dim_type(pgt->basic_structure()->nb_points());
std::stringstream name;
+ std::string suffix(discont ? "_DISCONTINUOUS" : "");
+ GMM_ASSERT2(discont || alpha == scalar_type(0),
+ "Cannot use an alpha parameter in continuous elements.");
+ std::stringstream arg_;
+ if (discont && alpha != scalar_type(0))
+ arg_ << "," << alpha;
+ std::string arg(arg_.str());
// Identifying if it is a torus structure
if (bgeot::is_torus_geom_trans(pgt) && n == 3) n = 2;
@@ -3759,49 +3806,72 @@ namespace getfem {
/* Identifying P1-simplexes. */
if (nbp == n+1)
if (pgt->basic_structure() == bgeot::simplex_structure(n)) {
- name << "FEM_PK" << suffix << "(" << n << ',' << k << arg << ')';
+ name << "FEM_PK" << suffix << "(" << n << "," << k << arg << ")";
found = true;
}
/* Identifying Q1-parallelepiped. */
if (!found && nbp == (size_type(1) << n))
if (pgt->basic_structure() == bgeot::parallelepiped_structure(n)) {
- name << "FEM_QK" << suffix << "(" << n << "," << k << arg << ")";
+ if (!complete && k == 2 && (n == 2 || n == 3) &&
+ pgt->structure() == bgeot::Q2_incomplete_structure(n)) {
+ GMM_ASSERT2(alpha == scalar_type(0),
+ "Cannot use an alpha parameter in incomplete Q2"
+ " elements.");
+ name << "FEM_Q2_INCOMPLETE" << suffix << "(" << n << ")";
+ } else
+ name << "FEM_QK" << suffix << "(" << n << "," << k << arg << ")";
found = true;
}
/* Identifying Q1-prisms. */
if (!found && nbp == 2 * n)
- if (pgt->basic_structure() == bgeot::prism_structure(n)) {
- name << "FEM_PRISM_PK" << suffix << "(" << n << "," << k << arg << ")";
+ if (pgt->basic_structure() == bgeot::prism_P1_structure(n)) {
+ if (!complete && k == 2 && n == 3 &&
+ pgt->structure() == bgeot::prism_incomplete_P2_structure()) {
+ GMM_ASSERT2(alpha == scalar_type(0),
+ "Cannot use an alpha parameter in incomplete prism"
+ " elements.");
+ name << "FEM_PRISM_INCOMPLETE_P2" << suffix;
+ } else
+ name << "FEM_PRISM_PK" << suffix << "(" << n << "," << k << arg <<
")";
found = true;
}
/* Identifying pyramids. */
if (!found && nbp == 5)
- if (pgt->basic_structure() == bgeot::pyramid_structure(1)) {
- name << "FEM_PYRAMID_QK" << suffix << "(" << k << arg << ")";
+ if (pgt->basic_structure() == bgeot::pyramid_QK_structure(1)) {
+ if (!complete && k == 2 &&
+ pgt->structure() == bgeot::pyramid_Q2_incomplete_structure()) {
+ GMM_ASSERT2(alpha == scalar_type(0),
+ "Cannot use an alpha parameter in incomplete pyramid"
+ " elements.");
+ name << "FEM_PYRAMID_Q2_INCOMPLETE" << suffix;
+ } else
+ name << "FEM_PYRAMID_QK" << suffix << "(" << k << arg << ")";
found = true;;
}
// To be completed
GMM_ASSERT1(found, "This element is not taken into account. Contact us");
- fm_last = fem_descriptor(name.str());
+ fem_last = fem_descriptor(name.str());
pgt_last = pgt;
k_last = k;
- return fm_last;
+ complete_last = complete;
+ discont_last = discont;
+ alpha_last = alpha;
+ return fem_last;
}
- pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k) {
- return classical_fem_("", "", pgt, k);
+ pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k,
+ bool complete) {
+ return classical_fem_(pgt, k, complete);
}
pfem classical_discontinuous_fem(bgeot::pgeometric_trans pgt, short_type k,
- scalar_type alpha) {
- char arg[128]; arg[0] = 0;
- if (alpha) sprintf(arg, ",%g", alpha);
- return classical_fem_("_DISCONTINUOUS", arg, pgt, k);
+ scalar_type alpha, bool complete) {
+ return classical_fem_(pgt, k, complete, true, alpha);
}
/* ******************************************************************** */
@@ -3855,6 +3925,7 @@ namespace getfem {
PK_composite_full_hierarch_fem);
add_suffix("PK_GAUSSLOBATTO1D", PK_GL_fem);
add_suffix("Q2_INCOMPLETE", Q2_incomplete_fem);
+ add_suffix("Q2_INCOMPLETE_DISCONTINUOUS",
Q2_incomplete_discontinuous_fem);
add_suffix("HCT_TRIANGLE", HCT_triangle_fem);
add_suffix("REDUCED_HCT_TRIANGLE", reduced_HCT_triangle_fem);
add_suffix("QUADC1_COMPOSITE", quadc1p3_fem);
diff --git a/src/getfem_mesh_fem.cc b/src/getfem_mesh_fem.cc
index 8217a5a..a86cc98 100644
--- a/src/getfem_mesh_fem.cc
+++ b/src/getfem_mesh_fem.cc
@@ -38,10 +38,12 @@ namespace getfem {
if (auto_add_elt_disc)
const_cast<mesh_fem *>(this)
->set_classical_discontinuous_finite_element
- (cv, auto_add_elt_K, auto_add_elt_alpha);
+ (cv, auto_add_elt_K, auto_add_elt_alpha,
+ auto_add_elt_complete);
else
const_cast<mesh_fem *>(this)
- ->set_classical_finite_element(cv, auto_add_elt_K);
+ ->set_classical_finite_element(cv, auto_add_elt_K,
+ auto_add_elt_complete);
}
else
const_cast<mesh_fem *>(this)->set_finite_element(cv, 0);
@@ -60,10 +62,11 @@ namespace getfem {
if (auto_add_elt_disc)
const_cast<mesh_fem *>(this)
->set_classical_discontinuous_finite_element
- (cv, auto_add_elt_K, auto_add_elt_alpha);
+ (cv, auto_add_elt_K, auto_add_elt_alpha,
auto_add_elt_complete);
else
const_cast<mesh_fem *>(this)
- ->set_classical_finite_element(cv, auto_add_elt_K);
+ ->set_classical_finite_element(cv, auto_add_elt_K,
+ auto_add_elt_complete);
}
}
}
@@ -169,46 +172,51 @@ namespace getfem {
{ set_finite_element(linked_mesh().convex_index(), ppf); set_auto_add(ppf); }
void mesh_fem::set_classical_finite_element(size_type cv,
- dim_type fem_degree) {
+ dim_type fem_degree,
+ bool complete) {
pfem pf = getfem::classical_fem(linked_mesh().trans_of_convex(cv),
- fem_degree);
+ fem_degree, complete);
set_finite_element(cv, pf);
}
void mesh_fem::set_classical_finite_element(const dal::bit_vector &cvs,
- dim_type fem_degree) {
+ dim_type fem_degree,
+ bool complete) {
for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
pfem pf = getfem::classical_fem(linked_mesh().trans_of_convex(cv),
- fem_degree);
+ fem_degree, complete);
set_finite_element(cv, pf);
}
}
- void mesh_fem::set_classical_finite_element(dim_type fem_degree) {
- set_classical_finite_element(linked_mesh().convex_index(), fem_degree);
+ void mesh_fem::set_classical_finite_element(dim_type fem_degree,
+ bool complete) {
+ set_classical_finite_element(linked_mesh().convex_index(), fem_degree,
+ complete);
set_auto_add(fem_degree, false);
}
void mesh_fem::set_classical_discontinuous_finite_element
- (size_type cv, dim_type fem_degree, scalar_type alpha) {
+ (size_type cv, dim_type fem_degree, scalar_type alpha, bool complete) {
pfem pf = getfem::classical_discontinuous_fem
- (linked_mesh().trans_of_convex(cv), fem_degree, alpha);
+ (linked_mesh().trans_of_convex(cv), fem_degree, alpha, complete);
set_finite_element(cv, pf);
}
void mesh_fem::set_classical_discontinuous_finite_element
- (const dal::bit_vector &cvs, dim_type fem_degree, scalar_type alpha) {
+ (const dal::bit_vector &cvs, dim_type fem_degree, scalar_type alpha,
+ bool complete) {
for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
pfem pf = getfem::classical_discontinuous_fem
- (linked_mesh().trans_of_convex(cv), fem_degree, alpha);
+ (linked_mesh().trans_of_convex(cv), fem_degree, alpha, complete);
set_finite_element(cv, pf);
}
}
void mesh_fem::set_classical_discontinuous_finite_element
- (dim_type fem_degree, scalar_type alpha) {
- set_classical_discontinuous_finite_element(linked_mesh().convex_index(),
- fem_degree,alpha);
+ (dim_type fem_degree, scalar_type alpha, bool complete) {
+ set_classical_discontinuous_finite_element
+ (linked_mesh().convex_index(), fem_degree, alpha, complete);
set_auto_add(fem_degree, true, alpha);
}
@@ -499,6 +507,7 @@ namespace getfem {
auto_add_elt_pf = mf.auto_add_elt_pf;
auto_add_elt_K = mf.auto_add_elt_K;
auto_add_elt_disc = mf.auto_add_elt_disc;
+ auto_add_elt_complete = mf.auto_add_elt_complete;
auto_add_elt_alpha = mf.auto_add_elt_alpha;
mi = mf.mi;
dof_partition = mf.dof_partition;
@@ -786,8 +795,9 @@ namespace getfem {
struct mf__key_ : public context_dependencies {
const mesh *pmsh;
dim_type order, qdim;
- mf__key_(const mesh &msh, dim_type o, dim_type q)
- : pmsh(&msh), order(o), qdim(q)
+ bool complete;
+ mf__key_(const mesh &msh, dim_type o, dim_type q, bool complete_)
+ : pmsh(&msh), order(o), qdim(q), complete(complete_)
{ add_dependency(msh); }
bool operator <(const mf__key_ &a) const {
if (pmsh < a.pmsh) return true;
@@ -795,11 +805,16 @@ namespace getfem {
else if (order < a.order) return true;
else if (order > a.order) return false;
else if (qdim < a.qdim) return true;
+ else if (qdim > a.qdim) return false;
+ else if (complete < a.complete) return true;
return false;
}
void update_from_context() const {}
mf__key_(const mf__key_ &mfk) : context_dependencies( ) {
- pmsh = mfk.pmsh; order = mfk.order; qdim = mfk.qdim;
+ pmsh = mfk.pmsh;
+ order = mfk.order;
+ qdim = mfk.qdim;
+ complete = mfk.complete;
add_dependency(*pmsh);
}
private :
@@ -816,7 +831,8 @@ namespace getfem {
public :
- const mesh_fem &operator()(const mesh &msh, dim_type o, dim_type qdim) {
+ const mesh_fem &operator()(const mesh &msh, dim_type o, dim_type qdim,
+ bool complete=false) {
mesh_fem_tab::iterator itt = mfs.begin(), itn = mfs.begin();
if (itn != mfs.end()) itn++;
while (itt != mfs.end()) {
@@ -826,7 +842,7 @@ namespace getfem {
if (itn != mfs.end()) itn++;
}
- mf__key_ key(msh, o, qdim);
+ mf__key_ key(msh, o, qdim, complete);
mesh_fem_tab::iterator it = mfs.find(key);
assert(it == mfs.end() || it->second->is_context_valid());
@@ -844,10 +860,11 @@ namespace getfem {
};
const mesh_fem &classical_mesh_fem(const mesh &msh,
- dim_type order, dim_type qdim) {
+ dim_type order, dim_type qdim,
+ bool complete) {
classical_mesh_fem_pool &pool
= dal::singleton<classical_mesh_fem_pool>::instance();
- return pool(msh, order, qdim);
+ return pool(msh, order, qdim, complete);
}
struct dummy_mesh_fem_ {