diff --git a/DESCRIPTION.rst b/DESCRIPTION.rst
old mode 100644
new mode 100755
index 2ff45fb..a778309
--- a/DESCRIPTION.rst
+++ b/DESCRIPTION.rst
@@ -1,9 +1,9 @@
-PETGEM
+petgem
======
PETGEM is a parallel python code for 3D Controlled-Source
-Electromagnetic Method (3D CSEM) in geophysics using edge finite
-elements (Nedelec finite elements).
+Electromagnetic Method (3D CSEM) in geophysics using high-order edge finite
+elements (Nédélec finite elements).
Requirements
@@ -29,15 +29,15 @@ Install
* Following commands may require root privileges
-* Download `PETSc `__ (PETSc 3.7 and 3.8 have been tested)
+* Download `PETSc `__ (PETSc 3.7, 3.8, and 3.9 have been tested)
-* Uncompress the PETSc archive (in this example, using PETSc 3.8.3)::
+* Uncompress the PETSc archive (in this example, using PETSc 3.9.3)::
- $ tar zxvf petsc-3.8.3.tar.gz
+ $ tar zxvf petsc-3.9.3.tar.gz
* Configure and build PETSc. The configuration options depend on the calculations you want to perform (complex- or real-valued) as well as your compiler/MPI/Blas/Lapack setup. For PETGEM executions, **PETSC MUST BE BUILD FOR COMPLEX-VALUED NUMBERS**. In order to avoid incompatibilities between PETSC, petsc4py and PETGEM, we highly recommend the following configuration lines. Please, visit PETSc website for advanced configuration options. If you have a clean environment (not working MPI/Blas/Lapack), then run::
- $ cd petsc-3.8.3
+ $ cd petsc-3.9.3
$ export PETSC_DIR=$PWD
$ export PETSC_ARCH=arch-linux2-c-debug
@@ -49,6 +49,12 @@ Install
$ --download-mumps --download-scalapack --download-parmetis --download-metis --download-ptscotch --download-cmake
+* Further, to activate GPUs support, please add following options to previous configure line::
+
+ $ --with-cuda=1 --with_cuda_dir=PATH
+
+ where ``PATH`` is the directory of your CUDA libraries.
+
* Then, build and install PETSc::
$ make $PETSC_DIR $PETSC_ARCH all
@@ -79,8 +85,8 @@ publication, please acknowledge that fact by citing the project:
elements*. Computers & Geosciences, vol 119: 123-136. ISSN 0098-3004,
Elsevier. https://doi.org/10.1016/j.cageo.2018.07.005
-* Castillo-Reyes, O., de la Puente, J., Cela, J.M. (2017).
- *Three-Dimensional CSEM Modelling on Unstructured Tetrahedral Meshes
- Using Edge Finite Elements*. Communications in Computer and
- Information Science, vol 697: 247-256. ISBN 978-3-319-57971-9,
- Springer, Cham. https://doi.org/10.1007/978-3-319-57972-6_18
+* Castillo-Reyes, O., de la Puente, J., Cela, J.M. (2017).
+ *Three-Dimensional CSEM Modelling on Unstructured Tetrahedral Meshes
+ Using Edge Finite Elements*, Communications in Computer and
+ Information Science, vol 697: 247-256. ISBN 978-3-319-57971-9
+ Springer, Cham. https://doi.org/10.1007/978-3-319-57972-6_18
diff --git a/README.rst b/README.rst
old mode 100644
new mode 100755
index 9360fe7..233d630
--- a/README.rst
+++ b/README.rst
@@ -4,9 +4,9 @@ petgem
Overview
========
-Welcome to petgem. This code is a parallel python modelling tool for 3D
+Welcome to PETGEM. This code is a parallel python modelling tool for 3D
Controlled-Source Electromagnetic Method (3D CSEM) in geophysics using
-edge finite elements (Nedelec finite elements).
+high-order edge finite elements (Nédélec finite elements).
Dependencies
------------
@@ -34,7 +34,7 @@ License
PETGEM is developed as open-source under GPLv3.0 license at Computer
Applications in Science & Engineering of the Barcelona Supercomputing
Center - Centro Nacional de Supercomputación. Please, see the CONDITIONS
-OF USE described in the LICENSE.rst file.
+OF USE described in the LICENSE.rst file.
Documentation
diff --git a/doc/Makefile b/doc/Makefile
old mode 100644
new mode 100755
diff --git a/doc/source/CSEMEdges.rst b/doc/source/CSEMEdges.rst
old mode 100644
new mode 100755
index 235037b..d476755
--- a/doc/source/CSEMEdges.rst
+++ b/doc/source/CSEMEdges.rst
@@ -19,8 +19,8 @@ of freedom, e.g. size of the problem. Furthermore, its divergence-free basis
is very well suited for solving Maxwell’s equation. On top of that, we choose
to support tetrahedral meshes, as these are the easiest to use for very large
domains or complex geometries. We present the numerical formulation and
-results of 3D CSEM forward modelling (FM) using tetrahedral EFEM on
-unstructured meshes.
+results of 3D CSEM forward modelling (FM) using EFEM of high-order on
+unstructured tetrahedral meshes.
.. _CSEM problem:
@@ -33,11 +33,11 @@ CSEM surveys generally work with low frequency electromagnetic fields
(:math:`\sim` 1 Hz to :math:`\sim` 3 Hz) because the electric conductivity of the geological
structures is much larger than their dielectric permittivity. As a
consequence, in an unbound domain :math:`\Gamma`, the electric field
-can be obtained by solving Maxwell’s equations in their diffusive form:
+can be obtained by solving Maxwell’s equations in their diffusive form
.. math::
- \nabla \times \mathbf{E} &= i\omega \mu_{0}\mathbf H \\
- \nabla \times \mathbf{H} &= \mathbf J_{s} + \tilde{\sigma}\mathbf E
+ \nabla \times \mathbf{E} &= i\omega \mu_{0}\mathbf H, \\
+ \nabla \times \mathbf{H} &= \mathbf J_{s} + \tilde{\sigma}\mathbf E,
:label: maxwellDiffusive
where the harmonic time dependence :math:`e^{-i \omega t}` is omitted,
@@ -52,21 +52,21 @@ The first one is the inevitable spatial singularity at the source. The
second is the grid refinement requirements in order to capture the rapid
change of the primary field [1]_. In order to mitigate these issues,
PETGEM used a secondary field approach where the total electric
-field :math:`\mathbf E` is obtained as:
+field :math:`\mathbf E` is obtained as
.. math::
- \mathbf E &= \mathbf E_{p} + \mathbf E_{s} \\
- \tilde{\sigma} &= \tilde{\sigma_{s}} + \Delta \tilde{\sigma}
+ \mathbf E &= \mathbf E_{p} + \mathbf E_{s}, \\
+ \tilde{\sigma} &= \tilde{\sigma_{s}} + \Delta \tilde{\sigma},
:label: total_electric_field
where subscripts :math:`p` and :math:`s` represent a primary field and
secondary field respectively. For a general layered Earth model,
:math:`\mathbf E_{p}` can be computed semi-analytically by using Hankel
transform filters. Based on this decomposition and following the work by
-[3]_ the equation system to solve :math:`\mathbf E_{s}` is:
+[3]_ the equation system to solve :math:`\mathbf E_{s}` is
.. math::
- \nabla \times \nabla \times \mathbf E_{s} + i \omega \mu \tilde{\sigma} \mathbf E_{s} = -i \omega \mu \Delta \sigma \mathbf E_{p}
+ \nabla \times \nabla \times \mathbf E_{s} + i \omega \mu \tilde{\sigma} \mathbf E_{s} = -i \omega \mu \Delta \sigma \mathbf E_{p},
:label: electric_field_weak_form1
where the electrical conductivity :math:`\sigma` is a function of position
@@ -81,60 +81,60 @@ based on the skin depth of the electric field [4]_.
Edge finite element formulation
-------------------------------
For the computation of :math:`\mathbf E_{s}`, PETGEM implemented the
-Nédélec EFEM which uses vector basis functions defined on the edges of
-the corresponding elements. Its basis functions are divergence-free but
+high-order Nédélec EFEM which uses vector basis functions defined on the edges,
+faces and volume of the corresponding elements. Its basis functions are divergence-free but
not curl-free [2]_. Thus, EFEM naturally ensures tangential continuity and
allows normal discontinuity of :math:`\mathbf E_{s}` at material interfaces.
PETGEM used unstructured tetrahedral meshes because of their ability to
represent complex geological structures such as bathymetry or reservoirs as
well as the local refinement capability in order to improve the solution
-accuracy. `Figure 4.1`_ shows the tetrahedral Nédélec elements (lowest order)
+accuracy. `Figure 4.1`_ shows the tetrahedral Nédélec elements (first-, second-, and third-order)
together with their node and edge indexing.
.. _Figure 4.1:
.. figure:: _static/figures/edgeElement.jpg
- :scale: 12%
- :alt: Tetrahedral Nédélec edge element with node/edge indexing.
+ :scale: 25%
+ :alt: Tetrahedral Nédélec edge element with node/edge/face indexing.
:align: center
- Figure 4.1. Tetrahedral Nédélec edge element with node/edge indexing.
+ Figure 4.1. Reference tetrahedral element showing numeration of DOFs for each order :math:`p`. For :math:`p=1` there are 6 DOFs (1 per edge). For :math:`p=2` there are 20 DOFs (2 per edge and 2 per face). Finally, for :math:`p=3` there are 45 DOFs (3 per edge, 6 per face and 3 per element's volume).
In PETGEM workflow, the tangential component of the secondary electric
field is assigned to the edges in the mesh. Therefore, all components of the
electric field at a point :math:`\mathbf x` located inside a tetrahedral
-element :math:`e` can be obtained as follows:
+element :math:`e` can be obtained as follows
.. math::
- \mathbf E^{e}(\mathbf x) = \sum_{i=1}^{6} \mathbf N^{e}_{i}(\mathbf x) E^{e}_{i}
+ \mathbf E^{e}(\mathbf x) = \sum_{i=1}^{ndofs} \mathbf N^{e}_{i}(\mathbf x) E^{e}_{i},
:label: field_components_edge_element
-where :math:`\mathbf N^{e}_{i}` are the vector basis functions associated
-to each edge :math:`i` and :math:`E^{e}_{i}` their degrees of freedom.
-Considering the node and edge indexing in `Figure 4.1`_, the vector basis
-functions can be expressed as follows:
+where :math:`\mathbf N^{e}_{i}` are the vector basis functions and :math:`E^{e}_{i}` their degrees of freedom.
+For instance, considering the node and edge indexing in `Figure 4.1`_, the vector basis
+functions for :math:`p=1` (first-order) can be expressed as follows
.. math::
- \mathbf N^{e}_{i} &= (\lambda^{e}_{i1} \nabla \lambda^{e}_{i2} - \lambda^{e}_{i2} \nabla \lambda^{e}_{i1}) \ell^{e}_{i}
+ \mathbf N^{e}_{i} &= (\lambda^{e}_{i1} \nabla \lambda^{e}_{i2} - \lambda^{e}_{i2} \nabla \lambda^{e}_{i1}) \ell^{e}_{i},
:label: nedelec_basis
where subscripts :math:`i1` and :math:`i2` are the first and second nodes
linked to the :math:`i`-th edge, :math:`\lambda^{e}_{i}` are the linear
nodal basis functions, and :math:`\ell^{e}_{i}` is the length of the
-:math:`i`-th edge of the element :math:`e`.
+:math:`i`-th edge of the element :math:`e`. A systematic approach for obtaining
+mixed-order curl-conforming basis functions may be seen in [4]_, [5]_.
By substituting equation :eq:`field_components_edge_element` into
:eq:`electric_field_weak_form1`, and using Galerkin's approach, the weak
-form of the original differential equation becomes:
+form of the original differential equation becomes
.. math::
- Q_{i} = \int_{\Omega} \mathbf N_{i} \cdot [ \nabla \times \nabla \times \mathbf E_{s} -i \omega \mu \tilde{\sigma} \mathbf E_{s} + i \omega \mu \Delta \tilde{\sigma} \mathbf E_{p} ] dV
+ Q_{i} = \int_{\Omega} \mathbf N_{i} \cdot [ \nabla \times \nabla \times \mathbf E_{s} -i \omega \mu \tilde{\sigma} \mathbf E_{s} + i \omega \mu \Delta \tilde{\sigma} \mathbf E_{p} ] dV,
:label: electric_field_weak_form2
The compact discretized form of :eq:`electric_field_weak_form2` is
-obtained after applying the Green's theorem:
+obtained after applying the Green's theorem
.. math::
- [K^{e}_{jk} + i \omega \tilde{\sigma}_{e} M^{e}_{jk}] \cdot \{ E_{sk} \} = - i \omega \mu \Delta \tilde{\sigma}_{e} R^{e}_k
+ [K^{e}_{jk} + i \omega \tilde{\sigma}_{e} M^{e}_{jk}] \cdot \{ E_{sk} \} = - i \omega \mu \Delta \tilde{\sigma}_{e} R^{e}_k,
:label: system_eq_edge_electric
where :math:`K^{e}` and :math:`M^{e}` are the elemental stiffness
@@ -146,3 +146,5 @@ side which requires numerical integration.
.. [2] Jin, J. (2002). The Finite Element Method in Electromagnetics. Wiley, New York, second edn.
.. [3] Newman, G.A. and Alumbaugh, D.L. (2002). Three-dimensional induction logging problems, Part 2: A finite difference solution. Geophysics, 67(2), 484–491.
.. [4] Puzyrev, V., Koldan, J., de la Puente, J., Houzeaux, G., Vázquez, M. and Cela, J.M. (2013). A parallel finite-element method for three-dimensional controlled-source electromagnetic forward modelling. Geophysical Journal International, ggt027.
+.. [5] Garcia-Castillo, L.E., Salazar-Palma, M., 2000. Second-order Nédélec tetrahedral element for computational electromagnetics. International Journal of Numerical Modelling: Electronic Networks, Devices and Fields (John Wiley & Sons, Inc.) 13, 261–287.
+.. [6] Garcia-Castillo, L.E., Ruiz-Genovés, A.J., Gómez-Revuelto, I., Salazar-Palma, M., Sarkar, T.K., 2002. Third-order Nédélec curl-conforming finite element. IEEE Transactions on Magnetics 38, 2370–2372.
diff --git a/doc/source/Contact.rst b/doc/source/Contact.rst
old mode 100644
new mode 100755
diff --git a/doc/source/Download.rst b/doc/source/Download.rst
old mode 100644
new mode 100755
index dab324d..6ffdc84
--- a/doc/source/Download.rst
+++ b/doc/source/Download.rst
@@ -184,7 +184,7 @@ Downloads
Scripts
*******
-* PETGEM is available for download at the project website generously hosted by PyPi. Download `here `__.
+* PETGEM is available for download at the project website generously hosted by PyPi and GitHub. Download `here `__ or `here `__.
* ``kernel.py``: python script that manages the PETGEM work-flow. Download :download:`here <_downloads/kernel.py>`.
@@ -201,6 +201,8 @@ Examples
* Example 1: Dataset for Pre-processing stage within PETGEM. Download :download:`here <_downloads/Example1.zip>`.
-* Example 2: Dataset for the Canonical model of an off-shore hydrocarbon reservoir. Download :download:`here <_downloads/Example2.zip>`.
+* Example 2: Dataset for the Canonical model of an off-shore hydrocarbon reservoir (Nédélec elements of first-order). Download :download:`here <_downloads/Example2.zip>`.
-* Example 3: Dataset for the use of PETSc solvers. Download :download:`here <_downloads/Example3.zip>`.
+* Example 3: Dataset for the Canonical model of an off-shore hydrocarbon reservoir (Nédélec elements of second-order). Download :download:`here <_downloads/Example3.zip>`.
+
+* Example 4: Dataset for the use of PETSc solvers. Download :download:`here <_downloads/Example4.zip>`.
diff --git a/doc/source/Features.rst b/doc/source/Features.rst
old mode 100644
new mode 100755
index e1abb45..3b2e1f7
--- a/doc/source/Features.rst
+++ b/doc/source/Features.rst
@@ -3,7 +3,7 @@
Features
===============
-PETGEM use a code structure for the Nédélec FE algorithm that emphasizes
+PETGEM use a code structure for the high-order Nédélec FE algorithm that emphasizes
good parallel scalability, which is crucial in the multi-core era.
Furthermore, it’s modularity should simplify the process of reaching the
best possible performance in terms of percentage of the peak amount of
@@ -30,7 +30,7 @@ A more detailed explanation is the following:
* Independent of problem formulation, numerical solution, and data storage: The kernel provides the independent abstractions for modeling, numerical methods, data storage and analysis.
-* Parallel processing support: Based on distributed-memory parallelism (`petsc4py `__) and static load balancing.
+* Parallel processing support: Based on distributed-memory parallelism (`petsc4py `__) and static load balancing. Further, GPUs architectures are supported.
* Confidence and performance monitoring: Based on an simple and automatic profiling module.
@@ -38,7 +38,7 @@ A more detailed explanation is the following:
* Interface to mesh generator: Simple and light library to export nodal finite element meshes to edge elements data structures. Current version support `Gmsh `__ meshes.
-* Edge FEM library: Edge-based discretisations, vector basis functions, their geometry description, and generalized integration rules provides a generic support for implementing edge-based solution algorithms.
+* Edge FEM library: High-order Edge-based discretisations, vector basis functions, their geometry description, and generalized integration rules provides a generic support for implementing edge-based solution algorithms.
* Linear systems library: Support to Compressed Row Storage (CSR) format for sparse matrices and their easy and efficient parallel assembly on distributed-memory platforms.
@@ -80,8 +80,9 @@ Target architecture
--------------------
The HPC goal of the PETGEM involves using cutting-edge architectures.
To that goal, the code is implemented in current state-of-the-art
-platforms such as Intel Xeon Platinum, Intel Haswell and Intel Xeon Phi processors, which offer
-high performance, flexibility, and power efficiency. Nevertheless,
+platforms such as Intel Xeon Platinum processors from the Skylake generation,
+Intel Haswell and Intel Xeon Phi processors, which offer
+high-performance, flexibility, and power efficiency. Nevertheless,
PETGEM support older architectures such as SandyBridge, for the sake
of usability and to be able to compare performance.
diff --git a/doc/source/Installation.rst b/doc/source/Installation.rst
old mode 100644
new mode 100755
index 5a093c0..6f110de
--- a/doc/source/Installation.rst
+++ b/doc/source/Installation.rst
@@ -31,19 +31,19 @@ Install PETGEM
* Following commands may require root privileges
-* Download `PETSc `__ (PETSc 3.7 and 3.8 have been tested)
+* Download `PETSc `__ (PETSc 3.7, 3.8 and 3.9 have been tested)
-* Uncompress the `PETSc `__ archive (in this example, using PETSc 3.8.3):
+* Uncompress the `PETSc `__ archive (in this example, using PETSc 3.9.3):
.. code-block:: bash
- $ tar zxvf petsc-3.8.3.tar.gz
+ $ tar zxvf petsc-3.9.3.tar.gz
-* Configure and build `PETSc `__. The configuration options depend on the calculations you want to perform (complex- or real-valued) as well as your compiler/MPI/Blas/Lapack setup. For PETGEM executions, **PETSC MUST BE BUILD FOR COMPLEX-VALUED NUMBERS**. In order to avoid incompatibilities between PETSC, petsc4py and PETGEM, we highly recommend the following configuration lines. Please, visit PETSc website for advanced configuration options. If you have a clean environment (not working MPI/Blas/Lapack), then run:
+* Configure and build `PETSc `__. The configuration options depend on the calculations you want to perform (complex- or real-valued) as well as your compiler/MPI/Blas/Lapack setup. For PETGEM executions, **PETSC MUST BE BUILD FOR COMPLEX-VALUED NUMBERS**. In order to avoid incompatibilities between PETSC, petsc4py and PETGEM, we highly recommend the following configuration lines. Please, visit `PETSc `__ website for advanced configuration options. If you have a clean environment (not working MPI/Blas/Lapack), then run:
.. code-block:: bash
- $ cd petsc-3.8.3
+ $ cd petsc-3.9.3
$ export PETSC_DIR=$PWD
$ export PETSC_ARCH=arch-linux2-c-debug
@@ -59,6 +59,14 @@ Install PETGEM
$ --download-mumps --download-scalapack --download-parmetis --download-metis --download-ptscotch --download-cmake
+* Further, to activate GPUs support, please add following options to previous configure line:
+
+ .. code-block:: bash
+
+ $ --with-cuda=1 --with_cuda_dir=PATH
+
+ where ``PATH`` is the directory of your CUDA libraries.
+
* Then, build and install `PETSc `__:
.. code-block:: bash
@@ -91,7 +99,8 @@ Downloading and building PETGEM
-------------------------------
The PETGEM package is available for download at
-`Python Package Index (PyPI) `__
+`Python Package Index (PyPI) `__, at
+`GitHub `__,
and the :ref:`Download` section of this project website.
* Configure and install `PETSc `__ (see :ref:`Install` section)
@@ -111,7 +120,7 @@ and the :ref:`Download` section of this project website.
$ tar zxvf petgem-1.1.tar.gz
$ cd petgem-1.1
-* After unpacking the release tarball, the distribution is ready for building. Some environment configuration is needed to inform the location `PETSc `__. As in :ref:`Install` section, you can set the environment variables ``PETSC_DIR`` and ``PETSC_ARCH`` indicating where you have built/installed `PETSc `__:
+* After unpacking the release tarball, the distribution is ready for building. Some environment configuration is needed to inform the `PETSc `__ location. As in :ref:`Install` section, you can set the environment variables ``PETSC_DIR`` and ``PETSC_ARCH`` indicating where you have built/installed `PETSc `__:
.. code-block:: bash
diff --git a/doc/source/Manual.rst b/doc/source/Manual.rst
old mode 100644
new mode 100755
index 0737f48..e7a959d
--- a/doc/source/Manual.rst
+++ b/doc/source/Manual.rst
@@ -82,7 +82,7 @@ guidelines are the following:
PETGEM design
-------------
-PETGEM use a code structure for the Nédelec FE algorithm that emphasizes
+PETGEM use a code structure for the high-order Nédelec FE algorithm that emphasizes
good parallel scalability, which is crucial in the multi-core era.
Furthermore, it’s modularity should simplify the process of reaching the
best possible performance in terms of percentage of the peak amount of
@@ -188,7 +188,7 @@ The PETGEM source code is `petgem/`, which has the following contents:
- Common classes and functions for init process.
* - `efem/`
- General modules and classes for describing a 3D CSEM survey by using EFEM of
- lowest order in tetrahedral meshes
+ high-order (:math:`p=1,2,3`) in tetrahedral meshes
* - `mesh/`
- Interface to import mesh files
* - `monitoring/`
@@ -230,25 +230,35 @@ task. A glance of this file is the following:
# name and his key names MUST NOT BE changed. All file paths should consider as absolute.
preprocessing = {
+ # ---------- Nedelec element order ----------
+ # 1 = First Nédélec order (6 DOFS per element)
+ # 2 = Second Nédélec order (20 DOFS per element)
+ # 3 = Third Nédélec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 1,
+
# ---------- Mesh file ----------
- 'MESH_FILE': 'DIPOLE1D/Input_preprocessing/DIPOLE1D.msh',
+ 'MESH_FILE': 'PATH_TO_FILE',
# ---------- Material conductivities ----------
'MATERIAL_CONDUCTIVITIES': [1.0, 1./100., 1., 1./.3],
- # ---------- Receivers positions file ----------
- 'RECEIVERS_FILE': 'DIPOLE1D/Input_preprocessing/RECEIVER_POSITIONS.txt',
+ # ---------- Receivers position file ----------
+ 'RECEIVERS_FILE': 'PATH_TO_FILE',
# ---------- Path for Output ----------
- 'OUT_DIR': 'DIPOLE1D/Input_model/',
- }
+ 'OUT_DIR': 'PATH_TO_FILE',
+ }
As you can see, in the ``preprocessingParams.py`` are defined the main parameters,
-namely, mesh file path, material conductivities, receivers positions file path and the
+namely, Nédélec element order, mesh file path, material conductivities, receivers positions file path and the
pre-processing output path.
For this phase, the supported/expected formats are the following:
+* ``NEDELEC_ORDER``: nédélec element order for the discretization. Supported orders are :math:`p=1,2,3`
+
* ``MESH_FILE``: path to tetrahedral mesh file in MSH ASCII format from `Gmsh `__
* ``MATERIAL_CONDUCTIVITIES``: numpy array where each value represents the conductivity for each material defined in ``MESH_FILE``. Therefore, size of ``MATERIAL_CONDUCTIVITIES`` must match with the number of materials in ``MESH_FILE``
@@ -272,15 +282,19 @@ following:
* ``meshConnectivity.dat``: list of the node number of the n-th tetrahedral element in the mesh. The dimensions of ``meshConnectivity.dat`` are given by (number-of-elements, 4)
-* ``dofs.dat``: list of degrees of freedom of the n-th tetrahedral element in the mesh. Since PETGEM is based on linear Nédelec FE, the dimensions of ``dofs.dat`` are given by (number-of-elements, 6)
+* ``dofs.dat``: list of degrees of freedom of the n-th tetrahedral element in the mesh. Since PETGEM is based on high-order Nédelec FE, the dimensions of ``dofs.dat`` are given by (number-of-elements, 6) for :math:`p=1`, by (number-of-elements, 20) for :math:`p=2`, and by (number-of-elements, 45) for :math:`p=3`.
+
+* ``edgesNodes.dat``: list of the two nodes that make up each edge in the mesh. The dimensions of ``edgesNodes.dat`` are given by (number-of-edges, 2)
-* ``dofsNodes.dat``: list of the two nodes that make up each degrees-of-freedom (DOFs) in the mesh. The dimensions of ``dofsNodes.dat`` are given by (number-of-dofs, 2)
+* ``faces.dat``: list of the four faces that make up each tetrahedral element in the mesh. The dimensions of ``faces.dat`` are given by (number-of-elements, 4)
-* ``boundaries.dat``: list of the DOFs number that belongs on domain boundaries. The dimensions of ``boundaries.dat`` are given by (number-of-boundaries, 1)
+* ``facesNodes.dat``: list of the three nodes that make up each tetrahedral face in the mesh. The dimensions of ``facesNodes.dat`` are given by (number-of-faces, 3)
+
+* ``boundaries.dat``: list of the DOFs indexes that belongs on domain boundaries. The dimensions of ``boundaries.dat`` are given by (number-of-boundaries, 1)
* ``conductivityModel.dat``: floating point values giving the conductivity to which the n-th tetrahedral element belongs. The dimensions of ``conductivityModel.dat`` are given by (number-of-elements, 1)
-* ``receivers.dat``: floating point values giving the X, Y and Z coordinates of the receivers. Additionally, this file includes information about the tetrahedral element that contains the n-th receiver, namely, its X, Y and Z coordinates of the four nodes, its list of the node number and its list of DOFs. The dimensions of ``receivers.dat`` are given by (number-of-receivers, 25)
+* ``receivers.dat``: floating point values giving the X, Y and Z coordinates of the receivers. Additionally, this file includes information about the tetrahedral element that contains the n-th receiver, namely, its X, Y and Z coordinates of the four nodes, its list of the node number and its list of DOFs. The dimensions of ``receivers.dat`` are given by (number-of-receivers, 25) for :math:`p=1`, by (number-of-receivers, 39) for :math:`p=2`, and by (number-of-receivers, 64) for :math:`p=3`.
* ``nnz.dat``: list containing the number of nonzeros in the various matrix rows, namely, the sparsity pattern. According to the `PETSc `__ documentation, using the ``nnz.dat`` list to preallocate memory is especially important for efficient matrix assembly if the number of nonzeros varies considerably among the rows. The dimensions of ``nnz.dat`` are given by (number-of-DOFs, 1)
@@ -333,7 +347,8 @@ details about available options. A template of this file is included in
``examples/`` of the PETGEM source tree. Additionally, a freely
available copy of this file is located at :ref:`Download` section.
-On the other hand, any 3D CSEM survey should include: physical parameters,
+On the other hand, any 3D CSEM survey should include: order for Nédélec elements
+discretizations, physical parameters,
a mesh file, source and receivers files. These data are included in the
``modelParams.py`` file. Here all the files resulting from the pre-processing
phase are included. In order to avoid a specific parser, ``modelParams.py``
@@ -344,18 +359,33 @@ A glance of ``modelParams.py`` file is the following:
.. code-block:: python
- # Parameters file template for 3D CSEM modelling.
- # By definition, any 3D CSEM survey should include: physical parameters, a mesh file, source and receivers files. These data
- # are included in the modelParams.py file. Additionally, options for PETSc solvers are defined in a petsc.opts file.
- # In order to avoid a specific parser, modelParams.py file is imported by PETGEM as a Python dictionary. As consequence,
- # the dictionary name and his key names MUST NOT BE changed. All file paths should consider as absolute.
+# Parameters file template for 3D CSEM modelling.
+# By definition, any 3D CSEM survey should include: physical parameters, a mesh file, source and receivers files. These data
+# are included in the modelParams.py file. Additionally, options for PETSc solvers are defined in a petsc.opts file.
+# In order to avoid a specific parser, modelParams.py file is imported by PETGEM as a Python dictionary. As consequence,
+# the dictionary name and his key names MUST NOT BE changed. All file paths should consider as absolute.
+
+modelling = {
+ # ---------- Nedelec element order ----------
+ # 1 = First nedelec order (6 DOFS per element)
+ # 2 = Second nedelec order (20 DOFS per element)
+ # 3 = Third nedelec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 1,
- modelling = {
- # ----- Pyshical parameters -----
+ # ---------- CUDA SUPPORT ----------
+ # 0 = No
+ # 1 = Yes
+ # Type: int
+ # Optional: NO
+ 'CUDA': 0,
+
+ # ----- Physical parameters -----
# Source
# Source frequency. Type: float
# Optional: NO
- 'FREQ': 2.0,
+ 'FREQ': 1.0,
# Source position(x, y, z). Type: float
# Optional: NO
'SRC_POS': [1750.0, 1750.0, -975.0],
@@ -373,7 +403,7 @@ A glance of ``modelParams.py`` file is the following:
'SRC_LENGTH': 1.0,
# Conductivity model. Type: str
# Optional: NO
- 'CONDUCTIVITY_MODEL_FILE': 'DIPOLE1D/Input_model/conductivityModel.dat',
+ 'CONDUCTIVITY_MODEL_FILE': 'PATH_TO_FILE',
# Background conductivity. Type: float
# Optional: NO
'CONDUCTIVITY_BACKGROUND': 3.33,
@@ -382,34 +412,41 @@ A glance of ``modelParams.py`` file is the following:
# Mesh files
# Nodes spatial coordinates. Type: str
# Optional: NO
- 'NODES_FILE': 'DIPOLE1D/Input_model/nodes.dat',
+ 'NODES_FILE': 'PATH_TO_FILE',
# Elements-nodes connectivity. Type: str
# Optional: NO
- 'MESH_CONNECTIVITY_FILE': 'DIPOLE1D/Input_model/meshConnectivity.dat',
+ 'MESH_CONNECTIVITY_FILE': 'PATH_TO_FILE',
+ # Elements-faces connectivity. Type: str
+ # Optional: NO
+ 'FACES_CONNECTIVITY_FILE': 'PATH_TO_FILE',
+ # Faces-nodes connectivity. Type: str
+ # Optional: NO
+ 'FACES_NODES_FILE': 'PATH_TO_FILE',
# Elements-edges connectivity. Type: str
# Optional: NO
- 'DOFS_CONNECTIVITY_FILE': 'DIPOLE1D/Input_model/dofs.dat',
+ 'EDGES_CONNECTIVITY_FILE': 'PATH_TO_FILE',
# Edges-nodes connectivity. Type: str
# Optional: NO
- 'DOFS_NODES_FILE': 'DIPOLE1D/Input_model/dofsNodes.dat',
+ 'EDGES_NODES_FILE': 'PATH_TO_FILE',
# Sparsity pattern for matrix allocation (PETSc)
- 'NNZ_FILE': 'DIPOLE1D/Input_model/nnz.dat',
+ 'NNZ_FILE': 'PATH_TO_FILE',
# Boundaries. Type: str
# Optional: NO
- 'BOUNDARIES_FILE': 'DIPOLE1D/Input_model/boundaries.dat',
+ 'BOUNDARIES_FILE': 'PATH_TO_FILE',
# ------------ Solver -----------
# Solver options must be set in
- # petsc.opts file
+ # petsc_solver.opts
# ------------ Receivers file -----------
# Name of the file that contains the receivers position. Type: str
# Optional: NO
- 'RECEIVERS_FILE': 'DIPOLE1D/Input_model/receivers.dat',
- }
+ 'RECEIVERS_FILE': 'PATH_TO_FILE',
-The ``modelParams.py`` file is divided into 4 sections, namely, physical parameters
-(frequency, source position, source current, source length, conductivity model,
+}
+
+The ``modelParams.py`` file is divided into 5 sections, namely, Nédélec element order,
+physical parameters (frequency, source position, source current, source length, conductivity model,
background conductivity), mesh information (file path of nodal spatial coordinates,
mesh connectivity, DOFs connectivity, edges-nodes connectivity, sparsity
structure for `PETSc `__
@@ -436,8 +473,8 @@ is the modelling parameters file for PETGEM.
PETGEM solves the problem and outputs the solution to the ``Output/`` path.
By default PETGEM will create the ``Output`` directory at same level where the
``modelParams.py`` file is located. The output files will be in three formats:
-`PETSc `__, Matlab and ASCII. Therefore, the
-``Output`` directory will contain three subdirectories: ``Ascii``, ``Matlab``
+`PETSc `__, MATLAB and ASCII. Therefore, the
+``Output`` directory will contain three subdirectories: ``Ascii``, ``MATLAB``
and ``Petsc``. By default, and for each format, PETGEM save the electric
field responses in different files:
@@ -464,8 +501,8 @@ the next work-flow:
#. The problem sets up its domain, sub-domains, source, solver. This stage include the computation of the main data structures
#. Parallel assembling of :math:`Ax=b`. See :ref:`CSEM problem` and :ref:`Edge finite element formulation` sections for a detail mathematical background of this equation system
#. The solution is obtained in parallel by calling a ``ksp()`` `PETSc `__ object.
-#. Interpolation of electromagnetic responses & post-processing parallel stage
-#. Finally the solution can be stored by calling ``postProcessingFields()`` function. Current version support `PETSc `__, Matlab and ASCII formats.
+#. Interpolation of electromagnetic responses and post-processing parallel stage
+#. Finally the solution can be stored by calling ``postProcessingFields()`` function. Current version support `PETSc `__, MATLAB and ASCII formats
Based on previous work-flow, any 3D CSEM modelling requires the following
input files:
@@ -483,7 +520,7 @@ input files:
Mesh formats
------------
-Current PETGEM version supports mesh files in MSH ASCII from
+Current PETGEM version supports mesh files in MSH ASCII (version 2.2) from
`Gmsh `__. Aforementioned format must be pre-processed
using the ``run_preprocessing.py`` script. The ``run_preprocessing.py``
script is included in the top-level directory of the PETGEM source tree.
@@ -590,7 +627,7 @@ Visualization of results
Once a solution of a 3D CSEM survey has been obtained, it should be
post-processed by using a visualization program. PETGEM does not do the
visualization by itself, but it generates output files (ASCII,
-`PETSc `__ and Matlab formats are supported)
+`PETSc `__ and MATLAB formats are supported)
with the electric responses at receivers positions. It also gives timing values
in order to evaluate the performance.
@@ -658,7 +695,7 @@ which content is the following:
* Visit http://gmsh.info/ for details about mesh scripting with Gmsh
*
* by Octavio Castillo-Reyes, BSC-CASE (octavio.castillo@bsc.es)
- * Latest update: January 30th, 2018
+ * Latest update: September 19th, 2018
*********************************************************************/
// #################################################################
// # Parameters #
@@ -752,6 +789,9 @@ which content is the following:
// #################################################################
Characteristic Length {1, 2, 3, 4, 5, 6, 7, 8, 9 , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} = dg;
+ // Mesh file format supported by PETGEM
+ Mesh.MshFileVersion = 2.2;
+
Once the mesh have been created, the PETGEM pre-processing is invoked as
follows:
@@ -769,18 +809,30 @@ task. A glance of this script is the following:
# name and his key names MUST NOT BE changed. All file paths should consider as absolute.
preprocessing = {
+ # ---------- Nedelec element order ----------
+ # 1 = First Nédélec order (6 DOFS per element)
+ # 2 = Second Nédélec order (20 DOFS per element)
+ # 3 = Third Nédélec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 1,
+
# ---------- Mesh file ----------
- 'MESH_FILE': 'PREPROCESSING/Input_preprocessing/PREPROCESSING.msh',
+ # Type: str
+ 'MESH_FILE': 'Example1/PREPROCESSING/Input_preprocessing/PREPROCESSING.msh',
# ---------- Material conductivities ----------
+ # Type: float
'MATERIAL_CONDUCTIVITIES': [1., 1./.3],
- # ---------- Receivers positions file ----------
- 'RECEIVERS_FILE': 'PREPROCESSING/Input_preprocessing/RECEIVER_POSITIONS.txt',
+ # ---------- Receivers position file ----------
+ # Type: str
+ 'RECEIVERS_FILE': 'Example1/PREPROCESSING/Input_preprocessing/RECEIVER_POSITIONS.txt',
# ---------- Path for Output ----------
- 'OUT_DIR': 'Input_model/',
- }
+ # Type: str
+ 'OUT_DIR': 'Example1/PREPROCESSING/Input_model/',
+ }
As you can see, in the ``preprocessingParams.py`` are defined the main parameters,
namely, mesh file path, material conductivities, receivers positions file path and the
@@ -790,7 +842,7 @@ The expected output of this phase is show in `Figure 7.7`_.
.. _Figure 7.7:
.. figure:: _static/figures/output_preprocessing.png
- :scale: 35%
+ :scale: 65%
:alt: PETGEM output for pre-processing stage
:align: center
@@ -814,11 +866,12 @@ consists in four-layers: 1000 m thick seawater (3.3 :math:`S/m`), 1000 m thick s
(1 :math:`S/m`). The computational domain is a :math:`[0,3500]^3` m cube. For this model,
a 2 Hz x-directed dipole source is located at :math:`z=975`, :math:`x=1750`,
:math:`y=1750`. The receivers are placed in-line to the source position and along its
-orientation, directly above the seafloor (:math:`z = 990`).
+orientation, directly above the seafloor (:math:`z = 990`). Further, the
+Nédélec element order is p=1 (first order)
Meshing
#######
-PETGEM V1.0 is based on tetrahedral meshes of lowest order. Therefore, `Figure 7.8`_
+PETGEM V1.0 is based on tetrahedral meshes. Therefore, `Figure 7.8`_
shows a 3D view of the model with its unstructured tetrahedral mesh for
the halfspace :math:`y>1750`, with the color scale representing the electrical
conductivity :math:`\sigma` for each layer. Mesh in `Figure 7.8`_ have been
@@ -866,61 +919,82 @@ this example follows:
# the dictionary name and his key names MUST NOT BE changed. All file paths should consider as absolute.
modelling = {
- # ----- Pyshical parameters -----
- # Source
- # Source frequency. Type: float
- # Optional: NO
- 'FREQ': 2.0,
- # Source position(x, y, z). Type: float
- # Optional: NO
- 'SRC_POS': [1750.0, 1750.0, -975.0],
- # Source orientarion. Type: int
- # 1 = X-directed source
- # 2 = Y-directed source
- # 3 = Z-directed source
- # Optional: NO
- 'SRC_DIREC': 1,
- # Source current. Type: float
- # Optional: NO
- 'SRC_CURRENT': 1.0,
- # Source length. Type: float
- # Optional: NO
- 'SRC_LENGTH': 1.0,
- # Conductivity model. Type: str
- # Optional: NO
- 'CONDUCTIVITY_MODEL_FILE': 'DIPOLE1D/Input_model/conductivityModel.dat',
- # Background conductivity. Type: float
- # Optional: NO
- 'CONDUCTIVITY_BACKGROUND': 3.33,
-
- # ------- Mesh and conductivity model files ------
- # Mesh files
- # Nodes spatial coordinates. Type: str
- # Optional: NO
- 'NODES_FILE': 'DIPOLE1D/Input_model/nodes.dat',
- # Elements-nodes connectivity. Type: str
- # Optional: NO
- 'MESH_CONNECTIVITY_FILE': 'DIPOLE1D/Input_model/meshConnectivity.dat',
- # Elements-edges connectivity. Type: str
- # Optional: NO
- 'DOFS_CONNECTIVITY_FILE': 'DIPOLE1D/Input_model/dofs.dat',
- # Edges-nodes connectivity. Type: str
- # Optional: NO
- 'DOFS_NODES_FILE': 'DIPOLE1D/Input_model/dofsNodes.dat',
- # Sparsity pattern for matrix allocation (PETSc)
- 'NNZ_FILE': 'DIPOLE1D/Input_model/nnz.dat',
- # Boundaries. Type: str
- # Optional: NO
- 'BOUNDARIES_FILE': 'DIPOLE1D/Input_model/boundaries.dat',
-
- # ------------ Solver -----------
- # Solver options must be set in
- # petsc.opts file
-
- # ------------ Receivers file -----------
- # Name of the file that contains the receivers position. Type: str
- # Optional: NO
- 'RECEIVERS_FILE': 'DIPOLE1D/Input_model/receivers.dat',
+ # ---------- Nedelec element order ----------
+ # 1 = First nedelec order (6 DOFS per element)
+ # 2 = Second nedelec order (20 DOFS per element)
+ # 3 = Third nedelec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 1,
+
+ # ---------- CUDA SUPPORT ----------
+ # 0 = No
+ # 1 = Yes
+ # Type: int
+ # Optional: NO
+ 'CUDA': 0,
+
+ # ----- Physical parameters -----
+ # Source
+ # Source frequency. Type: float
+ # Optional: NO
+ 'FREQ': 2.0,
+ # Source position(x, y, z). Type: float
+ # Optional: NO
+ 'SRC_POS': [1750.0, 1750.0, -975.0],
+ # Source orientarion. Type: int
+ # 1 = X-directed source
+ # 2 = Y-directed source
+ # 3 = Z-directed source
+ # Optional: NO
+ 'SRC_DIREC': 1,
+ # Source current. Type: float
+ # Optional: NO
+ 'SRC_CURRENT': 1.0,
+ # Source length. Type: float
+ # Optional: NO
+ 'SRC_LENGTH': 1.0,
+ # Conductivity model. Type: str
+ # Optional: NO
+ 'CONDUCTIVITY_MODEL_FILE': 'Example2/DIPOLE1D/Input_model/conductivityModel.dat',
+ # Background conductivity. Type: float
+ # Optional: NO
+ 'CONDUCTIVITY_BACKGROUND': 3.33,
+
+ # ------- Mesh and conductivity model files ------
+ # Mesh files
+ # Nodes spatial coordinates. Type: str
+ # Optional: NO
+ 'NODES_FILE': 'Example2/DIPOLE1D/Input_model/nodes.dat',
+ # Elements-nodes connectivity. Type: str
+ # Optional: NO
+ 'MESH_CONNECTIVITY_FILE': 'Example2/DIPOLE1D/Input_model/meshConnectivity.dat',
+ # Elements-faces connectivity. Type: str
+ # Optional: NO
+ 'FACES_CONNECTIVITY_FILE': 'Example2/DIPOLE1D/Input_model/faces.dat',
+ # Faces-nodes connectivity. Type: str
+ # Optional: NO
+ 'FACES_NODES_FILE': 'Example2/DIPOLE1D/Input_model/facesNodes.dat',
+ # Elements-edges connectivity. Type: str
+ # Optional: NO
+ 'EDGES_CONNECTIVITY_FILE': 'Example2/DIPOLE1D/Input_model/edges.dat',
+ # Edges-nodes connectivity. Type: str
+ # Optional: NO
+ 'EDGES_NODES_FILE': 'Example2/DIPOLE1D/Input_model/edgesNodes.dat',
+ # Sparsity pattern for matrix allocation (PETSc)
+ 'NNZ_FILE': 'Example2/DIPOLE1D/Input_model/nnz.dat',
+ # Boundaries. Type: str
+ # Optional: NO
+ 'BOUNDARIES_FILE': 'Example2/DIPOLE1D/Input_model/boundaries.dat',
+
+ # ------------ Solver -----------
+ # Solver options must be set in
+ # petsc_solver.opts
+
+ # ------------ Receivers file -----------
+ # Name of the file that contains the receivers position. Type: str
+ # Optional: NO
+ 'RECEIVERS_FILE': 'Example2/DIPOLE1D/Input_model/receivers.dat',
}
Note that you may wish to change the location of the input files to
@@ -931,12 +1005,12 @@ the solver options have been configured in the ``petsc.opts`` file as follows:
.. code-block:: python
- # Solver options for PETSc
- -ksp_type gmres
- -pc_type sor
- -ksp_rtol 1e-8
- -ksp_converged_reason
- -log_summary
+ # Solver options for
+ -ksp_type gmres
+ -pc_type sor
+ -ksp_rtol 1e-8
+ -ksp_converged_reason
+ -log_summary
That's it, we are now ready to solve the modelling.
@@ -959,8 +1033,8 @@ directory of the PETGEM source tree:
and outputs the solution to the output path
(``DIPOLE1D/Output/``). The output files will be in three formats:
-`PETSc `__, Matlab and ASCII. Therefore, the
-``Output`` directory will contain three subdirectories: ``Ascii``, ``Matlab``
+`PETSc `__, MATLAB and ASCII. Therefore, the
+``Output`` directory will contain three subdirectories: ``Ascii``, ``MATLAB``
and ``Petsc``. By default, and for each format, PETGEM save the electric
field responses in different files:
@@ -975,7 +1049,7 @@ PETGEM post-processing
Once a solution of a 3D CSEM survey has been obtained, it should be
post-processed by using a visualization program. PETGEM does not do the
visualization by itself, but it generates output files (ASCII,
-`PTSc `__ and Matlab formats are supported)
+`PETSc `__ and MATLAB formats are supported)
with the electric responses at receivers positions. It also gives timing values
in order to evaluate the performance.
@@ -996,7 +1070,159 @@ mesh with :math:`\approx2` millions of DOFs.
Figure 7.9. Total electric field comparative for x-component between PETGEM V1.0 and DIPOLE1D.
-Example 3: Use of PETSc solvers
+Example 3: Use of high-order Nédélec elements
+*********************************************
+In order to show the potential of high-order Nédélec elements, here is
+considered the same model of previous example. In this case, the
+Nédélec element order is p=2 (second order).
+
+Meshing
+##########################
+As in previous example, the mesh is composed by four conductivity materials. The
+resulting `Gmsh `__ script can be found in :ref:`Download`
+section. It is worth to mention that the use a Nédélec element order p=2 helps
+to reduce the number of tetrahedral elements to achieved a certain error level.
+
+Parameters file for PETGEM
+##########################
+The parameters file used for this example follows:
+
+.. code-block:: python
+
+ # Parameters file template for 3D CSEM modelling.
+ # By definition, any 3D CSEM survey should include: physical parameters, a mesh file, source and receivers files. These data
+ # are included in the modelParams.py file. Additionally, options for PETSc solvers are defined in a petsc.opts file.
+ # In order to avoid a specific parser, modelParams.py file is imported by PETGEM as a Python dictionary. As consequence,
+ # the dictionary name and his key names MUST NOT BE changed. All file paths should consider as absolute.
+
+ modelling = {
+ # ---------- Nedelec element order ----------
+ # 1 = First nedelec order (6 DOFS per element)
+ # 2 = Second nedelec order (20 DOFS per element)
+ # 3 = Third nedelec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 2,
+
+ # ---------- CUDA SUPPORT ----------
+ # 0 = No
+ # 1 = Yes
+ # Type: int
+ # Optional: NO
+ 'CUDA': 0,
+
+ # ----- Physical parameters -----
+ # Source
+ # Source frequency. Type: float
+ # Optional: NO
+ 'FREQ': 2.0,
+ # Source position(x, y, z). Type: float
+ # Optional: NO
+ 'SRC_POS': [1750.0, 1750.0, -975.0],
+ # Source orientarion. Type: int
+ # 1 = X-directed source
+ # 2 = Y-directed source
+ # 3 = Z-directed source
+ # Optional: NO
+ 'SRC_DIREC': 1,
+ # Source current. Type: float
+ # Optional: NO
+ 'SRC_CURRENT': 1.0,
+ # Source length. Type: float
+ # Optional: NO
+ 'SRC_LENGTH': 1.0,
+ # Conductivity model. Type: str
+ # Optional: NO
+ 'CONDUCTIVITY_MODEL_FILE': 'Example2/DIPOLE1D/Input_model/conductivityModel.dat',
+ # Background conductivity. Type: float
+ # Optional: NO
+ 'CONDUCTIVITY_BACKGROUND': 3.33,
+
+ # ------- Mesh and conductivity model files ------
+ # Mesh files
+ # Nodes spatial coordinates. Type: str
+ # Optional: NO
+ 'NODES_FILE': 'Example2/DIPOLE1D/Input_model/nodes.dat',
+ # Elements-nodes connectivity. Type: str
+ # Optional: NO
+ 'MESH_CONNECTIVITY_FILE': 'Example2/DIPOLE1D/Input_model/meshConnectivity.dat',
+ # Elements-faces connectivity. Type: str
+ # Optional: NO
+ 'FACES_CONNECTIVITY_FILE': 'Example2/DIPOLE1D/Input_model/faces.dat',
+ # Faces-nodes connectivity. Type: str
+ # Optional: NO
+ 'FACES_NODES_FILE': 'Example2/DIPOLE1D/Input_model/facesNodes.dat',
+ # Elements-edges connectivity. Type: str
+ # Optional: NO
+ 'EDGES_CONNECTIVITY_FILE': 'Example2/DIPOLE1D/Input_model/edges.dat',
+ # Edges-nodes connectivity. Type: str
+ # Optional: NO
+ 'EDGES_NODES_FILE': 'Example2/DIPOLE1D/Input_model/edgesNodes.dat',
+ # Sparsity pattern for matrix allocation (PETSc)
+ 'NNZ_FILE': 'Example2/DIPOLE1D/Input_model/nnz.dat',
+ # Boundaries. Type: str
+ # Optional: NO
+ 'BOUNDARIES_FILE': 'Example2/DIPOLE1D/Input_model/boundaries.dat',
+
+ # ------------ Solver -----------
+ # Solver options must be set in
+ # petsc_solver.opts
+
+ # ------------ Receivers file -----------
+ # Name of the file that contains the receivers position. Type: str
+ # Optional: NO
+ 'RECEIVERS_FILE': 'Example2/DIPOLE1D/Input_model/receivers.dat',
+ }
+
+Running PETGEM
+##############
+To run the simulation, the following command should be run in the top-level
+directory of the PETGEM source tree:
+
+.. code-block:: bash
+
+ $ mpirun -n 48 python3 kernel.py -options_file DIPOLE1D/petsc.opts DIPOLE1D/modelParams.py
+
+``kernel.py`` solves the problem as follows:
+
+ #. Problem initialization
+ #. Import files
+ #. Parallel assembly system
+ #. Parallel solution system
+ #. Post-processing of electric responses
+
+and outputs the solution to the output path
+(``DIPOLE1D/Output/``). The output files will be in three formats:
+`PETSc `__, MATLAB and ASCII. Therefore, the
+``Output`` directory will contain three subdirectories: ``Ascii``, ``MATLAB``
+and ``Petsc``. By default, and for each format, PETGEM save the electric
+field responses in different files:
+
+ * ``Ep.xx``: primary electric field components
+ * ``Es.xx``: secondary electric field components
+ * ``Et.xx``: total electric field components
+
+where ``.xx`` is the file extension that depends of the format file.
+
+Nédélec order comparison
+########################
+`Figure 7.10`_ shows a comparison of the x-component of total electric field between p=1
+and p=2 against the quasi-analytical solution obtained with the
+`DIPOLE1D `_ tool. The total
+electric field in `Figure 7.10`_ was calculated using a
+mesh with :math:`\approx2` millions of DOFs for p=1 and a mesh with
+:math:`\approx600` thousands of DOFs.
+
+.. _Figure 7.10:
+.. figure:: _static/figures/total_field_X_model2.png
+ :scale: 40%
+ :alt: Nédélec order comparison for an in-line canonical off-shore hydrocarbon model with its unstructured tetrahedral mesh for :math:`y>150`
+ :align: center
+
+ Figure 7.10. Nédélec order comparative within PETGEM V1.0
+
+
+Example 4: Use of PETSc solvers
*******************************
In PETGEM, options for `PETSc `__ solvers/preconditioners
diff --git a/doc/source/Publications.rst b/doc/source/Publications.rst
old mode 100644
new mode 100755
index 0911455..77f1033
--- a/doc/source/Publications.rst
+++ b/doc/source/Publications.rst
@@ -4,6 +4,8 @@ Publications
============
Papers:
+* Castillo-Reyes, O., de la Puente, Cela, J. M. `PETGEM: A parallel code for 3D CSEM forward modeling using edge finite elements `_. Computers & Geosciences, vol 119: 123-136. ISSN 0098-3004. Elsevier.
+* Castillo-Reyes, O., de la Puente, Cela, J. M. `Three-Dimensional CSEM modelling on unstructured tetrahedral meshes using edge finite elements `_. In: Barrios Hernández C., Gitler I., Klapp J. (eds) High Performance Computing. CARLA 2016. Communications in Computer and Information Science, vol 697: 247-256. ISBN 978-3-319-57971-9 Springer, Cham. 2017.
* Castillo-Reyes, O., de la Puente, Cela, J. M. `Improving edge finite element assembly for geophysical electromagnetic modelling on shared-memory architectures `_. 7th Annual Ubiquitous Computing, Electronics & Mobile Communication Conference – UEMCON. 2016.
* Castillo-Reyes, O., de la Puente, J., Puzyrev, V., and Cela, J. M., `Edge-based parallel framework for the simulation of 3D CSEM surveys `_. ICE Barcelona-AAPG/SEG International Conference & Exhibition. 2016.
* Castillo-Reyes, O., de la Puente, J., Barucq, H., Diaz, J., and Cela, J. M., `Parallel and vectorized code for CSEM surveys in geophysics: An edge-based approach `_. ECCOMAS. 2016.
@@ -17,6 +19,8 @@ Papers:
Conferences:
+* Castillo-Reyes, O. HPC geophysical electromagnetic modeling. Fifth International Congress on Multiphysics, Multiscale, and Optimization problems. University of the Basque Country. Bilbao, Spain. May 2018.
+* Castillo-Reyes, O. Python performance for HPC geophysical applications. 9th International Supercomputing Conference in Mexico – ISUM 2018. Red Mexicana de Supercómputo. Mérida, Yucatán, Mexico. March 2018.
* Castillo-Reyes, O. Overview of numerical techniques and applications for CSEM/MT geophysical surveys. SIAM Conference on Mathematical and Computational Issues in the Geosciences. University Erlangen-Nürnberg. Erlangen, Germany. September 2017.
* Castillo-Reyes, O. PETGEM: Parallel Edge-based Tool for Geophysical Electromagnetic Modelling. Congress on Numerical Methods in Engineering. Technical University of Valencia. Valencia, Spain. July 2017.
* Castillo-Reyes, O. PETGEM: potential of 3D CSEM modelling using a new HPC tool for exploration geophysics. 10th International Marine Electromagnetics conference – MARELEC. University of Liverpool. Liverpool, United Kingdom. June 2017.
@@ -48,6 +52,7 @@ Work on PETGEM has received funding from the European Union's Horizon 2020 resea
the Marie Sklodowska-Curie grant agreement No. 644202. The research leading to these results has received funding
from the European Union's Horizon 2020 Programme (2014-2020) and from Brazilian Ministry of Science, Technology and
Innovation through Rede Nacional de Pesquisa (RNP) under the `HPC4E Project `_ , grant agreement
-No. 689772.
+No. 689772. Further, this project has received funding from the European Union's Horizon 2020 research and innovation
+programme under the Marie Sklodowska-Curie grant agreement No. 777778.
Octavio Castillo-Reyes expresses his gratitude to the Mexican National Council for Science and Technology (`CONACyT `_) for his support.
diff --git a/doc/source/Tutorial.rst b/doc/source/Tutorial.rst
old mode 100644
new mode 100755
index f6fbf15..e851912
--- a/doc/source/Tutorial.rst
+++ b/doc/source/Tutorial.rst
@@ -97,18 +97,26 @@ A glance of this file is the following:
# name and his key names MUST NOT BE changed. All file paths should consider as absolute.
preprocessing = {
+ # ---------- Nedelec element order ----------
+ # 1 = First Nédélec order (6 DOFS per element)
+ # 2 = Second Nédélec order (20 DOFS per element)
+ # 3 = Third Nédélec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 1,
+
# ---------- Mesh file ----------
- 'MESH_FILE': 'DIPOLE1D/Input_preprocessing/DIPOLE1D.msh',
+ 'MESH_FILE': 'PATH_TO_FILE',
# ---------- Material conductivities ----------
'MATERIAL_CONDUCTIVITIES': [1.0, 1./100., 1., 1./.3],
- # ---------- Receivers positions file ----------
- 'RECEIVERS_FILE': 'DIPOLE1D/Input_preprocessing/RECEIVER_POSITIONS.txt',
+ # ---------- Receivers position file ----------
+ 'RECEIVERS_FILE': 'PATH_TO_FILE',
# ---------- Path for Output ----------
- 'OUT_DIR': 'DIPOLE1D/Input_model/',
- }
+ 'OUT_DIR': 'PATH_TO_FILE',
+ }
A template of this file is included in ``examples/``
of the PETGEM source tree. Additionally, a freely available copy of this file
@@ -169,11 +177,26 @@ A glance of ``modelParams.py`` file is the following:
# the dictionary name and his key names MUST NOT BE changed. All file paths should consider as absolute.
modelling = {
- # ----- Pyshical parameters -----
+ # ---------- Nedelec element order ----------
+ # 1 = First nedelec order (6 DOFS per element)
+ # 2 = Second nedelec order (20 DOFS per element)
+ # 3 = Third nedelec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 2,
+
+ # ---------- CUDA SUPPORT ----------
+ # 0 = No
+ # 1 = Yes
+ # Type: int
+ # Optional: NO
+ 'CUDA': 0,
+
+ # ----- Physical parameters -----
# Source
# Source frequency. Type: float
# Optional: NO
- 'FREQ': 2.0,
+ 'FREQ': 1.0,
# Source position(x, y, z). Type: float
# Optional: NO
'SRC_POS': [1750.0, 1750.0, -975.0],
@@ -191,7 +214,7 @@ A glance of ``modelParams.py`` file is the following:
'SRC_LENGTH': 1.0,
# Conductivity model. Type: str
# Optional: NO
- 'CONDUCTIVITY_MODEL_FILE': 'DIPOLE1D/Input_model/conductivityModel.dat',
+ 'CONDUCTIVITY_MODEL_FILE': 'PATH_TO_FILE',
# Background conductivity. Type: float
# Optional: NO
'CONDUCTIVITY_BACKGROUND': 3.33,
@@ -200,21 +223,27 @@ A glance of ``modelParams.py`` file is the following:
# Mesh files
# Nodes spatial coordinates. Type: str
# Optional: NO
- 'NODES_FILE': 'DIPOLE1D/Input_model/nodes.dat',
+ 'NODES_FILE': 'PATH_TO_FILE',
# Elements-nodes connectivity. Type: str
# Optional: NO
- 'MESH_CONNECTIVITY_FILE': 'DIPOLE1D/Input_model/meshConnectivity.dat',
+ 'MESH_CONNECTIVITY_FILE': 'PATH_TO_FILE',
+ # Elements-faces connectivity. Type: str
+ # Optional: NO
+ 'FACES_CONNECTIVITY_FILE': 'PATH_TO_FILE',
+ # Faces-nodes connectivity. Type: str
+ # Optional: NO
+ 'FACES_NODES_FILE': 'PATH_TO_FILE',
# Elements-edges connectivity. Type: str
# Optional: NO
- 'DOFS_CONNECTIVITY_FILE': 'DIPOLE1D/Input_model/dofs.dat',
+ 'EDGES_CONNECTIVITY_FILE': 'PATH_TO_FILE',
# Edges-nodes connectivity. Type: str
# Optional: NO
- 'DOFS_NODES_FILE': 'DIPOLE1D/Input_model/dofsNodes.dat',
+ 'EDGES_NODES_FILE': 'PATH_TO_FILE',
# Sparsity pattern for matrix allocation (PETSc)
- 'NNZ_FILE': 'DIPOLE1D/Input_model/nnz.dat',
+ 'NNZ_FILE': 'PATH_TO_FILE',
# Boundaries. Type: str
# Optional: NO
- 'BOUNDARIES_FILE': 'DIPOLE1D/Input_model/boundaries.dat',
+ 'BOUNDARIES_FILE': 'PATH_TO_FILE',
# ------------ Solver -----------
# Solver options must be set in
@@ -223,7 +252,7 @@ A glance of ``modelParams.py`` file is the following:
# ------------ Receivers file -----------
# Name of the file that contains the receivers position. Type: str
# Optional: NO
- 'RECEIVERS_FILE': 'DIPOLE1D/Input_model/receivers.dat',
+ 'RECEIVERS_FILE': 'PATH_TO_FILE',
}
A template of this file is included in ``examples/``
diff --git a/doc/source/WhatIs.rst b/doc/source/WhatIs.rst
old mode 100644
new mode 100755
index e72ead1..633bfb1
--- a/doc/source/WhatIs.rst
+++ b/doc/source/WhatIs.rst
@@ -31,7 +31,7 @@ easiest to scale-up to very large domains or arbitrary shape. It supports
distributed-memory paralelism through `petsc4py `__
package.
-As a result, PETGEM tool allow users to specify edge-based
+As a result, PETGEM tool allow users to specify high-order edge-based
variational forms of H(curl) for the simulation of electromagnetic fields
in realistic 3D CSEM surveys with accuracy, reliability and efficiency.
diff --git a/doc/source/_downloads/Example1.zip b/doc/source/_downloads/Example1.zip
new file mode 100644
index 0000000..27f1b8a
Binary files /dev/null and b/doc/source/_downloads/Example1.zip differ
diff --git a/doc/source/_downloads/Example2.zip b/doc/source/_downloads/Example2.zip
new file mode 100644
index 0000000..2191f34
Binary files /dev/null and b/doc/source/_downloads/Example2.zip differ
diff --git a/doc/source/_downloads/Example3.zip b/doc/source/_downloads/Example3.zip
new file mode 100644
index 0000000..288ba26
Binary files /dev/null and b/doc/source/_downloads/Example3.zip differ
diff --git a/doc/source/_downloads/Example4.zip b/doc/source/_downloads/Example4.zip
new file mode 100644
index 0000000..070fba0
Binary files /dev/null and b/doc/source/_downloads/Example4.zip differ
diff --git a/doc/source/_downloads/GPLv3_T_C.pdf b/doc/source/_downloads/GPLv3_T_C.pdf
old mode 100644
new mode 100755
diff --git a/doc/source/_downloads/kernel.py b/doc/source/_downloads/kernel.py
old mode 100644
new mode 100755
index 7184b0f..cfde18f
--- a/doc/source/_downloads/kernel.py
+++ b/doc/source/_downloads/kernel.py
@@ -42,10 +42,6 @@
# -- Get rank, size and MASTER of the MPI pool --
MASTER, rank, size = getRankSize()
- # ###############################################
- # ----- Define geometry and EFEM constants -----
- edgeOrder, nodalOrder, numDimensions = defineEFEMConstants()
-
# ###############################################
# ----------- Print header (Master) -------------
printPetgemHeader(rank)
@@ -60,6 +56,10 @@
# ------- Check and read parameters file --------
modelling = readUserParams(input_params, rank)
+ # ###############################################
+ # ----- Define geometry and EFEM constants -----
+ edgeOrder, nodalOrder, numDimensions = defineEFEMConstants(modelling['NEDELEC_ORDER'])
+
# ###############################################
# ---------------- Read mesh --------------------
printMessage('\nImport files', rank)
@@ -72,23 +72,34 @@
nodes = readPetscMatrix(modelling['NODES_FILE'], communicator=None)
# elements-nodes connectivity
printMessage(' Elements-nodes connectivity', rank)
- elemsN = readPetscMatrix(modelling['MESH_CONNECTIVITY_FILE'], communicator=None)
+ elemsN = readPetscMatrix(modelling['MESH_CONNECTIVITY_FILE'],
+ communicator=None)
+ # elements-faces connectivity
+ printMessage(' Elements-faces connectivity', rank)
+ elemsF = readPetscMatrix(modelling['FACES_CONNECTIVITY_FILE'],
+ communicator=None)
+ # facesN connectivity
+ printMessage(' Faces-nodes connectivity', rank)
+ facesN = readPetscMatrix(modelling['FACES_NODES_FILE'],
+ communicator=None)
# elements-edges connectivity
printMessage(' Elements-edges connectivity', rank)
- elemsE = readPetscMatrix(modelling['DOFS_CONNECTIVITY_FILE'], communicator=None)
+ elemsE = readPetscMatrix(modelling['EDGES_CONNECTIVITY_FILE'],
+ communicator=None)
# edgesN connectivity
printMessage(' Edges-nodes connectivity', rank)
- edgesN = readPetscMatrix(modelling['DOFS_NODES_FILE'], communicator=None)
- # Boundary-Edges
+ edgesN = readPetscMatrix(modelling['EDGES_NODES_FILE'], communicator=None)
+ # Boundaries
printMessage(' Boundary-Edges', rank)
- bEdges = readPetscVector(modelling['BOUNDARIES_FILE'], communicator=None)
+ boundaries = readPetscVector(modelling['BOUNDARIES_FILE'], communicator=None)
# Sparsity pattern (NNZ) for matrix allocation
printMessage(' Vector for matrix allocation', rank)
Q = readPetscVector(modelling['NNZ_FILE'], communicator=None)
nnz = (Q.getArray().real).astype(PETSc.IntType)
# Conductivity model
printMessage(' Conductivity model', rank)
- elemsSigma = readPetscVector(modelling['CONDUCTIVITY_MODEL_FILE'], communicator=None)
+ elemsSigma = readPetscVector(modelling['CONDUCTIVITY_MODEL_FILE'],
+ communicator=None)
# Receivers data
printMessage(' Receivers data', rank)
receivers = readPetscMatrix(modelling['RECEIVERS_FILE'], communicator=None)
@@ -97,25 +108,30 @@
# ###############################################
# -------------- Mesh information ---------------
- [nElems, nEdges, nBoundaries, ndofs] = getMeshInfo(elemsN, edgesN, bEdges, rank)
+ [nElems, nFaces, nEdges, ndofs, nBoundaries] = getMeshInfo(modelling['NEDELEC_ORDER'],
+ elemsN, elemsF, facesN,
+ edgesN, boundaries,
+ rank)
+
+
# ###############################################
# --------- Information of parallel pool --------
printMessage('\nParallel information', rank)
printMessage('='*75, rank)
[Istart_elemsE, Iend_elemsE,
- Istart_bEdges, Iend_bEdges,
- Istart_receivers, Iend_receivers] = getRanges(elemsE, bEdges, receivers,
- size, rank)
+ Istart_boundaries, Iend_boundaries,
+ Istart_receivers, Iend_receivers] = getRanges(elemsE, boundaries,
+ receivers, size, rank)
# ###############################################
# ----- Create and setup parallel structures ----
# Left-hand side
- A = createParallelMatrix(nEdges, nEdges, nnz, communicator=None)
+ A = createParallelMatrix(ndofs, ndofs, nnz, communicator=None)
# Right-hand side
- b = createParallelVector(nEdges, communicator=None)
+ b = createParallelVector(ndofs, communicator=None)
# X vector
- x = createParallelVector(nEdges, communicator=None)
+ x = createParallelVector(ndofs, communicator=None)
# ###############################################
# -------------- Parallel assembly --------------
@@ -125,7 +141,11 @@
assemblerLog = startLogEvent("Assembler")
assemblerLog.begin()
# System assembly
- [A, b, elapsedTimeAssembly] = parallelAssembler(modelling, A, b, nodes, elemsE, elemsN, elemsSigma, Istart_elemsE, Iend_elemsE, rank)
+ [A, b, elapsedTimeAssembly] = parallelAssembler(modelling, A, b, nodes,
+ elemsE, elemsN, elemsF,
+ elemsSigma, Istart_elemsE,
+ Iend_elemsE, nEdges, nFaces,
+ rank)
# End log event for assembly task
assemblerLog.end()
@@ -137,9 +157,9 @@
boundariesLog = startLogEvent("Boundaries")
boundariesLog.begin()
# Set boundary conditions
- [A, b, elapsedTimeBoundaries] = setBoundaryConditions(A, b, bEdges,
- Istart_bEdges,
- Iend_bEdges, rank)
+ [A, b, elapsedTimeBoundaries] = setBoundaryConditions(A, b, boundaries,
+ Istart_boundaries,
+ Iend_boundaries, rank)
# End log event for setting boundary conditions task
boundariesLog.end()
@@ -162,14 +182,20 @@
# Create and start log event for assembly task
postProcessingLog = startLogEvent("Postprocessing")
postProcessingLog.begin()
- elapsedTimepostProcessing = postProcessingFields(receivers, modelling, x, Iend_receivers, Istart_receivers, edgeOrder, nodalOrder, numDimensions, rank)
+ elapsedTimepostProcessing = postProcessingFields(receivers, modelling, x,
+ Iend_receivers,
+ Istart_receivers,
+ modelling['NEDELEC_ORDER'],
+ nodalOrder,
+ numDimensions, rank)
postProcessingLog.end()
# ###############################################
# -------------- Print elapsed times-------------
printMessage('\nElapsed times (seconds)', rank)
printMessage('='*75, rank)
- printElapsedTimes(elapsedTimeAssembly, elapsedTimeSolver, elapsedTimepostProcessing, iterationNumber, rank)
+ printElapsedTimes(elapsedTimeAssembly, elapsedTimeSolver,
+ elapsedTimepostProcessing, iterationNumber, rank)
# ###############################################
# ----------- Print footer (Master) -------------
diff --git a/doc/source/_downloads/modelParams.py b/doc/source/_downloads/modelParams.py
old mode 100644
new mode 100755
index 8627f37..7b08a6c
--- a/doc/source/_downloads/modelParams.py
+++ b/doc/source/_downloads/modelParams.py
@@ -13,7 +13,15 @@
Next, each key is described.
'''
modelling = {
- # ----- Pyshical parameters -----
+ # ---------- Nedelec element order ----------
+ # 1 = First Nédélec order (6 DOFS per element)
+ # 2 = Second Nédélec order (20 DOFS per element)
+ # 3 = Third Nédélec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 2,
+
+ # ----- Physical parameters -----
# Source
# Source frequency. Type: float
# Optional: NO
@@ -50,10 +58,10 @@
'MESH_CONNECTIVITY_FILE': 'examples/DIPOLE1D/Input_model/meshConnectivity.dat',
# Elements-edges connectivity. Type: str
# Optional: NO
- 'DOFS_CONNECTIVITY_FILE': 'examples/DIPOLE1D/Input_model/dofs.dat',
+ 'EDGES_CONNECTIVITY_FILE': 'examples/DIPOLE1D/Input_model/edges.dat',
# Edges-nodes connectivity. Type: str
# Optional: NO
- 'DOFS_NODES_FILE': 'examples/DIPOLE1D/Input_model/dofsNodes.dat',
+ 'EDGES_NODES_FILE': 'examples/DIPOLE1D/Input_model/edgesNodes.dat',
# Sparsity pattern for matrix allocation (PETSc)
'NNZ_FILE': 'examples/DIPOLE1D/Input_model/nnz.dat',
# Boundaries. Type: str
diff --git a/doc/source/_downloads/petsc.opts b/doc/source/_downloads/petsc.opts
old mode 100644
new mode 100755
diff --git a/doc/source/_downloads/preprocessingParams.py b/doc/source/_downloads/preprocessingParams.py
old mode 100644
new mode 100755
index f443ee0..feb242e
--- a/doc/source/_downloads/preprocessingParams.py
+++ b/doc/source/_downloads/preprocessingParams.py
@@ -10,16 +10,28 @@
All file paths should consider as absolute.
'''
preprocessing = {
+ # ---------- Nedelec element order ----------
+ # 1 = First Nédélec order (6 DOFS per element)
+ # 2 = Second Nédélec order (20 DOFS per element)
+ # 3 = Third Nédélec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 3,
+
# ---------- Mesh file ----------
+ # Type: str
'MESH_FILE': 'examples/DIPOLE1D/Input_preprocessing/DIPOLE1D.msh',
# ---------- Material conductivities ----------
+ # Type: float
'MATERIAL_CONDUCTIVITIES': [1.0, 1./100., 1., 1./.3],
# ---------- Receivers position file ----------
+ # Type: str
'RECEIVERS_FILE': 'examples/DIPOLE1D/Input_preprocessing/RECEIVER_POSITIONS.txt',
# ---------- Path for Output ----------
+ # Type: str
'OUT_DIR': 'examples/DIPOLE1D/Input_model/',
}
diff --git a/doc/source/_downloads/run_preprocessing.py b/doc/source/_downloads/run_preprocessing.py
old mode 100644
new mode 100755
index 5db2ef5..b59631f
--- a/doc/source/_downloads/run_preprocessing.py
+++ b/doc/source/_downloads/run_preprocessing.py
@@ -18,7 +18,8 @@
from petgem.preprocessing.preprocessing import readPreprocessingParams
from petgem.preprocessing.preprocessing import preprocessNodes
from petgem.preprocessing.preprocessing import preprocessingNodalConnectivity
-from petgem.preprocessing.preprocessing import preprocessingDOF
+from petgem.preprocessing.preprocessing import preprocessingEdges
+from petgem.preprocessing.preprocessing import preprocessingFaces
from petgem.preprocessing.preprocessing import preprocessingConductivityModel
from petgem.preprocessing.preprocessing import preprocessingDataReceivers
from petgem.preprocessing.preprocessing import preprocessingNNZ
@@ -49,31 +50,43 @@
# ###############################################
# ----------- Data preprocessing ---------
# Nodal coordinates preprocessing (nodes)
-nNodes = preprocessNodes(preprocessing['MESH_FILE'], preprocessing['OUT_DIR'], rank)
+nNodes = preprocessNodes(preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
# Nodal connectivity preprocessing (elemsN)
-nElems = preprocessingNodalConnectivity(preprocessing['MESH_FILE'], preprocessing['OUT_DIR'], rank)
+nElems = preprocessingNodalConnectivity(preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
+
+# Edges connectivity and edge boundaries preprocessing (edges)
+nEdges, nDofs = preprocessingEdges(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
-# Degrees of freedom preprocessing (dofs)
-nDofs = preprocessingDOF(preprocessing['MESH_FILE'], preprocessing['OUT_DIR'], rank)
+# Faces connectivity and faces boundaries preprocessing (faces)
+nFaces = preprocessingFaces(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
# Conductivity model
preprocessingConductivityModel(preprocessing['MESH_FILE'],
preprocessing['MATERIAL_CONDUCTIVITIES'],
preprocessing['OUT_DIR'], rank)
# Receiver positions
-nReceivers = preprocessingDataReceivers(preprocessing['MESH_FILE'],
+nReceivers = preprocessingDataReceivers(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
preprocessing['RECEIVERS_FILE'],
preprocessing['OUT_DIR'], rank)
# Sparsity pattern for parallel matrix allocation
-preprocessingNNZ(preprocessing['MESH_FILE'], preprocessing['OUT_DIR'], rank)
+preprocessingNNZ(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
# ###############################################
# ------------------ Summary --------------------
printMessage('\nSummary', rank)
printMessage('='*75, rank)
-printPreprocessingSummary(nNodes, nElems, nDofs, nReceivers, rank)
+printPreprocessingSummary(nElems, nNodes, nFaces, nDofs, nReceivers, rank)
# ###############################################
# ----------- Print footer (Master) -------------
diff --git a/doc/source/_static/Documentation.rst~ b/doc/source/_static/Documentation.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/_static/Features.rst~ b/doc/source/_static/Features.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/_static/Tutorial.rst~ b/doc/source/_static/Tutorial.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/PETGEM_assembly.png b/doc/source/_static/figures/PETGEM_assembly.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/PETGEM_parallel_scheme.png b/doc/source/_static/figures/PETGEM_parallel_scheme.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/class_diagram.png b/doc/source/_static/figures/class_diagram.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/component_diagram.png b/doc/source/_static/figures/component_diagram.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/edgeElement.jpg b/doc/source/_static/figures/edgeElement.jpg
old mode 100644
new mode 100755
index ee60462..0e7846c
Binary files a/doc/source/_static/figures/edgeElement.jpg and b/doc/source/_static/figures/edgeElement.jpg differ
diff --git a/doc/source/_static/figures/logo_bsc.jpeg b/doc/source/_static/figures/logo_bsc.jpeg
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/model1.png b/doc/source/_static/figures/model1.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/model_preprocessing.png b/doc/source/_static/figures/model_preprocessing.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/output_preprocessing.png b/doc/source/_static/figures/output_preprocessing.png
index 59f9975..79276e2 100644
Binary files a/doc/source/_static/figures/output_preprocessing.png and b/doc/source/_static/figures/output_preprocessing.png differ
diff --git a/doc/source/_static/figures/petgem_logo.png b/doc/source/_static/figures/petgem_logo.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/sequence_diagram.png b/doc/source/_static/figures/sequence_diagram.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/softwareStack.jpg b/doc/source/_static/figures/softwareStack.jpg
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/totalFieldVTK.png b/doc/source/_static/figures/totalFieldVTK.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/total_field_X_model1.png b/doc/source/_static/figures/total_field_X_model1.png
old mode 100644
new mode 100755
diff --git a/doc/source/_static/figures/total_field_X_model2.png b/doc/source/_static/figures/total_field_X_model2.png
new file mode 100644
index 0000000..352b24b
Binary files /dev/null and b/doc/source/_static/figures/total_field_X_model2.png differ
diff --git a/doc/source/_static/petgem.css b/doc/source/_static/petgem.css
old mode 100644
new mode 100755
diff --git a/doc/source/_static/petgem.css~ b/doc/source/_static/petgem.css~
old mode 100644
new mode 100755
diff --git a/doc/source/_static/setup.cfg b/doc/source/_static/setup.cfg
old mode 100644
new mode 100755
diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html
old mode 100644
new mode 100755
diff --git a/doc/source/conf.py b/doc/source/conf.py
old mode 100644
new mode 100755
diff --git a/doc/source/examples/modelParams.rst b/doc/source/examples/modelParams.rst
old mode 100644
new mode 100755
diff --git a/doc/source/examples/preprocessingParams.rst b/doc/source/examples/preprocessingParams.rst
old mode 100644
new mode 100755
diff --git a/doc/source/index.rst b/doc/source/index.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/base/basis_scripts.rst b/doc/source/petgem/base/basis_scripts.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/base/modelling.rst b/doc/source/petgem/base/modelling.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/base/modelling.rst~ b/doc/source/petgem/base/modelling.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/base/styles.rst b/doc/source/petgem/base/styles.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/base/styles.rst~ b/doc/source/petgem/base/styles.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/efem.rst b/doc/source/petgem/efem/efem.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/efem.rst~ b/doc/source/petgem/efem/efem.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/fem.rst b/doc/source/petgem/efem/fem.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/fem.rst~ b/doc/source/petgem/efem/fem.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/general.rst~ b/doc/source/petgem/efem/general.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/mesh.rst~ b/doc/source/petgem/efem/mesh.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/nedelec_elements.rst~ b/doc/source/petgem/efem/nedelec_elements.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/efem/vectorMatrixFunctions.rst b/doc/source/petgem/efem/vectorMatrixFunctions.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/kernel/kernel.rst b/doc/source/petgem/kernel/kernel.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/kernel/kernel.rst~ b/doc/source/petgem/kernel/kernel.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/mesh/mesh.rst b/doc/source/petgem/mesh/mesh.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/mesh/mesh.rst~ b/doc/source/petgem/mesh/mesh.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/monitoring/monitoring.rst b/doc/source/petgem/monitoring/monitoring.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/monitoring/monitoring.rst~ b/doc/source/petgem/monitoring/monitoring.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/parallel/mesh.rst~ b/doc/source/petgem/parallel/mesh.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/parallel/parallel.rst b/doc/source/petgem/parallel/parallel.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/parallel/parallel.rst~ b/doc/source/petgem/parallel/parallel.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/postprocessing/assembler.rst~ b/doc/source/petgem/postprocessing/assembler.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/postprocessing/postprocessing.rst b/doc/source/petgem/postprocessing/postprocessing.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/postprocessing/postprocessing.rst~ b/doc/source/petgem/postprocessing/postprocessing.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/postprocessing/solver.rst~ b/doc/source/petgem/postprocessing/solver.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/preprocessing/assembler.rst~ b/doc/source/petgem/preprocessing/assembler.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/preprocessing/postprocessing.rst~ b/doc/source/petgem/preprocessing/postprocessing.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/preprocessing/preprocessing.rst b/doc/source/petgem/preprocessing/preprocessing.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/preprocessing/solver.rst~ b/doc/source/petgem/preprocessing/solver.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/solver/assembler.rst b/doc/source/petgem/solver/assembler.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/solver/assembler.rst~ b/doc/source/petgem/solver/assembler.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/solver/solver.rst b/doc/source/petgem/solver/solver.rst
old mode 100644
new mode 100755
diff --git a/doc/source/petgem/solver/solver.rst~ b/doc/source/petgem/solver/solver.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/petgem_theme/theme.conf b/doc/source/petgem_theme/theme.conf
old mode 100644
new mode 100755
diff --git a/doc/source/petgem_theme/theme.conf~ b/doc/source/petgem_theme/theme.conf~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/config.rst~ b/doc/source/setup/config.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/init.rst~ b/doc/source/setup/init.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-base.rst~ b/doc/source/setup/setup-base.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-decomposition.rst~ b/doc/source/setup/setup-decomposition.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-efem.rst~ b/doc/source/setup/setup-efem.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-mesh.rst~ b/doc/source/setup/setup-mesh.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-monitor.rst~ b/doc/source/setup/setup-monitor.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-monitoring.rst~ b/doc/source/setup/setup-monitoring.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-parallel.rst~ b/doc/source/setup/setup-parallel.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-petgem.rst~ b/doc/source/setup/setup-petgem.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-postprocessing.rst~ b/doc/source/setup/setup-postprocessing.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup-solver.rst~ b/doc/source/setup/setup-solver.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup.rst b/doc/source/setup/setup.rst
old mode 100644
new mode 100755
diff --git a/doc/source/setup/setup.rst~ b/doc/source/setup/setup.rst~
old mode 100644
new mode 100755
diff --git a/doc/source/setup/version.rst~ b/doc/source/setup/version.rst~
old mode 100644
new mode 100755
diff --git a/examples/Example1.zip b/examples/Example1.zip
index 5788c9c..27f1b8a 100644
Binary files a/examples/Example1.zip and b/examples/Example1.zip differ
diff --git a/examples/Example2.zip b/examples/Example2.zip
index cc0efd9..2191f34 100644
Binary files a/examples/Example2.zip and b/examples/Example2.zip differ
diff --git a/examples/Example3.zip b/examples/Example3.zip
index bae1369..288ba26 100644
Binary files a/examples/Example3.zip and b/examples/Example3.zip differ
diff --git a/examples/Example4.zip b/examples/Example4.zip
new file mode 100644
index 0000000..070fba0
Binary files /dev/null and b/examples/Example4.zip differ
diff --git a/examples/modelParams.py b/examples/modelParams.py
index 8627f37..711ccf4 100644
--- a/examples/modelParams.py
+++ b/examples/modelParams.py
@@ -13,11 +13,26 @@
Next, each key is described.
'''
modelling = {
- # ----- Pyshical parameters -----
+ # ---------- Nedelec element order ----------
+ # 1 = First nedelec order (6 DOFS per element)
+ # 2 = Second nedelec order (20 DOFS per element)
+ # 3 = Third nedelec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 2,
+
+ # ---------- CUDA SUPPORT ----------
+ # 0 = No
+ # 1 = Yes
+ # Type: int
+ # Optional: NO
+ 'CUDA': 0,
+
+ # ----- Physical parameters -----
# Source
# Source frequency. Type: float
# Optional: NO
- 'FREQ': 2.0,
+ 'FREQ': 1.0,
# Source position(x, y, z). Type: float
# Optional: NO
'SRC_POS': [1750.0, 1750.0, -975.0],
@@ -35,7 +50,7 @@
'SRC_LENGTH': 1.0,
# Conductivity model. Type: str
# Optional: NO
- 'CONDUCTIVITY_MODEL_FILE': 'examples/DIPOLE1D/Input_model/conductivityModel.dat',
+ 'CONDUCTIVITY_MODEL_FILE': 'PATH_TO_FILE',
# Background conductivity. Type: float
# Optional: NO
'CONDUCTIVITY_BACKGROUND': 3.33,
@@ -44,21 +59,27 @@
# Mesh files
# Nodes spatial coordinates. Type: str
# Optional: NO
- 'NODES_FILE': 'examples/DIPOLE1D/Input_model/nodes.dat',
+ 'NODES_FILE': 'PATH_TO_FILE',
# Elements-nodes connectivity. Type: str
# Optional: NO
- 'MESH_CONNECTIVITY_FILE': 'examples/DIPOLE1D/Input_model/meshConnectivity.dat',
+ 'MESH_CONNECTIVITY_FILE': 'PATH_TO_FILE',
+ # Elements-faces connectivity. Type: str
+ # Optional: NO
+ 'FACES_CONNECTIVITY_FILE': 'PATH_TO_FILE',
+ # Faces-nodes connectivity. Type: str
+ # Optional: NO
+ 'FACES_NODES_FILE': 'PATH_TO_FILE',
# Elements-edges connectivity. Type: str
# Optional: NO
- 'DOFS_CONNECTIVITY_FILE': 'examples/DIPOLE1D/Input_model/dofs.dat',
+ 'EDGES_CONNECTIVITY_FILE': 'PATH_TO_FILE',
# Edges-nodes connectivity. Type: str
# Optional: NO
- 'DOFS_NODES_FILE': 'examples/DIPOLE1D/Input_model/dofsNodes.dat',
+ 'EDGES_NODES_FILE': 'PATH_TO_FILE',
# Sparsity pattern for matrix allocation (PETSc)
- 'NNZ_FILE': 'examples/DIPOLE1D/Input_model/nnz.dat',
+ 'NNZ_FILE': 'PATH_TO_FILE',
# Boundaries. Type: str
# Optional: NO
- 'BOUNDARIES_FILE': 'examples/DIPOLE1D/Input_model/boundaries.dat',
+ 'BOUNDARIES_FILE': 'PATH_TO_FILE',
# ------------ Solver -----------
# Solver options must be set in
@@ -67,5 +88,5 @@
# ------------ Receivers file -----------
# Name of the file that contains the receivers position. Type: str
# Optional: NO
- 'RECEIVERS_FILE': 'examples/DIPOLE1D/Input_model/receivers.dat',
+ 'RECEIVERS_FILE': 'PATH_TO_FILE',
}
diff --git a/examples/petsc.opts b/examples/petsc.opts
old mode 100644
new mode 100755
diff --git a/examples/preprocessingParams.py b/examples/preprocessingParams.py
index f443ee0..c7b461f 100644
--- a/examples/preprocessingParams.py
+++ b/examples/preprocessingParams.py
@@ -10,16 +10,24 @@
All file paths should consider as absolute.
'''
preprocessing = {
+ # ---------- Nedelec element order ----------
+ # 1 = First Nédélec order (6 DOFS per element)
+ # 2 = Second Nédélec order (20 DOFS per element)
+ # 3 = Third Nédélec order (45 DOFS per element)
+ # Type: int
+ # Optional: NO
+ 'NEDELEC_ORDER': 1,
+
# ---------- Mesh file ----------
- 'MESH_FILE': 'examples/DIPOLE1D/Input_preprocessing/DIPOLE1D.msh',
+ 'MESH_FILE': 'PATH_TO_FILE',
# ---------- Material conductivities ----------
'MATERIAL_CONDUCTIVITIES': [1.0, 1./100., 1., 1./.3],
# ---------- Receivers position file ----------
- 'RECEIVERS_FILE': 'examples/DIPOLE1D/Input_preprocessing/RECEIVER_POSITIONS.txt',
+ 'RECEIVERS_FILE': 'PATH_TO_FILE',
# ---------- Path for Output ----------
- 'OUT_DIR': 'examples/DIPOLE1D/Input_model/',
+ 'OUT_DIR': 'PATH_TO_FILE',
}
diff --git a/kernel.py b/kernel.py
old mode 100644
new mode 100755
index 571648e..4fc3110
--- a/kernel.py
+++ b/kernel.py
@@ -42,10 +42,6 @@
# -- Get rank, size and MASTER of the MPI pool --
MASTER, rank, size = getRankSize()
- # ###############################################
- # ----- Define geometry and EFEM constants -----
- edgeOrder, nodalOrder, numDimensions = defineEFEMConstants()
-
# ###############################################
# ----------- Print header (Master) -------------
printPetgemHeader(rank)
@@ -60,6 +56,11 @@
# ------- Check and read parameters file --------
modelling = readUserParams(input_params, rank)
+ # ###############################################
+ # ----- Define geometry and EFEM constants -----
+ [edgeOrder, nodalOrder,
+ numDimensions] = defineEFEMConstants(modelling['NEDELEC_ORDER'])
+
# ###############################################
# ---------------- Read mesh --------------------
printMessage('\nImport files', rank)
@@ -74,16 +75,25 @@
printMessage(' Elements-nodes connectivity', rank)
elemsN = readPetscMatrix(modelling['MESH_CONNECTIVITY_FILE'],
communicator=None)
+ # elements-faces connectivity
+ printMessage(' Elements-faces connectivity', rank)
+ elemsF = readPetscMatrix(modelling['FACES_CONNECTIVITY_FILE'],
+ communicator=None)
+ # facesN connectivity
+ printMessage(' Faces-nodes connectivity', rank)
+ facesN = readPetscMatrix(modelling['FACES_NODES_FILE'],
+ communicator=None)
# elements-edges connectivity
printMessage(' Elements-edges connectivity', rank)
- elemsE = readPetscMatrix(modelling['DOFS_CONNECTIVITY_FILE'],
+ elemsE = readPetscMatrix(modelling['EDGES_CONNECTIVITY_FILE'],
communicator=None)
# edgesN connectivity
printMessage(' Edges-nodes connectivity', rank)
- edgesN = readPetscMatrix(modelling['DOFS_NODES_FILE'], communicator=None)
- # Boundary-Edges
+ edgesN = readPetscMatrix(modelling['EDGES_NODES_FILE'], communicator=None)
+ # Boundaries
printMessage(' Boundary-Edges', rank)
- bEdges = readPetscVector(modelling['BOUNDARIES_FILE'], communicator=None)
+ boundaries = readPetscVector(modelling['BOUNDARIES_FILE'],
+ communicator=None)
# Sparsity pattern (NNZ) for matrix allocation
printMessage(' Vector for matrix allocation', rank)
Q = readPetscVector(modelling['NNZ_FILE'], communicator=None)
@@ -100,26 +110,28 @@
# ###############################################
# -------------- Mesh information ---------------
- [nElems, nEdges, nBoundaries, ndofs] = getMeshInfo(elemsN, edgesN,
- bEdges, rank)
+ [nElems, nFaces, nEdges, ndofs,
+ nBoundaries] = getMeshInfo(modelling['NEDELEC_ORDER'], elemsN, elemsF,
+ facesN, edgesN, boundaries, rank)
# ###############################################
# --------- Information of parallel pool --------
printMessage('\nParallel information', rank)
printMessage('='*75, rank)
[Istart_elemsE, Iend_elemsE,
- Istart_bEdges, Iend_bEdges,
- Istart_receivers, Iend_receivers] = getRanges(elemsE, bEdges, receivers,
- size, rank)
+ Istart_boundaries, Iend_boundaries,
+ Istart_receivers, Iend_receivers] = getRanges(elemsE, boundaries,
+ receivers, size, rank)
# ###############################################
# ----- Create and setup parallel structures ----
# Left-hand side
- A = createParallelMatrix(nEdges, nEdges, nnz, communicator=None)
+ A = createParallelMatrix(ndofs, ndofs, nnz, modelling['CUDA'],
+ communicator=None)
# Right-hand side
- b = createParallelVector(nEdges, communicator=None)
+ b = createParallelVector(ndofs, modelling['CUDA'], communicator=None)
# X vector
- x = createParallelVector(nEdges, communicator=None)
+ x = createParallelVector(ndofs, modelling['CUDA'], communicator=None)
# ###############################################
# -------------- Parallel assembly --------------
@@ -130,9 +142,10 @@
assemblerLog.begin()
# System assembly
[A, b, elapsedTimeAssembly] = parallelAssembler(modelling, A, b, nodes,
- elemsE, elemsN, elemsSigma,
+ elemsE, elemsN, elemsF,
+ facesN, elemsSigma,
Istart_elemsE, Iend_elemsE,
- rank)
+ nEdges, nFaces, rank)
# End log event for assembly task
assemblerLog.end()
@@ -144,9 +157,10 @@
boundariesLog = startLogEvent("Boundaries")
boundariesLog.begin()
# Set boundary conditions
- [A, b, elapsedTimeBoundaries] = setBoundaryConditions(A, b, bEdges,
- Istart_bEdges,
- Iend_bEdges, rank)
+ [A, b, elapsedTimeBoundaries] = setBoundaryConditions(A, b, boundaries,
+ Istart_boundaries,
+ Iend_boundaries,
+ rank)
# End log event for setting boundary conditions task
boundariesLog.end()
@@ -166,14 +180,16 @@
# --------------- Post-processing ---------------
printMessage('\nPost-processing', rank)
printMessage('='*75, rank)
- # Create and start log event for assembly task
+ # # Create and start log event for assembly task
postProcessingLog = startLogEvent("Postprocessing")
postProcessingLog.begin()
- elapsedTimepostProcessing = postProcessingFields(receivers, modelling, x,
- Iend_receivers,
- Istart_receivers,
- edgeOrder, nodalOrder,
- numDimensions, rank)
+ elapsedTimepostProcess = postProcessingFields(receivers, modelling, x,
+ Iend_receivers,
+ Istart_receivers,
+ modelling['NEDELEC_ORDER'],
+ modelling['CUDA'],
+ nodalOrder,
+ numDimensions, rank)
postProcessingLog.end()
# ###############################################
@@ -181,7 +197,7 @@
printMessage('\nElapsed times (seconds)', rank)
printMessage('='*75, rank)
printElapsedTimes(elapsedTimeAssembly, elapsedTimeSolver,
- elapsedTimepostProcessing, iterationNumber, rank)
+ elapsedTimepostProcess, iterationNumber, rank)
# ###############################################
# ----------- Print footer (Master) -------------
diff --git a/petgem.egg-info/PKG-INFO b/petgem.egg-info/PKG-INFO
old mode 100644
new mode 100755
index d0ae852..38ef9ff
--- a/petgem.egg-info/PKG-INFO
+++ b/petgem.egg-info/PKG-INFO
@@ -1,19 +1,18 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: petgem
-Version: 0.30.48
+Version: 0.5
Summary: Parallel python code for electromagnetic modeling in geophysics
Home-page: https://www.bsc.es/castillo-octavio
-Author: Octavio Castillo Reyes
-Author-email: octavio.castillo@bsc.es
+Maintainer: Octavio Castillo Reyes
+Maintainer-email: octavio.castillo@bsc.es
License: GPLv3.0
Download-URL: http://petgem.bsc.es
-Description-Content-Type: UNKNOWN
Description: petgem
======
- petgem is a parallel python code for 3D Controlled-Source
- Electromagnetic Method (3D CSEM) in geophysics using edge finite
- elements (Nedelec finite elements).
+ PETGEM is a parallel python code for 3D Controlled-Source
+ Electromagnetic Method (3D CSEM) in geophysics using high-order edge finite
+ elements (Nédélec finite elements).
Requirements
@@ -39,15 +38,15 @@ Description: petgem
* Following commands may require root privileges
- * Download `PETSc `__ (PETSc 3.7 and 3.8 have been tested)
+ * Download `PETSc `__ (PETSc 3.7, 3.8, and 3.9 have been tested)
- * Uncompress the PETSc archive (in this example, using PETSc 3.8.3)::
+ * Uncompress the PETSc archive (in this example, using PETSc 3.9.3)::
- $ tar zxvf petsc-3.8.3.tar.gz
+ $ tar zxvf petsc-3.9.3.tar.gz
* Configure and build PETSc. The configuration options depend on the calculations you want to perform (complex- or real-valued) as well as your compiler/MPI/Blas/Lapack setup. For PETGEM executions, **PETSC MUST BE BUILD FOR COMPLEX-VALUED NUMBERS**. In order to avoid incompatibilities between PETSC, petsc4py and PETGEM, we highly recommend the following configuration lines. Please, visit PETSc website for advanced configuration options. If you have a clean environment (not working MPI/Blas/Lapack), then run::
- $ cd petsc-3.8.3
+ $ cd petsc-3.9.3
$ export PETSC_DIR=$PWD
$ export PETSC_ARCH=arch-linux2-c-debug
@@ -59,6 +58,12 @@ Description: petgem
$ --download-mumps --download-scalapack --download-parmetis --download-metis --download-ptscotch --download-cmake
+ * Further, to activate GPUs support, please add following options to previous configure line::
+
+ $ --with-cuda=1 --with_cuda_dir=PATH
+
+ where ``PATH`` is the directory of your CUDA libraries.
+
* Then, build and install PETSc::
$ make $PETSC_DIR $PETSC_ARCH all
@@ -81,14 +86,19 @@ Description: petgem
Citations
---------
- If petgem been significant to a project that leads to an academic
+ If PETGEM been significant to a project that leads to an academic
publication, please acknowledge that fact by citing the project:
- * Castillo-Reyes, O., de la Puente, J., Cela, J.M. (2017).
- *Three-Dimensional CSEM Modelling on Unstructured Tetrahedral Meshes
- Using Edge Finite Elements*, Communications in Computer and
- Information Science, vol 697: 247-256. ISBN 978-3-319-57971-9
- Springer, Cham. https://doi.org/10.1007/978-3-319-57972-6_18
+ * Castillo-Reyes, O., de la Puente, J., Cela, J. M. (2018).
+ *PETGEM: A parallel code for 3D CSEM forward modeling using edge finite
+ elements*. Computers & Geosciences, vol 119: 123-136. ISSN 0098-3004,
+ Elsevier. https://doi.org/10.1016/j.cageo.2018.07.005
+
+ * Castillo-Reyes, O., de la Puente, J., Cela, J.M. (2017).
+ *Three-Dimensional CSEM Modelling on Unstructured Tetrahedral Meshes
+ Using Edge Finite Elements*, Communications in Computer and
+ Information Science, vol 697: 247-256. ISBN 978-3-319-57971-9
+ Springer, Cham. https://doi.org/10.1007/978-3-319-57972-6_18
Keywords: 3D CSEM, edge finite elements, HPC, petsc, petsc4py.
Platform: Linux
diff --git a/petgem.egg-info/SOURCES.txt b/petgem.egg-info/SOURCES.txt
old mode 100644
new mode 100755
index 8f79187..95fdd66
--- a/petgem.egg-info/SOURCES.txt
+++ b/petgem.egg-info/SOURCES.txt
@@ -7,243 +7,6 @@ run_preprocessing.py
setup.cfg
setup.py
doc/Makefile
-doc/build/doctrees/CSEMEdges.doctree
-doc/build/doctrees/Contact.doctree
-doc/build/doctrees/Download.doctree
-doc/build/doctrees/Features.doctree
-doc/build/doctrees/Installation.doctree
-doc/build/doctrees/Manual.doctree
-doc/build/doctrees/Publications.doctree
-doc/build/doctrees/Tutorial.doctree
-doc/build/doctrees/WhatIs.doctree
-doc/build/doctrees/environment.pickle
-doc/build/doctrees/index.doctree
-doc/build/doctrees/examples/modelParams.doctree
-doc/build/doctrees/examples/preprocessingParams.doctree
-doc/build/doctrees/petgem/base/basis_scripts.doctree
-doc/build/doctrees/petgem/base/modelling.doctree
-doc/build/doctrees/petgem/base/styles.doctree
-doc/build/doctrees/petgem/efem/efem.doctree
-doc/build/doctrees/petgem/efem/fem.doctree
-doc/build/doctrees/petgem/efem/vectorMatrixFunctions.doctree
-doc/build/doctrees/petgem/kernel/kernel.doctree
-doc/build/doctrees/petgem/mesh/mesh.doctree
-doc/build/doctrees/petgem/monitoring/monitoring.doctree
-doc/build/doctrees/petgem/parallel/parallel.doctree
-doc/build/doctrees/petgem/postprocessing/postprocessing.doctree
-doc/build/doctrees/petgem/preprocessing/preprocessing.doctree
-doc/build/doctrees/petgem/solver/assembler.doctree
-doc/build/doctrees/petgem/solver/solver.doctree
-doc/build/doctrees/setup/setup.doctree
-doc/build/html/.buildinfo
-doc/build/html/CSEMEdges.html
-doc/build/html/Contact.html
-doc/build/html/Download.html
-doc/build/html/Features.html
-doc/build/html/Installation.html
-doc/build/html/Manual.html
-doc/build/html/Publications.html
-doc/build/html/Tutorial.html
-doc/build/html/WhatIs.html
-doc/build/html/genindex.html
-doc/build/html/index.html
-doc/build/html/objects.inv
-doc/build/html/py-modindex.html
-doc/build/html/search.html
-doc/build/html/searchindex.js
-doc/build/html/_downloads/GPLv3_T_C.pdf
-doc/build/html/_downloads/kernel.py
-doc/build/html/_downloads/modelParams.py
-doc/build/html/_downloads/petsc.opts
-doc/build/html/_downloads/preprocessingParams.py
-doc/build/html/_downloads/run_preprocessing.py
-doc/build/html/_images/PETGEM_parallel_scheme.png
-doc/build/html/_images/class_diagram.png
-doc/build/html/_images/component_diagram.png
-doc/build/html/_images/edgeElement.jpg
-doc/build/html/_images/model1.png
-doc/build/html/_images/model_preprocessing.png
-doc/build/html/_images/output_preprocessing.png
-doc/build/html/_images/sequence_diagram.png
-doc/build/html/_images/softwareStack.jpg
-doc/build/html/_images/totalFieldVTK.png
-doc/build/html/_images/total_field_X_model1.png
-doc/build/html/_images/math/011e5790a6c33043ceadca81d9657dde6c61d769.png
-doc/build/html/_images/math/04615352c253577db465254c8472a56a22f929e3.png
-doc/build/html/_images/math/0637d483fd4572928af77d351880fa5d99de0639.png
-doc/build/html/_images/math/0f61209c74e91af59effb0034a18c9e20842b9ad.png
-doc/build/html/_images/math/108b261d0fb9e1fc5ef05bca89d81f9536276306.png
-doc/build/html/_images/math/128cb7613c50e091d5ed0c4c631f94c14b2208ea.png
-doc/build/html/_images/math/12de4daabfac3d325423a62d25e1c644d7aff1c5.png
-doc/build/html/_images/math/18fbb1ca63534927f6185e7da753a45d89e8a6bb.png
-doc/build/html/_images/math/1ab98880e07cc102c8b27c778be235fa35447d60.png
-doc/build/html/_images/math/1b1751f7c08678ec02839c883370e1f485bf1cfe.png
-doc/build/html/_images/math/1b23b00cdc487a2b00a9d479e09947c43e8bf66b.png
-doc/build/html/_images/math/26a8dcae237b2cc1c4af9341b5ad47b43501f34f.png
-doc/build/html/_images/math/27d463da4622be5b3ef1d4176ced7d7a323c6425.png
-doc/build/html/_images/math/302f31b1a918dd143d53dab4649346d85a8fa792.png
-doc/build/html/_images/math/382bac1ca802500dfe8557b2cc59091ce27a7357.png
-doc/build/html/_images/math/43e5f6f8941e97dad900f219e8296c1ead98fae7.png
-doc/build/html/_images/math/4494e9b5e147f29c6cd47e00ad0805d3c13c0d99.png
-doc/build/html/_images/math/54a34fd8abde26fa0013111971eccd6158094e8b.png
-doc/build/html/_images/math/5ecfb5efd13556512083272088a2baa0839e3c66.png
-doc/build/html/_images/math/63751cb2e98ba393b0f22e45ca127c3cebb61487.png
-doc/build/html/_images/math/66c954fa19dbde81a9ef695623119ca386b322a8.png
-doc/build/html/_images/math/78a06cf7a34f39fde71fbba0d5539baae7c72d4e.png
-doc/build/html/_images/math/7e2fc44f1822d652ad5eec7fb3a4091404b2bae9.png
-doc/build/html/_images/math/7f940eafc240052d58ba29449f1b42f362d728a5.png
-doc/build/html/_images/math/85bab93280badb33fa5af4e02512594786b8b96d.png
-doc/build/html/_images/math/8b5bfe447077684d8941d5813a7eac322b809de9.png
-doc/build/html/_images/math/8c77da2488bbc1f116151218ea2db969e41278a9.png
-doc/build/html/_images/math/8dad0dea5e39bdc613bcdbee3df2aa308c4bfb36.png
-doc/build/html/_images/math/92d87ddbc8556091823ce39983632b51a9017155.png
-doc/build/html/_images/math/949aeae100d4cedce0cdac415b623cb45987a610.png
-doc/build/html/_images/math/a6a3f8d12297ed2927849fdb3781c0b2a102a10f.png
-doc/build/html/_images/math/a83d027b4a941b54bdc83c9dd2f8aa3c17632757.png
-doc/build/html/_images/math/b33ce3703c911a1378e4daee36821363ac79623a.png
-doc/build/html/_images/math/b51aa99e0bc8cc8c3d17c0b9cf822db73e13293e.png
-doc/build/html/_images/math/b9040d52d78d98aea6867a562560cc34dd30b780.png
-doc/build/html/_images/math/ca92360eea377f62866449804d0938704a76f5bf.png
-doc/build/html/_images/math/cb5fc5bdb973c86de9def73a1a02062126b06948.png
-doc/build/html/_images/math/d275af031e98b6eb55e1438bf891a34a840441f7.png
-doc/build/html/_images/math/d79e8a2c7ce54906c2b25549da38bdbe02cf40d6.png
-doc/build/html/_images/math/d872993ed0c7c420e73e77a1d285ac100c516806.png
-doc/build/html/_images/math/dad48cd4c5cab157b7c283308b11d4ba1bbb037c.png
-doc/build/html/_images/math/df0deb143e5ac127f00bd248ee8001ecae572adc.png
-doc/build/html/_images/math/e7e68cfb93d1957dc2310ad17a25221b7e397f18.png
-doc/build/html/_images/math/eaa3cc725b3b1d2897f997f93c7b7a058130eb58.png
-doc/build/html/_images/math/eeb09f98a36d7f95bf06fa6b39ec78f9718c39ed.png
-doc/build/html/_modules/index.html
-doc/build/html/_modules/setup.html
-doc/build/html/_modules/petgem/base/base.html
-doc/build/html/_modules/petgem/base/modelling.html
-doc/build/html/_modules/petgem/base/styles.html
-doc/build/html/_modules/petgem/efem/efem.html
-doc/build/html/_modules/petgem/efem/fem.html
-doc/build/html/_modules/petgem/efem/vectorMatrixFunctions.html
-doc/build/html/_modules/petgem/mesh/mesh.html
-doc/build/html/_modules/petgem/monitoring/monitoring.html
-doc/build/html/_modules/petgem/parallel/parallel.html
-doc/build/html/_modules/petgem/postprocessing/postprocessing.html
-doc/build/html/_modules/petgem/preprocessing/preprocessing.html
-doc/build/html/_modules/petgem/solver/assembler.html
-doc/build/html/_modules/petgem/solver/solver.html
-doc/build/html/_sources/CSEMEdges.rst.txt
-doc/build/html/_sources/Contact.rst.txt
-doc/build/html/_sources/Download.rst.txt
-doc/build/html/_sources/Features.rst.txt
-doc/build/html/_sources/Installation.rst.txt
-doc/build/html/_sources/Manual.rst.txt
-doc/build/html/_sources/Publications.rst.txt
-doc/build/html/_sources/Tutorial.rst.txt
-doc/build/html/_sources/WhatIs.rst.txt
-doc/build/html/_sources/index.rst.txt
-doc/build/html/_sources/examples/modelParams.rst.txt
-doc/build/html/_sources/examples/preprocessingParams.rst.txt
-doc/build/html/_sources/petgem/base/basis_scripts.rst.txt
-doc/build/html/_sources/petgem/base/modelling.rst.txt
-doc/build/html/_sources/petgem/base/styles.rst.txt
-doc/build/html/_sources/petgem/efem/efem.rst.txt
-doc/build/html/_sources/petgem/efem/fem.rst.txt
-doc/build/html/_sources/petgem/efem/vectorMatrixFunctions.rst.txt
-doc/build/html/_sources/petgem/kernel/kernel.rst.txt
-doc/build/html/_sources/petgem/mesh/mesh.rst.txt
-doc/build/html/_sources/petgem/monitoring/monitoring.rst.txt
-doc/build/html/_sources/petgem/parallel/parallel.rst.txt
-doc/build/html/_sources/petgem/postprocessing/postprocessing.rst.txt
-doc/build/html/_sources/petgem/preprocessing/preprocessing.rst.txt
-doc/build/html/_sources/petgem/solver/assembler.rst.txt
-doc/build/html/_sources/petgem/solver/solver.rst.txt
-doc/build/html/_sources/setup/setup.rst.txt
-doc/build/html/_static/Documentation.rst~
-doc/build/html/_static/Features.rst~
-doc/build/html/_static/Tutorial.rst~
-doc/build/html/_static/ajax-loader.gif
-doc/build/html/_static/basic.css
-doc/build/html/_static/comment-bright.png
-doc/build/html/_static/comment-close.png
-doc/build/html/_static/comment.png
-doc/build/html/_static/doctools.js
-doc/build/html/_static/down-pressed.png
-doc/build/html/_static/down.png
-doc/build/html/_static/file.png
-doc/build/html/_static/jquery-3.1.0.js
-doc/build/html/_static/jquery.js
-doc/build/html/_static/minus.png
-doc/build/html/_static/petgem.css
-doc/build/html/_static/petgem.css~
-doc/build/html/_static/plus.png
-doc/build/html/_static/pygments.css
-doc/build/html/_static/searchtools.js
-doc/build/html/_static/setup.cfg
-doc/build/html/_static/underscore-1.3.1.js
-doc/build/html/_static/underscore.js
-doc/build/html/_static/up-pressed.png
-doc/build/html/_static/up.png
-doc/build/html/_static/websupport.js
-doc/build/html/_static/figures/PETGEM_assembly.png
-doc/build/html/_static/figures/PETGEM_parallel_scheme.png
-doc/build/html/_static/figures/class_diagram.png
-doc/build/html/_static/figures/component_diagram.png
-doc/build/html/_static/figures/edgeElement.jpg
-doc/build/html/_static/figures/logo_bsc.jpeg
-doc/build/html/_static/figures/model1.png
-doc/build/html/_static/figures/model_preprocessing.png
-doc/build/html/_static/figures/output_preprocessing.png
-doc/build/html/_static/figures/petgem_logo.png
-doc/build/html/_static/figures/sequence_diagram.png
-doc/build/html/_static/figures/softwareStack.jpg
-doc/build/html/_static/figures/totalFieldVTK.png
-doc/build/html/_static/figures/total_field_X_model1.png
-doc/build/html/examples/modelParams.html
-doc/build/html/examples/preprocessingParams.html
-doc/build/html/petgem/base/basis_scripts.html
-doc/build/html/petgem/base/modelling.html
-doc/build/html/petgem/base/styles.html
-doc/build/html/petgem/efem/efem.html
-doc/build/html/petgem/efem/fem.html
-doc/build/html/petgem/efem/vectorMatrixFunctions.html
-doc/build/html/petgem/kernel/kernel.html
-doc/build/html/petgem/mesh/mesh.html
-doc/build/html/petgem/monitoring/monitoring.html
-doc/build/html/petgem/parallel/parallel.html
-doc/build/html/petgem/postprocessing/postprocessing.html
-doc/build/html/petgem/preprocessing/preprocessing.html
-doc/build/html/petgem/solver/assembler.html
-doc/build/html/petgem/solver/solver.html
-doc/build/html/setup/setup.html
-doc/build/latex/Makefile
-doc/build/latex/PETGEM.aux
-doc/build/latex/PETGEM.fdb_latexmk
-doc/build/latex/PETGEM.fls
-doc/build/latex/PETGEM.idx
-doc/build/latex/PETGEM.ilg
-doc/build/latex/PETGEM.ind
-doc/build/latex/PETGEM.log
-doc/build/latex/PETGEM.out
-doc/build/latex/PETGEM.pdf
-doc/build/latex/PETGEM.tex
-doc/build/latex/PETGEM.toc
-doc/build/latex/PETGEM_parallel_scheme.png
-doc/build/latex/class_diagram.png
-doc/build/latex/component_diagram.png
-doc/build/latex/edgeElement.jpg
-doc/build/latex/footnotehyper-sphinx.sty
-doc/build/latex/latexmkjarc
-doc/build/latex/latexmkrc
-doc/build/latex/model1.png
-doc/build/latex/model_preprocessing.png
-doc/build/latex/output_preprocessing.png
-doc/build/latex/python.ist
-doc/build/latex/sequence_diagram.png
-doc/build/latex/softwareStack.jpg
-doc/build/latex/sphinx.sty
-doc/build/latex/sphinxhighlight.sty
-doc/build/latex/sphinxhowto.cls
-doc/build/latex/sphinxmanual.cls
-doc/build/latex/sphinxmulticell.sty
-doc/build/latex/totalFieldVTK.png
-doc/build/latex/total_field_X_model1.png
doc/source/CSEMEdges.rst
doc/source/Contact.rst
doc/source/Download.rst
@@ -255,6 +18,10 @@ doc/source/Tutorial.rst
doc/source/WhatIs.rst
doc/source/conf.py
doc/source/index.rst
+doc/source/_downloads/Example1.zip
+doc/source/_downloads/Example2.zip
+doc/source/_downloads/Example3.zip
+doc/source/_downloads/Example4.zip
doc/source/_downloads/GPLv3_T_C.pdf
doc/source/_downloads/kernel.py
doc/source/_downloads/modelParams.py
@@ -281,6 +48,7 @@ doc/source/_static/figures/sequence_diagram.png
doc/source/_static/figures/softwareStack.jpg
doc/source/_static/figures/totalFieldVTK.png
doc/source/_static/figures/total_field_X_model1.png
+doc/source/_static/figures/total_field_X_model2.png
doc/source/_templates/layout.html
doc/source/examples/modelParams.rst
doc/source/examples/preprocessingParams.rst
@@ -338,11 +106,12 @@ doc/source/setup/version.rst~
examples/Example1.zip
examples/Example2.zip
examples/Example3.zip
+examples/Example4.zip
examples/modelParams.py
examples/petsc.opts
examples/preprocessingParams.py
-examples/__pycache__/modelParams.cpython-35.pyc
-examples/__pycache__/preprocessingParams.cpython-35.pyc
+examples/__pycache__/modelParams.cpython-36.pyc
+examples/__pycache__/preprocessingParams.cpython-36.pyc
petgem.egg-info/PKG-INFO
petgem.egg-info/SOURCES.txt
petgem.egg-info/dependency_links.txt
diff --git a/petgem.egg-info/dependency_links.txt b/petgem.egg-info/dependency_links.txt
old mode 100644
new mode 100755
diff --git a/petgem.egg-info/requires.txt b/petgem.egg-info/requires.txt
old mode 100644
new mode 100755
diff --git a/petgem.egg-info/top_level.txt b/petgem.egg-info/top_level.txt
old mode 100644
new mode 100755
diff --git a/petgem/base/__init__.py b/petgem/base/__init__.py
old mode 100644
new mode 100755
diff --git a/petgem/base/__pycache__/__init__.cpython-35.pyc b/petgem/base/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..add1d76
Binary files /dev/null and b/petgem/base/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/base/__pycache__/__init__.cpython-36.pyc b/petgem/base/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..591ae33
Binary files /dev/null and b/petgem/base/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/base/__pycache__/base.cpython-35.pyc b/petgem/base/__pycache__/base.cpython-35.pyc
new file mode 100755
index 0000000..3fb3b37
Binary files /dev/null and b/petgem/base/__pycache__/base.cpython-35.pyc differ
diff --git a/petgem/base/__pycache__/base.cpython-36.pyc b/petgem/base/__pycache__/base.cpython-36.pyc
new file mode 100644
index 0000000..281bb9e
Binary files /dev/null and b/petgem/base/__pycache__/base.cpython-36.pyc differ
diff --git a/petgem/base/__pycache__/modelling.cpython-35.pyc b/petgem/base/__pycache__/modelling.cpython-35.pyc
new file mode 100755
index 0000000..5a4439f
Binary files /dev/null and b/petgem/base/__pycache__/modelling.cpython-35.pyc differ
diff --git a/petgem/base/__pycache__/modelling.cpython-36.pyc b/petgem/base/__pycache__/modelling.cpython-36.pyc
new file mode 100644
index 0000000..c91ad7a
Binary files /dev/null and b/petgem/base/__pycache__/modelling.cpython-36.pyc differ
diff --git a/petgem/base/__pycache__/preprocessing.cpython-35.pyc b/petgem/base/__pycache__/preprocessing.cpython-35.pyc
new file mode 100755
index 0000000..1947483
Binary files /dev/null and b/petgem/base/__pycache__/preprocessing.cpython-35.pyc differ
diff --git a/petgem/base/__pycache__/styles.cpython-35.pyc b/petgem/base/__pycache__/styles.cpython-35.pyc
new file mode 100755
index 0000000..afd11e0
Binary files /dev/null and b/petgem/base/__pycache__/styles.cpython-35.pyc differ
diff --git a/petgem/base/__pycache__/styles.cpython-36.pyc b/petgem/base/__pycache__/styles.cpython-36.pyc
new file mode 100644
index 0000000..7885d5b
Binary files /dev/null and b/petgem/base/__pycache__/styles.cpython-36.pyc differ
diff --git a/petgem/base/base.py b/petgem/base/base.py
old mode 100644
new mode 100755
index 0878c8d..26dbc08
--- a/petgem/base/base.py
+++ b/petgem/base/base.py
@@ -107,6 +107,23 @@ def checkDictionaryConsistencyMaster(rank, in_dict, file_name, dir_name):
PETSc.Sys.Print(' Checking parameters consistency...')
+ # NEDELEC_ORDER parameter
+ msg = msg1 + 'NEDELEC_ORDER' + msg2
+ assert 'NEDELEC_ORDER' in in_dict, msg
+ msg = msg3 + 'NEDELEC_ORDER' + msg4
+ nedelec_order = in_dict['NEDELEC_ORDER']
+ assert type(nedelec_order) is int, msg
+ PETSc.Sys.Print(' checkDictionaryConsistency(): NEDELEC_ORDER ' +
+ 'consistency OK.')
+
+ # CUDA parameter
+ msg = msg1 + 'CUDA' + msg2
+ assert 'CUDA' in in_dict, msg
+ msg = msg3 + 'CUDA' + msg4
+ cuda = in_dict['CUDA']
+ assert type(cuda) is int, msg
+ PETSc.Sys.Print(' checkDictionaryConsistency(): CUDA consistency OK.')
+
# freq parameter
msg = msg1 + 'FREQ' + msg2
assert 'FREQ' in in_dict, msg
@@ -196,22 +213,40 @@ def checkDictionaryConsistencyMaster(rank, in_dict, file_name, dir_name):
PETSc.Sys.Print(' checkDictionaryConsistency(): MESH_CONNECTIVITY_FILE '
'consistency OK.')
+ # elemsF_file parameter
+ msg = msg1 + 'FACES_CONNECTIVITY_FILE' + msg2
+ assert 'FACES_CONNECTIVITY_FILE' in in_dict, msg
+ msg = msg3 + 'FACES_CONNECTIVITY_FILE' + msg4
+ elemsF_file = in_dict['FACES_CONNECTIVITY_FILE']
+ assert type(elemsF_file) is str, msg
+ PETSc.Sys.Print(' checkDictionaryConsistency(): FACES_CONNECTIVITY_FILE '
+ 'consistency OK.')
+
+ # facesN_file parameter
+ msg = msg1 + 'FACES_NODES_FILE' + msg2
+ assert 'FACES_NODES_FILE' in in_dict, msg
+ msg = msg3 + 'FACES_NODES_FILE' + msg4
+ facesN_file = in_dict['FACES_NODES_FILE']
+ assert type(facesN_file) is str, msg
+ PETSc.Sys.Print(' checkDictionaryConsistency(): FACES_NODES_FILE '
+ 'consistency OK.')
+
# elemsE_file parameter
- msg = msg1 + 'DOFS_CONNECTIVITY_FILE' + msg2
- assert 'DOFS_CONNECTIVITY_FILE' in in_dict, msg
- msg = msg3 + 'DOFS_CONNECTIVITY_FILE' + msg4
- elemsE_file = in_dict['DOFS_CONNECTIVITY_FILE']
+ msg = msg1 + 'EDGES_CONNECTIVITY_FILE' + msg2
+ assert 'EDGES_CONNECTIVITY_FILE' in in_dict, msg
+ msg = msg3 + 'EDGES_CONNECTIVITY_FILE' + msg4
+ elemsE_file = in_dict['EDGES_CONNECTIVITY_FILE']
assert type(elemsE_file) is str, msg
- PETSc.Sys.Print(' checkDictionaryConsistency(): DOFS_CONNECTIVITY_FILE '
+ PETSc.Sys.Print(' checkDictionaryConsistency(): EDGES_CONNECTIVITY_FILE '
'consistency OK.')
# edgesN_file parameter
- msg = msg1 + 'DOFS_NODES_FILE' + msg2
- assert 'DOFS_NODES_FILE' in in_dict, msg
- msg = msg3 + 'DOFS_NODES_FILE' + msg4
- edgesN_file = in_dict['DOFS_NODES_FILE']
+ msg = msg1 + 'EDGES_NODES_FILE' + msg2
+ assert 'EDGES_NODES_FILE' in in_dict, msg
+ msg = msg3 + 'EDGES_NODES_FILE' + msg4
+ edgesN_file = in_dict['EDGES_NODES_FILE']
assert type(edgesN_file) is str, msg
- PETSc.Sys.Print(' checkDictionaryConsistency(): DOFS_NODES_FILE '
+ PETSc.Sys.Print(' checkDictionaryConsistency(): EDGES_NODES_FILE '
'consistency OK.')
# nnz_file parameter
@@ -222,12 +257,12 @@ def checkDictionaryConsistencyMaster(rank, in_dict, file_name, dir_name):
assert type(nnz_file) is str, msg
PETSc.Sys.Print(' checkDictionaryConsistency(): NNZ_FILE consistency OK.')
- # bEedges_file parameter
+ # boundaries_file parameter
msg = msg1 + 'BOUNDARIES_FILE' + msg2
assert 'BOUNDARIES_FILE' in in_dict, msg
msg = msg3 + 'BOUNDARIES_FILE' + msg4
- bEdges_file = in_dict['BOUNDARIES_FILE']
- assert type(bEdges_file) is str, msg
+ boundaries_file = in_dict['BOUNDARIES_FILE']
+ assert type(boundaries_file) is str, msg
PETSc.Sys.Print(' checkDictionaryConsistency(): BOUNDARIES_FILE '
'consistency OK.')
@@ -277,6 +312,26 @@ def checkDictionaryConsistencyMaster(rank, in_dict, file_name, dir_name):
' does not exist.')
raise ValueError(msg)
+ # check elemsF_file path
+ success = checkFilePath(elemsF_file)
+ if success:
+ PETSc.Sys.Print(' checkDictionaryConsistency(): "' + elemsF_file +
+ '" exists.')
+ else:
+ msg = (' checkDictionaryConsistency(): file ' + elemsF_file +
+ ' does not exist.')
+ raise ValueError(msg)
+
+ # check facesN_file path
+ success = checkFilePath(facesN_file)
+ if success:
+ PETSc.Sys.Print(' checkDictionaryConsistency(): "' + facesN_file +
+ '" exists.')
+ else:
+ msg = (' checkDictionaryConsistency(): file ' + facesN_file +
+ ' does not exist.')
+ raise ValueError(msg)
+
# check elemsE_file path
success = checkFilePath(elemsE_file)
if success:
@@ -297,6 +352,16 @@ def checkDictionaryConsistencyMaster(rank, in_dict, file_name, dir_name):
' does not exist.')
raise ValueError(msg)
+ # check boundaries_file path
+ success = checkFilePath(boundaries_file)
+ if success:
+ PETSc.Sys.Print(' checkDictionaryConsistency(): "' +
+ boundaries_file + '" exists.')
+ else:
+ msg = (' checkDictionaryConsistency(): file ' + boundaries_file +
+ ' does not exist.')
+ raise ValueError(msg)
+
# check receivers_file path
success = checkFilePath(receivers_file)
if success:
@@ -312,11 +377,12 @@ def checkDictionaryConsistencyMaster(rank, in_dict, file_name, dir_name):
file_name + '" are consistent.')
# Create csem_modelling dictionary
- out_model = CSEM_MODELLING(rank, freq, src_pos, src_direc, src_current,
- src_length, sigma_background, sigma_file,
- nodes_file, elemsN_file, elemsE_file,
- edgesN_file, nnz_file, bEdges_file,
- receivers_file, dir_name)
+ out_model = CSEM_MODELLING(rank, nedelec_order, cuda, freq, src_pos,
+ src_direc, src_current, src_length,
+ sigma_background, sigma_file, nodes_file,
+ elemsN_file, elemsF_file, facesN_file,
+ elemsE_file, edgesN_file, nnz_file,
+ boundaries_file, receivers_file, dir_name)
PETSc.Sys.Print(' A new CSEM_MODELLING dictionary has been '
'successfully created.')
@@ -335,6 +401,14 @@ def checkDictionaryConsistencySlave(rank, in_dict, file_name, dir_name):
:return: csem modelling dictionary after test.
:rtype: csem_modelling dictionary.
'''
+ # nedelec_order parameter
+ nedelec_order = in_dict['NEDELEC_ORDER']
+ nedelec_order = np.int(nedelec_order)
+
+ # cuda parameter
+ cuda = in_dict['CUDA']
+ cuda = np.int(cuda)
+
# freq parameter
freq = in_dict['FREQ']
freq = np.float(in_dict['FREQ'])
@@ -344,7 +418,7 @@ def checkDictionaryConsistencySlave(rank, in_dict, file_name, dir_name):
# src_direc parameter
src_direc = in_dict['SRC_DIREC']
- src_direc = int(src_direc)
+ src_direc = np.int(src_direc)
# src_current parameter
src_current = in_dict['SRC_CURRENT']
@@ -367,27 +441,34 @@ def checkDictionaryConsistencySlave(rank, in_dict, file_name, dir_name):
# elemsN_file parameter
elemsN_file = in_dict['MESH_CONNECTIVITY_FILE']
+ # elemsF_file parameter
+ elemsF_file = in_dict['FACES_CONNECTIVITY_FILE']
+
+ # facesN_file parameter
+ facesN_file = in_dict['FACES_NODES_FILE']
+
# elemsE_file parameter
- elemsE_file = in_dict['DOFS_CONNECTIVITY_FILE']
+ elemsE_file = in_dict['EDGES_CONNECTIVITY_FILE']
# edgesN_file parameter
- edgesN_file = in_dict['DOFS_NODES_FILE']
+ edgesN_file = in_dict['EDGES_NODES_FILE']
# nnz_file parameter
nnz_file = in_dict['NNZ_FILE']
# edgesN_file parameter
- bEdges_file = in_dict['BOUNDARIES_FILE']
+ boundaries_file = in_dict['BOUNDARIES_FILE']
# receivers_file parameter
receivers_file = in_dict['RECEIVERS_FILE']
# Create csem_modelling dictionary
- out_model = CSEM_MODELLING(rank, freq, src_pos, src_direc, src_current,
- src_length, sigma_background, sigma_file,
- nodes_file, elemsN_file, elemsE_file,
- edgesN_file, nnz_file, bEdges_file,
- receivers_file, dir_name)
+ out_model = CSEM_MODELLING(rank, nedelec_order, cuda, freq, src_pos,
+ src_direc, src_current, src_length,
+ sigma_background, sigma_file, nodes_file,
+ elemsN_file, elemsF_file, facesN_file,
+ elemsE_file, edgesN_file, nnz_file,
+ boundaries_file, receivers_file, dir_name)
return out_model
diff --git a/petgem/base/modelling.py b/petgem/base/modelling.py
old mode 100644
new mode 100755
index 9cc9856..5070168
--- a/petgem/base/modelling.py
+++ b/petgem/base/modelling.py
@@ -7,13 +7,16 @@
'''
-def CSEM_MODELLING(rank, freq, src_pos, src_direc, src_current,
- src_length, sigma_background, sigma_file,
- nodes_file, elemsN_file, elemsE_file, edgesN_file,
- nnz_file, bEdges_file, receivers_file, dir_name):
+def CSEM_MODELLING(rank, nedelec_order, cuda, freq, src_pos, src_direc,
+ src_current, src_length, sigma_background, sigma_file,
+ nodes_file, elemsN_file, elemsF_file, facesN_file,
+ elemsE_file, edgesN_file, nnz_file, boundaries_file,
+ receivers_file, dir_name):
''' csem_modelling dictionary with main parameters for CSEM FM.
:param int rank: MPI rank.
+ :param int nedelec_order: nedelec element order.
+ :param int cuda: flag for cuda support.
:param int,float freq: frequency.
:param list src_pos: source position.
:param int,float src_dir: source orientation.
@@ -23,10 +26,12 @@ def CSEM_MODELLING(rank, freq, src_pos, src_direc, src_current,
:param str sigma_file: file name of conductivity model.
:param str nodes_file: file name of node spatial coordinates.
:param str elemsN_file: file name of elements-nodes connectivity.
+ :param str elemsF_file: file name of elements-faces connectivity.
+ :param str facesN_file: file name of faces-nodes connectivity.
:param str elemsE_file: file name of elements-edges connectivity.
:param str edgesN_file: file name of edges-nodes connectivity.
:param str nnz_file: file name of nnz for matrix allocation.
- :param str bEdges_file: file name of boundary edges.
+ :param str boundaries_file: file name of boundary edges.
:param str receivers_file: file name or receivers position.
:param str dir_name: parent directory of sigma_file, nodes_file
and elemsN_file.
@@ -38,7 +43,9 @@ def CSEM_MODELLING(rank, freq, src_pos, src_direc, src_current,
PETSc.Sys.Print(' CSEM_MODELLING(): Creating a '
'CSEM_MODELLING dictionary.')
- modelling = {'FREQ': freq,
+ modelling = {'NEDELEC_ORDER': nedelec_order,
+ 'CUDA': cuda,
+ 'FREQ': freq,
'SRC_POS': src_pos,
'SRC_DIREC': src_direc,
'SRC_CURRENT': src_current,
@@ -47,10 +54,12 @@ def CSEM_MODELLING(rank, freq, src_pos, src_direc, src_current,
'CONDUCTIVITY_MODEL_FILE': sigma_file,
'NODES_FILE': nodes_file,
'MESH_CONNECTIVITY_FILE': elemsN_file,
- 'DOFS_CONNECTIVITY_FILE': elemsE_file,
- 'DOFS_NODES_FILE': edgesN_file,
+ 'FACES_CONNECTIVITY_FILE': elemsF_file,
+ 'FACES_NODES_FILE': facesN_file,
+ 'EDGES_CONNECTIVITY_FILE': elemsE_file,
+ 'EDGES_NODES_FILE': edgesN_file,
'NNZ_FILE': nnz_file,
- 'BOUNDARIES_FILE': bEdges_file,
+ 'BOUNDARIES_FILE': boundaries_file,
'RECEIVERS_FILE': receivers_file,
'DIR_NAME': dir_name}
@@ -63,39 +72,50 @@ def printModellingData(input_modelling):
:return: None.
'''
- A = str(input_modelling['FREQ'])
- B = str(input_modelling['SRC_POS'])
- C = str(input_modelling['SRC_DIREC'])
- D = str(input_modelling['SRC_CURRENT'])
- E = str(input_modelling['SRC_LENGTH'])
- F = str(input_modelling['CONDUCTIVITY_BACKGROUND'])
- G = input_modelling['CONDUCTIVITY_MODEL_FILE']
- H = input_modelling['NODES_FILE']
- I = input_modelling['MESH_CONNECTIVITY_FILE']
- J = input_modelling['DOFS_CONNECTIVITY_FILE']
- K = input_modelling['DOFS_NODES_FILE']
- L = input_modelling['NNZ_FILE']
- M = input_modelling['BOUNDARIES_FILE']
- N = input_modelling['RECEIVERS_FILE']
- O = input_modelling['DIR_NAME']
+ A = str(input_modelling['NEDELEC_ORDER'])
+ if input_modelling['CUDA'] == 0:
+ B = str('0 (No)')
+ else:
+ B = str('1 (Yes)')
+ C = str(input_modelling['FREQ'])
+ D = str(input_modelling['SRC_POS'])
+ E = str(input_modelling['SRC_DIREC'])
+ F = str(input_modelling['SRC_CURRENT'])
+ G = str(input_modelling['SRC_LENGTH'])
+ H = str(input_modelling['CONDUCTIVITY_BACKGROUND'])
+ II = input_modelling['CONDUCTIVITY_MODEL_FILE']
+ J = input_modelling['NODES_FILE']
+ K = input_modelling['MESH_CONNECTIVITY_FILE']
+ L = input_modelling['FACES_CONNECTIVITY_FILE']
+ M = input_modelling['FACES_NODES_FILE']
+ N = input_modelling['EDGES_CONNECTIVITY_FILE']
+ OO = input_modelling['EDGES_NODES_FILE']
+ P = input_modelling['NNZ_FILE']
+ Q = input_modelling['BOUNDARIES_FILE']
+ R = input_modelling['RECEIVERS_FILE']
+ S = input_modelling['DIR_NAME']
PETSc.Sys.Print('\nData for CSEM_MODELLING')
PETSc.Sys.Print('='*75)
- PETSc.Sys.Print(' Frequency: {0:50}'.format(A))
- PETSc.Sys.Print(' Source position: {0:50}'.format(B))
- PETSc.Sys.Print(' Source orientation: {0:50}'.format(C))
- PETSc.Sys.Print(' Source current: {0:50}'.format(D))
- PETSc.Sys.Print(' Source length: {0:50}'.format(E))
- PETSc.Sys.Print(' Sigma background: {0:50}'.format(F))
- PETSc.Sys.Print(' Sigma file: {0:50}'.format(G))
- PETSc.Sys.Print(' Nodes file: {0:50}'.format(H))
- PETSc.Sys.Print(' Elements-nodes file: {0:50}'.format(I))
- PETSc.Sys.Print(' Elements-edges file: {0:50}'.format(J))
- PETSc.Sys.Print(' Edges-nodes file: {0:50}'.format(K))
- PETSc.Sys.Print(' nnz file: {0:50}'.format(L))
- PETSc.Sys.Print(' Boundary edges file: {0:50}'.format(M))
- PETSc.Sys.Print(' Receivers file: {0:50}'.format(N))
- PETSc.Sys.Print(' Parent directory: {0:50}'.format(O))
+ PETSc.Sys.Print(' Nedelec order: {0:50}'.format(A))
+ PETSc.Sys.Print(' CUDA support: {0:50}'.format(B))
+ PETSc.Sys.Print(' Frequency: {0:50}'.format(C))
+ PETSc.Sys.Print(' Source position: {0:50}'.format(D))
+ PETSc.Sys.Print(' Source orientation: {0:50}'.format(E))
+ PETSc.Sys.Print(' Source current: {0:50}'.format(F))
+ PETSc.Sys.Print(' Source length: {0:50}'.format(G))
+ PETSc.Sys.Print(' Sigma background: {0:50}'.format(H))
+ PETSc.Sys.Print(' Sigma file: {0:50}'.format(II))
+ PETSc.Sys.Print(' Nodes file: {0:50}'.format(J))
+ PETSc.Sys.Print(' Elements-nodes file: {0:50}'.format(K))
+ PETSc.Sys.Print(' Elements-faces file: {0:50}'.format(L))
+ PETSc.Sys.Print(' Faces-nodes file: {0:50}'.format(M))
+ PETSc.Sys.Print(' Elements-edges file: {0:50}'.format(N))
+ PETSc.Sys.Print(' Edges-nodes file: {0:50}'.format(OO))
+ PETSc.Sys.Print(' nnz file: {0:50}'.format(P))
+ PETSc.Sys.Print(' Boundaries file: {0:50}'.format(Q))
+ PETSc.Sys.Print(' Receivers file: {0:50}'.format(R))
+ PETSc.Sys.Print(' Parent directory: {0:50}'.format(S))
return
@@ -103,22 +123,23 @@ def printModellingData(input_modelling):
def unitary_test():
''' Unitary test for modelling.py script.
'''
- from styles import (petgemHeader, test_header,
- petgemFooter, test_footer)
+ from styles import (printPetgemHeader, test_header,
+ printPetgemFooter, test_footer)
- printPetgemHeader()
+ rank = 0 # MASTER
+ printPetgemHeader(rank)
test_header('modelling.py')
PETSc.Sys.Print('Testing csem_modelling creation.')
PETSc.Sys.Print('Creating modelling...')
- # sample data: [rank, freq, src_pos, src_direc, src_current,
- # src_length, sigma_background, sigma_file,
+ # sample data: [rank, nedelec_order, cuda, freq, src_pos, src_direc,
+ # src_current, src_length, sigma_background, sigma_file,
# nodes_file, elemsN_file, elemsE_file, edgesN_file,
- # bEdges_file, receivers_file, out_prefix, dir_name)
- sample_data = [0, 1.0, [100, 100, 100], 1, 2.5, 2.5,
+ # boundaries_file, receivers_file, out_prefix, dir_name)
+ sample_data = [0, 2, 1, 1.0, [100, 100, 100], 1, 2.5, 2.5,
3.3, 'sigma_file.data', 'nodes_file.data',
- 'elemsN_file.data', 'elemsE_file.data', 'edgesN_file.data',
- 'nnz_file', 'bEdges_file.dat', 'receivers.data',
- 'parent/path']
+ 'elemsN_file.data', 'elemsF_file.data', 'facesN_file.data',
+ 'elemsE_file.data', 'edgesN_file.data', 'nnz_file',
+ 'boundaries_file.dat', 'receivers.data', 'parent/path']
sample_csem = CSEM_MODELLING(*sample_data)
@@ -127,7 +148,7 @@ def unitary_test():
pass_test = True
test_footer(pass_test)
- printPetgemFooter()
+ printPetgemFooter(rank)
if __name__ == '__main__':
diff --git a/petgem/base/styles.py b/petgem/base/styles.py
old mode 100644
new mode 100755
diff --git a/petgem/efem/__init__.py b/petgem/efem/__init__.py
old mode 100644
new mode 100755
index 47b2a45..fa85256
--- a/petgem/efem/__init__.py
+++ b/petgem/efem/__init__.py
@@ -1,11 +1,29 @@
from .efem import unitary_test
from .efem import defineEFEMConstants
from .efem import nedelecBasisIterative
-from .efem import computeDofs
+from .efem import computeEdges
from .efem import computeFaces
from .efem import computeBoundaryFaces
-from .efem import computeBoundaryDofs
+from .efem import computeBoundaryEdges
+from .efem import computeBoundaries
+from .efem import computeElementDOFs
+from .efem import edgeFaceVerticesInit
+from .efem import computeSignsJacobLegth
+from .efem import definitionHighOrderTet
+from .efem import computeCoefficientsSecondOrder
+from .efem import nedelecBasisSecondOrder
+from .efem import computeMassMatrixSecondOrder
+from .efem import computeStiffnessMatrixSecondOrder
+from .efem import computeCoefficientsThirdOrder
+from .efem import nedelecBasisThirdOrder
+from .efem import computeMassMatrixThirdOrder
+from .efem import computeStiffnessMatrixThirdOrder
from .fem import tetraXiEtaZeta2XYZ
from .fem import gauss_points_tetrahedron
+from .fem import gauss_points_reference_tetrahedron
+from .fem import volumetricToCartesianCoordinates
+from .fem import cartesianToVolumetricCoordinates
from .vectorMatrixFunctions import deleteDuplicateRows
from .vectorMatrixFunctions import findUniqueRows
+from .vectorMatrixFunctions import crossprod
+from .vectorMatrixFunctions import is_duplicate_entry
diff --git a/petgem/efem/__pycache__/__init__.cpython-35.pyc b/petgem/efem/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..8bdfd20
Binary files /dev/null and b/petgem/efem/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/efem/__pycache__/__init__.cpython-36.pyc b/petgem/efem/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..afa3529
Binary files /dev/null and b/petgem/efem/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/efem/__pycache__/efem.cpython-35.pyc b/petgem/efem/__pycache__/efem.cpython-35.pyc
new file mode 100755
index 0000000..7565b06
Binary files /dev/null and b/petgem/efem/__pycache__/efem.cpython-35.pyc differ
diff --git a/petgem/efem/__pycache__/efem.cpython-36.pyc b/petgem/efem/__pycache__/efem.cpython-36.pyc
new file mode 100644
index 0000000..ff73d2a
Binary files /dev/null and b/petgem/efem/__pycache__/efem.cpython-36.pyc differ
diff --git a/petgem/efem/__pycache__/fem.cpython-35.pyc b/petgem/efem/__pycache__/fem.cpython-35.pyc
new file mode 100755
index 0000000..a3e9aef
Binary files /dev/null and b/petgem/efem/__pycache__/fem.cpython-35.pyc differ
diff --git a/petgem/efem/__pycache__/fem.cpython-36.pyc b/petgem/efem/__pycache__/fem.cpython-36.pyc
new file mode 100644
index 0000000..29c75cd
Binary files /dev/null and b/petgem/efem/__pycache__/fem.cpython-36.pyc differ
diff --git a/petgem/efem/__pycache__/vectorMatrixFunctions.cpython-35.pyc b/petgem/efem/__pycache__/vectorMatrixFunctions.cpython-35.pyc
new file mode 100755
index 0000000..818cccb
Binary files /dev/null and b/petgem/efem/__pycache__/vectorMatrixFunctions.cpython-35.pyc differ
diff --git a/petgem/efem/__pycache__/vectorMatrixFunctions.cpython-36.pyc b/petgem/efem/__pycache__/vectorMatrixFunctions.cpython-36.pyc
new file mode 100644
index 0000000..cdfe1fa
Binary files /dev/null and b/petgem/efem/__pycache__/vectorMatrixFunctions.cpython-36.pyc differ
diff --git a/petgem/efem/efem.py b/petgem/efem/efem.py
old mode 100644
new mode 100755
index f8bcdd8..85f8871
--- a/petgem/efem/efem.py
+++ b/petgem/efem/efem.py
@@ -7,23 +7,40 @@
'''
-def computeDofs(elemsN, nElems):
- ''' Compute degrees of freedom (DOF) of a 3D tetrahedral mesh. Here, dofs
- are defined for edge finite element computations.
+def computeEdges(elemsN, nElems, nedelec_order):
+ ''' Compute edges of a 3D tetrahedral mesh. For edge finite element of linear
+ order the edges are the dofs. For edge finite element of second order
+ the dofs are computed in runtime based on edges and faces on each
+ tetrahedral element.
:param ndarray elemsN: elements-nodes connectivity.
:param int nElems: number of tetrahedral elements in the mesh.
- :return: dof connectivity and dofsNodes connectivity.
+ :param int nedelec_order: nedelec element order.
+ :return: edges connectivity and edgesNodes connectivity.
:rtype: ndarray
'''
- # Extracts sets of edges
- edges1 = elemsN[:, [0, 1]]
- edges2 = elemsN[:, [0, 2]]
- edges3 = elemsN[:, [0, 3]]
- edges4 = elemsN[:, [1, 2]]
- edges5 = elemsN[:, [3, 1]]
- edges6 = elemsN[:, [2, 3]]
+ # First order edge element
+ if nedelec_order == 1:
+ # Extracts sets of edges
+ edges1 = elemsN[:, [0, 1]]
+ edges2 = elemsN[:, [0, 2]]
+ edges3 = elemsN[:, [0, 3]]
+ edges4 = elemsN[:, [1, 2]]
+ edges5 = elemsN[:, [3, 1]]
+ edges6 = elemsN[:, [2, 3]]
+ # Second and third order edge element
+ elif nedelec_order == 2 or nedelec_order == 3:
+ # Extracts sets of edges
+ edges1 = elemsN[:, [0, 1]]
+ edges2 = elemsN[:, [1, 2]]
+ edges3 = elemsN[:, [2, 0]]
+ edges4 = elemsN[:, [0, 3]]
+ edges5 = elemsN[:, [1, 3]]
+ edges6 = elemsN[:, [2, 3]]
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
# Edges as sets of their nodes (vertices)
vertices = np.zeros([nElems*6, 2])
@@ -35,22 +52,24 @@ def computeDofs(elemsN, nElems):
vertices[5::6] = edges6
# Delete duplicate rows
- [dofsNodes, dofs] = deleteDuplicateRows(vertices)
+ [edgesNodes, edges] = deleteDuplicateRows(vertices)
# Build dofs matrix
- dofs = np.array(np.reshape(dofs, (nElems, 6)), dtype=np.int)
+ edges = np.array(np.reshape(edges, (nElems, 6)), dtype=np.int)
# Build dofs to nodes connectivity
- dofsNodes.sort(axis=1)
- dofsNodes = np.array(dofsNodes, dtype=np.int)
+ edgesNodes.sort(axis=1)
+ edgesNodes = np.array(edgesNodes, dtype=np.int)
- return dofs, dofsNodes
+ return edges, edgesNodes
-def computeFaces(elemsN, nElems):
+def computeFaces(elemsN, nElems, nedelec_order):
''' Compute the element\'s faces of a 3D tetrahedral mesh.
:param ndarray matrix: elements-nodes connectivity.
+ :param int nElems: number of elements in the mesh.
+ :param int nedelec_order: nedelec element order.
:return: element/faces connectivity.
:rtype: ndarray
@@ -60,11 +79,21 @@ def computeFaces(elemsN, nElems):
SIAM Journal on Scientific Computing 31.6 (2009): 4130-4151.
'''
- # Extracts sets of faces
- faces1 = elemsN[:, [0, 2, 1]]
- faces2 = elemsN[:, [0, 1, 3]]
- faces3 = elemsN[:, [0, 3, 2]]
- faces4 = elemsN[:, [1, 2, 3]]
+ # Extracts sets of faces for each nedelec element order
+ if nedelec_order == 1: # First order edge element
+ faces1 = elemsN[:, [0, 2, 1]]
+ faces2 = elemsN[:, [0, 1, 3]]
+ faces3 = elemsN[:, [0, 3, 2]]
+ faces4 = elemsN[:, [1, 2, 3]]
+ elif nedelec_order == 2 or nedelec_order == 3: # Second and third order
+ # edge element
+ faces1 = elemsN[:, [0, 1, 2]]
+ faces2 = elemsN[:, [0, 2, 3]]
+ faces3 = elemsN[:, [0, 3, 1]]
+ faces4 = elemsN[:, [3, 1, 2]]
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
# Faces as sets of their nodes (vertices)
vertices = np.zeros([nElems*4, 3])
@@ -88,7 +117,7 @@ def computeBoundaryFaces(elemsF, facesN):
:param ndarray elemsF: elements-face connectivity.
:param ndarray facesN: faces-nodes connectivity.
- :return: boundary-faces connectivity.
+ :return: nodal-connectivity and indexes of boundary-faces.
:rtype: ndarray
'''
@@ -145,16 +174,22 @@ def computeBoundaryFaces(elemsF, facesN):
# related to only one single tetra, which means it is on the
# boundary of the domain. Since faces are defined by their nodes,
# we have the boundary nodes too.
- tmp = (E[:, 1] == 0)
- ind = np.where(tmp)[False]
-
+ # Get boundary faces to nodes
+ ind = (E[:, 1] == 0)
bfacesN = np.array(np.transpose(facesN[ind, :]), dtype=np.int)
- return bfacesN
+ # Get indexes of boundary faces
+ ind = np.where(ind == True)
+ bFaces = np.array(np.transpose(ind), dtype=np.int)
+ size = bFaces.shape
+ nBoundaryFaces = size[0]
+ bFaces = bFaces.reshape((nBoundaryFaces))
+ return bfacesN, bFaces
-def computeBoundaryDofs(edgesN, bfacesN):
- ''' Compute boundary dofs of a tetrahedral mesh.
+
+def computeBoundaryEdges(edgesN, bfacesN):
+ ''' Compute boundary edges of a tetrahedral mesh.
:param ndarray edgesN: edges-nodes connectivity.
:param ndarray bfacesN: boundary-faces-nodes connectivity.
@@ -209,17 +244,157 @@ def computeBoundaryDofs(edgesN, bfacesN):
return bEdges
-def defineEFEMConstants():
+def computeBoundaries(elemsN, nElems, edgesNodes, nedelec_order):
+ ''' Compute boundaries of the domain for edge finite element computations.
+
+ :param ndarray elemsN: elements-nodes connectivity.
+ :param int nElems: number of elements in the mesh.
+ :param ndarray edgesN: edges-nodes connectivity.
+ :param int nedelec_order: nedelec element order.
+ :return: boundaries, ndofs
+ :rtype: ndarray
+ '''
+
+ # Compute faces
+ elemsF, facesN = computeFaces(elemsN, nElems, nedelec_order)
+
+ # Compute boundary faces
+ boundaryFacesN, boundaryFaces = computeBoundaryFaces(elemsF, facesN)
+
+ # Compute boundary edges
+ boundaryEdges = computeBoundaryEdges(edgesNodes, boundaryFacesN)
+
+ # Number of edges
+ size = edgesNodes.shape
+ nEdges = size[0]
+
+ # Number of faces
+ size = facesN.shape
+ nFaces = size[0]
+
+ # Number of boundary edges
+ size = boundaryEdges.shape
+ nBoundaryEdges = size[1]
+
+ # Number of boundary faces
+ size = boundaryFaces.shape
+ nBoundaryFaces = size[0]
+
+ # Compute boundaries
+ if nedelec_order == 1: # First order edge element
+ # Boundaries correspond to boundary edges
+ boundaries = boundaryEdges
+ # Number of DOFs correspond to edges in the mesh
+ size = edgesNodes.shape
+ ndofs = size[0]
+
+ elif nedelec_order == 2: # Second order edge element
+ # Number of DOFS
+ ndofs = nEdges*2 + nFaces*2
+
+ # Total number of boundaries
+ nBoundaries = nBoundaryEdges*2 + nBoundaryFaces*2
+
+ # Allocate
+ boundaries = np.zeros((nBoundaries), dtype=np.int)
+ newEdgesNumb = np.zeros((nBoundaryEdges, 2), dtype=np.int)
+ newFacesNumb = np.zeros((nBoundaryFaces, 2), dtype=np.int)
+
+ # Compute boundaries on edges
+ # Use 1-based indexing in boundaryEdges and boundaryFaces
+ boundaryEdges += np.int(1)
+ boundaryFaces += np.int(1)
+
+ # Get boundaries on edges
+ newEdgesNumb[:, 0] = (boundaryEdges*2)-1
+ newEdgesNumb[:, 1] = boundaryEdges*2
+ newEdgesNumb = newEdgesNumb.reshape((nBoundaryEdges*2), order='F')
+
+ # Insert edge boundary indexes in boundary array
+ boundaries[0:nBoundaryEdges*2] = newEdgesNumb
+
+ # Get boundaries on faces
+ newFacesNumb[:, 0] = (boundaryFaces*2+nEdges*2)-1
+ newFacesNumb[:, 1] = boundaryFaces*2+nEdges*2
+ newFacesNumb = newFacesNumb.reshape((nBoundaryFaces*2), order='F')
+
+ # Insert face boundary indexes in boundary array
+ boundaries[nBoundaryEdges*2:] = newFacesNumb
+
+ # Use 0-based indexing in boundaries
+ boundaries -= np.int(1)
+
+ elif nedelec_order == 3: # Third order edge element
+ # Number of DOFS
+ ndofs = nEdges*3 + nFaces*6 + nElems*3
+
+ # Total number of boundaries
+ nBoundaries = nBoundaryEdges*3 + nBoundaryFaces*6
+
+ # Allocate
+ boundaries = np.zeros((nBoundaries), dtype=np.int)
+ newEdgesNumb = np.zeros((nBoundaryEdges, 3), dtype=np.int)
+ newFacesNumb = np.zeros((nBoundaryFaces, 6), dtype=np.int)
+
+ # Compute boundaries on edges
+ # Use 1-based indexing in boundaryEdges and boundaryFaces
+ boundaryEdges += np.int(1)
+ boundaryFaces += np.int(1)
+
+ # Get boundaries on edges
+ newEdgesNumb[:, 0] = (boundaryEdges*3)-2
+ newEdgesNumb[:, 1] = (boundaryEdges*3)-1
+ newEdgesNumb[:, 2] = boundaryEdges*3
+ newEdgesNumb = newEdgesNumb.reshape((nBoundaryEdges*3), order='F')
+
+ # Insert edge boundary indexes in boundary array
+ boundaries[0:nBoundaryEdges*3] = newEdgesNumb
+
+ # Get boundaries on faces
+ newFacesNumb[:, 0] = (boundaryFaces*6+nEdges*3)-5
+ newFacesNumb[:, 1] = (boundaryFaces*6+nEdges*3)-4
+ newFacesNumb[:, 2] = (boundaryFaces*6+nEdges*3)-3
+ newFacesNumb[:, 3] = (boundaryFaces*6+nEdges*3)-2
+ newFacesNumb[:, 4] = (boundaryFaces*6+nEdges*3)-1
+ newFacesNumb[:, 5] = boundaryFaces*6+nEdges*3
+ newFacesNumb = newFacesNumb.reshape((nBoundaryFaces*6), order='F')
+
+ # Insert face boundary indexes in boundary array
+ boundaries[nBoundaryEdges*3:] = newFacesNumb
+
+ # Use 0-based indexing in boundaries
+ boundaries -= np.int(1)
+
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
+ return boundaries, ndofs
+
+
+def defineEFEMConstants(nedelec_order):
''' Set constants for edge finite element computations, namely,
- order linear edge finite elements (edgeOrder), order linear nodal finite
+ order of edge finite elements (edgeOrder), order of nodal finite
elements (nodalOrder) and number of dimensions (numDimensions).
- :param: None.
+ :param int nedelec_order: nedelec element order.
:return: edgeOrder, nodalOrder and numDimensions.
:rtype: integer.
'''
- # Set order of linear edge finite elements
- edgeOrder = 6
+ # Set order of edge finite elements
+ if nedelec_order == 1: # First order edge element
+ # Nedelec order
+ edgeOrder = 6
+ elif nedelec_order == 2: # Second order edge element
+ # Nedelec order
+ edgeOrder = 20
+ elif nedelec_order == 3: # Third order edge element
+ # Nedelec order
+ edgeOrder = 45
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
# Set order of linear nodal finite lements
nodalOrder = 4
# Set number of dimensions
@@ -245,13 +420,13 @@ def nedelecBasisIterative(eleNodes, points, eleVol, lengthEdges, edgeOrder):
John Wiley & Sons, 2002.
'''
# Coefficients computation. Running in a cycling way
- a = np.zeros([4], dtype=np.float64)
- b = np.zeros([4], dtype=np.float64)
- c = np.zeros([4], dtype=np.float64)
- d = np.zeros([4], dtype=np.float64)
+ a = np.zeros([4], dtype=np.float)
+ b = np.zeros([4], dtype=np.float)
+ c = np.zeros([4], dtype=np.float)
+ d = np.zeros([4], dtype=np.float)
tmp = np.array([0, 1, 2, 3, 0, 1, 2], dtype=np.int)
- temp_ones = np.ones([3], dtype=np.float64)
+ temp_ones = np.ones([3], dtype=np.float)
for iCoeff in np.arange(4):
a[iCoeff] = det([[eleNodes[tmp[iCoeff+1], 0],
@@ -286,7 +461,7 @@ def nedelecBasisIterative(eleNodes, points, eleVol, lengthEdges, edgeOrder):
eleNodes[tmp[iCoeff+3], 1]]])
# Add signs
- sign = np.float64(-1.0)
+ sign = np.float(-1.0)
a[1] = a[1] * sign
a[3] = a[3] * sign
b[0] = b[0] * sign
@@ -304,7 +479,7 @@ def nedelecBasisIterative(eleNodes, points, eleVol, lengthEdges, edgeOrder):
# Nedelec basis for all points
if nPoints == 1:
- AA = np.float64(1.0) / ((np.float64(6.0)*eleVol)**2)
+ AA = np.float(1.0) / ((np.float(6.0)*eleVol)**2)
# To reduce number of multiplications
b1x = b[0]*points[0]
b2x = b[1]*points[0]
@@ -348,11 +523,11 @@ def nedelecBasisIterative(eleNodes, points, eleVol, lengthEdges, edgeOrder):
d[3]*A3-d[2]*A4], lengthEdges[5])
basis = np.array(np.vstack((b1, b2, b3, b4, b5, b6)) * AA,
- dtype=np.float64)
+ dtype=np.float)
# If not
else:
- basis = np.zeros((edgeOrder, 3, nPoints), dtype=np.float64)
- AA = np.float64(1.0) / ((np.float64(6.0)*eleVol)**2)
+ basis = np.zeros((edgeOrder, 3, nPoints), dtype=np.float)
+ AA = np.float(1.0) / ((np.float(6.0)*eleVol)**2)
# Compute basis for each point
for iP in np.arange(nPoints):
# To reduce number of multiplications
@@ -402,16 +577,3100 @@ def nedelecBasisIterative(eleNodes, points, eleVol, lengthEdges, edgeOrder):
return basis
+def computeElementDOFs(iEle, nodesEle, edgesEle, facesEle, nodesFace,
+ nEdges, nFaces, nedelec_order):
+ ''' Compute global DOFs for tetrahedral element.
+
+ :param int iEle: id of the tetrahedral element-th.
+ :param ndarray nodesEle: array with nodal indexes of element.
+ :param ndarray edgesEle: array with edge indexes of element.
+ :param ndarray facesEle: array with face indexes of element.
+ :param ndarray nodesFace: array with node indexes of faces.
+ :param ndarray nEdges: total number of edges in the mesh.
+ :param ndarray nFaces: total number of faces in the mesh.
+ :param int nedelec_order: nedelec element order.
+ :return: DOFs indexes.
+ :rtype: ndarray
+ '''
+ if nedelec_order == 1: # First order edge element
+ # DOFs correspond to element's edges in the mesh (6 DOFs)
+ dofsEle = edgesEle
+
+ elif nedelec_order == 2: # Second order edge element
+ # First order ele
+ firstOrderEdgeElement = 6
+
+ # Second order ele
+ secondOrderEdgeElement = 20
+
+ # Number of faces per tetrahedral element
+ nFacesEle = 4
+
+ # Edge's signs computation
+ idx_signs1 = np.array([1, 2, 0, 3, 3, 3], dtype=np.int)
+ idx_signs2 = np.array([0, 1, 2, 0, 1, 2], dtype=np.int)
+ tmp = nodesEle
+ tmp = tmp[idx_signs1] - tmp[idx_signs2]
+ signsEle = tmp / np.abs(tmp)
+
+ # Allocate
+ dofsEle = np.zeros((secondOrderEdgeElement), dtype=np.int)
+ newEdgesNumb = np.zeros((firstOrderEdgeElement, 2), dtype=np.int)
+ newFacesNumb = np.zeros((nFacesEle, 2), dtype=np.int)
+
+ # Use 1-based indexing in edgesEle and facesEle
+ edgesEle += np.int(1)
+ facesEle += np.int(1)
+
+ # Get dofs on edges
+ newEdgesNumb[:, 0] = (edgesEle*2)-1
+ newEdgesNumb[:, 1] = edgesEle*2
+
+ # Reverse dofs in case they are negative
+ for iEdge in np.arange(firstOrderEdgeElement):
+ if (signsEle[iEdge] < 0):
+ newEdgesNumb[iEdge, [0, 1]] = newEdgesNumb[iEdge, [1, 0]]
+
+ newEdgesNumb = newEdgesNumb.reshape((firstOrderEdgeElement * 2))
+
+ # Get dofs on faces
+ newFacesNumb[:, 0] = (facesEle*2+nEdges*2)-1
+ newFacesNumb[:, 1] = facesEle*2+nEdges*2
+ newFacesNumb = newFacesNumb.reshape((nFacesEle*2))
+
+ # Insert dofs on edges in dofsEle array
+ dofsEle[0:firstOrderEdgeElement*2] = newEdgesNumb
+
+ # Insert dofs on faces in dofsEle array
+ dofsEle[firstOrderEdgeElement*2:] = newFacesNumb
+
+ # Use 0-based indexing in boundaries
+ dofsEle -= np.int(1)
+
+ elif nedelec_order == 3: # Third order edge element
+ # First order ele
+ firstOrderEdgeElement = 6
+
+ # Third order ele
+ thirdOrderEdgeElement = 45
+
+ # Number of faces per tetrahedral element
+ nFacesEle = 4
+
+ # Edge's signs computation
+ idx_signs1 = np.array([1, 2, 0, 3, 3, 3], dtype=np.int)
+ idx_signs2 = np.array([0, 1, 2, 0, 1, 2], dtype=np.int)
+ tmp = nodesEle
+ tmp = tmp[idx_signs1] - tmp[idx_signs2]
+ signsEle = tmp / np.abs(tmp)
+
+ # Allocate
+ dofsEle = np.zeros((thirdOrderEdgeElement), dtype=np.int)
+ newEdgesNumb = np.zeros((firstOrderEdgeElement, 3), dtype=np.int)
+ newFacesNumb = np.zeros((nFacesEle, 6), dtype=np.int)
+ newVolumeNumb = np.zeros([3], dtype=np.int)
+
+ # Use 1-based indexing in edgesEle and facesEle
+ edgesEle += np.int(1)
+ facesEle += np.int(1)
+ iEle += np.int(1)
+
+ # Get dofs on edges
+ newEdgesNumb[:, 0] = (edgesEle*3)-2
+ newEdgesNumb[:, 1] = (edgesEle*3)-1
+ newEdgesNumb[:, 2] = edgesEle*3
+
+ # Reverse dofs in case they are negative
+ for iEdge in np.arange(firstOrderEdgeElement):
+ if (signsEle[iEdge] < 0):
+ newEdgesNumb[iEdge, [0, 1, 2]] = newEdgesNumb[iEdge, [2, 1, 0]]
+
+ newEdgesNumb = newEdgesNumb.reshape((firstOrderEdgeElement*3))
+
+ # Get dofs on faces
+ # Definition of faces (global ordering)
+ global_faces = np.array([[0, 1, 2], [0, 2, 3],
+ [0, 3, 1], [3, 1, 2]], dtype=np.int)
+
+ tmp_dofs = np.zeros((3, 2), dtype=np.int)
+
+ for iFace in np.arange(nFacesEle):
+ tmp_dofs[0, :] = [(facesEle[iFace]*6+nEdges*3)-5,
+ (facesEle[iFace]*6+nEdges*3)-4]
+ tmp_dofs[1, :] = [(facesEle[iFace]*6+nEdges*3)-3,
+ (facesEle[iFace]*6+nEdges*3)-2]
+ tmp_dofs[2, :] = [(facesEle[iFace]*6+nEdges*3)-1,
+ (facesEle[iFace]*6+nEdges*3)]
+
+ if not np.all(nodesFace[iFace, :] ==
+ nodesEle[global_faces[iFace, :]]):
+ a = nodesFace[iFace, :]
+ b = nodesEle[global_faces[iFace, :]]
+ idx = np.where(a[:, None] == b[None, :])[1]
+ tmp_dofs_idx = tmp_dofs[idx, :]
+ newFacesNumb[iFace, :] = tmp_dofs_idx.reshape(1, 6)
+ else:
+ newFacesNumb[iFace, :] = tmp_dofs.reshape(1, 6)
+
+ newFacesNumb = newFacesNumb.reshape((nFacesEle*6))
+
+ # Get dofs on element volume
+ newVolumeNumb[0] = (((nEdges*3) + (nFaces*6)) +
+ (iEle-1) * 3 + np.int(1))
+ newVolumeNumb[1] = (((nEdges*3) + (nFaces*6)) +
+ (iEle-1)*3 + np.int(2))
+ newVolumeNumb[2] = (((nEdges*3) + (nFaces*6)) +
+ (iEle-1) * 3 + np.int(3))
+
+ # Insert dofs on edges in dofsEle array
+ dofsEle[0:firstOrderEdgeElement*3] = newEdgesNumb
+
+ # Insert dofs on faces in dofsEle array
+ dofsEle[firstOrderEdgeElement*3:
+ firstOrderEdgeElement*3+nFacesEle*6] = newFacesNumb
+
+ # Insert dofs on volume in dofsEle array
+ dofsEle[firstOrderEdgeElement*3+nFacesEle*6:] = newVolumeNumb
+
+ # Use 0-based indexing in boundaries
+ dofsEle -= np.int(1)
+ iEle -= np.int(1)
+ edgesEle -= np.int(1)
+ facesEle -= np.int(1)
+
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
+ return dofsEle
+
+
+def edgeFaceVerticesInit():
+ ''' Initialization of arrays that define edges and faces of tetrahedral
+ elements. Vector basis functions are based on these arrays.
+
+ :param: None.
+ :return: edge_vertices and face_vertices.
+ :rtype: ndarray
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+
+ # Edges definition
+ edge_vertices = np.array([[0, 1],
+ [1, 2],
+ [2, 0],
+ [0, 3],
+ [1, 3],
+ [2, 3]], dtype=np.int)
+
+ # Faces definition
+ face_vertices = np.array([[0, 1, 2],
+ [1, 3, 2],
+ [2, 3, 0],
+ [3, 1, 0]], dtype=np.int)
+
+ # Reference element
+ ref_ele = np.array([[0, 1, 0, 0],
+ [0, 0, 1, 0],
+ [0, 0, 0, 1]], dtype=np.int)
+
+ return edge_vertices, face_vertices, ref_ele
+
+
+def isigno(xx, yy, zz):
+ ''' Compute signs for edges in a given tetrahedral element.
+
+ :param float xx: x-coordinates of the nodes.
+ :param float yy: x-coordinates of the nodes.
+ :param float zz: x-coordinates of the nodes.
+ :return: signs of edges.
+ :rtype: ndarray
+ '''
+ isign = -1
+
+ if ((xx == 0) and (yy == 0) and (zz == 0)):
+ print('Warning: Null sign in edge')
+ isign = 0
+ elif ((xx > 0) or ((xx == 0) and (yy > 0)) or ((xx == 0)
+ and (yy == 0) and (zz > 0))):
+ isign = 1
+
+ return isign
+
+
+def computeSignsJacobLegth(eleNodes, edge_vertices, face_vertices,
+ nedelec_order):
+ ''' Compute signs, edges length and jacobian for mapping.
+
+ :param ndarray nodesEle: array with nodal indexes of element.
+ :param ndarray edge_vertices: edges connectivity based on vertices.
+ :param ndarray face_vertices: .
+ :param int nedelec_order: nedelec element order.
+ :return: tangential unitary vectors for each edge, edges length,
+ dofs signs, normal face vectors, jacobiano, determinant
+ of jacobian, faces area.
+ :rtype: ndarray
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # First order ele
+ firstOrderEdgeElement = 6
+
+ # Second order ele
+ secondOrderEdgeElement = 20
+
+ # Third order ele
+ thirdOrderEdgeElement = 45
+
+ if nedelec_order == 2:
+ orderEle = secondOrderEdgeElement
+ elif nedelec_order == 3:
+ orderEle = thirdOrderEdgeElement
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
+ # Absolute values for edges and faces numbering
+ edge_vertices_abs = np.abs(edge_vertices)
+ face_vertices_abs = np.abs(face_vertices)
+
+ # Jacobian computation
+ jacob = np.zeros((3, 3), dtype=np.float)
+ jacob[0, :] = eleNodes[:, 1] - eleNodes[:, 0]
+ jacob[1, :] = eleNodes[:, 2] - eleNodes[:, 0]
+ jacob[2, :] = eleNodes[:, 3] - eleNodes[:, 0]
+
+ # Compute jacobian determinant
+ detJacob = (jacob[0, 0]*jacob[1, 1]*jacob[2, 2] +
+ jacob[0, 1]*jacob[1, 2]*jacob[2, 0] +
+ jacob[0, 2]*jacob[1, 0]*jacob[2, 1] -
+ jacob[0, 2]*jacob[1, 1]*jacob[2, 0] -
+ jacob[0, 1]*jacob[1, 0]*jacob[2, 2] -
+ jacob[0, 0]*jacob[1, 2]*jacob[2, 1])
+
+ # Definition of tangetial unitary vectors for each edge
+ taui = np.zeros((3, firstOrderEdgeElement), dtype=np.float)
+ taui[0:3, :] = (eleNodes[:, edge_vertices_abs[:, 1]] -
+ eleNodes[:, edge_vertices_abs[:, 0]])
+
+ # Computation of normal face vectors, signs and edge length computation
+ nreal = np.zeros((3, 4), dtype=np.float)
+ area_faces = np.zeros(4, dtype=np.float)
+ length = np.zeros(firstOrderEdgeElement, dtype=np.float)
+ signs = np.zeros(orderEle, dtype=np.float)
+
+ if nedelec_order == 2:
+ for iedge in np.arange(firstOrderEdgeElement):
+ length[iedge] = norm(taui[:, iedge])
+ taui[:, iedge] = taui[:, iedge]/length[iedge]
+
+ if np.sum(np.sign(edge_vertices[iedge, :]+np.int(1))) == -2:
+ taui[:, iedge] = -taui[:, iedge]
+ elif np.sum(np.sign(edge_vertices[iedge, :]+np.int(1))) == 0:
+ raise ValueError('The signs of ', iedge,
+ ' are incorrect.')
+
+ dof = np.linspace(2*iedge-1, 2*iedge, 2,
+ dtype=np.int) + np.int(1)
+
+ signs[dof] = isigno(taui[0, iedge], taui[1, iedge],
+ taui[2, iedge])
+
+ for facenumber in np.arange(4):
+ aux1 = (eleNodes[:, face_vertices_abs[facenumber, 1]] -
+ eleNodes[:, face_vertices_abs[facenumber, 0]])
+ aux2 = (eleNodes[:, face_vertices_abs[facenumber, 2]] -
+ eleNodes[:, face_vertices_abs[facenumber, 0]])
+
+ nreal[:, facenumber] = -np.cross(aux1, aux2)
+
+ area_faces[facenumber] = norm(nreal[:, facenumber])
+ nreal[:, facenumber] = nreal[:, facenumber]/area_faces[facenumber]
+
+ dof = np.linspace(2*facenumber-1, 2*facenumber, 2,
+ dtype=np.int) + np.int(13)
+
+ signs[dof] = isigno(nreal[0, facenumber], nreal[1, facenumber],
+ nreal[2, facenumber])
+
+ elif nedelec_order == 3:
+ # Compute components for xx, yy, zz for the dofs associated
+ # to edges (18 dofs, 3 per edge)
+ # Allocate
+ xx = np.zeros(18, dtype=np.float)
+ yy = np.zeros(18, dtype=np.float)
+ zz = np.zeros(18, dtype=np.float)
+
+ xyz21 = eleNodes[:, 1] - eleNodes[:, 0]
+ xyz31 = eleNodes[:, 2] - eleNodes[:, 0]
+ xyz41 = eleNodes[:, 3] - eleNodes[:, 0]
+
+ # Node 1,2,3
+ xx[[0, 1, 2]] = xyz21[0]
+ yy[[0, 1, 2]] = xyz21[1]
+ zz[[0, 1, 2]] = xyz21[2]
+
+ # Node 4,5,6
+ xx[[3, 4, 5]] = eleNodes[0, 2]-eleNodes[0, 1]
+ yy[[3, 4, 5]] = eleNodes[1, 2]-eleNodes[1, 1]
+ zz[[3, 4, 5]] = eleNodes[2, 2]-eleNodes[2, 1]
+
+ # Node 7,8,9
+ xx[[6, 7, 8]] = -xyz31[0]
+ yy[[6, 7, 8]] = -xyz31[1]
+ zz[[6, 7, 8]] = -xyz31[2]
+
+ # Node 10,11,12
+ xx[[9, 10, 11]] = xyz41[0]
+ yy[[9, 10, 11]] = xyz41[1]
+ zz[[9, 10, 11]] = xyz41[2]
+
+ # Node 13,14,15
+ xx[[12, 13, 14]] = eleNodes[0, 3]-eleNodes[0, 1]
+ yy[[12, 13, 14]] = eleNodes[1, 3]-eleNodes[1, 1]
+ zz[[12, 13, 14]] = eleNodes[2, 3]-eleNodes[2, 1]
+
+ # Node 16,17,18
+ xx[[15, 16, 17]] = eleNodes[0, 3]-eleNodes[0, 2]
+ yy[[15, 16, 17]] = eleNodes[1, 3]-eleNodes[1, 2]
+ zz[[15, 16, 17]] = eleNodes[2, 3]-eleNodes[2, 2]
+
+ nreal[:, 0] = np.cross(np.hstack((xx[0], yy[0], zz[0])),
+ np.hstack((xx[6], yy[6], zz[6])))
+ nreal[:, 1] = np.cross(np.hstack((xx[6], yy[6], zz[6])),
+ np.hstack((xx[9], yy[9], zz[9])))
+ nreal[:, 2] = np.cross(np.hstack((xx[0], yy[0], zz[0])),
+ np.hstack((xx[9], yy[9], zz[9])))
+ nreal[:, 3] = np.cross(np.hstack((xx[3], yy[3], zz[3])),
+ np.hstack((xx[12], yy[12], zz[12])))
+
+ for facenumber in np.arange(4):
+ nreal[:, facenumber] = (nreal[:, facenumber] /
+ norm(nreal[:, facenumber]))
+
+ # Sign for dofs on edges
+ for idof in np.arange(18):
+ signs[idof] = isigno(xx[idof], yy[idof], zz[idof])
+
+ # Sign for dofs on faces
+ signs[18:24] = isigno(nreal[0, 0], nreal[1, 0], nreal[2, 0])
+ signs[24:30] = isigno(nreal[0, 1], nreal[1, 1], nreal[2, 1])
+ signs[30:36] = isigno(nreal[0, 2], nreal[1, 2], nreal[2, 2])
+ signs[36:42] = isigno(nreal[0, 3], nreal[1, 3], nreal[2, 3])
+
+ # Sign for dofs on volume
+ signs[42:45] = 1
+
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
+ area_faces = area_faces/2.
+
+ return taui, length, signs, nreal, jacob, detJacob, area_faces
+
+
+def definitionHighOrderTet(nreal, signs, jacob, nedelec_order):
+ ''' Compute "q" vectors on faces -dof definition of edge tetrahedral
+ element of second and third order.
+
+ :param float-array nreal: normal face vectors.
+ :param float-array signs: dofs signs.
+ :param float jacob: jacobian.
+ :param int nedelec_order: nedelec element order.
+ :return: q vectors on faces, inverse jacobian, 3x3 tensor.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # q vectors general
+ q_genera = np.eye(3, dtype=np.float)
+
+ # Add sign to face
+ n_faces = np.zeros((3, 4), dtype=np.float)
+ if nedelec_order == 2:
+ n_faces[:, 0] = nreal[:, 0]*signs[12]
+ n_faces[:, 1] = nreal[:, 1]*signs[14]
+ n_faces[:, 2] = nreal[:, 2]*signs[16]
+ n_faces[:, 3] = nreal[:, 3]*signs[18]
+ elif nedelec_order == 3:
+ n_faces[:, 0] = nreal[:, 0]*signs[18]
+ n_faces[:, 1] = nreal[:, 1]*signs[24]
+ n_faces[:, 2] = nreal[:, 2]*signs[30]
+ n_faces[:, 3] = nreal[:, 3]*signs[36]
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
+ qface = np.zeros((3, 8), dtype=np.float)
+
+ for nface in np.arange(4):
+ aux1 = crossprod(n_faces[:, nface], q_genera[:, 0])
+ aux2 = crossprod(n_faces[:, nface], q_genera[:, 1])
+ aux3 = crossprod(n_faces[:, nface], q_genera[:, 2])
+
+ if ((norm(aux1) >= norm(aux2)) and (norm(aux1) >= norm(aux3))):
+ qface[:, nface*2] = aux1[:, 0]
+ elif ((norm(aux2) >= norm(aux1)) and (norm(aux2) >= norm(aux3))):
+ qface[:, nface*2] = aux2[:, 0]
+ elif ((norm(aux3) >= norm(aux1)) and (norm(aux3) >= norm(aux2))):
+ qface[:, nface*2] = aux3[:, 0]
+
+ qface[:, nface*2] = qface[:, nface*2]/norm(qface[:, nface*2])
+
+ qface[:, (nface*2)+1] = crossprod(n_faces[:, nface],
+ qface[:, nface*2])[:, 0]
+
+ qface[:, (nface*2)+1] = (qface[:, (nface*2)+1] /
+ norm(qface[:, (nface*2)+1]))
+
+ # Computation of jacob^-1
+ gr = np.eye(3, dtype=np.float)
+ invjj = inv(jacob)
+ GR = np.matmul(invjj.transpose(), np.matmul(gr, invjj))
+
+ qface1_ref = np.matmul(jacob, qface[:, [0, 1]])
+ qface2_ref = np.matmul(jacob, qface[:, [2, 3]])
+ qface3_ref = np.matmul(jacob, qface[:, [4, 5]])
+ qface4_ref = np.matmul(jacob, qface[:, [6, 7]])
+
+ return qface1_ref, qface2_ref, qface3_ref, qface4_ref, invjj, GR
+
+
+def aristaMappingTetrahedral(edge_vertices_old, edge_vertices_new):
+ ''' Mapping edges of a real element defined by edge_vertices to a reference
+ element por edge_vertices_ref. Furthermore, compute relations between
+ "tau" tangential vectors to edges.
+
+ :param int-array edge_vertices_old: edges definition based on
+ vertices (old).
+ :param int-array edge_vertices_new: edges definition based on
+ vertices (new).
+ :return: signs of unitary tangential vectors for each edge and
+ edges mapping.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+
+ Example:
+ tau_sign = [-1 1 1 1 1 1] sign of tau of (old) edge 1 is on opposite
+ direction. Note that old edge 1 will be
+ new edge 3 (see arista_mapping below)
+
+
+ arista_mapping=[-3 2 1 4 5 6] new edge 1 is old edge 3 The dof of
+ edge are interchanged, i.e., the dof
+ of the old edge 3 are placed
+ interchanged in new edge 1.
+ '''
+ # Number of edges
+ size = edge_vertices_old.shape
+ numaristas = size[0]
+ size = edge_vertices_new.shape
+ numaristas2 = size[0]
+
+ # Use 1-based indexes on edge_vertices_new
+ edge_vertices_new += np.int(1)
+
+ # Allocate
+ tau_sign = np.ones(numaristas, dtype=np.int)
+ arista_mapping = np.zeros(numaristas, dtype=np.int)
+
+ edge_vertices_old_abs = np.abs(edge_vertices_old)
+ edge_vertices_new_abs = np.abs(edge_vertices_new)
+
+ # Previous validations
+ # Dimensional coherence
+ if numaristas != numaristas2:
+ raise ValueError('Dimensions of edge_vertices_old and ' +
+ 'edge_vertices_new are incoherence')
+
+ # Signs coherence
+ if not (np.array_equal(np.sign(edge_vertices_old[:, 0]),
+ np.sign(edge_vertices_old[:, 1]))):
+ raise ValueError('Signs of edge_vertices_old are incoherence')
+
+ if not (np.array_equal(np.sign(edge_vertices_new[:, 0]),
+ np.sign(edge_vertices_new[:, 1]))):
+ raise ValueError('Signs of edge_vertices_new are incoherence')
+
+ for new_iedge in np.arange(numaristas):
+ new = edge_vertices_new[new_iedge, :]
+ new_abs = edge_vertices_new_abs[new_iedge, :]
+ new_sign = np.sign(new[0])
+
+ for old_iedge in np.arange(numaristas):
+ old = edge_vertices_old[old_iedge, :]
+ old_abs = edge_vertices_old_abs[old_iedge, :]
+ old_sign = np.sign(old[0])
+
+ # Check vertices coincidence (regardless of order or sign)
+ if (np.array_equal(new_abs, old_abs) or
+ np.array_equal(new_abs, np.flip(old_abs, axis=0))):
+ if (new_sign != old_sign):
+ tau_sign[old_iedge] = -tau_sign[old_iedge]
+
+ if (np.array_equal(new_abs, old_abs)):
+ # Coincidence in order too
+ arista_mapping[new_iedge] = old_iedge
+ else:
+ # vertices ordering changed => sign '-' in arista_mapping
+ # => change sign in tau of
+ # old edge
+ arista_mapping[new_iedge] = -old_iedge
+ tau_sign[old_iedge] = -tau_sign[old_iedge]
+
+ # Subsequent validations
+ # In arista_mapping must be all edge numbers and no repetitions
+ for iedge in np.arange(numaristas):
+ if np.where(np.abs(arista_mapping) == iedge)[0].size == 0:
+ raise ValueError('arista_mapping does not contain arista ' +
+ iedge)
+
+ if is_duplicate_entry(np.abs(arista_mapping)) != 0:
+ raise ValueError('arista_mapping has duplicated values')
+
+ return tau_sign, arista_mapping
+
+
+def faceMappingTetrahedral(face_vertices_old, face_vertices_new, stage):
+ ''' Compute mapping between faces of a tetrahedron with face_vertices to a
+ tetrahedron with faces_vertices_ref.
+
+ :param int-array face_vertices_old: faces definition based on
+ vertices (old).
+ :param int-array face_vertices_new: faces definition based on
+ vertices (new).
+ :param int face: number of stage of mapping (1 or 2).
+ :return: signs of unitary tangential vectors for each face and
+ faces mapping.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Number of faces
+ size = face_vertices_old.shape
+ numfaces = size[0]
+ size = face_vertices_new.shape
+ numfaces2 = size[0]
+
+ # Use 1-based indexes on face_vertices_old or face_vertices_new
+ if stage == 1: # Mapping of first stage
+ face_vertices_old += np.int(1)
+ elif stage == 2: # Mapping of second stage
+ pass
+ else:
+ raise ValueError('Mapping stage = ', stage, ' not supported.')
+
+ # Allocate
+ face_mapping = np.zeros(numfaces, dtype=np.int)
+ vertex_shift = np.zeros(numfaces, dtype=np.int)
+
+ face_vertices_old_abs = np.abs(face_vertices_old)
+ face_vertices_new_abs = np.abs(face_vertices_new)
+
+ # Previous validations
+ # Dimensional coherence
+ if numfaces != numfaces2:
+ raise ValueError('Dimensions of face_vertices_old and ' +
+ 'face_vertices_new are incoherence')
+
+ # Mapping
+ nvertices_face = 3
+
+ for new_facenumber in np.arange(numfaces):
+ new = face_vertices_new[new_facenumber, :]
+ new_abs = face_vertices_new_abs[new_facenumber, :]
+
+ for old_facenumber in np.arange(numfaces):
+ old = face_vertices_old[old_facenumber, :]
+ old_abs = face_vertices_old_abs[old_facenumber, :]
+
+ old_abs_reversed = np.roll(np.flip(old_abs, axis=0), 1)
+
+ # Ciclic shift until match
+ for cont_vertex_shift in np.arange(nvertices_face):
+ if (np.array_equal(new_abs, old_abs)):
+ face_mapping[new_facenumber] = old_facenumber
+ vertex_shift[new_facenumber] = cont_vertex_shift
+ break
+ if (np.array_equal(new_abs, old_abs_reversed)):
+ face_mapping[new_facenumber] = -old_facenumber
+ vertex_shift[new_facenumber] = cont_vertex_shift
+ break
+
+ old_abs = np.roll(old_abs, 1)
+ old_abs_reversed = np.roll(old_abs_reversed, -1)
+
+ # Subsequent validations
+ # In face_mapping must be all face numbers and no repetitions
+ for facenumber in np.arange(numfaces):
+ if np.where(np.abs(face_mapping) == facenumber)[0].size == 0:
+ raise ValueError('face_mapping does not contain arista ' +
+ facenumber)
+
+ if is_duplicate_entry(np.abs(face_mapping)) != 0:
+ raise ValueError('face_mapping has duplicated values')
+
+ return vertex_shift, face_mapping
+
+
+def computeCoefficientsSecondOrder(qface1, qface2, qface3, qface4,
+ r_vertices_ref, edge_vertices,
+ face_vertices):
+ ''' Compute the coefficients for edge basis functions of second order
+ on reference element.
+
+ :param float-array qface1: vector q on face 1.
+ :param float-array qface2: vector q on face 2.
+ :param float-array qface3: vector q on face 3.
+ :param float-array qface4: vector q on face 4.
+ :param float-array r_vertices: vertices of reference element.
+ :param int-array edge_vertices: initialization of edges connectivity.
+ :param int-array face_vertices: initialization of faces connectivity.
+ :return: coefficients.
+ :rtype: float.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # First order ele
+ firstOrderEdgeElement = 6
+
+ # Second order ele
+ secondOrderEdgeElement = 20
+
+ # Absolute values for edges numbering
+ edge_vertices_abs = np.abs(edge_vertices)
+
+ # Definition of tangetial unitary vectors for each edge (2 dofs per edge)
+ taui = np.zeros((3, firstOrderEdgeElement*2), dtype=np.float)
+
+ for iedge in np.arange(firstOrderEdgeElement):
+ taui[:, iedge*2] = (r_vertices_ref[:, edge_vertices_abs[iedge, 1]] -
+ r_vertices_ref[:, edge_vertices_abs[iedge, 0]])
+ taui[:, iedge*2+1] = taui[:, 2*iedge]
+
+ # Normalization of taui by using edges length
+ length = np.zeros(firstOrderEdgeElement, dtype=np.float)
+
+ for iedge in np.arange(firstOrderEdgeElement):
+ length[iedge] = norm(taui[:, iedge*2+1])
+ taui[:, iedge*2: 2*iedge+2] = taui[:, iedge*2: 2*iedge+2]/length[iedge]
+ if (np.sum(np.sign(edge_vertices[iedge, :]+1)) == -2):
+ taui[:, iedge*2: 2*iedge+2] = -taui[:, iedge*2: 2*iedge+2]
+ elif (np.sum(np.sign(edge_vertices[iedge, :]+1)) == 0):
+ raise ValueError('The signs of ', iedge, ' are incorrect.')
+
+ # Definition of normal vectors to faces
+ n1 = np.array([0, 0, -1], dtype=np.float)
+ n1 = n1/norm(n1)
+ n2 = np.array([-1, 0, 0], dtype=np.float)
+ n2 = n2/norm(n2)
+ n3 = np.array([0, -1, 0], dtype=np.float)
+ n3 = n3/norm(n3)
+ n4 = np.array([1, 1, 1], dtype=np.float)
+ n4 = n4/norm(n4)
+
+ # Allocate
+ matrix = np.zeros((secondOrderEdgeElement, secondOrderEdgeElement),
+ dtype=np.float)
+
+ # ----- Auxiliar definition of edges -----
+ # We define the edges and their dof according to a predefined direction
+ # given by edge_vertices_aux. Then at the end the necessary changes are
+ # made so that the dof of the edges adhere to the definition given by
+ # edge_vertices. Here we use a 1-based indexes.
+ edge_vertices_aux = np.array([[1, 2],
+ [2, 3],
+ [-3, -1],
+ [1, 4],
+ [2, 4],
+ [3, 4]], dtype=np.int)
+ # Edges length
+ LengthAris = length
+
+ # Integrals
+ # Int edge 1 (node 1 --> 2)
+ aux_x_L1 = LengthAris[0]*np.array([1./2., 1./6., 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ dtype=np.float)
+ aux_x_L2 = LengthAris[0]*np.array([1./2., 1./3., 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ dtype=np.float)
+ matrix[0, :] = aux_x_L1 # Dof 1 associated to L1
+ matrix[1, :] = aux_x_L2 # Dof 2 associated to L2
+
+ del aux_x_L1, aux_x_L2
+
+ aux_x_L2 = LengthAris[1]*np.array([1./2., 1./3., 1./6., 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1./12., 0, -1./12., 0, 0, 0,
+ 0, 0], dtype=np.float)
+ aux_y_L2 = LengthAris[1]*np.array([0, 0, 0, 0, 1./2., 1./3., 1./6., 0, 0,
+ 0, 0, 0, -1./12., 0, 1./4., 0, 0, 0,
+ 0, 0], dtype=np.float)
+ aux_x_L3 = LengthAris[1]*np.array([1./2., 1./6., 1./3., 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1./4., 0, -1./12., 0, 0, 0,
+ 0, 0], dtype=np.float)
+ aux_y_L3 = LengthAris[1]*np.array([0, 0, 0, 0, 1./2., 1./6., 1./3., 0, 0,
+ 0, 0, 0, -1./12., 0, 1./12., 0, 0, 0,
+ 0, 0], dtype=np.float)
+
+ # Dof 3 associated to L2
+ matrix[2, :] = (1./LengthAris[1])*(-aux_x_L2+aux_y_L2)
+ # Dof 4 associated to L3
+ matrix[3, :] = (1./LengthAris[1])*(-aux_x_L3+aux_y_L3)
+
+ del aux_x_L2, aux_y_L2, aux_x_L3, aux_y_L3
+
+ # Int edge 3 (node 1 --> 3)
+ aux_y_L1 = LengthAris[2]*np.array([0, 0, 0, 0, 1./2., 0, 1./6., 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ dtype=np.float)
+ aux_y_L3 = LengthAris[2]*np.array([0, 0, 0, 0, 1./2., 0, 1./3., 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ dtype=np.float)
+ matrix[4, :] = aux_y_L3 # Dof 5 associated to L3
+ matrix[5, :] = aux_y_L1 # Dof 6 associated to L1
+
+ del aux_y_L1, aux_y_L3
+
+ # Int edge 4 (node 1 --> 4)
+ aux_z_L1 = LengthAris[3]*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 0, 0,
+ 1./6., 0, 0, 0, 0, 0, 0, 0, 0],
+ dtype=np.float)
+ aux_z_L4 = LengthAris[3]*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 0, 0,
+ 1./3., 0, 0, 0, 0, 0, 0, 0, 0],
+ dtype=np.float)
+ matrix[6, :] = aux_z_L1 # Dof 7 associated to L1
+ matrix[7, :] = aux_z_L4 # Dof 8 associated to L4
+
+ del aux_z_L1, aux_z_L4
+
+ # Int edge 5 (vertices 2 --> 4)
+ aux_x_L2 = LengthAris[4]*np.array([1./2., 1./3., 0, 1./6., 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1./12., 1./12., 0,
+ 0, 0], dtype=np.float)
+ aux_z_L2 = LengthAris[4]*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 1./3.,
+ 0, 1./6., 0, 0, 0, 1./4., -1./12., 0,
+ 0, 0], dtype=np.float)
+ aux_x_L4 = LengthAris[4]*np.array([1./2., 1./6., 0, 1./3., 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1./12., 1./4., 0, 0,
+ 0], dtype=np.float)
+ aux_z_L4 = LengthAris[4]*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 1./6.,
+ 0, 1./3., 0, 0, 0, 1./12., -1./12., 0,
+ 0, 0], dtype=np.float)
+
+ # Dof 9 associated to L2
+ matrix[8, :] = (1./np.sqrt(2.))*(-aux_x_L2+aux_z_L2)
+ # Dof 10 associated to L4
+ matrix[9, :] = (1./np.sqrt(2.))*(-aux_x_L4+aux_z_L4)
+
+ del aux_x_L2, aux_z_L2, aux_x_L4, aux_z_L4
+
+ # Int edge 6 (nodes 3 --> 4)
+ aux_y_L3 = LengthAris[5]*np.array([0, 0, 0, 0, 1./2., 0, 1./3., 1./6., 0,
+ 0, 0, 0, 0, -1./12., 0, 0, 0, 1./12.,
+ 0, 0], dtype=np.float)
+ aux_z_L3 = LengthAris[5]*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 0, 1./3.,
+ 1./6., 0., 1./4., 0, 0, 0, -1./12., 0,
+ 0], dtype=np.float)
+ aux_y_L4 = LengthAris[5]*np.array([0, 0, 0, 0, 1./2., 0, 1./6., 1./3., 0,
+ 0, 0, 0, 0, -1./12., 0, 0, 0, 1./4.,
+ 0, 0], dtype=np.float)
+ aux_z_L4 = LengthAris[5]*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 0, 1./6.,
+ 1./3., 0, 1./12., 0, 0, 0, -1./12., 0,
+ 0], dtype=np.float)
+
+ # Dof 11 associated to L3
+ matrix[10, :] = (1./np.sqrt(2))*(-aux_y_L3+aux_z_L3)
+ # Dof 12 associated to L4
+ matrix[11, :] = (1./np.sqrt(2))*(-aux_y_L4+aux_z_L4)
+
+ del aux_y_L3, aux_z_L3, aux_y_L4, aux_z_L4
+
+ # Mapping DOF order
+ # A change of order of the dof (functions) of the edge is made to
+ # fit the given in edge_vertices
+ tau_sign, arista_mapping = aristaMappingTetrahedral(edge_vertices_aux,
+ edge_vertices)
+
+ # Change sign 'tau' of edges
+ nodes_sign = np.reshape(np.ones((2, 1))*tau_sign, (12, 1), order='F')
+ tmp1 = nodes_sign*np.ones((1, secondOrderEdgeElement), dtype=np.float)
+ matrix[0:12, :] = np.multiply(tmp1, matrix[0:12, :])
+
+ # Change sign 'tau' of faces
+ nodes_mapping = np.reshape(np.array([[2*np.abs(arista_mapping)],
+ [2*np.abs(arista_mapping)+1]]), (12), order='F')
+ matrix[0:12, :] = matrix[nodes_mapping, :]
+
+ # Once ordered by edges, sort the dof of each edge according to the
+ # sign of arista_mapping
+ for iedge in np.arange(firstOrderEdgeElement):
+ if np.sign(arista_mapping[iedge]) == -1:
+ matrix[[2*iedge+1, 2*iedge], :] = matrix[[2*iedge, 2*iedge+1], :]
+
+ del edge_vertices_aux, arista_mapping, tau_sign, nodes_sign, nodes_mapping
+
+ # Conditions on faces int {n x Ni) .q}
+ # We define the faces and their dof according to a predefined sign given
+ # by face_vertices_aux. Then, the necessary changes are made so that the
+ # dof of the faces adhere to the definition given by edge_vertices. In
+ # this case, the dof are all associated to the barycenter of the face
+ # with what there is no such numbering sense as such and the only
+ # thing we will do is map the dof of some faces in the dof of other faces.
+ face_vertices_aux = np.array([[1, 2, 3],
+ [1, 3, 4],
+ [1, 4, 2],
+ [2, 4, 3]], dtype=np.int)
+
+ # The qfacei that enter as a parameter of entry to the routine are
+ # referred to face numbering given by face_vertices. You have to map
+ # them to the number given by face_verttices_aux, which is what the
+ # calculations are programmed to do.
+
+ # For second order, vertex_shift can be ignored
+ stage = 1
+ _, face_mapping = faceMappingTetrahedral(face_vertices, face_vertices_aux,
+ stage)
+
+ tmp1 = np.array([[2*np.abs(face_mapping)], [2*np.abs(face_mapping)+1]])
+ q_mapping_aux = np.reshape(tmp1, (8), order='F')
+
+ qface_all = np.hstack((qface1, qface2, qface3, qface4))
+ qface_all = qface_all[:, q_mapping_aux]
+ qface1 = qface_all[:, [0, 1]]
+ qface2 = qface_all[:, [2, 3]]
+ qface3 = qface_all[:, [4, 5]]
+ qface4 = qface_all[:, [6, 7]]
+
+ # The variables aux_x (i, :), aux_y (i, :), aux_z (i, :) are the
+ # integrals of Nx, Ny and Nz on the i side of the tetrahedron. The
+ # integral is a function of the coefficients in such a way that
+ # aux_x (ii,:)*coeff is the integral coefficient Nix on face ii.
+
+ # Int face1
+ aux_x = np.array([1./2., 1./6., 1./6., 0, 0, 0, 0, 0, 0, 0, 0, 0, 1./12.,
+ 0, -1./24., 0, 0, 0, 0, 0], dtype=np.float)
+ aux_y = np.array([0, 0, 0, 0, 1./2., 1./6., 1./6., 0, 0, 0, 0, 0, -1./24.,
+ 0, 1./12., 0, 0, 0, 0, 0], dtype=np.float)
+ aux_z = np.zeros(secondOrderEdgeElement) # No considered
+
+ q1 = qface1[:, 0]
+ q2 = qface1[:, 1]
+ matrix[12, :] = ((q1[1]*n1[2]-q1[2]*n1[1])*aux_x +
+ (q1[2]*n1[0]-q1[0]*n1[2])*aux_y +
+ (q1[0]*n1[1]-q1[1]*n1[0])*aux_z)
+ matrix[13, :] = ((q2[1]*n1[2]-q2[2]*n1[1])*aux_x +
+ (q2[2]*n1[0]-q2[0]*n1[2])*aux_y +
+ (q2[0]*n1[1]-q2[1]*n1[0])*aux_z)
+
+ del aux_x, aux_y, aux_z
+
+ # Int face2
+ aux_x = np.zeros(secondOrderEdgeElement) # No considered
+ aux_y = np.array([0, 0, 0, 0, 1./2., 0, 1./6., 1./6., 0, 0, 0, 0, 0,
+ -1./24., 0, 0, 0, 1./12., 0, 0], dtype=np.float)
+ aux_z = np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 0, 1./6., 1./6., 0,
+ 1./12., 0, 0, 0, -1./24., 0, 0], dtype=np.float)
+
+ q1 = qface2[:, 0]
+ q2 = qface2[:, 1]
+ matrix[14, :] = ((q1[1]*n2[2]-q1[2]*n2[1])*aux_x +
+ (q1[2]*n2[0]-q1[0]*n2[2])*aux_y +
+ (q1[0]*n2[1]-q1[1]*n2[0])*aux_z)
+ matrix[15, :] = ((q2[1]*n2[2]-q2[2]*n2[1])*aux_x +
+ (q2[2]*n2[0]-q2[0]*n2[2])*aux_y +
+ (q2[0]*n2[1]-q2[1]*n2[0])*aux_z)
+
+ del aux_x, aux_y, aux_z
+
+ # Int face3
+ aux_x = np.array([1./2., 1./6., 0, 1./6., 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -1./24., 1./12., 0, 0, 0], dtype=np.float)
+ aux_y = np.zeros(secondOrderEdgeElement) # No considered
+ aux_z = np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 1./6., 0, 1./6., 0, 0, 0,
+ 1./12., -1./24., 0, 0, 0], dtype=np.float)
+
+ q1 = qface3[:, 0]
+ q2 = qface3[:, 1]
+ matrix[16, :] = ((q1[1]*n3[2]-q1[2]*n3[1])*aux_x +
+ (q1[2]*n3[0]-q1[0]*n3[2])*aux_y +
+ (q1[0]*n3[1]-q1[1]*n3[0])*aux_z)
+ matrix[17, :] = ((q2[1]*n3[2]-q2[2]*n3[1])*aux_x +
+ (q2[2]*n3[0]-q2[0]*n3[2])*aux_y +
+ (q2[0]*n3[1]-q2[1]*n3[0])*aux_z)
+
+ del aux_x, aux_y, aux_z
+
+ # Int face4
+ # Here (x,y,z) are L1, L2, L3
+ area_face4 = np.sqrt(3.)/2.
+
+ aux_x = 2.*area_face4*np.array([1./2., 1./6., 1./6., 1./6., 0, 0, 0, 0,
+ 0, 0, 0, 0, 1./12., 0, -1./24., -1./24.,
+ 1./12., 0, 1./24., 0], dtype=np.float)
+ aux_y = 2.*area_face4*np.array([0, 0, 0, 0, 1./2., 1./6., 1./6., 1./6., 0,
+ 0, 0, 0, -1./24., -1./24., 1./12., 0, 0,
+ 1./12., -1./24., 1./24.], dtype=np.float)
+ aux_z = 2.*area_face4*np.array([0, 0, 0, 0, 0, 0, 0, 0, 1./2., 1./6.,
+ 1./6., 1./6., 0, 1./12., 0, 1./12.,
+ -1./24., -1./24., 0, -1./24],
+ dtype=np.float)
+
+ q1 = qface4[:, 0]
+ q2 = qface4[:, 1]
+ matrix[18, :] = ((q1[1]*n4[2]-q1[2]*n4[1])*aux_x +
+ (q1[2]*n4[0]-q1[0]*n4[2])*aux_y +
+ (q1[0]*n4[1]-q1[1]*n4[0])*aux_z)
+ matrix[19, :] = ((q2[1]*n4[2]-q2[2]*n4[1])*aux_x +
+ (q2[2]*n4[0]-q2[0]*n4[2])*aux_y +
+ (q2[0]*n4[1]-q2[1]*n4[0])*aux_z)
+
+ del aux_x, aux_y, aux_z
+
+ # vertex_shift can be ignored for the case of second order since the
+ # dof are associated with barycenter of the face and not a certain
+ # face vertice
+ stage = 2
+ _, face_mapping = faceMappingTetrahedral(face_vertices_aux, face_vertices,
+ stage)
+
+ tmp1 = np.array([[2*np.abs(face_mapping)], [2*np.abs(face_mapping)+1]])
+ nodes_mapping = np.int(12) + np.reshape(tmp1, (8), order='F')
+
+ matrix[12:20, :] = matrix[nodes_mapping, :]
+
+ del face_vertices_aux, face_mapping, nodes_mapping, qface_all
+
+ # computation of the second member: one column for each Ni
+ secm = np.zeros((secondOrderEdgeElement, secondOrderEdgeElement),
+ dtype=np.float)
+ for ii in np.arange(secondOrderEdgeElement):
+ if ii <= 11:
+ secm[ii, ii] = 1.
+ elif ii > 11:
+ secm[ii, ii] = 1.
+
+ # Dual basis computation. Obtaining polynomial coefficients by resolution
+ # of the system: matrix * {coef} = {secm}
+ coef = lstsq(matrix, secm, rcond=None)[0]
+
+ # Coefficients EPS --> 0
+ EPS = 1.e-12
+ aux1, aux2 = np.where(np.abs(coef) < EPS)
+ size = aux1.shape
+ n = size[0]
+
+ for kk in np.arange(n):
+ coef[aux1[kk], aux2[kk]] = 0.
+
+ a1 = coef[0, :]
+ a2 = coef[1, :]
+ a3 = coef[2, :]
+ a4 = coef[3, :]
+ b1 = coef[4, :]
+ b2 = coef[5, :]
+ b3 = coef[6, :]
+ b4 = coef[7, :]
+ c1 = coef[8, :]
+ c2 = coef[9, :]
+ c3 = coef[10, :]
+ c4 = coef[11, :]
+ D = coef[12, :]
+ E = coef[13, :]
+ F = coef[14, :]
+ G = coef[15, :]
+ H = coef[16, :]
+ II = coef[17, :]
+ JJ = coef[18, :]
+ K = coef[19, :]
+
+ return (a1, a2, a3, a4, b1, b2, b3, b4, c1,
+ c2, c3, c4, D, E, F, G, H, II, JJ, K)
+
+
+def NiTetrahedralSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4,
+ D, E, F, G, H, II, JJ, K, x, y, z, r):
+ ''' Computation of Ni (Nedelec basis functions of second order) in a
+ tetrahedral element with vertices (x,y,z) for point r.
+
+ :param float coefficients: a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,D,E,
+ F,G,H,II,JJ,K.
+ :param float-array x: x-coordinates of reference element.
+ :param float-array y: y-coordinates of reference element.
+ :param float-array z: z-coordinates of reference element.
+ :param float-array r: xyz coordinates of the evaluation point.
+ :return: basis nedelec funcions of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Number of dimensions
+ nDimensions = 3
+
+ # Second order ele
+ secondOrderEdgeElement = 20
+
+ # Initialization
+ coef = np.zeros((secondOrderEdgeElement, secondOrderEdgeElement),
+ dtype=np.float)
+
+ coef[0, :] = a1
+ coef[1, :] = a2
+ coef[2, :] = a3
+ coef[3, :] = a4
+ coef[4, :] = b1
+ coef[5, :] = b2
+ coef[6, :] = b3
+ coef[7, :] = b4
+ coef[8, :] = c1
+ coef[9, :] = c2
+ coef[10, :] = c3
+ coef[11, :] = c4
+ coef[12, :] = D
+ coef[13, :] = E
+ coef[14, :] = F
+ coef[15, :] = G
+ coef[16, :] = H
+ coef[17, :] = II
+ coef[18, :] = JJ
+ coef[19, :] = K
+
+ # Computation on reference element
+ L = cartesianToVolumetricCoordinates(x, y, z, r)
+
+ xref = np.array([0, 1, 0, 0], dtype=np.float)
+ yref = np.array([0, 0, 1, 0], dtype=np.float)
+ zref = np.array([0, 0, 0, 1], dtype=np.float)
+
+ rref = np.zeros(3, dtype=np.float)
+ rref[0] = np.dot(L, xref)
+ rref[1] = np.dot(L, yref)
+ rref[2] = np.dot(L, zref)
+
+ aux_x = np.array([1, rref[0], rref[1], rref[2], 0, 0, 0, 0, 0, 0, 0,
+ 0, rref[1]**2, 0, -rref[0]*rref[1], -rref[0]*rref[2],
+ rref[2]**2, 0, rref[1]*rref[2], 0], dtype=np.float)
+
+ aux_y = np.array([0, 0, 0, 0, 1, rref[0], rref[1], rref[2], 0, 0, 0, 0,
+ -rref[0]*rref[1], -rref[1]*rref[2], rref[0]**2, 0, 0,
+ rref[2]**2, -rref[0]*rref[2], rref[0]*rref[2]],
+ dtype=np.float)
+
+ aux_z = np.array([0, 0, 0, 0, 0, 0, 0, 0, 1, rref[0], rref[1], rref[2],
+ 0, rref[1]**2, 0, rref[0]**2, -rref[0]*rref[2],
+ -rref[1]*rref[2], 0, -rref[0]*rref[1]], dtype=np.float)
+
+ # Allocate
+ Niref = np.zeros((nDimensions, secondOrderEdgeElement), dtype=np.float)
+
+ Niref[0, :] = np.matmul(aux_x, coef)
+ Niref[1, :] = np.matmul(aux_y, coef)
+ Niref[2, :] = np.matmul(aux_z, coef)
+
+ del aux_x, aux_y, aux_z
+
+ # Vector element reference to the real element through the Jacobian
+ # Ni_real=([J]^-1)*Niref
+
+ x21 = x[1]-x[0]
+ y21 = y[1]-y[0]
+ z21 = z[1]-z[0]
+ x31 = x[2]-x[0]
+ y31 = y[2]-y[0]
+ z31 = z[2]-z[0]
+ x41 = x[3]-x[0]
+ y41 = y[3]-y[0]
+ z41 = z[3]-z[0]
+
+ jacob = np.array([[x21, y21, z21], [x31, y31, z31],
+ [x41, y41, z41]], dtype=np.float)
+
+ Ni = lstsq(jacob, Niref, rcond=None)[0]
+
+ return Ni
+
+
+def nedelecBasisSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, D,
+ E, F, G, H, II, JJ, K, ref_ele, points):
+ ''' This function computes the basis nedelec functions of second order
+ for a set of points in a given tetrahedral element.
+
+ :param float coefficients: a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,
+ D,E,F,G,H,II,JJ,K.
+ :param float-array ref_ele: nodal coordinates of reference element.
+ :param float-array points: spatial coordinates of the evaluation points.
+ :return: basis nedelec functions of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Number of points
+ size = points.shape
+ if len(size) == 2: # More than one point
+ nPoints = size[1]
+ elif len(size) == 1: # One point
+ nPoints = 1
+
+ # Number of dimensions
+ nDimensions = 3
+
+ # Second order ele
+ secondOrderEdgeElement = 20
+
+ # Allocate
+ basis = np.zeros((nDimensions, secondOrderEdgeElement, nPoints),
+ dtype=np.float)
+
+ # Get reference element coordinates
+ xref = ref_ele[0, :]
+ yref = ref_ele[1, :]
+ zref = ref_ele[2, :]
+
+ # Compute nedelec basis functions of second order for all points
+ if nPoints == 1: # One point
+ for iPoint in np.arange(nPoints):
+ r = points
+
+ # Basis funtions for iPoint|
+ basis[:, :, iPoint] = NiTetrahedralSecondOrder(a1, a2, a3, a4,
+ b1, b2, b3, b4,
+ c1, c2, c3, c4,
+ D, E, F, G, H,
+ II, JJ, K, xref,
+ yref, zref, r)
+ else: # More than one point
+ for iPoint in np.arange(nPoints):
+ r = points[:, iPoint]
+
+ # Basis funtions for iPoint|
+ basis[:, :, iPoint] = NiTetrahedralSecondOrder(a1, a2, a3, a4,
+ b1, b2, b3, b4,
+ c1, c2, c3, c4,
+ D, E, F, G, H,
+ II, JJ, K, xref,
+ yref, zref, r)
+
+ return basis
+
+
+def computeMassMatrixSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3,
+ c4, D, E, F, G, H, II, JJ, K, ref_ele, GR,
+ signs, DetJacob, Wi, rx, ry, rz, ngaussP):
+ ''' Compute mass matrix for tetrahedral edge elements of second order.
+
+ :param float coefficients: a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,D,E,F,G,
+ H,II,JJ,K.
+ :param float-array ref_ele: nodal coordinates of reference element.
+ :param float-array GR: tensor.
+ :param int-array signs: dofs signs.
+ :param float DetJacob: determinant of the jacobian.
+ :param float Wi: gauss weigths.
+ :param float-array rx: x-coordinates of gauss points.
+ :param float-array ry: y-coordinates of gauss points.
+ :param float-array rz: z-coordinates of gauss points.
+ :param int ngaussP: number of gauss points.
+ :return: mass matrix for edge element of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Second order ele
+ secondOrderEdgeElement = 20
+
+ # Get reference element coordinates
+ xref = ref_ele[0, :]
+ yref = ref_ele[1, :]
+ zref = ref_ele[2, :]
+
+ # Allocate
+ Me = np.zeros((secondOrderEdgeElement, secondOrderEdgeElement),
+ dtype=np.float)
+
+ # Mass matrix computation
+ r = np.zeros(3, dtype=np.float)
+ for iPoint in np.arange(ngaussP):
+ r[0] = rx[iPoint]
+ r[1] = ry[iPoint]
+ r[2] = rz[iPoint]
+
+ Ni = NiTetrahedralSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4,
+ c1, c2, c3, c4, D, E, F, G, H,
+ II, JJ, K, xref, yref, zref, r)
+ nix = Ni[0, :]
+ niy = Ni[1, :]
+ niz = Ni[2, :]
+
+ for ii in np.arange(secondOrderEdgeElement):
+ for jj in np.arange(secondOrderEdgeElement):
+ Me[ii, jj] += Wi[iPoint]*((GR[0, 0] * nix[ii]*nix[jj] +
+ GR[0, 1] * (nix[ii]*niy[jj] +
+ niy[ii]*nix[jj]) +
+ GR[1, 1] * niy[ii]*niy[jj] +
+ GR[0, 2] * (nix[ii]*niz[jj] +
+ niz[ii]*nix[jj]) +
+ GR[1, 2] * (niy[ii]*niz[jj] +
+ niz[ii]*niy[jj]) +
+ GR[2, 2] * niz[ii]*niz[jj]) *
+ signs[ii]*signs[jj])
+
+ Me = Me*DetJacob*(1./6.)
+
+ return Me
+
+
+def computeDerivativesSecondOrder(a2, a3, a4, b2, b3, b4, c2, c3, c4,
+ D, E, F, G, H, II, JJ, K, point):
+ ''' Compute partial derivatives of basis functions for tetrahedral edge
+ elements of second order (reference element)
+
+ :param float coefficients: a2,a3,a4,b2,b3,b4,c2,c3,c4,D,E,F,G,H,II,JJ,K.
+ :param float-array point: coordinates of the gaussian point.
+ :return: partial derivatives for edge element of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Point coordinates
+ x = point[0]
+ y = point[1]
+ z = point[2]
+
+ # dxNix
+ dxNix = a2 - F*y - G*z
+
+ # dxNiy
+ dxNiy = b2 + 2.*F*x - D*y - JJ*z + K*z
+
+ # dxNiz
+ dxNiz = c2 + 2.*G*x - K*y - H*z
+
+ # dyNix
+ dyNix = a3 - F*x + 2.*D*y + JJ*z
+
+ # dyNiy
+ dyNiy = b3 - D*x - E*z
+
+ # dyNiz
+ dyNiz = c3 - K*x + 2.*E*y - II*z
+
+ # dzNix
+ dzNix = a4 - G*x + JJ*y + 2.*H*z
+
+ # dzNiy
+ dzNiy = b4 - JJ*x + K*x - E*y + 2.*II*z
+
+ # dzNiz
+ dzNiz = c4 - H*x - II*y
+
+ return dxNix, dxNiy, dxNiz, dyNix, dyNiy, dyNiz, dzNix, dzNiy, dzNiz
+
+
+def computeStiffnessMatrixSecondOrder(a2, a3, a4, b2, b3, b4, c2, c3, c4,
+ D, E, F, G, H, II, JJ, K, invjj, signs,
+ DetJacob, Wi, rx, ry, rz, ngaussP):
+ ''' Compute stiffness matrix for tetrahedral edge elements of second order.
+
+ :param float coefficients: a2,a3,a4,b2,b3,b4,c2,c3,c4,D,E,F,G,H,II,JJ,K.
+ :param float-array invjj: inverse jacobian.
+ :param int-array signs: dofs signs.
+ :param float DetJacob: determinant of the jacobian.
+ :param float Wi: gauss weigths.
+ :param float-array rx: x-coordinates of gauss points.
+ :param float-array ry: y-coordinates of gauss points.
+ :param float-array rz: z-coordinates of gauss points.
+ :param int ngaussP: number of gauss points.
+ :return: stiffness matrix for edge element of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Second order element
+ secondOrderEdgeElement = 20
+
+ # Allocate
+ Ke = np.zeros((secondOrderEdgeElement, secondOrderEdgeElement),
+ dtype=np.float)
+
+ # Tensor computation
+ fr = np.eye(3, dtype=np.float)
+ invfr = inv(fr)
+
+ tmp1 = np.array([[0, 0, 0], [0, 0, 1], [0, -1, 0]], dtype=np.float)
+ A = np.matmul(invjj.transpose(), np.matmul(tmp1, invjj))
+
+ tmp1 = np.array([[0, 0, -1], [0, 0, 0], [1, 0, 0]], dtype=np.float)
+ B = np.matmul(invjj.transpose(), np.matmul(tmp1, invjj))
+
+ tmp1 = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 0]], dtype=np.float)
+ C = np.matmul(invjj.transpose(), np.matmul(tmp1, invjj))
+
+ # Stiffness matrix computation
+ r = np.zeros(3, dtype=np.float)
+ for iPoint in np.arange(ngaussP):
+ r[0] = rx[iPoint]
+ r[1] = ry[iPoint]
+ r[2] = rz[iPoint]
+
+ [_, dxNiy, dxNiz,
+ dyNix, _, dyNiz,
+ dzNix, dzNiy, _] = computeDerivativesSecondOrder(a2, a3, a4, b2, b3,
+ b4, c2, c3, c4, D,
+ E, F, G, H,
+ II, JJ, K, r)
+
+ rotNix = (A[0, 1]*dxNiy + A[0, 2]*dxNiz -
+ A[0, 1]*dyNix + A[1, 2]*dyNiz -
+ A[0, 2]*dzNix - A[1, 2]*dzNiy)
+ rotNiy = (B[0, 1]*dxNiy + B[0, 2]*dxNiz -
+ B[0, 1]*dyNix + B[1, 2]*dyNiz -
+ B[0, 2]*dzNix - B[1, 2]*dzNiy)
+ rotNiz = (C[0, 1]*dxNiy + C[0, 2]*dxNiz -
+ C[0, 1]*dyNix + C[1, 2]*dyNiz -
+ C[0, 2]*dzNix - C[1, 2]*dzNiy)
+
+ for ii in np.arange(secondOrderEdgeElement):
+ for jj in np.arange(secondOrderEdgeElement):
+ Ke[ii, jj] += Wi[iPoint]*((invfr[0, 0]*rotNix[ii]*rotNix[jj] +
+ invfr[0, 1]*(rotNix[ii] *
+ rotNiy[jj] +
+ rotNiy[ii] *
+ rotNix[jj]) +
+ invfr[1, 1]*rotNiy[ii]*rotNiy[jj] +
+ invfr[0, 2]*(rotNix[ii] *
+ rotNiz[jj] +
+ rotNiz[ii] *
+ rotNix[jj]) +
+ invfr[1, 2]*(rotNiy[ii] *
+ rotNiz[jj] +
+ rotNiz[ii] *
+ rotNiy[jj]) +
+ invfr[2, 2]*rotNiz[ii]*rotNiz[jj]) *
+ signs[ii]*signs[jj])
+
+ Ke = Ke*DetJacob*(1./6.)
+
+ return Ke
+
+
+def polynomialProduct(poly1, poly2):
+ ''' Compute the product of two polynomials according to convention for
+ tetrahedral edge element of third order.
+
+ :param float-array poly1: first polynomial to be computed.
+ :param float-array poly2: second polynomial to be computed.
+ :return: polynomial product.
+ :rtype: ndarray
+ '''
+
+ # Allocate
+ polProd = np.zeros((5, 5), dtype=np.float)
+
+ for abs1 in np.arange(5):
+ for ord1 in np.arange(5-abs1):
+ for abs2 in np.arange(5):
+ for ord2 in np.arange(5-abs2):
+ if (poly1[abs1, ord1] != 0):
+ if (poly2[abs2, ord2] != 0):
+ indx1 = abs1+abs2
+ indx2 = ord1+ord2
+ polProd[indx1, indx2] = (polProd[indx1, indx2] +
+ poly1[abs1, ord1] *
+ poly2[abs2, ord2])
+ return polProd
+
+
+def componentProductPolynomial(nxNi_term, function_n, component_q, face):
+ ''' Compute the product for a given component of nxNi.
+
+ :param float-array nxNi_term: matrix of coefficients.
+ :param float-array function_n: matrix function.
+ :param float-array component_q: id of the q component.
+ :param float-array face: face of the aforementioned parameters.
+ :return: product of nxNi, face and function_q.
+ :rtype: ndarray
+ '''
+
+ # Third order element
+ thirdOrderEdgeElement = 45
+
+ # Copy data as float
+ data_temp = nxNi_term.astype(np.float)
+
+ if (component_q != 0):
+ for coefficient in np.arange(1, thirdOrderEdgeElement+1):
+ indx1 = (coefficient-1)*5+1
+ indx2 = coefficient*5
+ coeff_Ni = data_temp[:, indx1-1:indx2]
+
+ coeff_aux_indep = np.zeros((5, 5), dtype=np.float)
+ if (function_n[0, 0] != 0):
+ output = 0
+ for abs in np.arange(5):
+ for ord in np.arange(5-abs):
+ if (coeff_Ni[abs, ord] != 0):
+ coeff_aux_indep[abs, ord] = (function_n[0, 0] *
+ coeff_Ni[abs, ord] *
+ component_q)
+ if (face != 4):
+ output = 1
+ break
+ if (output == 1):
+ break
+
+ coeff_aux_abs = np.zeros((5, 5), dtype=np.float)
+ if (function_n[1, 0] != 0):
+ output = 0
+ for abs in np.arange(5):
+ for ord in np.arange(5-abs):
+ if (coeff_Ni[abs, ord] != 0):
+ coeff_aux_abs[abs+1, ord] = (function_n[1, 0] *
+ coeff_Ni[abs, ord] *
+ component_q)
+ if (face != 4):
+ output = 1
+ break
+ if (output == 1):
+ break
+
+ coeff_aux_ord = np.zeros((5, 5), dtype=np.float)
+ if (function_n[0, 1] != 0):
+ output = 0
+ for abs in np.arange(5):
+ for ord in np.arange(5-abs):
+ if (coeff_Ni[abs, ord] != 0):
+ coeff_aux_ord[abs, ord+1] = (function_n[0, 1] *
+ coeff_Ni[abs, ord] *
+ component_q)
+ if (face != 4):
+ output = 1
+ break
+ if (output == 1):
+ break
+
+ tmp = coeff_aux_indep + coeff_aux_abs + coeff_aux_ord
+ indx1_1 = ((coefficient-1)*5+1)-1
+ indx2_1 = coefficient*5
+ data_temp[:, indx1_1:indx2_1] = tmp
+
+ product_result = data_temp
+ else:
+ product_result = np.zeros((5, 225), dtype=np.float)
+
+ return product_result
+
+
+def analyticIntegral(input_functions):
+ ''' Compute the integrals of the product of monomials in the reference
+ triangle.
+
+ :param float-array input_functions: matrix of functions with coefficients
+ of Ni before integration process.
+ :return: integrals of the product of monomials in the reference triangle.
+ :rtype: ndarray
+ '''
+
+ # Third order element
+ thirdOrderEdgeElement = 45
+
+ integral_tab = np.array([[1/2, 1/6, 1/12, 1/20, 1/30],
+ [1/6, 1/24, 1/60, 1/120, 0],
+ [1/12, 1/60, 1/180, 0, 0],
+ [1/20, 1/120, 0, 0, 0],
+ [1/30, 0, 0, 0, 0]], dtype=np.float)
+ # Allocate
+ integral_res = np.zeros((thirdOrderEdgeElement), dtype=np.float)
+
+ for coefficient in np.arange(1, thirdOrderEdgeElement+1):
+ indx1 = (coefficient-1)*5+1
+ indx2 = coefficient*5
+ aux = input_functions[:, indx1-1:indx2]
+
+ for abs in np.arange(5):
+ for ord in np.arange(5-abs):
+ aux[abs, ord] = aux[abs, ord]*integral_tab[abs, ord]
+
+ integral_res[coefficient-1] = 0
+
+ for abs in np.arange(5):
+ for ord in np.arange(5-abs):
+ integral_res[coefficient-1] = (integral_res[coefficient-1] +
+ aux[abs, ord])
+ return integral_res
+
+
+def computeCoefficientsThirdOrder(qface1, qface2, qface3, qface4):
+ ''' Compute the coefficients for edge basis functions of third order
+ on reference element.
+
+ :param float-array qface1: vector q on face 1.
+ :param float-array qface2: vector q on face 2.
+ :param float-array qface3: vector q on face 3.
+ :param float-array qface4: vector q on face 4.
+ :return: coefficients.
+ :rtype: float.
+
+ .. note: References:\n
+ Garcia-Castillo, L. E., Ruiz-Genovés, A. J., Gómez-Revuelto, I.,
+ Salazar-Palma, M., & Sarkar, T. K. (2002). Third-order Nédélec
+ curl-conforming finite element. IEEE transactions on magnetics,
+ 38(5), 2370-2372.
+ '''
+ # Third order element
+ thirdOrderEdgeElement = 45
+
+ # Definition of q functions
+ q_functions = np.array([[1, -1, 0, 0, 0, 1],
+ [-1, 0, 1, 0, 0, 0]], dtype=np.float)
+
+ # Definition of q functions on faces
+ q_faces_ref = np.hstack((qface1, qface2, qface3, qface4))
+
+ # Definition of q functions on volume
+ q_volumen_ref = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float)
+
+ # Tangential unitary vectors for each edge (18 dofs)
+ Taui = np.array([[1, 1, 1, -1, -1, -1, 0, 0, 0,
+ 0, 0, 0, -1, -1, -1, 0, 0, 0],
+ [0, 0, 0, 1, 1, 1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, -1, -1, -1],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1]], dtype=np.float)
+
+ # Normalization to unitary module
+ for idof in np.arange(18):
+ Taui[:, idof] = Taui[:, idof]/norm(Taui[:, idof])
+
+ # Edge length on reference element
+ length = np.array([1, np.sqrt(2), 1, 1, np.sqrt(2), np.sqrt(2)],
+ dtype=np.float)
+
+ # Definition of the position of the 18 nodes of the edges. "a" is the
+ # distance to the center of the edge of the integration points for the
+ # interval [-1,1]. For our length edge Li => points located at
+ # "(Li / 2) * a" from the center of the edge. In the case that concerns
+ # us, tetrahedron of order 3, the third point of integration is the center
+ # of the edge. a = sqrt (3/5) in the case of third-order Gauss integration.
+ a = 0.7745966692
+
+ # Auxiliar varaible for spatial coordinates of the nodes
+ aux1 = (1.-a)/2.
+ aux2 = 1./2.
+ aux3 = (1.+a)/2.
+
+ # Nodei contains coordinates of the 18 nodes on edges
+ Nodei = np.array([[aux1, aux2, aux3, aux3, aux2, aux1,
+ 0, 0, 0, 0, 0, 0, aux3, aux2, aux1, 0, 0, 0],
+ [0, 0, 0, aux1, aux2, aux3, aux3, aux2, aux1,
+ 0, 0, 0, 0, 0, 0, aux3, aux2, aux1],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, aux1, aux2, aux3,
+ aux1, aux2, aux3, aux1, aux2, aux3]], dtype=np.float)
+
+ # Clear variables
+ del aux1, aux2
+
+ # Definition of the first 18 rows of the coefficient matrix of the system
+ # of equations to be presented. These equations are those that come from
+ # the imposition of the dofs of the edges.
+ matrix = np.zeros((thirdOrderEdgeElement, thirdOrderEdgeElement),
+ dtype=np.float)
+
+ # Integrals over edges
+ for idof in np.arange(18):
+ tmp = np.hstack((Taui[0, idof], Nodei[0, idof]*Taui[0, idof],
+ Nodei[1, idof]*Taui[0, idof],
+ Nodei[2, idof]*Taui[0, idof],
+ (Nodei[0, idof]**2)*Taui[0, idof],
+ (Nodei[1, idof]**2)*Taui[0, idof],
+ (Nodei[2, idof]**2)*Taui[0, idof],
+ Nodei[0, idof]*Nodei[1, idof]*Taui[0, idof],
+ Nodei[0, idof]*Nodei[2, idof]*Taui[0, idof],
+ Nodei[1, idof]*Nodei[2, idof]*Taui[0, idof],
+ Taui[1, idof], Nodei[0, idof]*Taui[1, idof],
+ Nodei[1, idof]*Taui[1, idof],
+ Nodei[2, idof]*Taui[1, idof],
+ (Nodei[0, idof]**2)*Taui[1, idof],
+ (Nodei[1, idof]**2)*Taui[1, idof],
+ (Nodei[2, idof]**2)*Taui[1, idof],
+ Nodei[0, idof]*Nodei[1, idof]*Taui[1, idof],
+ Nodei[0, idof]*Nodei[2, idof]*Taui[1, idof],
+ Nodei[1, idof]*Nodei[2, idof]*Taui[1, idof],
+ Taui[2, idof], Nodei[0, idof]*Taui[2, idof],
+ Nodei[1, idof]*Taui[2, idof],
+ Nodei[2, idof]*Taui[2, idof],
+ (Nodei[0, idof]**2)*Taui[2, idof],
+ (Nodei[1, idof]**2)*Taui[2, idof],
+ (Nodei[2, idof]**2)*Taui[2, idof],
+ Nodei[0, idof]*Nodei[1, idof]*Taui[2, idof],
+ Nodei[0, idof]*Nodei[2, idof]*Taui[2, idof],
+ Nodei[1, idof]*Nodei[2, idof]*Taui[2, idof],
+ (Nodei[0, idof]**2)*Nodei[1, idof]*Taui[0, idof] -
+ (Nodei[0, idof]**3)*Taui[1, idof],
+ (Nodei[1, idof]**2)*Nodei[0, idof]*Taui[1, idof] -
+ (Nodei[1, idof]**3)*Taui[0, idof],
+ (Nodei[2, idof]**2)*Nodei[0, idof]*Taui[2, idof] -
+ (Nodei[2, idof]**3)*Taui[0, idof],
+ (Nodei[0, idof]**2)*Nodei[2, idof]*Taui[0, idof] -
+ (Nodei[0, idof]**3)*Taui[2, idof],
+ (Nodei[2, idof]**2)*Nodei[1, idof]*Taui[2, idof] -
+ (Nodei[2, idof]**3)*Taui[1, idof],
+ (Nodei[1, idof]**2)*Nodei[2, idof]*Taui[1, idof] -
+ (Nodei[1, idof]**3)*Taui[2, idof],
+ (Nodei[1, idof]**2)*Nodei[0, idof]*Taui[0, idof] -
+ (Nodei[0, idof]**2)*Nodei[1, idof]*Taui[1, idof],
+ (Nodei[2, idof]**2)*Nodei[0, idof]*Taui[0, idof] -
+ (Nodei[0, idof]**2)*Nodei[2, idof]*Taui[2, idof],
+ (Nodei[2, idof]**2)*Nodei[1, idof]*Taui[1, idof] -
+ (Nodei[1, idof]**2)*Nodei[2, idof]*Taui[2, idof],
+ Nodei[0, idof]*Nodei[1, idof] *
+ Nodei[2, idof]*Taui[0, idof] -
+ (Nodei[0, idof]**2)*Nodei[2, idof]*Taui[1, idof],
+ (Nodei[0, idof]**2)*Nodei[2, idof]*Taui[1, idof] -
+ (Nodei[0, idof]**2)*Nodei[1, idof]*Taui[2, idof],
+ Nodei[0, idof]*Nodei[1, idof] *
+ Nodei[2, idof]*Taui[1, idof] -
+ (Nodei[1, idof]**2)*Nodei[2, idof]*Taui[0, idof],
+ (Nodei[1, idof]**2)*Nodei[2, idof]*Taui[0, idof] -
+ (Nodei[1, idof]**2)*Nodei[0, idof]*Taui[2, idof],
+ Nodei[0, idof]*Nodei[1, idof] *
+ Nodei[2, idof]*Taui[2, idof] -
+ (Nodei[2, idof]**2)*Nodei[1, idof]*Taui[0, idof],
+ (Nodei[2, idof]**2)*Nodei[1, idof]*Taui[0, idof] -
+ (Nodei[2, idof]**2)*Nodei[0, idof]*Taui[1, idof]))
+
+ matrix[idof, :] = tmp
+
+ # Integrals over faces
+ # Definition of a matrix zeros (5,5) for the coefficients that do not
+ # appear in the definition of Ni particularized in each one of the faces
+ # and that can not be ignored so that when stacking matrices all result
+ # with the same size.
+ null_values = np.zeros((5, 5), dtype=np.float)
+
+ # Definition of x-component for Ni on face 1
+ Ni_x_face1_a1 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_a1[0, 0] = 1
+ Ni_x_face1_a2 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_a2[1, 0] = 1
+ Ni_x_face1_a3 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_a3[0, 1] = 1
+ Ni_x_face1_a5 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_a5[2, 0] = 1
+ Ni_x_face1_a6 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_a6[0, 2] = 1
+ Ni_x_face1_a8 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_a8[1, 1] = 1
+
+ Ni_x_face1_D = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_D[2, 1] = 1
+ Ni_x_face1_E = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_E[0, 3] = -1
+ Ni_x_face1_J = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face1_J[1, 2] = 1
+
+ Ni_x_face1 = np.hstack((Ni_x_face1_a1, Ni_x_face1_a2, Ni_x_face1_a3,
+ null_values, Ni_x_face1_a5, Ni_x_face1_a6,
+ null_values, Ni_x_face1_a8, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, Ni_x_face1_D, Ni_x_face1_E,
+ null_values, null_values, null_values, null_values,
+ Ni_x_face1_J, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values))
+
+ # Definition of y-component for Ni on face 1
+ Ni_y_face1_b1 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_b1[0, 0] = 1
+ Ni_y_face1_b2 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_b2[1, 0] = 1
+ Ni_y_face1_b3 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_b3[0, 1] = 1
+ Ni_y_face1_b5 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_b5[2, 0] = 1
+ Ni_y_face1_b6 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_b6[0, 2] = 1
+ Ni_y_face1_b8 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_b8[1, 1] = 1
+
+ Ni_y_face1_D = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_D[3, 0] = -1
+ Ni_y_face1_E = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_E[1, 2] = 1
+ Ni_y_face1_J = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face1_J[2, 1] = -1
+
+ Ni_y_face1 = np.hstack((null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_y_face1_b1,
+ Ni_y_face1_b2, Ni_y_face1_b3, null_values,
+ Ni_y_face1_b5, Ni_y_face1_b6, null_values,
+ Ni_y_face1_b8, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_y_face1_D,
+ Ni_y_face1_E, null_values, null_values,
+ null_values, null_values, Ni_y_face1_J,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values))
+
+ # Definition of y-component for Ni on face 2
+ Ni_y_face2_b1 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_b1[0, 0] = 1
+ Ni_y_face2_b3 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_b3[1, 0] = 1
+ Ni_y_face2_b4 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_b4[0, 1] = 1
+ Ni_y_face2_b6 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_b6[2, 0] = 1
+ Ni_y_face2_b7 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_b7[0, 2] = 1
+ Ni_y_face2_b10 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_b10[1, 1] = 1
+
+ Ni_y_face2_H = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_H[0, 3] = -1
+ Ni_y_face2_I = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_I[2, 1] = 1
+ Ni_y_face2_L = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face2_L[1, 2] = 1
+
+ Ni_y_face2 = np.hstack((null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_y_face2_b1,
+ null_values, Ni_y_face2_b3, Ni_y_face2_b4,
+ null_values, Ni_y_face2_b6, Ni_y_face2_b7,
+ null_values, null_values, Ni_y_face2_b10,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_y_face2_H,
+ Ni_y_face2_I, null_values, null_values,
+ Ni_y_face2_L, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values))
+
+ # Definition of z-component for Ni on face 2
+ Ni_z_face2_c1 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_c1[0, 0] = 1
+ Ni_z_face2_c3 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_c3[1, 0] = 1
+ Ni_z_face2_c4 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_c4[0, 1] = 1
+ Ni_z_face2_c6 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_c6[2, 0] = 1
+ Ni_z_face2_c7 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_c7[0, 2] = 1
+ Ni_z_face2_c10 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_c10[1, 1] = 1
+
+ Ni_z_face2_H = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_H[1, 2] = 1
+ Ni_z_face2_I = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_I[3, 0] = -1
+ Ni_z_face2_L = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face2_L[2, 1] = -1
+
+ Ni_z_face2 = np.hstack((null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ Ni_z_face2_c1, null_values, Ni_z_face2_c3,
+ Ni_z_face2_c4, null_values, Ni_z_face2_c6,
+ Ni_z_face2_c7, null_values, null_values,
+ Ni_z_face2_c10, null_values, null_values,
+ null_values, null_values, Ni_z_face2_H,
+ Ni_z_face2_I, null_values, null_values,
+ Ni_z_face2_L, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values))
+
+ # Definition of x-component for Ni on face 3
+ Ni_x_face3_a1 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_a1[0, 0] = 1
+ Ni_x_face3_a2 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_a2[0, 1] = 1
+ Ni_x_face3_a4 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_a4[1, 0] = 1
+ Ni_x_face3_a5 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_a5[0, 2] = 1
+ Ni_x_face3_a7 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_a7[2, 0] = 1
+ Ni_x_face3_a9 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_a9[1, 1] = 1
+
+ Ni_x_face3_F = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_F[3, 0] = -1
+ Ni_x_face3_G = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_G[1, 2] = 1
+ Ni_x_face3_K = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face3_K[2, 1] = 1
+
+ Ni_x_face3 = np.hstack((Ni_x_face3_a1, Ni_x_face3_a2, null_values,
+ Ni_x_face3_a4, Ni_x_face3_a5, null_values,
+ Ni_x_face3_a7, null_values, Ni_x_face3_a9,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ Ni_x_face3_F, Ni_x_face3_G, null_values,
+ null_values, null_values, Ni_x_face3_K,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values))
+
+ # Definition of z-component for Ni on face 3
+ Ni_z_face3_c1 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_c1[0, 0] = 1
+ Ni_z_face3_c2 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_c2[0, 1] = 1
+ Ni_z_face3_c4 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_c4[1, 0] = 1
+ Ni_z_face3_c5 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_c5[0, 2] = 1
+ Ni_z_face3_c7 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_c7[2, 0] = 1
+ Ni_z_face3_c9 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_c9[1, 1] = 1
+
+ Ni_z_face3_F = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_F[2, 1] = 1
+ Ni_z_face3_G = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_G[0, 3] = -1
+ Ni_z_face3_K = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face3_K[1, 2] = -1
+
+ Ni_z_face3 = np.hstack((null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ Ni_z_face3_c1, Ni_z_face3_c2, null_values,
+ Ni_z_face3_c4, Ni_z_face3_c5, null_values,
+ Ni_z_face3_c7, null_values, Ni_z_face3_c9,
+ null_values, null_values, null_values,
+ Ni_z_face3_F, Ni_z_face3_G, null_values,
+ null_values, null_values, Ni_z_face3_K,
+ null_values, null_values, null_values,
+ null_values, null_values,
+ null_values, null_values))
+
+ # For the computation of the surface integral in the face 4, we are
+ # going to do it translating it to the calculation of the integral on the
+ # domain of its projection in the XY plane, and substituting z for the
+ # value in the surface, i.e., z = 1-xy, taking into account that the
+ # surface differential ds, is transformed into dxdy/cos (gamma), where
+ # gamma is the director cosine with the z axis. For z = 1-x-y
+ # cos(gamma)= 1/sqrt(3); With the help of the routine polynomialProduct
+ # we will develop all the terms. We will define first the equivalent
+ # terms of z(z), z^2 (z_2) and z^3 (z_3) that we will need.
+ z = np.zeros((5, 5), dtype=np.float)
+ z[0, 0] = 1
+ z[1, 0] = -1
+ z[0, 1] = -1
+ z_2 = polynomialProduct(z, z)
+ z_3 = polynomialProduct(z_2, z)
+
+ # Definition of x-component for Ni on face 4
+ Ni_x_face4_a1 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a1[0, 0] = 1
+ Ni_x_face4_a2 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a2[1, 0] = 1
+ Ni_x_face4_a3 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a3[0, 1] = 1
+ Ni_x_face4_a4 = z
+ Ni_x_face4_a5 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a5[2, 0] = 1
+ Ni_x_face4_a6 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a6[0, 2] = 1
+ Ni_x_face4_a7 = z_2
+ Ni_x_face4_a8 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a8[1, 1] = 1
+
+ Ni_x_face4_a9 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a9[1, 0] = 1
+ Ni_x_face4_a9 = polynomialProduct(Ni_x_face4_a9, z)
+
+ Ni_x_face4_a10 = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_a10[0, 1] = 1
+ Ni_x_face4_a10 = polynomialProduct(Ni_x_face4_a10, z)
+
+ Ni_x_face4_D = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_D[2, 1] = 1
+ Ni_x_face4_E = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_E[0, 3] = -1
+ Ni_x_face4_F = -z_3
+
+ Ni_x_face4_G = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_G[2, 0] = 1
+ Ni_x_face4_G = polynomialProduct(Ni_x_face4_G, z)
+
+ Ni_x_face4_J = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_J[1, 2] = 1
+
+ Ni_x_face4_K = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_K[1, 0] = 1
+ Ni_x_face4_K = polynomialProduct(Ni_x_face4_K, z_2)
+
+ Ni_x_face4_M = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_M[1, 1] = 1
+ Ni_x_face4_M = polynomialProduct(Ni_x_face4_M, z)
+
+ Ni_x_face4_O = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_O[0, 2] = 1
+ Ni_x_face4_O = -polynomialProduct(Ni_x_face4_O, z)
+
+ Ni_x_face4_P = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_P[0, 2] = 1
+ Ni_x_face4_P = polynomialProduct(Ni_x_face4_P, z)
+
+ Ni_x_face4_Q = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_Q[0, 1] = 1
+ Ni_x_face4_Q = -polynomialProduct(Ni_x_face4_Q, z_2)
+
+ Ni_x_face4_R = np.zeros((5, 5), dtype=np.float)
+ Ni_x_face4_R[0, 1] = 1
+ Ni_x_face4_R = polynomialProduct(Ni_x_face4_R, z_2)
+
+ Ni_x_face4 = np.hstack((Ni_x_face4_a1, Ni_x_face4_a2, Ni_x_face4_a3,
+ Ni_x_face4_a4, Ni_x_face4_a5, Ni_x_face4_a6,
+ Ni_x_face4_a7, Ni_x_face4_a8, Ni_x_face4_a9,
+ Ni_x_face4_a10, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_x_face4_D,
+ Ni_x_face4_E, Ni_x_face4_F, Ni_x_face4_G,
+ null_values, null_values, Ni_x_face4_J,
+ Ni_x_face4_K, null_values, Ni_x_face4_M,
+ null_values, Ni_x_face4_O, Ni_x_face4_P,
+ Ni_x_face4_Q, Ni_x_face4_R))
+
+ # Definition of y-component for Ni on face 4
+ Ni_y_face4_b1 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b1[0, 0] = 1
+ Ni_y_face4_b2 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b2[1, 0] = 1
+ Ni_y_face4_b3 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b3[0, 1] = 1
+ Ni_y_face4_b4 = z
+ Ni_y_face4_b5 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b5[2, 0] = 1
+ Ni_y_face4_b6 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b6[0, 2] = 1
+ Ni_y_face4_b7 = z_2
+ Ni_y_face4_b8 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b8[1, 1] = 1
+
+ Ni_y_face4_b9 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b9[1, 0] = 1
+ Ni_y_face4_b9 = polynomialProduct(Ni_y_face4_b9, z)
+
+ Ni_y_face4_b10 = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_b10[0, 1] = 1
+ Ni_y_face4_b10 = polynomialProduct(Ni_y_face4_b10, z)
+
+ Ni_y_face4_D = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_D[3, 0] = -1
+ Ni_y_face4_E = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_E[1, 2] = 1
+ Ni_y_face4_H = -z_3
+
+ Ni_y_face4_I = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_I[0, 2] = 1
+ Ni_y_face4_I = polynomialProduct(Ni_y_face4_I, z)
+
+ Ni_y_face4_J = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_J[2, 1] = -1
+
+ Ni_y_face4_L = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_L[0, 1] = 1
+ Ni_y_face4_L = polynomialProduct(Ni_y_face4_L, z_2)
+
+ Ni_y_face4_M = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_M[2, 0] = 1
+ Ni_y_face4_M = -polynomialProduct(Ni_y_face4_M, z)
+
+ Ni_y_face4_N = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_N[2, 0] = 1
+ Ni_y_face4_N = polynomialProduct(Ni_y_face4_N, z)
+
+ Ni_y_face4_O = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_O[1, 1] = 1
+ Ni_y_face4_O = polynomialProduct(Ni_y_face4_O, z)
+
+ Ni_y_face4_R = np.zeros((5, 5), dtype=np.float)
+ Ni_y_face4_R[1, 0] = 1
+ Ni_y_face4_R = -polynomialProduct(Ni_y_face4_R, z_2)
+
+ Ni_y_face4 = np.hstack((null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_y_face4_b1,
+ Ni_y_face4_b2, Ni_y_face4_b3, Ni_y_face4_b4,
+ Ni_y_face4_b5, Ni_y_face4_b6, Ni_y_face4_b7,
+ Ni_y_face4_b8, Ni_y_face4_b9, Ni_y_face4_b10,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, Ni_y_face4_D,
+ Ni_y_face4_E, null_values, null_values,
+ Ni_y_face4_H, Ni_y_face4_I, Ni_y_face4_J,
+ null_values, Ni_y_face4_L, Ni_y_face4_M,
+ Ni_y_face4_N, Ni_y_face4_O, null_values,
+ null_values, Ni_y_face4_R))
+
+ # Definition of z-component for Ni on face 4
+ Ni_z_face4_c1 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c1[0, 0] = 1
+ Ni_z_face4_c2 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c2[1, 0] = 1
+ Ni_z_face4_c3 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c3[0, 1] = 1
+ Ni_z_face4_c4 = z
+ Ni_z_face4_c5 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c5[2, 0] = 1
+ Ni_z_face4_c6 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c6[0, 2] = 1
+ Ni_z_face4_c7 = z_2
+ Ni_z_face4_c8 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c8[1, 1] = 1
+
+ Ni_z_face4_c9 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c9[1, 0] = 1
+ Ni_z_face4_c9 = polynomialProduct(Ni_z_face4_c9, z)
+
+ Ni_z_face4_c10 = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_c10[0, 1] = 1
+ Ni_z_face4_c10 = polynomialProduct(Ni_z_face4_c10, z)
+
+ Ni_z_face4_F = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_F[1, 0] = 1
+ Ni_z_face4_F = polynomialProduct(Ni_z_face4_F, z_2)
+
+ Ni_z_face4_G = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_G[3, 0] = -1
+
+ Ni_z_face4_H = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_H[0, 1] = 1
+ Ni_z_face4_H = polynomialProduct(Ni_z_face4_H, z_2)
+
+ Ni_z_face4_I = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_I[0, 3] = -1
+
+ Ni_z_face4_K = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_K[2, 0] = 1
+ Ni_z_face4_K = -polynomialProduct(Ni_z_face4_K, z)
+
+ Ni_z_face4_L = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_L[0, 2] = 1
+ Ni_z_face4_L = -polynomialProduct(Ni_z_face4_L, z)
+
+ Ni_z_face4_N = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_N[2, 1] = -1
+ Ni_z_face4_P = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_P[1, 2] = -1
+
+ Ni_z_face4_Q = np.zeros((5, 5), dtype=np.float)
+ Ni_z_face4_Q[1, 1] = 1
+ Ni_z_face4_Q = polynomialProduct(Ni_z_face4_Q, z)
+
+ Ni_z_face4 = np.hstack((null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ null_values, null_values, null_values, null_values,
+ Ni_z_face4_c1, Ni_z_face4_c2, Ni_z_face4_c3,
+ Ni_z_face4_c4, Ni_z_face4_c5, Ni_z_face4_c6,
+ Ni_z_face4_c7, Ni_z_face4_c8, Ni_z_face4_c9,
+ Ni_z_face4_c10, null_values, null_values,
+ Ni_z_face4_F, Ni_z_face4_G, Ni_z_face4_H,
+ Ni_z_face4_I, null_values, Ni_z_face4_K,
+ Ni_z_face4_L, null_values, Ni_z_face4_N,
+ null_values, Ni_z_face4_P, Ni_z_face4_Q,
+ null_values))
+
+ # As a previous step to the integration, we must obtain the matrices
+ # of: n(normal to the face) x Ni(particularized in the face). Then, we
+ # can make the scalar product with the corresponding q's.
+ null_values2 = np.zeros((5, 225), dtype=np.float)
+
+ n_face1xNi_face1 = np.vstack((Ni_y_face1, -Ni_x_face1, null_values2))
+ n_face2xNi_face2 = np.vstack((null_values2, Ni_z_face2, -Ni_y_face2))
+ n_face3xNi_face3 = np.vstack((-Ni_z_face3, null_values2, Ni_x_face3))
+ n_face4xNi_face4 = np.vstack((Ni_z_face4 - Ni_y_face4,
+ Ni_x_face4 - Ni_z_face4,
+ Ni_y_face4 - Ni_x_face4))
+
+ n_facesxNi = np.vstack((n_face1xNi_face1, n_face2xNi_face2,
+ n_face3xNi_face3, n_face4xNi_face4))
+
+ for face in np.arange(1, 5):
+ for q in np.arange(1, 3):
+ for function_N in np.arange(1, 4):
+ # Three components of n_face(face)xNi particularized to face
+ indx1 = (face-1)*15+1
+ indx2 = (face*15)
+ n_facexNi_face = n_facesxNi[indx1-1:indx2, :]
+
+ # Auxiliar for integral
+ integral_aux = np.zeros((5, 225), dtype=np.float)
+
+ for icomponent in np.arange(1, 4):
+ # Development of what I have to integrate in each face
+ # for each row of the matrix of the system of equations.
+ # n_facexNi_x*q_x+n_facexNi_y*q_y+n_facexNi_z*q_z
+
+ # Each of the parameters and counters involved in the
+ # call to componentProductPolynomail are:
+ # n_facexNi (((icomponent-1)*5+1):(5*icomponent),:): One
+ # of the 3 components of n_facexNi in the face that
+ # concerns us.
+ # Functions_q(:,2*function-1:2*function): The function
+ # (2x2 matrix) that at that moment is multiplying to q.
+ # q_faces_ref(icomponent,2*(face-1)+q): One of the 3
+ # components of the vector q.
+ v1 = n_facexNi_face[((icomponent-1)*5+1)-1:
+ (5*icomponent), :]
+ v2 = q_functions[:, (2*function_N-1)-1:2*function_N]
+ v3 = q_faces_ref[icomponent-1, (2*(face-1)+q)-1]
+ integral_aux += componentProductPolynomial(v1, v2,
+ v3, face)
+
+ # Get row of the coefficient matrix of the system of equations.
+ # These equations are those that come from the imposition of
+ # the dofs of the edges.
+ row_matrix = 19+(face-1)*6+(function_N-1)*2+(q-1)
+ matrix[row_matrix-1, :] = analyticIntegral(integral_aux)
+
+ # Integrals over volume
+ # Rows 43,44, and 45 of the coefficient matrix of the system of equations
+ # are linked to the definition of the dofs associated with the volume.
+ # We need again a matrix zeros(5,5) for the coefficients that do not
+ # appear in the definition of Ni and that can not be ignored so that when
+ # stacking matrices all result in the same size. We use "null_values"
+ # already defined for face integrals.
+ # For the computation of the volume integral, we perform the integral of
+ # Ni = f(x,y,z) between z(x,y)=0 and z(x,y)=1-xy, face 4 in the
+ # reference element. For this, we must integrate in z, which we do
+ # manually and then with the help of "polynomialProduct"
+ # develop all the terms. We will define first the term z^4(z_4)
+ # that we will need. The terms z(z), z^2(z_2) and z^3(z_3) have been
+ # defined previously for the integrals on face 4.
+ z_4 = polynomialProduct(z_3, z)
+
+ # Definition of x-component of z-integral in Ni
+ Int_en_z_Ni_x_a1 = z
+
+ Int_en_z_Ni_x_a2 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a2[1, 0] = 1
+ Int_en_z_Ni_x_a2 = polynomialProduct(Int_en_z_Ni_x_a2, z)
+
+ Int_en_z_Ni_x_a3 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a3[0, 1] = 1
+ Int_en_z_Ni_x_a3 = polynomialProduct(Int_en_z_Ni_x_a3, z)
+
+ Int_en_z_Ni_x_a4 = 1/2*z_2
+
+ Int_en_z_Ni_x_a5 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a5[2, 0] = 1
+ Int_en_z_Ni_x_a5 = polynomialProduct(Int_en_z_Ni_x_a5, z)
+
+ Int_en_z_Ni_x_a6 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a6[0, 2] = 1
+ Int_en_z_Ni_x_a6 = polynomialProduct(Int_en_z_Ni_x_a6, z)
+
+ Int_en_z_Ni_x_a7 = 1/3*z_3
+
+ Int_en_z_Ni_x_a8 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a8[1, 1] = 1
+ Int_en_z_Ni_x_a8 = polynomialProduct(Int_en_z_Ni_x_a8, z)
+
+ Int_en_z_Ni_x_a9 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a9[1, 0] = 1
+ Int_en_z_Ni_x_a9 = 1/2*polynomialProduct(Int_en_z_Ni_x_a9, z_2)
+
+ Int_en_z_Ni_x_a10 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_a10[0, 1] = 1
+ Int_en_z_Ni_x_a10 = 1/2*polynomialProduct(Int_en_z_Ni_x_a10, z_2)
+
+ Int_en_z_Ni_x_D = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_D[2, 1] = 1
+ Int_en_z_Ni_x_D = polynomialProduct(Int_en_z_Ni_x_D, z)
+
+ Int_en_z_Ni_x_E = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_E[0, 3] = 1
+ Int_en_z_Ni_x_E = -polynomialProduct(Int_en_z_Ni_x_E, z)
+
+ Int_en_z_Ni_x_F = -1/4*z_4
+
+ Int_en_z_Ni_x_G = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_G[2, 0] = 1
+ Int_en_z_Ni_x_G = 1/2*polynomialProduct(Int_en_z_Ni_x_G, z_2)
+
+ Int_en_z_Ni_x_J = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_J[1, 2] = 1
+ Int_en_z_Ni_x_J = polynomialProduct(Int_en_z_Ni_x_J, z)
+
+ Int_en_z_Ni_x_K = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_K[1, 0] = 1
+ Int_en_z_Ni_x_K = 1/3*polynomialProduct(Int_en_z_Ni_x_K, z_3)
+
+ Int_en_z_Ni_x_M = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_M[1, 1] = 1
+ Int_en_z_Ni_x_M = 1/2*polynomialProduct(Int_en_z_Ni_x_M, z_2)
+
+ Int_en_z_Ni_x_O = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_O[0, 2] = 1
+ Int_en_z_Ni_x_O = -1/2*polynomialProduct(Int_en_z_Ni_x_O, z_2)
+
+ Int_en_z_Ni_x_P = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_P[0, 2] = 1
+ Int_en_z_Ni_x_P = 1/2*polynomialProduct(Int_en_z_Ni_x_P, z_2)
+
+ Int_en_z_Ni_x_Q = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_Q[0, 1] = 1
+ Int_en_z_Ni_x_Q = -1/3*polynomialProduct(Int_en_z_Ni_x_Q, z_3)
+
+ Int_en_z_Ni_x_R = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_x_R[0, 1] = 1
+ Int_en_z_Ni_x_R = 1/3*polynomialProduct(Int_en_z_Ni_x_R, z_3)
+
+ Int_en_z_Ni_x = np.hstack((Int_en_z_Ni_x_a1, Int_en_z_Ni_x_a2,
+ Int_en_z_Ni_x_a3, Int_en_z_Ni_x_a4,
+ Int_en_z_Ni_x_a5, Int_en_z_Ni_x_a6,
+ Int_en_z_Ni_x_a7, Int_en_z_Ni_x_a8,
+ Int_en_z_Ni_x_a9, Int_en_z_Ni_x_a10,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, Int_en_z_Ni_x_D,
+ Int_en_z_Ni_x_E, Int_en_z_Ni_x_F,
+ Int_en_z_Ni_x_G, null_values, null_values,
+ Int_en_z_Ni_x_J, Int_en_z_Ni_x_K, null_values,
+ Int_en_z_Ni_x_M, null_values, Int_en_z_Ni_x_O,
+ Int_en_z_Ni_x_P, Int_en_z_Ni_x_Q,
+ Int_en_z_Ni_x_R))
+
+ # Definition of y-component of z-integral in Ni
+ Int_en_z_Ni_y_b1 = z
+
+ Int_en_z_Ni_y_b2 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b2[1, 0] = 1
+ Int_en_z_Ni_y_b2 = polynomialProduct(Int_en_z_Ni_y_b2, z)
+
+ Int_en_z_Ni_y_b3 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b3[0, 1] = 1
+ Int_en_z_Ni_y_b3 = polynomialProduct(Int_en_z_Ni_y_b3, z)
+
+ Int_en_z_Ni_y_b4 = 1/2*z_2
+
+ Int_en_z_Ni_y_b5 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b5[2, 0] = 1
+ Int_en_z_Ni_y_b5 = polynomialProduct(Int_en_z_Ni_y_b5, z)
+
+ Int_en_z_Ni_y_b6 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b6[0, 2] = 1
+ Int_en_z_Ni_y_b6 = polynomialProduct(Int_en_z_Ni_y_b6, z)
+
+ Int_en_z_Ni_y_b7 = 1/3*z_3
+
+ Int_en_z_Ni_y_b8 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b8[1, 1] = 1
+ Int_en_z_Ni_y_b8 = polynomialProduct(Int_en_z_Ni_y_b8, z)
+
+ Int_en_z_Ni_y_b9 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b9[1, 0] = 1
+ Int_en_z_Ni_y_b9 = 1/2*polynomialProduct(Int_en_z_Ni_y_b9, z_2)
+
+ Int_en_z_Ni_y_b10 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_b10[0, 1] = 1
+ Int_en_z_Ni_y_b10 = 1/2*polynomialProduct(Int_en_z_Ni_y_b10, z_2)
+
+ Int_en_z_Ni_y_D = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_D[3, 0] = 1
+ Int_en_z_Ni_y_D = -polynomialProduct(Int_en_z_Ni_y_D, z)
+
+ Int_en_z_Ni_y_E = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_E[1, 2] = 1
+ Int_en_z_Ni_y_E = polynomialProduct(Int_en_z_Ni_y_E, z)
+
+ Int_en_z_Ni_y_H = -1/4*z_4
+
+ Int_en_z_Ni_y_I = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_I[0, 2] = 1
+ Int_en_z_Ni_y_I = 1/2*polynomialProduct(Int_en_z_Ni_y_I, z_2)
+
+ Int_en_z_Ni_y_J = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_J[2, 1] = 1
+ Int_en_z_Ni_y_J = -polynomialProduct(Int_en_z_Ni_y_J, z)
+
+ Int_en_z_Ni_y_L = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_L[0, 1] = 1
+ Int_en_z_Ni_y_L = 1/3*polynomialProduct(Int_en_z_Ni_y_L, z_3)
+
+ Int_en_z_Ni_y_M = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_M[2, 0] = 1
+ Int_en_z_Ni_y_M = -1/2*polynomialProduct(Int_en_z_Ni_y_M, z_2)
+
+ Int_en_z_Ni_y_N = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_N[2, 0] = 1
+ Int_en_z_Ni_y_N = 1/2*polynomialProduct(Int_en_z_Ni_y_N, z_2)
+
+ Int_en_z_Ni_y_O = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_O[1, 1] = 1
+ Int_en_z_Ni_y_O = 1/2*polynomialProduct(Int_en_z_Ni_y_O, z_2)
+
+ Int_en_z_Ni_y_R = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_y_R[1, 0] = 1
+ Int_en_z_Ni_y_R = -1/3*polynomialProduct(Int_en_z_Ni_y_R, z_3)
+
+ Int_en_z_Ni_y = np.hstack((null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, Int_en_z_Ni_y_b1, Int_en_z_Ni_y_b2,
+ Int_en_z_Ni_y_b3, Int_en_z_Ni_y_b4,
+ Int_en_z_Ni_y_b5, Int_en_z_Ni_y_b6,
+ Int_en_z_Ni_y_b7, Int_en_z_Ni_y_b8,
+ Int_en_z_Ni_y_b9, Int_en_z_Ni_y_b10,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, Int_en_z_Ni_y_D, Int_en_z_Ni_y_E,
+ null_values, null_values, Int_en_z_Ni_y_H,
+ Int_en_z_Ni_y_I, Int_en_z_Ni_y_J, null_values,
+ Int_en_z_Ni_y_L, Int_en_z_Ni_y_M,
+ Int_en_z_Ni_y_N, Int_en_z_Ni_y_O, null_values,
+ null_values, Int_en_z_Ni_y_R))
+
+ # Definition of z-component of z-integral in Ni
+ Int_en_z_Ni_z_c1 = z
+
+ Int_en_z_Ni_z_c2 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c2[1, 0] = 1
+ Int_en_z_Ni_z_c2 = polynomialProduct(Int_en_z_Ni_z_c2, z)
+
+ Int_en_z_Ni_z_c3 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c3[0, 1] = 1
+ Int_en_z_Ni_z_c3 = polynomialProduct(Int_en_z_Ni_z_c3, z)
+
+ Int_en_z_Ni_z_c4 = 1/2*z_2
+
+ Int_en_z_Ni_z_c5 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c5[2, 0] = 1
+ Int_en_z_Ni_z_c5 = polynomialProduct(Int_en_z_Ni_z_c5, z)
+
+ Int_en_z_Ni_z_c6 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c6[0, 2] = 1
+ Int_en_z_Ni_z_c6 = polynomialProduct(Int_en_z_Ni_z_c6, z)
+
+ Int_en_z_Ni_z_c7 = 1/3*z_3
+
+ Int_en_z_Ni_z_c8 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c8[1, 1] = 1
+ Int_en_z_Ni_z_c8 = polynomialProduct(Int_en_z_Ni_z_c8, z)
+
+ Int_en_z_Ni_z_c9 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c9[1, 0] = 1
+ Int_en_z_Ni_z_c9 = 1/2*polynomialProduct(Int_en_z_Ni_z_c9, z_2)
+
+ Int_en_z_Ni_z_c10 = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_c10[0, 1] = 1
+ Int_en_z_Ni_z_c10 = 1/2*polynomialProduct(Int_en_z_Ni_z_c10, z_2)
+
+ Int_en_z_Ni_z_F = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_F[1, 0] = 1
+ Int_en_z_Ni_z_F = 1/3*polynomialProduct(Int_en_z_Ni_z_F, z_3)
+
+ Int_en_z_Ni_z_G = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_G[3, 0] = 1
+ Int_en_z_Ni_z_G = -polynomialProduct(Int_en_z_Ni_z_G, z)
+
+ Int_en_z_Ni_z_H = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_H[0, 1] = 1
+ Int_en_z_Ni_z_H = 1/3*polynomialProduct(Int_en_z_Ni_z_H, z_3)
+
+ Int_en_z_Ni_z_I = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_I[0, 3] = 1
+ Int_en_z_Ni_z_I = -polynomialProduct(Int_en_z_Ni_z_I, z)
+
+ Int_en_z_Ni_z_K = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_K[2, 0] = 1
+ Int_en_z_Ni_z_K = -1/2*polynomialProduct(Int_en_z_Ni_z_K, z_2)
+
+ Int_en_z_Ni_z_L = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_L[0, 2] = 1
+ Int_en_z_Ni_z_L = -1/2*polynomialProduct(Int_en_z_Ni_z_L, z_2)
+
+ Int_en_z_Ni_z_N = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_N[2, 1] = 1
+ Int_en_z_Ni_z_N = -polynomialProduct(Int_en_z_Ni_z_N, z)
+
+ Int_en_z_Ni_z_P = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_P[1, 2] = 1
+ Int_en_z_Ni_z_P = -polynomialProduct(Int_en_z_Ni_z_P, z)
+
+ Int_en_z_Ni_z_Q = np.zeros((5, 5), dtype=np.float)
+ Int_en_z_Ni_z_Q[1, 1] = 1
+ Int_en_z_Ni_z_Q = 1/2*polynomialProduct(Int_en_z_Ni_z_Q, z_2)
+
+ Int_en_z_Ni_z = np.hstack((null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, null_values,
+ null_values, null_values, Int_en_z_Ni_z_c1,
+ Int_en_z_Ni_z_c2, Int_en_z_Ni_z_c3,
+ Int_en_z_Ni_z_c4, Int_en_z_Ni_z_c5,
+ Int_en_z_Ni_z_c6, Int_en_z_Ni_z_c7,
+ Int_en_z_Ni_z_c8, Int_en_z_Ni_z_c9,
+ Int_en_z_Ni_z_c10, null_values, null_values,
+ Int_en_z_Ni_z_F, Int_en_z_Ni_z_G,
+ Int_en_z_Ni_z_H, Int_en_z_Ni_z_I, null_values,
+ Int_en_z_Ni_z_K, Int_en_z_Ni_z_L, null_values,
+ Int_en_z_Ni_z_N, null_values, Int_en_z_Ni_z_P,
+ Int_en_z_Ni_z_Q, null_values))
+
+ # Build matrix of volume
+ Int_en_z_Ni = np.vstack((Int_en_z_Ni_x, Int_en_z_Ni_y, Int_en_z_Ni_z))
+
+ # Volumetric integral
+ for q in np.arange(1, 4):
+ integral_aux = np.zeros((5, 225), dtype=np.float)
+ for idof in np.arange(1, 4):
+ idx1 = ((idof-1)*5+1)
+ idx2 = (5*idof)
+ integral_aux = (integral_aux+Int_en_z_Ni[idx1-1:idx2, :] *
+ q_volumen_ref[idof-1, q-1])
+
+ # Get row of the coefficient matrix of the system of equations.
+ row_matrix = 43+(q-1)
+ matrix[row_matrix-1, :] = analyticIntegral(integral_aux)
+
+ # Computation of the second member of the total equation system. Each
+ # column represents the independent terms in the second member of the
+ # system of equations proposed for each Ni function.
+ rhs = np.zeros((thirdOrderEdgeElement, thirdOrderEdgeElement),
+ dtype=np.float)
+
+ for idof in np.arange(1, thirdOrderEdgeElement+1):
+ if (idof <= 18):
+ idx1 = np.int(np.round((idof+1)/3)) - np.int(1)
+ rhs[idof-1, idof-1] = 1/length[idx1]
+ elif (idof > 18):
+ rhs[idof-1, idof-1] = 1
+
+ # Obtaining the coefficients of the Ni by solving the system of equations:
+ # matrix * {Coefficients} = rhs
+ # We call "Coefficients" the matrix that hosts each of the 45 coefficients
+ # a1, ... R of the Ni functions. Each of the 45 columns of said matrix
+ # therefore represents each of the functions.
+ coef = lstsq(matrix, rhs, rcond=None)[0]
+
+ # Coefficients EPS --> 0
+ EPS = 1.e-14
+ aux1, aux2 = np.where(np.abs(coef) < EPS)
+ size = aux1.shape
+ n = size[0]
+
+ for kk in np.arange(n):
+ coef[aux1[kk], aux2[kk]] = 0.
+
+ a1 = coef[0, :]
+ a2 = coef[1, :]
+ a3 = coef[2, :]
+ a4 = coef[3, :]
+ a5 = coef[4, :]
+ a6 = coef[5, :]
+ a7 = coef[6, :]
+ a8 = coef[7, :]
+ a9 = coef[8, :]
+ a10 = coef[9, :]
+
+ b1 = coef[10, :]
+ b2 = coef[11, :]
+ b3 = coef[12, :]
+ b4 = coef[13, :]
+ b5 = coef[14, :]
+ b6 = coef[15, :]
+ b7 = coef[16, :]
+ b8 = coef[17, :]
+ b9 = coef[18, :]
+ b10 = coef[19, :]
+
+ c1 = coef[20, :]
+ c2 = coef[21, :]
+ c3 = coef[22, :]
+ c4 = coef[23, :]
+ c5 = coef[24, :]
+ c6 = coef[25, :]
+ c7 = coef[26, :]
+ c8 = coef[27, :]
+ c9 = coef[28, :]
+ c10 = coef[29, :]
+
+ D = coef[30, :]
+ E = coef[31, :]
+ F = coef[32, :]
+ G = coef[33, :]
+ H = coef[34, :]
+ II = coef[35, :]
+ JJ = coef[36, :]
+ K = coef[37, :]
+ L = coef[38, :]
+ M = coef[39, :]
+ N = coef[40, :]
+ OO = coef[41, :]
+ P = coef[42, :]
+ Q = coef[43, :]
+ R = coef[44, :]
+
+ return (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, b1, b2, b3, b4, b5, b6,
+ b7, b8, b9, b10, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, D, E,
+ F, G, H, II, JJ, K, L, M, N, OO, P, Q, R)
+
+
+def NiTetrahedralThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N, OO, P, Q,
+ R, x, y, z, r):
+ ''' Computation of Ni (Nedelec basis functions of second order) in a
+ tetrahedral element with vertices (x,y,z) for point r.
+
+ :param float coefficients: a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,D,E,F,
+ G,H,II,JJ,K.
+ :param float-array x: x-coordinates of reference element.
+ :param float-array y: y-coordinates of reference element.
+ :param float-array z: z-coordinates of reference element.
+ :param float-array r: xyz coordinates of the evaluation point.
+ :return: basis nedelec funcions of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+ # Number of dimensions
+ nDimensions = 3
+
+ # Third order ele
+ thirdOrderEdgeElement = 45
+
+ # Initialization
+ coef = np.zeros((thirdOrderEdgeElement, thirdOrderEdgeElement),
+ dtype=np.float)
+
+ coef[0, :] = a1
+ coef[1, :] = a2
+ coef[2, :] = a3
+ coef[3, :] = a4
+ coef[4, :] = a5
+ coef[5, :] = a6
+ coef[6, :] = a7
+ coef[7, :] = a8
+ coef[8, :] = a9
+ coef[9, :] = a10
+ coef[10, :] = b1
+ coef[11, :] = b2
+ coef[12, :] = b3
+ coef[13, :] = b4
+ coef[14, :] = b5
+ coef[15, :] = b6
+ coef[16, :] = b7
+ coef[17, :] = b8
+ coef[18, :] = b9
+ coef[19, :] = b10
+ coef[20, :] = c1
+ coef[21, :] = c2
+ coef[22, :] = c3
+ coef[23, :] = c4
+ coef[24, :] = c5
+ coef[25, :] = c6
+ coef[26, :] = c7
+ coef[27, :] = c8
+ coef[28, :] = c9
+ coef[29, :] = c10
+ coef[30, :] = D
+ coef[31, :] = E
+ coef[32, :] = F
+ coef[33, :] = G
+ coef[34, :] = H
+ coef[35, :] = II
+ coef[36, :] = JJ
+ coef[37, :] = K
+ coef[38, :] = L
+ coef[39, :] = M
+ coef[40, :] = N
+ coef[41, :] = OO
+ coef[42, :] = P
+ coef[43, :] = Q
+ coef[44, :] = R
+
+ # Computation on reference element
+ L = cartesianToVolumetricCoordinates(x, y, z, r)
+
+ xref = np.array([0, 1, 0, 0], dtype=np.float)
+ yref = np.array([0, 0, 1, 0], dtype=np.float)
+ zref = np.array([0, 0, 0, 1], dtype=np.float)
+
+ rref = np.zeros(3, dtype=np.float)
+ rref[0] = np.dot(L, xref)
+ rref[1] = np.dot(L, yref)
+ rref[2] = np.dot(L, zref)
+
+ aux_x = np.array([1, rref[0], rref[1], rref[2], rref[0]**2, rref[1]**2,
+ rref[2]**2, rref[0]*rref[1], rref[0]*rref[2],
+ rref[1]*rref[2], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, (rref[0]**2)*rref[1], -rref[1]**3,
+ -rref[2]**3, (rref[0]**2)*rref[2], 0, 0,
+ (rref[1]**2)*rref[0], (rref[2]**2)*rref[0], 0,
+ rref[0]*rref[1]*rref[2], 0, -(rref[1]**2)*rref[2],
+ (rref[1]**2)*rref[2], -(rref[2]**2)*rref[1],
+ (rref[2]**2)*rref[1]], dtype=np.float)
+
+ aux_y = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, rref[0], rref[1],
+ rref[2], rref[0]**2, rref[1]**2, rref[2]**2,
+ rref[0]*rref[1], rref[0]*rref[2], rref[1]*rref[2],
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -rref[0]**3,
+ (rref[1]**2)*rref[0], 0, 0, -rref[2]**3,
+ (rref[1]**2)*rref[2], -(rref[0]**2)*rref[1], 0,
+ (rref[2]**2)*rref[1], -(rref[0]**2)*rref[2],
+ (rref[0]**2)*rref[2], rref[0]*rref[1]*rref[2], 0, 0,
+ -(rref[2]**2)*rref[0]], dtype=np.float)
+
+ aux_z = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, rref[0], rref[1], rref[2], rref[0]**2,
+ rref[1]**2, rref[2]**2, rref[0]*rref[1], rref[0]*rref[2],
+ rref[1]*rref[2], 0, 0, (rref[2]**2)*rref[0],
+ -rref[0]**3, (rref[2]**2)*rref[1], -rref[1]**3, 0,
+ -(rref[0]**2)*rref[2], -(rref[1]**2)*rref[2], 0,
+ -(rref[0]**2)*rref[1], 0, -(rref[1]**2)*rref[0],
+ rref[0]*rref[1]*rref[2], 0], dtype=np.float)
+
+ # Allocate
+ Niref = np.zeros((nDimensions, thirdOrderEdgeElement), dtype=np.float)
+
+ Niref[0, :] = np.matmul(aux_x, coef)
+ Niref[1, :] = np.matmul(aux_y, coef)
+ Niref[2, :] = np.matmul(aux_z, coef)
+
+ del aux_x, aux_y, aux_z
+
+ # Vector element reference to the real element through the Jacobian
+ # Ni_real=([J]^-1)*Niref
+ x21 = x[1]-x[0]
+ y21 = y[1]-y[0]
+ z21 = z[1]-z[0]
+ x31 = x[2]-x[0]
+ y31 = y[2]-y[0]
+ z31 = z[2]-z[0]
+ x41 = x[3]-x[0]
+ y41 = y[3]-y[0]
+ z41 = z[3]-z[0]
+
+ jacob = np.array([[x21, y21, z21], [x31, y31, z31],
+ [x41, y41, z41]], dtype=np.float)
+
+ Ni = lstsq(jacob, Niref, rcond=None)[0]
+
+ return Ni
+
+
+def nedelecBasisThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N,
+ O, P, Q, R, ref_ele, points):
+ ''' This function computes the basis nedelec functions of third order
+ for a set of points in a given tetrahedral element.
+
+ :param float coefficients: a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,b1,b2,b3,b4,b5,
+ b6,b7,b8,b9,b10,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,D,E,F,G,H,II,JJ,K,L,M,N,
+ O,P,Q,R.
+ :param float-array ref_ele: nodal coordinates of reference element.
+ :param float-array points: spatial coordinates of the evaluation points.
+ :return: basis nedelec functions of second order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Garcia-Castillo, L. E., Ruiz-Genovés, A. J., Gómez-Revuelto, I.,
+ Salazar-Palma, M., & Sarkar, T. K. (2002). Third-order Nédélec
+ curl-conforming finite element. IEEE transactions on magnetics,
+ 38(5), 2370-2372.
+ '''
+ # Number of points
+ size = points.shape
+ # More than one point
+ if len(size) == 2:
+ nPoints = size[1]
+ # One point
+ elif len(size) == 1:
+ nPoints = 1
+
+ # Number of dimensions
+ nDimensions = 3
+
+ # Third order ele
+ thirdOrderEdgeElement = 45
+
+ # Allocate
+ basis = np.zeros((nDimensions, thirdOrderEdgeElement, nPoints),
+ dtype=np.float)
+
+ # Get reference element coordinates
+ xref = ref_ele[0, :]
+ yref = ref_ele[1, :]
+ zref = ref_ele[2, :]
+
+ # Compute nedelec basis functions of second order for all points
+ if nPoints == 1: # One point
+ for iPoint in np.arange(nPoints):
+ r = points
+
+ # Basis funtions for iPoint|
+ basis[:, :, iPoint] = NiTetrahedralThirdOrder(a1, a2, a3, a4, a5,
+ a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5,
+ b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5,
+ c6, c7, c8, c9, c10,
+ D, E, F, G, H, II,
+ JJ, K, L, M, N, O,
+ P, Q, R, xref, yref,
+ zref, r)
+ else: # More than one point
+ for iPoint in np.arange(nPoints):
+ r = points[:, iPoint]
+
+ # Basis funtions for iPoint|
+ basis[:, :, iPoint] = NiTetrahedralThirdOrder(a1, a2, a3, a4, a5,
+ a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5,
+ b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5,
+ c6, c7, c8, c9, c10,
+ D, E, F, G, H, II,
+ JJ, K, L, M, N, O,
+ P, Q, R, xref, yref,
+ zref, r)
+
+ return basis
+
+
+def computeMassMatrixThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N, O, P,
+ Q, R, ref_ele, GR, signs, DetJacob):
+ ''' Compute mass matrix for tetrahedral edge elements of third order.
+
+ :param float coefficients: a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,b1,b2,b3,b4,b5,
+ b6,b7,b8,b9,b10,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,D,E,F,G,H,II,JJ,K,L,M,N,
+ O,P,Q,R
+ :param float-array ref_ele: nodal coordinates of reference element.
+ :param float-array GR: tensor.
+ :param int-array signs: dofs signs.
+ :param float DetJacob: determinant of the jacobian.
+ :return: mass matrix for edge element of third order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Garcia-Castillo, L. E., Ruiz-Genovés, A. J., Gómez-Revuelto, I.,
+ Salazar-Palma, M., & Sarkar, T. K. (2002). Third-order Nédélec
+ curl-conforming finite element. IEEE transactions on magnetics,
+ 38(5), 2370-2372.
+ '''
+ # Third order ele
+ nedelecOrder = 3
+ thirdOrderEdgeElement = 45
+
+ # Gaussian points for the unit reference tetrahedron
+ ngaussP = 24
+ [Wi, rx, ry, rz] = gauss_points_reference_tetrahedron(ngaussP,
+ nedelecOrder)
+
+ # Get reference element coordinates
+ xref = ref_ele[0, :]
+ yref = ref_ele[1, :]
+ zref = ref_ele[2, :]
+
+ # Allocate
+ Me = np.zeros((thirdOrderEdgeElement, thirdOrderEdgeElement),
+ dtype=np.float)
+
+ # Mass matrix computation
+ r = np.zeros(3, dtype=np.float)
+ for iPoint in np.arange(ngaussP):
+ r[0] = rx[iPoint]
+ r[1] = ry[iPoint]
+ r[2] = rz[iPoint]
+
+ Ni = NiTetrahedralThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N, O,
+ P, Q, R, xref, yref, zref, r)
+ nix = Ni[0, :]
+ niy = Ni[1, :]
+ niz = Ni[2, :]
+
+ for ii in np.arange(thirdOrderEdgeElement):
+ for jj in np.arange(thirdOrderEdgeElement):
+ Me[ii, jj] += Wi[iPoint]*((GR[0, 0]*nix[ii]*nix[jj] +
+ GR[0, 1]*(nix[ii]*niy[jj] +
+ niy[ii]*nix[jj]) +
+ GR[1, 1]*niy[ii]*niy[jj] +
+ GR[0, 2]*(nix[ii]*niz[jj] +
+ niz[ii]*nix[jj]) +
+ GR[1, 2]*(niy[ii]*niz[jj] +
+ niz[ii]*niy[jj]) +
+ GR[2, 2]*niz[ii]*niz[jj]) *
+ signs[ii]*signs[jj])
+
+ Me = Me*DetJacob
+
+ return Me
+
+
+def computeDerivativesThirdOrder(a2, a3, a4, a5, a6, a7, a8, a9, a10, b2, b3,
+ b4, b5, b6, b7, b8, b9, b10, c2, c3, c4, c5,
+ c6, c7, c8, c9, c10, D, E, F, G, H, II, JJ,
+ K, L, M, N, O, P, Q, R, point):
+ ''' Compute partial derivatives of basis functions for tetrahedral edge
+ elements of third order (reference element)
+
+ :param float coefficients: a2,a3,a4,a5,a6,a7,a8,a9,a10,b2,b3,b4,b5,b6,
+ b7,b8,b9,b10,c2,c3,c4,c5,c6,c7,c8,c9,c10,D,E,F,G,H,II,JJ,K,L,M,N,O,P,Q,R.
+ :param float-array point: coordinates of the gaussian point.
+ :return: partial derivatives for edge element of third order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Garcia-Castillo, L. E., Ruiz-Genovés, A. J., Gómez-Revuelto, I.,
+ Salazar-Palma, M., & Sarkar, T. K. (2002). Third-order Nédélec
+ curl-conforming finite element. IEEE transactions on magnetics,
+ 38(5), 2370-2372.
+ '''
+ # Point coordinates
+ x = point[0]
+ y = point[1]
+ z = point[2]
+
+ # dxNix
+ dxNix = (a2 + 2*a5*x + a8*y + a9*z + 2*D*x*y +
+ 2*G*x*z + JJ*y**2 + K*z**2 + M*y*z)
+
+ # dxNiy
+ dxNiy = (b2 + 2*b5*x + b8*y + b9*z - 2*JJ*x*y - 2*M*x*z +
+ 2*N*x*z + E*y**2 - R*z**2 + O*y*z - 3*D*x**2)
+
+ # dxNiz
+ dxNiz = (c2 + 2*c5*x + c8*y + c9*z - 2*N*x*y -
+ 2*K*x*z - P*y**2 + F*z**2 + Q*y*z - 3*G*x**2)
+
+ # dyNix
+ dyNix = (a3 + 2*a6*y + a8*x + a10*z + D*x**2 + 2*JJ*y*x -
+ 2*O*y*z + 2*P*y*z - Q*z**2 + R*z**2 + M*x*z - 3*E*y**2)
+
+ # dyNiy
+ dyNiy = (b3 + 2*b6*y + b8*x + b10*z - JJ*x**2 +
+ 2*E*y*x + 2*II*y*z + L*z**2 + O*x*z)
+
+ # dyNiz
+ dyNiz = (c3 + 2*c6*y + c8*x + c10*z - N*x**2 -
+ 2*P*y*x - 2*L*y*z + H*z**2 + Q*x*z - 3*II*y**2)
+
+ # dzNix
+ dzNix = (a4 + 2*a7*z + a9*x + a10*y + G*x**2 - O*y**2 +
+ P*y**2 + 2*K*z*x - 2*Q*z*y + 2*R*z*y + M*x*y - 3*F*z**2)
+
+ # dzNiy
+ dzNiy = (b4 + 2*b7*z + b9*x + b10*y - M*x**2 +
+ N*x**2 + II*y**2 - 2*R*z*x + 2*L*z*y + O*x*y - 3*H*z**2)
+
+ # dzNiz
+ dzNiz = (c4 + 2*c7*z + c9*x + c10*y - K*x**2 -
+ L*y**2 + 2*F*z*x + 2*H*z*y + Q*x*y)
+
+ return dxNix, dxNiy, dxNiz, dyNix, dyNiy, dyNiz, dzNix, dzNiy, dzNiz
+
+
+def computeStiffnessMatrixThirdOrder(a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N,
+ O, P, Q, R, invjj, signs, DetJacob):
+ ''' Compute stiffness matrix for tetrahedral edge elements of third order.
+
+ :param float coefficients: a2,a3,a4,a5,a6,a7,a8,a9,a10,b2,b3,b4,b5,b6,b7,
+ b8,b9,b10,c2,c3,c4,c5,c6,c7,c8,c9,c10,D,E,F,G,H,II,JJ,K,L,M,N,O,P,Q,R.
+ :param float-array invjj: inverse jacobian.
+ :param int-array signs: dofs signs.
+ :param float DetJacob: determinant of the jacobian.
+ :return: stiffness matrix for edge element of third order.
+ :rtype: ndarray.
+
+ .. note: References:\n
+ Garcia-Castillo, L. E., Ruiz-Genovés, A. J., Gómez-Revuelto, I.,
+ Salazar-Palma, M., & Sarkar, T. K. (2002). Third-order Nédélec
+ curl-conforming finite element. IEEE transactions on magnetics,
+ 38(5), 2370-2372.
+ '''
+ # Third order ele
+ nedelecOrder = 3
+ thirdOrderEdgeElement = 45
+
+ # Gaussian points for the unit reference tetrahedron
+ ngaussP = 15
+ [Wi, rx, ry, rz] = gauss_points_reference_tetrahedron(ngaussP,
+ nedelecOrder)
+
+ # Allocate
+ Ke = np.zeros((thirdOrderEdgeElement, thirdOrderEdgeElement),
+ dtype=np.float)
+
+ # Tensor computation
+ fr = np.eye(3, dtype=np.float)
+ invfr = inv(fr)
+
+ tmp1 = np.array([[0, 0, 0], [0, 0, 1], [0, -1, 0]], dtype=np.float)
+ tmp2 = np.matmul(tmp1, invjj)
+ A = np.matmul(invjj.transpose(), tmp2)
+
+ tmp1 = np.array([[0, 0, -1], [0, 0, 0], [1, 0, 0]], dtype=np.float)
+ tmp2 = np.matmul(tmp1, invjj)
+ B = np.matmul(invjj.transpose(), tmp2)
+
+ tmp1 = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 0]], dtype=np.float)
+ tmp2 = np.matmul(tmp1, invjj)
+ C = np.matmul(invjj.transpose(), tmp2)
+
+ # Stiffness matrix computation
+ r = np.zeros(3, dtype=np.float)
+ for iPoint in np.arange(ngaussP):
+ r[0] = rx[iPoint]
+ r[1] = ry[iPoint]
+ r[2] = rz[iPoint]
+
+ [_, dxNiy, dxNiz,
+ dyNix, _, dyNiz,
+ dzNix, dzNiy, _] = computeDerivativesThirdOrder(a2, a3, a4, a5, a6,
+ a7, a8, a9, a10, b2,
+ b3, b4, b5, b6, b7,
+ b8, b9, b10, c2, c3,
+ c4, c5, c6, c7, c8,
+ c9, c10, D, E, F, G,
+ H, II, JJ, K, L, M, N,
+ O, P, Q, R, r)
+
+ rotNix = (A[0, 1]*dxNiy + A[0, 2]*dxNiz -
+ A[0, 1]*dyNix + A[1, 2]*dyNiz -
+ A[0, 2]*dzNix - A[1, 2]*dzNiy)
+ rotNiy = (B[0, 1]*dxNiy + B[0, 2]*dxNiz -
+ B[0, 1]*dyNix + B[1, 2]*dyNiz -
+ B[0, 2]*dzNix - B[1, 2]*dzNiy)
+ rotNiz = (C[0, 1]*dxNiy + C[0, 2]*dxNiz -
+ C[0, 1]*dyNix + C[1, 2]*dyNiz -
+ C[0, 2]*dzNix - C[1, 2]*dzNiy)
+
+ for ii in np.arange(thirdOrderEdgeElement):
+ for jj in np.arange(thirdOrderEdgeElement):
+ Ke[ii, jj] += Wi[iPoint]*((invfr[0, 0]*rotNix[ii]*rotNix[jj] +
+ invfr[0, 1]*(rotNix[ii] *
+ rotNiy[jj] +
+ rotNiy[ii] *
+ rotNix[jj]) +
+ invfr[1, 1]*rotNiy[ii]*rotNiy[jj] +
+ invfr[0, 2]*(rotNix[ii] *
+ rotNiz[jj] +
+ rotNiz[ii] *
+ rotNix[jj]) +
+ invfr[1, 2]*(rotNiy[ii] *
+ rotNiz[jj] +
+ rotNiz[ii] *
+ rotNiy[jj]) +
+ invfr[2, 2]*rotNiz[ii] *
+ rotNiz[jj])*signs[ii]*signs[jj])
+
+ Ke = Ke*DetJacob
+
+ return Ke
+
+
def unitary_test():
''' Unitary test for efem.py script.
'''
+
if __name__ == '__main__':
# Standard module import
unitary_test()
else:
# Standard module import
import numpy as np
+ from numpy.linalg import lstsq
from scipy.linalg import det
+ from scipy.linalg import norm
+ from scipy.linalg import inv
# PETGEM module import
from petgem.efem.vectorMatrixFunctions import deleteDuplicateRows
+ from petgem.efem.vectorMatrixFunctions import crossprod
+ from petgem.efem.vectorMatrixFunctions import is_duplicate_entry
+ from petgem.efem.fem import cartesianToVolumetricCoordinates
+ from petgem.efem.fem import gauss_points_reference_tetrahedron
diff --git a/petgem/efem/fem.py b/petgem/efem/fem.py
old mode 100644
new mode 100755
index a3fe220..f41274c
--- a/petgem/efem/fem.py
+++ b/petgem/efem/fem.py
@@ -7,12 +7,12 @@
def tetraXiEtaZeta2XYZ(eleNodes, XiEtaZetaPoints):
- ''' Map a set of points in XiEtaZeta coordinates to XYZ coordinates.
+ ''' Map a set of points in XiEtaZeta coord to XYZ coord.
- :param ndarray eleNodes: nodal spatial coordinates of the
+ :param ndarray eleNodes: nodal spatial coord of the
tetrahedral element.
- :param ndarray XiEtaZetaPoints: set of points in XiEtaZeta coordinates.
- :return: new spatial coordinates of XiEtaZetaPoints.
+ :param ndarray XiEtaZetaPoints: set of points in XiEtaZeta coord.
+ :return: new spatial coord of XiEtaZetaPoints.
:rtype: ndarray.
'''
# Get number of points
@@ -21,17 +21,17 @@ def tetraXiEtaZeta2XYZ(eleNodes, XiEtaZetaPoints):
# Allocate
xyzPoints = np.zeros((3), dtype=np.float64)
# Mapping all points
- # x-coordinates
+ # x-coord
xyzPoints[0] = eleNodes[0][0] + \
(eleNodes[1][0]-eleNodes[0][0])*XiEtaZetaPoints[0] + \
(eleNodes[2][0]-eleNodes[0][0])*XiEtaZetaPoints[1] + \
(eleNodes[3][0]-eleNodes[0][0])*XiEtaZetaPoints[2]
- # y-coordinates
+ # y-coord
xyzPoints[1] = eleNodes[0][1] + \
(eleNodes[1][1]-eleNodes[0][1])*XiEtaZetaPoints[0] + \
(eleNodes[2][1]-eleNodes[0][1])*XiEtaZetaPoints[1] + \
(eleNodes[3][1]-eleNodes[0][1])*XiEtaZetaPoints[2]
- # z-coordinates
+ # z-coord
xyzPoints[2] = eleNodes[0][2] + \
(eleNodes[1][2]-eleNodes[0][2])*XiEtaZetaPoints[0] + \
(eleNodes[2][2]-eleNodes[0][2])*XiEtaZetaPoints[1] + \
@@ -41,17 +41,17 @@ def tetraXiEtaZeta2XYZ(eleNodes, XiEtaZetaPoints):
# Allocate
xyzPoints = np.zeros((nPoints, 3), dtype=np.float64)
# Mapping all points
- # x-coordinates
+ # x-coord
xyzPoints[:, 0] = eleNodes[0][0] + \
([eleNodes[1][0]-eleNodes[0][0]])*XiEtaZetaPoints[:, 0] + \
([eleNodes[2][0]-eleNodes[0][0]])*XiEtaZetaPoints[:, 1] + \
([eleNodes[3][0]-eleNodes[0][0]])*XiEtaZetaPoints[:, 2]
- # y-coordinates
+ # y-coord
xyzPoints[:, 1] = eleNodes[0][1] + \
([eleNodes[1][1]-eleNodes[0][1]])*XiEtaZetaPoints[:, 0] + \
([eleNodes[2][1]-eleNodes[0][1]])*XiEtaZetaPoints[:, 1] + \
([eleNodes[3][1]-eleNodes[0][1]])*XiEtaZetaPoints[:, 2]
- # z-coordinates
+ # z-coord
xyzPoints[:, 2] = eleNodes[0][2] + \
([eleNodes[1][2]-eleNodes[0][2]])*XiEtaZetaPoints[:, 0] + \
([eleNodes[2][2]-eleNodes[0][2]])*XiEtaZetaPoints[:, 1] + \
@@ -807,9 +807,9 @@ def s4(w):
return (X, W)
def s31(a, w):
- ''' First star: Compute the barycentric coordinates, which
+ ''' First star: Compute the barycentric coord, which
contain 4 dimensions. The points are obtained by taking all
- the unique 3 dimensional permutations from the barycentric coordinates.
+ the unique 3 dimensional permutations from the barycentric coord.
'''
baryc = [a, a, a, (1.0-3.0*a)]
temp = np.array(list(itertools.permutations(baryc)), dtype=np.float64)
@@ -822,9 +822,9 @@ def s31(a, w):
return (X, W)
def s22(a, w):
- ''' Second star: Compute the barycentric coordinates, which
+ ''' Second star: Compute the barycentric coord, which
contain 4 dimensions. The points are obtained by taking all
- the unique 3 dimensional permutations from the barycentric coordinates.
+ the unique 3 dimensional permutations from the barycentric coord.
'''
baryc = [a, a, 0.5-a, 0.5-a]
temp = np.array(list(itertools.permutations(baryc)), dtype=np.float64)
@@ -837,9 +837,9 @@ def s22(a, w):
return (X, W)
def s211(a, b, w):
- ''' Second star: Compute the barycentric coordinates, which
+ ''' Second star: Compute the barycentric coord, which
contain 4 dimensions. The points are obtained by taking all
- the unique 3 dimensional permutations from the barycentric coordinates.
+ the unique 3 dimensional permutations from the barycentric coord.
'''
baryc = [a, a, b, (1.0-2.0*a-b)]
temp = np.array(list(itertools.permutations(baryc)), dtype=np.float64)
@@ -852,9 +852,9 @@ def s211(a, b, w):
return (X, W)
def s1111(a, b, c, w):
- ''' Fourth star: Compute the barycentric coordinates, which
+ ''' Fourth star: Compute the barycentric coord, which
contain 4 dimensions. The points are obtained by taking all
- the unique 3 dimensional permutations from the barycentric coordinates.
+ the unique 3 dimensional permutations from the barycentric coord.
'''
baryc = [a, b, c, (1.0-a-b-c)]
temp = np.array(list(itertools.permutations(baryc)), dtype=np.float64)
@@ -890,10 +890,462 @@ def s1111(a, b, c, w):
return (X, W)
+def gauss_points_reference_tetrahedron(npointeg, nedelec_order):
+ ''' Compute the quadrature points X,Y,Z and the weights Wi for the
+ integration over the reference tetrahedral.
+
+ :param int npointeg: number of gauss points to be computed.
+ :param int nedelec_order: nedelec element order.
+ :return: quadrature Gauss points (X, Y, Z) and Gauss weights.
+ :rtype: ndarray.
+
+ .. note:: References:\n
+ Amor-Martin, A., Garcia-Castillo, L. E., & Garcia-Doñoro, D. D.
+ (2016). Second-order Nédélec curl-conforming prismatic element
+ for computational electromagnetics. IEEE Transactions on
+ Antennas and Propagation, 64(10), 4384-4395.
+ '''
+
+ # ----- Gaussian points computation for unit tetrahedron ----
+ # Allocate
+ Wi = np.zeros(npointeg, dtype=np.float)
+ x = np.zeros(npointeg, dtype=np.float)
+ y = np.zeros(npointeg, dtype=np.float)
+ z = np.zeros(npointeg, dtype=np.float)
+
+ if npointeg == 5 and nedelec_order == 2:
+ # Compute weigths
+ Wi[0] = -2./15.
+ Wi[1] = 3./40.
+ Wi[2] = 3./40.
+ Wi[3] = 3./40.
+ Wi[4] = 3./40.
+ # Unit tetrahedron (Volume)
+ Wi = Wi*6.
+
+ # Compute coord
+ x[0] = 1./4.
+ x[1] = 1./6.
+ x[2] = 1./6.
+ x[3] = 1./6.
+ x[4] = 1./2.
+ y[0] = 1./4.
+ y[1] = 1./6.
+ y[2] = 1./6.
+ y[3] = 1./2.
+ y[4] = 1./6.
+ z[0] = 1./4.
+ z[1] = 1./6.
+ z[2] = 1./2.
+ z[3] = 1./6.
+ z[4] = 1./6.
+
+ elif npointeg == 15 and nedelec_order == 2:
+ # Compute weigths
+ a = 1./4.
+ b1 = (7.+np.sqrt(15.))/34.
+ b2 = (7.-np.sqrt(15.))/34.
+ c1 = (13.-3.*np.sqrt(15.))/34.
+ c2 = (13.+3.*np.sqrt(15.))/34.
+ d = (5.-np.sqrt(15.))/20.
+ ee = (5.+np.sqrt(15.))/20.
+
+ Wi[0] = 8./405.
+ Wi[1] = (2665.-14.*np.sqrt(15.))/226800.
+ Wi[2] = (2665.-14.*np.sqrt(15.))/226800.
+ Wi[3] = (2665.-14.*np.sqrt(15.))/226800.
+ Wi[4] = (2665.-14.*np.sqrt(15.))/226800.
+ Wi[5] = (2665.+14.*np.sqrt(15.))/226800.
+ Wi[6] = (2665.+14.*np.sqrt(15.))/226800.
+ Wi[7] = (2665.+14.*np.sqrt(15.))/226800.
+ Wi[8] = (2665.+14.*np.sqrt(15.))/226800.
+ Wi[9] = 5./567.
+ Wi[10] = 5./567.
+ Wi[11] = 5./567.
+ Wi[12] = 5./567.
+ Wi[13] = 5./567.
+ Wi[14] = 5./567.
+
+ # Unit tetrahedron (Volume)
+ Wi = Wi*6.
+
+ # Compute coord
+ x[0] = a
+ y[0] = a
+ z[0] = a
+
+ x[1] = b1
+ x[2] = b1
+ x[3] = b1
+ x[4] = c1
+ x[5] = b2
+ x[6] = b2
+ x[7] = b2
+ x[8] = c2
+ y[1] = b1
+ y[2] = b1
+ y[3] = c1
+ y[4] = b1
+ y[5] = b2
+ y[6] = b2
+ y[7] = c2
+ y[8] = b2
+ z[1] = b1
+ z[2] = c1
+ z[3] = b1
+ z[4] = b1
+ z[5] = b2
+ z[6] = c2
+ z[7] = b2
+ z[8] = b2
+
+ x[9] = d
+ x[10] = d
+ x[11] = ee
+ y[9] = d
+ y[10] = ee
+ y[11] = d
+ z[9] = ee
+ z[10] = d
+ z[11] = d
+
+ x[12] = d
+ x[13] = ee
+ x[14] = ee
+ y[12] = ee
+ y[13] = d
+ y[14] = ee
+ z[12] = ee
+ z[13] = ee
+ z[14] = d
+
+ elif npointeg == 15 and nedelec_order == 3:
+ # Compute weigths
+ W0 = 8/405
+ W1 = (2665-14*np.sqrt(15))/226800
+ W2 = (2665+14*np.sqrt(15))/226800
+ W3 = 5/567
+
+ a = 1/4
+ b1 = (7+np.sqrt(15))/34
+ b2 = (7-np.sqrt(15))/34
+ c1 = (13-3*np.sqrt(15))/34
+ c2 = (13+3*np.sqrt(15))/34
+ d = (5-np.sqrt(15))/20
+ ee = (5+np.sqrt(15))/20
+
+ Wi[0] = W0
+ Wi[1] = W1
+ Wi[2] = W1
+ Wi[3] = W1
+ Wi[4] = W1
+ Wi[5] = W2
+ Wi[6] = W2
+ Wi[7] = W2
+ Wi[8] = W2
+ Wi[9] = W3
+ Wi[10] = W3
+ Wi[11] = W3
+ Wi[12] = W3
+ Wi[13] = W3
+ Wi[14] = W3
+
+ # Compute coordinates
+ x[0] = a
+ y[0] = a
+ z[0] = a
+
+ x[1] = b1
+ x[2] = b1
+ x[3] = b1
+ x[4] = c1
+ y[1] = b1
+ y[2] = b1
+ y[3] = c1
+ y[4] = b1
+ z[1] = b1
+ z[2] = c1
+ z[3] = b1
+ z[4] = b1
+
+ x[5] = b2
+ x[6] = b2
+ x[7] = b2
+ x[8] = c2
+ y[5] = b2
+ y[6] = b2
+ y[7] = c2
+ y[8] = b2
+ z[5] = b2
+ z[6] = c2
+ z[7] = b2
+ z[8] = b2
+
+ x[9] = d
+ x[10] = d
+ x[11] = ee
+ y[9] = d
+ y[10] = ee
+ y[11] = d
+ z[9] = ee
+ z[10] = d
+ z[11] = d
+
+ x[12] = d
+ x[13] = ee
+ x[14] = ee
+ y[12] = ee
+ y[13] = d
+ y[14] = ee
+ z[12] = ee
+ z[13] = ee
+ z[14] = d
+
+ elif npointeg == 24 and nedelec_order == 3:
+ # Definition of reference element (volumetric coord)
+ x_tet_ref = np.array([0, 1, 0, 0], dtype=np.float)
+ y_tet_ref = np.array([0, 0, 1, 0], dtype=np.float)
+ z_tet_ref = np.array([0, 0, 0, 1], dtype=np.float)
+
+ # Allocate array for cartesian coord
+ cartesian_coord = np.zeros((3, npointeg), dtype=np.float)
+
+ # First group K[3,1]. 4 points
+ W1 = 0.665379170969464506e-2
+ Wi[0] = W1
+ Wi[1] = W1
+ Wi[2] = W1
+ Wi[3] = W1
+
+ L1A = 0.214602871259151684
+ L1B = 0.356191386222544953
+
+ # Volumetric coord to cartesian coord. 4 points
+ L1_1 = np.vstack((L1A, L1A, L1A, L1B))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L1_1)
+ cartesian_coord[:, 0] = tmp[:, 0]
+
+ L1_2 = np.vstack((L1A, L1A, L1B, L1A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L1_2)
+ cartesian_coord[:, 1] = tmp[:, 0]
+
+ L1_3 = np.vstack((L1A, L1B, L1A, L1A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L1_3)
+ cartesian_coord[:, 2] = tmp[:, 0]
+
+ L1_4 = np.vstack((L1B, L1A, L1A, L1A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L1_4)
+ cartesian_coord[:, 3] = tmp[:, 0]
+
+ # Second group K[3,1]. 4 points
+ W2 = 0.167953517588677620e-2
+ Wi[4] = W2
+ Wi[5] = W2
+ Wi[6] = W2
+ Wi[7] = W2
+
+ L2A = 0.406739585346113397e-1
+ L2B = 0.877978124396165982
+
+ # Volumetric coord to cartesian coord. 4 points
+ L2_1 = np.vstack((L2A, L2A, L2A, L2B))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L2_1)
+ cartesian_coord[:, 4] = tmp[:, 0]
+
+ L2_2 = np.vstack((L2A, L2A, L2B, L2A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L2_2)
+ cartesian_coord[:, 5] = tmp[:, 0]
+
+ L2_3 = np.vstack((L2A, L2B, L2A, L2A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L2_3)
+ cartesian_coord[:, 6] = tmp[:, 0]
+
+ L2_4 = np.vstack((L2B, L2A, L2A, L2A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L2_4)
+ cartesian_coord[:, 7] = tmp[:, 0]
+
+ # Third group K[3,1]. 4 points
+ W3 = 0.922619692394239843e-2
+ Wi[8] = W3
+ Wi[9] = W3
+ Wi[10] = W3
+ Wi[11] = W3
+
+ L3A = 0.322337890142275646
+ L3B = 0.329863295731730594e-1
+
+ # Volumetric coord to cartesian coord. 4 points
+ L3_1 = np.vstack((L3A, L3A, L3A, L3B))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L3_1)
+ cartesian_coord[:, 8] = tmp[:, 0]
+
+ L3_2 = np.vstack((L3A, L3A, L3B, L3A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L3_2)
+ cartesian_coord[:, 9] = tmp[:, 0]
+
+ L3_3 = np.vstack((L3A, L3B, L3A, L3A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L3_3)
+ cartesian_coord[:, 10] = tmp[:, 0]
+
+ L3_4 = np.vstack((L3B, L3A, L3A, L3A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L3_4)
+ cartesian_coord[:, 11] = tmp[:, 0]
+
+ # GroupK[2,1,1]. 12 points.
+ W4 = 0.803571428571428248e-2
+
+ for iPoint in np.arange(12, npointeg):
+ Wi[iPoint] = W4
+
+ L4A = 0.636610018750175299e-1
+ L4B = 0.269672331458315867
+ L4C = 0.603005664791649076
+
+ # Volumetric coord to cartesian coord. 12 points.
+ L4_1 = np.vstack((L4A, L4A, L4B, L4C))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_1)
+ cartesian_coord[:, 12] = tmp[:, 0]
+
+ L4_2 = np.vstack((L4A, L4A, L4C, L4B))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_2)
+ cartesian_coord[:, 13] = tmp[:, 0]
+
+ L4_3 = np.vstack((L4B, L4A, L4A, L4C))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_3)
+ cartesian_coord[:, 14] = tmp[:, 0]
+
+ L4_4 = np.vstack((L4C, L4A, L4A, L4B))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_4)
+ cartesian_coord[:, 15] = tmp[:, 0]
+
+ L4_5 = np.vstack((L4B, L4C, L4A, L4A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_5)
+ cartesian_coord[:, 16] = tmp[:, 0]
+
+ L4_6 = np.vstack((L4C, L4B, L4A, L4A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_6)
+ cartesian_coord[:, 17] = tmp[:, 0]
+
+ L4_7 = np.vstack((L4A, L4B, L4A, L4C))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_7)
+ cartesian_coord[:, 18] = tmp[:, 0]
+
+ L4_8 = np.vstack((L4A, L4C, L4A, L4B))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_8)
+ cartesian_coord[:, 19] = tmp[:, 0]
+
+ L4_9 = np.vstack((L4A, L4B, L4C, L4A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_9)
+ cartesian_coord[:, 20] = tmp[:, 0]
+
+ L4_10 = np.vstack((L4A, L4C, L4B, L4A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_10)
+ cartesian_coord[:, 21] = tmp[:, 0]
+
+ L4_11 = np.vstack((L4B, L4A, L4C, L4A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_11)
+ cartesian_coord[:, 22] = tmp[:, 0]
+
+ L4_12 = np.vstack((L4C, L4A, L4B, L4A))
+ tmp = volumetricToCartesianCoordinates(x_tet_ref, y_tet_ref,
+ z_tet_ref, L4_12)
+ cartesian_coord[:, 23] = tmp[:, 0]
+
+ for iPoint in np.arange(npointeg):
+ x[iPoint] = cartesian_coord[0, iPoint]
+ y[iPoint] = cartesian_coord[1, iPoint]
+ z[iPoint] = cartesian_coord[2, iPoint]
+ else:
+ disp('Number of gauss points not supported')
+
+ return Wi, x, y, z
+
+
+def volumetricToCartesianCoordinates(x, y, z, L):
+ ''' Change of volumetric coord to cartesian coord.
+
+ :param float-array x: x-coord of real element.
+ :param float-array y: y-coord of real element.
+ :param float-array z: z-coord of real element.
+ :param float-array L: xyz-coord of reference element.
+ :return: points in cartesian coord.
+ :rtype: ndarray
+ '''
+ # Number of points
+ size = L.shape
+ nPoints = size[1]
+
+ # Number of dimensions
+ nDimensions = 3
+
+ # Allocate
+ points = np.zeros((nDimensions, nPoints), dtype=np.float)
+
+ # Change of volumetric coord to cartesian coord
+ LL = np.transpose(L)
+
+ points[0, :] = np.matmul(LL, x)
+ points[1, :] = np.matmul(LL, y)
+ points[2, :] = np.matmul(LL, z)
+
+ return points
+
+
+def cartesianToVolumetricCoordinates(x, y, z, r):
+ ''' Change of cartesian coord to volumetric coord.
+
+ :param float-array x: x-coord of real element.
+ :param float-array y: y-coord of real element.
+ :param float-array z: z-coord of real element.
+ :param float-array r: xyz-coord of reference element.
+ :return: points in volumetric coord.
+ :rtype: ndarray
+ '''
+
+ # Initialization
+ matrix = np.vstack((x, y, z, np.ones(4, dtype=np.float)))
+
+ # Coord transformation
+ matrix_inv = inv(matrix)
+
+ L = np.zeros(4, dtype=np.float)
+ tmp = np.hstack((r[0], r[1], r[2], np.float(1)))
+ L[0] = np.dot(matrix_inv[0, :], tmp)
+ L[1] = np.dot(matrix_inv[1, :], tmp)
+ L[2] = np.dot(matrix_inv[2, :], tmp)
+ L[3] = np.dot(matrix_inv[3, :], tmp)
+
+ return L
+
+
def unitary_test():
''' Unitary test for fem.py script.
'''
+
if __name__ == '__main__':
# Standard module import
unitary_test()
@@ -901,5 +1353,6 @@ def unitary_test():
# Standard module import
import itertools
import numpy as np
+ from scipy.linalg import inv
# PETGEM module import
from petgem.efem.vectorMatrixFunctions import findUniqueRows
diff --git a/petgem/efem/vectorMatrixFunctions.py b/petgem/efem/vectorMatrixFunctions.py
old mode 100644
new mode 100755
index 16ba751..aeefc58
--- a/petgem/efem/vectorMatrixFunctions.py
+++ b/petgem/efem/vectorMatrixFunctions.py
@@ -30,6 +30,8 @@ def findUniqueRows(array, return_index=False, return_inverse=False):
unique array.
:param bool return_inverse: indices of the unique array that
can be used to reconstruct array.
+ :return: unique rows.
+ :rtype: ndarray.
'''
array = np.ascontiguousarray(array)
@@ -55,10 +57,43 @@ def findUniqueRows(array, return_index=False, return_inverse=False):
return out
+def crossprod(x, y):
+ ''' Compute cross product of two arrays.
+
+ :param float-array x: array1.
+ :param float-array y: array2.
+ :return: cross product.
+ :rtype: ndarray.
+ '''
+ # Cross product
+ compx = x[1]*y[2] - x[2]*y[1]
+ compy = -(x[0]*y[2] - x[2]*y[0])
+ compz = x[0]*y[1] - x[1]*y[0]
+
+ z = np.vstack((compx, compy, compz))
+
+ return z
+
+
+def is_duplicate_entry(x):
+ ''' Compute number of duplicate entries in a vector.
+
+ :param int-array x: matrix.
+ :return: number of duplicate entries.
+ :rtype: int.
+ '''
+ counts = np.bincount(x)
+ duplicate_entries = np.where(counts > 1)[0]
+ num_duplicate = duplicate_entries.size
+
+ return num_duplicate
+
+
def unitary_test():
''' Unitary test for vector_matrix_functions.py script.
'''
+
if __name__ == '__main__':
# Standard module import
import sys
diff --git a/petgem/mesh/__init__.py b/petgem/mesh/__init__.py
old mode 100644
new mode 100755
diff --git a/petgem/mesh/__pycache__/__init__.cpython-35.pyc b/petgem/mesh/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..a0dff85
Binary files /dev/null and b/petgem/mesh/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/mesh/__pycache__/__init__.cpython-36.pyc b/petgem/mesh/__pycache__/__init__.cpython-36.pyc
new file mode 100755
index 0000000..c21eb9e
Binary files /dev/null and b/petgem/mesh/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/mesh/__pycache__/mesh.cpython-35.pyc b/petgem/mesh/__pycache__/mesh.cpython-35.pyc
new file mode 100755
index 0000000..a9c4edc
Binary files /dev/null and b/petgem/mesh/__pycache__/mesh.cpython-35.pyc differ
diff --git a/petgem/mesh/__pycache__/mesh.cpython-36.pyc b/petgem/mesh/__pycache__/mesh.cpython-36.pyc
new file mode 100644
index 0000000..ce8e019
Binary files /dev/null and b/petgem/mesh/__pycache__/mesh.cpython-36.pyc differ
diff --git a/petgem/mesh/mesh.py b/petgem/mesh/mesh.py
old mode 100644
new mode 100755
index cbd0bd7..9907c12
--- a/petgem/mesh/mesh.py
+++ b/petgem/mesh/mesh.py
@@ -105,6 +105,8 @@ def __init__(self, mshfilename):
# Close file
self.mshfID.close()
+ return
+
def __gmshPrint__(self, msg):
''' Print a message related with a gmshObject.
@@ -122,6 +124,8 @@ def __gmshError__(self, msg):
'''
sys.stderr.write(' gmshObject: Error! -> ' + msg + '\n')
+ return
+
def __destroy__(self):
''' Destroy a gmshObject.
@@ -129,6 +133,8 @@ def __destroy__(self):
'''
self.mshfID.close()
+ return
+
def printNumberNodes(self):
''' Print number of nodes of a gmshObject.
@@ -373,12 +379,16 @@ def gmshParser(self):
hexahedron_125_node = np.int32(93)
-def getMeshInfo(elemsN, edgesN, bEdges, rank):
+def getMeshInfo(nedelec_order, elemsN, elemsF,
+ facesN, edgesN, boundaries, rank):
''' Get and print data mesh.
+ :param int nedelec_order: nedelec element order.
:param matrix elemsN: elements-nodes connectivity.
+ :param matrix elemsF: elements-faces connectivity.
+ :param matrix facesN: faces-nodes connectivity.
:param matrix edgesN: edges-nodes connectivity.
- :param vector bEdges: boundary edges.
+ :param vector boundaries: boundaries.
:return: number of elements, number of edges, number
of boundaries and number of degrees of freedom
:rtype: int
@@ -388,23 +398,42 @@ def getMeshInfo(elemsN, edgesN, bEdges, rank):
# Number of edges
nEdges = edgesN.getSize()[0]
# Number of boundaries
- nBoundaries = bEdges.getSize()
- # Number of dofs
- ndofs = nEdges - nBoundaries
+ nBoundaries = boundaries.getSize()
+ # Number of faces
+ Istart_facesN, Iend_facesN = facesN.getOwnershipRange()
+ tmp = (facesN.getRow(Istart_facesN)[1].real).astype(PETSc.IntType)
+ nFaces = tmp[0]
+
+ # Compute number of DOFS
+ if nedelec_order == 1: # First order edge element
+ # Number of DOFs correspond to edges in the mesh
+ ndofs = nEdges
+ elif nedelec_order == 2: # Second order edge element
+ # Number of dofs
+ ndofs = nEdges*2 + nFaces*2
+ elif nedelec_order == 3: # Third order edge element
+ # Number of dofs
+ ndofs = nEdges*3 + nFaces*6 + nElems*3
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
# Print mesh information
if rank == 0:
PETSc.Sys.Print('\nMesh information')
PETSc.Sys.Print('='*75)
PETSc.Sys.Print(' Number of elements: {0:12}'.
format(str(nElems)))
+ PETSc.Sys.Print(' Number of faces: {0:12}'.
+ format(str(nFaces)))
PETSc.Sys.Print(' Number of edges: {0:12}'.
format(str(nEdges)))
PETSc.Sys.Print(' Number of dofs: {0:12}'.
format(str(ndofs)))
- PETSc.Sys.Print(' Number of boundary edges: {0:12}'.
+ PETSc.Sys.Print(' Number of boundaries: {0:12}'.
format(str(nBoundaries)))
- return nElems, nEdges, nBoundaries, ndofs
+ return nElems, nFaces, nEdges, ndofs, nBoundaries
def readGmshNodes(mesh_file):
@@ -580,6 +609,7 @@ def unitary_test():
''' Unitary test for mesh.py script.
'''
+
if __name__ == '__main__':
# Standard module import
import numpy as np
diff --git a/petgem/monitoring/__init__.py b/petgem/monitoring/__init__.py
old mode 100644
new mode 100755
diff --git a/petgem/monitoring/__pycache__/__init__.cpython-35.pyc b/petgem/monitoring/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..da97d85
Binary files /dev/null and b/petgem/monitoring/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/monitoring/__pycache__/__init__.cpython-36.pyc b/petgem/monitoring/__pycache__/__init__.cpython-36.pyc
new file mode 100755
index 0000000..bf69f48
Binary files /dev/null and b/petgem/monitoring/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/monitoring/__pycache__/monitoring.cpython-35.pyc b/petgem/monitoring/__pycache__/monitoring.cpython-35.pyc
new file mode 100755
index 0000000..b0a2aee
Binary files /dev/null and b/petgem/monitoring/__pycache__/monitoring.cpython-35.pyc differ
diff --git a/petgem/monitoring/__pycache__/monitoring.cpython-36.pyc b/petgem/monitoring/__pycache__/monitoring.cpython-36.pyc
new file mode 100644
index 0000000..406e007
Binary files /dev/null and b/petgem/monitoring/__pycache__/monitoring.cpython-36.pyc differ
diff --git a/petgem/monitoring/monitoring.py b/petgem/monitoring/monitoring.py
old mode 100644
new mode 100755
diff --git a/petgem/parallel/__init__.py b/petgem/parallel/__init__.py
old mode 100644
new mode 100755
diff --git a/petgem/parallel/__pycache__/__init__.cpython-35.pyc b/petgem/parallel/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..8e53774
Binary files /dev/null and b/petgem/parallel/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/parallel/__pycache__/__init__.cpython-36.pyc b/petgem/parallel/__pycache__/__init__.cpython-36.pyc
new file mode 100755
index 0000000..0462201
Binary files /dev/null and b/petgem/parallel/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/parallel/__pycache__/parallel.cpython-35.pyc b/petgem/parallel/__pycache__/parallel.cpython-35.pyc
new file mode 100755
index 0000000..09a4973
Binary files /dev/null and b/petgem/parallel/__pycache__/parallel.cpython-35.pyc differ
diff --git a/petgem/parallel/__pycache__/parallel.cpython-36.pyc b/petgem/parallel/__pycache__/parallel.cpython-36.pyc
new file mode 100644
index 0000000..6e7e9e6
Binary files /dev/null and b/petgem/parallel/__pycache__/parallel.cpython-36.pyc differ
diff --git a/petgem/parallel/parallel.py b/petgem/parallel/parallel.py
old mode 100644
new mode 100755
index 8239123..1a337a6
--- a/petgem/parallel/parallel.py
+++ b/petgem/parallel/parallel.py
@@ -36,21 +36,31 @@ def printMessage(msg, rank):
return
-def createParallelMatrix(dimension1, dimension2, nnz, communicator=None):
+def createParallelMatrix(dimension1, dimension2, nnz,
+ matrix_type, communicator=None):
''' Create a parallel sparse matrix in petsc format.
- :param int dimension1: matrix dimension (rows)
- :param int dimension2: matrix dimension (columns)
- :param int nnz: not zero pattern for allocation
- :param str communicator: mpi communicator
- :return: parallel matrix
- :rtype: petsc AIJ parallel matrix
+ :param int dimension1: matrix dimension (rows).
+ :param int dimension2: matrix dimension (columns).
+ :param int nnz: not zero pattern for allocation.
+ :param int matrix_type: matrix type for parallel computations.
+ :param str communicator: mpi communicator.
+ :return: parallel matrix.
+ :rtype: petsc AIJ parallel matrix.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
- parallel_matrix = PETSc.Mat().createAIJ([dimension1, dimension2],
- comm=communicator)
+ if matrix_type == 0: # No cuda support
+ parallel_matrix = PETSc.Mat().createAIJ([dimension1, dimension2],
+ comm=communicator)
+ elif matrix_type == 1: # Cuda support
+ parallel_matrix = PETSc.Mat().create(comm=communicator)
+ parallel_matrix.setType('aijcusparse')
+ parallel_matrix.setSizes([dimension1, dimension2])
+ else:
+ raise ValueError('Cuda option=', matrix_type, ' not supported.')
+
parallel_matrix.setPreallocationNNZ((nnz, nnz))
parallel_matrix.setFromOptions()
parallel_matrix.setUp()
@@ -58,18 +68,26 @@ def createParallelMatrix(dimension1, dimension2, nnz, communicator=None):
return parallel_matrix
-def createParallelVector(size, communicator=None):
+def createParallelVector(size, vector_type, communicator=None):
''' Create a parallel vector in petsc format.
- :param int size: vector size
- :param str communicator: mpi communicator
- :return: parallel vector
- :rtype: petsc parallel vector
+ :param int size: vector size.
+ :param int vector_type: vector type for parallel computations.
+ :param str communicator: mpi communicator.
+ :return: parallel vector.
+ :rtype: petsc parallel vector.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
- parallel_vector = PETSc.Vec().createMPI(size, comm=communicator)
+ if vector_type == 0: # No cuda support
+ parallel_vector = PETSc.Vec().createMPI(size, comm=communicator)
+ elif vector_type == 1: # Cuda support
+ parallel_vector = PETSc.Vec().create(comm=communicator)
+ parallel_vector.setType('cuda')
+ parallel_vector.setSizes(size)
+ else:
+ raise ValueError('Cuda option=', vector_type, ' not supported.')
parallel_vector.setUp()
return parallel_vector
@@ -78,11 +96,11 @@ def createParallelVector(size, communicator=None):
def createParallelDenseMatrix(dimension1, dimension2, communicator=None):
''' Create a parallel dense matrix in petsc format.
- :param int dimension1: matrix dimension (rows)
- :param int dimension2: matrix dimension (columns)
- :param str communicator: mpi communicator
- :return: parallel matrix
- :rtype: petsc parallel and dense matrix
+ :param int dimension1: matrix dimension (rows).
+ :param int dimension2: matrix dimension (columns).
+ :param str communicator: mpi communicator.
+ :return: parallel matrix.
+ :rtype: petsc parallel and dense matrix.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
@@ -98,11 +116,11 @@ def createParallelDenseMatrix(dimension1, dimension2, communicator=None):
def createSequentialDenseMatrixWithArray(dimension1, dimension2, data):
''' Given an input array, create a sequential dense matrix in petsc format.
- :param int dimension1: matrix dimension (rows)
- :param int dimension2: matrix dimension (columns)
- :param ndarray data: data to be exported
- :return: parallel matrix
- :rtype: petsc parallel and dense matrix
+ :param int dimension1: matrix dimension (rows).
+ :param int dimension2: matrix dimension (columns).
+ :param ndarray data: data to be exported.
+ :return: parallel matrix.
+ :rtype: petsc parallel and dense matrix.
'''
parallel_matrix = PETSc.Mat().createDense([dimension1, dimension2],
@@ -117,9 +135,9 @@ def createSequentialDenseMatrixWithArray(dimension1, dimension2, data):
def createSequentialVectorWithArray(data):
''' Given an input array, create a sequential vector in petsc format.
- :param ndarray data: data to be exported
- :return: parallel matrix
- :rtype: petsc parallel and dense matrix
+ :param ndarray data: data to be exported.
+ :return: parallel matrix.
+ :rtype: petsc parallel and dense matrix.
'''
parallel_vector = PETSc.Vec().createWithArray(data, comm=PETSc.COMM_SELF)
@@ -129,18 +147,29 @@ def createSequentialVectorWithArray(data):
return parallel_vector
-def createSequentialVector(size, communicator=None):
+def createSequentialVector(size, vector_type, communicator=None):
''' Create a sequential vector in petsc format.
- :param int size: vector size
- :param str communicator: mpi communicator
- :return: sequential vector
- :rtype: petsc sequential vector
+ :param int size: vector size.
+ :param int vector_type: vector type for parallel computations.
+ :param str communicator: mpi communicator.
+ :return: sequential vector.
+ :rtype: petsc sequential vector.
'''
if communicator is None:
communicator = PETSc.COMM_SELF
- sequential_vector = PETSc.Vec().createSeq(size, comm=communicator)
+ #sequential_vector = PETSc.Vec().createSeq(size, comm=communicator)
+ #sequential_vector.setUp()
+
+
+ if vector_type == 0: # No cuda support
+ sequential_vector = PETSc.Vec().createSeq(size, comm=communicator)
+ elif vector_type == 1: # Cuda support
+ sequential_vector = PETSc.Vec().create(comm=communicator)
+ sequential_vector.setType('cuda')
+ sequential_vector.setSizes(size)
+
sequential_vector.setUp()
return sequential_vector
@@ -150,10 +179,10 @@ def readPetscMatrix(input_file, communicator=None):
''' Read a Petsc matrix which format is defined by two files:
input_file.dat and input_file.info
- :param str input_file: file name to be readed
- :param str communicator: mpi communicator
- :return: petsc_matrix
- :rtype: petsc sparse matrix
+ :param str input_file: file name to be readed.
+ :param str communicator: mpi communicator.
+ :return: petsc_matrix.
+ :rtype: petsc sparse matrix.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
@@ -169,10 +198,10 @@ def readPetscVector(input_file, communicator=None):
''' Read a Petsc vector which format is defined by two files:
input_file.dat and input_file.info.
- :param str input_file: file name to be readed
- :param str communicator: mpi communicator
- :return: petsc_vector
- :rtype: petsc vector
+ :param str input_file: file name to be readed.
+ :param str communicator: mpi communicator.
+ :return: petsc_vector.
+ :rtype: petsc vector.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
@@ -188,10 +217,10 @@ def writePetscVector(output_file, data, communicator=None):
''' Write a Petsc vector which format is defined by two files:
output_file.dat and output_file.info.
- :param str output_file: file name to be saved
- :param petsc vector data: array to be saved
- :param str communicator: mpi communicator
- :return: None
+ :param str output_file: file name to be saved.
+ :param petsc vector data: array to be saved.
+ :param str communicator: mpi communicator.
+ :return: None.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
@@ -207,10 +236,10 @@ def writeDenseMatrix(output_file, data, communicator=None):
''' Write a Petsc dense matrix which format is defined by two files:
output_file.dat and output_file.info.
- :param str output_file: file name to be saved
- :param petsc matrix data: dense matrix to be saved
- :param str communicator: mpi communicator
- :return: None
+ :param str output_file: file name to be saved.
+ :param petsc matrix data: dense matrix to be saved.
+ :param str communicator: mpi communicator.
+ :return: None.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
@@ -228,10 +257,10 @@ def writeParallelDenseMatrix(output_file, data, communicator=None):
''' Write a Petsc parallel dense matrix which format is defined by two
files: output_file.dat and output_file.info.
- :param str output_file: file name to be saved
- :param petsc matrix data: dense matrix to be saved
- :param str communicator: mpi communicator
- :return: None
+ :param str output_file: file name to be saved.
+ :param petsc matrix data: dense matrix to be saved.
+ :param str communicator: mpi communicator.
+ :return: None.
'''
if communicator is None:
communicator = PETSc.COMM_WORLD
@@ -243,26 +272,27 @@ def writeParallelDenseMatrix(output_file, data, communicator=None):
return
-def getRanges(elemsE, bEdges, receivers, size, rank):
+def getRanges(elemsE, boundaries, receivers, size, rank):
''' Get owner ship ranges of matrices and vectors for parallel computations.
- :param petsc matrix elemsE: elements-edges connectivity
- :param petsc vector bEdges: boundary-edges indexes
- :param petsc matrix receivers: receivers matrix
- :param int size: size of the parallel pool
- :para int rank: MPI rank
+ :param petsc matrix elemsE: elements-edges connectivity.
+ :param petsc vector boundaries: boundary indexes.
+ :param petsc matrix receivers: receivers matrix.
+ :param int size: size of the parallel pool.
+ :para int rank: MPI rank.
:return: Istart_elemsE, Iend_elemsE, Istart_bEdges,
- Iend_bEdges, Istart_bEdges, Iend_bEdges,
- Istart_receivers, Iend_receivers
+ Iend_bEdges, Istart_boundaries, Iend_boundaries,
+ Istart_receivers, Iend_receivers.
:rtype: int
'''
# Get global indices
# elemsE
Istart_elemsE, Iend_elemsE = elemsE.getOwnershipRange()
# bEdges
- Istart_bEdges, Iend_bEdges = bEdges.getOwnershipRange()
+ Istart_boundaries, Iend_boundaries = boundaries.getOwnershipRange()
# receivers
Istart_receivers, Iend_receivers = receivers.getOwnershipRange()
+
if rank == 0:
# Print size of MPI pool
PETSc.Sys.Print(' Number of MPI tasks: ', size)
@@ -273,53 +303,104 @@ def getRanges(elemsE, bEdges, receivers, size, rank):
Istart_elemsE, Iend_elemsE)
PETSc.Sys.syncFlush()
- return (Istart_elemsE, Iend_elemsE, Istart_bEdges,
- Iend_bEdges, Istart_receivers, Iend_receivers)
+ return (Istart_elemsE, Iend_elemsE, Istart_boundaries,
+ Iend_boundaries, Istart_receivers, Iend_receivers)
-def parallelAssembler(modelling, A, b, nodes, elemsE, elemsN, elemsSigma,
- Istart_elemsE, Iend_elemsE, rank):
+def parallelAssembler(modelling, A, b, nodes, elemsE, elemsN, elemsF, facesN,
+ elemsSigma, Istart_elemsE, Iend_elemsE, nEdges, nFaces,
+ rank):
''' Assembly matrix A and vector b for 3D CSEM in parallel.
- :param dictionary modelling: CSEM modelling with physical parameters
- :param petsc matrix A: left-hand side
- :param petsc vector b: right-hand side
- :param petsc matrix nodes: nodal coordinates
- :param petsc matrix elemsE: elements-edges connectivity
- :param petsc matrix elemsN: elements-nodes connectivity
- :param petsc vector elemsSigma: elements-conductivity array
- :param int Istart_elemsE: init range for assembly
- :param int Iend_elemsE: last range for assembly
- :para int rank: MPI rank
- :return: matrix A, vector b assembled, elapsedTimeAssembly
- :rtype: petsc matrix, petsc vector and float
+ :param dictionary modelling: CSEM modelling with physical parameters.
+ :param petsc matrix A: left-hand side.
+ :param petsc vector b: right-hand side.
+ :param petsc matrix nodes: nodal coordinates.
+ :param petsc matrix elemsE: elements-edges connectivity.
+ :param petsc matrix elemsN: elements-nodes connectivity.
+ :param petsc matrix elemsF: elements-faces connectivity.
+ :param petsc matrix facesN: faces-nodes connectivity.
+ :param petsc vector elemsSigma: elements-conductivity array.
+ :param int Istart_elemsE: init range for assembly.
+ :param int Iend_elemsE: last range for assembly.
+ :param int nEdges: total number of edges in the mesh.
+ :para int rank: MPI rank.
+ :return: matrix A, vector b assembled, elapsedTimeAssembly.
+ :rtype: petsc matrix, petsc vector and float.
'''
# Print information of assembly
PETSc.Sys.syncPrint(' Rank: ', rank, ' is assembling ',
Iend_elemsE-Istart_elemsE, ' elements')
PETSc.Sys.syncFlush()
- # Start timer
- Init_assembly = getTime()
-
- # Compute contributions for all local elements
- for iEle in np.arange(Istart_elemsE, Iend_elemsE):
- # Get coordinates of iEle
- coordEle = nodes.getRow(iEle)[1].real
- # Get edges of iEle
- edgesEle = (elemsE.getRow(iEle)[1].real).astype(PETSc.IntType)
- # Get nodal indexes of iEle
- nodesEle = elemsN.getRow(iEle)[1].real
- # Get sigma of iEle
- sigmaEle = elemsSigma.getValue(iEle).real
- # Compute elemental contributions for iEle
- # Elemental matrix (Ae) and elemental vector (be)
- [Ae, be] = computeElementalContributionsMPI(modelling, coordEle,
- nodesEle, sigmaEle)
- # Add local contributions to global matrix
- A.setValues(edgesEle, edgesEle, Ae, addv=PETSc.InsertMode.ADD_VALUES)
- # Add local contributions to global vector
- b.setValues(edgesEle, be, addv=PETSc.InsertMode.ADD_VALUES)
+ # Get order of edge elements
+ nedelec_order = modelling['NEDELEC_ORDER']
+
+ if nedelec_order == 1: # First order edge element
+
+ # Start timer
+ Init_assembly = getTime()
+
+ # Compute contributions for all local elements
+ for iEle in np.arange(Istart_elemsE, Iend_elemsE):
+ # Get coordinates of iEle
+ coordEle = nodes.getRow(iEle)[1].real
+ # Get nodal indexes of iEle
+ nodesEle = (elemsN.getRow(iEle)[1].real).astype(PETSc.IntType)
+ # Get sigma of iEle
+ sigmaEle = elemsSigma.getValue(iEle).real
+ # Get dofs of iEle
+ dofsEle = (elemsE.getRow(iEle)[1].real).astype(PETSc.IntType)
+ # Compute elemental contributions for iEle
+ # Elemental matrix (Ae) and elemental vector (be)
+ [Ae, be] = computeElementalContributionsMPI_FirstOrder(modelling,
+ coordEle,
+ nodesEle,
+ sigmaEle)
+ # Add local contributions to global matrix
+ A.setValues(dofsEle, dofsEle, Ae, addv=PETSc.InsertMode.ADD_VALUES)
+ # Add local contributions to global vector
+ b.setValues(dofsEle, be, addv=PETSc.InsertMode.ADD_VALUES)
+
+ # Second or third order edge element
+ elif nedelec_order == 2 or nedelec_order == 3:
+
+ # Start timer
+ Init_assembly = getTime()
+
+ # Compute contributions for all local elements
+ for iEle in np.arange(Istart_elemsE, Iend_elemsE):
+ # Get coordinates of iEle
+ coordEle = nodes.getRow(iEle)[1].real
+ # Get edges indexes of iEle
+ edgesEle = (elemsE.getRow(iEle)[1].real).astype(PETSc.IntType)
+ # Get nodal indexes of iEle
+ nodesEle = (elemsN.getRow(iEle)[1].real).astype(PETSc.IntType)
+ # Get faces indexes of iEle
+ facesEle = (elemsF.getRow(iEle)[1].real).astype(PETSc.IntType)
+ # Get nodes indexes for each face
+ nodesFaceEle = (facesN.getRow(iEle)[1].real).astype(PETSc.IntType)
+ nodesFaceEle = np.reshape(np.delete(nodesFaceEle, 0), (4, 3))
+ # Get sigma of iEle
+ sigmaEle = elemsSigma.getValue(iEle).real
+
+ # Compute dofs of iEle
+ dofsEle = computeElementDOFs(iEle, nodesEle, edgesEle, facesEle,
+ nodesFaceEle, nEdges, nFaces,
+ nedelec_order)
+ dofsEle = dofsEle.astype(PETSc.IntType)
+ # Compute elemental contributions for iEle
+ # Elemental matrix (Ae) and elemental vector (be)
+ [Ae,
+ be] = computeElementalContributionsMPI_HighOrder(modelling,
+ coordEle,
+ nodesEle,
+ sigmaEle,
+ nedelec_order)
+ # Add local contributions to global matrix
+ A.setValues(dofsEle, dofsEle, Ae, addv=PETSc.InsertMode.ADD_VALUES)
+ # Add local contributions to global vector
+ b.setValues(dofsEle, be, addv=PETSc.InsertMode.ADD_VALUES)
# Start global system assembly
A.assemblyBegin()
@@ -341,6 +422,7 @@ def unitary_test():
''' Unitary test for parallel.py script.
'''
+
if __name__ == '__main__':
# Standard module import
unitary_test()
@@ -350,4 +432,6 @@ def unitary_test():
from petsc4py import PETSc
# PETGEM module import
from petgem.monitoring.monitoring import getTime
- from petgem.solver.assembler import computeElementalContributionsMPI
+ from petgem.efem.efem import computeElementDOFs
+ from petgem.solver.assembler import computeElementalContributionsMPI_FirstOrder
+ from petgem.solver.assembler import computeElementalContributionsMPI_HighOrder
diff --git a/petgem/postprocessing/__init__.py b/petgem/postprocessing/__init__.py
old mode 100644
new mode 100755
diff --git a/petgem/postprocessing/__pycache__/__init__.cpython-35.pyc b/petgem/postprocessing/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..a6e1b46
Binary files /dev/null and b/petgem/postprocessing/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/postprocessing/__pycache__/__init__.cpython-36.pyc b/petgem/postprocessing/__pycache__/__init__.cpython-36.pyc
new file mode 100755
index 0000000..c1ea915
Binary files /dev/null and b/petgem/postprocessing/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/postprocessing/__pycache__/postprocessing.cpython-35.pyc b/petgem/postprocessing/__pycache__/postprocessing.cpython-35.pyc
new file mode 100755
index 0000000..bc4c258
Binary files /dev/null and b/petgem/postprocessing/__pycache__/postprocessing.cpython-35.pyc differ
diff --git a/petgem/postprocessing/__pycache__/postprocessing.cpython-36.pyc b/petgem/postprocessing/__pycache__/postprocessing.cpython-36.pyc
new file mode 100644
index 0000000..0a3e791
Binary files /dev/null and b/petgem/postprocessing/__pycache__/postprocessing.cpython-36.pyc differ
diff --git a/petgem/postprocessing/postprocessing.py b/petgem/postprocessing/postprocessing.py
old mode 100644
new mode 100755
index bb4f8d7..1fa7a3b
--- a/petgem/postprocessing/postprocessing.py
+++ b/petgem/postprocessing/postprocessing.py
@@ -103,13 +103,13 @@ def EpReceiverComputation(model, point, numDimensions):
SIGMA_BGROUND = np.float(model['CONDUCTIVITY_BACKGROUND'])
SRC_POS = np.asarray(model['SRC_POS'], dtype=np.float)
SRC_DIREC = np.int(model['SRC_DIREC'])
- I = np.float(model['SRC_CURRENT'])
+ II = np.float(model['SRC_CURRENT'])
dS = np.float(model['SRC_LENGTH'])
# Source position as independent variables
- X0 = np.float64(SRC_POS[0])
- Y0 = np.float64(SRC_POS[1])
- Z0 = np.float64(SRC_POS[2])
+ X0 = np.float(SRC_POS[0])
+ Y0 = np.float(SRC_POS[1])
+ Z0 = np.float(SRC_POS[2])
# Compute constants
# Imaginary part for complex numbers
@@ -128,37 +128,37 @@ def EpReceiverComputation(model, point, numDimensions):
xx = point[0] - X0
yy = point[1] - Y0
zz = point[2] - Z0
- r = np.float64(np.sqrt(xx**2 + yy**2 + zz**2))
+ r = np.float(np.sqrt(xx**2 + yy**2 + zz**2))
- if(r < np.float64(1.0e0)):
- r = np.float64(1.0e0)
+ if(r < np.float(1.0e0)):
+ r = np.float(1.0e0)
# E = AA [ BB + (wavenumber^2 * r^2 -1i * wavenumber * r-1)]
- AA = I * dS * \
- (np.float64(4.0) * np.pi * SIGMA_BGROUND * r**3)**-1 * \
+ AA = II * dS * \
+ (np.float(4.0) * np.pi * SIGMA_BGROUND * r**3)**-1 * \
np.exp((-imag_part) * WAVENUMBER * r)
BB = -WAVENUMBER**2 * r**2 + \
- (np.float64(3.0) * imag_part * WAVENUMBER * r) + \
- np.float64(3.0)
+ (np.float(3.0) * imag_part * WAVENUMBER * r) + \
+ np.float(3.0)
if SRC_DIREC == 1:
# X-directed
Ep[0] = AA * ((xx**2/r**2)*BB + (WAVENUMBER**2 * r**2 - imag_part *
- WAVENUMBER * r - np.float64(1.0)))
+ WAVENUMBER * r - np.float(1.0)))
Ep[1] = AA * (xx*yy/r**2)*BB
Ep[2] = AA * (xx*zz/r**2)*BB
elif SRC_DIREC == 2:
# Y-directed
Ep[0] = AA * (xx*yy/r**2)*BB
Ep[1] = AA * ((yy**2/r**2)*BB + (WAVENUMBER**2 * r**2 - imag_part *
- WAVENUMBER*r-np.float64(1.0)))
+ WAVENUMBER*r-np.float(1.0)))
Ep[2] = AA * (yy*zz/r**2)*BB
else:
# Z-directed
Ep[0] = AA * (xx*zz/r**2)*BB
Ep[1] = AA * (zz*yy/r**2)*BB
Ep[2] = AA * ((zz**2/r**2)*BB + (WAVENUMBER**2 * r**2 - imag_part *
- WAVENUMBER*r-np.float64(1.0)))
+ WAVENUMBER*r-np.float(1.0)))
return Ep
@@ -181,14 +181,14 @@ def EtReceiverComputation(primary_field, secondary_field, numDimensions):
def EsReceiverComputation(field, coordEle, coordReceiver, nodesEle,
- edgeOrder, numDimensions):
+ nedelec_order, numDimensions):
''' Compute the secondary electric field on receivers.
:param ndarray field: secondary field to be interpolated
:param ndarray coordElement: element spatial coordinates
:param ndarray coordReceiver: receiver spatial coordinates
:param ndarray nodesEle: nodal indices of element (element container)
- :param int edgeOrder: order of tetrahedral edge element
+ :param int nedelec_order: order of tetrahedral edge element
:param int numDimensions: number of dimensions
:return: secondary electric field on receivers
:rtype: ndarray.
@@ -197,66 +197,186 @@ def EsReceiverComputation(field, coordEle, coordReceiver, nodesEle,
# Imaginary part for complex numbers
imag_part = np.complex(0.0 + 1.0j)
- # ----------- Edge definition for the tetrahedral elements -----------
- # ----- Table 8.2 of Jin's book. Here is consider as an 1D-array -----
- edgesN = np.array([0, 1, 0, 2, 0, 3, 1, 2, 3, 1, 2, 3], dtype=np.int)
-
- # ----------- Definition of arrays for vector operations -----------
- # Signs computation
- idx_signs1 = np.array([1, 2, 3, 2, 1, 3], dtype=np.int)
- idx_signs2 = np.array([0, 0, 0, 1, 3, 2], dtype=np.int)
-
- # Allocate
- Es = np.zeros(numDimensions, dtype=np.complex)
-
- # ----------- Compute edges's length of element -----------
- tmp = coordEle.reshape(4, 3)
- tmp = tmp[edgesN, :]
- edges = tmp[1::2, :] - tmp[0::2, :]
- lengthEle = np.sqrt(np.sum(np.square(edges), axis=1))
-
- # ----------- Compute element's volume -----------
- CONST_VOL1 = np.float(1.0)/np.float(6.0)
- eleVol = (((coordEle[3]-coordEle[0])*(coordEle[7]-coordEle[1]) *
- (coordEle[11]-coordEle[2]) +
- (coordEle[4]-coordEle[1])*(coordEle[8]-coordEle[2]) *
- (coordEle[9]-coordEle[0]) +
- (coordEle[6]-coordEle[0])*(coordEle[10]-coordEle[1]) *
- (coordEle[5]-coordEle[2])) -
- ((coordEle[5]-coordEle[2])*(coordEle[7]-coordEle[1]) *
- (coordEle[9]-coordEle[0]) +
- (coordEle[6]-coordEle[0])*(coordEle[4]-coordEle[1]) *
- (coordEle[11]-coordEle[2]) +
- (coordEle[10]-coordEle[1])*(coordEle[8]-coordEle[2]) *
- (coordEle[3]-coordEle[0]))) * CONST_VOL1
-
- # ----------- Edge's signs -----------
- tmp = nodesEle
- tmp = tmp[idx_signs1] - tmp[idx_signs2]
- signsEle = tmp / np.abs(tmp)
-
- # Nedelec basis computation
- basis = nedelecBasisIterative(coordEle.reshape(4, 3),
- coordReceiver, eleVol, lengthEle, edgeOrder)
-
- rField = np.real(field)
- iField = np.imag(field)
-
- # Compute secondary field
- for kedge in np.arange(edgeOrder):
- # Add contributions
- Es[0] += (rField[kedge]*basis[kedge, 0]*signsEle[kedge]) + \
- (imag_part*iField[kedge]*basis[kedge, 0]*signsEle[kedge])
- Es[1] += (rField[kedge]*basis[kedge, 1]*signsEle[kedge]) + \
- (imag_part*iField[kedge]*basis[kedge, 1]*signsEle[kedge])
- Es[2] += (rField[kedge]*basis[kedge, 2]*signsEle[kedge]) + \
- (imag_part*iField[kedge]*basis[kedge, 2]*signsEle[kedge])
+ if nedelec_order == 1: # First order edge element
+ # ----------- Edge element of first order -----------
+ edgeOrder = 6
+
+ # ----------- Edge definition for the tetrahedral elements -----------
+ # ----- Table 8.2 of Jin's book. Here is consider as an 1D-array -----
+ edgesN = np.array([0, 1, 0, 2, 0, 3, 1, 2, 3, 1, 2, 3], dtype=np.int)
+
+ # ----------- Definition of arrays for vector operations -----------
+ # Signs computation
+ idx_signs1 = np.array([1, 2, 3, 2, 1, 3], dtype=np.int)
+ idx_signs2 = np.array([0, 0, 0, 1, 3, 2], dtype=np.int)
+
+ # Allocate
+ Es = np.zeros(numDimensions, dtype=np.complex)
+
+ # ----------- Compute edges's length of element -----------
+ tmp = coordEle.reshape(4, 3)
+ tmp = tmp[edgesN, :]
+ edges = tmp[1::2, :] - tmp[0::2, :]
+ lengthEle = np.sqrt(np.sum(np.square(edges), axis=1))
+
+ # ----------- Compute element's volume -----------
+ CONST_VOL1 = np.float(1.0)/np.float(6.0)
+ eleVol = (((coordEle[3]-coordEle[0])*(coordEle[7]-coordEle[1]) *
+ (coordEle[11]-coordEle[2]) +
+ (coordEle[4]-coordEle[1])*(coordEle[8]-coordEle[2]) *
+ (coordEle[9]-coordEle[0]) +
+ (coordEle[6]-coordEle[0])*(coordEle[10]-coordEle[1]) *
+ (coordEle[5]-coordEle[2])) -
+ ((coordEle[5]-coordEle[2])*(coordEle[7]-coordEle[1]) *
+ (coordEle[9]-coordEle[0]) +
+ (coordEle[6]-coordEle[0])*(coordEle[4]-coordEle[1]) *
+ (coordEle[11]-coordEle[2]) +
+ (coordEle[10]-coordEle[1])*(coordEle[8]-coordEle[2]) *
+ (coordEle[3]-coordEle[0]))) * CONST_VOL1
+
+ # ----------- Edge's signs -----------
+ tmp = nodesEle
+ tmp = tmp[idx_signs1] - tmp[idx_signs2]
+ signsEle = tmp / np.abs(tmp)
+
+ # Nedelec basis computation
+ basis = nedelecBasisIterative(coordEle.reshape(4, 3),
+ coordReceiver, eleVol,
+ lengthEle, edgeOrder)
+
+ rField = np.real(field)
+ iField = np.imag(field)
+
+ # Compute secondary field
+ for kedge in np.arange(edgeOrder):
+ # Add contributions
+ Es[0] += (rField[kedge]*basis[kedge, 0]*signsEle[kedge]) + \
+ (imag_part*iField[kedge]*basis[kedge, 0]*signsEle[kedge])
+ Es[1] += (rField[kedge]*basis[kedge, 1]*signsEle[kedge]) + \
+ (imag_part*iField[kedge]*basis[kedge, 1]*signsEle[kedge])
+ Es[2] += (rField[kedge]*basis[kedge, 2]*signsEle[kedge]) + \
+ (imag_part*iField[kedge]*basis[kedge, 2]*signsEle[kedge])
+
+ elif nedelec_order == 2: # Second edge element
+ # ----------- Nodal order -----------
+ nodalOrder = 4
+
+ # ----------- Edge element of second order -----------
+ edgeOrder = 20
+
+ # Allocate
+ Es = np.zeros(numDimensions, dtype=np.complex)
+
+ # ----- Initialization of edges/vertices/faces numbering ------
+ [edge_vertices, face_vertices, ref_ele] = edgeFaceVerticesInit()
+
+ # Element's nodes coordinates
+ coordEle = coordEle.reshape((numDimensions, nodalOrder), order='F')
+
+ # Elemental computations (Signs, jacobian, edges length, area faces)
+ [_, _, signs, nreal,
+ jacob, DetJacob, _] = computeSignsJacobLegth(coordEle, edge_vertices,
+ face_vertices,
+ nedelec_order)
+ # Definition of q vectors on faces
+ [qface1, qface2,
+ qface3, qface4,
+ invjj, GR] = definitionHighOrderTet(nreal, signs, jacob,
+ nedelec_order)
+
+ # Computation coefficients for basis functions
+ [a1, a2, a3, a4,
+ b1, b2, b3, b4,
+ c1, c2, c3, c4,
+ D, E, F, G, H,
+ II, JJ, K] = computeCoefficientsSecondOrder(qface1, qface2, qface3,
+ qface4, ref_ele,
+ edge_vertices,
+ face_vertices)
+ # Computation of basis functions
+ basis = nedelecBasisSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4, c1,
+ c2, c3, c4, D, E, F, G, H, II, JJ,
+ K, coordEle, coordReceiver)
+ # Reshape basis array (from 3D to 2D)
+ basis = np.reshape(basis, (numDimensions, edgeOrder))
+
+ rField = np.real(field)
+ iField = np.imag(field)
+
+ # Compute secondary field
+ for kedge in np.arange(edgeOrder):
+ # Add contributions
+ Es[0] += (rField[kedge]*basis[0, kedge]*signs[kedge]) + \
+ (imag_part*iField[kedge]*basis[0, kedge]*signs[kedge])
+ Es[1] += (rField[kedge]*basis[1, kedge]*signs[kedge]) + \
+ (imag_part*iField[kedge]*basis[1, kedge]*signs[kedge])
+ Es[2] += (rField[kedge]*basis[2, kedge]*signs[kedge]) + \
+ (imag_part*iField[kedge]*basis[2, kedge]*signs[kedge])
+
+ elif nedelec_order == 3: # Third edge element
+ # ----------- Nodal order -----------
+ nodalOrder = 4
+
+ # ----------- Edge element of third order -----------
+ edgeOrder = 45
+
+ # Allocate
+ Es = np.zeros(numDimensions, dtype=np.complex)
+
+ # ----- Initialization of edges/vertices/faces numbering ------
+ [edge_vertices, face_vertices, ref_ele] = edgeFaceVerticesInit()
+
+ # Element's nodes coordinates
+ coordEle = coordEle.reshape((numDimensions, nodalOrder), order='F')
+
+ # Elemental computations (Signs, jacobian, edges length, area faces)
+ [_, _, signs, nreal,
+ jacob, _, _] = computeSignsJacobLegth(coordEle, edge_vertices,
+ face_vertices, nedelec_order)
+ # Definition of q vectors on faces
+ [qface1, qface2,
+ qface3, qface4,
+ _, _] = definitionHighOrderTet(nreal, signs, jacob, nedelec_order)
+
+ # Computation of coefficients
+ [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N, O,
+ P, Q, R] = computeCoefficientsThirdOrder(qface1, qface2,
+ qface3, qface4)
+
+ # Computation of basis functions
+ basis = nedelecBasisThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N,
+ O, P, Q, R, coordEle, coordReceiver)
+
+ # Reshape basis array (from 3D to 2D)
+ basis = np.reshape(basis, (numDimensions, edgeOrder))
+
+ rField = np.real(field)
+ iField = np.imag(field)
+
+ # Compute secondary field
+ for kedge in np.arange(edgeOrder):
+ # Add contributions
+ Es[0] += (rField[kedge]*basis[0, kedge]*signs[kedge]) + \
+ (imag_part*iField[kedge]*basis[0, kedge]*signs[kedge])
+ Es[1] += (rField[kedge]*basis[1, kedge]*signs[kedge]) + \
+ (imag_part*iField[kedge]*basis[1, kedge]*signs[kedge])
+ Es[2] += (rField[kedge]*basis[2, kedge]*signs[kedge]) + \
+ (imag_part*iField[kedge]*basis[2, kedge]*signs[kedge])
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
return Es
def computeFieldsReceiver(modelling, coordReceiver, coordElement,
- nodesElement, x_field, edgeOrder, numDimensions):
+ nodesElement, x_field, nedelec_order, numDimensions):
''' Compute the CSEM modelling output: primary electric field, secondary
electric field and total electric field on receivers position.
@@ -265,7 +385,7 @@ def computeFieldsReceiver(modelling, coordReceiver, coordElement,
:param ndarray coordElement: element spatial coordinates
:param ndarray nodesElement: nodal indices of element (element container)
:param ndarray x_field: vector solution for receiver
- :param int edgeOrder: order of tetrahedral edge element
+ :param int nedelec_order: order of tetrahedral edge element
:param int numDimensions: number of dimensions
:return: primary, secondary and total electric field
:rtype: ndarray
@@ -275,7 +395,7 @@ def computeFieldsReceiver(modelling, coordReceiver, coordElement,
# ----- Secondary field computation -----
Es = EsReceiverComputation(x_field, coordElement, coordReceiver,
- nodesElement, edgeOrder, numDimensions)
+ nodesElement, nedelec_order, numDimensions)
# ----- Total field computation -----
Et = EtReceiverComputation(Ep, Es, numDimensions)
@@ -284,8 +404,8 @@ def computeFieldsReceiver(modelling, coordReceiver, coordElement,
def postProcessingFields(receivers, modelling, x, Iend_receivers,
- Istart_receivers, edgeOrder, nodalOrder,
- numDimensions, rank):
+ Istart_receivers, nedelec_order, vector_type,
+ nodalOrder, numDimensions, rank):
''' Compute the CSEM modelling output: primary electric field, secondary
electric field and total electric field on receivers position.
@@ -294,7 +414,7 @@ def postProcessingFields(receivers, modelling, x, Iend_receivers,
:param petsc vector x: solution vector
:param int Iend_receivers: last range for receivers
:param int Istart_receivers: init range for receivers
- :param int edgeOrder: order of tetrahedral edge element
+ :param int nedelec_order: order of tetrahedral edge element
:param int nodalOrder: order of tetrahedral nodal element
:param int numDimensions: number of dimensions
:param int rank: MPI rank
@@ -305,6 +425,16 @@ def postProcessingFields(receivers, modelling, x, Iend_receivers,
# Start timer
Init_postprocessing = getTime()
+ if nedelec_order == 1: # First order edge element
+ edgeOrder = 6
+ elif nedelec_order == 2: # Second edge element
+ edgeOrder = 20
+ elif nedelec_order == 3: # Third edge element
+ edgeOrder = 45
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
# Number of receivers
nReceivers = receivers.getSize()[0]
nReceiversLocal = Iend_receivers-Istart_receivers
@@ -315,44 +445,45 @@ def postProcessingFields(receivers, modelling, x, Iend_receivers,
nReceiversLocal, ' receivers')
PETSc.Sys.syncFlush()
- # Read edges-connectivity for receivers
+ # Read dofs-connectivity for receivers
# Auxiliar arrays
dataRecv = np.zeros(edgeOrder, dtype=np.float)
- edgesIdxRecv = np.zeros((nReceiversLocal, edgeOrder), dtype=PETSc.IntType)
+ dofsIdxRecv = np.zeros((nReceiversLocal, edgeOrder), dtype=PETSc.IntType)
idx = 0
for iRecv in np.arange(Istart_receivers, Iend_receivers):
# Get data of iRecv
temp = np.asarray(receivers.getRow(iRecv))
- dataRecv[:] = np.real(temp[1, 19:25])
+ dataRecv[:] = np.real(temp[1, 19:])
# Edge-indexes for iRecv
- edgesIdxRecv[idx, :] = (dataRecv).astype(PETSc.IntType)
+ dofsIdxRecv[idx, :] = (dataRecv).astype(PETSc.IntType)
idx += 1
# Gather global solution of x to local vector
# Sequential vector for gather tasks
x_local = createSequentialVector(edgeOrder*nReceiversLocal,
+ modelling['CUDA'],
communicator=None)
# Build Index set in PETSc format
- IS_edges = PETSc.IS().createGeneral(edgesIdxRecv.flatten(),
- comm=PETSc.COMM_WORLD)
+ IS_dofs = PETSc.IS().createGeneral(dofsIdxRecv.flatten(),
+ comm=PETSc.COMM_WORLD)
# Build gather vector
- gatherVector = PETSc.Scatter().create(x, IS_edges, x_local, None)
+ gatherVector = PETSc.Scatter().create(x, IS_dofs, x_local, None)
# Ghater values
gatherVector.scatter(x, x_local, PETSc.InsertMode.INSERT_VALUES,
PETSc.ScatterMode.FORWARD)
# Post-processing electric fields
# Create parallel structures
- EpX = createParallelVector(nReceivers, communicator=None)
- EpY = createParallelVector(nReceivers, communicator=None)
- EpZ = createParallelVector(nReceivers, communicator=None)
- EsX = createParallelVector(nReceivers, communicator=None)
- EsY = createParallelVector(nReceivers, communicator=None)
- EsZ = createParallelVector(nReceivers, communicator=None)
- EtX = createParallelVector(nReceivers, communicator=None)
- EtY = createParallelVector(nReceivers, communicator=None)
- EtZ = createParallelVector(nReceivers, communicator=None)
+ EpX = createParallelVector(nReceivers, vector_type, communicator=None)
+ EpY = createParallelVector(nReceivers, vector_type, communicator=None)
+ EpZ = createParallelVector(nReceivers, vector_type, communicator=None)
+ EsX = createParallelVector(nReceivers, vector_type, communicator=None)
+ EsY = createParallelVector(nReceivers, vector_type, communicator=None)
+ EsZ = createParallelVector(nReceivers, vector_type, communicator=None)
+ EtX = createParallelVector(nReceivers, vector_type, communicator=None)
+ EtY = createParallelVector(nReceivers, vector_type, communicator=None)
+ EtZ = createParallelVector(nReceivers, vector_type, communicator=None)
EpDense = createParallelDenseMatrix(nReceivers, numDimensions,
communicator=None)
EsDense = createParallelDenseMatrix(nReceivers, numDimensions,
@@ -385,7 +516,7 @@ def postProcessingFields(receivers, modelling, x, Iend_receivers,
(idx *
edgeOrder) +
edgeOrder],
- edgeOrder,
+ nedelec_order,
numDimensions)
idx += 1
# Set primary field components
@@ -553,6 +684,7 @@ def unitary_test():
''' Unitary test for post_processing.py script.
'''
+
if __name__ == '__main__':
# Standard module import
unitary_test()
@@ -574,4 +706,11 @@ def unitary_test():
from petgem.parallel.parallel import printMessage
from petgem.parallel.parallel import writeDenseMatrix
from petgem.efem.efem import nedelecBasisIterative
+ from petgem.efem.efem import edgeFaceVerticesInit
+ from petgem.efem.efem import computeSignsJacobLegth
+ from petgem.efem.efem import definitionHighOrderTet
+ from petgem.efem.efem import computeCoefficientsSecondOrder
+ from petgem.efem.efem import nedelecBasisSecondOrder
+ from petgem.efem.efem import computeCoefficientsThirdOrder
+ from petgem.efem.efem import nedelecBasisThirdOrder
from petgem.monitoring.monitoring import getTime
diff --git a/petgem/preprocessing/__init__.py b/petgem/preprocessing/__init__.py
old mode 100644
new mode 100755
index 14e5fec..740363b
--- a/petgem/preprocessing/__init__.py
+++ b/petgem/preprocessing/__init__.py
@@ -3,7 +3,8 @@
from .preprocessing import checkNumberParamsPreprocessing
from .preprocessing import preprocessNodes
from .preprocessing import preprocessingNodalConnectivity
-from .preprocessing import preprocessingDOF
+from .preprocessing import preprocessingEdges
+from .preprocessing import preprocessingFaces
from .preprocessing import preprocessingConductivityModel
from .preprocessing import preprocessingDataReceivers
from .preprocessing import preprocessingNNZ
diff --git a/petgem/preprocessing/__pycache__/__init__.cpython-35.pyc b/petgem/preprocessing/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..6b054c9
Binary files /dev/null and b/petgem/preprocessing/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/preprocessing/__pycache__/__init__.cpython-36.pyc b/petgem/preprocessing/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..50600e9
Binary files /dev/null and b/petgem/preprocessing/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/preprocessing/__pycache__/preprocessing.cpython-35.pyc b/petgem/preprocessing/__pycache__/preprocessing.cpython-35.pyc
new file mode 100755
index 0000000..3352d52
Binary files /dev/null and b/petgem/preprocessing/__pycache__/preprocessing.cpython-35.pyc differ
diff --git a/petgem/preprocessing/__pycache__/preprocessing.cpython-36.pyc b/petgem/preprocessing/__pycache__/preprocessing.cpython-36.pyc
new file mode 100644
index 0000000..d259901
Binary files /dev/null and b/petgem/preprocessing/__pycache__/preprocessing.cpython-36.pyc differ
diff --git a/petgem/preprocessing/preprocessing.py b/petgem/preprocessing/preprocessing.py
old mode 100644
new mode 100755
index d12037b..577af9c
--- a/petgem/preprocessing/preprocessing.py
+++ b/petgem/preprocessing/preprocessing.py
@@ -32,12 +32,13 @@ def checkNumberParamsPreprocessing(init_params):
return num_params
-def buildPreprocessing(rank, MESH_FILE, MATERIAL_CONDUCTIVITIES,
+def buildPreprocessing(rank, NEDELEC_ORDER, MESH_FILE, MATERIAL_CONDUCTIVITIES,
RECEIVERS_FILE, OUT_DIR):
''' Build a dictionary with main parameters for
PETGEM preprocessing.
:param int rank: MPI rank.
+ :param in NEDELEC_ORDER: nedelec element order.
:param str MESH_FILE: file name of mesh.
:param ndarray MATERIAL_CONDUCTIVITIES: conductivity values of
materials in the mesh.
@@ -51,7 +52,8 @@ def buildPreprocessing(rank, MESH_FILE, MATERIAL_CONDUCTIVITIES,
PETSc.Sys.Print(' buildPreprocessing(): Creating a ' +
'preprocessing dictionary.')
- preprocessing = {'MESH_FILE': MESH_FILE,
+ preprocessing = {'NEDELEC_ORDER': NEDELEC_ORDER,
+ 'MESH_FILE': MESH_FILE,
'MATERIAL_CONDUCTIVITIES': MATERIAL_CONDUCTIVITIES,
'RECEIVERS_FILE': RECEIVERS_FILE,
'OUT_DIR': OUT_DIR
@@ -69,18 +71,20 @@ def printPreprocessingData(input_preprocessing, file_name):
'''
A = str(file_name)
- B = str(input_preprocessing['MESH_FILE'])
- C = str(input_preprocessing['MATERIAL_CONDUCTIVITIES'])
- D = str(input_preprocessing['RECEIVERS_FILE'])
- E = str(input_preprocessing['OUT_DIR'])
+ B = str(input_preprocessing['NEDELEC_ORDER'])
+ C = str(input_preprocessing['MESH_FILE'])
+ D = str(input_preprocessing['MATERIAL_CONDUCTIVITIES'])
+ E = str(input_preprocessing['RECEIVERS_FILE'])
+ F = str(input_preprocessing['OUT_DIR'])
PETSc.Sys.Print('\nData for preprocessing')
PETSc.Sys.Print('='*75)
PETSc.Sys.Print(' Preprocessing file name: {0:50}'.format(A))
- PETSc.Sys.Print(' Mesh file: {0:50}'.format(B))
- PETSc.Sys.Print(' Material conductivities: {0:50}'.format(C))
- PETSc.Sys.Print(' Receiver positions file: {0:50}'.format(D))
- PETSc.Sys.Print(' Out directory: {0:50}'.format(E))
+ PETSc.Sys.Print(' Nedelec element order: {0:50}'.format(B))
+ PETSc.Sys.Print(' Mesh file: {0:50}'.format(C))
+ PETSc.Sys.Print(' Material conductivities: {0:50}'.format(D))
+ PETSc.Sys.Print(' Receiver positions file: {0:50}'.format(E))
+ PETSc.Sys.Print(' Out directory: {0:50}'.format(F))
return
@@ -104,6 +108,15 @@ def checkPreprocessingConsistency(rank, in_dict, file_name):
PETSc.Sys.Print(' Checking preprocessing parameters consistency.')
+ # NEDELEC_ORDER parameter
+ msg = msg1 + 'NEDELEC_ORDER' + msg2
+ assert 'NEDELEC_ORDER' in in_dict, msg
+ msg = msg3 + 'NEDELEC_ORDER' + msg4
+ NEDELEC_ORDER = in_dict['NEDELEC_ORDER']
+ assert type(NEDELEC_ORDER) is int, msg
+ PETSc.Sys.Print(' checkPreprocessingConsistency(): NEDELEC_ORDER ' +
+ 'consistency OK.')
+
# NODES_FILE parameter
msg = msg1 + 'MESH_FILE' + msg2
assert 'MESH_FILE' in in_dict, msg
@@ -141,7 +154,8 @@ def checkPreprocessingConsistency(rank, in_dict, file_name):
'OUT_DIR consistency OK.')
# Create preprocessing dictionary
- out_model = buildPreprocessing(rank, MESH_FILE, MATERIAL_CONDUCTIVITIES,
+ out_model = buildPreprocessing(rank, NEDELEC_ORDER, MESH_FILE,
+ MATERIAL_CONDUCTIVITIES,
RECEIVERS_FILE, OUT_DIR)
return out_model
@@ -213,7 +227,6 @@ def readPreprocessingParams(input_params, rank):
preprocessing_temp.
preprocessing,
PARAMS_FILE_NAME)
-
# Print modelling content
if rank == 0:
printPreprocessingData(preprocessing, input_path)
@@ -321,121 +334,202 @@ def preprocessingNodalConnectivity(mesh_file, out_dir, rank):
return nElems
-def preprocessingDOF(mesh_file, out_dir, rank):
- ''' Preprocess degrees of freedom (DOF) and its associated data structures
- of a given mesh in Gmsh format. Here, dofs are defined for edge
- finite element computations.
+def preprocessingEdges(nedelec_order, mesh_file, out_dir, rank):
+ ''' Preprocess edges, edge boundaries and its associated data structures
+ of a given mesh in Gmsh format. For edge finite element of linear
+ order the edges are the dofs. For edge finite element of second order
+ the dofs are computed in runtime based on edges and faces on each
+ tetrahedral element.
+ :param int nedelec_order: nedelec element order.
:param str mesh_file: mesh file name to be preprocess.
:param str out_dir: path for output.
:param int rank: MPI rank.
- :return: number of DOFS.
+ :return: number of edges.
:rtype: int
'''
+ # ---------- Export Edges ----------
if rank == 0:
- PETSc.Sys.Print(' Degrees of freedom (dofs.dat)')
+ PETSc.Sys.Print(' Edges (edges.dat)')
# Check if mesh_file exist
success = checkFilePath(mesh_file)
if rank == 0:
if not success:
- msg = (' preprocessingDOF(): file ' + mesh_file +
+ msg = (' preprocessingEdges(): file ' + mesh_file +
' does not exist.')
raise ValueError(msg)
# Read connectivity
elemsN, nElems = readGmshConnectivity(mesh_file)
- # Compute dofs
- dofs, dofsNodes = computeDofs(elemsN, nElems)
- nDofs = dofsNodes.shape[0]
+ # Compute edges
+ elemsE, edgesNodes = computeEdges(elemsN, nElems, nedelec_order)
+ nEdges = edgesNodes.shape[0]
- # Compute faces
- elemsF, facesN = computeFaces(elemsN, nElems)
+ # Compute boundaries
+ boundaries, nDofs = computeBoundaries(elemsN, nElems, edgesNodes,
+ nedelec_order)
- # Compute boundary faces
- boundaryFacesN = computeBoundaryFaces(elemsF, facesN)
+ # ---------- Export Edges ----------
+ # Get matrix dimensions
+ size = elemsE.shape
+ # Build PETSc structures
+ matrix = createSequentialDenseMatrixWithArray(size[0], size[1], elemsE)
# Delete unnecesary arrays
- del elemsN
- del elemsF
- del facesN
+ del elemsE
- # Compute boundary dofs
- boundaryDofs = computeBoundaryDofs(dofsNodes, boundaryFacesN)
+ # Verify if OUT_DIR exists
+ checkIfDirectoryExist(out_dir)
- # Delete unnecesary arrays
- del boundaryFacesN
+ # Build path to save the file
+ out_path = out_dir + 'edges.dat'
+
+ # Write PETGEM edges in PETSc format
+ writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF)
+
+ # ---------- Export Edges to nodes ----------
+ if rank == 0:
+ PETSc.Sys.Print(' Edges connectivity (edgesNodes.dat)')
- # ---------- DOFS ----------
# Get matrix dimensions
- size = dofs.shape
+ size = edgesNodes.shape
# Build PETSc structures
- matrix = createSequentialDenseMatrixWithArray(size[0], size[1], dofs)
+ matrix = createSequentialDenseMatrixWithArray(size[0], size[1], edgesNodes)
# Delete unnecesary arrays
- del dofs
+ del edgesNodes
# Verify if OUT_DIR exists
checkIfDirectoryExist(out_dir)
# Build path to save the file
- out_path = out_dir + 'dofs.dat'
+ out_path = out_dir + 'edgesNodes.dat'
- # Write PETGEM nodes in PETSc format
+ # Write PETGEM edgesNodes in PETSc format
writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF)
- # ---------- DOFS TO NODES ----------
+ # ---------- Export boundaries ----------
if rank == 0:
- PETSc.Sys.Print(' Dofs connectivity (dofsNodes.dat)')
-
- # Get matrix dimensions
- size = dofsNodes.shape
+ PETSc.Sys.Print(' Boundaries (boundaries.dat)')
# Build PETSc structures
- matrix = createSequentialDenseMatrixWithArray(size[0], size[1], dofsNodes)
+ vector = createSequentialVectorWithArray(boundaries)
# Delete unnecesary arrays
- del dofsNodes
+ del boundaries
# Verify if OUT_DIR exists
checkIfDirectoryExist(out_dir)
# Build path to save the file
- out_path = out_dir + 'dofsNodes.dat'
+ out_path = out_dir + 'boundaries.dat'
# Write PETGEM nodes in PETSc format
+ writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF)
+
+ return nEdges, nDofs
+
+
+def preprocessingFaces(nedelec_order, mesh_file, out_dir, rank):
+ ''' Preprocess faces, face boundaries and its associated data structures
+ of a given mesh in Gmsh format.
+
+ :param int nedelec_order: nedelec element order.
+ :param str mesh_file: mesh file name to be preprocess.
+ :param str out_dir: path for output.
+ :param int rank: MPI rank.
+ :return: number of edges.
+ :rtype: int
+ '''
+
+ # Check if mesh_file exist
+ success = checkFilePath(mesh_file)
+
+ if rank == 0:
+ if not success:
+ msg = (' preprocessingFaces(): file ' + mesh_file +
+ ' does not exist.')
+ raise ValueError(msg)
+
+ # Read connectivity
+ elemsN, nElems = readGmshConnectivity(mesh_file)
+
+ # Compute faces
+ elemsF, facesN = computeFaces(elemsN, nElems, nedelec_order)
+
+ # Number of faces
+ size = facesN.shape
+ nFaces = size[0]
+
+ # Delete unnecesary arrays
+ del elemsN
+
+ # ---------- Export Faces connectivity ----------
+ if rank == 0:
+ PETSc.Sys.Print(' Faces connectivity (faces.dat)')
+
+ # Get matrix dimensions
+ size = elemsF.shape
+ # Build PETSc structures
+ matrix = createSequentialDenseMatrixWithArray(size[0], size[1], elemsF)
+
+ # Verify if OUT_DIR exists
+ checkIfDirectoryExist(out_dir)
+
+ # Build path to save the file
+ out_path = out_dir + 'faces.dat'
+
+ # Write PETGEM edges in PETSc format
writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF)
- # ---------- BOUNDARY DOFs ----------
+ # ---------- Export Faces connectivity ----------
if rank == 0:
- PETSc.Sys.Print(' Boundaries (boundaries.dat)')
+ PETSc.Sys.Print(' Faces-nodes connectivity (facesN.dat)')
+
+ # Build facesN connectivity for each element
+ nNodes_face = 3
+ nFaces_element = 4
+ # Allocate matrix with an additional position to store the total number of
+ # faces in the mesh
+ facesN_tmp = np.zeros((nElems, nNodes_face*nFaces_element+1))
+ for iEle in np.arange(nElems):
+ facesElement = elemsF[iEle, :]
+ nodesFace = facesN[facesElement, :]
+ facesN_tmp[iEle, 0] = nFaces
+ facesN_tmp[iEle, 1:] = nodesFace.reshape(1, nNodes_face*nFaces_element)
+
+ # Get matrix dimensions
+ size = facesN_tmp.shape
# Build PETSc structures
- vector = createSequentialVectorWithArray(boundaryDofs)
+ matrix = createSequentialDenseMatrixWithArray(size[0], size[1], facesN_tmp)
# Delete unnecesary arrays
- del boundaryDofs
+ del elemsF
+ del facesN
+ del facesN_tmp
# Verify if OUT_DIR exists
checkIfDirectoryExist(out_dir)
# Build path to save the file
- out_path = out_dir + 'boundaries.dat'
+ out_path = out_dir + 'facesNodes.dat'
- # Write PETGEM nodes in PETSc format
- writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF)
+ # Write PETGEM edges in PETSc format
+ writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF)
- return nDofs
+ return nFaces
def preprocessingConductivityModel(mesh_file, material_conductivities,
out_dir, rank):
''' Preprocess conductivity model associated to a given mesh in Gmsh
- format. Here, dofs are defined for edge finite element computations.
+ format.
:param str mesh_file: mesh file name to be preprocess.
:param ndarray material_conductivities: conductivity values
@@ -495,11 +589,11 @@ def preprocessingConductivityModel(mesh_file, material_conductivities,
return
-def preprocessingDataReceivers(mesh_file, receivers_file,
+def preprocessingDataReceivers(nedelec_order, mesh_file, receivers_file,
out_dir, rank):
- ''' Preprocess conductivity model associated to a given mesh in Gmsh
- format. Here, dofs are defined for edge finite element computations.
+ ''' Preprocess receivers and its data for a given 3D CSEM model.
+ :param int nedelec_order: nedelec element order.
:param str mesh_file: mesh file name to be preprocess.
:param str receivers_file: receiver positions file name to be preprocess.
:param str out_dir: path for output.
@@ -551,17 +645,26 @@ def preprocessingDataReceivers(mesh_file, receivers_file,
# Read connectivity
elemsN, nElems = readGmshConnectivity(mesh_file)
- # Compute dofs
- dofs, _ = computeDofs(elemsN, nElems)
+ # Compute edges
+ elemsE, _ = computeEdges(elemsN, nElems, nedelec_order)
+
+ # Number of edges
+ numberEdges = np.max(elemsE) + np.int(1)
- # Overwrite Delaunay structure with mesh_file connectivity
+ # Compute faces
+ elemsF, facesN = computeFaces(elemsN, nElems, nedelec_order)
+
+ # Number of faces
+ numberFaces = np.max(elemsF) + np.int(1)
+
+ # Overwrite Delaunay structure with mesh_file connectivity and points
tri.simplices = elemsN.astype(np.int32)
# Delete unnecesary arrays
del elemsN
# Find out which tetrahedral element points are in
- recvElems = tri.find_simplex(receivers)
+ recvElems = tri.find_simplex(receivers, tol=np.spacing(1))
# Determine if all receiver points were found
idx = np.where(recvElems < 0)[0]
@@ -592,9 +695,22 @@ def preprocessingDataReceivers(mesh_file, receivers_file,
np.savetxt(out_path, receivers, fmt='%1.8e')
# Allocate space for receives in PETGEM format
- numDimensions = 3
- nodalOrder = 4
- edgeOrder = 6
+ if nedelec_order == 1: # First order edge element
+ numDimensions = 3
+ nodalOrder = 4
+ edgeOrder = 6
+ elif nedelec_order == 2: # Second order edge element
+ numDimensions = 3
+ nodalOrder = 4
+ edgeOrder = 20
+ elif nedelec_order == 3: # Third order edge element
+ numDimensions = 3
+ nodalOrder = 4
+ edgeOrder = 45
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
+
allocate = numDimensions+nodalOrder*numDimensions+nodalOrder+edgeOrder
tmp = np.zeros((nReceivers, allocate), dtype=np.float)
@@ -603,26 +719,46 @@ def preprocessingDataReceivers(mesh_file, receivers_file,
for iReceiver in np.arange(nReceivers):
# If there is one receiver
if nReceivers == 1:
+ # Get index of tetrahedral element (receiver container)
+ iEle = recvElems
# Get receiver coordinates
coordiReceiver = receivers[0:]
# Get element coordinates (container element)
- coordElement = tri.points[tri.simplices[recvElems, :]]
+ coordElement = tri.points[tri.simplices[iEle, :]]
coordElement = coordElement.flatten()
# Get nodal indexes (container element)
- nodesElement = tri.simplices[recvElems, :]
+ nodesElement = tri.simplices[iEle, :]
# Get element-dofs indices (container element)
- dofsElement = dofs[recvElems, :]
+ edgesElement = elemsE[iEle, :]
+ facesElement = elemsF[iEle, :]
+ nodesFace = facesN[facesElement, :]
+
+ dofsElement = computeElementDOFs(iEle, nodesElement, edgesElement,
+ facesElement, nodesFace,
+ numberEdges, numberFaces,
+ nedelec_order)
# If there are more than one receivers
else:
+ # Get index of tetrahedral element (receiver container)
+ iEle = recvElems[iReceiver]
# Get receiver coordinates
coordiReceiver = receivers[iReceiver, :]
# Get element coordinates (container element)
- coordElement = tri.points[tri.simplices[recvElems[iReceiver], :]]
+ coordElement = tri.points[tri.simplices[iEle, :]]
coordElement = coordElement.flatten()
# Get nodal indexes (container element)
- nodesElement = tri.simplices[recvElems[iReceiver], :]
+ nodesElement = tri.simplices[iEle, :]
# Get element-dofs indices (container element)
- dofsElement = dofs[recvElems[iReceiver], :]
+ edgesElement = elemsE[iEle, :]
+ facesElement = elemsF[iEle, :]
+ nodesFace = facesN[facesElement, :]
+
+ # Compute element-dofs indices (container element)
+ dofsElement = computeElementDOFs(iEle, nodesElement, edgesElement,
+ facesElement, nodesFace,
+ numberEdges, numberFaces,
+ nedelec_order)
+
# Insert data for iReceiver
tmp[iReceiver, 0:3] = coordiReceiver
tmp[iReceiver, 3:15] = coordElement
@@ -631,7 +767,7 @@ def preprocessingDataReceivers(mesh_file, receivers_file,
# Delete unnecesary arrays
del tri
- del dofs
+ del elemsE
# Get matrix dimensions
size = tmp.shape
@@ -654,11 +790,26 @@ def preprocessingDataReceivers(mesh_file, receivers_file,
return nReceivers
-def preprocessingNNZ(mesh_file, out_dir, rank):
+def preprocessingNNZ(nedelec_order, mesh_file, out_dir, rank):
''' Preprocess sparsity pattern (NNZ) for parallel matrix allocation
- of a given mesh in Gmsh format. Here, dofs are defined for edge
- finite element computations.
+ of a given mesh in Gmsh format.
+
+ Since PETGEM parallelism is based on PETSc, computation of the matrix
+ sparsity pattern is critical in sake of performance. Furthermore, PETGEM
+ is based on tetrahedral edge finite elements of first, second and third
+ order which produces:
+
+ * 6 DOFs per element in first order discretizations
+ * 20 DOFs per element in second order discretizations
+ * 45 DOFs per element in third order discretizations
+
+ Hence, the tetrahedral valence is equal to:
+ * 34 in first order discretizations
+ * 134 in second order discretizations
+ * 363 in third order discretizations
+
+ :param int nedelec_order: nedelec element order.
:param str mesh_file: mesh file name to be preprocess.
:param int rank: MPI rank.
:return: None
@@ -679,18 +830,34 @@ def preprocessingNNZ(mesh_file, out_dir, rank):
# Read connectivity
elemsN, nElems = readGmshConnectivity(mesh_file)
- # Compute dofs
- _, dofsNodes = computeDofs(elemsN, nElems)
- nDofs = dofsNodes.shape[0]
-
- # Since PETGEM parallelism is based on PETSc, computation of the matrix
- # sparsity pattern is critical in sake of performance. Furthermore, PETGEM
- # V1.0 is based on linear edge finite elements which produces six dofs per
- # tetrahedral element. Hence, the tetrahedral valence is equal to 34. based
- # on this information we build the NNZ vector.
+ # Compute number of edges
+ _, edgesNodes = computeEdges(elemsN, nElems, nedelec_order)
+ nEdges = edgesNodes.shape[0]
+
+ # Compute number of faces
+ elemsF, facesN = computeFaces(elemsN, nElems, nedelec_order)
+ nFaces = facesN.shape[0]
+
+ if nedelec_order == 1: # First order edge element
+ # Number of DOFs correspond to the number of edges in the mesh
+ nDofs = nEdges
+ # In order to avoid memory performance issues, add 20% to valence
+ valence = 41
+ elif nedelec_order == 2: # Second order edge element
+ # Number of DOFs
+ nDofs = nEdges*np.int(2) + nFaces*np.int(2)
+ # In order to avoid memory performance issues, add 20% to valence
+ valence = 161
+ elif nedelec_order == 3: # Third order edge element
+ # Number of DOFs
+ nDofs = nEdges*np.int(3) + nFaces*np.int(6) + nElems*np.int(3)
+ # In order to avoid memory performance issues, add 20% to valence
+ valence = 436
+ else:
+ raise ValueError('Edge element order=',
+ nedelec_order, ' not supported.')
- # In order to avoid memory performance issues, add 40% to valence
- valence = 50
+ # Build nnz pattern for each row
nnz = np.full((nDofs), valence, dtype=np.int)
# Build PETSc structures
@@ -711,27 +878,30 @@ def preprocessingNNZ(mesh_file, out_dir, rank):
return
-def printPreprocessingSummary(nNodes, nElems, nDofs, nReceivers, rank):
+def printPreprocessingSummary(nElems, nNodes, nFaces, nDofs, nReceivers, rank):
''' Print a summary of data preprocessed.
- :param int nNodes: number of nodes in the mesh.
:param int nElems: number of tetrahedral elements in the mesh.
+ :param int nNodes: number of nodes in the mesh.
+ :param int nFaces: number of faces in the mesh.
:param int nDofs: number of DOFS in the mesh.
:param int nReceivers: number of receivers.
:param int rank: MPI rank.
:return: None.
'''
- A = str(nNodes)
- B = str(nElems)
- C = str(nDofs)
- D = str(nReceivers)
+ A = str(nElems)
+ B = str(nNodes)
+ C = str(nFaces)
+ D = str(nDofs)
+ E = str(nReceivers)
if rank == 0:
- PETSc.Sys.Print(' Number of nodes: {0:50}'.format(A))
- PETSc.Sys.Print(' Number of elements: {0:50}'.format(B))
- PETSc.Sys.Print(' Number of DOFS: {0:50}'.format(C))
- PETSc.Sys.Print(' Number of receivers: {0:50}'.format(D))
+ PETSc.Sys.Print(' Number of elements: {0:50}'.format(A))
+ PETSc.Sys.Print(' Number of nodes: {0:50}'.format(B))
+ PETSc.Sys.Print(' Number of faces: {0:50}'.format(C))
+ PETSc.Sys.Print(' Number of DOFS: {0:50}'.format(D))
+ PETSc.Sys.Print(' Number of receivers: {0:50}'.format(E))
return
@@ -765,7 +935,10 @@ def printPreprocessingSummary(nNodes, nElems, nDofs, nReceivers, rank):
from petgem.parallel.parallel import createSequentialVectorWithArray
from petgem.parallel.parallel import writeParallelDenseMatrix
from petgem.parallel.parallel import writePetscVector
- from petgem.efem.efem import computeDofs
+ from petgem.efem.efem import computeEdges
from petgem.efem.efem import computeFaces
from petgem.efem.efem import computeBoundaryFaces
- from petgem.efem.efem import computeBoundaryDofs
+ from petgem.efem.efem import computeBoundaryEdges
+ from petgem.efem.efem import computeBoundaries
+ from petgem.efem.efem import computeElementDOFs
+ from scipy.io import savemat
diff --git a/petgem/solver/__init__.py b/petgem/solver/__init__.py
old mode 100644
new mode 100755
index 8f6f11b..2e5dc42
--- a/petgem/solver/__init__.py
+++ b/petgem/solver/__init__.py
@@ -1,3 +1,4 @@
-from .assembler import computeElementalContributionsMPI
+from .assembler import computeElementalContributionsMPI_FirstOrder
+from .assembler import computeElementalContributionsMPI_HighOrder
from .solver import setBoundaryConditions
from .solver import solveSystem
diff --git a/petgem/solver/__pycache__/__init__.cpython-35.pyc b/petgem/solver/__pycache__/__init__.cpython-35.pyc
new file mode 100755
index 0000000..f1161ce
Binary files /dev/null and b/petgem/solver/__pycache__/__init__.cpython-35.pyc differ
diff --git a/petgem/solver/__pycache__/__init__.cpython-36.pyc b/petgem/solver/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..69a7515
Binary files /dev/null and b/petgem/solver/__pycache__/__init__.cpython-36.pyc differ
diff --git a/petgem/solver/__pycache__/assembler.cpython-35.pyc b/petgem/solver/__pycache__/assembler.cpython-35.pyc
new file mode 100755
index 0000000..2002224
Binary files /dev/null and b/petgem/solver/__pycache__/assembler.cpython-35.pyc differ
diff --git a/petgem/solver/__pycache__/assembler.cpython-36.pyc b/petgem/solver/__pycache__/assembler.cpython-36.pyc
new file mode 100644
index 0000000..f0fbc80
Binary files /dev/null and b/petgem/solver/__pycache__/assembler.cpython-36.pyc differ
diff --git a/petgem/solver/__pycache__/solver.cpython-35.pyc b/petgem/solver/__pycache__/solver.cpython-35.pyc
new file mode 100755
index 0000000..8ac898e
Binary files /dev/null and b/petgem/solver/__pycache__/solver.cpython-35.pyc differ
diff --git a/petgem/solver/__pycache__/solver.cpython-36.pyc b/petgem/solver/__pycache__/solver.cpython-36.pyc
new file mode 100644
index 0000000..6924320
Binary files /dev/null and b/petgem/solver/__pycache__/solver.cpython-36.pyc differ
diff --git a/petgem/solver/assembler.py b/petgem/solver/assembler.py
old mode 100644
new mode 100755
index c589be6..b6ecf8d
--- a/petgem/solver/assembler.py
+++ b/petgem/solver/assembler.py
@@ -6,10 +6,12 @@
'''
-def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
- '''Compute the elemental contributions of matrix A (LHS) and right hand
- side (RHS) in a parallel-vectorized manner for CSEM surveys by EFEM. Here,
- all necessary arrays are populated (Distributed-memory approach).
+def computeElementalContributionsMPI_FirstOrder(modelling, coordEle,
+ nodesEle, sigmaEle):
+ '''Compute the first order elemental contributions of matrix A (LHS) and
+ right hand side (RHS) in a parallel-vectorized manner for CSEM surveys by
+ EFEM. Here, all necessary arrays are populated (Distributed-memory
+ approach).
:param dictionary modelling: CSEM modelling with physical parameters.
:param ndarray coordEle: array with nodal coordinates of element.
@@ -23,17 +25,17 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
SIGMA_BGROUND = np.float(modelling['CONDUCTIVITY_BACKGROUND'])
SRC_POS = np.asarray(modelling['SRC_POS'], dtype=np.float)
SRC_DIREC = np.int(modelling['SRC_DIREC'])
- I = np.float(modelling['SRC_CURRENT'])
+ II = np.float(modelling['SRC_CURRENT'])
dS = np.float(modelling['SRC_LENGTH'])
# ----------- Edge order -----------
- edgeOrder = 6
+ firstOrderEdgeElement = 6
# ----------- Nodal order -----------
nodalOrder = 4
# ----------- Number of dimensions -----------
nDimensions = 3
- # ----------- Definition of constants-----------
+ # ----------- Definition of constants-|----------
ZERO = np.float(0.0)
ONE = np.float(1.0)
TWO = np.float(2.0)
@@ -53,7 +55,7 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
# Propagation parameter
WAVENUMBER = np.complex(np.sqrt(-IMAG_PART*MU*OMEGA*SIGMA_BGROUND))
# Physical constants
- CONST_PHY1 = I * dS
+ CONST_PHY1 = II * dS
CONST_PHY2 = FOUR * np.pi * SIGMA_BGROUND
CONST_PHY3 = -IMAG_PART * WAVENUMBER
CONST_PHY4 = -WAVENUMBER**2
@@ -97,7 +99,7 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
pEvalY = np.zeros(allocate, dtype=np.float)
pEvalZ = np.zeros(allocate, dtype=np.float)
# Nedelec basis functions
- allocate = ngaussP*edgeOrder
+ allocate = ngaussP*firstOrderEdgeElement
temp_A1 = np.zeros(allocate, dtype=np.float)
temp_A2 = np.zeros(allocate, dtype=np.float)
temp_b1 = np.zeros(allocate, dtype=np.float)
@@ -105,24 +107,24 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
basis = np.zeros((nDimensions, allocate), dtype=np.float)
# Vector operations over edges
rep_edges1 = np.repeat((0, 1, 2, 3, 4, 5), ngaussP)
- rep_edges2 = np.repeat((0, 1, 2, 3, 4, 5), edgeOrder)
- rep_edges3 = np.tile((0, 1, 2, 3, 4, 5), edgeOrder)
+ rep_edges2 = np.repeat((0, 1, 2, 3, 4, 5), firstOrderEdgeElement)
+ rep_edges3 = np.tile((0, 1, 2, 3, 4, 5), firstOrderEdgeElement)
# Vector operations over gauss points
idxbx1 = np.repeat((1, 2, 3, 2, 1, 3), ngaussP)
idxbx2 = np.repeat((0, 0, 0, 1, 3, 2), ngaussP)
# Mass matrix
- allocate = edgeOrder**2
+ allocate = firstOrderEdgeElement**2
Me = np.zeros(allocate, dtype=np.float)
# Stiffness matrix
- rep_edges_stiff1 = np.tile((0, 0, 0, 1, 3, 2), edgeOrder)
- rep_edges_stiff2 = np.tile((1, 2, 3, 2, 1, 3), edgeOrder)
+ rep_edges_stiff1 = np.tile((0, 0, 0, 1, 3, 2), firstOrderEdgeElement)
+ rep_edges_stiff2 = np.tile((1, 2, 3, 2, 1, 3), firstOrderEdgeElement)
rep_edges_stiff3 = np.array([0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1,
3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2], dtype=np.int)
- rep_edges_stiff4 = np.repeat((1, 2, 3, 2, 1, 3), edgeOrder)
+ rep_edges_stiff4 = np.repeat((1, 2, 3, 2, 1, 3), firstOrderEdgeElement)
# Stiffness matrix
Ke = np.zeros(allocate, dtype=np.float)
# Auxiliar vectors
@@ -132,7 +134,7 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
f2 = np.zeros(allocate, dtype=np.float)
f3 = np.zeros(allocate, dtype=np.float)
f4 = np.zeros(allocate, dtype=np.float)
- allocate = edgeOrder**2
+ allocate = firstOrderEdgeElement**2
std_v1 = np.zeros(allocate, dtype=np.float)
std_v2 = np.zeros(allocate, dtype=np.float)
std_v3 = np.zeros(allocate, dtype=np.float)
@@ -166,13 +168,13 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
distance = np.zeros(allocate, dtype=np.float)
# Electric field
field = np.zeros((nDimensions, allocate), dtype=np.complex)
- indx_field = np.tile((np.arange(0, ngaussP)), edgeOrder)
- allocate = edgeOrder*ngaussP
+ indx_field = np.tile((np.arange(0, ngaussP)), firstOrderEdgeElement)
+ allocate = firstOrderEdgeElement*ngaussP
temp_field = np.zeros((nDimensions, allocate), dtype=np.complex)
# Elemental matrix and elemental vector
- allocate = edgeOrder**2
+ allocate = firstOrderEdgeElement**2
Ae = np.zeros(allocate, dtype=np.complex)
- allocate = edgeOrder
+ allocate = firstOrderEdgeElement
be = np.zeros(allocate, dtype=np.complex)
# Indexes within dimensions of gauss points and basis functions
idx_gaussP_1 = ngaussP
@@ -477,7 +479,7 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
temp = np.sum(temp_field*basis, 0) * signsEle * weightEle * deltaSigma
# Integral over edges
- for iBasis in np.arange(edgeOrder):
+ for iBasis in np.arange(firstOrderEdgeElement):
for iPoint in np.arange(ngaussP):
be[iBasis] = be[iBasis] + temp[(iBasis*ngaussP)+iPoint]
@@ -487,6 +489,235 @@ def computeElementalContributionsMPI(modelling, coordEle, nodesEle, sigmaEle):
return Ae, be
+def computeElementalContributionsMPI_HighOrder(modelling, coordEle, nodesEle,
+ sigmaEle, nedelec_order):
+ '''Compute the second or third order elemental contributions of matrix A
+ (LHS) and right hand side (RHS) in a parallel-vectorized manner for CSEM
+ surveys by EFEM. Here, all necessary arrays are populated
+ (Distributed-memory approach).
+
+ :param dictionary modelling: CSEM modelling with physical parameters.
+ :param ndarray coordEle: array with nodal coordinates of element.
+ :param ndarray nodesEle: array with nodal indexes of element.
+ :param float sigmaEle: element conductiviy.
+ :param int nedelec_order: nedelec element order.
+ :return: Ae, be.
+ :rtype: complex.
+ '''
+ # ----------- Nodal order -----------
+ nodalOrder = 4
+
+ # ----------- Edge element order -----------
+ if nedelec_order == 2:
+ orderEle = 20
+ ngaussP = 15
+ elif nedelec_order == 3:
+ orderEle = 45
+ ngaussP = 24
+
+ # ----------- Number of dimensions -----------
+ nDimensions = 3
+
+ # ----------- Read physical parameters -----------
+ FREQ = np.float(modelling['FREQ'])
+ SIGMA_BGROUND = np.float(modelling['CONDUCTIVITY_BACKGROUND'])
+ SRC_POS = np.asarray(modelling['SRC_POS'], dtype=np.float)
+ SRC_DIREC = np.int(modelling['SRC_DIREC'])
+ II = np.float(modelling['SRC_CURRENT'])
+ dS = np.float(modelling['SRC_LENGTH'])
+
+ # ----------- Definition of constants -----------
+ ZERO = np.float(0.0)
+ ONE = np.float(1.0)
+ TWO = np.float(2.0)
+ THREE = np.float(3.0)
+ FOUR = np.float(4.0)
+ SIX = np.float(6.0)
+ # Imaginary part for complex numbers
+ IMAG_PART = np.complex128(0.0 + 1.0j)
+ # Vacuum permeability
+ MU = np.float(FOUR*np.pi*np.float(1.0e-7))
+ # Angular frequency
+ OMEGA = np.float(FREQ*TWO*np.pi)
+ # Propagation parameter
+ WAVENUMBER = np.complex(np.sqrt(-IMAG_PART*MU*OMEGA*SIGMA_BGROUND))
+ # Physical constants
+ CONST_PHY1 = II * dS
+ CONST_PHY2 = FOUR * np.pi * SIGMA_BGROUND
+ CONST_PHY3 = -IMAG_PART * WAVENUMBER
+ CONST_PHY4 = -WAVENUMBER**2
+ CONST_PHY5 = THREE * IMAG_PART * WAVENUMBER
+ CONST_PHY6 = IMAG_PART*OMEGA*MU
+
+ # Gaussian points for the unit reference tetrahedron
+ [Wi, rx, ry, rz] = gauss_points_reference_tetrahedron(ngaussP,
+ nedelec_order)
+
+ # ----- Initialization of edges/vertices/faces numbering ------
+ [edge_vertices, face_vertices, ref_ele] = edgeFaceVerticesInit()
+
+ # ----------- Delta sigma of element -----------
+ deltaSigma = sigmaEle - SIGMA_BGROUND
+
+ # Element's nodes coordinates
+ coordEle = coordEle.reshape((nDimensions, nodalOrder), order='F')
+
+ # Elemental computations (Signs, jacobian, edges length, area faces)
+ [_, _, signs, nreal,
+ jacob, DetJacob, _] = computeSignsJacobLegth(coordEle, edge_vertices,
+ face_vertices,
+ nedelec_order)
+ # Definition of q vectors on faces
+ [qface1, qface2,
+ qface3, qface4,
+ invjj, GR] = definitionHighOrderTet(nreal, signs, jacob, nedelec_order)
+
+ # Traslation of gauss points to real element
+ L = np.vstack((np.float(1)-rx-ry-rz, rx, ry, rz))
+ pEval = volumetricToCartesianCoordinates(coordEle[0, :], coordEle[1, :],
+ coordEle[2, :], L)
+
+ # Computation coefficients for basis functions
+ if nedelec_order == 2:
+ # Gaussian points weigths (normalization)
+ weightEle = Wi*DetJacob*1./6.
+
+ # Computation of coefficients
+ [a1, a2, a3, a4,
+ b1, b2, b3, b4,
+ c1, c2, c3, c4,
+ D, E, F, G, H,
+ II, JJ, K] = computeCoefficientsSecondOrder(qface1, qface2, qface3,
+ qface4, ref_ele,
+ edge_vertices,
+ face_vertices)
+ # Computation of basis functions
+ basis = nedelecBasisSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4, c1,
+ c2, c3, c4, D, E, F, G, H, II, JJ,
+ K, coordEle, pEval)
+
+ # Compute mass matrix
+ Me = computeMassMatrixSecondOrder(a1, a2, a3, a4, b1, b2, b3, b4,
+ c1, c2, c3, c4, D, E, F, G, H,
+ II, JJ, K, ref_ele, GR, signs,
+ DetJacob, Wi, rx, ry, rz, ngaussP)
+
+ # Compute stiffness matrix
+ Ke = computeStiffnessMatrixSecondOrder(a2, a3, a4, b2, b3, b4, c2, c3,
+ c4, D, E, F, G, H, II, JJ, K,
+ invjj, signs, DetJacob, Wi,
+ rx, ry, rz, ngaussP)
+
+ # Compute elemental matrix
+ Ae = Ke + CONST_PHY6*sigmaEle*Me
+ Ae = Ae.flatten()
+
+ # Allocate RHS
+ be = np.zeros(orderEle, dtype=np.complex)
+
+ elif nedelec_order == 3:
+ # Gaussian points weigths (normalization)
+ weightEle = Wi*DetJacob
+
+ # Computation of coefficients
+ [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N, O,
+ P, Q, R] = computeCoefficientsThirdOrder(qface1, qface2,
+ qface3, qface4)
+
+ # Computation of basis functions
+ basis = nedelecBasisThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
+ c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
+ D, E, F, G, H, II, JJ, K, L, M, N,
+ O, P, Q, R, coordEle, pEval)
+
+ # Compute mass matrix
+ Me = computeMassMatrixThirdOrder(a1, a2, a3, a4, a5, a6, a7, a8, a9,
+ a10, b1, b2, b3, b4, b5, b6, b7, b8,
+ b9, b10, c1, c2, c3, c4, c5, c6, c7,
+ c8, c9, c10, D, E, F, G, H, II, JJ,
+ K, L, M, N, O, P, Q, R, ref_ele,
+ GR, signs, DetJacob)
+
+ # Compute stiffness matrix
+ Ke = computeStiffnessMatrixThirdOrder(a2, a3, a4, a5, a6, a7, a8, a9,
+ a10, b2, b3, b4, b5, b6, b7, b8,
+ b9, b10, c2, c3, c4, c5, c6, c7,
+ c8, c9, c10, D, E, F, G, H, II,
+ JJ, K, L, M, N, O, P, Q, R,
+ invjj, signs, DetJacob)
+
+ # Compute elemental matrix
+ Ae = Ke + CONST_PHY6*sigmaEle*Me
+ Ae = Ae.flatten()
+
+ # Allocate RHS
+ be = np.zeros(orderEle, dtype=np.complex)
+
+ # Compute primary field for all gauss points
+ # Allocate
+ field = np.zeros(nDimensions, dtype=np.complex)
+ for iPoint in np.arange(ngaussP):
+ # Basis functions
+ Ni = basis[:, :, iPoint]
+
+ # Evaluation point
+ pEvalX = pEval[0, iPoint]
+ pEvalY = pEval[1, iPoint]
+ pEvalZ = pEval[2, iPoint]
+
+ # Compute distance to the source for all Gaussian points
+ distX = pEvalX - SRC_POS[0] # X-component
+ distY = pEvalY - SRC_POS[1] # Y-component
+ distZ = pEvalZ - SRC_POS[2] # Z-component
+ distance = np.sqrt(distX**2 + distY**2 + distZ**2)
+
+ # To avoid very large or small numbers
+ if distance < 1.e0:
+ distance = ONE
+ # Compute the primary field for all Gaussian points
+ # E = AA [ BB + (wavenumber^2*distance^2 -1i*wavenumber*distance-1)]
+ SQUARE_DISTANCE = distance**2
+ AA = CONST_PHY1 / (CONST_PHY2 * distance**3) * np.exp(CONST_PHY3 *
+ distance)
+ BB = CONST_PHY4 * SQUARE_DISTANCE + (CONST_PHY5 * distance) + THREE
+ RR = ONE/SQUARE_DISTANCE
+
+ # Compute primary field in function of source direction
+ if SRC_DIREC == 1:
+ # X-directed
+ field[0] = AA * ((distX**2 * RR)*BB +
+ (WAVENUMBER**2 * SQUARE_DISTANCE - IMAG_PART *
+ WAVENUMBER * distance - ONE))
+ field[1] = AA * (distX*distY*RR)*BB
+ field[2] = AA * (distX*distZ*RR)*BB
+ elif SRC_DIREC == 2:
+ # Y-directed
+ field[0] = AA * (distX*distY*RR)*BB
+ field[1] = AA * ((distY**2 * RR)*BB +
+ (WAVENUMBER**2 * SQUARE_DISTANCE - IMAG_PART *
+ WAVENUMBER * distance - ONE))
+ field[2] = AA * (distY*distZ*RR)*BB
+ else:
+ # Z-directed
+ field[0] = AA * (distX*distZ*RR)*BB
+ field[1] = AA * (distZ*distY*RR)*BB
+ field[2] = AA * ((distZ**2 * RR)*BB +
+ (WAVENUMBER**2 * SQUARE_DISTANCE - IMAG_PART *
+ WAVENUMBER * distance - ONE))
+
+ be += (deltaSigma*weightEle[iPoint] *
+ np.multiply(np.matmul(Ni.transpose(), field), signs))
+
+ # Scale vector by constant -1i*OMEGA*MU
+ be = be*-CONST_PHY6
+
+ return Ae, be
+
+
def unitary_test():
''' Unitary test for assembler.py script.
'''
@@ -502,3 +733,17 @@ def unitary_test():
from petsc4py import PETSc
# PETGEM module import
from petgem.efem.fem import gauss_points_tetrahedron
+ from petgem.efem.fem import gauss_points_reference_tetrahedron
+ from petgem.efem.fem import volumetricToCartesianCoordinates
+ from petgem.efem.efem import edgeFaceVerticesInit
+ from petgem.efem.efem import computeSignsJacobLegth
+ from petgem.efem.efem import definitionHighOrderTet
+ from petgem.efem.efem import computeCoefficientsSecondOrder
+ from petgem.efem.efem import nedelecBasisSecondOrder
+ from petgem.efem.efem import computeMassMatrixSecondOrder
+ from petgem.efem.efem import computeStiffnessMatrixSecondOrder
+ from petgem.efem.efem import computeCoefficientsThirdOrder
+ from petgem.efem.efem import nedelecBasisThirdOrder
+ from petgem.efem.efem import computeMassMatrixThirdOrder
+ from petgem.efem.efem import computeStiffnessMatrixThirdOrder
+ from scipy.io import savemat
diff --git a/petgem/solver/solver.py b/petgem/solver/solver.py
old mode 100644
new mode 100755
index 10a9b18..030a8a9
--- a/petgem/solver/solver.py
+++ b/petgem/solver/solver.py
@@ -7,16 +7,17 @@
'''
-def setBoundaryConditions(A, b, bEdges, Istart_bEdges, Iend_bEdges, rank):
+def setBoundaryConditions(A, b, boundaries, Istart_boundaries, Iend_boundaries,
+ rank):
''' Given a parallel matrix and a parallel vector, set Dirichlet boundary
conditions.
:param petsc matrix A: sparse and complex coefficients matrix in
petsc format
:param petsc vector b: parallel right hand side
- :param petsc vector bEdges: array of boundary indexes
- :param int Istart_bEdges: init range for boundaries
- :param int Iend_bEdges: last range for boundaries
+ :param petsc vector boundaries: array of boundary indexes
+ :param int Istart_boundaries: init range for boundaries
+ :param int Iend_boundaries: last range for boundaries
:para int rank: MPI rank
:return: equation system after applied Dirichlet boundary conditions
and elapsed time
@@ -30,10 +31,10 @@ def setBoundaryConditions(A, b, bEdges, Istart_bEdges, Iend_bEdges, rank):
Init_boundaries = getTime()
# Boundaries for LHS
- A.zeroRowsColumns(np.real(bEdges).astype(PETSc.IntType))
+ A.zeroRowsColumns(np.real(boundaries).astype(PETSc.IntType))
# Boundaries for RHS
- numLocalBoundaries = Iend_bEdges - Istart_bEdges
- b.setValues(np.real(bEdges).astype(PETSc.IntType),
+ numLocalBoundaries = Iend_boundaries - Istart_boundaries
+ b.setValues(np.real(boundaries).astype(PETSc.IntType),
np.zeros(numLocalBoundaries, dtype=np.complex),
addv=PETSc.InsertMode.INSERT_VALUES)
@@ -93,6 +94,7 @@ def unitary_test():
''' Unitary test for solver.py script.
'''
+
if __name__ == '__main__':
# Standard module import
unitary_test()
diff --git a/run_preprocessing.py b/run_preprocessing.py
old mode 100644
new mode 100755
index cfe9277..b59631f
--- a/run_preprocessing.py
+++ b/run_preprocessing.py
@@ -18,7 +18,8 @@
from petgem.preprocessing.preprocessing import readPreprocessingParams
from petgem.preprocessing.preprocessing import preprocessNodes
from petgem.preprocessing.preprocessing import preprocessingNodalConnectivity
-from petgem.preprocessing.preprocessing import preprocessingDOF
+from petgem.preprocessing.preprocessing import preprocessingEdges
+from petgem.preprocessing.preprocessing import preprocessingFaces
from petgem.preprocessing.preprocessing import preprocessingConductivityModel
from petgem.preprocessing.preprocessing import preprocessingDataReceivers
from petgem.preprocessing.preprocessing import preprocessingNNZ
@@ -56,27 +57,36 @@
nElems = preprocessingNodalConnectivity(preprocessing['MESH_FILE'],
preprocessing['OUT_DIR'], rank)
-# Degrees of freedom preprocessing (dofs)
-nDofs = preprocessingDOF(preprocessing['MESH_FILE'],
- preprocessing['OUT_DIR'], rank)
+# Edges connectivity and edge boundaries preprocessing (edges)
+nEdges, nDofs = preprocessingEdges(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
+
+# Faces connectivity and faces boundaries preprocessing (faces)
+nFaces = preprocessingFaces(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
# Conductivity model
preprocessingConductivityModel(preprocessing['MESH_FILE'],
preprocessing['MATERIAL_CONDUCTIVITIES'],
preprocessing['OUT_DIR'], rank)
# Receiver positions
-nReceivers = preprocessingDataReceivers(preprocessing['MESH_FILE'],
+nReceivers = preprocessingDataReceivers(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
preprocessing['RECEIVERS_FILE'],
preprocessing['OUT_DIR'], rank)
# Sparsity pattern for parallel matrix allocation
-preprocessingNNZ(preprocessing['MESH_FILE'], preprocessing['OUT_DIR'], rank)
+preprocessingNNZ(preprocessing['NEDELEC_ORDER'],
+ preprocessing['MESH_FILE'],
+ preprocessing['OUT_DIR'], rank)
# ###############################################
# ------------------ Summary --------------------
printMessage('\nSummary', rank)
printMessage('='*75, rank)
-printPreprocessingSummary(nNodes, nElems, nDofs, nReceivers, rank)
+printPreprocessingSummary(nElems, nNodes, nFaces, nDofs, nReceivers, rank)
# ###############################################
# ----------- Print footer (Master) -------------
diff --git a/setup.py b/setup.py
old mode 100644
new mode 100755
index 5b07575..34bba8c
--- a/setup.py
+++ b/setup.py
@@ -50,6 +50,7 @@ def get_ext_modules():
return numpy_includes
+
if __name__ == '__main__':
from setuptools import setup
import os
@@ -57,7 +58,7 @@ def get_ext_modules():
setup(name=name(),
maintainer="Octavio Castillo Reyes",
maintainer_email="octavio.castillo@bsc.es",
- version='0.30.48',
+ version='0.5',
long_description=long_description(),
description=description(),
url="https://www.bsc.es/castillo-octavio",