getfem-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Getfem-commits] (no subject)


From: Franz Chouly
Subject: [Getfem-commits] (no subject)
Date: Fri, 26 May 2017 10:31:29 -0400 (EDT)

branch: devel-franz
commit 515905dfa4070a3be8ee2c2aeba3fb1b85dfc84f
Author: Franz CHOULY MCF <address@hidden>
Date:   Fri May 26 16:31:09 2017 +0200

    Pyramid element (in progress)
---
 doc/sphinx/source/userdoc/appendixA.rst          |   4 +-
 interface/src/gf_mesh.cc                         |  87 ++++++++++++++
 interface/tests/python/demo_laplacian_pyramid.py | 141 +++++++++++++++++++++++
 src/bgeot_convex_ref.cc                          |   4 +-
 src/bgeot_convex_structure.cc                    |   2 +-
 src/bgeot_geometric_trans.cc                     |  11 +-
 src/getfem/getfem_mesh.h                         |   3 +
 src/getfem/getfem_regular_meshes.h               |  16 +++
 src/getfem_mesh.cc                               |   6 +
 src/getfem_regular_meshes.cc                     |  51 +++++++-
 10 files changed, 315 insertions(+), 10 deletions(-)

diff --git a/doc/sphinx/source/userdoc/appendixA.rst 
b/doc/sphinx/source/userdoc/appendixA.rst
index 14b950b..3367648 100644
--- a/doc/sphinx/source/userdoc/appendixA.rst
+++ b/doc/sphinx/source/userdoc/appendixA.rst
@@ -1309,7 +1309,7 @@ Specific elements in dimension 3
 Lagrange elements on 3D pyramid
 +++++++++++++++++++++++++++++++
 
-|gf| proposes some LAgrange pyramidal elements of dergree 0, 1 and two based 
on [GR-GH1999]_ and [BE-CO-DU2010]_. See these references for more details. The 
proposed element can be raccorded to standard :math:`P_1` or :math:`P_2` 
Lagrange fem on the triangular faces and to a standard :math:`Q_1` or 
:math:`Q_2` Lagrange fem on the quatrilateral face.
+|gf| proposes some Lagrange pyramidal elements of degree 0, 1 and two based on 
[GR-GH1999]_ and [BE-CO-DU2010]_. See these references for more details. The 
proposed element can be raccorded to standard :math:`P_1` or :math:`P_2` 
Lagrange fem on the triangular faces and to a standard :math:`Q_1` or 
:math:`Q_2` Lagrange fem on the quatrilateral face.
 
 .. _ud-fig-pyramid-lagrange:
 .. list-table:: Lagrange element on a pyramidal element of order 0, 1 and 2
@@ -1345,7 +1345,7 @@ The shape functions are not polynomial ones but rational 
fractions. For the firs
    \widehat{\varphi}_{4}(x,y,z) =  z.\\
    \end{array}
 
-For the second degree, en posant
+For the second degree, setting
 
 .. math::
 
diff --git a/interface/src/gf_mesh.cc b/interface/src/gf_mesh.cc
index 4168ec9..1167c8f 100644
--- a/interface/src/gf_mesh.cc
+++ b/interface/src/gf_mesh.cc
@@ -98,6 +98,87 @@ cartesian_mesh(getfem::mesh *pmesh, getfemint::mexargs_in 
&in,
   }
 }
 
