Compare commits

..
Author SHA1 Message Date
Yohann Dudouit 798a7d047d Testing environment on. 2019-04-01 15:36:26 -07:00
Yohann Dudouit d88ea50d65 Add computation time to ex9 2019-02-04 11:10:41 -08:00
Yohann Dudouit f865768703 Simplifications and some vectorization attempts. 2018-05-14 17:29:32 -07:00
Yohann Dudouit 8c7eee36ac Cleaning and making the code easier to understand. 2018-05-07 19:07:39 -07:00
Yohann Dudouit a5e22fe61e Use Partial Assembly for the evaluation of Jacobians for face terms. 2018-05-07 14:56:22 -07:00
Yohann Dudouit ecf98066b0 Add a Local Conjugate Gradient with local preconditioner for DG methods. 2018-05-03 15:42:19 -07:00
Yohann Dudouit df6a848fd8 Adds a Conjugate Gradient Solvers for partial assembly.
- Basic conjugate gradient solver for partial assembly without preconditioning.
- Conjugate gradient solver for PA with Prec.
- Diag Solver (can be used as preconditionner).
- Conjugate gradient working on element level for DG methods.
2018-05-03 15:00:37 -07:00
Yohann Dudouit 0eecb89c77 Adds a local CG solver and a Diag solver for DG problems. 2018-04-16 11:17:57 -07:00
Yohann Dudouit d5896ec636 Correctly computes Jacobian for 2D and 3D in partial assembly using tensorial products. 2018-04-06 16:51:49 -07:00
Yohann Dudouit c8151962af Merge branch 'master' into ex9-pa-dev
Resolved conflicts:
	examples/makefile
	fem/bilinearform.hpp
	fem/nonlininteg.hpp
	linalg/densemat.hpp
	linalg/operator.hpp
2018-04-06 15:37:52 -07:00
Yohann Dudouit 32e2808ff7 Adds tensorial construction of the Jacobian and splits code in different files. 2018-03-27 14:49:29 -07:00
Yohann Dudouit 564054e5f1 Replace keyword "using" by "typedef". 2018-03-20 15:13:40 -07:00
Yohann Dudouit 7eb9af3ffe Adds function that avoid variadic templates for integrators. 2018-03-20 14:29:13 -07:00
Yohann Dudouit e078a2bc24 Fix 3D DG for structured and periodic meshes.
* Unstructured meshes with different orientations configurations have
to be tested
2018-03-16 16:09:29 -07:00
Yohann Dudouit 32157d90ae 3D implemented, compiles, but doesn't work.
- Adds the 3D permutation functions
 - Add 3D BtDB Kernel for faces
2018-03-09 16:13:02 -08:00
Yohann Dudouit 5db57ef64e Fix some compilation errors due to previous commit. 2018-03-07 15:48:44 -08:00
Yohann Dudouit 20afdbd7b6 Simplify the code and add the 3D permutations for DG. 2018-03-07 15:32:07 -08:00
Yohann Dudouit 286d8a31d3 Integrates Johann's changes to this branch. 2018-03-07 15:30:11 -08:00
Yohann Dudouit 34edd1e775 Merge branch 'pa-oper-dev' into ex9-pa-dev
Conflicts:
	examples/makefile
	fem/bilinearform.cpp
	fem/obilininteg.hpp
	fem/painteg.cpp
	makefile
2017-12-11 14:37:11 -08:00
Yohann Dudouit 398562a73b Unified and simpler design for Domain and Face Partial Assembly
Integrators.
2017-12-11 09:28:57 -08:00
Yohann Dudouit 9e4c36094f Always more efficient Face Partial Assembly Kernels.
Lot of simplifications in the design of Domain Kernels.
Remove inefficient Kernels Based on Eigen.
2017-12-06 16:20:54 -08:00
Johann Dahm 96e9557c25 Fix uninitialization bug and unrelated compiler warning 2017-12-04 17:41:54 -08:00
Johann Dahm 02778c55fd Add ex1p support 2017-12-04 15:20:32 -08:00
Johann Dahm 4937dff6d7 Add VectorMassIntegrator to PAIntegratorMap 2017-12-03 21:16:54 -08:00
Johann Dahm 32801fa560 Add AssembleForm to MixedBilinearForm 2017-12-01 21:33:41 -08:00
Johann Dahm 772b83ee0d Rename operator and edits to FormSystemOperator and FormLinearSystem 2017-11-30 15:36:47 -08:00
Johann Dahm 8eb4b72fb8 Merge branch 'tbasis-dev' into pa-oper-dev 2017-11-30 10:24:48 -08:00
Yohann Dudouit 290141b127 Corrects a bug for partial assembly DG Face terms for advection
when velocity field is non constant.
2017-11-29 14:49:01 -08:00
Yohann Dudouit b92436a89e Adds the missing templated Tensor class. 2017-11-29 11:03:45 -08:00
Johann Dahm d064feaf63 Add FESpaceForm (mostly replaces BilinearFormOperator) 2017-11-28 22:30:04 -05:00
Yohann Dudouit 2b0a4268b0 Removes memory leak for the templated Tensor class. 2017-11-28 18:29:42 -08:00
Yohann Dudouit abb2181550 New Kernel working for unstructured meshes. 2017-11-28 15:41:20 -08:00
Yohann Dudouit 26679914fb Adds the external fluxes for the Dummy Kernel 2, only works for
"structured" mesh for the moment.
2017-11-22 10:51:46 -08:00
Yohann Dudouit 8fa336fd85 Adds a templated interface for Face terms partial assembly integrators,
called PAFaceIntegrator. Adds a per element Partial Assembly Face Kernel.
Adds the interior fluxes kernels for the previous kernel.
2017-11-20 13:46:29 -08:00
Yohann Dudouit 66ad469e34 Adds a Partial Assembly Face Kernel Interface for Partial Assembly
Face Integrators.
2017-11-16 16:52:24 -08:00
Johann Dahm 511be753c4 Refactor of partial assembly 2017-11-15 15:59:18 -08:00
Johann Dahm 1570e99bff Merge branch 'intrule-dev' into pa-oper-dev 2017-11-15 15:32:54 -08:00
Yohann Dudouit 0d6ad1a455 Adds a generic PADomainIntegrator that defines the interface the
PA Kernels.
2017-11-14 11:12:39 -08:00
Johann Dahm ee51644ddb Merge branch 'master' into pa-oper-dev 2017-11-13 14:32:42 -08:00
Yohann Dudouit 03db4d58c6 fixes few typos 2017-11-13 10:13:50 -08:00
Yohann Dudouit 0d7fc30429 Dummy domain kernels available for any variational form (BtDB, BtDG, GtDB, GtDG)
and any dimension (1 to 3).
2017-11-13 09:48:47 -08:00
Yohann Dudouit 2a56202df8 Removes unecessary pre-instantiation of partial assembly kernels. 2017-11-07 17:03:51 -08:00
Yohann Dudouit 4496d921e0 Adds a Domain Partial Assembly Kernel based on Tensors from Eigen library 2017-11-07 16:48:11 -08:00
Yohann Dudouit 8db895f790 ex9PA working, but code needs a lot of cleaning 2017-11-02 17:13:12 -07:00
Yohann Dudouit 266f4e4c1c Compute all fluxes for 2D case 2017-10-27 13:18:11 -07:00
Yohann Dudouit df2aa5f201 Added a 2d DummyFaceKernel 2017-10-26 18:24:10 -07:00
Yohann Dudouit 45490c50e9 Adds a dummy Face Partial Assembly Kernel.
Adds a PADGConvectionFaceIntegrator that initialize the 4 differents
convection fluxes for a face.
2017-10-24 14:00:09 -07:00
Yohann Dudouit 2b1662672f Separate the partial assembly implementation from obilininteg.* .
The DG implementation uses Kernels to separate the computation of D
and the computation of V=BDBU. Uses a dummy kernel implementation
for domain Integrator. The dummy Kernel for face Integrator is
not yet implemented.
Also adds functions to compute change of basis from one element to
another on a face.
2017-10-17 15:57:15 -07:00
Yohann Dudouit d9ffb65430 New functions in dgfacefunctions to compute coordinate transformation on a face
according to the element on one side or on the other side of the face.
2017-10-11 14:00:55 -07:00
Yohann Dudouit 9733b2d200 added a partial assembly convection operator (PAConvectionIntegrator) 2017-10-06 10:33:00 -07:00
Yohann Dudouit 6bcb4767e9 Merge branch 'pa-oper-dev' into ex9-pa-dev 2017-10-05 10:58:39 -07:00
Johann Dahm 84df47605e Remove the TensorBasisElement from class storage 2017-10-04 17:10:06 -07:00
Johann Dahm 40067064d5 FiniteElementSpace* -> const FiniteElement* in ComputeBasis1d 2017-10-04 17:03:36 -07:00
Yohann Dudouit a40477d96a factorize tensor operations into one class instead of having them in every PAIntegrator. 2017-10-04 14:02:36 -07:00
Yohann Dudouit 6e8c31b861 adds the partial assembly file for example 9. 2017-10-04 13:59:22 -07:00
Johann Dahm 48bfad0ad7 Add vdim support to PA integrators 2017-09-30 22:31:27 -07:00
Johann Dahm 7f22a84a33 Fix: increment offset in 1D PA integrators 2017-09-30 22:18:16 -07:00
Johann Dahm 0e6783a659 Remove unneeded DenseTensor constructor
This constructor is added on the array-dev branch but not needed here.
2017-09-29 15:38:22 -07:00
Yohann Dudouit 62602a44a3 Overload ComputeBasis1d to compute only shape1d (skip gradient computation) 2017-09-29 15:27:11 -07:00
Johann Dahm ce8809c55d Add coefficients and support in ex16 2017-09-25 15:21:54 -07:00
Johann Dahm bd65eb1818 Add mass integrator 2017-09-25 12:04:26 -07:00
Johann Dahm f9f1ab74fd Add 1D diffusion integrator 2017-09-25 11:09:26 -07:00
Johann Dahm 566f03cbaa Make notation consistent 2017-09-23 20:34:31 -07:00
Johann Dahm f93db7db30 Put back preconditioner and clean up logic 2017-09-22 17:19:13 -07:00
Johann Dahm ad102a5d29 Add 3D diffusion integrator and refactor 2017-09-22 15:03:14 -07:00
Johann Dahm 7c37ac0a24 Merge branch 'tbasis-dev' into pa-oper-dev 2017-09-22 08:27:39 -07:00
Johann Dahm d6bb74d2a0 Merge branch 'master' into pa-oper-dev 2017-09-22 08:24:44 -07:00
Johann Dahm ea535368b6 Move PA integrations to fem/obilininteg.{c,h}pp 2017-09-20 17:16:39 -07:00
Johann Dahm 7721bb8e9e Merge branch 'master' into pa-oper-dev 2017-09-20 14:23:50 -07:00
Johann Dahm 6fa3f1da2e Add partial assembly-based operator for quads and add to ex1 2017-09-13 13:57:17 -07:00
Johann Dahm eb520d1a12 Tensorized finite element bases from occa-dev branch.
Thanks, David!
2017-09-12 14:14:42 -07:00
152 changed files with 12408 additions and 77108 deletions
-9
View File
@@ -112,15 +112,6 @@ examples/petsc/deformed.*
examples/petsc/velocity.*
examples/petsc/elastic_energy.*
examples/pumi/ex1
examples/pumi/ex[126]p
examples/pumi/refined.mesh
examples/pumi/sol.gf
examples/pumi/mesh.*
examples/pumi/sol.*
examples/pumi/displaced.mesh
miniapps/electromagnetics/volta
miniapps/electromagnetics/tesla
miniapps/electromagnetics/maxwell
+5 -31
View File
@@ -8,30 +8,11 @@
http://mfem.org
Version 3.4.1 (development)
Version 3.3.3 (development)
===========================
- Added support for reading linear and quadratic 2D quadrilateral and triangular
Cubit meshes.
- The tetrahedral mesh refinement algorithm in serial and in parallel now
follows precisely the paper:
D. Arnold, A. Mukherjee, and L. Pouly, "Locally Adapted Tetrahedral Meshes
Using Bisection", SIAM J. Sci. Comput., 22(2), 431448.
This guarantees that the shape regularity of the elements will be preserved
under refinement.
Version 3.4, released on May 29, 2018
=====================================
More general and efficient mesh adaptivity
------------------------------------------
- Added support for PUMI, the Parallel Unstructured Mesh Infrastructure from
https://scorec.rpi.edu/pumi. PUMI is an unstructured, distributed mesh data
management system that is capable of handling general non-manifold models and
effectively supports automated adaptive analysis. PUMI enables for the first
time support for parallel unstructured modifications of MFEM meshes.
More efficient non-conforming adaptive mesh refinement
------------------------------------------------------
- Significantly reduced MPI communication in the construction of the parallel
prolongation matrix in ParFiniteElementSpace, for much improved parallel
scaling of non-conforming AMR on hundreds of thousands of MPI tasks. The
@@ -73,10 +54,8 @@ Discretization improvements
- In the classes NonlinearForm and ParNonlinearForm, added support for
non-conforming AMR meshes; see also the "API changes" section.
- New specialized time integrators: symplectic integrators of orders 1-4 for
systems of first order ODEs derived from a Hamiltonian and generalized-alpha
ODE solver for the filtered NavierStokes equations with stabilization. See
classes SIASolver and GeneralizedAlphaSolver in linalg/ode.hpp.
- Added symplectic integrators of orders 1-4 for systems of first order ODEs
derived from a Hamiltonian, see class SIASolver in linalg/ode.hpp.
- Inherit finite element classes from the new base class TensorBasisElement,
whenever the basis can be represented by a tensor product of 1D bases.
@@ -100,11 +79,6 @@ New and updated examples and miniapps
NURBS meshes in the miniapps/nurbs directory. Currently the directory contains
variable order NURBS versions of examples 1, 1p and 11p.
- Added PUMI versions of examples ex1, ex1p, ex2 and ex6p in a new examples/pumi
directory. The new examples demonstrate the PUMI APIs for parallel and serial
mesh loading (ex1 and ex1p), applying BCs using classification (ex2), and
performing parallel mesh adaptation (ex6p).
- Added two new miniapps related to DataCollection I/O in miniapps/tools:
load-dc.cpp can be used to visualize fields saved via DataCollection classes;
convert-dc.cpp demonstrates how to convert between MFEM's different concrete
+4 -20
View File
@@ -45,7 +45,7 @@ project(mfem NONE)
# Current version of MFEM, see also `makefile`.
# mfem_VERSION = (string)
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
set(${PROJECT_NAME}_VERSION 3.4.1)
set(${PROJECT_NAME}_VERSION 3.3.3)
# Prohibit in-source build
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
@@ -139,7 +139,7 @@ if (MFEM_USE_MPI)
set(PETSC_INCLUDE_DIRS ${PETSC_INCLUDES})
endif()
else()
set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK PUMI)
set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK)
foreach(PKG IN LISTS PKGS_NEED_MPI)
if (MFEM_USE_${PKG})
message(STATUS "Disabling package ${PKG} - requires MPI")
@@ -246,22 +246,6 @@ if (MFEM_USE_SIDRE)
find_package(Axom REQUIRED Sidre SLIC axom_utils)
endif()
# PUMI
if (MFEM_USE_PUMI)
# If PUMI_DIR was specified, only link to that directory,
# i.e. don't link to another installation in /usr/lib by mistake
find_package(SCOREC 2.1.0 REQUIRED OPTIONAL_COMPONENTS gmi_sim
CONFIG PATHS ${PUMI_DIR} NO_DEFAULT_PATH)
if (SCOREC_FOUND)
# Define a header file with the MFEM_USE_SIMMETRIX preprocessor variable
set(MFEM_USE_SIMMETRIX ${SCOREC_gmi_sim_FOUND})
set(PUMI_FOUND ${SCOREC_FOUND})
get_target_property(PUMI_INCLUDE_DIRS
SCOREC::apf INTERFACE_INCLUDE_DIRECTORIES)
set(PUMI_LIBRARIES SCOREC::core)
endif()
endif()
# MFEM_TIMER_TYPE
if (NOT DEFINED MFEM_TIMER_TYPE)
if (APPLE)
@@ -286,8 +270,8 @@ endif()
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT GECKO GNUTLS NETCDF MPFR PUMI
POSIXCLOCKS MFEMBacktrace ZLIB)
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT GECKO GNUTLS NETCDF MPFR POSIXCLOCKS
MFEMBacktrace ZLIB)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
+2 -103
View File
@@ -1,15 +1,3 @@
<p align="center">
<a href="http://mfem.org/"><img alt="mfem" src="http://mfem.org/img/logo-300.png"></a>
</p>
<p align="center">
<a href="https://github.com/mfem/mfem/blob/master/COPYRIGHT"><img alt="License" src="https://img.shields.io/badge/License-LGPL--2.1-brightgreen.svg"></a>
<a href="https://travis-ci.org/mfem/mfem"><img alt="Build Status" src="https://travis-ci.org/mfem/mfem.svg?branch=master"></a>
<a href="https://ci.appveyor.com/project/mfem/mfem"><img alt="Build Status" src="https://ci.appveyor.com/api/projects/status/19non9sqm6msi2wy?svg=true"></a>
<a href="http://mfem.github.io/doxygen/html/index.html"><img alt="Doxygen" src="https://img.shields.io/badge/code-documented-brightgreen.svg"></a>
</p>
# How to Contribute
The MFEM team welcomes contributions at all levels: bugfixes; code
@@ -28,7 +16,6 @@ See the [Quick Summary](#quick-summary) section for the main highlights of our
GitHub workflow. For more details, consult the following sections and refer
back to them before issuing pull requests:
- [Code Overview](#code-overview)
- [GitHub Workflow](#github-workflow)
- [MFEM Organization](#mfem-organization)
- [New Feature Development](#new-feature-development)
@@ -66,94 +53,6 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
- Don't hesitate to [contact us](#contact-information) if you have any questions.
### Code Overview
- The MFEM library uses object-orient design principles which reflect, in code,
the independent mathematical concepts of meshing, linear algebra and finite
element spaces and operators.
- The MFEM source code has the following structure:
```
.
├── config
│ └── cmake
│ └── modules
├── data
├── doc
│ └── web
│ └── examples
├── examples
│ ├── petsc
│ ├── pumi
│ └── sundials
├── fem
├── general
├── linalg
├── mesh
└── miniapps
├── common
├── electromagnetics
├── meshing
├── nurbs
├── performance
└── tools
```
- The main directories are `fem/`, `mesh/` and `linalg/` containing the C++
classes implementing the finite element, mesh and linear algebra concepts
respectively.
- The main mesh classes are:
+ [`Mesh`](http://mfem.github.io/doxygen/html/classmfem_1_1Mesh.html)
+ [`NCMesh`](http://mfem.github.io/doxygen/html/classmfem_1_1NCMesh.html)
+ [`Element`](http://mfem.github.io/doxygen/html/classmfem_1_1Element.html)
+ [`ElementTransformation`](http://mfem.github.io/doxygen/html/classmfem_1_1ElementTransformation.html)
- The main finite element classes are:
+ [`FiniteElement`](http://mfem.github.io/doxygen/html/classmfem_1_1FiniteElement.html)
+ [`FiniteElementCollection`](http://mfem.github.io/doxygen/html/classmfem_1_1FiniteElement.html)
+ [`FiniteElementSpace`](http://mfem.github.io/doxygen/html/classmfem_1_1FiniteElementSpace.html)
+ [`GridFunction`](http://mfem.github.io/doxygen/html/classmfem_1_1GridFunction.html)
+ [`BilinearFormIntegrator`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearFormIntegrator.html) and [`LinearFormIntegrator`](http://mfem.github.io/doxygen/html/classmfem_1_1LinearFormIntegrator.html)
+ [`LinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1LinearFormIntegrator.html), [`BilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearForm.html) and [`MixedBilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1MixedBilinearForm.html)
- The main linear algebra classes and sources are
+ [`Operator`](http://mfem.github.io/doxygen/html/classmfem_1_1Operator.html) and [`BilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearForm.html)
+ [`Vector`](http://mfem.github.io/doxygen/html/classmfem_1_1BilinearForm.html) and [`LinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1LinearForm.html)
+ [`DenseMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1DenseMatrix.html) and [`SparseMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1SparseMatrix.html)
+ Sparse [smoothers](http://mfem.github.io/doxygen/html/sparsesmoothers_8hpp.html) and linear [solvers](http://mfem.github.io/doxygen/html/solvers_8hpp.html)
- Parallel MPI objects in MFEM inherit their serial counterparts, so a parallel
mesh for example is just a serial mesh on each task plus the information on
shared geometric entities between different tasks. The parallel source files
have a `p` prefix, e.g. `pmesh.cpp` vs. the serial `mesh.cpp`.
- The main parallel classes are
+ [`ParMesh`](http://mfem.github.io/doxygen/html/solvers_8hpp.html)
+ [`ParNCMesh`](http://mfem.github.io/doxygen/html/classmfem_1_1ParMesh.html)
+ [`ParFiniteElementSpace`](http://mfem.github.io/doxygen/html/classmfem_1_1ParFiniteElementSpace.html)
+ [`ParGridFunction`](http://mfem.github.io/doxygen/html/classmfem_1_1ParGridFunction.html)
+ [`ParBilinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1ParBilinearForm.html) and [`ParLinearForm`](http://mfem.github.io/doxygen/html/classmfem_1_1ParLinearForm.html)
+ [`HypreParMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParMatrix.html) and [`HypreParVector`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParVector.html)
+ [`HypreSolver`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreSolver.html) and other [hypre classes](http://mfem.github.io/doxygen/html/hypre_8hpp.html)
- The `general/` directory contains C++ classes that serve as utilities for
communication, error handling, arrays, (Boolean) tables, timing, etc.
- The `config/` directory contains build-related files, both for the plain
Makefile and the CMake build options.
- The `doc/` directory contains configuration for the Doxygen code documentation
that can either be build locally, or browsed online at
http://mfem.github.io/doxygen/html/index.html.
- The `data/` directory contains a collection of small mesh files, that are used
in the simple example codes and more fully-featured mini applications in the
`examples/` and `miniapps/` directories.
- See also the [code overview](http://mfem.org/code-overview/) section on the
MFEM website.
## GitHub Workflow
The GitHub organization, https://github.com/mfem, is the main developer hub for
@@ -223,7 +122,7 @@ will allow us to reach you directly with project announcements.
# Work on "feature-dev", add local commits
# ...
# (One time only) push the branch to github and setup your local
# One time only) push the branch to github and setup your local
# branch to track the github branch (for "git pull"):
git push -u origin feature-dev
@@ -433,7 +332,7 @@ MFEM uses a `master`/`next`-branch workflow as described below:
- [ ] `CHANGELOG`
- [ ] `makefile`
- [ ] `CMakeLists.txt`
- [ ] `doc/CodeDocumentation.conf.in`
- [ ] `doc/CodeDocumentation.conf`
- [ ] (LLNL only) Make sure all `README.html` files in the source repo are up to date.
- [ ] Tag the repository:
+3 -22
View File
@@ -25,16 +25,10 @@ The library supports two build systems: one based on GNU make, and a second one
based on CMake. Both build systems are described below. Some hints for building
without GNU make or CMake can be found at the end of this file.
In addition to the native build systems, MFEM packages are also available in the
following package managers:
In addition to the native build systems, MFEM packages are also available in
the Homebrew/Science, https://github.com/Homebrew/homebrew-science, and the
Spack, https://github.com/LLNL/spack, package managers.
- Spack, https://github.com/spack/spack
- OpenHPC, http://openhpc.community
- Homebrew/Science, https://github.com/Homebrew/homebrew-science
We also recommend downloading and building the MFEM-based GLVis visualization
tool which can be used to visualize the meshes and solution in MFEM's examples
and miniapps. See http://glvis.org and http://mfem.org/building.
Quick start with GNU make
=========================
@@ -355,13 +349,6 @@ MFEM_USE_GZSTREAM = YES/NO
before attempting to use it with MFEM.
When enabled, this option uses the ZLIB_* library options, see below.
MFEM_USE_PUMI = YES/NO
Enable the usage of PUMI (https://scorec.rpi.edu/pumi/) in MFEM. The Parallel
Unstructured Mesh Infrastructure (PUMI) is an unstructured, distributed mesh
data management system that is capable of handling general non-manifold
models and effectively supports automated adaptive analysis. PUMI enables
support for parallel unstructured mesh modifications in MFEM.
MFEM_BUILD_TAG = (any value)
An optional tag to characterize the build. Exported to config/config.mk.
Can be used to identify the MFEM build from other makefiles.
@@ -471,10 +458,6 @@ The specific libraries and their options are:
https://support.hdfgroup.org/HDF5 (HDF5)
Options: CONDUIT_OPT, CONDUIT_LIB.
- PUMI, used when MFEM_USE_PUMI = YES.
URL: https://scorec.rpi.edu/pumi
Options: PUMI_OPT, PUMI_LIB.
- MPFR (optional), used when MFEM_USE_MPFR = YES.
URL: http://mpfr.org, it depends on the GMP library: https://gmplib.org
Options: MPFR_OPT, MPFR_LIB.
@@ -607,7 +590,6 @@ MFEM_USE_GNUTLS
MFEM_USE_NETCDF
MFEM_USE_MPFR
MFEM_USE_GZSTREAM
MFEM_USE_PUMI
The following options are CMake specific:
@@ -653,7 +635,6 @@ The CMake build system adds auto-detection for the following packages/libraries:
- MPFR
- LIBUNWIND
- POSIXCLOCKS
- PUMI
The following built-in CMake packages are also used:
+6 -11
View File
@@ -12,15 +12,11 @@ to enable the research and development of scalable finite element discretization
and solver algorithms through general finite element abstractions, accurate and
flexible visualization, and tight integration with the hypre library.
* For building instructions, see the file INSTALL, or type "make help".
For building instructions, see the file INSTALL, or type "make help". Copyright
information and licensing restrictions can be found in the file COPYRIGHT.
* Copyright and licensing information can be found in the file COPYRIGHT.
* The best starting point for new users interested in MFEM's features is the
interactive documentation in examples/README.html.
* Developers interested in contributing to the library, should read the
instructions and documentation in the CONTRIBUTING.md file.
The best starting point for new users interested in MFEM's features is the
interactive documentation in examples/README.html.
Conceptually, MFEM can be viewed as a finite element toolbox that provides the
building blocks for developing finite element algorithms in a manner similar to
@@ -60,8 +56,7 @@ time integrators, etc.
For examples of using MFEM, see the examples/ and miniapps/ directories, as well
as the OpenGL visualization tool GLVis which is available at http://glvis.org.
This project is released under the LGPL v2.1 license with static linking
exception. See files COPYRIGHT and LICENSE file for full details.
This project is released under the LGPL v2.1 license. See LICENSE file for full
details.
LLNL Release Number: LLNL-CODE-443211
DOI: 10.11578/dc.20171025.1248
-1
View File
@@ -39,7 +39,6 @@ set(MFEM_USE_PETSC @MFEM_USE_PETSC@)
set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
set(MFEM_USE_PUMI @MFEM_USE_PUMI@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
-7
View File
@@ -98,9 +98,6 @@
// Enable MFEM functionality based on Conduit
#cmakedefine MFEM_USE_CONDUIT
// Enable MFEM functionality based on the PUMI library
#cmakedefine MFEM_USE_PUMI
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
@@ -116,8 +113,4 @@
// Version of HYPRE used for building MFEM.
#cmakedefine MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
// Macro defined when PUMI is built with support for the Simmetrix SimModSuite
// library.
#cmakedefine MFEM_USE_SIMMETRIX
#endif // MFEM_CONFIG_HEADER
-3
View File
@@ -36,7 +36,4 @@
#ifdef MFEM_USE_PETSC
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#ifdef MFEM_USE_PUMI
#error Building with PUMI (MFEM_USE_PUMI=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#endif // MFEM_USE_MPI not defined
+3 -7
View File
@@ -58,6 +58,9 @@
// Use LAPACK routines for various dense linear algebra operations.
// #define MFEM_USE_LAPACK
// Use Eigen for math routines
// #define MFEM_USE_EIGEN
// Use thread-safe implementation. This comes at the cost of extra memory
// allocation and de-allocation.
// #define MFEM_THREAD_SAFE
@@ -109,9 +112,6 @@
// Enable functionality based on the MPFR library.
// #define MFEM_USE_MPFR
// Enable MFEM functionality based on the PUMI library
// #define MFEM_USE_PUMI
// Windows specific options
#ifdef _WIN32
// Macro needed to get defines like M_PI from <cmath>. (Visual Studio C++ only?)
@@ -121,8 +121,4 @@
// Version of HYPRE used for building MFEM.
// #define MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
// Macro defined when PUMI is built with support for the Simmetrix SimModSuite
// library.
// #define MFEM_USE_SIMMETRIX
#endif // MFEM_CONFIG_HEADER
+1 -1
View File
@@ -21,6 +21,7 @@ MFEM_USE_EXCEPTIONS = @MFEM_USE_EXCEPTIONS@
MFEM_USE_GZSTREAM = @MFEM_USE_GZSTREAM@
MFEM_USE_LIBUNWIND = @MFEM_USE_LIBUNWIND@
MFEM_USE_LAPACK = @MFEM_USE_LAPACK@
MFEM_USE_EIGEN = @MFEM_USE_EIGEN@
MFEM_THREAD_SAFE = @MFEM_THREAD_SAFE@
MFEM_USE_OPENMP = @MFEM_USE_OPENMP@
MFEM_USE_MEMALLOC = @MFEM_USE_MEMALLOC@
@@ -37,7 +38,6 @@ MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
MFEM_USE_PUMI = @MFEM_USE_PUMI@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
-4
View File
@@ -40,7 +40,6 @@ option(MFEM_USE_PETSC "Enable PETSc support." OFF)
option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
option(MFEM_USE_PUMI "Enable PUMI" OFF)
# Allow a user to disable testing, examples, and/or miniapps at CONFIGURE TIME
# if they don't want/need them (e.g. if MFEM is "just a dependency" and all they
@@ -146,9 +145,6 @@ set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH "Path to the Axom library.")
set(Axom_REQUIRED_PACKAGES "Conduit/relay" CACHE STRING
"Additional packages required by Axom.")
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
"Directory where PUMI is installed")
set(BLAS_INCLUDE_DIRS "" CACHE STRING "Path to BLAS headers.")
set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
+7 -9
View File
@@ -21,7 +21,7 @@ NOTMAC := $(subst Darwin,,$(shell uname -s))
CXX = g++
MPICXX = mpicxx
OPTIM_FLAGS = -O3
OPTIM_FLAGS = -O3 -pg
DEBUG_FLAGS = -g -Wall
# Destination location of make install
@@ -90,6 +90,7 @@ MFEM_USE_EXCEPTIONS = NO
MFEM_USE_GZSTREAM = NO
MFEM_USE_LIBUNWIND = NO
MFEM_USE_LAPACK = NO
MFEM_USE_EIGEN = NO
MFEM_THREAD_SAFE = NO
MFEM_USE_OPENMP = NO
MFEM_USE_MEMALLOC = YES
@@ -106,7 +107,6 @@ MFEM_USE_PETSC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
MFEM_USE_PUMI = NO
# Compile and link options for zlib.
ZLIB_DIR =
@@ -146,6 +146,11 @@ endif
LAPACK_OPT =
LAPACK_LIB = $(if $(NOTMAC),-llapack -lblas,-framework Accelerate)
# Eigen configuration
EIGEN_DIR = @MFEM_DIR@/../eigen
EIGEN_OPT = -I$(EIGEN_DIR) -std=c++11 -Wno-enum-compare
EIGEN_LIB =
# OpenMP configuration
OPENMP_OPT = -fopenmp
OPENMP_LIB =
@@ -272,13 +277,6 @@ SIDRE_LIB = \
-Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \
-lsidre -lslic -laxom_utils -lconduit -lconduit_relay -lhdf5 $(ZLIB_LIB) -ldl
# PUMI
# Note that PUMI_DIR is needed -- it is used to check for gmi_sim.h
PUMI_DIR = @MFEM_DIR@/../pumi-2.1.0
PUMI_OPT = -I$(PUMI_DIR)/include
PUMI_LIB = -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf -lpcu -lgmi -lparma\
-llion -lmth -lapf_zoltan -lspr
# If YES, enable some informational messages
VERBOSE = NO
+2 -11
View File
@@ -38,9 +38,6 @@ all: header config-mk
MPI = $(MFEM_USE_MPI:NO=)
GHV = get_hypre_version
GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
SMX_PATH = $(PUMI_DIR)/include/gmi_sim.h
SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
$(GHV): $(SRC)$(GHV).cpp
$(call mfem-info, Determining HYPRE version ...)
@@ -55,16 +52,10 @@ get-hypre-version: $(GHV).out
$(info HYPRE version: $(MFEM_HYPRE_VERSION)),\
$(error Unable to determine HYPRE version))
check-smx:
$(call mfem-info, Checking for Simmetrix header [$(SMX_FILE)] ...)
$(eval MFEM_USE_SIMMETRIX:=$(if $(wildcard $(SMX_FILE)),YES,NO))
$(call mfem-info, MFEM_USE_SIMMETRIX = $(MFEM_USE_SIMMETRIX))
$(eval export MFEM_USE_SIMMETRIX)
header: $(if $(MPI),get-hypre-version,) $(if $(SMX),check-smx)
header: $(if $(MPI),get-hypre-version,)
$(call mfem-info, Writing $(CONFIG_HPP) ...)
@set -- && \
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION) $(SMX); do \
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION,); do \
eval var=\$$$$def && \
if [ "NO" != "$${var}" ]; then \
set -- "$$@" -e "s|// \(#define $${def} \)|\1|" && \
-2
View File
@@ -14,13 +14,11 @@
# Colors used below:
# green '\033[0;32m'
# red '\033[0;31m'
# yellow '\033[0;33m'
# no color '\033[0m'
COLOR_PRINT = if [ -t 1 ]; then \
printf $(1)$(2)'\033[0m'$(3); else printf $(2)$(3); fi
PRINT_OK = $(call COLOR_PRINT,'\033[0;32m',OK," ($$1 $$2)\n")
PRINT_FAILED = $(call COLOR_PRINT,'\033[0;31m',FAILED," ($$1 $$2)\n")
PRINT_SKIP = $(call COLOR_PRINT,'\033[0;33m',SKIP,"\n")
# Timing support
define TIMECMD_detect
-218
View File
@@ -1,218 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
74
2 3 0 1 2 3
2 3 1 5 6 2
2 3 5 8 9 6
2 3 8 11 12 9
2 3 11 14 15 12
2 3 14 17 18 15
2 3 17 20 21 18
2 3 20 23 24 21
2 3 23 26 27 24
2 3 26 29 30 27
2 3 29 32 33 30
2 3 32 35 36 33
2 3 35 38 39 36
2 3 38 41 42 39
2 3 41 44 45 42
2 3 44 47 48 45
2 3 47 50 51 48
2 3 50 53 54 51
2 3 53 56 57 54
2 3 56 59 60 57
2 3 59 62 63 60
2 3 62 65 66 63
2 3 65 68 69 66
2 3 68 71 72 69
2 3 71 74 75 72
1 2 2 3 4
1 2 6 2 7
1 2 9 6 10
1 2 12 9 13
1 2 15 12 16
1 2 18 15 19
1 2 21 18 22
1 2 24 21 25
1 2 27 24 28
1 2 30 27 31
1 2 33 30 34
1 2 36 33 37
1 2 39 36 40
1 2 42 39 43
1 2 45 42 46
1 2 48 45 49
1 2 51 48 52
1 2 54 51 55
1 2 57 54 58
1 2 60 57 61
1 2 63 60 64
1 2 66 63 67
1 2 69 66 70
1 2 72 69 73
1 2 75 72 76
1 2 2 4 7
1 2 6 7 10
1 2 9 10 13
1 2 12 13 16
1 2 15 16 19
1 2 18 19 22
1 2 21 22 25
1 2 24 25 28
1 2 27 28 31
1 2 30 31 34
1 2 33 34 37
1 2 36 37 40
1 2 39 40 43
1 2 42 43 46
1 2 45 46 49
1 2 48 49 52
1 2 51 52 55
1 2 54 55 58
1 2 57 58 61
1 2 60 61 64
1 2 63 64 67
1 2 66 67 70
1 2 69 70 73
1 2 72 73 76
boundary
53
1 1 0 1
1 1 1 5
1 1 5 8
1 1 8 11
1 1 11 14
1 1 14 17
1 1 17 20
1 1 20 23
1 1 23 26
1 1 26 29
1 1 29 32
1 1 32 35
1 1 35 38
1 1 38 41
1 1 41 44
1 1 44 47
1 1 47 50
1 1 50 53
1 1 53 56
1 1 56 59
1 1 59 62
1 1 62 65
1 1 65 68
1 1 68 71
1 1 71 74
1 1 74 75
1 1 75 76
1 1 76 73
1 1 73 70
1 1 70 67
1 1 67 64
1 1 64 61
1 1 61 58
1 1 58 55
1 1 55 52
1 1 52 49
1 1 49 46
1 1 46 43
1 1 43 40
1 1 40 37
1 1 37 34
1 1 34 31
1 1 31 28
1 1 28 25
1 1 25 22
1 1 22 19
1 1 19 16
1 1 16 13
1 1 13 10
1 1 10 7
1 1 7 4
1 1 4 3
1 1 3 0
vertices
77
2
3.9788735773 0.0
3.84329674785 1.02980825986
2.88247256089 0.772356194895
2.98415518297 0.0
1.97241688113 0.259673608685
3.44580559639 1.98943678865
2.58435419729 1.49207759149
1.83799993026 0.761324498753
2.81348848799 2.81348848799
2.11011636599 2.11011636599
1.57832632157 1.21109238238
1.98943678865 3.44580559639
1.49207759149 2.58435419729
1.21109238238 1.57832632157
1.02980825986 3.84329674785
0.772356194895 2.88247256089
0.761324498753 1.83799993026
2.43635739532e-16 3.9788735773
1.82726804649e-16 2.98415518297
0.259673608685 1.97241688113
-1.02980825986 3.84329674785
-0.772356194895 2.88247256089
-0.259673608685 1.97241688113
-1.98943678865 3.44580559639
-1.49207759149 2.58435419729
-0.761324498753 1.83799993026
-2.81348848799 2.81348848799
-2.11011636599 2.11011636599
-1.21109238238 1.57832632157
-3.44580559639 1.98943678865
-2.58435419729 1.49207759149
-1.57832632157 1.21109238238
-3.84329674785 1.02980825986
-2.88247256089 0.772356194895
-1.83799993026 0.761324498753
-3.9788735773 4.87271479065e-16
-2.98415518297 3.65453609299e-16
-1.97241688113 0.259673608685
-3.84329674785 -1.02980825986
-2.88247256089 -0.772356194895
-1.97241688113 -0.259673608685
-3.44580559639 -1.98943678865
-2.58435419729 -1.49207759149
-1.83799993026 -0.761324498753
-2.81348848799 -2.81348848799
-2.11011636599 -2.11011636599
-1.57832632157 -1.21109238238
-1.98943678865 -3.44580559639
-1.49207759149 -2.58435419729
-1.21109238238 -1.57832632157
-1.02980825986 -3.84329674785
-0.772356194895 -2.88247256089
-0.761324498753 -1.83799993026
-7.30907218597e-16 -3.9788735773
-5.48180413948e-16 -2.98415518297
-0.259673608685 -1.97241688113
1.02980825986 -3.84329674785
0.772356194895 -2.88247256089
0.259673608685 -1.97241688113
1.98943678865 -3.44580559639
1.49207759149 -2.58435419729
0.761324498753 -1.83799993026
2.81348848799 -2.81348848799
2.11011636599 -2.11011636599
1.21109238238 -1.57832632157
3.44580559639 -1.98943678865
2.58435419729 -1.49207759149
1.57832632157 -1.21109238238
3.84329674785 -1.02980825986
2.88247256089 -0.772356194895
1.83799993026 -0.761324498753
3.9788735773 -9.7454295813e-16
2.98415518297 -7.30907218597e-16
1.97241688113 -0.259673608685
3.84329674785 1.02980825986
2.88247256089 0.772356194895
1.97241688113 0.259673608685
@@ -1,74 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
20
2 3 0 1 2 3
2 3 1 5 6 2
2 3 5 8 9 6
2 3 8 11 12 9
2 3 11 14 15 12
2 3 14 17 18 15
2 3 17 20 21 18
1 2 2 3 4
1 2 6 2 7
1 2 9 6 10
1 2 12 9 13
1 2 15 12 16
1 2 18 15 19
1 2 21 18 22
1 2 2 4 7
1 2 6 7 10
1 2 9 10 13
1 2 12 13 16
1 2 15 16 19
1 2 18 19 22
boundary
17
1 1 0 1
1 1 1 5
1 1 5 8
1 1 8 11
1 1 11 14
1 1 14 17
1 1 17 20
1 1 20 21
1 1 21 22
1 1 22 19
1 1 19 16
1 1 16 13
1 1 13 10
1 1 10 7
1 1 7 4
1 1 4 3
1 1 3 0
vertices
23
2
1.11408460164 0.0
0.557042300822 0.964825566988
0.417781725616 0.723619175241
0.835563451232 0.0
0.482412783494 0.278521150411
-0.557042300822 0.964825566988
-0.417781725616 0.723619175241
3.41090035345e-17 0.557042300822
-1.11408460164 1.36436014138e-16
-0.835563451232 1.02327010604e-16
-0.482412783494 0.278521150411
-0.557042300822 -0.964825566988
-0.417781725616 -0.723619175241
-0.482412783494 -0.278521150411
0.557042300822 -0.964825566988
0.417781725616 -0.723619175241
-1.02327010604e-16 -0.557042300822
1.11408460164 -2.72872028276e-16
0.835563451232 -2.04654021207e-16
0.482412783494 -0.278521150411
0.557042300822 0.964825566988
0.417781725616 0.723619175241
0.482412783494 0.278521150411
-924
View File
@@ -1,924 +0,0 @@
#Title:circInSquare.py
#Author:T. M. McManus
#Date:10-7-18
#Purpose: Fill a circular sector with triangles and a bounding region,
#defined by 3 nodes, with quads. Then reflect/preserve QuadI twice to
#create a complete disc bounded in a square.
import scipy as sp
import argparse
import sys
import subprocess
import time
parser=argparse.ArgumentParser(description='Fill a circular sector with triangles and a bounding region,\
defined by 3 nodes, with quads. Then reflect/preserve QuadI twice to create a complete disc bounded in a square.'
,epilog='Sample run: python circInSquare.py -r 1 -e 2 -n 8 -g ../../../glvis/glvis')
parser.add_argument('-r','--circRad', nargs='?',const=1, default = 1.0, type=float, help='Radius of circle')
parser.add_argument('-e','--edgeLength', nargs='?',const=1,default=2.0,type=float,help='Edge-length of bounding square')
parser.add_argument('-n','--numEdges',nargs='?',const=1,default=6,type=int,help='n-gon approximation of internal circle')
parser.add_argument('-o','--outputFile',nargs='?',const=1,default='circInSquare', help='Output file name.')
parser.add_argument('-g','--glvis',nargs='?',const=1,default='',type=str,help='Abs. or rel. path of glvis binary.')
args=parser.parse_args()
r=args.circRad
edgeLength=args.edgeLength
numEdges=args.numEdges
outputName=args.outputFile
glvis=args.glvis
visMesh=False;
if glvis!='':
visMesh=True
if r >= edgeLength:
print("Circle radius must be less than bounding square edge length")
sys.exit(1)
if sp.mod(numEdges,2) != 0:
print("Currently this mixed element generator only supports an even numbers of edges.")
sys.exit(1)
#The basic idea:
#1. Construct topology for regions
#2. Combine topologies
#3. Construct boundary
#4. Construct geometry for regions
#5. Combine geometries
#6. Output
def eleMatCirc(numEdges):
nNodesSeq=sp.zeros([numEdges])
nNodesSeq[0]=3
if numEdges != 1:
for n in range(1,numEdges):
nNodesSeq[n]=nNodesSeq[n-1]+(2+n)
numCircNodesTot =int(((numEdges+1)*(numEdges+2))/2)
b=range(numCircNodesTot)
row_size=1
A=sp.zeros([numEdges+1,numEdges+1])
start=0;stop=1;
for m in range(numEdges+1):
if m==0:
A[m,range(m+1)]=b[0:1]
start=0
stop=1
else:
start=stop
stop=stop+m+1
A[m,range(m+1)]=b[start:stop]
M=sp.ones([numEdges**2,5])
m_row=0
for m in range(numEdges):
if m==0:
M[0,:]=[1,2,0,1,2]
m_row+=1
else:
holder=sp.size(sp.nonzero(A[m,:]))
for n in range(holder):
if n!=holder-1:
M[m_row,:]=[1,2,A[m,n],A[m,n+1],A[m+1,n+1]]
m_row+=1
M[m_row,:]=[1,2,A[m,n],A[m+1,n],A[m+1,n+1]]
m_row+=1
else:
M[m_row,:]=[1,2,A[m,n],A[m+1,n],A[m+1,n+1]]
m_row+=1
return M.astype(int),numCircNodesTot
def eleMatQuad(numEdges):
S0=numEdges*(numEdges+1)/(2.0)
A=sp.linspace(S0,(S0+(numEdges+1)**2)-1,(numEdges+1)**2)
A=A.reshape([numEdges+1,numEdges+1])
quadNode=sp.delete(A,-1,1)
quadNode=sp.delete(quadNode,-1,0)
quadNode=quadNode.flatten()
M=sp.zeros([numEdges**2,6])
for n in range(numEdges**2):
M[n,:]=[2,3,quadNode[n],quadNode[n]+1,quadNode[n]+numEdges+2,quadNode[n]+numEdges+1]
return M.astype(int)
def boundMatTot(numEdges):
triS1=sp.zeros(numEdges+1)
triS3=sp.zeros(numEdges+1)
quadS1=sp.zeros(numEdges)
quadS2=sp.zeros(numEdges-1)
quadS3=sp.zeros(numEdges)
triS1[0]=0;
triS3[0]=0;
for n in range(1,numEdges+1):
triS1[n]=triS1[n-1]+n
triS3[n]=triS1[n]+n
ref1=triS3
triS3=sp.flipud(triS3)
quadS1[0]=triS1[-1]+numEdges+1
quadS3[0]=triS1[-1]+2*numEdges+1
for n in range(1,numEdges):
quadS1[n]=quadS1[n-1]+(numEdges+1)
quadS3[n]=quadS3[n-1]+(numEdges+1)
ref2=quadS3
xAxisRootRef=sp.concatenate([triS1.copy(),quadS1],axis=0)
quadS3=sp.flipud(quadS3)
quadS2=range(int(quadS1[-1]+1),int(quadS3[0]),1)
STOT=sp.concatenate([triS1,quadS1,quadS2,quadS3,triS3],axis=0)
filler=sp.zeros(1)
filler[0]=quadS3[0]
fillerFirst=sp.zeros(1)
fillerFirst[0]=quadS1[-1]
sTotRef=sp.concatenate([triS1,quadS1,quadS2,filler],axis=0)
newsTotRef=sp.concatenate([fillerFirst,quadS2,filler],axis=0)
boundMat=sp.zeros([STOT.size-1,4])
boundMatRef=sp.zeros([sTotRef.size-1,4])
new_boundMat_ref=sp.zeros([newsTotRef.size-1,4])
for n in range(STOT.size-1):
boundMat[n,:]=[1,1,STOT[n],STOT[n+1]]
for n in range(sTotRef.size-1):
boundMatRef[n,:]=[1,1,sTotRef[n],sTotRef[n+1]]
for n in range(newsTotRef.size-1):
new_boundMat_ref[n,:]=[1,1,newsTotRef[n],newsTotRef[n+1]]
ref=sp.concatenate([ref1,ref2],axis=0).astype(int)
return boundMat.astype(int),ref,boundMatRef.astype(int),xAxisRootRef.astype(int),new_boundMat_ref.astype(int)
def vertMatCirc(numEdges):
r_o=sp.linspace(0,r,numEdges+1)
counter=0
vertMat=sp.zeros([numCircNodesTot,2])
for m in range(numEdges+1):
theta=sp.linspace(0,sp.pi/2.0,m+1)
for n in range(sp.size(theta)):
vertMat[counter,:]=[r_o[m]*sp.cos(theta[n]),r_o[m]*sp.sin(theta[n])]
counter+=1
return vertMat
def vertMatQuad(numEdges):
theta=sp.linspace(0,sp.pi/2.0,numEdges+1)
AX=sp.zeros([numEdges+1,numEdges+1])
AY=sp.zeros([numEdges+1,numEdges+1])
AX[0,:]=r*sp.cos(theta)
AY[0,:]=r*sp.sin(theta)
vertLinSpace=sp.linspace(0,edgeLength,(numEdges/2)+1)
horzLineSpace=sp.linspace(edgeLength,0,(numEdges/2)+1)
#Assigning node locations along the boundary
vertCount=0
horzCount=1
for n in range(numEdges+1):
if n < (numEdges/2):
AX[-1,n]=edgeLength
AY[-1,n]=vertLinSpace[vertCount]
vertCount+=1
elif n == int(numEdges/2):
AX[-1,n]=edgeLength
AY[-1,n]=edgeLength
else:
AX[-1,n]=horzLineSpace[horzCount]
AY[-1,n]=edgeLength
horzCount+=1
#Linearly spacing nodes between the inner/outer boundaries
#One could then smooth this via r-based adaptivity
for col in range(numEdges+1):
for row in range(1,numEdges):
AX[row,col]=sp.linspace(AX[0,col],AX[-1,col],numEdges+1)[row]
AY[row,col]=sp.linspace(AY[0,col],AY[-1,col],numEdges+1)[row]
AX=sp.delete(AX,0,0)
AY=sp.delete(AY,0,0)
AX=AX.flatten()
AY=AY.flatten()
AX_reshape = AX.flatten()
numQuadNodesTot=numEdges*(numEdges+1)
vertMat=sp.zeros([numQuadNodesTot,2])
for n in range(numQuadNodesTot):
vertMat[n,:]=[AX[n],AY[n]]
return vertMat
def orient(A):
aOrient=sp.zeros([A.shape[0],A.shape[1]])
triCounter=0
quadCounter=0
#Determine the number of triangle and quad elments in the given element matrix
for n in range(A.shape[0]):
if A[n,1]==2:
triCounter+=1
else:
quadCounter+=1
edgeMatTotal=sp.zeros([3*triCounter+4*quadCounter,2])
counter=0
for n in range(A.shape[0]):
detected=0
if A[n,1]==2:
for m in range(edgeMatTotal.shape[0]):
if detected != 1:
if edgeMatTotal[m,0]==A[n,2] and edgeMatTotal[m,1]==A[n,3]:
aOrient[n,:]=[1,2,A[n,2],A[n,4],A[n,3],0]
detected=1
#print("reorder:[{} {} {}] to [{} {} {}]".format(A[n,2],A[n,3],A[n,4],int(aOrient[n,2]),int(aOrient[n,3]),int(aOrient[n,4])))
elif edgeMatTotal[m,0]==A[n,4] and edgeMatTotal[m,1]==A[n,2]:
aOrient[n,:]=[1,2,A[n,2],A[n,4],A[n,3],0]
detected=1
else:
aOrient[n,:]=A[n,:]
edgeMatTotal[counter,:]=[aOrient[n,2],aOrient[n,3]]
counter+=1
edgeMatTotal[counter,:]=[aOrient[n,3],aOrient[n,4]]
counter+=1
edgeMatTotal[counter,:]=[aOrient[n,4],aOrient[n,2]]
counter+=1
else:
for m in range(edgeMatTotal.shape[0]):
if detected != 1:
if edgeMatTotal[m,0]==A[n,2] and edgeMatTotal[m,1]==A[n,3]:
aOrient[n,:]=[2,3,A[n,2],A[n,5],A[n,4],A[n,3]]
detected=1
#print("reorder:[{} {} {} {}] to [{} {} {} {}]".format(A[n,2],A[n,3],A[n,4],A[n,5],int(aOrient[n,2]),int(aOrient[n,3]),int(aOrient[n,4]),int(aOrient[n,5])))
elif edgeMatTotal[m,0]==A[n,5] and edgeMatTotal[m,1]==A[n,2]:
aOrient[n,:]=[2,3,A[n,2],A[n,5],A[n,4],A[n,3]]
detected=1
else:
aOrient[n,:]=A[n,:]
edgeMatTotal[counter,:]=[aOrient[n,2],aOrient[n,3]]
counter+=1
edgeMatTotal[counter,:]=[aOrient[n,3],aOrient[n,4]]
counter+=1
edgeMatTotal[counter,:]=[aOrient[n,4],aOrient[n,5]]
counter+=1
edgeMatTotal[counter,:]=[aOrient[n,5],aOrient[n,2]]
counter+=1
return aOrient.astype(int)
def gVis(_glvis,_meshFile):
if(_glvis==''):
print("Failure: Set glvis location via -g switch")
sys.exit(1)
colFuncFileName=_meshFile.replace('.mesh','.gf')
glvsScriptFileName=_meshFile.replace('.mesh','.glvs')
imageFileName=_meshFile.replace('.mesh','.png')
#Create Coloring Function for mesh
_colFuncCommand=_glvis+ ' -m '+ _meshFile +' -sc -k q'
args=_colFuncCommand.split()
p=subprocess.Popen(args)#Create 'GLVis_coloring.gf'
_renameCommand='mv GLVis_coloring.gf {}'.format(colFuncFileName)
args=_renameCommand.split()
p=subprocess.Popen(args)
#Glvis script template
f=open(glvsScriptFileName,'w')
f.write('window 0 0 800 800\n'+'\n')
f.write('solution {} {}\n'.format(_meshFile,colFuncFileName)+'\n')
f.write('{\n'+'perspective off\n'+'zoom 1.5\n'+'keys gAeeRM\n'+'solution {} {} screenshot {}\n'.format(_meshFile,colFuncFileName,imageFileName)+'keys q\n'+'}\n')
f.close()
_runGlvisCommand=_glvis+' -run {}'.format(glvsScriptFileName)
args=_runGlvisCommand.split()
p=subprocess.Popen(args)
p.wait()
return 0
def quadInterDof(_edge,_linEleMat,_linVertMatRound):
_state=False
for n in range(_linEleMat.shape[0]):
if _linEleMat[n,1]==3:
if sp.any(_edge[0]==_linEleMat[n,2:6]) and sp.any(_edge[1]==_linEleMat[n,2:6]):
print("{} is possibly in {}".format(_edge,_linEleMat[n,2:6]))
_n1Loc=sp.where(_edge[0]==_linEleMat[n,2:6])[0][0]
_n2Loc=sp.where(_edge[1]==_linEleMat[n,2:6])[0][0]
if _n1Loc==sp.mod(_n2Loc+1,4) or _n1Loc==sp.mod(_n2Loc-1,4):
_state=True
xcent=(_linVertMatRound[_linEleMat[n,2],0]+_linVertMatRound[_linEleMat[n,3],0]+_linVertMatRound[_linEleMat[n,4],0]+_linVertMatRound[_linEleMat[n,5],0])/4.0
ycent=(_linVertMatRound[_linEleMat[n,2],1]+_linVertMatRound[_linEleMat[n,3],1]+_linVertMatRound[_linEleMat[n,4],1]+_linVertMatRound[_linEleMat[n,5],1])/4.0
_interDof=sp.zeros(2)
_interDof[0]=sp.round_((_linVertMatRound[_edge[0],0]+_linVertMatRound[_edge[1],0]+xcent)/3.0,5)
_interDof[1]=sp.round_((_linVertMatRound[_edge[0],1]+_linVertMatRound[_edge[1],1]+ycent)/3.0,5)
print("dof loc is {},{}".format(_interDof[0],_interDof[1]))
return(_state,_interDof[0],_interDof[1])
return(_state,0,0)
[eleMatTriHolder,numCircNodesTot]=eleMatCirc(numEdges) #Construct tri element matrix for the region inside circular sector
eleMatQuadHolder=eleMatQuad(numEdges) #Construct quad element matrix for region outside the circular sector
#Combining eleMatTriHolder and eleMatQuadHolder
linEleMat=sp.zeros([eleMatTriHolder.shape[0]+eleMatQuadHolder.shape[0],6])
counter=0
for n in range(eleMatTriHolder.shape[0]):
linEleMat[n,[0,1,2,3,4]]=eleMatTriHolder[n,:]
counter+=1
for n in range(eleMatQuadHolder.shape[0]):
linEleMat[counter+n,:]=eleMatQuadHolder[n,:]
linEleMat=linEleMat.astype(int)
linBoundMat=boundMatTot(numEdges)[0] #Construct the boundary
vertMatCircHolder = vertMatCirc(numEdges) #Construct vertex matrix for triang region
vertMatQuadHolder = vertMatQuad(numEdges) #Construct vertex matrix for the quad region
#Combining the two vertex matrices in Quadrant I (q1)
linVertMat=sp.zeros([vertMatCircHolder.shape[0]+vertMatQuadHolder.shape[0],2])
counter=0
for n in range(vertMatCircHolder.shape[0]):
linVertMat[n,:]=vertMatCircHolder[n,:]
counter+=1
for n in range(vertMatQuadHolder.shape[0]):
linVertMat[counter+n,:]=vertMatQuadHolder[n,:]
#Outputting P1/Q1 mesh to a .mesh file
g=open(outputName+'Lin.mesh','w')
g.write('MFEM mesh v1.0\n'+'\n')
g.write('dimension\n'+'2\n'+'\n')
g.write('elements\n'+'{}\n'.format(linEleMat.shape[0]))
for n in range(linEleMat.shape[0]):
if linEleMat[n,1]==2:
g.write('{} {} {} {} {}\n'.format(linEleMat[n,0],linEleMat[n,1],linEleMat[n,2],linEleMat[n,3],linEleMat[n,4]))
else:
g.write('{} {} {} {} {} {}\n'.format(linEleMat[n,0],linEleMat[n,1],linEleMat[n,2],linEleMat[n,3],linEleMat[n,4],linEleMat[n,5]))
g.write('\n'+'boundary\n'+'{}\n'.format(linBoundMat.shape[0]))
for n in range(linBoundMat.shape[0]):
g.write('{} {} {} {}\n'.format(linBoundMat[n,0],linBoundMat[n,1],linBoundMat[n,2],linBoundMat[n,3]))
g.write('\n'+'vertices\n'+'{}\n'.format(linVertMat.shape[0])+'2\n')
for n in range(linVertMat.shape[0]):
g.write('{} {}\n'.format(linVertMat[n,0],linVertMat[n,1]))
g.close()
if(visMesh==True):
gVis(glvis,outputName+'Lin.mesh')
#Quadratic (P2/Q2) Element Generation
#1.)Create Edge list from previously generated linear elements
edgeMat=sp.zeros([3*eleMatTriHolder.shape[0]+4*eleMatQuadHolder.shape[0],2])
linEleMat=orient(linEleMat)#Make sure that element orientation is in agreement with MFEM requirements
counter=0
for n in range(linEleMat.shape[0]):
if linEleMat[n,1]==2:
edgeMat[counter,:]=[linEleMat[n,2],linEleMat[n,3]]
counter+=1
edgeMat[counter,:]=[linEleMat[n,3],linEleMat[n,4]]
counter+=1
edgeMat[counter,:]=[linEleMat[n,4],linEleMat[n,2]]
counter+=1
else:
edgeMat[counter,:]=[linEleMat[n,2],linEleMat[n,3]]
counter+=1
edgeMat[counter,:]=[linEleMat[n,3],linEleMat[n,4]]
counter+=1
edgeMat[counter,:]=[linEleMat[n,4],linEleMat[n,5]]
counter+=1
edgeMat[counter,:]=[linEleMat[n,5],linEleMat[n,2]]
counter+=1
#Remove duplicates
holder=[]
for n in range(edgeMat.shape[0]):
counter=0
for m in range(edgeMat.shape[0]):
if edgeMat[n,0]==edgeMat[m,0] and edgeMat[n,1]==edgeMat[m,1] and m!=n:
holder.append([n,m])
elif edgeMat[n,1]==edgeMat[m,0] and edgeMat[n,0]==edgeMat[m,1] and m!=n:
holder.append([n,m])
removeIndices=sp.zeros(len(holder))
for n in range(len(holder)):
if holder[n][0]>holder[n][1]:
removeIndices[n]=holder[n][0]
else:
removeIndices[n]=holder[n][1]
removeIndices=sp.unique(removeIndices).astype(int)
edgeMat=sp.delete(edgeMat,removeIndices,0)
edgeMat=edgeMat.astype(int)
edgeDofMat=sp.zeros([edgeMat.shape[0],2])#These will be the new DoFs that appear after the Element Vertices within the .mesh file
linVertMatRound=sp.round_(linVertMat,5)
counter=0
for n in edgeMat:
if linVertMatRound[n[0],1] == linVertMatRound[n[1],1]:
xmid=(linVertMatRound[n[0],0]+linVertMatRound[n[1],0])/2.0
ymid=linVertMatRound[n[0],1]
edgeDofMat[counter,:]=[xmid,ymid]
elif linVertMatRound[n[0],0] == linVertMatRound[n[1],0]:
xmid=linVertMatRound[n[0],0]
ymid=(linVertMatRound[n[0],1]+linVertMatRound[n[1],1])/2.0
edgeDofMat[counter,:]=[xmid,ymid]
else:
r0=sp.sqrt(linVertMatRound[n[0],0]**2+linVertMatRound[n[0],1]**2)
r1=sp.sqrt(linVertMatRound[n[1],0]**2+linVertMatRound[n[1],1]**2)
rmid = (r0+r1)/2.0 #should not be needed
xmidOld=(linVertMatRound[n[0],0]+linVertMatRound[n[1],0])/2.0
ymidOld=(linVertMatRound[n[0],1]+linVertMatRound[n[1],1])/2.0
midtheta=sp.arctan(ymidOld/xmidOld)
xmid=rmid*sp.cos(midtheta)
ymid=rmid*sp.sin(midtheta)
edgeDofMat[counter,:]=[xmid,ymid]
counter+=1
edgeDofMat = sp.round_(edgeDofMat,5)
#Determine midpoints of all Q1 elements:
quadCentroidLoc=sp.zeros([eleMatQuadHolder.shape[0],2])
for n in range(eleMatQuadHolder.shape[0]):
quadCentroidLoc[n,0]=(linVertMatRound[eleMatQuadHolder[n,2],0]+linVertMatRound[eleMatQuadHolder[n,3],0]+linVertMatRound[eleMatQuadHolder[n,4],0]+linVertMatRound[eleMatQuadHolder[n,5],0])/4.0
quadCentroidLoc[n,1]=(linVertMatRound[eleMatQuadHolder[n,2],1]+linVertMatRound[eleMatQuadHolder[n,3],1]+linVertMatRound[eleMatQuadHolder[n,4],1]+linVertMatRound[eleMatQuadHolder[n,5],1])/4.0
quadCentroidLoc = sp.round_(quadCentroidLoc,5)
#3.)Populate nodes section
g=open(outputName+'Quad.mesh','w')
g.write('MFEM mesh v1.0\n'+'\n')
g.write('dimension\n'+'2\n'+'\n')
g.write('elements\n'+'{}\n'.format(linEleMat.shape[0]))
for n in range(linEleMat.shape[0]):
if linEleMat[n,1]==2:
g.write('{} {} {} {} {}\n'.format(linEleMat[n,0],linEleMat[n,1],linEleMat[n,2],linEleMat[n,3],linEleMat[n,4]))
else:
g.write('{} {} {} {} {} {}\n'.format(linEleMat[n,0],linEleMat[n,1],linEleMat[n,2],linEleMat[n,3],linEleMat[n,4],linEleMat[n,5]))
g.write('\n'+'boundary\n'+'{}\n'.format(linBoundMat.shape[0]))
for n in range(linBoundMat.shape[0]):
g.write('{} {} {} {}\n'.format(linBoundMat[n,0],linBoundMat[n,1],linBoundMat[n,2],linBoundMat[n,3]))
g.write('\n'+'vertices\n'+'{}\n'.format(linVertMat.shape[0]))
g.write('\n'+'nodes'+'\n'+'FiniteElementSpace'+'\n'+'FiniteElementCollection: H1_2D_P2'+'\n'+'VDim: 2'+'\n'+'Ordering: 1' +'\n\n')
for n in range(linVertMatRound.shape[0]):
g.write('{} {}\n'.format(linVertMatRound[n,0],linVertMatRound[n,1]))
for n in range(edgeDofMat.shape[0]):
g.write('{} {}\n'.format(edgeDofMat[n,0],edgeDofMat[n,1]))
for n in range(quadCentroidLoc.shape[0]):
g.write('{} {}\n'.format(quadCentroidLoc[n,0],quadCentroidLoc[n,1]))
g.close()
if(visMesh==True):
gVis(glvis,outputName+'Quad.mesh')
#Cubic (P3/Q3) Element Generation
cubeDofMat=sp.zeros([2*edgeMat.shape[0],2])#These will be the new DoFs that appear after the Element Vertices within the .mesh file
counter=0
for n in edgeMat: #Here DoF ordering matters.
if linVertMatRound[n[0],1] == linVertMatRound[n[1],1]:
xmid=(linVertMatRound[n[0],0]+linVertMatRound[n[1],0])/2.0
ymid=linVertMatRound[n[0],1]
xmid1=(linVertMatRound[n[0],0]+xmid)/2.0
ymid1=linVertMatRound[n[0],1]
xmid2=(linVertMatRound[n[1],0]+xmid)/2.0
ymid2=linVertMatRound[n[0],1]
if n[0] > n[1]:
cubeDofMat[counter,:]=[xmid2,ymid2]
counter+=1
cubeDofMat[counter,:]=[xmid1,ymid1]
counter+=1
else:
cubeDofMat[counter,:]=[xmid1,ymid1]
counter+=1
cubeDofMat[counter,:]=[xmid2,ymid2]
counter+=1
elif linVertMatRound[n[0],0] == linVertMatRound[n[1],0]:
xmid=linVertMatRound[n[0],0]
ymid=(linVertMatRound[n[0],1]+linVertMatRound[n[1],1])/2.0
xmid1=linVertMatRound[n[0],0]
ymid1=(linVertMatRound[n[0],1]+ymid)/2.0
xmid2=linVertMatRound[n[0],0]
ymid2=(linVertMatRound[n[1],1]+ymid)/2.0
if n[0] > n[1]:
cubeDofMat[counter,:]=[xmid2,ymid2]
counter+=1
cubeDofMat[counter,:]=[xmid1,ymid1]
counter+=1
else:
cubeDofMat[counter,:]=[xmid1,ymid1]
counter+=1
cubeDofMat[counter,:]=[xmid2,ymid2]
counter+=1
else:
r0=sp.sqrt(linVertMatRound[n[0],0]**2+linVertMatRound[n[0],1]**2)
r1=sp.sqrt(linVertMatRound[n[1],0]**2+linVertMatRound[n[1],1]**2)
rmid = (r0+r1)/2.0 #should not be needed
xmidOld=(linVertMatRound[n[0],0]+linVertMatRound[n[1],0])/2.0
ymidOld=(linVertMatRound[n[0],1]+linVertMatRound[n[1],1])/2.0
midtheta=sp.arctan(ymidOld/xmidOld)
xmid=rmid*sp.cos(midtheta)
ymid=rmid*sp.sin(midtheta)
xmid1=(linVertMatRound[n[0],0]+xmid)/2.0
ymid1=(linVertMatRound[n[0],1]+ymid)/2.0
xmid2=(linVertMatRound[n[1],0]+xmid)/2.0
ymid2=(linVertMatRound[n[1],1]+ymid)/2.0
if n[0] > n[1]:
cubeDofMat[counter,:]=[xmid2,ymid2]
counter+=1
cubeDofMat[counter,:]=[xmid1,ymid1]
counter+=1
else:
cubeDofMat[counter,:]=[xmid1,ymid1]
counter+=1
cubeDofMat[counter,:]=[xmid2,ymid2]
counter+=1
cubeDofMat = sp.round_(cubeDofMat,5)
triCentroidLoc=sp.zeros([eleMatTriHolder.shape[0],2])
for n in range(eleMatTriHolder.shape[0]):
triCentroidLoc[n,0]=(linVertMatRound[eleMatTriHolder[n,2],0]+linVertMatRound[eleMatTriHolder[n,3],0]+linVertMatRound[eleMatTriHolder[n,4],0])/3.0
triCentroidLoc[n,1]=(linVertMatRound[eleMatTriHolder[n,2],1]+linVertMatRound[eleMatTriHolder[n,3],1]+linVertMatRound[eleMatTriHolder[n,4],1])/3.0
quadCentroidLocCubic=sp.zeros([4*eleMatQuadHolder.shape[0],2])
counter=0
for n in range(eleMatQuadHolder.shape[0]):
xcent=quadCentroidLoc[n,0];ycent=quadCentroidLoc[n,1]
a=eleMatQuadHolder[n,2:6]
aMinIndex=sp.where(a[:]==a.min())[0][0]
dof0=0.5*sp.array([xcent+linVertMatRound[a[aMinIndex],0],ycent+linVertMatRound[a[aMinIndex],1]])
quadCentroidLocCubic[counter,:]=dof0
counter+=1
if aMinIndex==0:
aLeft=-1
aRight=1
aLast=2
else:
aLeft=aMinIndex-1
aRight=aMinIndex+1
aLast=sp.delete(a,[aMinIndex,aLeft,aRight])[0]
edge1=[a[aMinIndex], a[aLeft]]
edge2=[a[aMinIndex], a[aRight]]
edge1Index=0
edge2Index=0
edgeCounter=0
for edge in edgeMat:
if(edge[0]==edge1[0] and edge[1]==edge1[1]) or (edge[1]==edge1[0] and edge[0]==edge1[1]):
edge1Index=edgeCounter
if(edge[0]==edge2[0] and edge[1]==edge2[1]) or (edge[1]==edge2[0] and edge[0]==edge2[1]):
edge2Index=edgeCounter
edgeCounter+=1
if (edge1Index > edge2Index):
dof1=0.5*sp.array([xcent+linVertMatRound[a[aLeft],0],ycent+linVertMatRound[a[aLeft],1]])
quadCentroidLocCubic[counter,:]=dof1
counter+=1
dof2=0.5*sp.array([xcent+linVertMatRound[a[aRight],0],ycent+linVertMatRound[a[aRight],1]])
quadCentroidLocCubic[counter,:]=dof2
counter+=1
dof3=0.5*sp.array([xcent+linVertMatRound[a[aLast],0],ycent+linVertMatRound[a[aLast],1]])
quadCentroidLocCubic[counter,:]=dof3
counter+=1
else:
dof1=0.5*sp.array([xcent+linVertMatRound[a[aRight],0],ycent+linVertMatRound[a[aRight],1]])
quadCentroidLocCubic[counter,:]=dof1
counter+=1
dof2=0.5*sp.array([xcent+linVertMatRound[a[aLeft],0],ycent+linVertMatRound[a[aLeft],1]])
quadCentroidLocCubic[counter,:]=dof2
counter+=1
dof3=0.5*sp.array([xcent+linVertMatRound[a[aLast],0],ycent+linVertMatRound[a[aLast],1]])
quadCentroidLocCubic[counter,:]=dof3
counter+=1
truCentroidLoc=sp.round_(triCentroidLoc,5)
#3.)Populate nodes section
g=open(outputName+'Cub.mesh','w')
g.write('MFEM mesh v1.0\n'+'\n')
g.write('dimension\n'+'2\n'+'\n')
g.write('elements\n'+'{}\n'.format(linEleMat.shape[0]))
for n in range(linEleMat.shape[0]):
if linEleMat[n,1]==2:
g.write('{} {} {} {} {}\n'.format(linEleMat[n,0],linEleMat[n,1],linEleMat[n,2],linEleMat[n,3],linEleMat[n,4]))
else:
g.write('{} {} {} {} {} {}\n'.format(linEleMat[n,0],linEleMat[n,1],linEleMat[n,2],linEleMat[n,3],linEleMat[n,4],linEleMat[n,5]))
g.write('\n'+'boundary\n'+'{}\n'.format(linBoundMat.shape[0]))
for n in range(linBoundMat.shape[0]):
g.write('{} {} {} {}\n'.format(linBoundMat[n,0],linBoundMat[n,1],linBoundMat[n,2],linBoundMat[n,3]))
g.write('\n'+'vertices\n'+'{}\n'.format(linVertMat.shape[0]))
g.write('\n'+'nodes'+'\n'+'FiniteElementSpace'+'\n'+'FiniteElementCollection: H1_2D_P3'+'\n'+'VDim: 2'+'\n'+'Ordering: 1' +'\n\n')
for n in range(linVertMatRound.shape[0]):
g.write('{} {}\n'.format(linVertMatRound[n,0],linVertMatRound[n,1]))
for n in range(cubeDofMat.shape[0]):
g.write('{} {}\n'.format(cubeDofMat[n,0],cubeDofMat[n,1]))
for n in range(triCentroidLoc.shape[0]):
g.write('{} {}\n'.format(triCentroidLoc[n,0],triCentroidLoc[n,1]))
for n in range(quadCentroidLocCubic.shape[0]):
g.write('{} {}\n'.format(quadCentroidLocCubic[n,0],quadCentroidLocCubic[n,1]))
g.close()
if(visMesh==True):
gVis(glvis,outputName+'Cub.mesh')
#raw_input()
#'Reflecting' topology about one of its edges and append it to itself
upperPlaneEleMat = sp.zeros([2*linEleMat.shape[0],6])
for n in range(linEleMat.shape[0]):
upperPlaneEleMat[n,:]=linEleMat[n,:]
#Create ele_mat_holder.shape[0]x2 matrix for mapping
refEdge=boundMatTot(numEdges)[1]
q1NumNodes=linVertMat.shape[0]
mapping = sp.zeros([q1NumNodes])
counter=0
for n in range(q1NumNodes):
if (sp.any(refEdge == n)):
mapping[n]=n
else:
mapping[n]=counter+q1NumNodes
counter+=1
mapping=mapping.astype(int)
#Implement mapping
counter=0
for n in range(linEleMat.shape[0],2*linEleMat.shape[0]):
upperPlaneEleMat[n,0]=linEleMat[counter,0]
upperPlaneEleMat[n,1]=linEleMat[counter,1]
upperPlaneEleMat[n,2]=mapping[linEleMat[counter,2]]
upperPlaneEleMat[n,3]=mapping[linEleMat[counter,3]]
upperPlaneEleMat[n,4]=mapping[linEleMat[counter,4]]
upperPlaneEleMat[n,5]=mapping[linEleMat[counter,5]]
counter+=1
upperPlaneEleMat = upperPlaneEleMat.astype(int)
#Reflecting boundary matrix
origBound=boundMatTot(numEdges)[2]
upperPlaneBoundMat=sp.zeros([2*origBound.shape[0],4])
for n in range(origBound.shape[0]):
upperPlaneBoundMat[n,:]=origBound[n,:]
counter=0
newOrigBound=origBound.copy()
newOrigBound[:,2]=sp.flipud(origBound[:,3])
newOrigBound[:,3]=sp.flipud(origBound[:,2])
for n in range(newOrigBound.shape[0],upperPlaneBoundMat.shape[0]):
upperPlaneBoundMat[n,0]=newOrigBound[counter,0]
upperPlaneBoundMat[n,1]=newOrigBound[counter,1]
upperPlaneBoundMat[n,2]=mapping[newOrigBound[counter,2]]
upperPlaneBoundMat[n,3]=mapping[newOrigBound[counter,3]]
counter+=1
upperPlaneBoundMat=upperPlaneBoundMat.astype(int)
#Reflecting vertex matrix about the y-axis and appending it to itself
upperPlaneNumNodes=q1NumNodes+(q1NumNodes-refEdge.shape[0])
upperPlaneVertMat = sp.zeros([upperPlaneNumNodes,2])
for n in range(linVertMat.shape[0]):
upperPlaneVertMat[n,:]=linVertMat[n,:]
counter=0
for n in range(linVertMat.shape[0],upperPlaneNumNodes):
upperPlaneVertMat[n,0]=-1.0*linVertMat[sp.where(mapping==n)[0][0],0]
upperPlaneVertMat[n,1]=linVertMat[sp.where(mapping==n)[0][0],1]
counter+=1
upperPlaneEleMat=orient(upperPlaneEleMat)
g=open(outputName+'UpperPlaneLin.mesh','w')
g.write('MFEM mesh v1.0\n'+'\n')
g.write('dimension\n'+'2\n'+'\n')
g.write('elements\n'+'{}\n'.format(upperPlaneEleMat.shape[0]))
for n in range(upperPlaneEleMat.shape[0]):
if upperPlaneEleMat[n,1]==2:
g.write('{} {} {} {} {}\n'.format(upperPlaneEleMat[n,0],upperPlaneEleMat[n,1],upperPlaneEleMat[n,2],upperPlaneEleMat[n,3],upperPlaneEleMat[n,4]))
else:
g.write('{} {} {} {} {} {}\n'.format(upperPlaneEleMat[n,0],upperPlaneEleMat[n,1],upperPlaneEleMat[n,2],upperPlaneEleMat[n,3],upperPlaneEleMat[n,4],upperPlaneEleMat[n,5]))
g.write('\n'+'boundary\n'+'{}\n'.format(upperPlaneBoundMat.shape[0]))
for n in range(upperPlaneBoundMat.shape[0]):
g.write('{} {} {} {}\n'.format(upperPlaneBoundMat[n,0],upperPlaneBoundMat[n,1],upperPlaneBoundMat[n,2],upperPlaneBoundMat[n,3]))
g.write('\n'+'vertices\n'+'{}\n'.format(upperPlaneVertMat.shape[0])+'2\n')
for n in range(upperPlaneVertMat.shape[0]):
g.write('{} {}\n'.format(upperPlaneVertMat[n,0],upperPlaneVertMat[n,1]))
g.close()
if(visMesh==True):
gVis(glvis,outputName+'UpperPlaneLin.mesh')
#'Reflecting' topology about one of its edges and append it to itself
wholePlaneEleMat = sp.zeros([2*upperPlaneEleMat.shape[0],6])
for n in range(upperPlaneEleMat.shape[0]):
wholePlaneEleMat[n,:]=upperPlaneEleMat[n,:]
quad1Edge=boundMatTot(numEdges)[3]
newRefEdge=sp.zeros(2*quad1Edge.shape[0]-1)
for n in range(quad1Edge.shape[0]):
newRefEdge[n]=quad1Edge[n]
counter=0
for n in range(quad1Edge.shape[0],newRefEdge.shape[0]):
newRefEdge[n]=mapping[quad1Edge[counter]]
counter+=1
newRefEdge=sp.unique(newRefEdge)
newRefEdge=newRefEdge.astype(int)
newTotNumNodes=upperPlaneVertMat.shape[0]
newMapping=sp.zeros([newTotNumNodes])
counter=0
for n in range(newTotNumNodes):
if (sp.any(newRefEdge == n)):
newMapping[n]=n
else:
newMapping[n]=counter+newTotNumNodes
counter+=1
newMapping=newMapping.astype(int)
counter=0
for n in range(upperPlaneEleMat.shape[0],2*upperPlaneEleMat.shape[0]):
wholePlaneEleMat[n,0]=upperPlaneEleMat[counter,0]
wholePlaneEleMat[n,1]=upperPlaneEleMat[counter,1]
wholePlaneEleMat[n,2]=newMapping[upperPlaneEleMat[counter,2]]
wholePlaneEleMat[n,3]=newMapping[upperPlaneEleMat[counter,3]]
wholePlaneEleMat[n,4]=newMapping[upperPlaneEleMat[counter,4]]
wholePlaneEleMat[n,5]=newMapping[upperPlaneEleMat[counter,5]]
counter+=1
wholePlaneEleMat=wholePlaneEleMat.astype(int)
#Reflecting boundary matrix
newOrigBoundQuad1=boundMatTot(numEdges)[4]
newFirstBoundMatHolder=sp.zeros([2*newOrigBoundQuad1.shape[0],4])
for n in range(newOrigBoundQuad1.shape[0]):
newFirstBoundMatHolder[n,:]=newOrigBoundQuad1[n,:]
newNewOrigBoundQuad1=newOrigBoundQuad1.copy()
newNewOrigBoundQuad1[:,2]=sp.flipud(newOrigBoundQuad1[:,3])
newNewOrigBoundQuad1[:,3]=sp.flipud(newOrigBoundQuad1[:,2])
counter=0
for n in range(newOrigBoundQuad1.shape[0],newFirstBoundMatHolder.shape[0]):
newFirstBoundMatHolder[n,0]=newNewOrigBoundQuad1[counter,0]
newFirstBoundMatHolder[n,1]=newNewOrigBoundQuad1[counter,1]
newFirstBoundMatHolder[n,2]=mapping[newNewOrigBoundQuad1[counter,2]]
newFirstBoundMatHolder[n,3]=mapping[newNewOrigBoundQuad1[counter,3]]
counter+=1
upperQuadMat=newFirstBoundMatHolder.copy()
wholePlaneBoundMat=sp.zeros([2*upperQuadMat.shape[0],4])
for n in range(upperQuadMat.shape[0]):
wholePlaneBoundMat[n,:]=upperQuadMat[n,:]
counter=0
newNewOrigBound=upperQuadMat.copy()
newNewOrigBound[:,2]=sp.flipud(upperQuadMat[:,3])
newNewOrigBound[:,3]=sp.flipud(upperQuadMat[:,2])
newNewOrigBound=newNewOrigBound.astype(int)
for n in range(newNewOrigBound.shape[0],wholePlaneBoundMat.shape[0]):
wholePlaneBoundMat[n,0]=newNewOrigBound[counter,0]
wholePlaneBoundMat[n,1]=newNewOrigBound[counter,1]
wholePlaneBoundMat[n,2]=newMapping[newNewOrigBound[counter,2]]
wholePlaneBoundMat[n,3]=newMapping[newNewOrigBound[counter,3]]
counter+=1
wholePlaneBoundMat=wholePlaneBoundMat.astype(int)
wholePlaneNumNodes=newTotNumNodes+(newTotNumNodes-newRefEdge.shape[0])
wholePlaneVertMat = sp.zeros([wholePlaneNumNodes,2])
for n in range(upperPlaneVertMat.shape[0]):
wholePlaneVertMat[n,:]=upperPlaneVertMat[n,:]
counter=0
for n in range(upperPlaneVertMat.shape[0],wholePlaneNumNodes):
wholePlaneVertMat[n,0]=upperPlaneVertMat[sp.where(newMapping==n)[0][0],0]
wholePlaneVertMat[n,1]=-1.0*upperPlaneVertMat[sp.where(newMapping==n)[0][0],1]
counter+=1
g=open(outputName+'WholePlaneLin.mesh','w')
g.write('MFEM mesh v1.0\n'+'\n')
g.write('dimension\n'+'2\n'+'\n')
g.write('elements\n'+'{}\n'.format(wholePlaneEleMat.shape[0]))
for n in range(wholePlaneEleMat.shape[0]):
if wholePlaneEleMat[n,1]==2:
g.write('{} {} {} {} {}\n'.format(wholePlaneEleMat[n,0],wholePlaneEleMat[n,1],wholePlaneEleMat[n,2],wholePlaneEleMat[n,3],wholePlaneEleMat[n,4]))
else:
g.write('{} {} {} {} {} {}\n'.format(wholePlaneEleMat[n,0],wholePlaneEleMat[n,1],wholePlaneEleMat[n,2],wholePlaneEleMat[n,3],wholePlaneEleMat[n,4],wholePlaneEleMat[n,5]))
g.write('\n'+'boundary\n'+'{}\n'.format(wholePlaneBoundMat.shape[0]))
for n in range(wholePlaneBoundMat.shape[0]):
g.write('{} {} {} {}\n'.format(wholePlaneBoundMat[n,0],wholePlaneBoundMat[n,1],wholePlaneBoundMat[n,2],wholePlaneBoundMat[n,3]))
g.write('\n'+'vertices\n'+'{}\n'.format(wholePlaneVertMat.shape[0])+'2\n')
for n in range(wholePlaneVertMat.shape[0]):
g.write('{} {}\n'.format(wholePlaneVertMat[n,0],wholePlaneVertMat[n,1]))
g.close()
if(visMesh==True):
gVis(glvis,outputName+'WholePlaneLin.mesh')
#1.)Create Edge list from elements
wholePlaneEleMat=orient(wholePlaneEleMat)
triCounter=0;quadCounter=0;
for n in range(wholePlaneEleMat.shape[0]):
if wholePlaneEleMat[n,1]==2:
triCounter+=1
else:
quadCounter+=1
edgeMat=sp.zeros([3*triCounter+4*quadCounter,2])
counter=0
for n in range(wholePlaneEleMat.shape[0]):
if wholePlaneEleMat[n,1]==2:
edgeMat[counter,:]=[wholePlaneEleMat[n,2],wholePlaneEleMat[n,3]]
counter+=1
edgeMat[counter,:]=[wholePlaneEleMat[n,3],wholePlaneEleMat[n,4]]
counter+=1
edgeMat[counter,:]=[wholePlaneEleMat[n,4],wholePlaneEleMat[n,2]]
counter+=1
else:
edgeMat[counter,:]=[wholePlaneEleMat[n,2],wholePlaneEleMat[n,3]]
counter+=1
edgeMat[counter,:]=[wholePlaneEleMat[n,3],wholePlaneEleMat[n,4]]
counter+=1
edgeMat[counter,:]=[wholePlaneEleMat[n,4],wholePlaneEleMat[n,5]]
counter+=1
edgeMat[counter,:]=[wholePlaneEleMat[n,5],wholePlaneEleMat[n,2]]
counter+=1
#Remove duplicates
holder=[]
for n in range(edgeMat.shape[0]):
counter=0
for m in range(edgeMat.shape[0]):
if edgeMat[n,0]==edgeMat[m,0] and edgeMat[n,1]==edgeMat[m,1] and m!=n:
holder.append([n,m])
elif edgeMat[n,1]==edgeMat[m,0] and edgeMat[n,0]==edgeMat[m,1] and m!=n:
holder.append([n,m])
removeIndices=sp.zeros(len(holder))
for n in range(len(holder)):
if holder[n][0]>holder[n][1]:
removeIndices[n]=holder[n][0]
else:
removeIndices[n]=holder[n][1]
removeIndices=sp.unique(removeIndices).astype(int)
edgeMat=sp.delete(edgeMat,removeIndices,0)
edgeMat=edgeMat.astype(int)
edgeDofMat=sp.zeros([edgeMat.shape[0],2])
wholePlaneVertMatRound=sp.round_(wholePlaneVertMat,5)
counter=0
for n in edgeMat:
if wholePlaneVertMatRound[n[0],1] == wholePlaneVertMatRound[n[1],1]:
xmid=(wholePlaneVertMatRound[n[0],0]+wholePlaneVertMatRound[n[1],0])/2.0
ymid=wholePlaneVertMatRound[n[0],1]
edgeDofMat[counter,:]=[xmid,ymid]
elif wholePlaneVertMatRound[n[0],0] == wholePlaneVertMatRound[n[1],0]:
xmid=wholePlaneVertMatRound[n[0],0]
ymid=(wholePlaneVertMatRound[n[0],1]+wholePlaneVertMatRound[n[1],1])/2.0
edgeDofMat[counter,:]=[xmid,ymid]
else:
r0=sp.sqrt(wholePlaneVertMatRound[n[0],0]**2+wholePlaneVertMatRound[n[0],1]**2)
r1=sp.sqrt(wholePlaneVertMatRound[n[1],0]**2+wholePlaneVertMatRound[n[1],1]**2)
rmid = (r0+r1)/2.0 #should not be needed
xmidOld=(wholePlaneVertMatRound[n[0],0]+wholePlaneVertMatRound[n[1],0])/2.0
ymidOld=(wholePlaneVertMatRound[n[0],1]+wholePlaneVertMatRound[n[1],1])/2.0
midtheta=sp.arctan2(ymidOld,xmidOld)
xmid=rmid*sp.cos(midtheta)
ymid=rmid*sp.sin(midtheta)
edgeDofMat[counter,:]=[xmid,ymid]
counter+=1
edgeDofMat = sp.round_(edgeDofMat,5)
#2.)Create correct dof locations
#Determine midpoints of all quads:
quadCentroidLoc=sp.zeros([quadCounter,2])
counter=0
for n in range(wholePlaneEleMat.shape[0]):
if wholePlaneEleMat[n,1]==3:
quadCentroidLoc[counter,0]=(wholePlaneVertMatRound[wholePlaneEleMat[n,2],0]+wholePlaneVertMatRound[wholePlaneEleMat[n,3],0]+wholePlaneVertMatRound[wholePlaneEleMat[n,4],0]+wholePlaneVertMatRound[wholePlaneEleMat[n,5],0])/4.0
quadCentroidLoc[counter,1]=(wholePlaneVertMatRound[wholePlaneEleMat[n,2],1]+wholePlaneVertMatRound[wholePlaneEleMat[n,3],1]+wholePlaneVertMatRound[wholePlaneEleMat[n,4],1]+wholePlaneVertMatRound[wholePlaneEleMat[n,5],1])/4.0
counter+=1
quadCentroidLoc = sp.round_(quadCentroidLoc,5)
#3.)Populate nodes section
g=open(outputName+'WholePlaneQuad.mesh','w')
g.write('MFEM mesh v1.0\n'+'\n')
g.write('dimension\n'+'2\n'+'\n')
g.write('elements\n'+'{}\n'.format(wholePlaneEleMat.shape[0]))
for n in range(wholePlaneEleMat.shape[0]):
if wholePlaneEleMat[n,1]==2:
g.write('{} {} {} {} {}\n'.format(wholePlaneEleMat[n,0],wholePlaneEleMat[n,1],wholePlaneEleMat[n,2],wholePlaneEleMat[n,3],wholePlaneEleMat[n,4]))
else:
g.write('{} {} {} {} {} {}\n'.format(wholePlaneEleMat[n,0],wholePlaneEleMat[n,1],wholePlaneEleMat[n,2],wholePlaneEleMat[n,3],wholePlaneEleMat[n,4],wholePlaneEleMat[n,5]))
g.write('\n'+'boundary\n'+'{}\n'.format(wholePlaneBoundMat.shape[0]))
for n in range(wholePlaneBoundMat.shape[0]):
g.write('{} {} {} {}\n'.format(wholePlaneBoundMat[n,0],wholePlaneBoundMat[n,1],wholePlaneBoundMat[n,2],wholePlaneBoundMat[n,3]))
g.write('\n'+'vertices\n'+'{}\n'.format(wholePlaneVertMat.shape[0]))
g.write('\n'+'nodes'+'\n'+'FiniteElementSpace'+'\n'+'FiniteElementCollection: H1_2D_P2'+'\n'+'VDim: 2'+'\n'+'Ordering: 1' +'\n\n')
for n in range(wholePlaneVertMatRound.shape[0]):
g.write('{} {}\n'.format(wholePlaneVertMatRound[n,0],wholePlaneVertMatRound[n,1]))
for n in range(edgeDofMat.shape[0]):
g.write('{} {}\n'.format(edgeDofMat[n,0],edgeDofMat[n,1]))
for n in range(quadCentroidLoc.shape[0]):
g.write('{} {}\n'.format(quadCentroidLoc[n,0],quadCentroidLoc[n,1]))
g.close()
if(visMesh==True):
gVis(glvis,outputName+'WholePlaneQuad.mesh')
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,264 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
128
1 2 0 1 2
1 2 1 2 4
1 2 1 3 4
1 2 2 4 5
1 2 3 4 7
1 2 3 6 7
1 2 4 5 8
1 2 4 7 8
1 2 5 8 9
1 2 6 7 11
1 2 6 10 11
1 2 7 8 12
1 2 7 11 12
1 2 8 9 13
1 2 8 12 13
1 2 9 13 14
2 3 10 15 16 11
2 3 11 16 17 12
2 3 12 17 18 13
2 3 13 18 19 14
2 3 15 20 21 16
2 3 16 21 22 17
2 3 17 22 23 18
2 3 18 23 24 19
2 3 20 25 26 21
2 3 21 26 27 22
2 3 22 27 28 23
2 3 23 28 29 24
2 3 25 30 31 26
2 3 26 31 32 27
2 3 27 32 33 28
2 3 28 33 34 29
1 2 0 35 2
1 2 35 2 37
1 2 35 36 37
1 2 2 37 5
1 2 36 37 39
1 2 36 38 39
1 2 37 5 40
1 2 37 39 40
1 2 5 40 9
1 2 38 39 42
1 2 38 41 42
1 2 39 40 43
1 2 39 42 43
1 2 40 9 44
1 2 40 43 44
1 2 9 44 14
2 3 41 45 46 42
2 3 42 46 47 43
2 3 43 47 48 44
2 3 44 48 19 14
2 3 45 49 50 46
2 3 46 50 51 47
2 3 47 51 52 48
2 3 48 52 24 19
2 3 49 53 54 50
2 3 50 54 55 51
2 3 51 55 56 52
2 3 52 56 29 24
2 3 53 57 58 54
2 3 54 58 59 55
2 3 55 59 60 56
2 3 56 60 34 29
1 2 0 1 61
1 2 1 61 62
1 2 1 3 62
1 2 61 62 63
1 2 3 62 64
1 2 3 6 64
1 2 62 63 65
1 2 62 64 65
1 2 63 65 66
1 2 6 64 67
1 2 6 10 67
1 2 64 65 68
1 2 64 67 68
1 2 65 66 69
1 2 65 68 69
1 2 66 69 70
2 3 10 15 71 67
2 3 67 71 72 68
2 3 68 72 73 69
2 3 69 73 74 70
2 3 15 20 75 71
2 3 71 75 76 72
2 3 72 76 77 73
2 3 73 77 78 74
2 3 20 25 79 75
2 3 75 79 80 76
2 3 76 80 81 77
2 3 77 81 82 78
2 3 25 30 83 79
2 3 79 83 84 80
2 3 80 84 85 81
2 3 81 85 86 82
1 2 0 35 61
1 2 35 61 87
1 2 35 36 87
1 2 61 87 63
1 2 36 87 88
1 2 36 38 88
1 2 87 63 89
1 2 87 88 89
1 2 63 89 66
1 2 38 88 90
1 2 38 41 90
1 2 88 89 91
1 2 88 90 91
1 2 89 66 92
1 2 89 91 92
1 2 66 92 70
2 3 41 45 93 90
2 3 90 93 94 91
2 3 91 94 95 92
2 3 92 95 74 70
2 3 45 49 96 93
2 3 93 96 97 94
2 3 94 97 98 95
2 3 95 98 78 74
2 3 49 53 99 96
2 3 96 99 100 97
2 3 97 100 101 98
2 3 98 101 82 78
2 3 53 102 103 99
2 3 99 103 104 100
2 3 100 104 105 101
2 3 101 105 86 82
boundary
16
1 1 30 31
1 1 31 32
1 1 32 33
1 1 33 34
1 1 34 60
1 1 60 59
1 1 59 58
1 1 58 57
1 1 102 103
1 1 103 104
1 1 104 105
1 1 105 86
1 1 86 85
1 1 85 84
1 1 84 83
1 1 83 30
vertices
106
2
0.0 0.0
0.125 0.0
7.65404249467e-18 0.125
0.25 0.0
0.176776695297 0.176776695297
1.53080849893e-17 0.25
0.375 0.0
0.324759526419 0.1875
0.1875 0.324759526419
2.2962127484e-17 0.375
0.5 0.0
0.461939766256 0.191341716183
0.353553390593 0.353553390593
0.191341716183 0.461939766256
3.06161699787e-17 0.5
0.625 0.0
0.596454824692 0.268506287137
0.515165042945 0.515165042945
0.268506287137 0.596454824692
2.2962127484e-17 0.625
0.75 0.0
0.730969883128 0.345670858091
0.676776695297 0.676776695297
0.345670858091 0.730969883128
1.53080849893e-17 0.75
0.875 0.0
0.865484941564 0.422835429046
0.838388347648 0.838388347648
0.422835429046 0.865484941564
7.65404249467e-18 0.875
1.0 0.0
1.0 0.5
1.0 1.0
0.5 1.0
0.0 1.0
-0.125 0.0
-0.25 0.0
-0.176776695297 0.176776695297
-0.375 0.0
-0.324759526419 0.1875
-0.1875 0.324759526419
-0.5 0.0
-0.461939766256 0.191341716183
-0.353553390593 0.353553390593
-0.191341716183 0.461939766256
-0.625 0.0
-0.596454824692 0.268506287137
-0.515165042945 0.515165042945
-0.268506287137 0.596454824692
-0.75 0.0
-0.730969883128 0.345670858091
-0.676776695297 0.676776695297
-0.345670858091 0.730969883128
-0.875 0.0
-0.865484941564 0.422835429046
-0.838388347648 0.838388347648
-0.422835429046 0.865484941564
-1.0 0.0
-1.0 0.5
-1.0 1.0
-0.5 1.0
7.65404249467e-18 -0.125
0.176776695297 -0.176776695297
1.53080849893e-17 -0.25
0.324759526419 -0.1875
0.1875 -0.324759526419
2.2962127484e-17 -0.375
0.461939766256 -0.191341716183
0.353553390593 -0.353553390593
0.191341716183 -0.461939766256
3.06161699787e-17 -0.5
0.596454824692 -0.268506287137
0.515165042945 -0.515165042945
0.268506287137 -0.596454824692
2.2962127484e-17 -0.625
0.730969883128 -0.345670858091
0.676776695297 -0.676776695297
0.345670858091 -0.730969883128
1.53080849893e-17 -0.75
0.865484941564 -0.422835429046
0.838388347648 -0.838388347648
0.422835429046 -0.865484941564
7.65404249467e-18 -0.875
1.0 -0.5
1.0 -1.0
0.5 -1.0
0.0 -1.0
-0.176776695297 -0.176776695297
-0.324759526419 -0.1875
-0.1875 -0.324759526419
-0.461939766256 -0.191341716183
-0.353553390593 -0.353553390593
-0.191341716183 -0.461939766256
-0.596454824692 -0.268506287137
-0.515165042945 -0.515165042945
-0.268506287137 -0.596454824692
-0.730969883128 -0.345670858091
-0.676776695297 -0.676776695297
-0.345670858091 -0.730969883128
-0.865484941564 -0.422835429046
-0.838388347648 -0.838388347648
-0.422835429046 -0.865484941564
-1.0 -0.0
-1.0 -0.5
-1.0 -1.0
-0.5 -1.0
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,72 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
17
1 2 0 1 2
1 2 0 2 3
1 2 0 3 4
2 3 0 4 5 6
2 3 0 6 7 1
1 2 7 8 1
1 2 1 8 9
2 3 1 9 10 2
1 2 2 10 11
2 3 2 11 12 3
1 2 3 12 13
2 3 3 13 14 4
1 2 4 14 15
1 2 4 15 5
1 2 5 16 6
1 2 6 16 17
1 2 6 17 7
boundary
12
1 1 7 8
1 1 8 9
1 1 9 10
1 1 10 11
1 1 11 12
1 1 12 13
1 1 13 14
1 1 14 15
1 1 15 5
1 1 5 16
1 1 16 17
1 1 17 7
vertices
18
2
0 0
1 0
0.5 0.866025
-0.5 0.866025
-1 0
-1 -1
0 -1
1 -1
1.866025 -0.5
1.866025 0.5
1.366025 1.366025
0.5 1.866025
-0.5 1.866025
-1.366025 1.366025
-1.866025 0.5
-1.866025 -0.5
-0.5 -1.866025
0.5 -1.866025
@@ -1,362 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
154
2 3 0 1 2 3
2 3 1 5 6 2
2 3 5 8 9 6
2 3 8 11 12 9
2 3 11 14 15 12
2 3 14 17 18 15
2 3 17 20 21 18
2 3 20 23 24 21
2 3 23 26 27 24
2 3 26 29 30 27
2 3 29 32 33 30
2 3 32 35 36 33
2 3 35 38 39 36
2 3 38 41 42 39
2 3 41 44 45 42
2 3 44 47 48 45
2 3 47 50 51 48
2 3 50 53 54 51
2 3 53 56 57 54
2 3 56 59 60 57
2 3 59 62 63 60
2 3 62 65 66 63
2 3 65 68 69 66
2 3 68 71 72 69
2 3 71 74 75 72
2 3 74 77 78 75
1 2 2 3 4
1 2 6 2 7
1 2 9 6 10
1 2 12 9 13
1 2 15 12 16
1 2 18 15 19
1 2 21 18 22
1 2 24 21 25
1 2 27 24 28
1 2 30 27 31
1 2 33 30 34
1 2 36 33 37
1 2 39 36 40
1 2 42 39 43
1 2 45 42 46
1 2 48 45 49
1 2 51 48 52
1 2 54 51 55
1 2 57 54 58
1 2 60 57 61
1 2 63 60 64
1 2 66 63 67
1 2 69 66 70
1 2 72 69 73
1 2 75 72 76
1 2 78 75 79
1 2 2 4 7
1 2 6 7 10
1 2 9 10 13
1 2 12 13 16
1 2 15 16 19
1 2 18 19 22
1 2 21 22 25
1 2 24 25 28
1 2 27 28 31
1 2 30 31 34
1 2 33 34 37
1 2 36 37 40
1 2 39 40 43
1 2 42 43 46
1 2 45 46 49
1 2 48 49 52
1 2 51 52 55
1 2 54 55 58
1 2 57 58 61
1 2 60 61 64
1 2 63 64 67
1 2 66 67 70
1 2 69 70 73
1 2 72 73 76
1 2 75 76 79
2 3 80 81 82 83
2 3 81 84 85 82
2 3 84 86 87 85
2 3 86 88 89 87
2 3 88 90 91 89
2 3 90 92 93 91
2 3 92 94 95 93
2 3 94 96 97 95
2 3 96 98 99 97
2 3 98 100 101 99
2 3 100 102 103 101
2 3 102 104 105 103
2 3 104 106 107 105
2 3 106 108 109 107
2 3 108 110 111 109
2 3 110 112 113 111
2 3 112 114 115 113
2 3 114 116 117 115
2 3 116 118 119 117
2 3 118 120 121 119
2 3 120 122 123 121
2 3 122 124 125 123
2 3 124 126 127 125
2 3 126 128 129 127
2 3 128 130 131 129
2 3 130 132 133 131
1 2 82 83 4
1 2 85 82 7
1 2 87 85 10
1 2 89 87 13
1 2 91 89 16
1 2 93 91 19
1 2 95 93 22
1 2 97 95 25
1 2 99 97 28
1 2 101 99 31
1 2 103 101 34
1 2 105 103 37
1 2 107 105 40
1 2 109 107 43
1 2 111 109 46
1 2 113 111 49
1 2 115 113 52
1 2 117 115 55
1 2 119 117 58
1 2 121 119 61
1 2 123 121 64
1 2 125 123 67
1 2 127 125 70
1 2 129 127 73
1 2 131 129 76
1 2 133 131 79
1 2 82 4 7
1 2 85 7 10
1 2 87 10 13
1 2 89 13 16
1 2 91 16 19
1 2 93 19 22
1 2 95 22 25
1 2 97 25 28
1 2 99 28 31
1 2 101 31 34
1 2 103 34 37
1 2 105 37 40
1 2 107 40 43
1 2 109 43 46
1 2 111 46 49
1 2 113 49 52
1 2 115 52 55
1 2 117 55 58
1 2 119 58 61
1 2 121 61 64
1 2 123 64 67
1 2 125 67 70
1 2 127 70 73
1 2 129 73 76
1 2 131 76 79
boundary
60
1 1 0 1
1 1 1 5
1 1 5 8
1 1 8 11
1 1 11 14
1 1 14 17
1 1 17 20
1 1 20 23
1 1 23 26
1 1 26 29
1 1 29 32
1 1 32 35
1 1 35 38
1 1 38 41
1 1 41 44
1 1 44 47
1 1 47 50
1 1 50 53
1 1 53 56
1 1 56 59
1 1 59 62
1 1 62 65
1 1 65 68
1 1 68 71
1 1 71 74
1 1 74 77
1 1 77 78
1 1 78 79
1 1 79 133
1 1 133 132
1 1 132 130
1 1 130 128
1 1 128 126
1 1 126 124
1 1 124 122
1 1 122 120
1 1 120 118
1 1 118 116
1 1 116 114
1 1 114 112
1 1 112 110
1 1 110 108
1 1 108 106
1 1 106 104
1 1 104 102
1 1 102 100
1 1 100 98
1 1 98 96
1 1 96 94
1 1 94 92
1 1 92 90
1 1 90 88
1 1 88 86
1 1 86 84
1 1 84 81
1 1 81 80
1 1 80 83
1 1 83 4
1 1 4 3
1 1 3 0
vertices
134
2
0.0 0.0
1.0 0.0
1.0 1.0
0.0 1.0
0.5 1.86602540378
2.0 0.0
2.0 1.0
1.5 1.86602540378
3.0 0.0
3.0 1.0
2.5 1.86602540378
4.0 0.0
4.0 1.0
3.5 1.86602540378
5.0 0.0
5.0 1.0
4.5 1.86602540378
6.0 0.0
6.0 1.0
5.5 1.86602540378
7.0 0.0
7.0 1.0
6.5 1.86602540378
8.0 0.0
8.0 1.0
7.5 1.86602540378
9.0 0.0
9.0 1.0
8.5 1.86602540378
10.0 0.0
10.0 1.0
9.5 1.86602540378
11.0 0.0
11.0 1.0
10.5 1.86602540378
12.0 0.0
12.0 1.0
11.5 1.86602540378
13.0 0.0
13.0 1.0
12.5 1.86602540378
14.0 0.0
14.0 1.0
13.5 1.86602540378
15.0 0.0
15.0 1.0
14.5 1.86602540378
16.0 0.0
16.0 1.0
15.5 1.86602540378
17.0 0.0
17.0 1.0
16.5 1.86602540378
18.0 0.0
18.0 1.0
17.5 1.86602540378
19.0 0.0
19.0 1.0
18.5 1.86602540378
20.0 0.0
20.0 1.0
19.5 1.86602540378
21.0 0.0
21.0 1.0
20.5 1.86602540378
22.0 0.0
22.0 1.0
21.5 1.86602540378
23.0 0.0
23.0 1.0
22.5 1.86602540378
24.0 0.0
24.0 1.0
23.5 1.86602540378
25.0 0.0
25.0 1.0
24.5 1.86602540378
26.0 0.0
26.0 1.0
25.5 1.86602540378
0.0 3.73205080757
1.0 3.73205080757
1.0 2.73205080757
0.0 2.73205080757
2.0 3.73205080757
2.0 2.73205080757
3.0 3.73205080757
3.0 2.73205080757
4.0 3.73205080757
4.0 2.73205080757
5.0 3.73205080757
5.0 2.73205080757
6.0 3.73205080757
6.0 2.73205080757
7.0 3.73205080757
7.0 2.73205080757
8.0 3.73205080757
8.0 2.73205080757
9.0 3.73205080757
9.0 2.73205080757
10.0 3.73205080757
10.0 2.73205080757
11.0 3.73205080757
11.0 2.73205080757
12.0 3.73205080757
12.0 2.73205080757
13.0 3.73205080757
13.0 2.73205080757
14.0 3.73205080757
14.0 2.73205080757
15.0 3.73205080757
15.0 2.73205080757
16.0 3.73205080757
16.0 2.73205080757
17.0 3.73205080757
17.0 2.73205080757
18.0 3.73205080757
18.0 2.73205080757
19.0 3.73205080757
19.0 2.73205080757
20.0 3.73205080757
20.0 2.73205080757
21.0 3.73205080757
21.0 2.73205080757
22.0 3.73205080757
22.0 2.73205080757
23.0 3.73205080757
23.0 2.73205080757
24.0 3.73205080757
24.0 2.73205080757
25.0 3.73205080757
25.0 2.73205080757
26.0 3.73205080757
26.0 2.73205080757
@@ -1,66 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
17
2 3 0 1 2 3
2 3 1 5 6 2
2 3 5 8 9 6
2 3 8 11 12 9
2 3 11 14 15 12
2 3 14 17 18 15
1 2 2 3 4
1 2 6 2 7
1 2 9 6 10
1 2 12 9 13
1 2 15 12 16
1 2 18 15 19
1 2 2 4 7
1 2 6 7 10
1 2 9 10 13
1 2 12 13 16
1 2 15 16 19
boundary
15
1 1 0 1
1 1 1 5
1 1 5 8
1 1 8 11
1 1 11 14
1 1 14 17
1 1 17 18
1 1 18 19
1 1 19 16
1 1 16 13
1 1 13 10
1 1 10 7
1 1 7 4
1 1 4 3
1 1 3 0
vertices
20
2
0.0 0.0
1.0 0.0
1.0 1.0
0.0 1.0
0.5 1.86602540378
2.0 0.0
2.0 1.0
1.5 1.86602540378
3.0 0.0
3.0 1.0
2.5 1.86602540378
4.0 0.0
4.0 1.0
3.5 1.86602540378
5.0 0.0
5.0 1.0
4.5 1.86602540378
6.0 0.0
6.0 1.0
5.5 1.86602540378
-45
View File
@@ -1,45 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
5
1 2 0 1 2
1 2 0 2 3
1 2 0 3 4
2 3 0 4 5 6
2 3 0 6 7 1
boundary
7
1 1 1 2
1 1 2 3
1 1 3 4
1 1 4 5
1 1 5 6
1 1 6 7
1 1 7 1
vertices
8
2
0 0
1 0
0.5 0.866025
-0.5 0.866025
-1 0
-1 -1
0 -1
1 -1
-45
View File
@@ -1,45 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
5
1 2 0 1 2
1 2 0 2 3
1 2 0 5 6
2 3 0 3 4 5
2 3 0 6 7 1
boundary
7
1 1 1 2
1 1 2 3
1 1 3 4
1 1 4 5
1 1 5 6
1 1 6 7
1 1 7 1
vertices
8
2
0 0
0.866025 0.5
0 1
-0.866025 0.5
-1.366025 -0.36602500
-0.5 -0.866025
0.5 -0.866025
1.366025 -0.36602500
File diff suppressed because it is too large Load Diff
@@ -1,57 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
16
1 2 0 1 2
1 2 1 2 4
1 2 1 3 4
1 2 2 4 5
1 2 3 4 7
1 2 3 6 7
1 2 4 5 8
1 2 4 7 8
1 2 5 8 9
1 2 6 7 11
1 2 6 10 11
1 2 7 8 12
1 2 7 11 12
1 2 8 9 13
1 2 8 12 13
1 2 9 13 14
boundary
12
1 1 0 1
1 1 1 3
1 1 3 6
1 1 6 10
1 1 10 11
1 1 11 12
1 1 12 13
1 1 13 14
1 1 14 9
1 1 9 5
1 1 5 2
1 1 2 0
vertices
15
2
0.0 0.0
0.25 0.0
1.53080849893e-17 0.25
0.5 0.0
0.353553390593 0.353553390593
3.06161699787e-17 0.5
0.75 0.0
0.649519052838 0.375
0.375 0.649519052838
4.5924254968e-17 0.75
1.0 0.0
0.923879532511 0.382683432365
0.707106781187 0.707106781187
0.382683432365 0.923879532511
6.12323399574e-17 1.0
-147
View File
@@ -1,147 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
64
1 2 0 1 2
1 2 1 2 4
1 2 1 3 4
1 2 2 4 5
1 2 3 4 7
1 2 3 6 7
1 2 4 5 8
1 2 4 7 8
1 2 5 8 9
1 2 6 7 11
1 2 6 10 11
1 2 7 8 12
1 2 7 11 12
1 2 8 9 13
1 2 8 12 13
1 2 9 13 14
1 2 10 11 16
1 2 10 15 16
1 2 11 12 17
1 2 11 16 17
1 2 12 13 18
1 2 12 17 18
1 2 13 14 19
1 2 13 18 19
1 2 14 19 20
1 2 15 16 22
1 2 15 21 22
1 2 16 17 23
1 2 16 22 23
1 2 17 18 24
1 2 17 23 24
1 2 18 19 25
1 2 18 24 25
1 2 19 20 26
1 2 19 25 26
1 2 20 26 27
1 2 21 22 29
1 2 21 28 29
1 2 22 23 30
1 2 22 29 30
1 2 23 24 31
1 2 23 30 31
1 2 24 25 32
1 2 24 31 32
1 2 25 26 33
1 2 25 32 33
1 2 26 27 34
1 2 26 33 34
1 2 27 34 35
1 2 28 29 37
1 2 28 36 37
1 2 29 30 38
1 2 29 37 38
1 2 30 31 39
1 2 30 38 39
1 2 31 32 40
1 2 31 39 40
1 2 32 33 41
1 2 32 40 41
1 2 33 34 42
1 2 33 41 42
1 2 34 35 43
1 2 34 42 43
1 2 35 43 44
boundary
24
1 1 0 1
1 1 1 3
1 1 3 6
1 1 6 10
1 1 10 15
1 1 15 21
1 1 21 28
1 1 28 36
1 1 36 37
1 1 37 38
1 1 38 39
1 1 39 40
1 1 40 41
1 1 41 42
1 1 42 43
1 1 43 44
1 1 44 35
1 1 35 27
1 1 27 20
1 1 20 14
1 1 14 9
1 1 9 5
1 1 5 2
1 1 2 0
vertices
45
2
0.0 0.0
0.125 0.0
7.65404249467e-18 0.125
0.25 0.0
0.176776695297 0.176776695297
1.53080849893e-17 0.25
0.375 0.0
0.324759526419 0.1875
0.1875 0.324759526419
2.2962127484e-17 0.375
0.5 0.0
0.461939766256 0.191341716183
0.353553390593 0.353553390593
0.191341716183 0.461939766256
3.06161699787e-17 0.5
0.625 0.0
0.594410322684 0.193135621484
0.505635621484 0.367365782683
0.367365782683 0.505635621484
0.193135621484 0.594410322684
3.82702124734e-17 0.625
0.75 0.0
0.724444369717 0.194114283827
0.649519052838 0.375
0.53033008589 0.53033008589
0.375 0.649519052838
0.194114283827 0.724444369717
4.5924254968e-17 0.75
0.875 0.0
0.853061923159 0.194705817212
0.788347759415 0.379648271728
0.68410254716 0.545553576626
0.545553576626 0.68410254716
0.379648271728 0.788347759415
0.194705817212 0.853061923159
5.35782974627e-17 0.875
1.0 0.0
0.980785280403 0.195090322016
0.923879532511 0.382683432365
0.831469612303 0.55557023302
0.707106781187 0.707106781187
0.55557023302 0.831469612303
0.382683432365 0.923879532511
0.195090322016 0.980785280403
6.12323399574e-17 1.0
@@ -1,73 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
8
1 2 0 1 2
1 2 1 4 2
1 2 1 3 4
1 2 4 5 2
2 3 3 6 7 4
2 3 8 5 4 7
2 3 6 9 10 7
2 3 11 8 7 10
boundary
10
1 1 0 1
1 1 1 3
1 1 3 6
1 1 6 9
1 1 9 10
1 1 10 11
1 1 11 8
1 1 8 5
1 1 5 2
1 1 2 0
vertices
12
nodes
FiniteElementSpace
FiniteElementCollection: Quadratic
VDim: 2
Ordering: 1
0.0 0.0
0.5 0.0
0.0 0.5
1.0 0.0
0.70711 0.70711
0.0 1.0
1.5 0.0
1.35355 1.35355
0.0 1.5
2.0 0.0
2.0 2.0
0.0 2.0
0.25 0.0
0.35355 0.35355
0.0 0.25
0.64714 0.37909
0.37909 0.64714
0.75 0.0
0.92388 0.38269
0.38269 0.92388
0.0 0.75
1.25 0.0
1.54238 0.73161
1.03033 1.03033
0.0 1.25
0.73161 1.54238
1.75 0.0
2.0 1.0
1.67678 1.67678
0.0 1.75
1.0 2.0
1.14017 0.51516
0.51516 1.14017
1.71339 0.83839
0.83839 1.71339
@@ -1,567 +0,0 @@
MFEM mesh v1.0
dimension
2
elements
128
1 2 0 1 2
1 2 1 4 2
1 2 1 3 4
1 2 2 4 5
1 2 3 7 4
1 2 3 6 7
1 2 4 8 5
1 2 4 7 8
1 2 5 8 9
1 2 6 11 7
1 2 6 10 11
1 2 7 12 8
1 2 7 11 12
1 2 8 13 9
1 2 8 12 13
1 2 9 13 14
2 3 10 15 16 11
2 3 11 16 17 12
2 3 12 17 18 13
2 3 13 18 19 14
2 3 15 20 21 16
2 3 16 21 22 17
2 3 17 22 23 18
2 3 18 23 24 19
2 3 20 25 26 21
2 3 21 26 27 22
2 3 22 27 28 23
2 3 23 28 29 24
2 3 25 30 31 26
2 3 26 31 32 27
2 3 27 32 33 28
2 3 28 33 34 29
1 2 0 2 35
1 2 35 2 37
1 2 35 37 36
1 2 2 5 37
1 2 36 37 39
1 2 36 39 38
1 2 37 5 40
1 2 37 40 39
1 2 5 9 40
1 2 38 39 42
1 2 38 42 41
1 2 39 40 43
1 2 39 43 42
1 2 40 9 44
1 2 40 44 43
1 2 9 14 44
2 3 41 42 46 45
2 3 42 43 47 46
2 3 43 44 48 47
2 3 44 14 19 48
2 3 45 46 50 49
2 3 46 47 51 50
2 3 47 48 52 51
2 3 48 19 24 52
2 3 49 50 54 53
2 3 50 51 55 54
2 3 51 52 56 55
2 3 52 24 29 56
2 3 53 54 58 57
2 3 54 55 59 58
2 3 55 56 60 59
2 3 56 29 34 60
1 2 0 61 1
1 2 1 61 62
1 2 1 62 3
1 2 61 63 62
1 2 3 62 64
1 2 3 64 6
1 2 62 63 65
1 2 62 65 64
1 2 63 66 65
1 2 6 64 67
1 2 6 67 10
1 2 64 65 68
1 2 64 68 67
1 2 65 66 69
1 2 65 69 68
1 2 66 70 69
2 3 10 67 71 15
2 3 67 68 72 71
2 3 68 69 73 72
2 3 69 70 74 73
2 3 15 71 75 20
2 3 71 72 76 75
2 3 72 73 77 76
2 3 73 74 78 77
2 3 20 75 79 25
2 3 75 76 80 79
2 3 76 77 81 80
2 3 77 78 82 81
2 3 25 79 83 30
2 3 79 80 84 83
2 3 80 81 85 84
2 3 81 82 86 85
1 2 0 35 61
1 2 35 87 61
1 2 35 36 87
1 2 61 87 63
1 2 36 88 87
1 2 36 38 88
1 2 87 89 63
1 2 87 88 89
1 2 63 89 66
1 2 38 90 88
1 2 38 41 90
1 2 88 91 89
1 2 88 90 91
1 2 89 92 66
1 2 89 91 92
1 2 66 92 70
2 3 41 45 93 90
2 3 90 93 94 91
2 3 91 94 95 92
2 3 92 95 74 70
2 3 45 49 96 93
2 3 93 96 97 94
2 3 94 97 98 95
2 3 95 98 78 74
2 3 49 53 99 96
2 3 96 99 100 97
2 3 97 100 101 98
2 3 98 101 82 78
2 3 53 102 103 99
2 3 99 103 104 100
2 3 100 104 105 101
2 3 101 105 86 82
boundary
16
1 1 30 31
1 1 31 32
1 1 32 33
1 1 33 34
1 1 34 60
1 1 60 59
1 1 59 58
1 1 58 57
1 1 102 103
1 1 103 104
1 1 104 105
1 1 105 86
1 1 86 85
1 1 85 84
1 1 84 83
1 1 83 30
vertices
106
nodes
FiniteElementSpace
FiniteElementCollection: H1_2D_P2
VDim: 2
Ordering: 1
0.0 0.0
0.25 0.0
0.0 0.25
0.5 0.0
0.35355 0.35355
0.0 0.5
0.75 0.0
0.64952 0.375
0.375 0.64952
0.0 0.75
1.0 0.0
0.92388 0.38268
0.70711 0.70711
0.38268 0.92388
0.0 1.0
1.25 0.0
1.19291 0.53701
1.03033 1.03033
0.53701 1.19291
0.0 1.25
1.5 0.0
1.46194 0.69134
1.35355 1.35355
0.69134 1.46194
0.0 1.5
1.75 0.0
1.73097 0.84567
1.67678 1.67678
0.84567 1.73097
0.0 1.75
2.0 0.0
2.0 1.0
2.0 2.0
1.0 2.0
0.0 2.0
-0.25 0.0
-0.5 0.0
-0.35355 0.35355
-0.75 0.0
-0.64952 0.375
-0.375 0.64952
-1.0 0.0
-0.92388 0.38268
-0.70711 0.70711
-0.38268 0.92388
-1.25 0.0
-1.19291 0.53701
-1.03033 1.03033
-0.53701 1.19291
-1.5 0.0
-1.46194 0.69134
-1.35355 1.35355
-0.69134 1.46194
-1.75 0.0
-1.73097 0.84567
-1.67678 1.67678
-0.84567 1.73097
-2.0 0.0
-2.0 1.0
-2.0 2.0
-1.0 2.0
0.0 -0.25
0.35355 -0.35355
0.0 -0.5
0.64952 -0.375
0.375 -0.64952
0.0 -0.75
0.92388 -0.38268
0.70711 -0.70711
0.38268 -0.92388
0.0 -1.0
1.19291 -0.53701
1.03033 -1.03033
0.53701 -1.19291
0.0 -1.25
1.46194 -0.69134
1.35355 -1.35355
0.69134 -1.46194
0.0 -1.5
1.73097 -0.84567
1.67678 -1.67678
0.84567 -1.73097
0.0 -1.75
2.0 -1.0
2.0 -2.0
1.0 -2.0
0.0 -2.0
-0.35355 -0.35355
-0.64952 -0.375
-0.375 -0.64952
-0.92388 -0.38268
-0.70711 -0.70711
-0.38268 -0.92388
-1.19291 -0.53701
-1.03033 -1.03033
-0.53701 -1.19291
-1.46194 -0.69134
-1.35355 -1.35355
-0.69134 -1.46194
-1.73097 -0.84567
-1.67678 -1.67678
-0.84567 -1.73097
-2.0 -0.0
-2.0 -1.0
-2.0 -2.0
-1.0 -2.0
0.125 0.0
0.17678 0.17678
0.0 0.125
0.32357 0.18954
0.18954 0.32357
0.375 0.0
0.46194 0.19134
0.19134 0.46194
0.0 0.375
0.59418 0.19384
0.50569 0.36729
0.625 0.0
0.72444 0.19411
0.36729 0.50569
0.19384 0.59418
0.53033 0.53033
0.19411 0.72444
0.0 0.625
0.85299 0.19501
0.78835 0.37964
0.875 0.0
0.98079 0.19509
0.68405 0.54563
0.54563 0.68405
0.83147 0.55557
0.37964 0.78835
0.19501 0.85299
0.55557 0.83147
0.19509 0.98079
0.0 0.875
1.125 0.0
1.24928 0.27462
1.05851 0.4599
1.13007 0.79668
0.86872 0.86872
0.79668 1.13007
0.4599 1.05851
0.27462 1.24928
0.0 1.125
1.375 0.0
1.51779 0.35426
1.32748 0.6142
1.42864 1.03762
1.19194 1.19194
1.03762 1.42864
0.6142 1.32748
0.35426 1.51779
0.0 1.375
1.625 0.0
1.78629 0.43396
1.59649 0.76852
1.72721 1.2785
1.51516 1.51516
1.2785 1.72721
0.76852 1.59649
0.43396 1.78629
0.0 1.625
1.875 0.0
2.0 0.5
1.8655 0.92284
2.0 1.5
1.83839 1.83839
1.5 2.0
0.92284 1.8655
0.5 2.0
0.0 1.875
-0.17678 0.17678
-0.125 0.0
-0.18954 0.32357
-0.32357 0.18954
-0.46194 0.19134
-0.375 0.0
-0.19134 0.46194
-0.50569 0.36729
-0.59418 0.19384
-0.72444 0.19411
-0.625 0.0
-0.19384 0.59418
-0.36729 0.50569
-0.53033 0.53033
-0.19411 0.72444
-0.78835 0.37964
-0.85299 0.19501
-0.98079 0.19509
-0.875 0.0
-0.54563 0.68405
-0.68405 0.54563
-0.83147 0.55557
-0.19501 0.85299
-0.37964 0.78835
-0.55557 0.83147
-0.19509 0.98079
-1.05851 0.4599
-1.24928 0.27462
-1.125 0.0
-0.86872 0.86872
-1.13007 0.79668
-0.4599 1.05851
-0.79668 1.13007
-0.27462 1.24928
-1.32748 0.6142
-1.51779 0.35426
-1.375 0.0
-1.19194 1.19194
-1.42864 1.03762
-0.6142 1.32748
-1.03762 1.42864
-0.35426 1.51779
-1.59649 0.76852
-1.78629 0.43396
-1.625 0.0
-1.51516 1.51516
-1.72721 1.2785
-0.76852 1.59649
-1.2785 1.72721
-0.43396 1.78629
-1.8655 0.92284
-2.0 0.5
-1.875 0.0
-1.83839 1.83839
-2.0 1.5
-0.92284 1.8655
-1.5 2.0
-0.5 2.0
0.0 -0.125
0.17678 -0.17678
0.18954 -0.32357
0.32357 -0.18954
0.46194 -0.19134
0.0 -0.375
0.19134 -0.46194
0.50569 -0.36729
0.59418 -0.19384
0.72444 -0.19411
0.19384 -0.59418
0.36729 -0.50569
0.53033 -0.53033
0.0 -0.625
0.19411 -0.72444
0.78835 -0.37964
0.85299 -0.19501
0.98079 -0.19509
0.54563 -0.68405
0.68405 -0.54563
0.83147 -0.55557
0.19501 -0.85299
0.37964 -0.78835
0.55557 -0.83147
0.0 -0.875
0.19509 -0.98079
1.05851 -0.4599
1.24928 -0.27462
0.86872 -0.86872
1.13007 -0.79668
0.4599 -1.05851
0.79668 -1.13007
0.0 -1.125
0.27462 -1.24928
1.32748 -0.6142
1.51779 -0.35426
1.19194 -1.19194
1.42864 -1.03762
0.6142 -1.32748
1.03762 -1.42864
0.0 -1.375
0.35426 -1.51779
1.59649 -0.76852
1.78629 -0.43396
1.51516 -1.51516
1.72721 -1.2785
0.76852 -1.59649
1.2785 -1.72721
0.0 -1.625
0.43396 -1.78629
1.8655 -0.92284
2.0 -0.5
1.83839 -1.83839
2.0 -1.5
0.92284 -1.8655
1.5 -2.0
0.0 -1.875
0.5 -2.0
-0.17678 -0.17678
-0.32357 -0.18954
-0.18954 -0.32357
-0.46194 -0.19134
-0.19134 -0.46194
-0.59418 -0.19384
-0.50569 -0.36729
-0.72444 -0.19411
-0.36729 -0.50569
-0.19384 -0.59418
-0.53033 -0.53033
-0.19411 -0.72444
-0.85299 -0.19501
-0.78835 -0.37964
-0.98079 -0.19509
-0.68405 -0.54563
-0.54563 -0.68405
-0.83147 -0.55557
-0.37964 -0.78835
-0.19501 -0.85299
-0.55557 -0.83147
-0.19509 -0.98079
-1.24928 -0.27462
-1.05851 -0.4599
-1.13007 -0.79668
-0.86872 -0.86872
-0.79668 -1.13007
-0.4599 -1.05851
-0.27462 -1.24928
-1.51779 -0.35426
-1.32748 -0.6142
-1.42864 -1.03762
-1.19194 -1.19194
-1.03762 -1.42864
-0.6142 -1.32748
-0.35426 -1.51779
-1.78629 -0.43396
-1.59649 -0.76852
-1.72721 -1.2785
-1.51516 -1.51516
-1.2785 -1.72721
-0.76852 -1.59649
-0.43396 -1.78629
-1.875 0.0
-2.0 -0.5
-1.8655 -0.92284
-2.0 -1.5
-1.83839 -1.83839
-1.5 -2.0
-0.92284 -1.8655
-0.5 -2.0
1.0917 0.22992
0.96356 0.66428
0.66428 0.96356
0.22992 1.0917
1.35121 0.30709
1.25968 0.90306
0.90306 1.25968
0.30709 1.35121
1.61073 0.38425
1.55581 1.14184
1.14184 1.55581
0.38425 1.61073
1.87024 0.46142
1.85194 1.38061
1.38061 1.85194
0.46142 1.87024
-1.0917 0.22992
-0.96356 0.66428
-0.66428 0.96356
-0.22992 1.0917
-1.35121 0.30709
-1.25968 0.90306
-0.90306 1.25968
-0.30709 1.35121
-1.61073 0.38425
-1.55581 1.14184
-1.14184 1.55581
-0.38425 1.61073
-1.87024 0.46142
-1.85194 1.38061
-1.38061 1.85194
-0.46142 1.87024
1.0917 -0.22992
0.96356 -0.66428
0.66428 -0.96356
0.22992 -1.0917
1.35121 -0.30709
1.25968 -0.90306
0.90306 -1.25968
0.30709 -1.35121
1.61073 -0.38425
1.55581 -1.14184
1.14184 -1.55581
0.38425 -1.61073
1.87024 -0.46142
1.85194 -1.38061
1.38061 -1.85194
0.46142 -1.87024
-1.0917 -0.22992
-0.96356 -0.66428
-0.66428 -0.96356
-0.22992 -1.0917
-1.35121 -0.30709
-1.25968 -0.90306
-0.90306 -1.25968
-0.30709 -1.35121
-1.61073 -0.38425
-1.55581 -1.14184
-1.14184 -1.55581
-0.38425 -1.61073
-1.87024 -0.46142
-1.85194 -1.38061
-1.38061 -1.85194
-0.46142 -1.87024
+1 -2
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = "MFEM"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = v3.4.1
PROJECT_NUMBER = v3.3.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -767,7 +767,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/fem \
@MFEM_SOURCE_DIR@/examples \
@MFEM_SOURCE_DIR@/examples/petsc \
@MFEM_SOURCE_DIR@/examples/pumi \
@MFEM_SOURCE_DIR@/examples/sundials \
@MFEM_SOURCE_DIR@/miniapps/common \
@MFEM_SOURCE_DIR@/miniapps/meshing \
+3 -12
View File
@@ -36,8 +36,8 @@ namespace mfem {
* - HypreSolver and other \link hypre.hpp hypre classes\endlink
*
* <H3>Example codes</H3>
* - <a class="el" href="examples_2ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem
* - <a class="el" href="examples_2ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem
* - <a class="el" href="ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="ex2_8cpp_source.html">Example 2</a>: vector FEM for linear elasticity
* - <a class="el" href="ex2p_8cpp_source.html">Example 2p</a>: parallel vector FEM for linear elasticity
* - <a class="el" href="ex3_8cpp_source.html">Example 3</a>: Nedelec H(curl) FEM for the definite Maxwell problem
@@ -56,7 +56,7 @@ namespace mfem {
* - <a class="el" href="ex9p_8cpp_source.html">Example 9p</a>: parallel Discontinuous Galerkin (DG) time-dependent advection
* - <a class="el" href="ex10_8cpp_source.html">Example 10</a>: time-dependent implicit nonlinear elasticity
* - <a class="el" href="ex10p_8cpp_source.html">Example 10p</a>: parallel time-dependent implicit nonlinear elasticity
* - <a class="el" href="examples_2ex11p_8cpp_source.html">Example 11p</a>: parallel Laplace eigensolver
* - <a class="el" href="ex11p_8cpp_source.html">Example 11p</a>: parallel Laplace eigensolver
* - <a class="el" href="ex12p_8cpp_source.html">Example 12p</a>: parallel linear elasticity eigensolver
* - <a class="el" href="ex13p_8cpp_source.html">Example 13p</a>: parallel Maxwell eigensolver
* - <a class="el" href="ex14_8cpp_source.html">Example 14</a>: Discontinuous Galerkin (DG) for the Laplace problem
@@ -96,15 +96,6 @@ namespace mfem {
* <a class="el" href="petsc_2ex10p_8cpp_source.html">10p</a>
* demonstrating the use of MFEM's \link petsc.hpp PETSc classes\endlink
*
* <H4>PUMI Examples</H4>
* - Variants of Examples
* <a class="el" href="examples_2pumi_2ex1_8cpp_source.html">1</a>,
* <a class="el" href="examples_2pumi_2ex1p_8cpp_source.html">1p</a>,
* <a class="el" href="pumi_2ex2_8cpp_source.html">2</a>,
* and
* <a class="el" href="pumi_2ex6p_8cpp_source.html">6p</a>
* demonstrating the use of MFEM's \link pumi.hpp PUMI classes\endlink
*
* <H3>Miniapps</H3>
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

+3 -8
View File
@@ -25,7 +25,6 @@ list(APPEND ALL_EXE_SRCS
ex16.cpp
ex17.cpp
ex18.cpp
ex19.cpp
)
if (MFEM_USE_MPI)
@@ -48,7 +47,6 @@ if (MFEM_USE_MPI)
ex16p.cpp
ex17p.cpp
ex18p.cpp
ex19p.cpp
)
endif()
@@ -63,6 +61,8 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(FIND ${TEST_NAME} "p" is_parallel_test)
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
@@ -70,7 +70,7 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
list(APPEND THIS_TEST_OPTIONS "-e" "1")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
if (is_parallel_test EQUAL -1)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
@@ -91,8 +91,3 @@ endif()
if (MFEM_USE_PETSC)
add_subdirectory(petsc)
endif()
# Include the examples/pumi directory if PUMI is enabled
if (MFEM_USE_PUMI)
add_subdirectory(pumi)
endif()
+77 -160
View File
File diff suppressed because one or more lines are too long
+46 -16
View File
@@ -48,7 +48,9 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool static_cond = false;
bool visualization = 1;
bool visualization = true;
bool use_partial_assembly = false;
bool use_smoother = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -56,8 +58,12 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&use_partial_assembly, "-pa", "--partial-assembly",
"-no-pa", "--no-partial-assembly", "Enable partial assembly.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&use_smoother, "-pc", "--peconditioner", "-no-pc",
"--no-preconditioner", "Use a Gauss-Seidel preconditioner.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -80,8 +86,8 @@ int main(int argc, char *argv[])
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels = 0;
//(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
int ref_levels =
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
@@ -138,33 +144,56 @@ int main(int argc, char *argv[])
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
Vector B, X;
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
BilinearFormOperator A_pa(new PAIntegratorMap);
SparseMatrix A_sp;
if (!use_partial_assembly)
{
a->AssembleForm(A_sp);
}
else
{
// Can add a custom FESpaceIntegrator in this way:
// a->AddIntegrator(new PADiffusionIntegrator(new DiffusionIntegrator(one)));
a->AssembleForm(A_pa);
}
Operator *A;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
cout << "Size of linear system: " << A->Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 200, 1e-12, 0.0);
if (use_smoother && !use_partial_assembly)
{
GSSmoother M(A_sp);
PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 200, 1e-12, 0.0);
}
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
if (!use_partial_assembly)
{
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A_sp);
umf_solver.Mult(B, X);
}
#endif
// 11. Recover the solution as a finite element grid function.
@@ -190,6 +219,7 @@ int main(int argc, char *argv[])
}
// 14. Free the used memory.
delete A;
delete a;
delete b;
delete fespace;
-1
View File
@@ -222,7 +222,6 @@ int main(int argc, char *argv[])
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
-1
View File
@@ -244,7 +244,6 @@ int main(int argc, char *argv[])
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
-1
View File
@@ -110,7 +110,6 @@ int main(int argc, char *argv[])
{
pmesh->UniformRefinement();
}
pmesh->ReorientTetMesh();
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
+95 -19
View File
@@ -35,6 +35,10 @@
using namespace std;
using namespace mfem;
bool partial_assembly_mass;
bool partial_assembly_diff;
bool preconditioner;
/** After spatial discretization, the conduction model can be written as:
*
* du/dt = M^{-1}(-Ku)
@@ -54,6 +58,8 @@ protected:
BilinearForm *M;
BilinearForm *K;
Operator *Koper, *Moper, *Toper;
BilinearFormOperator Mpaop, Kpaop;
SparseMatrix Mmat, Kmat;
SparseMatrix *T; // T = M + dt K
double current_dt;
@@ -83,11 +89,39 @@ public:
virtual ~ConductionOperator();
};
class TimeDerivativeOperator : public Operator
{
Operator *Moper;
Operator *Koper;
mutable Vector Kdu;
const double dt;
public:
TimeDerivativeOperator(Operator *_Moper, const double _dt, Operator *_Koper)
: Operator(_Moper->Height(), _Moper->Width()),
Moper(_Moper),
Koper(_Koper),
Kdu(Height()),
dt(_dt) { }
virtual void Mult(const Vector &x, Vector &y) const
{
Moper->Mult(x, y);
Koper->Mult(x, Kdu);
Kdu *= dt;
y += Kdu;
}
};
double InitialTemperature(const Vector &x);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
partial_assembly_mass = false;
partial_assembly_diff = false;
preconditioner = true;
const char *mesh_file = "../data/star.mesh";
int ref_levels = 2;
int order = 2;
@@ -121,6 +155,12 @@ int main(int argc, char *argv[])
"Alpha coefficient.");
args.AddOption(&kappa, "-k", "--kappa",
"Kappa coefficient offset.");
args.AddOption(&partial_assembly_mass, "-pam", "--partial-assembly-mass",
"-no-pam", "--no-partial-assembly-mass", "Enable partial assembly for the mass.");
args.AddOption(&partial_assembly_diff, "-pad", "--partial-assembly-diff",
"-no-pad", "--no-partial-assembly-diff", "Enable partial assembly for the diffusion.");
args.AddOption(&preconditioner, "-pc", "--peconditioner", "-no-pc",
"--no-preconditioner", "Use a Gauss-Seidel preconditioner.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -157,7 +197,6 @@ int main(int argc, char *argv[])
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
@@ -292,22 +331,35 @@ int main(int argc, char *argv[])
ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
double kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
Toper(NULL), Mpaop(new PAIntegratorMap), Kpaop(new PAIntegratorMap),
T(NULL), current_dt(0.0), z(height)
{
const double rel_tol = 1e-8;
M = new BilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble();
M->FormSystemMatrix(ess_tdof_list, Mmat);
M->AddDomainIntegrator(new MassIntegrator);
if (!partial_assembly_mass)
{
M->AssembleForm(Mmat);
M->FormSystemOperator(ess_tdof_list, Moper);
M_solver.SetOperator(static_cast<SparseMatrix&>(*Moper));
}
else
{
M->AssembleForm(Mpaop);
M->FormSystemOperator(ess_tdof_list, Moper);
M_solver.SetOperator(*Moper);
}
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(30);
M_solver.SetPrintLevel(0);
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(Mmat);
if (preconditioner && !partial_assembly_mass)
{
M_solver.SetPreconditioner(M_prec);
}
alpha = al;
kappa = kap;
@@ -317,7 +369,12 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
if (preconditioner &&
!partial_assembly_diff &&
!partial_assembly_mass)
{
T_solver.SetPreconditioner(T_prec);
}
SetParameters(u);
}
@@ -327,7 +384,7 @@ void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
// Compute:
// du_dt = M^{-1}*-K(u)
// for du_dt
Kmat.Mult(u, z);
Koper->Mult(u, z);
z.Neg(); // z = -z
M_solver.Mult(z, du_dt);
}
@@ -338,14 +395,22 @@ void ConductionOperator::ImplicitSolve(const double dt,
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
if (!T)
if (!T && !Toper)
{
T = Add(1.0, Mmat, dt, Kmat);
current_dt = dt;
T_solver.SetOperator(*T);
if (!partial_assembly_diff && !partial_assembly_mass)
{
T = Add(1.0, Mmat, dt, Kmat);
T_solver.SetOperator(*T);
}
else
{
Toper = new TimeDerivativeOperator(Moper, dt, Koper);
T_solver.SetOperator(*Toper);
}
}
MFEM_VERIFY(dt == current_dt, ""); // SDIRK methods use the same dt
Kmat.Mult(u, z);
Koper->Mult(u, z);
z.Neg();
T_solver.Mult(z, du_dt);
}
@@ -359,21 +424,32 @@ void ConductionOperator::SetParameters(const Vector &u)
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
}
delete K;
K = new BilinearForm(&fespace);
GridFunctionCoefficient u_coeff(&u_alpha_gf);
delete K;
K = new BilinearForm(&fespace);
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
K->Assemble();
K->FormSystemMatrix(ess_tdof_list, Kmat);
if (!partial_assembly_diff)
{
K->AssembleForm(Kmat);
K->FormSystemOperator(ess_tdof_list, Koper);
}
else
{
K->AssembleForm(Kpaop);
K->FormSystemOperator(ess_tdof_list, Koper);
}
// re-compute on the next ImplicitSolve
delete T;
T = NULL; // re-compute T on the next ImplicitSolve
delete Toper;
Toper = NULL;
T = NULL;
}
ConductionOperator::~ConductionOperator()
{
delete T;
delete Toper;
delete M;
delete K;
}
-1
View File
@@ -173,7 +173,6 @@ int main(int argc, char *argv[])
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
+1 -1
View File
@@ -50,7 +50,7 @@ using namespace mfem;
//
// and K^-1 is an approximation of the inverse of the displacement part of the
// Jacobian and S^-1 is an approximation of the inverse of the Schur
// complement S = B K^-1 B^T. The Schur complement is approximated using
// complement S = B K^-1 B^T. The Schur complement is approximiated using
// a mass matrix of the pressure variables.
class JacobianPreconditioner : public Solver
{
+1 -1
View File
@@ -50,7 +50,7 @@ using namespace mfem;
//
// and K^-1 is an approximation of the inverse of the displacement part of the
// Jacobian and S^-1 is an approximation of the inverse of the Schur
// complement S = B K^-1 B^T. The Schur complement is approximated using
// complement S = B K^-1 B^T. The Schur complement is approximiated using
// a mass matrix of the pressure variables.
class JacobianPreconditioner : public Solver
{
+48 -12
View File
@@ -54,7 +54,9 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool static_cond = false;
bool visualization = 1;
bool visualization = true;
bool use_partial_assembly = false;
bool use_amg = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -62,8 +64,12 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&use_partial_assembly, "-pa", "--partial-assembly",
"-no-pa", "--no-partial-assembly", "Enable partial assembly.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&use_amg, "-pc", "--peconditioner", "-no-pc",
"--no-preconditioner", "Use an algebraic multigrid preconditioner.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -173,30 +179,59 @@ int main(int argc, char *argv[])
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// Use the global map instead
BilinearFormOperator A_pa(new PAIntegratorMap);
HypreParMatrix A_hpm;
Vector B, X;
if (static_cond) { a->EnableStaticCondensation(); }
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
if (!use_partial_assembly)
{
a->AssembleForm(A_hpm);
}
else
{
a->AssembleForm(A_pa);
}
HypreParMatrix A;
Vector B, X;
Operator *A;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
cout << "Size of linear system: " << A->Height() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreSolver *amg = new HypreBoomerAMG(A);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
Solver *pcg = NULL;
HypreSolver *amg = NULL;
if (!use_partial_assembly)
{
HyprePCG *hypre_pcg = new HyprePCG(A_hpm);
pcg = hypre_pcg;
hypre_pcg->SetTol(1e-12);
hypre_pcg->SetMaxIter(200);
hypre_pcg->SetPrintLevel(2);
if (use_amg)
{
amg = new HypreBoomerAMG(A_hpm);
hypre_pcg->SetPreconditioner(*amg);
}
}
else
{
CGSolver *mfem_pcg = new CGSolver(MPI_COMM_WORLD);
pcg = mfem_pcg;
mfem_pcg->SetRelTol(1e-12);
mfem_pcg->SetMaxIter(200);
mfem_pcg->SetPrintLevel(1);
mfem_pcg->SetOperator(*A);
}
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
@@ -231,6 +266,7 @@ int main(int argc, char *argv[])
}
// 16. Free the used memory.
delete A;
delete pcg;
delete amg;
delete a;
+55 -6
View File
@@ -78,6 +78,7 @@ public:
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
problem = 0;
const char *mesh_file = "../data/periodic-hexagon.mesh";
@@ -178,8 +179,20 @@ int main(int argc, char *argv[])
FunctionCoefficient inflow(inflow_function);
FunctionCoefficient u0(u0_function);
tic_toc.Clear();
tic_toc.Start();
BilinearForm m(&fes);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
m.Finalize();
tic_toc.Stop();
double mass_init_time = tic_toc.RealTime();
cout << " Mass initialization time: " << mass_init_time << "s." << endl;
tic_toc.Clear();
tic_toc.Start();
BilinearForm k(&fes);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k.AddInteriorFaceIntegrator(
@@ -187,15 +200,20 @@ int main(int argc, char *argv[])
k.AddBdrFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
LinearForm b(&fes);
b.AddBdrFaceIntegrator(
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
m.Assemble();
m.Finalize();
int skip_zeros = 0;
k.Assemble(skip_zeros);
k.Finalize(skip_zeros);
tic_toc.Stop();
double adv_init_time = tic_toc.RealTime();
cout << " Advection initialization time: " << adv_init_time << "s." << endl;
tic_toc.Clear();
tic_toc.Start();
LinearForm b(&fes);
b.AddBdrFaceIntegrator(
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
b.Assemble();
// 7. Define the initial conditions, save the corresponding grid function to
@@ -213,6 +231,10 @@ int main(int argc, char *argv[])
u.Save(osol);
}
tic_toc.Stop();
double total_init_time = mass_init_time + adv_init_time + tic_toc.RealTime();
cout << " Initialization time: " << total_init_time << "s." << endl;
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
DataCollection *dc = NULL;
@@ -270,6 +292,9 @@ int main(int argc, char *argv[])
adv.SetTime(t);
ode_solver->Init(adv);
tic_toc.Clear();
tic_toc.Start();
bool done = false;
for (int ti = 0; !done; )
{
@@ -297,6 +322,9 @@ int main(int argc, char *argv[])
}
}
tic_toc.Stop();
cout << " Computation time: " << tic_toc.RealTime() << "s." << endl;
// 9. Save the final solution. This output can be viewed later using GLVis:
// "glvis -m ex9.mesh -g ex9-final.gf".
{
@@ -317,7 +345,7 @@ int main(int argc, char *argv[])
FE_Evolution::FE_Evolution(SparseMatrix &_M, SparseMatrix &_K, const Vector &_b)
: TimeDependentOperator(_M.Size()), M(_M), K(_K), b(_b), z(_M.Size())
{
M_solver.SetPreconditioner(M_prec);
//M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(M);
M_solver.iterative_mode = false;
@@ -329,10 +357,31 @@ FE_Evolution::FE_Evolution(SparseMatrix &_M, SparseMatrix &_K, const Vector &_b)
void FE_Evolution::Mult(const Vector &x, Vector &y) const
{
/*y = 0.;
Vector xx(x);
int size = xx.Size();
int n = size;
int order = 1;
int dofs = (order+1)*(order+1);
for (int i = 0; i < n; ++i)
{
cout << "cacahuete " << i << endl;
xx = 0.;
xx(i) = 1000.;
// y = M^{-1} (K x + b)
K.Mult(xx, z);
for (int j = 0; j < z.Size(); ++j)
{
z(j) = abs(z(j)) < 1e-12 ? 0 : z(j);
}
z.Print(std::cout,dofs);
y += z;
}*/
// y = M^{-1} (K x + b)
K.Mult(x, z);
z += b;
M_solver.Mult(z, y);
// K.Mult(x, y);
}
+584
View File
@@ -0,0 +1,584 @@
// MFEM Example 9
//
// Compile with: make ex9
//
// Sample runs:
// ex9 -m ../data/periodic-segment.mesh -p 0 -r 2 -dt 0.005
// ex9 -m ../data/periodic-square.mesh -p 0 -r 2 -dt 0.01 -tf 10
// ex9 -m ../data/periodic-hexagon.mesh -p 0 -r 2 -dt 0.01 -tf 10
// ex9 -m ../data/periodic-square.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/periodic-hexagon.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.002 -tf 9
// ex9 -m ../data/star-q3.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/disc-nurbs.mesh -p 1 -r 3 -dt 0.005 -tf 9
// ex9 -m ../data/disc-nurbs.mesh -p 2 -r 3 -dt 0.005 -tf 9
// ex9 -m ../data/periodic-square.mesh -p 3 -r 4 -dt 0.0025 -tf 9 -vs 20
// ex9 -m ../data/periodic-cube.mesh -p 0 -r 2 -o 2 -dt 0.02 -tf 8
//
// Description: This example code solves the time-dependent advection equation
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
// u0(x)=u(0,x) is a given initial condition.
//
// The example demonstrates the use of Discontinuous Galerkin (DG)
// bilinear forms in MFEM (face integrators), the use of explicit
// ODE time integrators, the definition of periodic boundary
// conditions through periodic meshes, as well as the use of GLVis
// for persistent visualization of a time-evolving solution. The
// saving of time-dependent data files for external visualization
// with VisIt (visit.llnl.gov) is also illustrated.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <algorithm>
#include "../fem/dgpabilininteg.hpp"
#include "../fem/dgfacefunctions.hpp"
#include "../fem/partialassemblykernel.hpp"
using namespace std;
using namespace mfem;
// Choice for the problem setup. The fluid velocity, initial condition and
// inflow boundary condition are chosen based on this parameter.
int problem;
// Velocity coefficient
void velocity_function(const Vector &x, Vector &v);
// Initial condition
double u0_function(const Vector &x);
// Inflow boundary condition
double inflow_function(const Vector &x);
// Mesh bounding box
Vector bb_min, bb_max;
/** A time-dependent operator for the right-hand side of the ODE. The DG weak
form of du/dt = -v.grad(u) is M du/dt = K u + b, where M and K are the mass
and advection matrices, and b describes the flow on the boundary. This can
be written as a general ODE, du/dt = M^{-1} (K u + b), and this class is
used to evaluate the right-hand side. */
class FE_Evolution : public TimeDependentOperator
{
private:
// BilinearForm &M;
Operator &M;
Operator &K;
const Vector &b;
CGSolver M_solver;
DSmoother M_prec;
mutable Vector z;
public:
// FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b);
FE_Evolution(Operator &_M, Operator &_K, const Vector &_b);
virtual void Mult(const Vector &x, Vector &y) const;
virtual ~FE_Evolution() { }
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
problem = 0;
const char *mesh_file = "../data/periodic-hexagon.mesh";
int ref_levels = 2;
int order = 3;
int ode_solver_type = 4;
double t_final = 10.0;
double dt = 0.01;
bool visualization = true;
bool visit = false;
bool binary = false;
int vis_steps = 5;
int precision = 8;
cout.precision(precision);
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&problem, "-p", "--problem",
"Problem setup to use. See options in velocity_function().");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
"--no-visit-datafiles",
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
"--ascii-datafiles",
"Use binary (Sidre) or ascii format for VisIt data files.");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle geometrically
// periodic meshes in this code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
// command-line parameter. If the mesh is of NURBS type, we convert it to
// a (piecewise-polynomial) high-order mesh.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh->UniformRefinement();
}
if (mesh->NURBSext)
{
mesh->SetCurvature(max(order, 1));
}
if (!mesh->GetNodes())
{
mesh->SetCurvature(1);
}
mesh->GetBoundingBox(bb_min, bb_max, max(order, 1));
// 5. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
DG_FECollection fec(order, dim);
//H1_FECollection fec(order, dim);
FiniteElementSpace fes(mesh, &fec);
cout << "Number of unknowns: " << fes.GetVSize() << endl;
// 6. Set up and assemble the bilinear and linear forms corresponding to the
// DG discretization. The DGTraceIntegrator involves integrals over mesh
// interior faces.
VectorFunctionCoefficient velocity(dim, velocity_function);
FunctionCoefficient inflow(inflow_function);
FunctionCoefficient u0(u0_function);
//Creating a partial assembly Kernel
//Maybe not the right place to initialize tensor size.
int ir_order = 2*order+1;
tic_toc.Clear();
tic_toc.Start();
//Initialization of the Mass operator
// BilinearFormOperator m(&fes);
// m.AddDomainIntegrator(new PAMassIntegrator(&fes,ir_order));
// m.AddDomainIntegrator(new EigenPAMassIntegrator<2>(&fes,ir_order));
// m.AddDomainIntegrator(new EigenPAMassIntegrator<2,EigenDomainPAK>(&fes,ir_order));
//BilinearForm m(&fes);
//m.AddIntegrator(new PADomainInt<MassEquation>(&fes,ir_order,MassEquation::ArgsEmpty{}));
// m.AddDomainIntegrator(new MassIntegrator());
// m.AddIntegrator(new PADomainInt<MassEquation,CGSolverDG>(&fes,ir_order,MassEquation::ArgsEmpty{}));
// m.AddIntegrator(new PADomainInt<MassEquation>(&fes,ir_order));
PADomainInt<MassEquation> mass(&fes,ir_order,MassEquation::ArgsEmpty{});
// DiagSolverDG m(fes,ir_order,mass);
// PACGSolver<PADomainInt<MassEquation>> m(&fes,mass);
DiagSolverDG prec(fes,ir_order,mass);
// PAPrecCGSolver<PADomainInt<MassEquation>,DiagSolverDG> m(&fes,mass,prec);
// CGSolverDG<PADomainInt<MassEquation>> m(fes,ir_order,mass);
PrecCGSolverDG<PADomainInt<MassEquation>,DiagSolverDG> m(fes,ir_order,mass,prec);
Operator* mo = &m;
Array<int> ess_tdof_list;
// SparseMatrix msp;
// BilinearFormOperator mbf;
// Operator *mo;
// m.AssembleForm(msp);
// m.AssembleForm(mbf);
// m.FormSystemOperator(ess_tdof_list, mo);
tic_toc.Stop();
double mass_init_time = tic_toc.RealTime();
cout << " Mass initialization time: " << mass_init_time << "s." << endl;
tic_toc.Clear();
tic_toc.Start();
//Initialization of the Stiffness operator
BilinearForm k(&fes);
//k.AddDomainIntegrator(new EigenPAConvectionIntegrator<2>(&fes,ir_order,velocity, -1.0));
// k.AddDomainIntegrator(new PAConvectionIntegrator<DummyDomainPAK>(&fes,ir_order,velocity, -1.0));
typename DGConvectionEquation::Args argsEq(velocity,-1.0,-0.5);
k.AddIntegrator(new PADomainInt<DGConvectionEquation>(&fes,ir_order,argsEq));
// k.AddIntegrator(new PADomainInt<DGConvectionEquation>(&fes,ir_order,velocity,-1.0));
// k.AddDomainIntegrator(
// new PADGConvectionFaceIntegrator<DummyFacePAK>(&fes,ir_order,velocity, 1.0, -0.5));
// k.AddDomainIntegrator(
// new PADGConvectionFaceIntegrator2<FacePAK>(&fes,ir_order,velocity, 1.0, -0.5));
k.AddIntegrator(new PAFaceInt<DGConvectionEquation>(&fes,ir_order,argsEq));
// k.AddIntegrator(new PAFaceInt<DGConvectionEquation>(&fes,ir_order,velocity, 1.0, -0.5));
BilinearFormOperator kbf;
Operator *ko;
k.AssembleForm(kbf);
k.FormSystemOperator(ess_tdof_list, ko);
tic_toc.Stop();
double adv_init_time = tic_toc.RealTime();
cout << " Advection initialization time: " << adv_init_time << "s." << endl;
tic_toc.Clear();
tic_toc.Start();
//No need to do PA
LinearForm b(&fes);
b.AddBdrFaceIntegrator(
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
b.Assemble();
tic_toc.Stop();
double total_init_time = mass_init_time + adv_init_time + tic_toc.RealTime();
cout << " Initialization time: " << total_init_time << "s." << endl;
// 7. Define the initial conditions, save the corresponding grid function to
// a file and (optionally) save data in the VisIt format and initialize
// GLVis visualization.
GridFunction u(&fes);
u.ProjectCoefficient(u0);
{
ofstream omesh("ex9.mesh");
omesh.precision(precision);
mesh->Print(omesh);
ofstream osol("ex9-init.gf");
osol.precision(precision);
u.Save(osol);
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9", mesh);
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
#endif
}
else
{
dc = new VisItDataCollection("Example9", mesh);
dc->SetPrecision(precision);
}
dc->RegisterField("solution", &u);
dc->SetCycle(0);
dc->SetTime(0.0);
dc->Save();
}
socketstream sout;
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
sout.open(vishost, visport);
if (!sout)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
visualization = false;
cout << "GLVis visualization disabled.\n";
}
else
{
sout.precision(precision);
sout << "solution\n" << *mesh << u;
sout << "pause\n";
sout << flush;
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
// 8. Define the time-dependent evolution operator describing the ODE
// right-hand side, and perform time-integration (looping over the time
// iterations, ti, with a time-step dt).
FE_Evolution adv(*mo, *ko, b);
// FE_Evolution adv(m, k, b);
double t = 0.0;
adv.SetTime(t);
ode_solver->Init(adv);
tic_toc.Clear();
tic_toc.Start();
bool done = false;
for (int ti = 0; !done; )
{
double dt_real = min(dt, t_final - t);
ode_solver->Step(u, t, dt_real);
ti++;
//done = true;
done = (t >= t_final - 1e-8*dt);
if (done || ti % vis_steps == 0)
{
cout << "time step: " << ti << ", time: " << t << endl;
if (visualization)
{
sout << "solution\n" << *mesh << u << flush;
// sout << "screenshot\n" << "ex9-" << ti << ".png" << flush;
}
if (visit)
{
dc->SetCycle(ti);
dc->SetTime(t);
dc->Save();
}
}
}
tic_toc.Stop();
cout << " Computation time: " << tic_toc.RealTime() << "s." << endl;
// 9. Save the final solution. This output can be viewed later using GLVis:
// "glvis -m ex9.mesh -g ex9-final.gf".
{
ofstream osol("ex9-final.gf");
osol.precision(precision);
u.Save(osol);
}
// 10. Free the used memory.
delete ode_solver;
delete dc;
//delete mo;
//delete ko;
return 0;
}
// Implementation of class FE_Evolution
// FE_Evolution::FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b)
// : TimeDependentOperator(_M.Size(), 0.0), M(_M), K(_K), b(_b), z(_M.Size())
// {
// //TODO have to take into account the block diagonal structure of M
// //M_solver.SetPreconditioner(M_prec);
// M_solver.SetOperator(M);
// M_solver.iterative_mode = true;
// M_solver.SetRelTol(1e-9);
// M_solver.SetAbsTol(0.0);
// M_solver.SetMaxIter(100);
// M_solver.SetPrintLevel(0);
// }
FE_Evolution::FE_Evolution(Operator &_M, Operator &_K, const Vector &_b)
: TimeDependentOperator(_M.Height(), 0.0), M(_M), K(_K), b(_b), z(_M.Height())
{
//TODO have to take into account the block diagonal structure of M
// M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(M);
M_solver.iterative_mode = true;
M_solver.SetRelTol(1e-9);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(100);
M_solver.SetPrintLevel(0);
}
void FE_Evolution::Mult(const Vector &x, Vector &y) const
{
// y = 0.;
// Vector xx(x);
// int size = xx.Size();
// int n = size;
// int order = 1;
// int dofs = (order+1)*(order+1);
// for (int i = 0; i < n; ++i)
// {
// cout << "cacahuete " << i << endl;
// xx = 0.;
// xx(i) = 1000.;
// // y = M^{-1} (K x + b)
// K.Mult(xx, z);
// for (int j = 0; j < z.Size(); ++j)
// {
// z(j) = abs(z(j)) < 1e-12 ? 0 : z(j);
// }
// z.Print(std::cout,dofs);
// y += z;
// }
K.Mult(x, z);
z += b;
// M_solver.Mult(z, y);
M.Mult(z,y);
// K.Mult(x, y);
}
// Velocity coefficient
void velocity_function(const Vector &x, Vector &v)
{
int dim = x.Size();
// map to the reference [-1,1] domain
Vector X(dim);
for (int i = 0; i < dim; i++)
{
double center = (bb_min[i] + bb_max[i]) * 0.5;
X(i) = 2 * (x(i) - center) / (bb_max[i] - bb_min[i]);
}
switch (problem)
{
case 4:
case 0:
{
// Translations in 1D, 2D, and 3D
switch (dim)
{
case 1: v(0) = 1.0; break;
case 2: v(0) = sqrt(2./3.); v(1) = sqrt(1./3.); break;
// case 2: v(0) = 1+abs(X(0)); v(1) = 1+abs(X(0)); break;
case 3: v(0) = sqrt(3./6.); v(1) = sqrt(2./6.); v(2) = sqrt(1./6.);
break;
}
break;
}
case 1:
case 2:
{
// Clockwise rotation in 2D around the origin
const double w = M_PI/2;
switch (dim)
{
case 1: v(0) = 1.0; break;
case 2: v(0) = w*X(1); v(1) = -w*X(0); break;
case 3: v(0) = w*X(1); v(1) = -w*X(0); v(2) = 0.0; break;
}
break;
}
case 3:
{
// Clockwise twisting rotation in 2D around the origin
const double w = M_PI/2;
double d = max((X(0)+1.)*(1.-X(0)),0.) * max((X(1)+1.)*(1.-X(1)),0.);
d = d*d;
switch (dim)
{
case 1: v(0) = 1.0; break;
case 2: v(0) = d*w*X(1); v(1) = -d*w*X(0); break;
case 3: v(0) = d*w*X(1); v(1) = -d*w*X(0); v(2) = 0.0; break;
}
break;
}
}
}
// Initial condition
double u0_function(const Vector &x)
{
int dim = x.Size();
// map to the reference [-1,1] domain
Vector X(dim);
for (int i = 0; i < dim; i++)
{
double center = (bb_min[i] + bb_max[i]) * 0.5;
X(i) = 2 * (x(i) - center) / (bb_max[i] - bb_min[i]);
}
switch (problem)
{
case 0:
case 1:
{
switch (dim)
{
case 1:
return exp(-40.*pow(X(0)-0.5,2));
case 2:
case 3:
{
double rx = 0.45, ry = 0.25, cx = 0., cy = -0.2, w = 10.;
// double rx = 0.05, ry = 0.05, cx = -0., cy = -0.5, w = 10.;
if (dim == 3)
{
const double s = (1. + 0.25*cos(2*M_PI*X(2)));
rx *= s;
ry *= s;
}
return ( erfc(w*(X(0)-cx-rx))*erfc(-w*(X(0)-cx+rx)) *
erfc(w*(X(1)-cy-ry))*erfc(-w*(X(1)-cy+ry)) )/16;
}
}
}
case 2:
{
double x_ = X(0), y_ = X(1), rho, phi;
rho = hypot(x_, y_);
phi = atan2(y_, x_);
return pow(sin(M_PI*rho),2)*sin(3*phi);
}
case 3:
{
const double f = M_PI;
return sin(f*X(0))*sin(f*X(1));
}
case 4:
{
return exp( -40*( X(0)*X(0) + X(1)*X(1) + X(2)*X(2) ) );
}
}
return 0.0;
}
// Inflow boundary condition (zero for the problems considered in this example)
double inflow_function(const Vector &x)
{
switch (problem)
{
case 0:
case 1:
case 2:
case 3: return 0.0;
}
return 0.0;
}
+2 -5
View File
@@ -21,8 +21,8 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 ex17\
ex18 ex19
SEQ_EXAMPLES = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex9PA ex10 ex14 ex15 ex16\
ex17 ex18 ex19
PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p ex12p\
ex13p ex14p ex15p ex16p ex17p ex18p ex19p
@@ -38,9 +38,6 @@ endif
ifeq ($(MFEM_USE_PETSC),YES)
SUBDIRS += petsc
endif
ifeq ($(MFEM_USE_PUMI),YES)
SUBDIRS += pumi
endif
SUBDIRS_ALL = $(addsuffix /all,$(SUBDIRS))
SUBDIRS_TEST = $(addsuffix /test,$(SUBDIRS))
SUBDIRS_CLEAN = $(addsuffix /clean,$(SUBDIRS))
+21 -19
View File
@@ -63,29 +63,31 @@ add_mfem_examples(PETSC_EXAMPLES_SRCS ${PFX} copy_petsc_rc_files test_petsc)
# ctest -R petsc
# Command line options for the tests.
set(EX1_ARGS_W -m ../../data/amr-quad.mesh --usepetsc)
set(EX1_ARGS_P -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p)
set(EX2_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p)
set(EX3_ARGS -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping)
set(EX4_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping)
set(EX4_HYB_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization)
set(EX5_BDDC_LB_ARGS -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping --local-bdr)
set(EX5_BDDC_GB_ARGS -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping)
set(EX5_FSPL_ARGS -m ../../data/beam-tet.mesh --usepetsc -o 0 --petscopts rc_ex5p_fieldsplit)
set(EX6_ARGS -m ../../data/amr-quad.mesh --usepetsc)
set(EX6_NONOVL_ARGS -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping)
set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1)
set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3)
set(EX1P_ARGS -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p)
set(EX2P_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p)
set(EX3P_ARGS -m ../../data/klein-bottle.mesh
-o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping)
set(EX4P_ARGS -m ../../data/klein-bottle.mesh
-o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping)
set(EX5P_BDDC_ARGS -m ../../data/star.mesh
--usepetsc --petscopts rc_ex5p_bddc --nonoverlapping)
set(EX5P_FSPL_ARGS -m ../../data/beam-tet.mesh
--usepetsc --petscopts rc_ex5p_fieldsplit)
set(EX6P_ARGS -m ../../data/amr-quad.mesh --usepetsc)
set(EX9P_E_ARGS -m ../../data/periodic-hexagon.mesh
--usepetsc --petscopts rc_ex9p_expl -dt 0.1)
set(EX9P_ES_ARGS -m ../../data/periodic-hexagon.mesh
--usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9P_IS_ARGS -m ../../data/periodic-hexagon.mesh
--usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10P_ARGS -m ../../data/beam-quad.mesh
-tf 30 -s 3 -rs 2 -dt 3 --usepetsc --petscopts rc_ex10p)
# Add the tests: one test per command-line-variable.
foreach(TEST_OPTIONS_VAR
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
EX1P_ARGS EX2P_ARGS EX3P_ARGS EX4P_ARGS EX5P_BDDC_ARGS EX5P_FSPL_ARGS
EX6P_ARGS EX9P_E_ARGS EX9P_ES_ARGS EX9P_IS_ARGS EX10P_ARGS)
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
+11 -20
View File
@@ -64,7 +64,6 @@ int main(int argc, char *argv[])
bool visualization = 1;
bool use_petsc = true;
bool use_nonoverlapping = false;
bool local_bdr_spec = false;
const char *petscrc_file = "";
OptionsParser args(argc, argv);
@@ -87,9 +86,6 @@ int main(int argc, char *argv[])
"-no-nonoverlapping", "--no-nonoverlapping",
"Use or not the block diagonal PETSc's matrix format "
"for non-overlapping domain decomposition.");
args.AddOption(&local_bdr_spec, "-local-bdr", "--local-bdr", "-no-local-bdr",
"--no-local-bdr",
"Specify boundary dofs in local (Vdofs) ordering.");
args.Parse();
if (!args.Good())
{
@@ -310,38 +306,33 @@ int main(int argc, char *argv[])
{
if (use_nonoverlapping)
{
PetscBDDCSolverParams opts;
// For saddle point problems, we need to provide BDDC the list of
// boundary dofs either essential or natural.
// Since R_space is the only space that may have boundary dofs and it
// is ordered first then W_space, we don't need any local offset when
// specifying the dofs.
Array<int> bdr_tdof_list;
bool local = false;
if (pmesh->bdr_attributes.Size())
{
Array<int> bdr(pmesh->bdr_attributes.Max());
bdr = 1;
if (!local_bdr_spec)
{
// Essential dofs in global ordering
R_space->GetEssentialTrueDofs(bdr, bdr_tdof_list);
}
else
{
// Alternatively, you can also provide the list of dofs in local
// ordering
R_space->GetEssentialVDofs(bdr, bdr_tdof_list);
bdr_tdof_list.SetSize(R_space->GetVSize()+W_space->GetVSize(),0);
}
opts.SetNatBdrDofs(&bdr_tdof_list,local_bdr_spec);
R_space->GetEssentialTrueDofs(bdr, bdr_tdof_list);
local = false;
// Alternatively, you can also provide the list of dofs in local
// ordering:
// R_space->GetEssentialVDofs(bdr, bdr_tdof_list);
// bdr_tdof_list.SetSize(R_space->GetVSize()+W_space->GetVSize(),0);
// local = true;
}
else
{
MFEM_WARNING("Missing boundary dofs. This may cause solver failures.");
MFEM_ABORT("Need to know the boundary dofs");
}
PetscBDDCSolverParams opts;
opts.SetNatBdrDofs(&bdr_tdof_list,local);
// See also command line options rc_ex5p_bddc
pdarcyPr = new PetscBDDCSolver(MPI_COMM_WORLD,*darcyOp,opts,"prec_");
}
+13 -19
View File
@@ -69,21 +69,18 @@ TESTNAME = Parallel PETSc example
# Testing PETSc execution options.
EX1_ARGS_W := -m ../../data/amr-quad.mesh --usepetsc
EX1_ARGS_P := -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
EX3_ARGS := -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping
EX4_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping
EX4_HYB_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization
EX5_BDDC_LB_ARGS := -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping --local-bdr
EX5_BDDC_GB_ARGS := -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping
EX5_FSPL_ARGS := -m ../../data/beam-tet.mesh --usepetsc -o 0 --petscopts rc_ex5p_fieldsplit
EX6_ARGS := -m ../../data/amr-quad.mesh --usepetsc
EX6_NONOVL_ARGS := -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping
EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
EX1_ARGS_W := -m ../../data/amr-quad.mesh --usepetsc
EX1_ARGS_P := -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
EX3_ARGS := -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping
EX4_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping
EX5_BDDC_ARGS := -m ../../data/star.mesh --usepetsc -o 0 --petscopts rc_ex5p_bddc --nonoverlapping
EX5_FSPL_ARGS := -m ../../data/beam-tet.mesh --usepetsc -o 0 --petscopts rc_ex5p_fieldsplit
EX6_ARGS := -m ../../data/amr-quad.mesh --usepetsc
EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_P))
@@ -93,14 +90,11 @@ ex3p-test-par: ex3p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX3_ARGS))
ex4p-test-par: ex4p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX4_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX4_HYB_ARGS))
ex5p-test-par: ex5p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_BDDC_LB_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_BDDC_GB_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_BDDC_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX5_FSPL_ARGS))
ex6p-test-par: ex6p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX6_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX6_NONOVL_ARGS))
ex9p-test-par: ex9p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_E_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_ES_ARGS))
-3
View File
@@ -6,7 +6,4 @@
# it needs PETSc configured with MUMPS
-solver_pc_type cholesky
# Petsc 3.9
-solver_pc_factor_mat_solver_type mumps
# Older versions of PETSc
-solver_pc_factor_mat_solver_package mumps
+3 -6
View File
@@ -16,10 +16,7 @@
#-pc_bddc_adaptive_threshold 10
# Customization of the local solvers
# With PETSc versions older than 3.9
# use "mat_solver_package" instead of "mat_solver_type"
#
#-pc_bddc_neumann_pc_factor_mat_solver_type mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_type mumps
#-pc_bddc_neumann_pc_factor_mat_solver_package mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_package mumps
#-pc_bddc_coarse_pc_type cholesky
#-pc_bddc_coarse_pc_factor_mat_solver_type mumps
#-pc_bddc_coarse_pc_factor_mat_solver_package mumps
-3
View File
@@ -2,7 +2,4 @@
# it needs PETSc configured with MUMPS
-solver_pc_type cholesky
# Petsc 3.9
-solver_pc_factor_mat_solver_type mumps
# Older versions of PETSc
-solver_pc_factor_mat_solver_package mumps
+3 -6
View File
@@ -13,10 +13,7 @@
#-pc_bddc_adaptive_threshold 10
# Customization of the local solvers
# With PETSc versions older than 3.9
# use "mat_solver_package" instead of "mat_solver_type"
#
#-pc_bddc_neumann_pc_factor_mat_solver_type mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_type mumps
#-pc_bddc_neumann_pc_factor_mat_solver_package mumps
#-pc_bddc_dirichlet_pc_factor_mat_solver_package mumps
#-pc_bddc_coarse_pc_type cholesky
#-pc_bddc_coarse_pc_factor_mat_solver_type mumps
#-pc_bddc_coarse_pc_factor_mat_solver_package mumps
+4 -18
View File
@@ -25,29 +25,15 @@
# verbose output
#-prec_pc_bddc_check_level 1
# local solvers (default "petsc" solvers will fail)
# needs PETSc compiled with support for MUMPS or SuiteSparse
# use "umfpack" in place of "mumps" if you want to use
# SuiteSparse solvers
#
# With PETSc versions older than 3.9
# use "mat_solver_package" instead of "mat_solver_type"
#
# local solvers (needs PETSc compiled with support for SuiteSparse)
# default solvers will fail
-prec_pc_bddc_neumann_pc_type lu
-prec_pc_bddc_neumann_pc_factor_mat_solver_type mumps
-prec_pc_bddc_neumann_pc_factor_mat_solver_package mumps
-prec_pc_bddc_neumann_pc_factor_mat_solver_package umfpack
-prec_pc_bddc_dirichlet_pc_type lu
-prec_pc_bddc_dirichlet_pc_factor_mat_solver_type mumps
-prec_pc_bddc_dirichlet_pc_factor_mat_solver_package mumps
# MUMPS sometimes fails with a very annoying error
-mat_mumps_icntl_14 500
-prec_pc_bddc_dirichlet_mat_mumps_icntl_14 500
-prec_pc_bddc_neumann_mat_mumps_icntl_14 500
-prec_pc_bddc_dirichlet_pc_factor_mat_solver_package umfpack
# coarse solver (needs PETSc compiled with support for MUMPS)
# default solver may fail
-prec_pc_bddc_coarse_pc_factor_mat_solver_type mumps
-prec_pc_bddc_coarse_pc_factor_mat_solver_package mumps
-prec_pc_bddc_coarse_pc_type cholesky
-72
View File
@@ -1,72 +0,0 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
set(PUMI_EXAMPLES_SRCS)
# All PUMI examples require MPI
if (MFEM_USE_MPI)
list(APPEND PUMI_EXAMPLES_SRCS
ex1.cpp
ex1p.cpp
ex2.cpp
ex6p.cpp
)
endif()
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
# Add "test_pumi" target, see below.
add_custom_target(test_pumi
${CMAKE_CTEST_COMMAND} -R pumi USES_TERMINAL)
# Add one executable per cpp file, adding "pumi_" as prefix. Sets
# "test_pumi" as a target that depends on the given examples.
set(PFX pumi_)
add_mfem_examples(PUMI_EXAMPLES_SRCS ${PFX} "" test_pumi)
# Testing.
# The PUMI tests can be run separately using the target "test_pumi"
# which builds the examples and runs:
# ctest -R pumi
# Command line options for the tests.
# TODO...
# Set the number of processors for the parallel examples.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
-18
View File
@@ -1,18 +0,0 @@
Finite Element Discretization Library
__
_ __ ___ / _| ___ _ __ ___
| '_ ` _ \ | |_ / _ \| '_ ` _ \
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on the Parallel Unstructured Mesh Infrastructure,
PUMI, from https://scorec.rpi.edu/pumi.
To build these examples, make sure that MFEM is configured with the option
"MFEM_USE_PUMI = YES", see the top-level INSTALL file for details.
We recommend comparing the original example codes with the corresponding files
in the current directory.
-262
View File
@@ -1,262 +0,0 @@
// MFEM Example 1
// PUMI Modification
//
// Compile with: make ex1
//
// Sample runs:
// ex1 -m ../../data/pumi/serial/Kova.smb -p ../../data/pumi/geom/Kova.dmg
//
// Note: Example models + meshes for the PUMI examples can be downloaded
// from github.com/mfem/data/pumi. After downloading we recommend
// creating a symbolic link to the above directory in ../../data.
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
//
// This PUMI modification demonstrates how PUMI's API can be used
// to load a PUMI mesh classified on a geometric model and then
// convert it to the MFEM mesh format. The inputs are a Parasolid
// model, "*.xmt_txt" and a SCOREC mesh "*.smb". The option "-o"
// is used for the Finite Element order and "-go" is used for the
// geometry order. Note that they can be used independently, i.e.
// "-o 8 -go 3" solves for 8th order FE on a third order geometry.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI).
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../../data/pumi/serial/Kova.smb";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/Kova.x_t";
#else
const char *model_file = "../../data/pumi/geom/Kova.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&model_file, "-p", "--parasolid",
"Parasolid model to use.");
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the SCOREC Mesh.
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
// 4. Increase the geometry order if necessary.
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 2);
bc.run();
}
pumi_mesh->verify();
// 5. Create the MFEM mesh object from the PUMI mesh. We can handle
// triangular and tetrahedral meshes. Other inputs are the same as the
// MFEM default constructor.
Mesh *mesh = new PumiMesh(pumi_mesh, 1, 1);
int dim = mesh->Dimension();
// 6. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels =
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 7. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 8. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 10. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 11. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the
// Diffusion domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 12. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 13. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 200, 1e-12, 0.0);
#else
// 13. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 14. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 15. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 17. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
-292
View File
@@ -1,292 +0,0 @@
// MFEM Example 1 - Parallel Version
// PUMI Modification
//
// Compile with: make ex1p
//
// Sample runs:
// mpirun -np 8 ex1p -m ../../data/pumi/parallel/Kova/Kova100k_8.smb
// -p ../../data/pumi/geom/Kova.dmg -o 1 -go 2
//
// Note: Example models + meshes for the PUMI examples can be downloaded
// from github.com/mfem/data/pumi. After downloading we recommend
// creating a symbolic link to the above directory in ../../data.
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
//
// This PUMI modification demonstrates how PUMI's API can be used
// to load a parallel PUMI mesh classified on a geometric model
// and then generate the corresponding parallel MFEM mesh. The
// example also performs a "uniform" refinement, similar to the
// MFEM examples, for coarse meshes. However, the refinement is
// performed using the PUMI API. The inputs are a Parasolid
// model, "*.xmt_txt" and SCOREC parallel meshes "*.smb". The
// option "-o" is used for the Finite Element order and "-go" for
// the geometry order. Note that they can be used independently:
// "-o 8 -go 3" solves for 8th order FE on third order geometry.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../../data/pumi/parallel/Kova/Kova100k_8.smb";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/Kova.x_t";
#else
const char *model_file = "../../data/pumi/geom/Kova.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&model_file, "-p", "--parasolid",
"Parasolid model to use.");
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the SCOREC Mesh
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
// 4. Increase the geometry order and refine the mesh if necessary. Parallel
// uniform refinement is performed if the total number of elements is less
// than 10,000.
int dim = pumi_mesh->getDimension();
int nEle = pumi_mesh->count(dim);
int ref_levels = (int)floor(log(10000./nEle)/log(2.)/dim);
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 2);
bc.run();
}
// Perform Uniform refinement
if (ref_levels > 1)
{
ma::Input* uniInput = ma::configureUniformRefine(pumi_mesh, ref_levels);
if (geom_order > 1)
{
crv::adapt(uniInput);
}
else
{
ma::adapt(uniInput);
}
}
pumi_mesh->verify();
// 5. Create the parallel MFEM mesh object from the parallel PUMI mesh.
// We can handle triangular and tetrahedral meshes. Note that the
// mesh resolution is performed on the PUMI mesh.
ParMesh *pmesh = new ParPumiMesh(MPI_COMM_WORLD, pumi_mesh);
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreSolver *amg = new HypreBoomerAMG(A);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 16. Free the used memory.
delete pcg;
delete amg;
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
-413
View File
@@ -1,413 +0,0 @@
// MFEM Example 2
// PUMI Modification
//
// Compile with: make ex2
//
// Sample runs:
// ex2 -m ../../data/pumi/serial/pillbox.smb -p ../../data/pumi/geom/pillbox.dmg
// -bf ../../data/pumi/serial/boundary.mesh
//
// Note: Example models + meshes for the PUMI examples can be downloaded
// from github.com/mfem/data/pumi. After downloading we recommend
// creating a symbolic link to the above directory in ../../data.
//
// Description: This example code solves a simple linear elasticity problem
// describing a multi-material cantilever beam.
//
// Specifically, we approximate the weak form of -div(sigma(u))=0
// where sigma(u)=lambda*div(u)*I+mu*(grad*u+u*grad) is the stress
// tensor corresponding to displacement field u, and lambda and mu
// are the material Lame constants. The boundary conditions are
// u=0 on the fixed part of the boundary with attribute 1, and
// sigma(u).n=f on the remainder with f being a constant pull down
// vector on boundary elements with attribute 2, and zero
// otherwise. The geometry of the domain is assumed to be as
// follows:
// boundary
// attribute 2
// (push down)
// ||
// \/
// +----------+
// | |
// | |
// +---------| material |----------+
// boundary --->| material| 2 | material |<--- boundary
// attribute 1 | 1 | | 3 | attribute 1
// (fixed) +---------+----------+----------+ (fixed)
//
// The example demonstrates the use of high-order and NURBS vector
// finite element spaces with the linear elasticity bilinear form,
// meshes with curved elements, and the definition of piece-wise
// constant and vector coefficient objects. Static condensation is
// also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "../../general/text.hpp"
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI).
int num_proc, myId;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_proc);
MPI_Comm_rank(MPI_COMM_WORLD, &myId);
// 2. Parse command-line options.
const char *mesh_file = "../../data/pumi/serial/pillbox.smb";
const char *boundary_file = "../../data/pumi/serial/boundary.mesh";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/pillbox.smd";
#else
const char *model_file = "../../data/pumi/geom/pillbox.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&model_file, "-p", "--parasolid",
"Parasolid model to use.");
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.AddOption(&boundary_file, "-bf", "--txt",
"txt file containing boundary tags");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 3. Read the SCOREC Mesh.
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
// 4. Increase the geometry order if necessary.
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 0);
bc.run();
}
pumi_mesh->verify();
// Read boundary
string bdr_tags;
named_ifgzstream input_bdr(boundary_file);
input_bdr >> ws;
getline(input_bdr, bdr_tags);
filter_dos(bdr_tags);
cout << " the boundary tag is : " << bdr_tags << endl;
Array<int> Dirichlet;
int numOfent;
if (bdr_tags == "Dirichlet")
{
input_bdr >> numOfent;
cout << " num of Dirichlet bdr conditions : " << numOfent << endl;
Dirichlet.SetSize(numOfent);
for (int kk = 0; kk < numOfent; kk++)
{
input_bdr >> Dirichlet[kk];
}
}
Dirichlet.Print();
Array<int> load_bdr;
skip_comment_lines(input_bdr, '#');
input_bdr >> bdr_tags;
filter_dos(bdr_tags);
cout << " the boundary tag is : " << bdr_tags << endl;
if (bdr_tags == "Load")
{
input_bdr >> numOfent;
load_bdr.SetSize(numOfent);
cout << " num of load bdr conditions : " << numOfent << endl;
for (int kk = 0; kk < numOfent; kk++)
{
input_bdr >> load_bdr[kk];
}
}
load_bdr.Print();
// 5. Create the MFEM mesh object from the PUMI mesh. We can handle triangular
// and tetrahedral meshes. Other inputs are the same as MFEM default
// constructor.
Mesh *mesh = new PumiMesh(pumi_mesh, 1, 1);
int dim = mesh->Dimension();
// Boundary conditions hack.
apf::MeshIterator* itr = pumi_mesh->begin(dim-1);
apf::MeshEntity* ent ;
int bdr_cnt = 0;
while ((ent = pumi_mesh->iterate(itr)))
{
apf::ModelEntity *me = pumi_mesh->toModel(ent);
if (pumi_mesh->getModelType(me) == (dim-1))
{
// Everywhere 3 as initial
(mesh->GetBdrElement(bdr_cnt))->SetAttribute(3);
int tag = pumi_mesh->getModelTag(me);
if (Dirichlet.Find(tag) != -1)
{
// Dirichlet attr -> 1
(mesh->GetBdrElement(bdr_cnt))->SetAttribute(1);
}
else if (load_bdr.Find(tag) != -1)
{
// Load attr -> 2
(mesh->GetBdrElement(bdr_cnt))->SetAttribute(2);
}
bdr_cnt++;
}
}
pumi_mesh->end(itr);
// Assign attributes for elements.
double ppt[3];
Vector cent(ppt, dim);
for (int el = 0; el < mesh->GetNE(); el++)
{
(mesh->GetElementTransformation(el))->
Transform(Geometries.GetCenter(mesh->GetElementBaseGeometry(el)),cent);
if (cent(0) <= -0.05)
{
mesh->SetAttribute(el , 1);
}
else if (cent(0) >= 0.05)
{
mesh->SetAttribute(el , 2);
}
else
{
mesh->SetAttribute(el , 3);
}
}
mesh->SetAttributes();
if (mesh->attributes.Max() < 2 || mesh->bdr_attributes.Max() < 2)
{
cerr << "\nInput mesh should have at least two materials and "
<< "two boundary attributes! (See schematic in ex2.cpp)\n"
<< endl;
return 3;
}
// 6. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 5,000
// elements.
{
int ref_levels =
(int)floor(log(5000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 7. Define a finite element space on the mesh. Here we use vector finite
// elements, i.e. dim copies of a scalar finite element space. The vector
// dimension is specified by the last argument of the FiniteElementSpace
// constructor. For NURBS meshes, we use the (degree elevated) NURBS space
// associated with the mesh nodes.
FiniteElementCollection *fec;
FiniteElementSpace *fespace;
if (mesh->NURBSext)
{
fec = NULL;
fespace = mesh->GetNodes()->FESpace();
}
else
{
fec = new H1_FECollection(order, dim);
fespace = new FiniteElementSpace(mesh, fec, dim);
}
cout << "Number of finite element unknowns: " << fespace->GetTrueVSize()
<< endl << "Assembling: " << flush;
// 8. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking only
// boundary attribute 1 from the mesh as essential and converting it to a
// list of true dofs.
Array<int> ess_tdof_list, ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 0;
ess_bdr[0] = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
// 9. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system. In this case, b_i equals the boundary integral
// of f*phi_i where f represents a "pull down" force on the Neumann part
// of the boundary and phi_i are the basis functions in the finite element
// fespace. The force is defined by the VectorArrayCoefficient object f,
// which is a vector of Coefficient objects. The fact that f is non-zero
// on boundary attribute 2 is indicated by the use of piece-wise constants
// coefficient for its last component.
VectorArrayCoefficient f(dim);
for (int i = 0; i < dim-1; i++)
{
f.Set(i, new ConstantCoefficient(0.0));
}
{
Vector pull_force(mesh->bdr_attributes.Max());
pull_force = 0.0;
pull_force(1) = -3.0e-2;
f.Set(dim-1, new PWConstCoefficient(pull_force));
f.Set(dim-2, new PWConstCoefficient(pull_force));
}
LinearForm *b = new LinearForm(fespace);
b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(f));
cout << "r.h.s. ... " << flush;
b->Assemble();
// 10. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 11. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the linear elasticity integrator with piece-wise
// constants coefficient lambda and mu.
Vector lambda(mesh->attributes.Max());
lambda = 1.0;
lambda(0) = lambda(1)*10;
lambda(1) = lambda(1)*100;
PWConstCoefficient lambda_func(lambda);
Vector mu(mesh->attributes.Max());
mu = 1.0;
mu(0) = mu(1)*10;
mu(1) = mu(1)*100;
PWConstCoefficient mu_func(mu);
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_func,mu_func));
// 12. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
cout << "matrix ... " << flush;
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "done." << endl;
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 13. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 500, 1e-8, 0.0);
#else
// 13. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 14. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 15. For non-NURBS meshes, make the mesh curved based on the finite element
// space. This means that we define the mesh elements through a fespace
// based transformation of the reference element. This allows us to save
// the displaced mesh as a curved mesh when using high-order finite
// element displacement field. We assume that the initial mesh (read from
// the file) is not higher order curved mesh compared to the chosen FE
// space.
if (!mesh->NURBSext)
{
mesh->SetNodalFESpace(fespace);
}
// 16. Save the displaced mesh and the inverted solution (which gives the
// backward displacements to the original grid). This output can be
// viewed later using GLVis: "glvis -m displaced.mesh -g sol.gf".
{
GridFunction *nodes = mesh->GetNodes();
*nodes += x;
x *= -1;
ofstream mesh_ofs("displaced.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 17. Send the above data by socket to a GLVis server. Use the "n" and "b"
// keys in GLVis to visualize the displacements.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 18. Free the used memory.
delete a;
delete b;
if (fec)
{
delete fespace;
delete fec;
}
delete mesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
-387
View File
@@ -1,387 +0,0 @@
// MFEM Example 6 - Parallel Version
// PUMI Modification
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 8 ex6p
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are adapted in a conforming (tetrahedrons) manner according
// to a simple SPR ZZ error estimator.
//
// This PUMI variation also performs a "uniform" refinement,
// similar to MFEM examples, for coarse meshes. However, the
// refinement is performed using the PUMI API. A new option "-ar"
// is added to modify the "adapt_ratio" which is the fraction of
// allowable error that scales the output size field of the error
// estimator.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifdef MFEM_USE_SIMMETRIX
#include <SimUtil.h>
#include <gmi_sim.h>
#endif
#include <apfMDS.h>
#include <gmi_null.h>
#include <PCU.h>
#include <spr.h>
#include <apfConvert.h>
#include <gmi_mesh.h>
#include <crv.h>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../../data/pumi/parallel/Kova/Kova100k_8.smb";
#ifdef MFEM_USE_SIMMETRIX
const char *model_file = "../../data/pumi/geom/Kova.x_t";
const char *smd_file = NULL;
#else
const char *model_file = "../../data/pumi/geom/Kova.dmg";
#endif
int order = 1;
bool static_cond = false;
bool visualization = 1;
int geom_order = 1;
double adapt_ratio = 0.05;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&model_file, "-p", "--model",
"parasolid or .dmg model to use.");
#ifdef MFEM_USE_SIMMETRIX
args.AddOption(&smd_file, "-sm", "--smd_model",
"smd model file to use.");
#endif
args.AddOption(&geom_order, "-go", "--geometry_order",
"Geometric order of the model");
args.AddOption(&adapt_ratio, "-ar", "--adapt_ratio",
"adaptation factor used in MeshAdapt");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the SCOREC Mesh.
PCU_Comm_Init();
#ifdef MFEM_USE_SIMMETRIX
Sim_readLicenseFile(0);
gmi_sim_start();
gmi_register_sim();
#endif
gmi_register_mesh();
apf::Mesh2* pumi_mesh;
#ifdef MFEM_USE_SIMMETRIX
if (smd_file)
{
gmi_model *mixed_model = gmi_sim_load(model_file, smd_file);
pumi_mesh = apf::loadMdsMesh(mixed_model, mesh_file);
}
else
#endif
{
pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);
}
// 4. Increase the geometry order and refine the mesh if necessary. Parallel
// uniform refinement is performed if the total number of elements is less
// than 100,000.
int dim = pumi_mesh->getDimension();
int nEle = pumi_mesh->count(dim);
int ref_levels = (int)floor(log(100000./nEle)/log(2.)/dim);
if (geom_order > 1)
{
crv::BezierCurver bc(pumi_mesh, geom_order, 2);
bc.run();
}
// Perform Uniform refinement
if (myid == 1)
{
std::cout << " ref level : " << ref_levels << std::endl;
}
if (ref_levels > 1)
{
ma::Input* uniInput = ma::configureUniformRefine(pumi_mesh, ref_levels);
if ( geom_order > 1)
{
crv::adapt(uniInput);
}
else
{
ma::adapt(uniInput);
}
}
pumi_mesh->verify();
// 5. Create the parallel MFEM mesh object from the parallel PUMI mesh. We
// can handle triangular and tetrahedral meshes. Note that the mesh
// resolution is performed on the PUMI mesh.
ParMesh *pmesh = new ParPumiMesh(MPI_COMM_WORLD, pumi_mesh);
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 1)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 1)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
// 8. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 9. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout;
if (visualization)
{
sout.open(vishost, visport);
if (!sout)
{
if (myid == 0)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
cout << "GLVis visualization disabled.\n";
}
visualization = false;
}
sout.precision(8);
}
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the
// Diffusion domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
// 12. The main AMR loop. In each iteration we solve the problem on the
// current mesh, visualize the solution, and adapt the mesh.
apf::Field* Tmag_field = 0;
apf::Field* temp_field = 0;
apf::Field* ipfield = 0;
apf::Field* sizefield = 0;
int max_iter = 3;
for (int Itr = 0; Itr < max_iter; Itr++)
{
HYPRE_Int global_dofs = fespace->GlobalTrueVSize();
if (myid == 1)
{
cout << "\nAMR iteration " << Itr << endl;
cout << "Number of unknowns: " << global_dofs << endl;
}
// Assemble.
a->Assemble();
b->Assemble();
// Essential boundary condition.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// Form linear system.
HypreParMatrix A;
Vector B, X;
const int copy_interior = 1;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B, copy_interior);
// 13. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreBoomerAMG amg;
amg.SetPrintLevel(0);
CGSolver pcg(A.GetComm());
pcg.SetPreconditioner(amg);
pcg.SetOperator(A);
pcg.SetRelTol(1e-6);
pcg.SetMaxIter(200);
pcg.SetPrintLevel(3); // print the first and the last iterations only
pcg.Mult(B, X);
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 15. Save in parallel the displaced mesh and the inverted solution (which
// gives the backward displacements to the original grid). This output
// can be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the above data by socket to a GLVis server. Use the "n" and "b"
// keys in GLVis to visualize the displacements.
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << *pmesh << x << flush;
}
// 17. Field transfer. Scalar solution field and magnitude field for error
// estimation are created the PUMI mesh.
if (order > geom_order)
{
Tmag_field = apf::createField(pumi_mesh, "field_mag",
apf::SCALAR, apf::getLagrange(order));
temp_field = apf::createField(pumi_mesh, "T_field",
apf::SCALAR, apf::getLagrange(order));
}
else
{
Tmag_field = apf::createFieldOn(pumi_mesh, "field_mag",apf::SCALAR);
temp_field = apf::createFieldOn(pumi_mesh, "T_field", apf::SCALAR);
}
ParPumiMesh* pPPmesh = dynamic_cast<ParPumiMesh*>(pmesh);
pPPmesh->FieldMFEMtoPUMI(pumi_mesh, &x, temp_field, Tmag_field);
ipfield= spr::getGradIPField(Tmag_field, "MFEM_gradip", 2);
sizefield = spr::getSPRSizeField(ipfield, adapt_ratio);
apf::destroyField(Tmag_field);
apf::destroyField(ipfield);
apf::destroyNumbering(pumi_mesh->findNumbering("LocalVertexNumbering"));
// 18. Perform MesAdapt.
ma::Input* erinput = ma::configure(pumi_mesh, sizefield);
erinput->shouldFixShape = true;
erinput->maximumIterations = 2;
if ( geom_order > 1)
{
crv::adapt(erinput);
}
else
{
ma::adapt(erinput);
}
ParMesh* Adapmesh = new ParPumiMesh(MPI_COMM_WORLD, pumi_mesh);
pPPmesh->UpdateMesh(Adapmesh);
delete Adapmesh;
// 19. Update the FiniteElementSpace, GridFunction, and bilinear form.
fespace->Update();
x.Update();
x = 0.0;
pPPmesh->FieldPUMItoMFEM(pumi_mesh, temp_field, &x);
a->Update();
b->Update();
// Destroy fields.
apf::destroyField(temp_field);
apf::destroyField(sizefield);
}
// 20. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
pumi_mesh->destroyNative();
apf::destroyMesh(pumi_mesh);
PCU_Comm_Free();
#ifdef MFEM_USE_SIMMETRIX
gmi_sim_stop();
Sim_unregisterAllKeys();
#endif
MPI_Finalize();
return 0;
}
-94
View File
@@ -1,94 +0,0 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/pumi/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
# All PUMI examples require MPI
SEQ_EXAMPLES =
PAR_EXAMPLES = ex1 ex1p ex2 ex6p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES)
endif
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
ifeq ($(MFEM_USE_PUMI),NO)
$(EXAMPLES):
$(error MFEM is not configured with PUMI)
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
ifneq (,$(filter test%,$(MAKECMDGOALS)))
ifeq (,$(wildcard ../../data/pumi))
$(info PUMI data directory not found. The PUMI tests will be SKIPPED.)
mfem-test = printf " $(3) [$(2) $(1) ... ]: "; $(PRINT_SKIP)
endif
endif
# Testing: Parallel vs. serial runs
RUN_MPI_NP = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP)
RUN_MPI = $(RUN_MPI_NP) $(MFEM_MPI_NP)
SERIAL_NAME := Serial PUMI example
PARALLEL_NAME := Parallel PUMI example
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME))
%-test-seq: %
@$(call mfem-test,$<,, $(SERIAL_NAME))
# Testing: Example-specific execution options:
ex1-test-par: ex1
@$(call mfem-test,$<, $(RUN_MPI_NP) 1, $(PARALLEL_NAME))
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI_NP) 8, $(PARALLEL_NAME))
ex2-test-par: ex2
@$(call mfem-test,$<, $(RUN_MPI_NP) 1, $(PARALLEL_NAME))
ex6p-test-par: ex6p
@$(call mfem-test,$<, $(RUN_MPI_NP) 8, $(PARALLEL_NAME))
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f refined.mesh sol.gf mesh.* sol.* displaced.mesh
+99 -8
View File
@@ -68,6 +68,8 @@ BilinearForm::BilinearForm (FiniteElementSpace * f)
fes = f;
sequence = f->GetSequence();
mat = mat_e = NULL;
oper = NULL;
oper_type = MFEM_SPARSEMAT;
extern_bfs = 0;
element_matrices = NULL;
static_cond = NULL;
@@ -85,6 +87,8 @@ BilinearForm::BilinearForm (FiniteElementSpace * f, BilinearForm * bf, int ps)
fes = f;
sequence = f->GetSequence();
mat_e = NULL;
oper = NULL;
oper_type = MFEM_SPARSEMAT;
extern_bfs = 1;
element_matrices = NULL;
static_cond = NULL;
@@ -235,6 +239,11 @@ void BilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
bfbfi_marker.Append(&bdr_marker);
}
void BilinearForm::AddIntegrator(LinearFESpaceIntegrator *bfi)
{
fesi.Append(bfi);
}
void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat)
{
if (element_matrices)
@@ -320,6 +329,8 @@ void BilinearForm::Assemble (int skip_zeros)
AllocMat();
}
oper_type = MFEM_SPARSEMAT;
#ifdef MFEM_USE_OPENMP
int free_element_matrices = 0;
if (!element_matrices)
@@ -505,6 +516,21 @@ void BilinearForm::Assemble (int skip_zeros)
#endif
}
void BilinearForm::AssembleForm(SparseMatrix &A, int skip_zeros)
{
Assemble(skip_zeros);
oper = &A;
oper_type = MFEM_SPARSEMAT;
}
void BilinearForm::AssembleForm(BilinearFormOperator &A)
{
A.Assemble(this);
oper = &A;
oper_type = MFEM_FORMOPER;
}
void BilinearForm::ConformingAssemble()
{
// Do not remove zero entries to preserve the symmetric structure of the
@@ -548,6 +574,7 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
const SparseMatrix *P = fes->GetConformingProlongation();
FormSystemMatrix(ess_tdof_list, A);
oper = &A;
// Transform the system and perform the elimination in B, based on the
// essential BC values from x. Restrict the BC part of x in X, and set the
@@ -606,6 +633,29 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
}
}
void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
Operator * &A, Vector &X, Vector &B,
int copy_interior)
{
if (oper_type == MFEM_SPARSEMAT)
{
SparseMatrix &Amat = static_cast<SparseMatrix&>(*oper);
FormLinearSystem(ess_tdof_list, x, b, Amat,
X, B, copy_interior);
SparseMatrix *M = new SparseMatrix;
M->MakeRef(Amat);
A = M;
}
else if (oper_type == MFEM_FORMOPER)
{
oper->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
}
else
{
mfem_error("Not supported.");
}
}
void BilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
SparseMatrix &A)
{
@@ -643,6 +693,24 @@ void BilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
}
}
void BilinearForm::FormSystemOperator(const Array<int> &ess_tdof_list,
Operator * &A)
{
if (oper_type == MFEM_SPARSEMAT)
{
FormSystemMatrix(ess_tdof_list, static_cast<SparseMatrix&>(*oper));
A = oper;
}
else if (oper_type == MFEM_FORMOPER)
{
A = oper;
}
else
{
mfem_error("Not supported.");
}
}
void BilinearForm::RecoverFEMSolution(const Vector &X,
const Vector &b, Vector &x)
{
@@ -734,7 +802,7 @@ void BilinearForm::ComputeElementMatrices()
}
void BilinearForm::EliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
const Vector &sol, Vector &rhs, DiagonalPolicy dpolicy)
Vector &sol, Vector &rhs, DiagonalPolicy dpolicy)
{
Array<int> ess_dofs, conf_ess_dofs;
fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
@@ -785,7 +853,7 @@ void BilinearForm::EliminateEssentialBCDiag (const Array<int> &bdr_attr_is_ess,
}
void BilinearForm::EliminateVDofs(const Array<int> &vdofs,
const Vector &sol, Vector &rhs,
Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy)
{
for (int i = 0; i < vdofs.Size(); i++)
@@ -825,8 +893,7 @@ void BilinearForm::EliminateVDofs(const Array<int> &vdofs,
}
void BilinearForm::EliminateEssentialBCFromDofs(
const Array<int> &ess_dofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy)
const Array<int> &ess_dofs, Vector &sol, Vector &rhs, DiagonalPolicy dpolicy)
{
MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
MFEM_ASSERT(sol.Size() == height, "incorrect sol Vector size");
@@ -930,10 +997,10 @@ BilinearForm::~BilinearForm()
for (k=0; k < bbfi.Size(); k++) { delete bbfi[k]; }
for (k=0; k < fbfi.Size(); k++) { delete fbfi[k]; }
for (k=0; k < bfbfi.Size(); k++) { delete bfbfi[k]; }
for (k=0; k < fesi.Size(); k++) { delete fesi[k]; }
}
}
MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
FiniteElementSpace *te_fes)
: Matrix(te_fes->GetVSize(), tr_fes->GetVSize())
@@ -955,7 +1022,7 @@ const double & MixedBilinearForm::Elem (int i, int j) const
void MixedBilinearForm::Mult (const Vector & x, Vector & y) const
{
mat -> Mult (x, y);
oper -> Mult (x, y);
}
void MixedBilinearForm::AddMult (const Vector & x, Vector & y,
@@ -1007,6 +1074,12 @@ void MixedBilinearForm::AddTraceFaceIntegrator (BilinearFormIntegrator * bfi)
skt.Append (bfi);
}
void MixedBilinearForm::AddIntegrator(LinearFESpaceIntegrator *integ)
{
fesi.Append(integ);
}
void MixedBilinearForm::Assemble (int skip_zeros)
{
int i, k;
@@ -1090,6 +1163,21 @@ void MixedBilinearForm::Assemble (int skip_zeros)
}
}
}
oper = mat;
}
void MixedBilinearForm::AssembleForm(SparseMatrix &A, int skip_zeros)
{
Assemble(skip_zeros);
oper = mat;
A.MakeRef(*mat);
}
void MixedBilinearForm::AssembleForm(BilinearFormOperator &A, int skip_zeros)
{
A.Assemble(this);
oper = &A;
}
void MixedBilinearForm::ConformingAssemble()
@@ -1114,12 +1202,14 @@ void MixedBilinearForm::ConformingAssemble()
mat = RAP;
}
oper = mat;
height = mat->Height();
width = mat->Width();
}
void MixedBilinearForm::EliminateTrialDofs (
Array<int> &bdr_attr_is_ess, const Vector &sol, Vector &rhs )
Array<int> &bdr_attr_is_ess, Vector &sol, Vector &rhs )
{
int i, j, k;
Array<int> tr_vdofs, cols_marker (trial_fes -> GetVSize());
@@ -1142,7 +1232,7 @@ void MixedBilinearForm::EliminateTrialDofs (
}
void MixedBilinearForm::EliminateEssentialBCFromTrialDofs (
Array<int> &marked_vdofs, const Vector &sol, Vector &rhs)
Array<int> &marked_vdofs, Vector &sol, Vector &rhs)
{
mat -> EliminateCols (marked_vdofs, &sol, &rhs);
}
@@ -1183,6 +1273,7 @@ MixedBilinearForm::~MixedBilinearForm()
for (i = 0; i < dom.Size(); i++) { delete dom[i]; }
for (i = 0; i < bdr.Size(); i++) { delete bdr[i]; }
for (i = 0; i < skt.Size(); i++) { delete skt[i]; }
for (i = 0; i < fesi.Size(); i++) { delete fesi[i]; }
}
+52 -7
View File
@@ -24,17 +24,27 @@
namespace mfem
{
// Forward declare BilinearFormOperator
class BilinearFormOperator;
/** Class for bilinear form - "Matrix" with associated FE space and
BLFIntegrators. */
class BilinearForm : public Matrix
{
protected:
// TODO remove mat
/// Sparse matrix to be associated with the form.
SparseMatrix *mat;
/// Matrix used to eliminate b.c.
SparseMatrix *mat_e;
/// Generic operator associated with the form.
Operator *oper;
/// Operator type.
enum Type oper_type;
/// FE space on which the form lives.
FiniteElementSpace *fes;
@@ -58,6 +68,9 @@ protected:
Array<BilinearFormIntegrator*> bfbfi;
Array<Array<int>*> bfbfi_marker;
/// Set of fespace integrators (does not matter what type)
Array<LinearFESpaceIntegrator*> fesi;
DenseMatrix elemmat;
Array<int> vdofs;
@@ -83,7 +96,9 @@ protected:
BilinearForm() : Matrix (0)
{
fes = NULL; sequence = -1;
mat = mat_e = NULL; extern_bfs = 0; element_matrices = NULL;
mat = mat_e = NULL;
oper = NULL; oper_type = MFEM_SPARSEMAT;
extern_bfs = 0; element_matrices = NULL;
static_cond = NULL; hybridization = NULL;
precompute_sparsity = 0;
diag_policy = DIAG_KEEP;
@@ -151,6 +166,8 @@ public:
Array<BilinearFormIntegrator*> *GetBFBFI() { return &bfbfi; }
Array<LinearFESpaceIntegrator*> *GetFESI() { return &fesi; }
const double &operator()(int i, int j) { return (*mat)(i,j); }
/// Returns reference to a_{ij}.
@@ -232,6 +249,9 @@ public:
/// Adds new boundary Face Integrator.
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi);
/// Adds a LinearFESpaceIntegrator.
void AddIntegrator(LinearFESpaceIntegrator *integ);
/** @brief Adds new boundary Face Integrator, restricted to specific boundary
attributes. */
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
@@ -246,6 +266,9 @@ public:
/// Assembles the form i.e. sums over all domain/bdr integrators.
void Assemble(int skip_zeros = 1);
void AssembleForm(BilinearFormOperator &A);
void AssembleForm(SparseMatrix &A, int skip_zeros = 1);
/// Get the finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return fes->GetConformingProlongation(); }
@@ -278,10 +301,17 @@ public:
NOTE: If there are no transformations, @a X simply reuses the data of
@a x. */
void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
Operator * &A, Vector &X, Vector &B,
int copy_interior = 0);
void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
SparseMatrix &A, Vector &X, Vector &B,
int copy_interior = 0);
/// Form the linear system matrix A, see FormLinearSystem for details.
void FormSystemOperator(const Array<int> &ess_tdof_list, Operator * &Aoper);
/// Form the linear system matrix A, see FormLinearSystem() for details.
void FormSystemMatrix(const Array<int> &ess_tdof_list, SparseMatrix &A);
@@ -311,7 +341,7 @@ public:
essential DOFs is set to 1.0. This behavior is controlled by the argument
@a dpolicy. */
void EliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
const Vector &sol, Vector &rhs,
Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/// Eliminate essential boundary DOFs from the system matrix.
@@ -322,7 +352,7 @@ public:
double value);
/// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs.
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
void EliminateVDofs(const Array<int> &vdofs, Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/// Eliminate the given @a vdofs, storing the eliminated part internally.
@@ -333,10 +363,10 @@ public:
DiagonalPolicy dpolicy = DIAG_ONE);
/** @brief Similar to
EliminateVDofs(const Array<int> &, const Vector &, Vector &, DiagonalPolicy)
EliminateVDofs(const Array<int> &, Vector &, Vector &, DiagonalPolicy)
but here @a ess_dofs is a marker (boolean) array on all vector-dofs
(@a ess_dofs[i] < 0 is true). */
void EliminateEssentialBCFromDofs(const Array<int> &ess_dofs, const Vector &sol,
void EliminateEssentialBCFromDofs(const Array<int> &ess_dofs, Vector &sol,
Vector &rhs, DiagonalPolicy dpolicy = DIAG_ONE);
/** @brief Similar to EliminateVDofs(const Array<int> &, DiagonalPolicy) but
@@ -375,6 +405,7 @@ public:
virtual ~BilinearForm();
};
/**
Class for assembling of bilinear forms `a(u,v)` defined on different
trial and test spaces. The assembled matrix `A` is such that
@@ -394,12 +425,14 @@ class MixedBilinearForm : public Matrix
{
protected:
SparseMatrix *mat;
Operator *oper;
FiniteElementSpace *trial_fes, *test_fes;
Array<BilinearFormIntegrator*> dom;
Array<BilinearFormIntegrator*> bdr;
Array<BilinearFormIntegrator*> skt; // trace face integrators
Array<LinearFESpaceIntegrator*> fesi;
public:
MixedBilinearForm (FiniteElementSpace *tr_fes,
@@ -442,16 +475,24 @@ public:
two adjacent volume FEs from the test space. */
void AddTraceFaceIntegrator (BilinearFormIntegrator * bfi);
/// Add an FESpaceIntegrator
void AddIntegrator (LinearFESpaceIntegrator *integ);
Array<BilinearFormIntegrator*> *GetDBFI() { return &dom; }
Array<BilinearFormIntegrator*> *GetBBFI() { return &bdr; }
Array<BilinearFormIntegrator*> *GetTFBFI() { return &skt; }
Array<LinearFESpaceIntegrator*> *GetFESI() { return &fesi; }
void operator= (const double a) { *mat = a; }
void Assemble (int skip_zeros = 1);
void AssembleForm(BilinearFormOperator &A, int skip_zeros = 1);
void AssembleForm(SparseMatrix &A, int skip_zeros = 1);
/** For partially conforming trial and/or test FE spaces, complete the
assembly process by performing A := P2^t A P1 where A is the internal
sparse matrix; P1 and P2 are the conforming prolongation matrices of the
@@ -460,15 +501,19 @@ public:
void ConformingAssemble();
void EliminateTrialDofs(Array<int> &bdr_attr_is_ess,
const Vector &sol, Vector &rhs);
Vector &sol, Vector &rhs);
void EliminateEssentialBCFromTrialDofs(Array<int> &marked_vdofs,
const Vector &sol, Vector &rhs);
Vector &sol, Vector &rhs);
virtual void EliminateTestDofs(Array<int> &bdr_attr_is_ess);
void Update();
FiniteElementSpace *TrialFESpace() const { return trial_fes; }
FiniteElementSpace *TestFESpace() const { return test_fes; }
virtual ~MixedBilinearForm();
};
+316
View File
@@ -0,0 +1,316 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// Implementation of BilinearFormOperator
#include "fem.hpp"
namespace mfem
{
static void BuildDofMaps(FiniteElementSpace *fespace, Array<int> *&off,
Array<int> *&ind)
{
// Get the total size without vdim
int size = 0;
const int vdim = fespace->GetVDim();
for (int e = 0; e < fespace->GetNE(); e++)
{
const FiniteElement *fe = fespace->GetFE(e);
size += fe->GetDof();
}
const int local_size = size * vdim;
const int global_size = fespace->GetVSize();
// Now we can allocate and fill the global map
off = new Array<int>(global_size + 1);
ind = new Array<int>(local_size);
Array<int> &offsets = *off;
Array<int> &indices = *ind;
Array<int> global_map(local_size);
Array<int> elem_vdof;
int offset = 0;
for (int e = 0; e < fespace->GetNE(); e++)
{
const FiniteElement *fe = fespace->GetFE(e);
const int dofs = fe->GetDof();
const int vdofs = dofs * vdim;
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement *>(fe);
const Array<int> &dof_map = tfe->GetDofMap();
fespace->GetElementVDofs(e, elem_vdof);
if (dof_map.Size()==0)
{
for (int vd = 0; vd < vdim; vd++)
for (int i = 0; i < vdofs; i++)
{
global_map[offset + dofs*vd + i] = elem_vdof[dofs*vd + i];
}
}else{
for (int vd = 0; vd < vdim; vd++)
for (int i = 0; i < vdofs; i++)
{
global_map[offset + dofs*vd + i] = elem_vdof[dofs*vd + dof_map[i]];
}
}
offset += vdofs;
}
// Store and use a set of offsets and indices instead of this map
// Zero the offset vector
offsets = 0;
// Keep track of how many local dof point to its global dof
// Count how many times each dof gets hit
for (int i = 0; i < local_size; i++)
{
const int g = global_map[i];
++offsets[g + 1];
}
// Aggregate the offsets
for (int i = 1; i <= global_size; i++)
{
offsets[i] += offsets[i - 1];
}
for (int i = 0; i < local_size; i++)
{
const int g = global_map[i];
indices[offsets[g]++] = i;
}
// Shift the offset vector back by one, since it was used as a
// counter above.
for (int i = global_size; i > 0; i--)
{
offsets[i] = offsets[i - 1];
}
offsets[0] = 0;
}
BilinearFormOperator::BilinearFormOperator(IntegratorMap *_map)
: bf(NULL), mbf(NULL),
trial_fes(NULL), test_fes(NULL),
trial_gs(false), test_gs(false),
trial_offsets(NULL), trial_indices(NULL),
test_offsets(NULL), test_indices(NULL),
X(NULL), Y(NULL),
map(_map) { }
BilinearFormOperator::~BilinearFormOperator()
{
delete map;
Clear();
}
void BilinearFormOperator::Assemble(BilinearForm *_bf)
{
if (_bf != bf)
{
bf = _bf;
height = bf->Height();
width = bf->Width();
Init(bf->FESpace(), NULL);
// Delete the old integrator list -- Note that this does not
// delete the integrators themselves (since the original
// bilinear form owns these)
lfesi.DeleteAll();
// Add the integrators from bf->fesi
Array<LinearFESpaceIntegrator*> &other_fesi = *(bf->GetFESI());
for (int i = 0; i < other_fesi.Size(); i++)
{
lfesi.Append(other_fesi[i]);
}
if (map)
{
Array<BilinearFormIntegrator*> &dbfi = *(bf->GetDBFI());
for (int i = 0; i < dbfi.Size(); i++)
{
lfesi.Append(map->DomainIntegrator(dbfi[i]));
}
}
}
Assemble();
}
void BilinearFormOperator::Assemble(MixedBilinearForm *_mbf)
{
if (_mbf != mbf)
{
mbf = _mbf;
height = bf->Height();
width = bf->Width();
Init(mbf->TrialFESpace(), mbf->TestFESpace());
// Delete the old integrator list -- Note that this does not
// delete the integrators themselves (since the original mixed
// bilinear form owns these)
lfesi.DeleteAll();
// Add the integrators from mbf->fesi
Array<LinearFESpaceIntegrator*> &other_fesi = *(mbf->GetFESI());
for (int i = 0; i < other_fesi.Size(); i++)
{
lfesi.Append(other_fesi[i]);
}
if (map)
{
Array<BilinearFormIntegrator*> &dbfi = *(mbf->GetDBFI());
for (int i = 0; i < dbfi.Size(); i++)
{
lfesi.Append(map->DomainIntegrator(dbfi[i]));
}
}
}
Assemble();
}
void BilinearFormOperator::Assemble()
{
// Linear assembly
for (int i = 0; i < lfesi.Size(); i++)
{
lfesi[i]->Assemble(trial_fes, test_fes);
}
}
void BilinearFormOperator::Clear()
{
delete trial_offsets;
delete trial_indices;
if (test_fes)
{
delete test_offsets;
delete test_indices;
}
if (trial_gs) delete X;
if (test_gs) delete Y;
}
void BilinearFormOperator::Init(FiniteElementSpace *_trial_fes,
FiniteElementSpace *_test_fes)
{
if ((_trial_fes != trial_fes) || (_test_fes != test_fes))
{
// Clear before recreating
Clear();
trial_fes = _trial_fes;
test_fes = _test_fes;
BuildDofMaps(trial_fes, trial_offsets, trial_indices);
if (test_fes != NULL)
{
BuildDofMaps(test_fes, test_offsets, test_indices);
}
else
{
// Point to the trial offsets and indices
test_offsets = trial_offsets;
test_indices = trial_indices;
}
X = new Vector(trial_indices->Size());
Y = new Vector(test_indices->Size());
}
const FiniteElementSpace *actual_test_fes =
(test_fes != NULL) ? test_fes : trial_fes;
trial_gs = test_gs = true;
if (dynamic_cast<const L2_FECollection *>(trial_fes->FEColl()))
{
trial_gs = test_gs = false;
}
else if (dynamic_cast<const L2_FECollection *>(actual_test_fes->FEColl()))
{
test_gs = false;
}
}
void BilinearFormOperator::LToEVector(const Array<int> &offsets,
const Array<int> &indices,
const Vector &v, Vector &V) const
{
const int size = v.Size();
for (int i = 0; i < size; i++)
{
const int offset = offsets[i];
const int next_offset = offsets[i + 1];
const double dof_value = v(i);
for (int j = offset; j < next_offset; j++) { V(indices[j]) = dof_value; }
}
}
void BilinearFormOperator::EToLVector(const Array<int> &offsets,
const Array<int> &indices,
const Vector &V, Vector &v) const
{
// NOTE: This method ADDS to the output v
const int size = v.Size();
for (int i = 0; i < size; i++)
{
const int offset = offsets[i];
const int next_offset = offsets[i + 1];
double dof_value = 0;
for (int j = offset; j < next_offset; j++) { dof_value += V(indices[j]); }
v(i) += dof_value;
}
}
void BilinearFormOperator::AddMult(const Vector &x, Vector &y) const
{
if (trial_gs) { LToEVector(*trial_offsets, *trial_indices, x, *X); }
else { X = const_cast<Vector *>(&x); }
if (!test_gs) { Y = &y; }
*Y = 0.0;
for (int i = 0; i < lfesi.Size(); i++) lfesi[i]->AddMult(*X, *Y);
for (int i = 0; i < nlfesi.Size(); i++) nlfesi[i]->AddMult(*X, *Y);
if (test_gs) { EToLVector(*test_offsets, *test_indices, *Y, y); }
}
void BilinearFormOperator::AddMultTranspose(const Vector &x, Vector &y) const
{
if (test_gs) { LToEVector(*test_offsets, *test_indices, x, *X); }
else { X = const_cast<Vector *>(&x); }
if (!trial_gs) { Y = &y; }
*Y = 0.0;
for (int i = 0; i < lfesi.Size(); i++) lfesi[i]->AddMultTranspose(*X, *Y);
for (int i = 0; i < nlfesi.Size(); i++) nlfesi[i]->AddMultTranspose(*X, *Y);
if (trial_gs) { EToLVector(*trial_offsets, *trial_indices, *Y, y); }
}
void BilinearFormOperator::Mult(const Vector &x, Vector &y) const
{ y = 0.0; AddMult(x, y); }
}
+96
View File
@@ -0,0 +1,96 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
//
// Defines the general object for the abstraction of bilinear and
// nonlinear forms.
#ifndef MFEM_BILINEARFORMOPER
#define MFEM_BILINEARFORMOPER
#include "../config/config.hpp"
#include "../linalg/linalg.hpp"
#include "fespace.hpp"
#include "nonlininteg.hpp"
namespace mfem
{
struct IntegratorMap
{
virtual LinearFESpaceIntegrator *DomainIntegrator(BilinearFormIntegrator *integ) const
{ mfem_error("Not supported."); return NULL; }
virtual LinearFESpaceIntegrator *InteriorFaceIntegrator(BilinearFormIntegrator *integ) const
{ mfem_error("Not supported."); return NULL; }
virtual LinearFESpaceIntegrator *BdrFaceIntegrator(BilinearFormIntegrator *integ) const
{ mfem_error("Not supported."); return NULL; }
virtual NonlinearFESpaceIntegrator *DomainIntegrator(NonlinearFormIntegrator *integ) const
{ mfem_error("Not supported."); return NULL; }
virtual ~IntegratorMap() { }
};
class BilinearFormOperator : public Operator
{
protected:
BilinearForm *bf; // Do not own
MixedBilinearForm *mbf; // Do not own
FiniteElementSpace *trial_fes; // Do not own
FiniteElementSpace *test_fes; // Do not own
bool trial_gs, test_gs;
Array<int> *trial_offsets, *trial_indices;
Array<int> *test_offsets, *test_indices;
mutable Vector *X;
mutable Vector *Y;
Array<LinearFESpaceIntegrator*> lfesi;
Array<NonlinearFESpaceIntegrator*> nlfesi;
IntegratorMap *map;
// Convert between vector types before calling Mult.
void LToEVector(const Array<int> &offsets, const Array<int> &indices,
const Vector &v, Vector &V) const;
void EToLVector(const Array<int> &offsets, const Array<int> &indices,
const Vector &V, Vector &v) const;
void Clear();
void Init(FiniteElementSpace *_trial_fes, FiniteElementSpace *_test_fes);
public:
// Create an empty object or assemble what is needed by the
// bilinear form integrators to later compute the action.
BilinearFormOperator(IntegratorMap *_map = NULL);
~BilinearFormOperator();
void Assemble();
void Assemble(BilinearForm *bf);
void Assemble(MixedBilinearForm *bf);
/// Perform the action of the bilinear form on a vector and set y.
virtual void Mult(const Vector &x, Vector &y) const;
virtual const Operator *GetProlongation() const { return trial_fes->GetProlongationMatrix(); }
virtual const Operator *GetRestriction() const { return trial_fes->GetRestrictionMatrix(); }
/// Perform the action of the bilinear form on a vector and add to y.
void AddMult(const Vector &x, Vector &y) const;
/// Perform the (transposed) action of the bilinear form on a vector and add to y.
void AddMultTranspose(const Vector &x, Vector &y) const;
};
}
#endif
+14 -6
View File
@@ -61,6 +61,19 @@ void BilinearFormIntegrator::AssembleElementVector(
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleMult(
const Vector &x, Vector& y)
{
mfem_error("BilinearFormIntegrator::AssembleMult\n"
" is not implemented fot this class.");
}
void BilinearFormIntegrator::AssembleMultTranspose(
const Vector &x, Vector& y)
{
mfem_error("BilinearFormIntegrator::AssembleMultTranspose\n"
" is not implemented fot this class.");
}
void TransposeIntegrator::AssembleElementMatrix (
const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
@@ -697,7 +710,7 @@ double DiffusionIntegrator::ComputeFluxEnergy
}
else
{
MQ->Eval(mq, Trans, ip);
MQ->Eval(mq, Trans, ip);
energy += w * mq.InnerProduct(pointflux, pointflux);
}
@@ -716,7 +729,6 @@ double DiffusionIntegrator::ComputeFluxEnergy
return energy;
}
void MassIntegrator::AssembleElementMatrix
( const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
@@ -807,7 +819,6 @@ void MassIntegrator::AssembleElementMatrix2(
}
}
void BoundaryMassIntegrator::AssembleFaceMatrix(
const FiniteElement &el1, const FiniteElement &el2,
FaceElementTransformations &Trans, DenseMatrix &elmat)
@@ -1626,7 +1637,6 @@ void VectorCurlCurlIntegrator::AssembleElementMatrix(
ir = &IntRules.Get(el.GetGeomType(), order);
}
elmat.SetSize(dof*dim);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
@@ -2055,7 +2065,6 @@ void DivDivIntegrator::AssembleElementMatrix(
}
}
void VectorDiffusionIntegrator::AssembleElementMatrix(
const FiniteElement &el,
ElementTransformation &Trans,
@@ -2299,7 +2308,6 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
+22
View File
@@ -80,6 +80,17 @@ public:
Vector &flux, Vector *d_energy = NULL)
{ return 0.0; }
/** Assemble any element or face-specific terms required for the
action with the bilinear form integrator. Later applied with
AssembleVector. */
virtual void AssembleOperator(const FiniteElementSpace *trial_fes,
const FiniteElementSpace *test_fes) { }
/** Compute `y = A * x` where A is the bilinear form integrator for
all elements/faces. */
virtual void AssembleMult(const Vector &fun, Vector &vect);
virtual void AssembleMultTranspose(const Vector &fun, Vector &vect);
virtual ~BilinearFormIntegrator() { }
};
@@ -1622,6 +1633,11 @@ public:
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
ElementTransformation &Trans,
Vector &flux, Vector *d_energy = NULL);
// Friend partial assembly version so it has access to the coefficients.
friend class PADiffusionIntegrator;
// TODO: Add a GetPAIntegrator method here
// PAIntegrator* GetPAIntegrator(type);
};
/** Class for local mass matrix assembling a(u,v) := (Q u, v) */
@@ -1649,6 +1665,9 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
// Friend partial assembly version so it has access to the coefficients.
friend class PAMassIntegrator;
};
class BoundaryMassIntegrator : public MassIntegrator
@@ -1742,6 +1761,9 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
// Friend partial assembly version so it has access to the coefficients.
friend class PAMassIntegrator;
};
+1 -1
View File
@@ -209,7 +209,7 @@ void VectorRestrictedCoefficient::Eval(
}
else
{
M.SetSize(vdim, ir.GetNPoints());
M.SetSize(vdim);
M = 0.0;
}
}
+57 -99
View File
@@ -164,7 +164,6 @@ ConduitDataCollection::SetProtocol(const std::string &protocol)
//---------------------------------------------------------------------------//
mfem::Mesh *
ConduitDataCollection::BlueprintMeshToMesh(const Node &n_mesh,
const std::string &main_toplogy_name,
bool zero_copy)
{
// n_conv holds converted data (when necessary for mfem api)
@@ -173,31 +172,11 @@ ConduitDataCollection::BlueprintMeshToMesh(const Node &n_mesh,
// can't return a mesh that zero copies the conduit data
Node n_conv;
//
// we need to find the topology and its coordset.
//
MFEM_ASSERT(n_mesh.has_path("coordsets/coords"),
"Expected topology named \"coords\" "
"(node is missing path \"coordsets/coords\")");
std::string topo_name = main_toplogy_name;
// if topo name is not set, look for first topology
if (topo_name == "")
{
topo_name = n_mesh["topologies"].schema().child_name(0);
}
MFEM_ASSERT(n_mesh.has_path("topologies/" + topo_name),
"Expected topology named \"" + topo_name + "\" "
"(node is missing path \"topologies/" + topo_name + "\")");
// find the coord set
std::string coords_name =
n_mesh["topologies"][topo_name]["coordset"].as_string();
MFEM_ASSERT(n_mesh.has_path("coordsets/" + coords_name),
"Expected topology named \"" + coords_name + "\" "
"(node is missing path \"coordsets/" + coords_name + "\")");
const Node &n_coordset = n_mesh["coordsets"][coords_name];
const Node &n_coordset = n_mesh["coordsets/coords"];
const Node &n_coordset_vals = n_coordset["values"];
// get the number of dims of the coordset
@@ -259,15 +238,17 @@ ConduitDataCollection::BlueprintMeshToMesh(const Node &n_mesh,
n_tmp["y"].set(DataType::c_double(num_verts));
}
Node &n_conv_coords_vals = n_conv["coordsets"][coords_name]["values"];
Node &n_conv_coords_vals = n_conv["coordsets/coords/values"];
blueprint::mcarray::to_interleaved(n_tmp,
n_conv_coords_vals);
verts_ptr = n_conv_coords_vals[0].value();
}
MFEM_ASSERT(n_mesh.has_path("topologies/main"),
"Expected topology named \"main\" "
"(node is missing path \"topologies/main\")");
const Node &n_mesh_topo = n_mesh["topologies"][topo_name];
const Node &n_mesh_topo = n_mesh["topologies/main"];
std::string mesh_ele_shape = n_mesh_topo["elements/shape"].as_string();
mfem::Geometry::Type mesh_geo = ShapeNameToGeomType(mesh_ele_shape);
@@ -284,8 +265,7 @@ ConduitDataCollection::BlueprintMeshToMesh(const Node &n_mesh,
}
else
{
Node &n_mesh_conn_conv=
n_conv["topologies"][topo_name]["elements/connectivity"];
Node &n_mesh_conn_conv= n_conv["topologies/main/elements/connectivity"];
n_mesh_conn.to_int_array(n_mesh_conn_conv);
elem_indices = n_mesh_conn_conv.value();
}
@@ -301,46 +281,33 @@ ConduitDataCollection::BlueprintMeshToMesh(const Node &n_mesh,
// table lookup, even if we don't have boundary info.
mfem::Geometry::Type bndry_geo = mfem::Geometry::POINT;
if ( n_mesh_topo.has_child("boundary_topology") )
if ( n_mesh.has_path("topologies/boundary") )
{
std::string bndry_topo_name = n_mesh_topo["boundary_topology"].as_string();
const Node &n_bndry_topo = n_mesh["topologies/boundary"];
std::string bndry_ele_shape = n_bndry_topo["elements/shape"].as_string();
// In VisIt, we encountered a case were a mesh specified a boundary
// topology, but the boundary topology was omitted from the blueprint
// index, so it's data could not be obtained.
//
// This guard prevents an error in that case, allowing the mesh to be
// created without boundary info
bndry_geo = ShapeNameToGeomType(bndry_ele_shape);
int num_idxs_per_bndry_ele = Geometry::NumVerts[mesh_geo];
if (n_mesh["topologies"].has_child(bndry_topo_name))
const Node &n_bndry_conn = n_bndry_topo["elements/connectivity"];
// mfem requires ints, we could have int64s, etc convert if necessary
if ( n_bndry_conn.dtype().is_int() &&
n_bndry_conn.is_compact())
{
const Node &n_bndry_topo = n_mesh["topologies"][bndry_topo_name];
std::string bndry_ele_shape = n_bndry_topo["elements/shape"].as_string();
bndry_geo = ShapeNameToGeomType(bndry_ele_shape);
int num_idxs_per_bndry_ele = Geometry::NumVerts[mesh_geo];
const Node &n_bndry_conn = n_bndry_topo["elements/connectivity"];
// mfem requires ints, we could have int64s, etc convert if necessary
if ( n_bndry_conn.dtype().is_int() &&
n_bndry_conn.is_compact())
{
bndry_indices = n_bndry_conn.value();
}
else
{
Node &(n_bndry_conn_conv) =
n_conv["topologies"][bndry_topo_name]["elements/connectivity"];
n_bndry_conn.to_int_array(n_bndry_conn_conv);
bndry_indices = (n_bndry_conn_conv).value();
}
num_bndry_ele =
n_bndry_topo["elements/connectivity"].dtype().number_of_elements();
num_bndry_ele = num_bndry_ele / num_idxs_per_bndry_ele;
bndry_indices = n_bndry_conn.value();
}
else
{
Node &(n_bndry_conn_conv) = n_conv["topologies/boundary/elements/connectivity"];
n_bndry_conn.to_int_array(n_bndry_conn_conv);
bndry_indices = (n_bndry_conn_conv).value();
}
num_bndry_ele =
n_bndry_topo["elements/connectivity"].dtype().number_of_elements();
num_bndry_ele = num_bndry_ele / num_idxs_per_bndry_ele;
}
else
{
@@ -642,17 +609,14 @@ ConduitDataCollection::BlueprintFieldToGridFunction(Mesh *mesh,
//---------------------------------------------------------------------------//
void
ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
Node &n_mesh,
const std::string &coordset_name,
const std::string &main_topology_name,
const std::string &boundary_topology_name)
Node &n_mesh)
{
int dim = mesh->SpaceDimension();
MFEM_ASSERT(dim >= 1 && dim <= 3, "invalid mesh dimension");
////////////////////////////////////////////
// Setup main coordset
// Setup main coordset "coords"
////////////////////////////////////////////
// Assumes mfem::Vertex has the layout of a double array.
@@ -664,40 +628,38 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
MFEM_ASSERT( ( stride == 3 * sizeof(double) ),
"Unexpected stride for Vertex");
Node &n_mesh_coords = n_mesh["coordsets"][coordset_name];
n_mesh_coords["type"] = "explicit";
n_mesh["coordsets/coords/type"] = "explicit";
double *coords_ptr = mesh->GetVertex(0);
n_mesh_coords["values/x"].set_external(coords_ptr,
num_vertices,
0,
stride);
n_mesh["coordsets/coords/values/x"].set_external(coords_ptr,
num_vertices,
0,
stride);
if (dim >= 2)
{
n_mesh_coords["values/y"].set_external(coords_ptr,
num_vertices,
sizeof(double),
stride);
n_mesh["coordsets/coords/values/y"].set_external(coords_ptr,
num_vertices,
sizeof(double),
stride);
}
if (dim >= 3)
{
n_mesh_coords["values/z"].set_external(coords_ptr,
num_vertices,
sizeof(double) * 2,
stride);
n_mesh["coordsets/coords/values/z"].set_external(coords_ptr,
num_vertices,
sizeof(double) * 2,
stride);
}
////////////////////////////////////////////
// Setup main topo
// Setup main topo "main"
////////////////////////////////////////////
Node &n_topo = n_mesh["topologies"][main_topology_name];
Node &n_topo = n_mesh["topologies/main"];
n_topo["type"] = "unstructured";
n_topo["coordset"] = coordset_name;
n_topo["coordset"] = "coords";
Element::Type ele_type = static_cast<Element::Type>(mesh->GetElement(
0)->GetType());
@@ -740,8 +702,7 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
if (gf_mesh_nodes != NULL)
{
GridFunctionToBlueprintField(gf_mesh_nodes,
n_mesh["fields/mesh_nodes"],
main_topology_name);
n_mesh["fields/mesh_nodes"]);
}
////////////////////////////////////////////
@@ -751,7 +712,7 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
Node &n_mesh_att = n_mesh["fields/element_attribute"];
n_mesh_att["association"] = "element";
n_mesh_att["topology"] = main_topology_name;
n_mesh_att["topology"] = "main";
n_mesh_att["values"].set(DataType::c_int(num_ele));
int_array att_vals = n_mesh_att["values"].value();
@@ -767,12 +728,10 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
// guard vs if we have boundary elements
if (mesh->GetNBE() > 0)
{
n_topo["boundary_topology"] = boundary_topology_name;
Node &n_bndry_topo = n_mesh["topologies"][boundary_topology_name];
Node &n_bndry_topo = n_mesh["topologies/boundary"];
n_bndry_topo["type"] = "unstructured";
n_bndry_topo["coordset"] = coordset_name;
n_bndry_topo["coordset"] = "coords";
Element::Type bndry_ele_type = static_cast<Element::Type>(mesh->GetBdrElement(
0)->GetType());
@@ -808,7 +767,7 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
Node &n_bndry_mesh_att = n_mesh["fields/boundary_attribute"];
n_bndry_mesh_att["association"] = "element";
n_bndry_mesh_att["topology"] = boundary_topology_name;
n_bndry_mesh_att["topology"] = "boundary";
n_bndry_mesh_att["values"].set(DataType::c_int(num_bndry_ele));
int_array bndry_att_vals = n_bndry_mesh_att["values"].value();
@@ -822,11 +781,10 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
//---------------------------------------------------------------------------//
void
ConduitDataCollection::GridFunctionToBlueprintField(mfem::GridFunction *gf,
Node &n_field,
const std::string &main_topology_name)
Node &n_field)
{
n_field["basis"] = gf->FESpace()->FEColl()->Name();
n_field["topology"] = main_topology_name;
n_field["topology"] = "main";
int vdim = gf->FESpace()->GetVDim();
int ndofs = gf->FESpace()->GetNDofs();
+9 -25
View File
@@ -148,25 +148,17 @@ public:
Zero-copies as much data as possible.
@a coordset_name, @a main_topology_name, and @a boundary_topology_name
control the names used for the mesh blueprint entries.
With the default set of names, this method describes the mesh's
coordinates with a coordinate set entry named `coords`. Describes the
mesh with a topology entry named 'main'. If the mesh has nodes, these
are described in a field entry named `mesh_nodes`. If the mesh has an
attribute field, this is described in a field entry named
`mesh_attribute`.
Describes the mesh's coordinates with a coordinate set entry named
`coords`. Describes the mesh with a topology entry named 'main'. If the
mesh has nodes, these are described in a field entry named
`mesh_nodes`. If the mesh has an attribute field, this is described in a
field entry named `mesh_attribute`.
If the mesh has boundary info, this is described in a topology entry
named `boundary`. If the boundary has an attribute field, this is
described in a field entry named `boundary_attribute`.
*/
static void MeshToBlueprintMesh(Mesh *m,
conduit::Node &out,
const std::string &coordset_name = "coords",
const std::string &main_topology_name = "main",
const std::string &boundary_topology_name = "boundary");
static void MeshToBlueprintMesh(Mesh *m, conduit::Node &out);
/// Describes a MFEM grid function using the mesh blueprint
/** Sets up passed conduit::Node out to describe the given grid function
@@ -174,26 +166,18 @@ public:
Zero-copies as much data as possible.
@a main_toplogy_name is used to set the associated topology name.
With the default setting, the resulting field is associated with the
topology `main`.
The resulting field is associated with the topology `main`.
*/
static void GridFunctionToBlueprintField(GridFunction *gf,
conduit::Node &out,
const std::string &main_topology_name = "main");
static void GridFunctionToBlueprintField(GridFunction *gf, conduit::Node &out);
/// Constructs and MFEM mesh from a Conduit Blueprint Description
/** @a main_topology_name is used to select which topology to use, when
empty ("") the first topology entry will be used.
If zero_copy == true, tries to construct a mesh that points to the data
/** If zero_copy == true, tries to construct a mesh that points to the data
described by the conduit node. This is only possible if the data in the
node matches the data types needed for the MFEM API (ints for
connectivity, doubles for field values, etc). If these constraints are
not met, a mesh that owns the data is created and returned.
*/
static Mesh *BlueprintMeshToMesh(const conduit::Node &n_mesh,
const std::string &main_toplogy_name = "",
bool zero_copy = false);
/// Constructs and MFEM Grid Function from a Conduit Blueprint Description
+1337
View File
File diff suppressed because it is too large Load Diff
+14 -49
View File
@@ -10,7 +10,6 @@
// Software Foundation) version 2.1 dated February 1999.
#include "fem.hpp"
#include "../mesh/nurbs.hpp"
#include "../general/text.hpp"
#include "picojson.h"
@@ -332,25 +331,6 @@ DataCollection::~DataCollection()
// class VisItDataCollection implementation
void VisItDataCollection::UpdateMeshInfo()
{
if (mesh)
{
spatial_dim = mesh->SpaceDimension();
topo_dim = mesh->Dimension();
if (mesh->NURBSext)
{
visit_levels_of_detail =
std::max(visit_levels_of_detail, mesh->NURBSext->GetOrder());
}
}
else
{
spatial_dim = 0;
topo_dim = 0;
}
}
VisItDataCollection::VisItDataCollection(const std::string& collection_name,
Mesh *mesh)
: DataCollection(collection_name, mesh)
@@ -358,10 +338,17 @@ VisItDataCollection::VisItDataCollection(const std::string& collection_name,
appendRankToFileName = true; // always include rank in file names
cycle = 0; // always include cycle in directory names
visit_levels_of_detail = 1;
if (mesh)
{
spatial_dim = mesh->SpaceDimension();
topo_dim = mesh->Dimension();
}
else
{
spatial_dim = 0;
topo_dim = 0;
}
visit_max_levels_of_detail = 32;
UpdateMeshInfo();
}
#ifdef MFEM_USE_MPI
@@ -375,11 +362,9 @@ VisItDataCollection::VisItDataCollection(MPI_Comm comm,
MPI_Comm_size(comm, &num_procs);
appendRankToFileName = true; // always include rank in file names
cycle = 0; // always include cycle in directory names
visit_levels_of_detail = 1;
spatial_dim = 0;
topo_dim = 0;
visit_max_levels_of_detail = 32;
UpdateMeshInfo();
}
#endif
@@ -387,7 +372,8 @@ void VisItDataCollection::SetMesh(Mesh *new_mesh)
{
DataCollection::SetMesh(new_mesh);
appendRankToFileName = true;
UpdateMeshInfo();
spatial_dim = mesh->SpaceDimension();
topo_dim = mesh->Dimension();
}
#ifdef MFEM_USE_MPI
@@ -406,26 +392,6 @@ void VisItDataCollection::RegisterField(const std::string& name,
{
DataCollection::RegisterField(name, gf);
field_info_map[name] = VisItFieldInfo("nodes", gf->VectorDim());
int LOD = 1;
if (gf->FESpace()->GetNURBSext())
{
LOD = gf->FESpace()->GetNURBSext()->GetOrder();
}
else
{
for (int e=0; e<gf->FESpace()->GetNE() ; e++)
{
LOD = std::max(LOD,gf->FESpace()->GetFE(e)->GetOrder());
}
}
visit_levels_of_detail = std::max(visit_levels_of_detail, LOD);
}
void VisItDataCollection::SetLevelsOfDetail(int levels_of_detail)
{
visit_levels_of_detail = levels_of_detail;
}
void VisItDataCollection::SetMaxLevelsOfDetail(int max_levels_of_detail)
@@ -629,7 +595,6 @@ std::string VisItDataCollection::GetVisItRootString()
{
ftags["assoc"] = picojson::value((it->second).association);
ftags["comps"] = picojson::value(to_string((it->second).num_components));
ftags["lod"] = picojson::value(to_string(visit_levels_of_detail));
field["path"] = picojson::value(path_str + it->first + file_ext_format);
field["tags"] = picojson::value(ftags);
fields[it->first] = picojson::value(field);
-6
View File
@@ -398,7 +398,6 @@ protected:
// Additional data needed in the VisIt root file, which describes the mesh
// and all the fields in the collection
int spatial_dim, topo_dim;
int visit_levels_of_detail;
int visit_max_levels_of_detail;
std::map<std::string, VisItFieldInfo> field_info_map;
typedef std::map<std::string, VisItFieldInfo>::iterator FieldInfoMapIterator;
@@ -408,8 +407,6 @@ protected:
/// Read in a VisIt root file in JSON format
void ParseVisItRootString(const std::string& json);
void UpdateMeshInfo();
// Helper functions for Load()
void LoadVisItRootFile(const std::string& root_name);
void LoadMesh();
@@ -440,9 +437,6 @@ public:
/// Add a grid function to the collection and update the root file
virtual void RegisterField(const std::string& field_name, GridFunction *gf);
/// Set VisIt parameter: default levels of detail for the MultiresControl
void SetLevelsOfDetail(int levels_of_detail);
/// Set VisIt parameter: maximum levels of detail for the MultiresControl
void SetMaxLevelsOfDetail(int max_levels_of_detail);
+760
View File
@@ -0,0 +1,760 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
//This file contains useful functions to compute fluxes for DG methods.
#include <vector>
#include "fem.hpp"
#include "dalg.hpp"
using std::vector;
using std::pair;
namespace mfem
{
/**
* Returns the canonical coordinate vectors e_1 and e_2.
*/
void getBaseVector2D(Vector& e1, Vector& e2)
{
e1.SetSize(2);
e1(0) = 1;
e1(1) = 0;
e2.SetSize(2);
e2(0) = 0;
e2(1) = 1;
}
/**
* Returns the canonical coordinate vectors e_1, e_2 and e_3.
*/
void getBaseVector3D(Vector& e1, Vector& e2, Vector& e3)
{
e1.SetSize(3);
e1(0) = 1;
e1(1) = 0;
e1(2) = 0;
e2.SetSize(3);
e2(0) = 0;
e2(1) = 1;
e2(2) = 0;
e3.SetSize(3);
e3(0) = 0;
e3(1) = 0;
e3(2) = 1;
}
/**
* A function that initialize the local coordinate base for a face with
* indice face_ind.
* This returns the local face coordinate base expressed in reference
* element coordinate.
*/
// Highly dependent of the node ordering from geom.cpp
void InitFaceCoord2D(const int face_id, IntMatrix& base)
{
//Vector e1,e2;
//getBaseVector2D(e1,e2);
base.Zero();
switch(face_id)
{
case 0://SOUTH
base(0,0)= 1;//base.SetCol(0, e1);
base(1,1)=-1;//base.SetCol(1,-e2);
break;
case 1://EAST
base(1,0)= 1;//base.SetCol(0, e2);
base(0,1)= 1;//base.SetCol(1, e1);
break;
case 2://NORTH
base(0,0)=-1;//base.SetCol(0,-e1);
base(1,1)= 1;//base.SetCol(1, e2);
break;
case 3://WEST
base(1,0)=-1;//base.SetCol(0,-e2);
base(0,1)= 1;//base.SetCol(1, e1);
break;
default:
mfem_error("The face_ind exceeds the number of faces in this dimension.");
break;
}
}
// Highly dependent of the node ordering from geom.cpp
void InitFaceCoord3D(const int face_id, IntMatrix& base)
{
//Vector e1,e2,e3;
//getBaseVector3D(e1,e2,e3);
base.Zero();
switch(face_id)
{
case 0://BOTTOM
base(0,0)= 1;//base.SetCol(0, e1);
base(1,1)=-1;//base.SetCol(1,-e2);
base(2,2)=-1;//base.SetCol(2,-e3);
break;
case 1://SOUTH
base(0,0)= 1;//base.SetCol(0, e1);
base(2,1)= 1;//base.SetCol(1, e3);
base(1,2)=-1;//base.SetCol(2,-e2);
break;
case 2://EAST
base(1,0)= 1;//base.SetCol(0, e2);
base(2,1)= 1;//base.SetCol(1, e3);
base(0,2)= 1;//base.SetCol(2, e1);
break;
case 3://NORTH
base(0,0)=-1;//base.SetCol(0,-e1);
base(2,1)= 1;//base.SetCol(1, e3);
base(1,2)= 1;//base.SetCol(2, e2);
break;
case 4://WEST
base(1,0)=-1;//base.SetCol(0,-e2);
base(2,1)= 1;//base.SetCol(1, e3);
base(0,2)=-1;//base.SetCol(2,-e1);
break;
case 5://TOP
base(0,0)= 1;//base.SetCol(0, e1);
base(1,1)= 1;//base.SetCol(1, e2);
base(2,2)= 1;//base.SetCol(2, e3);
break;
default:
mfem_error("The face_ind exceeds the number of faces in this dimension.");
break;
}
}
/** Maps the coordinate vectors of the first face to the coordinate vectors of the second face.
* nb_rot is the number of rotation to opperate so that the first node of each face match.
* The result map contains pairs of int, where the first int is the cofficient, and the
* second int is the indice of the second face vector.
*/
// There shouldn't be any rotation in 2D.
void GetLocalCoordMap2D(vector<pair<int,int> >& map, const int nb_rot)
{
map.resize(2);
//First and second coordinate vectors should always be of opposite direction in 2D.
//TODO Maybe not
map[0] = pair<int,int>(-1,0);
map[1] = pair<int,int>(-1,1);
}
// Default parameter nb_rot=0 should be only use with a structured mesh.
// Rotations follow the ordering of the nodes.
/*void GetLocalCoordMap3D(vector<pair<int,int> >& map, const int nb_rot)
{
map.resize(3);
// Normal to the face are always of opposite direction
map[2] = pair<int,int>(-1,2);
// nb_rot determines how local coordinates are oriented from one face to the other.
// See case 2 for an example.
switch(nb_rot)
{
case 0:
map[0] = pair<int,int>( 1,1);
map[1] = pair<int,int>( 1,0);
break;
case 1:
map[0] = pair<int,int>(-1,0);
map[1] = pair<int,int>( 1,1);
break;
case 2:
//first vector equals -1 times the second vector of the other face coordinates
map[0] = pair<int,int>(-1,1);
//second vector equals -1 times the first vector of the other face coordinates
map[1] = pair<int,int>(-1,0);
break;
case 3:
map[0] = pair<int,int>( 1,0);
map[1] = pair<int,int>(-1,1);
break;
default:
mfem_error("There shouldn't be that many rotations.");
break;
}
}*/
void GetLocalCoordMap3D(vector< pair<int,int> >& map, const int orientation)
{
map.resize(3);
// orientation determines how local coordinates are oriented from one face to the other.
// See case 2 for an example.
switch(orientation)
{
case 0://{0, 1, 2, 3}
map[0] = pair<int,int>( 1,0);
map[1] = pair<int,int>( 1,1);
map[2] = pair<int,int>( 1,2);
break;
case 1://{0, 3, 2, 1}
map[0] = pair<int,int>( 1,1);
map[1] = pair<int,int>( 1,0);
map[2] = pair<int,int>(-1,2);
break;
case 2://{1, 2, 3, 0}
//first vector equals -1 times the second vector of the other face coordinates
map[0] = pair<int,int>(-1,1);
//second vector equals -1 times the first vector of the other face coordinates
map[1] = pair<int,int>( 1,0);
//third vector equals -1 times the third vector of the other face coordinates
map[2] = pair<int,int>( 1,2);
break;
case 3://{1, 0, 3, 2}
map[0] = pair<int,int>(-1,0);
map[1] = pair<int,int>( 1,1);
map[2] = pair<int,int>(-1,2);
break;
case 4://{2, 3, 0, 1}
map[0] = pair<int,int>(-1,0);
map[1] = pair<int,int>(-1,1);
map[2] = pair<int,int>( 1,2);
break;
case 5://{2, 1, 0, 3}
map[0] = pair<int,int>(-1,1);
map[1] = pair<int,int>(-1,0);
map[2] = pair<int,int>(-1,2);
break;
case 6://{3, 0, 1, 2}
map[0] = pair<int,int>( 1,1);
map[1] = pair<int,int>(-1,0);
map[2] = pair<int,int>( 1,2);
break;
case 7://{3, 2, 1, 0}
map[0] = pair<int,int>( 1,0);
map[1] = pair<int,int>(-1,1);
map[2] = pair<int,int>(-1,2);
break;
default:
mfem_error("There shouldn't be that many orientations.");
break;
}
}
/**
* Returns the change of matrix P from base_K2 to base_K1 according to the mapping map.
*/
void GetChangeOfBasis(const IntMatrix& base_K1, IntMatrix& base_K2,
const vector<pair<int,int> >& map, IntMatrix& P)
{
/* int dim = map.size();
for (int j = 0; j < dim; j++)
{
int i = 0;
//we look if the vector is colinear with e_j
// Can be replaced by base_K2(j,i)!=0
while (base_K2(j,i)!=0) i++;
int coeff = map[i].first;
int ind = map[i].second;
for (int k = 0; k < dim; ++k)
{
P(k,j) = coeff * base_K1(k,ind);
}
}*/
//TODO make it valid for 3D!!!
int dim = base_K1.Height();
// for (int i = 0; i < dim; ++i)
// {
// int coeff = map[i].first;
// int ind = map[i].second;
// for (int j = 0; j < dim; ++j)
// {
// int sum = 0;
// for (int k = 0; k < dim; ++k)
// {
// sum += coeff*base_K1(i,k)*base_K2(j,k);
// }
// P(ind,j) = sum;
// }
// }
int i,j,ind;
double coeff;
for (int n = 0; n < dim; ++n)
{
i = 0;
while( base_K1(i,n) == 0 ) ++i;
j = 0;
ind = map[n].second;
while( base_K2(j,ind) == 0 ) ++j;
coeff = map[n].first;
P(i,j) = coeff * base_K1(i,n) * base_K2(j,ind);
}
}
void GetChangeOfBasis2D(const int face_id1, const int face_id2, IntMatrix& P)
{
// We add 8 because of C++ stupid definition of modulo
int nb_rot = (8 + face_id2 - face_id1 - 2)%4;
// if (face_id2!=-1)
// {
// cout << "face_id1=" << face_id1 << ", face_id2=" << face_id2 << ", nb_rot=" << nb_rot << endl;
// }
P.Zero();
switch(nb_rot)
{
case 0://Id=R^4
P(0,0) = 1;
P(1,1) = 1;
break;
case 1://R
P(1,0) = 1;
P(0,1) =-1;
break;
case 2://R²
P(0,0) =-1;
P(1,1) =-1;
break;
case 3://R³
P(1,0) =-1;
P(0,1) = 1;
break;
default:mfem_error("C++ modulo error in GetChangeOfBasis2D");
}
}
void GetChangeOfBasis(const int permutation, IntMatrix& P)
{
int code1 = permutation/100;
int ind1 = code1/2;
int val1 = code1%2==0?-1:1;
int code2 = (permutation%100)/10;
int ind2 = code2/2;
int val2 = code2%2==0?-1:1;
int code3 = permutation%10;
int ind3 = code3/2;
int val3 = code3%2==0?-1:1;
P.Zero();
P(ind1,0) = val1;
P(ind2,1) = val2;
P(ind3,2) = val3;
}
/**
* Returns the face_id that identifies the face on the reference element, and nb_rot the
* "rotations" the face did between reference to physical spaces.
*/
void GetIdRotInfo(const int face_info, int& face_id, int& nb_rot){
int orientation = face_info % 64;
face_id = face_info / 64;
// Test if my understanding of mfem code is correct, error if not
//MFEM_ASSERT(orientation % 2 == 0, "Unexpected inside out face");
nb_rot = orientation;// / 2;
}
void GetFaceInfo(const Mesh* mesh, const int face, int& ind_elt1, int& ind_elt2, int& face_id1, int& face_id2, int& nb_rot1, int& nb_rot2)
{
// We collect the indices of the two elements on the face, element1 is the master element,
// the one that defines the normal to the face.
mesh->GetFaceElements(face,&ind_elt1,&ind_elt2);
int info_elt1, info_elt2;
// We collect the informations on the face for the two elements.
mesh->GetFaceInfos(face,&info_elt1,&info_elt2);
GetIdRotInfo(info_elt1,face_id1,nb_rot1);//nb_rot1 is always 0 by convention
GetIdRotInfo(info_elt2,face_id2,nb_rot2);
}
/**
* Returns the permutation id, so that we can permute dofs to be in a structured case.
*/
int Permutation2D(const int face_id_trial, const int face_id_test)
{
int perm = face_id_trial - face_id_test - 2;
perm = perm < 0 ? perm+4 : perm;
return perm;
}
/**
* Returns an integer that encrypts P.
*/
void Permutation3D(const int face_id1, const int face_id2, const int orientation, int& perm1, int& perm2)
{
IntMatrix K1(3,3);
K1.Zero();
InitFaceCoord3D(face_id1, K1);
IntMatrix K2(3,3);
K2.Zero();
InitFaceCoord3D(face_id2, K2);
vector< pair<int,int> > map;
GetLocalCoordMap3D(map, orientation);
IntMatrix P(3,3);
P.Zero();
GetChangeOfBasis(K1, K2, map, P);
// cout << "orientation=" << orientation << endl;
// cout << P(0,0) << ", " << P(0,1) << ", " << P(0,2) << endl;
// cout << P(1,0) << ", " << P(1,1) << ", " << P(1,2) << endl;
// cout << P(2,0) << ", " << P(2,1) << ", " << P(2,2) << endl;
perm1 = 0;
// Encrypts first column
perm1 += 100*(0*(P(0,0)==-1) + 1*(P(0,0)==1) + 2*(P(1,0)==-1) + 3*(P(1,0)==1) + 4*(P(2,0)==-1) + 5*(P(2,0)==1));
// Encrypts second column
perm1 += 10 *(0*(P(0,1)==-1) + 1*(P(0,1)==1) + 2*(P(1,1)==-1) + 3*(P(1,1)==1) + 4*(P(2,1)==-1) + 5*(P(2,1)==1));
// Encrypts third column
perm1 += (0*(P(0,2)==-1) + 1*(P(0,2)==1) + 2*(P(1,2)==-1) + 3*(P(1,2)==1) + 4*(P(2,2)==-1) + 5*(P(2,2)==1));
// Encrypts the transposed permutation matrix in a second integer.
perm2 = 0;
perm2 += 100*(0*(P(0,0)==-1) + 1*(P(0,0)==1) + 2*(P(0,1)==-1) + 3*(P(0,1)==1) + 4*(P(0,2)==-1) + 5*(P(0,2)==1));
perm2 += 10 *(0*(P(1,0)==-1) + 1*(P(1,0)==1) + 2*(P(1,1)==-1) + 3*(P(1,1)==1) + 4*(P(1,2)==-1) + 5*(P(1,2)==1));
perm2 += (0*(P(2,0)==-1) + 1*(P(2,0)==1) + 2*(P(2,1)==-1) + 3*(P(2,1)==1) + 4*(P(2,2)==-1) + 5*(P(2,2)==1));
}
void GetPermutation(const int dim, const int face_id1, const int face_id2, const int orientation, int& perm1, int& perm2)
{
switch(dim){
case 1:
mfem_error("Not yet implemented");
break;
case 2:
perm1 = Permutation2D(face_id1, face_id2);
perm2 = Permutation2D(face_id2, face_id1);
break;
case 3:
Permutation3D(face_id1, face_id2, orientation, perm1, perm2);
break;
default:
mfem_error("Dimension of the problem too high.");
break;
}
}
/**
* Hardcoded permutation due to arbitrary hardcoded orientation in geom.cpp.
* Will break if geom.cpp changes.
* This function could be improved by returning the 'permutation' parameters once,
* instead of recomputing them for every quadrature point...
*/
int GetFaceQuadIndex3D(const int face_id, const int orientation, const int qind, const int quads, Tensor<1,int>& ind_f)
{
// cout << "orientation=" << orientation << endl;
int& k1 = ind_f(0);
int& k2 = ind_f(1);
int kf1,kf2;
kf1 = qind%quads;
kf2 = qind/quads;
switch(face_id)
{
case 0://BOTTOM
switch(orientation)
{
case 0://{0, 1, 2, 3}
k1 = kf1;
k2 = quads-1-kf2;
break;
case 1://{0, 3, 2, 1}
k1 = quads-1-kf2;
k2 = kf1;
break;
case 2://{1, 2, 3, 0}
k1 = quads-1-kf2;
k2 = quads-1-kf1;
break;
case 3://{1, 0, 3, 2}
k1 = quads-1-kf1;
k2 = quads-1-kf2;
break;
case 4://{2, 3, 0, 1}
k1 = quads-1-kf1;
k2 = kf2;
break;
case 5://{2, 1, 0, 3}
k1 = kf2;
k2 = quads-1-kf1;
break;
case 6://{3, 0, 1, 2}
k1 = kf2;
k2 = kf1;
break;
case 7://{3, 2, 1, 0}
k1 = kf1;
k2 = kf2;
break;
default:
mfem_error("This orientation does not exist in 3D");
break;
}
break;
case 1://SOUTH
switch(orientation)
{
case 0://{0, 1, 2, 3}
k1 = kf1;
k2 = kf2;
break;
case 1://{0, 3, 2, 1}
k1 = kf2;
k2 = kf1;
break;
case 2://{1, 2, 3, 0}
k1 = kf2;
k2 = quads-1-kf1;
break;
case 3://{1, 0, 3, 2}
k1 = quads-1-kf1;
k2 = kf2;
break;
case 4://{2, 3, 0, 1}
k1 = quads-1-kf1;
k2 = quads-1-kf2;
break;
case 5://{2, 1, 0, 3}
k1 = quads-1-kf2;
k2 = quads-1-kf1;
break;
case 6://{3, 0, 1, 2}
k1 = quads-1-kf2;
k2 = kf1;
break;
case 7://{3, 2, 1, 0}
k1 = kf1;
k2 = quads-1-kf2;
break;
default:
mfem_error("This orientation does not exist in 3D");
break;
}
break;
case 2://EAST
switch(orientation)
{
case 0://{0, 1, 2, 3}
k1 = kf1;
k2 = kf2;
break;
case 1://{0, 3, 2, 1}
k1 = kf2;
k2 = kf1;
break;
case 2://{1, 2, 3, 0}
k1 = kf2;
k2 = quads-1-kf1;
break;
case 3://{1, 0, 3, 2}
k1 = quads-1-kf1;
k2 = kf2;
break;
case 4://{2, 3, 0, 1}
k1 = quads-1-kf1;
k2 = quads-1-kf2;
break;
case 5://{2, 1, 0, 3}
k1 = quads-1-kf2;
k2 = quads-1-kf1;
break;
case 6://{3, 0, 1, 2}
k1 = quads-1-kf2;
k2 = kf1;
break;
case 7://{3, 2, 1, 0}
k1 = kf1;
k2 = quads-1-kf2;
break;
default:
mfem_error("This orientation does not exist in 3D");
break;
}
break;
case 3://NORTH
switch(orientation)
{
case 0://{0, 1, 2, 3}
k1 = quads-1-kf1;
k2 = kf2;
break;
case 1://{0, 3, 2, 1}
k1 = kf2;
k2 = quads-1-kf1;
break;
case 2://{1, 2, 3, 0}
k1 = kf2;
k2 = kf1;
break;
case 3://{1, 0, 3, 2}
k1 = kf1;
k2 = kf2;
break;
case 4://{2, 3, 0, 1}
k1 = kf1;
k2 = quads-1-kf2;
break;
case 5://{2, 1, 0, 3}
k1 = quads-1-kf2;
k2 = kf1;
break;
case 6://{3, 0, 1, 2}
k1 = quads-1-kf2;
k2 = quads-1-kf1;
break;
case 7://{3, 2, 1, 0}
k1 = quads-1-kf1;
k2 = quads-1-kf2;
break;
default:
mfem_error("This orientation does not exist in 3D");
break;
}
break;
case 4://WEST
switch(orientation)
{
case 0://{0, 1, 2, 3}
k1 = quads-1-kf1;
k2 = kf2;
break;
case 1://{0, 3, 2, 1}
k1 = kf2;
k2 = quads-1-kf1;
break;
case 2://{1, 2, 3, 0}
k1 = kf2;
k2 = kf1;
break;
case 3://{1, 0, 3, 2}
k1 = kf1;
k2 = kf2;
break;
case 4://{2, 3, 0, 1}
k1 = kf1;
k2 = quads-1-kf2;
break;
case 5://{2, 1, 0, 3}
k1 = quads-1-kf2;
k2 = kf1;
break;
case 6://{3, 0, 1, 2}
k1 = quads-1-kf2;
k2 = quads-1-kf1;
break;
case 7://{3, 2, 1, 0}
k1 = quads-1-kf1;
k2 = quads-1-kf2;
break;
default:
mfem_error("This orientation does not exist in 3D");
break;
}
break;
case 5://TOP
switch(orientation)
{
case 0://{0, 1, 2, 3}
k1 = kf1;
k2 = kf2;
break;
case 1://{0, 3, 2, 1}
k1 = kf2;
k2 = kf1;
break;
case 2://{1, 2, 3, 0}
k1 = kf2;
k2 = quads-1-kf1;
break;
case 3://{1, 0, 3, 2}
k1 = quads-1-kf1;
k2 = kf2;
break;
case 4://{2, 3, 0, 1}
k1 = quads-1-kf1;
k2 = quads-1-kf2;
break;
case 5://{2, 1, 0, 3}
k1 = quads-1-kf2;
k2 = quads-1-kf1;
break;
case 6://{3, 0, 1, 2}
k1 = quads-1-kf2;
k2 = kf1;
break;
case 7://{3, 2, 1, 0}
k1 = kf1;
k2 = quads-1-kf2;
break;
default:
mfem_error("This orientation does not exist in 3D");
break;
}
break;
default:
mfem_error("This face_id does not exist in 3D");
break;
}
return k1 + quads*k2;
}
int GetFaceQuadIndex(const int dim, const int face_id, const int orientation, const int qind, const int quads, Tensor<1,int>& ind_f)
{
int res = 0;
switch(dim)
{
case 1:
break;
case 2:
if(face_id<=1){//SOUTH or EAST (canonical ordering)
res = ind_f(0) = qind;
}else{//NORTH or WEST (counter-canonical ordering)
res = ind_f(0) = quads-1-qind;
}
break;
case 3:
res = GetFaceQuadIndex3D(face_id, orientation, qind, quads, ind_f);
break;
default:
mfem_error("Dimension too high.");
break;
}
return res;
}
const int GetGlobalQuadIndex(const int dim, const int face_id, const int quads, Tensor<1,int>& ind_f)
{
switch(dim)
{
case 1:
if (face_id==0)//WEST
{
return 0;
}else{//EAST
return quads-1;
}
case 2:
switch(face_id)
{
case 0://SOUTH
return ind_f(0);
case 1://EAST
return quads-1 + ind_f(0)*quads;
case 2://NORTH
return ind_f(0) + (quads-1)*quads;
case 3://WEST
return ind_f(0)*quads;
}
case 3:
switch(face_id)
{
case 0://BOTTOM
return ind_f(0) + ind_f(1)*quads;
case 1://SOUTH
return ind_f(0) + ind_f(1)*quads*quads;
case 2://EAST
return (quads-1) + ind_f(0)*quads + ind_f(1)*quads*quads;
case 3://NORTH
return ind_f(0) + (quads-1)*quads + ind_f(1)*quads*quads;
case 4://WEST
return ind_f(0)*quads + ind_f(1)*quads*quads;
case 5://TOP
return ind_f(0) + ind_f(1)*quads + (quads-1)*quads*quads;
}
default:
mfem_error("Dimension too high.");
break;
}
return -1;
}
}
+119
View File
@@ -0,0 +1,119 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
//This file contains useful functions to compute fluxes for DG methods.
#ifndef MFEM_DGFACEFUNC
#define MFEM_DGFACEFUNC
#include "dalg.hpp"
using std::vector;
using std::pair;
namespace mfem
{
/**
* Returns the canonical coordinate vectors e_1 and e_2.
*/
void getBaseVector2D(Vector& e1, Vector& e2);
/**
* Returns the canonical coordinate vectors e_1, e_2 and e_3.
*/
void getBaseVector3D(Vector& e1, Vector& e2, Vector& e3);
/** A function that initialize the local coordinate base for a face with
* indice face_ind.
* This returns the local face coordinate base expressed in reference
* element coordinate.
*/
// Highly dependent of the node ordering from geom.cpp
void InitFaceCoord2D(const int face_id, IntMatrix& base);
// Highly dependent of the node ordering from geom.cpp
void InitFaceCoord3D(const int face_id, IntMatrix& base);
/** Maps the coordinate vectors of the first face to the coordinate vectors of the second face.
* nb_rot is the number of rotation to opperate so that the first node of each face match.
* The result map contains pairs of int, where the first int is a direction cofficient,
* and the second int is the indice of the second face vector.
*/
// There shouldn't be any rotation in 2D.
void GetLocalCoordMap2D(vector<pair<int,int> >& map, const int nb_rot = 0);
// Rotations follow the ordering of the nodes.
void GetLocalCoordMap3D(vector<pair<int,int> >& map, const int nb_rot);
/**
* Returns the change of matrix P from base_K2 to base_K1 according to the mapping map.
*/
void GetChangeOfBasis(const IntMatrix& base_K1, IntMatrix& base_K2,
const vector<pair<int,int> >& map, IntMatrix& P);
void GetChangeOfBasis(const int permutation, IntMatrix& P);
/**
* Returns the change of coordinate from second element to first element on a 2D face.
*/
void GetChangeOfBasis2D(const int face_id1, const int face_id2, IntMatrix& P);
/**
* Returns the indices, face ID, and number of rotations, of the two element sharing a face.
* The number of rotations is relative to the element 1, so nb_rot1 is always 0.
*/
void GetFaceInfo(const Mesh* mesh, const int face,
int& ind_elt1, int& ind_elt2,
int& face_id1, int& face_id2,
int& nb_rot1, int& nb_rot2);
/**
* Returns the face_id that identifies the face on the reference element, and nb_rot the
* "rotations" the face did between reference to physical spaces.
*/
void GetIdRotInfo(const int face_info, int& face_id, int& nb_rot);
/**
* Returns an integer identifying the permutation to apply to be in structured-
* like configuration for 2D hex meshes.
*/
int Permutation2D(const int face_id_trial, const int face_id_test);
/**
* Returns an integer identifying the permutation to apply to be in structured-
* like configuration for 3D hex meshes.
*/
void Permutation3D(const int face_id1, const int face_id2, const int orientation, int& perm1, int& perm2);
/**
* Returns an integer identifying the permutation to apply to be in structured-
* like configuration.
*/
void GetPermutation(const int dim, const int face_id1, const int face_id2, const int orientation, int& perm1, int& perm2);
int GetFaceQuadIndex3D(const int face_id, const int orientation, const int qind, const int quads, Tensor<1,int>& ind_f);
/**
* Returns the indices of a quadrature point on the face of an hex element relative to the index of the quadrature
* point on the reference face.
*/
int GetFaceQuadIndex(const int dim, const int face_id, const int orientation, const int qind, const int quads, Tensor<1,int>& ind_f);
/**
* Returns the indices of a quadrature point on the element relative to the index of the quadrature
* point on the reference face.
*/
const int GetGlobalQuadIndex(const int dim, const int face_id, const int quads, Tensor<1,int>& ind_f);
}
#endif // MFEM_DGFACEFUNC
+174
View File
@@ -0,0 +1,174 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// This file contains a prototype version for Discontinuous Galerkin Partial assembly
#ifndef MFEM_DGPABILININTEG
#define MFEM_DGPABILININTEG
#include "../config/config.hpp"
#include "bilininteg.hpp"
#include "dalg.hpp"
#include "fem.hpp"
#include <cmath>
#include <algorithm>
#include "../linalg/vector.hpp"
namespace mfem
{
/**
* The different operators available for the Kernels
*/
enum PAOp { BtDB, BtDG, GtDB, GtDG };
/**
* A class that describes the Convection Equation using DG for Partial Assembly.
*/
class DGConvectionEquation
{
public:
/**
* Defines the Kernel to apply to the Domain
*/
static const PAOp OpName = BtDG;
/**
* Defines the variables needed to build D for the Domain kernel
*/
struct Args {
Args(VectorCoefficient& _q, double _a = 1.0, double _b = -1.0) : q(_q), a(_a), b(_b) {}
VectorCoefficient& q;
double a;
double b;
};
/**
* Returns the values of the D tensor at a given integration Point.
*/
void evalD(Tensor<1>& res, ElementTransformation *Tr, const IntegrationPoint& ip,
const Args& args)
{
const int dim = res.size(0);
Vector qvec(dim);
const DenseMatrix& locD = Tr->AdjugateJacobian();
args.q.Eval(qvec, *Tr, ip);
for (int i = 0; i < dim; ++i)
{
double val = 0.0;
for (int j = 0; j < dim; ++j)
{
val += locD(i,j) * qvec(j);
}
res(i) = ip.weight * args.a * val;
}
}
/**
* Returns the values of the D tensor at a given integration Point.
*/
void evalD(Tensor<1>& res, ElementTransformation *Tr, const IntegrationPoint& ip,
const Tensor<2>& Jac, const Args& args)
{
const int dim = res.size(0);
Vector qvec(dim);
args.q.Eval(qvec, *Tr, ip);
Tensor<2> Adj(dim,dim);
adjugate(Jac,Adj);
for (int i = 0; i < dim; ++i)
{
double val = 0.0;
for (int j = 0; j < dim; ++j)
{
val += Adj(i,j) * qvec(j);
}
res(i) = ip.weight * args.a * val;
}
}
/**
* Defines the Kernel to apply to the Faces
*/
static const PAOp FaceOpName = BtDB;
/**
* Returns the values of the Dint and Dext tensors at a given integration Point for
* each element over a face.
*/
void evalFaceD(double& res11, double& res21, double& res22, double& res12,
const FaceElementTransformations* face_tr, const Vector& normal,
const IntegrationPoint& ip1, const IntegrationPoint& ip2,
const Args& args)
{
const int dim = normal.Size();
Vector qvec(dim);
// FIXME: qvec might be discontinuous if not constant with a periodic mesh
// We should then use the evaluation on Elem2 and eip2
args.q.Eval( qvec, *(face_tr->Elem1), ip1 );
const double res = qvec * normal;
const double a = -args.a, b = args.b;
res11 = ip1.weight * ( a/2 * res + b * abs(res) );
res21 = ip1.weight * ( a/2 * res - b * abs(res) );
res22 = ip1.weight * ( - a/2 * res + b * abs(res) );
res12 = ip1.weight * ( - a/2 * res - b * abs(res) );
}
void evalFaceD(double& res11, double& res21, double& res22, double& res12,
const FaceElementTransformations* face_tr, const Vector& normal,
const IntegrationPoint& ip1, const IntegrationPoint& ip2,
const Tensor<2>& Jac1, const Tensor<2>& Jac2,
const Args& args)
{
const int dim = normal.Size();
Vector qvec(dim);
// FIXME: qvec might be discontinuous if not constant with a periodic mesh
// We should then use the evaluation on Elem2 and eip2
args.q.Eval( qvec, *(face_tr->Elem1), ip1 );
const double res = qvec * normal;
const double a = -args.a, b = args.b;
res11 = ip1.weight * ( a/2 * res + b * abs(res) );
res21 = ip1.weight * ( a/2 * res - b * abs(res) );
res22 = ip1.weight * ( - a/2 * res + b * abs(res) );
res12 = ip1.weight * ( - a/2 * res - b * abs(res) );
}
};
class MassEquation
{
public:
static const PAOp OpName = BtDB;
struct ArgsEmpty{};
void evalD(double& res, ElementTransformation* Tr, const IntegrationPoint& ip,
const Tensor<2>& Jac, ArgsEmpty args = {})
{
res = ip.weight * det(Jac);
}
struct ArgsCoeff
{
Coefficient& coeff;
};
void evalD(double& res, ElementTransformation* Tr, const IntegrationPoint& ip,
const Tensor<2>& Jac, ArgsCoeff& args)
{
res = args.coeff.Eval(*Tr, ip) * ip.weight * det(Jac);
}
};
}
#endif //MFEM_DGPABILININTEG
File diff suppressed because it is too large Load Diff
+1347
View File
File diff suppressed because it is too large Load Diff
-114
View File
@@ -6598,34 +6598,6 @@ void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d)
}
}
void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d,
double *dd)
{
// recursive definition, z in [-1,1]
// T_0(z) = 1, T_1(z) = z
// T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z)
// T'_n(z) = n*U_{n-1}(z)
// U_0(z) = 1 U_1(z) = 2*z
// U_{n+1}(z) = 2*z*U_n(z) - U_{n-1}(z)
// U_n(z) = z*U_{n-1}(z) + T_n(z) = z*T'_n(z)/n + T_n(z)
// T'_{n+1}(z) = (n + 1)*(z*T'_n(z)/n + T_n(z))
// T''_{n+1}(z) = (n + 1)*(2*(n + 1)*T'_n(z) + z*T''_n(z)) / n
double z;
u[0] = 1.;
d[0] = 0.;
dd[0]= 0.;
if (p == 0) { return; }
u[1] = z = 2.*x - 1.;
d[1] = 2.;
dd[1] = 0;
for (int n = 1; n < p; n++)
{
u[n+1] = 2*z*u[n] - u[n-1];
d[n+1] = (n + 1)*(z*d[n]/n + 2*u[n]);
dd[n+1] = (n + 1)*(2.*(n + 1)*d[n] + z*dd[n])/n;
}
}
const double *Poly_1D::GetPoints(const int p, const int btype)
{
BasisType::Check(btype);
@@ -7491,12 +7463,8 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype)
dshape_x.SetSize(p + 1);
dshape_y.SetSize(p + 1);
dshape_l.SetSize(p + 1);
ddshape_x.SetSize(p + 1);
ddshape_y.SetSize(p + 1);
ddshape_l.SetSize(p + 1);
u.SetSize(Dof);
du.SetSize(Dof, Dim);
ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2 );
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
#endif
@@ -7600,38 +7568,6 @@ void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip,
Ti.Mult(du, dshape);
}
void H1_TriangleElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const
{
const int p = Order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_l(p + 1);
DenseMatrix ddu(Dof, Dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y);
poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l, dshape_l, ddshape_l);
for (int o = 0, j = 0; j <= p; j++)
for (int i = 0; i + j <= p; i++)
{
int k = p - i - j;
// u_xx, u_xy, u_yy
ddu(o,0) = ((ddshape_x(i) * shape_l(k)) - 2. * (dshape_x(i) * dshape_l(k)) +
(shape_x(i) * ddshape_l(k))) * shape_y(j);
ddu(o,1) = (((shape_x(i) * ddshape_l(k)) - dshape_x(i) * dshape_l(k)) * shape_y(
j)) + (((dshape_x(i) * shape_l(k)) - (shape_x(i) * dshape_l(k))) * dshape_y(j));
ddu(o,2) = ((ddshape_y(j) * shape_l(k)) - 2. * (dshape_y(j) * dshape_l(k)) +
(shape_y(j) * ddshape_l(k))) * shape_x(i);
o++;
}
Ti.Mult(ddu, ddshape);
}
H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::TETRAHEDRON, ((p + 1)*(p + 2)*(p + 3))/6,
@@ -7648,13 +7584,8 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
dshape_y.SetSize(p + 1);
dshape_z.SetSize(p + 1);
dshape_l.SetSize(p + 1);
ddshape_x.SetSize(p + 1);
ddshape_y.SetSize(p + 1);
ddshape_z.SetSize(p + 1);
ddshape_l.SetSize(p + 1);
u.SetSize(Dof);
du.SetSize(Dof, Dim);
ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2);
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
#endif
@@ -7807,51 +7738,6 @@ void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip,
Ti.Mult(du, dshape);
}
void H1_TetrahedronElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const
{
const int p = Order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_l(p + 1);
DenseMatrix ddu(Dof, ((Dim + 1) * Dim) / 2);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y);
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z, ddshape_z);
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l, dshape_l, ddshape_l);
for (int o = 0, k = 0; k <= p; k++)
for (int j = 0; j + k <= p; j++)
for (int i = 0; i + j + k <= p; i++)
{
// u_xx, u_xy, u_xz, u_yy, u_yz, u_zz
int l = p - i - j - k;
ddu(o,0) = ((ddshape_x(i) * shape_l(l)) - 2. * (dshape_x(i) * dshape_l(l)) +
(shape_x(i) * ddshape_l(l))) * shape_y(j) * shape_z(k);
ddu(o,1) = ((dshape_y(j) * ((dshape_x(i) * shape_l(l)) -
(shape_x(i) * dshape_l(l)))) +
(shape_y(j) * ((ddshape_l(l) * shape_x(i)) -
(dshape_x(i) * dshape_l(l)))))* shape_z(k);
ddu(o,2) = ((dshape_z(k) * ((dshape_x(i) * shape_l(l)) -
(shape_x(i) * dshape_l(l)))) +
(shape_z(k) * ((ddshape_l(l) * shape_x(i)) -
(dshape_x(i) * dshape_l(l)))))* shape_y(j);
ddu(o,3) = ((ddshape_y(j) * shape_l(l)) - 2. * (dshape_y(j) * dshape_l(l)) +
(shape_y(j) * ddshape_l(l))) * shape_x(i) * shape_z(k);
ddu(o,4) = ((dshape_z(k) * ((dshape_y(j) * shape_l(l)) -
(shape_y(j)*dshape_l(l))) ) +
(shape_z(k)* ((ddshape_l(l)*shape_y(j)) -
(dshape_y(j) * dshape_l(l)) ) ) )* shape_x(i);
ddu(o,5) = ((ddshape_z(k) * shape_l(l)) - 2. * (dshape_z(k) * dshape_l(l)) +
(shape_z(k) * ddshape_l(l))) * shape_y(j) * shape_x(i);
o++;
}
Ti.Mult(ddu, ddshape);
}
H1Pos_TriangleElement::H1Pos_TriangleElement(const int p)
: PositiveFiniteElement(2, Geometry::TRIANGLE, ((p + 1)*(p + 2))/2, p,
+2 -18
View File
@@ -1564,8 +1564,6 @@ private:
static void CalcChebyshev(const int p, const double x, double *u);
static void CalcChebyshev(const int p, const double x, double *u, double *d);
static void CalcChebyshev(const int p, const double x, double *u, double *d,
double *dd);
QuadratureFunctions1D quad_func;
@@ -1620,14 +1618,6 @@ public:
// { CalcLegendre(p, x, u, d); }
{ CalcChebyshev(p, x, u, d); }
// Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x
static void CalcBasis(const int p, const double x, double *u, double *d,
double *dd)
// { CalcMono(p, x, u, d); }
// { CalcBernstein(p, x, u, d); }
// { CalcLegendre(p, x, u, d); }
{ CalcChebyshev(p, x, u, d, dd); }
// Evaluate a representation of a Delta function at point x
static double CalcDelta(const int p, const double x)
{ return pow(x, (double) p); }
@@ -1830,8 +1820,7 @@ class H1_TriangleElement : public NodalFiniteElement
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_l, dshape_x, dshape_y, dshape_l, u;
mutable Vector ddshape_x, ddshape_y, ddshape_l;
mutable DenseMatrix du, ddu;
mutable DenseMatrix du;
#endif
DenseMatrixInverse Ti;
@@ -1840,8 +1829,6 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const;
};
@@ -1851,8 +1838,7 @@ private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z, shape_l;
mutable Vector dshape_x, dshape_y, dshape_z, dshape_l, u;
mutable Vector ddshape_x, ddshape_y, ddshape_z, ddshape_l;
mutable DenseMatrix du, ddu;
mutable DenseMatrix du;
#endif
DenseMatrixInverse Ti;
@@ -1862,8 +1848,6 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const;
};
+2
View File
@@ -26,6 +26,8 @@
#include "linearform.hpp"
#include "nonlinearform.hpp"
#include "bilinearform.hpp"
#include "bilinearformoper.hpp"
#include "painteg.hpp"
#include "hybridization.hpp"
#include "datacollection.hpp"
#include "estimators.hpp"
+15 -5
View File
@@ -249,6 +249,16 @@ public:
/// Returns number of degrees of freedom.
inline int GetNDofs() const { return ndofs; }
/// Returns number of degrees of freedom in each direction.
inline const int GetNDofs1d() const { return GetFE(0)->GetOrder()+1; }
/// Returns number of quadrature points in each direction.
inline const int GetNQuads1d(const int order) const
{
const IntegrationRule &ir1d = IntRules.Get(Geometry::SEGMENT, order);
return ir1d.GetNPoints();
}
/// Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
inline int GetVSize() const { return vdim * ndofs; }
@@ -301,9 +311,9 @@ public:
ElementTransformation *GetElementTransformation(int i) const
{ return mesh->GetElementTransformation(i); }
/** @brief Returns the transformation defining the @a i-th element in the
user-defined variable @a ElTr. */
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
/** Returns the transformation defining the i-th element in the user-defined
variable. */
void GetElementTransformation(int i, IsoparametricTransformation *ElTr) const
{ mesh->GetElementTransformation(i, ElTr); }
/// Returns ElementTransformation for the @a i-th boundary element.
@@ -557,10 +567,10 @@ public:
virtual ~QuadratureSpace() { delete [] element_offsets; }
/// Return the total number of quadrature points.
int GetSize() const { return size; }
int GetSize() { return size; }
/// Get the IntegrationRule associated with mesh element @a idx.
const IntegrationRule &GetElementIntRule(int idx) const
const IntegrationRule &GetElementIntRule(int idx)
{ return *int_rule[mesh->GetElementBaseGeometry(idx)]; }
/// Write the QuadratureSpace to the stream @a out.
-24
View File
@@ -1492,8 +1492,6 @@ void GridFunction::ProjectCoefficient(Coefficient *coeff[])
transf->SetIntPoint(&ip);
for (d = 0; d < vdim; d++)
{
if (!coeff[d]) { continue; }
val = coeff[d]->Eval(*transf, ip);
if ( (ind = vdofs[fdof*d+j]) < 0 )
{
@@ -1588,8 +1586,6 @@ void GridFunction::ProjectBdrCoefficient(
transf->SetIntPoint(&ip);
for (d = 0; d < vdim; d++)
{
if (!coeff[d]) { continue; }
val = coeff[d]->Eval(*transf, ip);
if ( (ind = vdofs[fdof*d+j]) < 0 )
{
@@ -1631,8 +1627,6 @@ void GridFunction::ProjectBdrCoefficient(
vals.SetSize(fe->GetDof());
for (d = 0; d < vdim; d++)
{
if (!coeff[d]) { continue; }
fe->Project(*coeff[d], *transf, vals);
for (int k = 0; k < vals.Size(); k++)
{
@@ -2583,24 +2577,6 @@ QuadratureFunction::QuadratureFunction(Mesh *mesh, std::istream &in)
Load(in, vdim*qspace->GetSize());
}
QuadratureFunction & QuadratureFunction::operator=(double value)
{
Vector::operator=(value);
return *this;
}
QuadratureFunction & QuadratureFunction::operator=(const Vector &v)
{
MFEM_ASSERT(qspace && v.Size() == qspace->GetSize(), "");
Vector::operator=(v);
return *this;
}
QuadratureFunction & QuadratureFunction::operator=(const QuadratureFunction &v)
{
return this->operator=((const Vector &)v);
}
void QuadratureFunction::Save(std::ostream &out) const
{
qspace->Save(out);
+1 -58
View File
@@ -472,21 +472,8 @@ public:
/// Set the QuadratureSpace ownership flag.
void SetOwnsSpace(bool own) { own_qspace = own; }
/// Redefine '=' for QuadratureFunction = constant.
QuadratureFunction &operator=(double value);
/// Copy the data from @a v.
/** The size of @a v must be equal to the size of the QuadratureSpace
@a qspace. */
QuadratureFunction &operator=(const Vector &v);
/// Copy the data from @a v.
/** The QuadratureFunctions @a v and @a *this must have QuadratureSpaces with
the same size. */
QuadratureFunction &operator=(const QuadratureFunction &v);
/// Get the IntegrationRule associated with mesh element @a idx.
const IntegrationRule &GetElementIntRule(int idx) const
const IntegrationRule &GetElementIntRule(int idx)
{ return qspace->GetElementIntRule(idx); }
/// Return all values associated with mesh element @a idx in a Vector.
@@ -498,15 +485,6 @@ public:
*/
inline void GetElementValues(int idx, Vector &values);
/// Return all values associated with mesh element @a idx in a Vector.
/** The result is stored in the Vector @a values as a copy of the
global values.
Inside the Vector @a values, the index `i+vdim*j` corresponds to the
`i`-th vector component at the `j`-th quadrature point.
*/
inline void GetElementValues(int idx, Vector &values) const;
/// Return all values associated with mesh element @a idx in a DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a reference to the
global values.
@@ -516,15 +494,6 @@ public:
*/
inline void GetElementValues(int idx, DenseMatrix &values);
/// Return all values associated with mesh element @a idx in a const DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a copy of the
global values.
Inside the DenseMatrix @a values, the `(i,j)` entry corresponds to the
`i`-th vector component at the `j`-th quadrature point.
*/
inline void GetElementValues(int idx, DenseMatrix &values) const;
/// Write the QuadratureFunction to the stream @a out.
void Save(std::ostream &out) const;
};
@@ -598,18 +567,6 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values)
values.NewDataAndSize(data + vdim*s_offset, vdim*sl_size);
}
inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const
{
const int s_offset = qspace->element_offsets[idx];
const int sl_size = qspace->element_offsets[idx+1] - s_offset;
values.SetSize(vdim*sl_size);
double *q = data + vdim*s_offset;
for (int i = 0; i<values.Size(); i++)
{
values(i) = *(q++);
}
}
inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values)
{
const int s_offset = qspace->element_offsets[idx];
@@ -617,20 +574,6 @@ inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values)
values.Reset(data + vdim*s_offset, vdim, sl_size);
}
inline void QuadratureFunction::GetElementValues(int idx,
DenseMatrix &values) const
{
const int s_offset = qspace->element_offsets[idx];
const int sl_size = qspace->element_offsets[idx+1] - s_offset;
values.SetSize(vdim, sl_size);
double *q = data + vdim*s_offset;
for (int j = 0; j<sl_size; j++)
for (int i = 0; i<vdim; i++)
{
values(i,j) = *(q++);
}
}
} // namespace mfem
#endif
-2
View File
@@ -31,7 +31,6 @@ public:
void Set(const double *p, const int dim)
{
MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
x = p[0];
if (dim > 1)
{
@@ -45,7 +44,6 @@ public:
void Get(double *p, const int dim) const
{
MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
p[0] = x;
if (dim > 1)
{
+63 -1
View File
@@ -13,6 +13,7 @@
#define MFEM_NONLININTEG
#include "../config/config.hpp"
#include "fespace.hpp"
#include "fe.hpp"
#include "coefficient.hpp"
@@ -29,7 +30,7 @@ protected:
const IntegrationRule *IntRule;
NonlinearFormIntegrator(const IntegrationRule *ir = NULL)
: IntRule(ir) { }
: IntRule(NULL) { }
public:
/** @brief Prescribe a fixed IntegrationRule to use (when @a ir != NULL) or
@@ -71,6 +72,67 @@ public:
virtual ~NonlinearFormIntegrator() { }
};
class Integrator
{
protected:
const IntegrationRule *IntRule;
public:
Integrator(const IntegrationRule *_IntRule = NULL) :
IntRule(_IntRule) { }
void SetIntegrationRule(const IntegrationRule *ir) { IntRule = ir; }
};
class LinearFESpaceIntegrator : public Integrator
{
public:
LinearFESpaceIntegrator(const IntegrationRule *_IntRule = NULL) :
Integrator(_IntRule) { }
virtual ~LinearFESpaceIntegrator() { }
/// Internally assemble the integrator for the specific trial and
/// test spaces (with an optional vector u for semilinear forms).
virtual void Assemble(FiniteElementSpace *trial_fes,
FiniteElementSpace *test_fes) { }
/// Apply the action A * x = y.
virtual void AddMult(const Vector &x, Vector &y)
{ mfem_error("Not supported"); }
/// Apply the transposed action A^T * x = y.
virtual void AddMultTranspose(const Vector &x, Vector &y)
{ mfem_error("Not supported"); }
};
class NonlinearFESpaceIntegrator : public Integrator
{
public:
NonlinearFESpaceIntegrator(const IntegrationRule *_IntRule = NULL) :
Integrator(_IntRule) { }
virtual ~NonlinearFESpaceIntegrator() { }
/// Internally assemble the integrator for the specific trial and
/// test spaces (with an optional vector u for semilinear forms).
virtual void Assemble(FiniteElementSpace *trial_fes,
FiniteElementSpace *test_fes,
const Vector &u) { }
/// Apply the action A(u) * x = y.
virtual void AddMult(const Vector &x, Vector &y)
{ mfem_error("Not supported"); }
/// Apply the transposed action A(u)^T * x = y.
virtual void AddMultTranspose(const Vector &x, Vector &y)
{ mfem_error("Not supported"); }
};
/** The abstract base class BlockNonlinearFormIntegrator is
a generalization of the NonlinearFormIntegrator class suitable
for block state vectors. */
+704
View File
@@ -0,0 +1,704 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// Implementation of FESpaceIntegrators.
#include "fem.hpp"
namespace mfem
{
static void ComputeBasis1d(const FiniteElement *fe,
const TensorBasisElement *tfe, int ir_order,
DenseMatrix &shape1d)
{
// Compute the 1d shape functions and gradients
const Poly_1D::Basis &basis1d = tfe->GetBasis1D();
const IntegrationRule &ir1d = IntRules.Get(Geometry::SEGMENT, ir_order);
const int quads1d = ir1d.GetNPoints();
const int dofs = fe->GetOrder() + 1;
shape1d.SetSize(dofs, quads1d);
Vector u(dofs);
for (int k = 0; k < quads1d; k++)
{
const IntegrationPoint &ip = ir1d.IntPoint(k);
basis1d.Eval(ip.x, u);
for (int i = 0; i < dofs; i++)
{
shape1d(i, k) = u(i);
}
}
}
static void ComputeBasis1d(const FiniteElement *fe,
const TensorBasisElement *tfe, int ir_order,
DenseMatrix &shape1d, DenseMatrix &dshape1d)
{
// Compute the 1d shape functions and gradients
const Poly_1D::Basis &basis1d = tfe->GetBasis1D();
const IntegrationRule &ir1d = IntRules.Get(Geometry::SEGMENT, ir_order);
const int quads1d = ir1d.GetNPoints();
const int dofs = fe->GetOrder() + 1;
shape1d.SetSize(dofs, quads1d);
dshape1d.SetSize(dofs, quads1d);
Vector u(dofs);
Vector d(dofs);
for (int k = 0; k < quads1d; k++)
{
const IntegrationPoint &ip = ir1d.IntPoint(k);
basis1d.Eval(ip.x, u, d);
for (int i = 0; i < dofs; i++)
{
shape1d(i, k) = u(i);
dshape1d(i, k) = d(i);
}
}
}
void PADiffusionIntegrator::Assemble(FiniteElementSpace *_trial_fes,
FiniteElementSpace *_test_fes)
{
// Assumption: trial and test fespaces are the same (no mixed forms yet)
fes = _trial_fes;
// Assumption: all are same finite elements
const FiniteElement *fe = fes->GetFE(0);
// Get the corresponding tensor basis element
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe);
// Set integration rule
int ir_order;
if (!IntRule)
{
const int dim = fe->GetDim();
if (fe->Space() == FunctionSpace::Pk)
{
ir_order = 2*fe->GetOrder() - 2;
}
else
// order = 2*fe.GetOrder() - 2; // <-- this seems to work fine too
{
ir_order = 2*fe->GetOrder() + dim - 1;
}
if (fe->Space() == FunctionSpace::rQk)
{
SetIntegrationRule(&RefinedIntRules.Get(fe->GetGeomType(), ir_order));
}
else
{
SetIntegrationRule(&IntRules.Get(fe->GetGeomType(), ir_order));
}
}
else
{
ir_order = IntRule->GetOrder();
}
// Store the 1d shape functions and gradients
ComputeBasis1d(fes->GetFE(0), tfe, ir_order, shape1d, dshape1d);
// Create the operator
const int elems = fes->GetNE();
const int dim = fe->GetDim();
const int quads = IntRule->GetNPoints();
const int entries = dim * (dim + 1) / 2;
Dtensor.SetSize(entries, quads, elems);
DenseMatrix invdfdx(dim, dim);
DenseMatrix mat(dim, dim);
DenseMatrix cmat(dim, dim);
Coefficient *coeff = integ->Q;
MatrixCoefficient *mcoeff = integ->MQ;
for (int e = 0; e < fes->GetNE(); e++)
{
ElementTransformation *Tr = fes->GetElementTransformation(e);
DenseMatrix &Dmat = Dtensor(e);
for (int k = 0; k < quads; k++)
{
const IntegrationPoint &ip = IntRule->IntPoint(k);
Tr->SetIntPoint(&ip);
const DenseMatrix &temp = Tr->AdjugateJacobian();
MultABt(temp, temp, mat);
mat *= ip.weight / Tr->Weight();
if (coeff != NULL)
{
const double c = coeff->Eval(*Tr, ip);
for (int j = 0, l = 0; j < dim; j++)
for (int i = j; i < dim; i++, l++)
{
Dmat(l, k) = c * mat(i, j);
}
}
else if (mcoeff != NULL)
{
mcoeff->Eval(cmat, *Tr, ip);
for (int j = 0, l = 0; j < dim; j++)
for (int i = j; i < dim; i++, l++)
{
Dmat(l, k) = cmat(i, j) * mat(i, j);
}
}
else
{
for (int j = 0, l = 0; j < dim; j++)
for (int i = j; i < dim; i++, l++)
{
Dmat(l, k) = mat(i, j);
}
}
}
}
}
void PADiffusionIntegrator::MultSeg(const Vector &V, Vector &U)
{
const int dofs1d = shape1d.Height();
const int quads1d = shape1d.Width();
const int quads = quads1d;
const int vdim = fes->GetVDim();
Vector Q(quads1d);
int offset = 0;
for (int e = 0; e < fes->GetNE(); ++e)
{
for (int vd = 0; vd < vdim; ++vd)
{
const Vector Vmat(V.GetData() + offset, dofs1d);
Vector Umat(U.GetData() + offset, dofs1d);
// Q_k1 = dshape_j1_k1 * V_i1
dshape1d.MultTranspose(Vmat, Q);
double *data_q = Q.GetData();
const double *data_d = Dtensor(e).GetData();
for (int k = 0; k < quads; ++k)
{
data_q[k] *= data_d[k];
}
// Q_k1 = dshape_j1_k1 * Q_k1
dshape1d.AddMult(Q, Umat);
// increment offset into E-vectors.
offset += dofs1d;
}
}
}
void PADiffusionIntegrator::MultQuad(const Vector &V, Vector &U)
{
const int dim = 2;
const int terms = dim*(dim+1)/2;
const int vdim = fes->GetVDim();
const int dofs1d = shape1d.Height();
const int quads1d = shape1d.Width();
const int dofs = dofs1d * dofs1d;
const int quads = IntRule->GetNPoints();
DenseTensor QQ(quads1d, quads1d, dim);
DenseMatrix DQ(dofs1d, quads1d);
int offset = 0;
for (int e = 0; e < fes->GetNE(); ++e)
{
for (int vd = 0; vd < vdim; ++vd)
{
const DenseMatrix Vmat(V.GetData() + offset, dofs1d, dofs1d);
DenseMatrix Umat(U.GetData() + offset, dofs1d, dofs1d);
// DQ_j2_k1 = E_j1_j2 * dshape_j1_k1 -- contract in x direction
// QQ_0_k1_k2 = DQ_j2_k1 * shape_j2_k2 -- contract in y direction
MultAtB(Vmat, dshape1d, DQ);
MultAtB(DQ, shape1d, QQ(0));
// DQ_j2_k1 = E_j1_j2 * shape_j1_k1 -- contract in x direction
// QQ_1_k1_k2 = DQ_j2_k1 * dshape_j2_k2 -- contract in y direction
MultAtB(Vmat, shape1d, DQ);
MultAtB(DQ, dshape1d, QQ(1));
// QQ_c_k1_k2 = Dmat_c_d_k1_k2 * QQ_d_k1_k2
// NOTE: (k1, k2) = k -- 1d index over tensor product of quad points
double *data_qq = QQ(0).GetData();
const double *data_d = Dtensor(e).GetData();
for (int k = 0; k < quads; ++k)
{
const double D00 = data_d[terms*k + 0];
const double D01 = data_d[terms*k + 1];
const double D11 = data_d[terms*k + 2];
const double q0 = data_qq[0*quads + k];
const double q1 = data_qq[1*quads + k];
data_qq[0*quads + k] = D00 * q0 + D01 * q1;
data_qq[1*quads + k] = D01 * q0 + D11 * q1;
}
// DQ_i2_k1 = shape_i2_k2 * QQ_0_k1_k2
// U_i1_i2 += dshape_i1_k1 * DQ_i2_k1
MultABt(shape1d, QQ(0), DQ);
AddMultABt(dshape1d, DQ, Umat);
// DQ_i2_k1 = dshape_i2_k2 * QQ_1_k1_k2
// U_i1_i2 += shape_i1_k1 * DQ_i2_k1
MultABt(dshape1d, QQ(1), DQ);
AddMultABt(shape1d, DQ, Umat);
// increment offset
offset += dofs;
}
}
}
void PADiffusionIntegrator::MultHex(const Vector &V, Vector &U)
{
const int dim = 3;
const int terms = dim*(dim+1)/2;
const int vdim = fes->GetVDim();
const int dofs1d = shape1d.Height();
const int quads1d = shape1d.Width();
const int dofs = dofs1d * dofs1d * dofs1d;
const int quads = IntRule->GetNPoints();
DenseMatrix Q(quads1d, dim);
DenseTensor QQ(quads1d, quads1d, dim);
Array<double> QQQmem(quads1d * quads1d * quads1d * dim);
double *data_qqq = QQQmem.GetData();
DenseTensor QQQ0(data_qqq + 0*quads, quads1d, quads1d, quads1d);
DenseTensor QQQ1(data_qqq + 1*quads, quads1d, quads1d, quads1d);
DenseTensor QQQ2(data_qqq + 2*quads, quads1d, quads1d, quads1d);
int offset = 0;
for (int e = 0; e < fes->GetNE(); ++e)
{
for (int vd = 0; vd < vdim; ++vd)
{
const DenseTensor Vmat(V.GetData() + offset, dofs1d, dofs1d, dofs1d);
DenseTensor Umat(U.GetData() + offset, dofs1d, dofs1d, dofs1d);
// QQQ_0_k1_k2_k3 = dshape_j1_k1 * shape_j2_k2 * shape_j3_k3 * Vmat_j1_j2_j3
// QQQ_1_k1_k2_k3 = shape_j1_k1 * dshape_j2_k2 * shape_j3_k3 * Vmat_j1_j2_j3
// QQQ_2_k1_k2_k3 = shape_j1_k1 * shape_j2_k2 * dshape_j3_k3 * Vmat_j1_j2_j3
QQQ0 = 0.; QQQ1 = 0.; QQQ2 = 0.;
for (int j3 = 0; j3 < dofs1d; ++j3)
{
QQ = 0.;
for (int j2 = 0; j2 < dofs1d; ++j2)
{
Q = 0.;
for (int j1 = 0; j1 < dofs1d; ++j1)
{
for (int k1 = 0; k1 < quads1d; ++k1)
{
Q(k1, 0) += Vmat(j1, j2, j3) * dshape1d(j1, k1);
Q(k1, 1) += Vmat(j1, j2, j3) * shape1d(j1, k1);
}
}
for (int k2 = 0; k2 < quads1d; ++k2)
for (int k1 = 0; k1 < quads1d; ++k1)
{
QQ(k1, k2, 0) += Q(k1, 0) * shape1d(j2, k2);
QQ(k1, k2, 1) += Q(k1, 1) * dshape1d(j2, k2);
QQ(k1, k2, 2) += Q(k1, 1) * shape1d(j2, k2);
}
}
for (int k3 = 0; k3 < quads1d; ++k3)
for (int k2 = 0; k2 < quads1d; ++k2)
for (int k1 = 0; k1 < quads1d; ++k1)
{
QQQ0(k1, k2, k3) += QQ(k1, k2, 0) * shape1d(j3, k3);
QQQ1(k1, k2, k3) += QQ(k1, k2, 1) * shape1d(j3, k3);
QQQ2(k1, k2, k3) += QQ(k1, k2, 2) * dshape1d(j3, k3);
}
}
// QQQ_c_k1_k2_k3 = Dmat_c_d_k1_k2_k3 * QQQ_d_k1_k2_k3
// NOTE: (k1, k2, k3) = q -- 1d quad point index
const double *data_d = Dtensor(e).GetData();
for (int k = 0; k < quads; ++k)
{
const double D00 = data_d[terms*k + 0];
const double D01 = data_d[terms*k + 1];
const double D02 = data_d[terms*k + 2];
const double D11 = data_d[terms*k + 3];
const double D12 = data_d[terms*k + 4];
const double D22 = data_d[terms*k + 5];
const double q0 = data_qqq[0*quads + k];
const double q1 = data_qqq[1*quads + k];
const double q2 = data_qqq[2*quads + k];
data_qqq[0*quads + k] = D00 * q0 + D01 * q1 + D02 * q2;
data_qqq[1*quads + k] = D01 * q0 + D11 * q1 + D12 * q2;
data_qqq[2*quads + k] = D02 * q0 + D12 * q1 + D22 * q2;
}
// Apply transpose of the first operator that takes V -> QQQd -- QQQd -> U
for (int k3 = 0; k3 < quads1d; ++k3)
{
QQ = 0.;
for (int k2 = 0; k2 < quads1d; ++k2)
{
Q = 0.;
for (int k1 = 0; k1 < quads1d; ++k1)
{
for (int i1 = 0; i1 < dofs1d; ++i1)
{
Q(i1, 0) += QQQ0(k1, k2, k3) * dshape1d(i1, k1);
Q(i1, 1) += QQQ1(k1, k2, k3) * shape1d(i1, k1);
Q(i1, 2) += QQQ2(k1, k2, k3) * shape1d(i1, k1);
}
}
for (int i2 = 0; i2 < dofs1d; ++i2)
for (int i1 = 0; i1 < dofs1d; ++i1)
{
QQ(i1, i2, 0) += Q(i1, 0) * shape1d(i2, k2);
QQ(i1, i2, 1) += Q(i1, 1) * dshape1d(i2, k2);
QQ(i1, i2, 2) += Q(i1, 2) * shape1d(i2, k2);
}
}
for (int i3 = 0; i3 < dofs1d; ++i3)
for (int i2 = 0; i2 < dofs1d; ++i2)
for (int i1 = 0; i1 < dofs1d; ++i1)
{
Umat(i1, i2, i3) +=
QQ(i1, i2, 0) * shape1d(i3, k3) +
QQ(i1, i2, 1) * shape1d(i3, k3) +
QQ(i1, i2, 2) * dshape1d(i3, k3);
}
}
// increment offset
offset += dofs;
}
}
}
void PADiffusionIntegrator::AddMult(const Vector &x, Vector &y)
{
const int dim = fes->GetMesh()->Dimension();
switch (dim)
{
case 1: MultSeg(x, y); break;
case 2: MultQuad(x, y); break;
case 3: MultHex(x, y); break;
default: mfem_error("Not yet supported"); break;
}
}
void PAMassIntegrator::Assemble(FiniteElementSpace *_trial_fes,
FiniteElementSpace *_test_fes)
{
// Assumption: trial and test fespaces are the same (no mixed forms yet)
fes = _trial_fes;
// Assumption: all are same finite elements
const FiniteElement *fe = fes->GetFE(0);
// Get the corresponding tensor basis element
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe);
// Set integration rule
int ir_order;
if (!IntRule)
{
// int order = 2 * el.GetOrder();
// ir_order = 2 * fe.GetOrder() + Trans.OrderW();
ir_order = 2 * fe->GetOrder() + 1;
if (fe->Space() == FunctionSpace::rQk)
{
SetIntegrationRule(&RefinedIntRules.Get(fe->GetGeomType(), ir_order));
}
else
{
SetIntegrationRule(&IntRules.Get(fe->GetGeomType(), ir_order));
}
}
else
{
ir_order = IntRule->GetOrder();
}
ComputeBasis1d(fes->GetFE(0), tfe, ir_order, shape1d);
// Create the operator
const int nelem = fes->GetNE();
const int dim = fe->GetDim();
const int quads = IntRule->GetNPoints();
const int vdim = integ ? 1 : dim;
Dtensor.SetSize(quads, vdim, nelem);
Coefficient *coeff = NULL;
VectorCoefficient *vcoeff = NULL;
if (integ)
{
coeff = integ->Q;
}
else if (vinteg)
{
coeff = vinteg->Q;
vcoeff = vinteg->VQ;
if (vinteg->MQ != NULL) mfem_error("Not supported.");
}
DenseMatrix invdfdx(dim, dim);
DenseMatrix mat(dim, dim);
Vector cv(vdim);
for (int e = 0; e < fes->GetNE(); e++)
{
ElementTransformation *Tr = fes->GetElementTransformation(e);
DenseMatrix &Dmat = Dtensor(e);
for (int k = 0; k < quads; k++)
{
const IntegrationPoint &ip = IntRule->IntPoint(k);
Tr->SetIntPoint(&ip);
const double weight = ip.weight * Tr->Weight();
if (vcoeff != NULL)
{
vcoeff->Eval(cv, *Tr, ip);
}
for (int v = 0; v < vdim; v++)
{
Dmat(k, v) = weight;
if (coeff != NULL) Dmat(k, v) *= coeff->Eval(*Tr, ip);
else if (vcoeff != NULL)
{
Dmat(k, v) *= cv(v);
}
}
}
}
}
void PAMassIntegrator::MultSeg(const Vector &V, Vector &U)
{
const int dofs1d = shape1d.Height();
const int quads1d = shape1d.Width();
const int quads = quads1d;
const int vdim = fes->GetVDim();
Vector Q(quads1d);
int offset = 0;
for (int e = 0; e < fes->GetNE(); ++e)
{
DenseMatrix &Dmat = Dtensor(e);
for (int vd = 0; vd < vdim; ++vd)
{
const Vector Vmat(V.GetData() + offset, dofs1d);
Vector Umat(U.GetData() + offset, dofs1d);
// Q_k1 = dshape_j1_k1 * V_i1
shape1d.MultTranspose(Vmat, Q);
double *data_q = Q.GetData();
const double *data_d = Dmat.GetColumn(vd);
for (int k = 0; k < quads; ++k) { data_q[k] *= data_d[k]; }
// Q_k1 = dshape_j1_k1 * Q_k1
shape1d.AddMult(Q, Umat);
// Increment offset into E-vectors.
offset += dofs1d;
}
}
}
void PAMassIntegrator::MultQuad(const Vector &V, Vector &U)
{
const int dofs1d = shape1d.Height();
const int quads1d = shape1d.Width();
const int dofs = dofs1d * dofs1d;
const int quads = IntRule->GetNPoints();
const int vdim = fes->GetVDim();
DenseMatrix QQ(quads1d, quads1d);
DenseMatrix DQ(dofs1d, quads1d);
int offset = 0;
for (int e = 0; e < fes->GetNE(); ++e)
{
DenseMatrix &Dmat = Dtensor(e);
for (int vd = 0; vd < vdim; ++vd)
{
const DenseMatrix Vmat(V.GetData() + offset, dofs1d, dofs1d);
DenseMatrix Umat(U.GetData() + offset, dofs1d, dofs1d);
// DQ_j2_k1 = E_j1_j2 * dshape_j1_k1 -- contract in x direction
// QQ_0_k1_k2 = DQ_j2_k1 * shape_j2_k2 -- contract in y direction
MultAtB(Vmat, shape1d, DQ);
MultAtB(DQ, shape1d, QQ);
// QQ_c_k1_k2 = Dmat_c_d_k1_k2 * QQ_d_k1_k2
// NOTE: (k1, k2) = k -- 1d index over tensor product of quad points
double *data_qq = QQ.GetData();
const double *data_d = Dmat.GetColumn(vd);
for (int k = 0; k < quads; ++k) { data_qq[k] *= data_d[k]; }
// DQ_i2_k1 = shape_i2_k2 * QQ_0_k1_k2
// U_i1_i2 += dshape_i1_k1 * DQ_i2_k1
MultABt(shape1d, QQ, DQ);
AddMultABt(shape1d, DQ, Umat);
// increment offset
offset += dofs;
}
}
}
void PAMassIntegrator::MultHex(const Vector &V, Vector &U)
{
const int dofs1d = shape1d.Height();
const int quads1d = shape1d.Width();
const int dofs = dofs1d * dofs1d * dofs1d;
const int quads = IntRule->GetNPoints();
const int vdim = fes->GetVDim();
Vector Q(quads1d);
DenseMatrix QQ(quads1d, quads1d);
DenseTensor QQQ(quads1d, quads1d, quads1d);
int offset = 0;
for (int e = 0; e < fes->GetNE(); ++e)
{
DenseMatrix &Dmat = Dtensor(e);
for (int vd = 0; vd < vdim; ++vd)
{
const DenseTensor Vmat(V.GetData() + offset, dofs1d, dofs1d, dofs1d);
DenseTensor Umat(U.GetData() + offset, dofs1d, dofs1d, dofs1d);
// QQQ_k1_k2_k3 = shape_j1_k1 * shape_j2_k2 * shape_j3_k3 * Vmat_j1_j2_j3
QQQ = 0.;
for (int j3 = 0; j3 < dofs1d; ++j3)
{
QQ = 0.;
for (int j2 = 0; j2 < dofs1d; ++j2)
{
Q = 0.;
for (int j1 = 0; j1 < dofs1d; ++j1)
{
for (int k1 = 0; k1 < quads1d; ++k1)
{
Q(k1) += Vmat(j1, j2, j3) * shape1d(j1, k1);
}
}
for (int k2 = 0; k2 < quads1d; ++k2)
for (int k1 = 0; k1 < quads1d; ++k1)
{
QQ(k1, k2) += Q(k1) * shape1d(j2, k2);
}
}
for (int k3 = 0; k3 < quads1d; ++k3)
for (int k2 = 0; k2 < quads1d; ++k2)
for (int k1 = 0; k1 < quads1d; ++k1)
{
QQQ(k1, k2, k3) += QQ(k1, k2) * shape1d(j3, k3);
}
}
// QQQ_k1_k2_k3 = Dmat_k1_k2_k3 * QQQ_k1_k2_k3
// NOTE: (k1, k2, k3) = q -- 1d quad point index
double *data_qqq = QQQ.GetData(0);
const double *data_d = Dmat.GetColumn(vd);
for (int k = 0; k < quads; ++k) { data_qqq[k] *= data_d[k]; }
// Apply transpose of the first operator that takes V -> QQQ -- QQQ -> U
for (int k3 = 0; k3 < quads1d; ++k3)
{
QQ = 0.;
for (int k2 = 0; k2 < quads1d; ++k2)
{
Q = 0.;
for (int k1 = 0; k1 < quads1d; ++k1)
{
for (int i1 = 0; i1 < dofs1d; ++i1)
{
Q(i1) += QQQ(k1, k2, k3) * shape1d(i1, k1);
}
}
for (int i2 = 0; i2 < dofs1d; ++i2)
for (int i1 = 0; i1 < dofs1d; ++i1)
{
QQ(i1, i2) += Q(i1) * shape1d(i2, k2);
}
}
for (int i3 = 0; i3 < dofs1d; ++i3)
for (int i2 = 0; i2 < dofs1d; ++i2)
for (int i1 = 0; i1 < dofs1d; ++i1)
{
Umat(i1, i2, i3) += shape1d(i3, k3) * QQ(i1, i2);
}
}
// increment offset
offset += dofs;
}
}
}
void PAMassIntegrator::AddMult(const Vector &x, Vector &y)
{
const int dim = fes->GetMesh()->Dimension();
switch (dim)
{
case 1: MultSeg(x, y); break;
case 2: MultQuad(x, y); break;
case 3: MultHex(x, y); break;
default: mfem_error("Not yet supported"); break;
}
}
LinearFESpaceIntegrator *PAIntegratorMap::DomainIntegrator(BilinearFormIntegrator *integ) const
{
{
DiffusionIntegrator *actual_integ = dynamic_cast<DiffusionIntegrator*>(integ);
if (actual_integ) { return new PADiffusionIntegrator(actual_integ); }
}
{
MassIntegrator *actual_integ = dynamic_cast<MassIntegrator*>(integ);
if (actual_integ) { return new PAMassIntegrator(actual_integ); }
}
{
VectorMassIntegrator *actual_integ = dynamic_cast<VectorMassIntegrator*>(integ);
if (actual_integ) { return new PAMassIntegrator(actual_integ); }
}
mfem_error("Not supported.");
return NULL;
}
}
+90
View File
@@ -0,0 +1,90 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// This file contains FESpaceIntegrators.
#ifndef MFEM_PAINTEG
#define MFEM_PAINTEG
#include "../config/config.hpp"
#include "nonlininteg.hpp"
#include "bilinearformoper.hpp"
namespace mfem
{
// These integrators use constructors based on the non-PA versions so
// that the options are consistent. If that is not the case, the
// friendship can be revoked and those constructors can be removed.
/** Class for computing the action of (grad(u), grad(v)) from a scalar
* fespace using a partially assembled operator at quadrature
* points. */
class PADiffusionIntegrator : public LinearFESpaceIntegrator
{
protected:
// Carry pointer in order to have access to coefficient
DiffusionIntegrator *integ; // Own this
const FiniteElementSpace *fes; // TODO: support mixed spaces
DenseTensor Dtensor;
DenseMatrix shape1d, dshape1d;
// Action methods
void MultSeg(const Vector &V, Vector &U);
void MultQuad(const Vector &V, Vector &U);
void MultHex(const Vector &V, Vector &U);
public:
PADiffusionIntegrator(DiffusionIntegrator *_integ) : integ(_integ) {}
~PADiffusionIntegrator() { delete integ; }
virtual void Assemble(FiniteElementSpace *trial_fes,
FiniteElementSpace *test_fes);
virtual void AddMult(const Vector &x, Vector &y);
};
/** Class for computing the action of (u, v) from a scalar fespace
* using a partially assembled operator at quadrature points. */
class PAMassIntegrator : public LinearFESpaceIntegrator
{
protected:
MassIntegrator *integ; // Own this
VectorMassIntegrator *vinteg; // Own this
const FiniteElementSpace *fes; // TODO: support mixed spaces
DenseTensor Dtensor;
DenseMatrix shape1d;
// Action methods
void MultSeg(const Vector &V, Vector &U);
void MultQuad(const Vector &V, Vector &U);
void MultHex(const Vector &V, Vector &U);
public:
PAMassIntegrator(MassIntegrator *_integ) : integ(_integ), vinteg(NULL) {}
PAMassIntegrator(VectorMassIntegrator *_vinteg) : integ(NULL), vinteg(_vinteg) {}
~PAMassIntegrator() { delete integ; delete vinteg; }
virtual void Assemble(FiniteElementSpace *_trial_fes,
FiniteElementSpace *_test_fes);
virtual void AddMult(const Vector &x, Vector &y);
};
struct PAIntegratorMap : public IntegratorMap
{
virtual LinearFESpaceIntegrator *DomainIntegrator(BilinearFormIntegrator *integ) const;
};
}
#endif
File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// This file contains operator-based bilinear form integrators used
// with BilinearFormOperator.
#ifndef MFEM_PAK
#define MFEM_PAK
#include "fem.hpp"
#include "../config/config.hpp"
#include "bilininteg.hpp"
#include "dalg.hpp"
#include "dgfacefunctions.hpp"
#include "domainkernels.hpp"
#include "facekernels.hpp"
#include "solverkernels.hpp"
#include <iostream>
namespace mfem
{
/////////////////////////////////////////////////
// //
// //
// PARTIAL ASSEMBLY INTEGRATORS //
// //
// //
/////////////////////////////////////////////////
/////////////////////////////
// Domain Kernel Interface //
/////////////////////////////
struct ElementInfo
{
int dim;
int k;
int e;
ElementTransformation* tr;
IntegrationPoint ip;
Tensor<2> J_ek;
};
/**
* A partial assembly Integrator class for domain integrals.
* Takes an 'Equation' template parameter, that must contain 'OpName' of
* type 'PAOp' and a function named 'evalD', that receives a 'res' vector,
* the element transformation and the integration point, and then whatever
* is needed to compute at the point (Coefficient, VectorCoeffcient, etc...).
* The 'IMPL' template parameter allows to switch between different implementations
* of the tensor contraction kernels.
*/
template < typename Equation,
template<typename,PAOp> class IMPL = DomainMult>
class PADomainInt
: public LinearFESpaceIntegrator, public IMPL<Equation,Equation::OpName>, public Operator
{
private:
typedef IMPL<Equation,Equation::OpName> Op;
public:
/**
* The constructor is templated so that the argument needed for 'evalD' can be
* packed arbitrarily ('evalD' with the corresponding signature must exist).
*/
template <typename Args>
PADomainInt(FiniteElementSpace *fes, const int order, const Args& args)
: LinearFESpaceIntegrator(&IntRules.Get(fes->GetFE(0)->GetGeomType(), order)),
Op(fes,order,args),
Operator()
{
const int nb_elts = fes->GetNE();
const int quads = IntRule->GetNPoints();
const FiniteElement* fe = fes->GetFE(0);
const int dim = fe->GetDim();
this->InitD(dim,quads,nb_elts);
Tensor<1> Jac1D(dim*dim*quads*nb_elts);
EvalJacobians(dim,fes,order,Jac1D);
Tensor<4> Jac(Jac1D.getData(),dim,dim,quads,nb_elts);
for (int e = 0; e < nb_elts; ++e)
{
ElementTransformation *Tr = fes->GetElementTransformation(e);
for (int k = 0; k < quads; ++k)
{
Tensor<2> J_ek(&Jac(0,0,k,e),dim,dim);
const IntegrationPoint &ip = IntRule->IntPoint(k);
Tr->SetIntPoint(&ip);
this->evalEq(dim, k, e, Tr, ip, J_ek, args);
}
}
}
const typename Op::DTensor& getD() const
{
return Op::getD();
}
/**
* Applies the partial assembly operator.
*/
virtual void AddMult(const Vector &fun, Vector &vect)
{
int dim = this->fes->GetFE(0)->GetDim();
switch(dim)
{
case 1:this->Mult1d(fun,vect); break;
case 2:this->Mult2d(fun,vect); break;
case 3:this->Mult3d(fun,vect); break;
default: mfem_error("More than # dimension not yet supported"); break;
}
}
virtual void Mult(const Vector &fun, Vector &vect) const{
int dim = this->fes->GetFE(0)->GetDim();
switch(dim)
{
case 1:this->Mult1d(fun,vect); break;
case 2:this->Mult2d(fun,vect); break;
case 3:this->Mult3d(fun,vect); break;
default: mfem_error("More than # dimension not yet supported"); break;
}
}
};
///////////////////////////
// Face Kernel Interface //
///////////////////////////
struct FaceInfo
{
int dim; // The problem dimension
int k1, k2; // The indices of
IntegrationPoint eip1, eip2; // The integration points on each element
Vector* normal; // The normal to the face
int ind_elt1, ind_elt2; // The indices of the elements
int face_id1, face_id2; // The face ID for the face according to each element
FaceElementTransformations* face_tr; // The Face transformation
Tensor<2> J_e1, J_e2; // The Jacobians for each element at their respective quadrature point
};
/**
* A partial assembly Integrator interface class for face integrals.
* The template parameters have the same role as for 'PADomainInt'.
*/
template <typename Equation, template<typename,PAOp> class IMPL = FaceMult>
class PAFaceInt
: public LinearFESpaceIntegrator, public IMPL<Equation,Equation::FaceOpName>
{
private:
typedef IMPL<Equation,Equation::FaceOpName> Op;
public:
template <typename Args>
PAFaceInt(FiniteElementSpace* fes, const int order, Args& args)
: LinearFESpaceIntegrator(&IntRules.Get(fes->GetFE(0)->GetGeomType(), order)),
Op(fes, order, args)
{
const int dim = fes->GetFE(0)->GetDim();
const int quads1d = fes->GetNQuads1d(order);
Mesh* mesh = fes->GetMesh();
const int nb_elts = fes->GetNE();
const int nb_faces_elt = 2*dim;
const int nb_faces = mesh->GetNumFaces();
int geom;
switch(dim){
case 1:geom = Geometry::POINT;break;
case 2:geom = Geometry::SEGMENT;break;
case 3:geom = Geometry::SQUARE;break;
}
const IntegrationRule& ir = IntRules.Get(geom, order);
const int quads = ir.GetNPoints();
Vector qvec(dim);
Tensor<1> normal(dim);
Vector n(normal.getData(),dim);
// Vector n(dim);
this->init(dim,quads,nb_elts,nb_faces_elt);
// !!! Should not be recomputed... !!!
Tensor<1> Jac1D(dim*dim*quads*quads1d*nb_elts);
EvalJacobians(dim,fes,order,Jac1D);
Tensor<4> Jac(Jac1D.getData(),dim,dim,quads*quads1d,nb_elts);// Creating a view
// !!! !!!
// We have a per face approach for the fluxes
for (int face = 0; face < nb_faces; ++face)
{
int ind_elt1, ind_elt2;
int face_id1, face_id2;
int nb_rot1, nb_rot2;
GetFaceInfo(mesh, face, ind_elt1, ind_elt2, face_id1, face_id2, nb_rot1, nb_rot2);
FaceElementTransformations* face_tr = mesh->GetFaceElementTransformations(face);
int perm1, perm2;
// cout << "ind_elt1=" << ind_elt1 << ", face_id1=" << face_id1 << ", nb_rot1=" << nb_rot1 << ", ind_elt2=" << ind_elt2 << ", face_id2=" << face_id2 << ", nb_rot2=" << nb_rot2 << endl;
for (int kf = 0; kf < quads; ++kf)
{
const IntegrationPoint& ip = ir.IntPoint(kf);
if(ind_elt2!=-1){//Not a boundary face
Tensor<1,int> ind_f1(dim-1), ind_f2(dim-1);
// We compute the lexicographical index on each face
int k1 = GetFaceQuadIndex(dim,face_id1,nb_rot1,kf,quads1d,ind_f1);
int k2 = GetFaceQuadIndex(dim,face_id2,nb_rot2,kf,quads1d,ind_f2);
this->initFaceData(dim,ind_elt1,face_id1,nb_rot1,perm1,ind_elt2,face_id2,nb_rot2,perm2);
face_tr->Face->SetIntPoint( &ip );
IntegrationPoint eip1;
face_tr->Loc1.Transform(ip,eip1);
eip1.weight = ip.weight;//Sets the weight since Transform doesn't do it...
// face_tr->Elem1->SetIntPoint( &eip1 );
IntegrationPoint eip2;
face_tr->Loc2.Transform(ip,eip2);
eip2.weight = ip.weight;//Sets the weight since Transform doesn't do it...
// face_tr->Elem2->SetIntPoint( &eip2 );
int kg1 = GetGlobalQuadIndex(dim,face_id1,quads1d,ind_f1);
int kg2 = GetGlobalQuadIndex(dim,face_id2,quads1d,ind_f2);
Tensor<2> J_e1(&Jac(0,0,kg1,ind_elt1),dim,dim);
Tensor<2> J_e2(&Jac(0,0,kg2,ind_elt2),dim,dim);
Tensor<2> Adj(dim,dim);
adjugate(J_e1,Adj);
calcOrtho( Adj, face_id1, normal); // normal*determinant (risky, bug prone)
this->evalEq(dim,k1,k2,n,ind_elt1,face_id1,ind_elt2,face_id2,face_tr,eip1,eip2,J_e1,J_e2,args);
// FaceInfo face_info = {dim,k1,k2,n,ind_elt1,face_id1,ind_elt2,face_id2,face_tr,eip1,eip2,J_e1,J_e2};
// this->evalEq(face_info,args);
}else{//Boundary face
this->initBoundaryFaceData(ind_elt1,face_id1);
// TODO: Something should be done here when there is boundary conditions!
// D11(ind) = 0;
}
}
}
}
// Perform the action of the BilinearFormIntegrator
virtual void AddMult(const Vector &fun, Vector &vect)
{
int dim = this->fes->GetFE(0)->GetDim();
switch(dim)
{
case 1:
mfem_error("Not yet implemented");
break;
case 2:
this->EvalInt2D(fun, vect);
this->EvalExt2D(fun, vect);
break;
case 3:
this->EvalInt3D(fun, vect);
this->EvalExt3D(fun, vect);
break;
default:
mfem_error("Face Kernel does not exist for this dimension.");
break;
}
}
};
}
#endif //MFEM_PAK
+51
View File
@@ -239,6 +239,20 @@ void ParBilinearForm::Assemble(int skip_zeros)
}
}
void ParBilinearForm::AssembleForm(BilinearFormOperator &A, int skip_zeros)
{
A.Assemble(this);
oper = &A;
oper_type = MFEM_FORMOPER;
}
void ParBilinearForm::AssembleForm(HypreParMatrix &A, int skip_zeros)
{
Assemble(skip_zeros);
oper = &A;
oper_type = Hypre_ParCSR;
}
void ParBilinearForm
::ParallelEliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
HypreParMatrix &A, const HypreParVector &X,
@@ -324,6 +338,43 @@ void ParBilinearForm::FormLinearSystem(
}
}
template <typename OpType>
void ParBilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
OpType &A, Vector &X, Vector &B,
int copy_interior)
{
OperatorHandle Ah;
FormLinearSystem(ess_tdof_list, x, b, Ah, X, B, copy_interior);
OpType *A_ptr = Ah.Is<OpType>();
MFEM_VERIFY(A_ptr, "invalid OpType used");
A.MakeRef(*A_ptr);
}
template <>
void ParBilinearForm::FormLinearSystem<Operator*>(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
Operator * &A, Vector &X, Vector &B,
int copy_interior)
{
if (oper_type == Hypre_ParCSR)
{
HypreParMatrix &Amat = static_cast<HypreParMatrix&>(*oper);
FormLinearSystem(ess_tdof_list, x, b, Amat,
X, B, copy_interior);
HypreParMatrix *M = new HypreParMatrix;
M->MakeRef(Amat);
A = M;
}
else if (oper_type == MFEM_FORMOPER)
{
oper->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
}
else
{
mfem_error("Not supported.");
}
}
void ParBilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
OperatorHandle &A)
{
+4 -8
View File
@@ -70,6 +70,9 @@ public:
/// Assemble the local matrix
void Assemble(int skip_zeros = 1);
void AssembleForm(BilinearFormOperator &A, int skip_zeros = 1);
void AssembleForm(HypreParMatrix &A, int skip_zeros = 1);
/// Returns the matrix assembled on the true dofs, i.e. P^t A P.
/** The returned matrix has to be deleted by the caller. */
HypreParMatrix *ParallelAssemble() { return ParallelAssemble(mat); }
@@ -178,14 +181,7 @@ public:
template <typename OpType>
void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
OpType &A, Vector &X, Vector &B,
int copy_interior = 0)
{
OperatorHandle Ah;
FormLinearSystem(ess_tdof_list, x, b, Ah, X, B, copy_interior);
OpType *A_ptr = Ah.Is<OpType>();
MFEM_VERIFY(A_ptr, "invalid OpType used");
A.MakeRef(*A_ptr);
}
int copy_interior = 0);
/// Form the linear system matrix @a A, see FormLinearSystem() for details.
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
+18 -18
View File
@@ -1229,7 +1229,7 @@ void ParFiniteElementSpace::GetGhostDofs(int entity, const MeshId &id,
}
}
void ParFiniteElementSpace::GetBareDofs(int entity, int index,
void ParFiniteElementSpace::GetBareDofs(int entity, const MeshId &id,
Array<int> &dofs) const
{
int ned, ghost, first;
@@ -1238,25 +1238,25 @@ void ParFiniteElementSpace::GetBareDofs(int entity, int index,
case 0:
ned = fec->DofForGeometry(Geometry::POINT);
ghost = pncmesh->GetNVertices();
first = (index < ghost)
? index*ned // regular vertex
: ndofs + (index - ghost)*ned; // ghost vertex
first = (id.index < ghost)
? id.index*ned // regular vertex
: ndofs + (id.index - ghost)*ned; // ghost vertex
break;
case 1:
ned = fec->DofForGeometry(Geometry::SEGMENT);
ghost = pncmesh->GetNEdges();
first = (index < ghost)
? nvdofs + index*ned // regular edge
: ndofs + ngvdofs + (index - ghost)*ned; // ghost edge
first = (id.index < ghost)
? nvdofs + id.index*ned // regular edge
: ndofs + ngvdofs + (id.index - ghost)*ned; // ghost edge
break;
default:
ned = fec->DofForGeometry(mesh->GetFaceBaseGeometry(0));
ghost = pncmesh->GetNFaces();
first = (index < ghost)
? nvdofs + nedofs + index*ned // regular face
: ndofs + ngvdofs + ngedofs + (index - ghost)*ned; // ghost
first = (id.index < ghost)
? nvdofs + nedofs + id.index*ned // regular face
: ndofs + ngvdofs + ngedofs + (id.index - ghost)*ned; // ghost
break;
}
@@ -1674,7 +1674,7 @@ void ParFiniteElementSpace::ForwardRow(const PMatrixRow &row, int dof,
#ifdef MFEM_DEBUG_PMATRIX
void ParFiniteElementSpace
::DebugDumpDOFs(std::ostream &os,
::DebugDumpDOFs(std::ofstream &os,
const SparseMatrix &deps,
const Array<GroupId> &dof_group,
const Array<GroupId> &dof_owner,
@@ -1800,6 +1800,9 @@ int ParFiniteElementSpace
}
}
// make sure all master DOFs are transmitted to participating slave ranks
pncmesh->AugmentMasterGroups();
deps.Finalize();
}
@@ -1817,7 +1820,7 @@ int ParFiniteElementSpace
// initialize dof_group[], dof_owner[]
for (int entity = 0; entity <= 2; entity++)
{
const NCMesh::NCList &list = pncmesh->GetNCList(entity);
const NCMesh::NCList &list = pncmesh->GetSharedList(entity);
std::size_t lsize[3] =
{ list.conforming.size(), list.masters.size(), list.slaves.size() };
@@ -1831,16 +1834,13 @@ int ParFiniteElementSpace
(l == 1) ? (const MeshId&) list.masters[i]
/* */ : (const MeshId&) list.slaves[i];
GroupId owner = pncmesh->GetEntityOwnerId(entity, id.index);
GroupId group = pncmesh->GetEntityGroupId(entity, id.index);
GetBareDofs(entity, id.index, dofs);
GetBareDofs(entity, id, dofs);
for (int j = 0; j < dofs.Size(); j++)
{
int dof = dofs[j];
dof_owner[dof] = owner;
dof_group[dof] = group;
dof_owner[dof] = pncmesh->GetOwnerId(entity, id.index);
dof_group[dof] = pncmesh->GetGroupId(entity, id.index);
}
}
}

Some files were not shown because too many files have changed in this diff Show More