+static void
+pyramidal_mesh(getfem::mesh *pmesh, getfemint::mexargs_in &in) {
+  getfemint::size_type dim = 3;
+
+  std::vector<darray> ppos(dim);
+  std::vector<size_type> npts(dim);
+  size_type grid_npoints=1, grid_nconvex=1;
+  for (size_type i = 0; i < dim; i++) {
+    ppos[i] = in.pop().to_darray();
+    npts[i] = ppos[i].size();
+    grid_npoints *= npts[i];
+    grid_nconvex *= (npts[i]-1);
+  }
+
+  /* add the points in 'fortran style' order */
+  getfem::base_node pt(dim);
+  for (size_type i=0; i < grid_npoints; i++) {
+    size_type k = i;
+    for (size_type j = 0; j < dim; j++) {
+      pt[j] = ppos[j][k % (npts[j])];
+      k /= (npts[j]);
+    }
+
+    size_type id_pt = pmesh->add_point(pt);
+    if (id_pt != i) {
+      THROW_ERROR(
+               "something has changed in getfem, you need to reconsider "
+               "gf_mesh('cartesian')\nfor point " << i <<
+               ", the index is " << id_pt << endl);
+    }
+  }
+
+
+  std::vector<int> ipt(dim);
+  std::vector<getfem::base_node> pts(1 << (dim+1));
+
+  bgeot::pgeometric_trans pgt = bgeot::pyramidal_geotrans(1);
+
+  /* add the convexes */
+  for (size_type i=0; i < grid_nconvex; i++) {
+    size_type k = i;
+
+    /* find point location */
+    for (size_type j = 0; j < dim; j++) {
+      ipt[j] = int(k % (npts[j]-1));
+      k /= (npts[j]-1);
+    }
+
+    /* build the vertices list */
+    for (size_type j = 0; j < (unsigned(1)<<dim); j++) {
+      pts[j].resize(dim);
+      for (size_type d=0; d < dim; d++) {
+       if ((j >> d) & 1) {
+         pts[j][d] = ppos[d][ipt[d]+1];
+       } else {
+         pts[j][d] = ppos[d][ipt[d]];
+       }
+      }
+    }
+    bgeot::base_node barycenter;
+    std::vector<size_type> iipts(8);
+    for (size_type j = 0; j < 8; j++) {
+       barycenter += pts[j];
+       iipts[j] = pmesh->add_point(pts[j]);
+    }
+    barycenter /= 8.; size_type ib = pmesh->add_point(barycenter);
+   
+
+    // we don't use the add_parall since the geometric transformation
+    // is linear (the mesh is cartesian)
+    //pmesh->add_parallelepiped_by_points(dim, pts.begin());
+    //pmesh->add_convex_by_points(pgt, pts.begin());
+    pmesh->add_pyramid(iipts[0],iipts[1],iipts[2],iipts[3],ib);
+    pmesh->add_pyramid(iipts[4],iipts[6],iipts[5],iipts[7],ib);
+    pmesh->add_pyramid(iipts[0],iipts[4],iipts[1],iipts[5],ib);
+    pmesh->add_pyramid(iipts[1],iipts[5],iipts[3],iipts[7],ib);
+    pmesh->add_pyramid(iipts[3],iipts[7],iipts[2],iipts[6],ib);
+    pmesh->add_pyramid(iipts[2],iipts[6],iipts[0],iipts[4],ib);
+
+  }
+}
 
 static void
 triangles_grid_mesh(getfem::mesh *pmesh, getfemint::mexargs_in &in)
@@ -355,6 +436,12 @@ void gf_mesh(getfemint::mexargs_in& m_in,
        cartesian_mesh(pmesh, in);
        );
 
+    /address@hidden M = ('pyramidal', @dvec X[, @dvec Y[, @dvec Z,..]])
+      Build quickly a regular mesh of pyramids, address@hidden/
+    sub_command
+      ("pyramidal", 1, 32, 0, 1,
+       pyramidal_mesh(pmesh, in);
+       );
 
     /address@hidden M = ('cartesian Q1', @dvec X, @dvec Y[, @dvec Z,..])
       Build quickly a regular mesh of quadrangles, cubes, etc. with
diff --git a/interface/tests/python/demo_laplacian_pyramid.py 
b/interface/tests/python/demo_laplacian_pyramid.py
new file mode 100644
index 0000000..89bcb35
--- /dev/null
+++ b/interface/tests/python/demo_laplacian_pyramid.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Python GetFEM++ interface
+#
+# Copyright (C) 2004-2017 Yves Renard, Julien Pommier.
+#
+# This file is a part of GetFEM++
+#
+# GetFEM++  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;  either version 2.1 of the License,  or
+# (at your option) any later version.
+# This program  is  distributed  in  the  hope  that it will be useful,  but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# You  should  have received a copy of the GNU Lesser General Public License
+# along  with  this program;  if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+############################################################################
+"""  2D Poisson problem test.
+
+  This program is used to check that python-getfem is working. This is
+  also a good example of use of GetFEM++.
+
+  $Id$
+"""
+# Import basic modules
+import getfem as gf
+import numpy as np
+
+## Parameters
+NX = 100                           # Mesh parameter.
+Dirichlet_with_multipliers = True  # Dirichlet condition with multipliers
+                                   # or penalization
+dirichlet_coefficient = 1e10       # Penalization coefficient
+
+# Create a simple cartesian mesh
+m = gf.Mesh('pyramidal', np.arange(0,1+1./NX,1./NX),
+            np.arange(0,1+1./NX,1./NX), np.arange(0,1+1./NX,1./NX) )
+
+# Create a MeshFem for u and rhs fields of dimension 1 (i.e. a scalar field)
+mfu   = gf.MeshFem(m, 1)
+mfrhs = gf.MeshFem(m, 1)
+# assign the P2 fem to all convexes of the both MeshFem
+mfu.set_fem(gf.Fem('FEM_PYRAMID_LAGRANGE(1)'))
+mfrhs.set_fem(gf.Fem('FEM_PYRAMID_LAGRANGE(1)'))
+
+#  Integration method used
+mim = gf.MeshIm(m, gf.Integ('IM_PYRAMID_COMPOSITE(IM_TETRAHEDRON(4))'))
+
+# Boundary selection
+flst  = m.outer_faces()
+fnor  = m.normal_of_faces(flst)
+tleft = abs(fnor[1,:]+1) < 1e-14
+ttop  = abs(fnor[0,:]-1) < 1e-14
+fleft = np.compress(tleft, flst, axis=1)
+ftop  = np.compress(ttop, flst, axis=1)
+fneum = np.compress(True - ttop - tleft, flst, axis=1)
+
+# Mark it as boundary
+DIRICHLET_BOUNDARY_NUM1 = 1
+DIRICHLET_BOUNDARY_NUM2 = 2
+NEUMANN_BOUNDARY_NUM = 3
+m.set_region(DIRICHLET_BOUNDARY_NUM1, fleft)
+m.set_region(DIRICHLET_BOUNDARY_NUM2, ftop)
+m.set_region(NEUMANN_BOUNDARY_NUM, fneum)
+
+# Interpolate the exact solution (Assuming mfu is a Lagrange fem)
+Ue = mfu.eval('y*(y-1)*x*(x-1)+x*x*x*x*x')
+
+# Interpolate the source term
+F1 = mfrhs.eval('-(2*(x*x+y*y)-2*x-2*y+20*x*x*x)')
+F2 = mfrhs.eval('[y*(y-1)*(2*x-1) + 5*x*x*x*x, x*(x-1)*(2*y-1)]')
+
+# Model
+md = gf.Model('real')
+
+# Main unknown
+md.add_fem_variable('u', mfu)
+
+# Laplacian term on u
+md.add_Laplacian_brick(mim, 'u')
+
+# Volumic source term
+md.add_initialized_fem_data('VolumicData', mfrhs, F1)
+md.add_source_term_brick(mim, 'u', 'VolumicData')
+
+# Neumann condition.
+md.add_initialized_fem_data('NeumannData', mfrhs, F2)
+md.add_normal_source_term_brick(mim, 'u', 'NeumannData',
+                                NEUMANN_BOUNDARY_NUM)
+
+# Dirichlet condition on the left.
+md.add_initialized_fem_data("DirichletData", mfu, Ue)
+
+if (Dirichlet_with_multipliers):
+  md.add_Dirichlet_condition_with_multipliers(mim, 'u', mfu,
+                                              DIRICHLET_BOUNDARY_NUM1,
+                                              'DirichletData')
+else:
+  md.add_Dirichlet_condition_with_penalization(mim, 'u', dirichlet_coefficient,
+                                               DIRICHLET_BOUNDARY_NUM1,
+                                               'DirichletData')
+
+# Dirichlet condition on the top.
+# Two Dirichlet brick in order to test the multiplier
+# selection in the intersection.
+if (Dirichlet_with_multipliers):
+  md.add_Dirichlet_condition_with_multipliers(mim, 'u', mfu,
+                                              DIRICHLET_BOUNDARY_NUM2,
+                                              'DirichletData')
+else:
+  md.add_Dirichlet_condition_with_penalization(mim, 'u', dirichlet_coefficient,
+                                               DIRICHLET_BOUNDARY_NUM2,
+                                               'DirichletData')
+gf.memstats()
+# md.listvar()
+# md.listbricks()
+
+# Assembly of the linear system and solve.
+md.solve()
+
+# Main unknown
+U = md.variable('u')
+L2error = gf.compute(mfu, U-Ue, 'L2 norm', mim)
+H1error = gf.compute(mfu, U-Ue, 'H1 norm', mim)
+print 'Error in L2 norm : ', L2error
+print 'Error in H1 norm : ', H1error
+
+# Export data
+mfu.export_to_pos('laplacian.pos', Ue,'Exact solution',
+                                    U,'Computed solution')
+print 'You can view the solution with (for example):'
+print 'gmsh laplacian.pos'
+
+
+if (H1error > 1e-3):
+    print 'Error too large !'
+    exit(1)
diff --git a/src/bgeot_convex_ref.cc b/src/bgeot_convex_ref.cc
index 38536ab..6145062 100644
--- a/src/bgeot_convex_ref.cc
+++ b/src/bgeot_convex_ref.cc
@@ -318,7 +318,7 @@ namespace bgeot {
     }
     
     pyramid_of_ref_(dim_type k) {
-      GMM_ASSERT1(k == 1 || k == 2, "Sorry exist only in degree 2 or 3");
+      GMM_ASSERT1(k == 1 || k == 2, "Sorry exist only in degree 1 or 2");
 
       cvs = pyramidal_structure(k);
       convex<base_node>::points().resize(cvs->nb_points());
@@ -401,7 +401,7 @@ namespace bgeot {
 
     scalar_type is_in_face(short_type f, const base_node &pt) const {
       // ne controle pas si le point est dans le convexe mais si un point
-      // suppos� appartenir au convexe est dans une face donn�e
+      // suppos\E9 appartenir au convexe est dans une face donn\E9e
       dim_type n1 = cvr1->structure()->dim(), n2 = cvr2->structure()->dim();
       base_node pt1(n1), pt2(n2);
       GMM_ASSERT1(pt.size() == cvs->dim(), "Dimensions mismatch");
diff --git a/src/bgeot_convex_structure.cc b/src/bgeot_convex_structure.cc
index c96f210..bb936f3 100644
--- a/src/bgeot_convex_structure.cc
+++ b/src/bgeot_convex_structure.cc
@@ -481,7 +481,7 @@ namespace bgeot {
     p->dir_points_ = std::vector<short_type>(p->Nc + 1);
     
 
-    if (k == 2) {
+    if (k == 1) {
       p->nbpt = 5;
       p->nbf = 5;
       p->auto_basic = true;
diff --git a/src/bgeot_geometric_trans.cc b/src/bgeot_geometric_trans.cc
index bd0fd55..6d3b50b 100644
--- a/src/bgeot_geometric_trans.cc
+++ b/src/bgeot_geometric_trans.cc
@@ -882,9 +882,14 @@ namespace bgeot {
   }
   
   pgeometric_trans pyramidal_geotrans(short_type k) {
-    std::stringstream name;
-    name << "GT_PYRAMID(" << k << ")";
-    return geometric_trans_descriptor(name.str());
+    static short_type k_ = -1;
+    static pgeometric_trans pgt = 0;
+    if (k != k_) {
+      std::stringstream name;
+      name << "GT_PYRAMID(" << k << ")";
+      pgt = geometric_trans_descriptor(name.str());
+    }
+    return pgt;  
   }
 
   /* ******************************************************************** */
diff --git a/src/getfem/getfem_mesh.h b/src/getfem/getfem_mesh.h
index d480f5b..7f55050 100644
--- a/src/getfem/getfem_mesh.h
+++ b/src/getfem/getfem_mesh.h
@@ -279,6 +279,9 @@ namespace getfem {
                                         const base_node &p2,
                                         const base_node &p3,
                                         const base_node &p4);
+    /** Add a pyramid to the mesh, given the point id of its vertices. */
+    size_type add_pyramid(size_type a,
+                          size_type b, size_type c, size_type d, size_type e);
     /** Add a parallelepiped to the mesh.
         @param di dimension of the parallelepiped
         @param ipts iterator on the list of point id.
diff --git a/src/getfem/getfem_regular_meshes.h 
b/src/getfem/getfem_regular_meshes.h
index 69ae81b..7771be6 100644
--- a/src/getfem/getfem_regular_meshes.h
+++ b/src/getfem/getfem_regular_meshes.h
@@ -100,6 +100,22 @@ namespace getfem
     parallelepiped_regular_mesh_(me, N, org, &(vect[0]), &(ref[0]), linear_gt);
   } 
 
+  void parallelepiped_regular_pyramid_mesh_(mesh &me, const base_node &org,
+   const base_small_vector *ivect, const size_type *iref);
+
+  template<class ITER1, class ITER2>
+    void parallelepiped_regular_pyramid_mesh(mesh &me,
+                                     const base_node &org, ITER1 ivect, ITER2 
iref)
+  { 
+    int N=3;
+    std::vector<base_small_vector> vect(N);
+    std::copy(ivect, ivect+N, vect.begin());
+    std::vector<size_type> ref(N);
+    std::copy(iref, iref+N, ref.begin());
+    parallelepiped_regular_pyramid_mesh_(me, org, &(vect[0]), &(ref[0]));
+  } 
+
+
   /**
      Build a regular mesh of the unit square/cube/, etc.
      @param m the output mesh.
diff --git a/src/getfem_mesh.cc b/src/getfem_mesh.cc
index 51ced91..9d1764a 100644
--- a/src/getfem_mesh.cc
+++ b/src/getfem_mesh.cc
@@ -298,6 +298,12 @@ namespace getfem {
     return add_simplex(3, &(ipt[0]));
   }
 
+  size_type mesh::add_pyramid(size_type a, size_type b,
+                                  size_type c, size_type d, size_type e) {
+    size_type ipt[5]; ipt[0] = a; ipt[1] = b; ipt[2] = c; ipt[3] = d; ipt[4] = 
e;
+    return add_convex(bgeot::pyramidal_geotrans(1), &(ipt[0]));
+  }
+
   size_type mesh::add_tetrahedron_by_points
   (const base_node &p1, const base_node &p2,
    const base_node &p3, const base_node &p4) {
diff --git a/src/getfem_regular_meshes.cc b/src/getfem_regular_meshes.cc
index 6f85b58..29d13f6 100644
--- a/src/getfem_regular_meshes.cc
+++ b/src/getfem_regular_meshes.cc
@@ -100,8 +100,6 @@ namespace getfem
     }
   }
 
-
-
   void parallelepiped_regular_mesh_
   (mesh &me, dim_type N, const base_node &org,
    const base_small_vector *ivect, const size_type *iref, bool linear_gt) {
@@ -140,6 +138,52 @@ namespace getfem
     }
   }
 
+  void parallelepiped_regular_pyramid_mesh_
+  (mesh &me, const base_node &org,
+   const base_small_vector *ivect, const size_type *iref) {
+    dim_type N = 3;
+    bgeot::convex<base_node>
+      pararef = *(bgeot::parallelepiped_of_reference(N));
+    base_node a = org, barycenter;
+    size_type i, nbpt = pararef.nb_points();
+
+    for (i = 0; i < nbpt; ++i) {
+      gmm::clear(a);
+      for (dim_type n = 0; n < N; ++n)
+        gmm::add(gmm::scaled(ivect[n],pararef.points()[i][n]),a);
+      //a.addmul(pararef.points()[i][n], ivect[n]);
+      pararef.points()[i] = a;
+      barycenter += a;
+    }
+    barycenter /= double(nbpt);
+
+    std::vector<size_type> tab1(N+1), tab(N), tab3(nbpt);
+    size_type total = 0;
+    std::fill(tab.begin(), tab.end(), 0);
+    while (tab[N-1] != iref[N-1]) {
+      for (a = org, i = 0; i < N; i++)
+        gmm::add(gmm::scaled(ivect[i], scalar_type(tab[i])),a);
+      //a.addmul(scalar_type(tab[i]), ivect[i]);
+
+      for (i = 0; i < nbpt; i++)
+        tab3[i] = me.add_point(a + pararef.points()[i]);
+      size_type ib = me.add_point(a + barycenter);
+      me.add_pyramid(tab3[0],tab3[1],tab3[2],tab3[3],ib);
+      me.add_pyramid(tab3[4],tab3[6],tab3[5],tab3[7],ib);
+      me.add_pyramid(tab3[0],tab3[4],tab3[1],tab3[5],ib);
+      me.add_pyramid(tab3[1],tab3[5],tab3[3],tab3[7],ib);
+      me.add_pyramid(tab3[3],tab3[7],tab3[2],tab3[6],ib);
+      me.add_pyramid(tab3[2],tab3[6],tab3[0],tab3[4],ib);
+
+      for (dim_type l = 0; l < N; l++) {
+        tab[l]++; total++;
+        if (l < N-1 && tab[l] >= iref[l]) { total -= tab[l]; tab[l] = 0; }
+        else break;
+      }
+    }
+  }
+
+
   /* deformation inside a unit square  -- ugly */
   static base_node shake_func(const base_node& x) {
     base_node z(x.size());
@@ -210,6 +254,9 @@ namespace getfem
     } else if (pgt->basic_structure() == bgeot::prism_structure(N)) {
       getfem::parallelepiped_regular_prism_mesh
         (msh, N, org, vtab.begin(), nsubdiv.begin());
+    } else if (pgt->basic_structure() == bgeot::pyramidal_structure(1)) {
+      getfem::parallelepiped_regular_pyramid_mesh
+        (msh, org, vtab.begin(), nsubdiv.begin());
     } else {
       GMM_ASSERT1(false, "cannot build a regular mesh for "
                   << bgeot::name_of_geometric_trans(pgt));



reply via email to

[Prev in Thread] Current Thread [Next in Thread]