diff --git a/CHANGELOG b/CHANGELOG index 39041ef74b..570532ea2e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,39 @@ http://mfem.googlecode.com +Version 1.2, released on Apr 08, 2011 +===================================== + +- New MPI parallel version of the library based on the ParCSR parallel matrix + format from hypre and the metis graph partitioning library. This version + supports parallel local refinement and parallel curved meshes, as well as + several solvers from hypre. + +- Added a new example code describing an electromagnetic diffusion problem + discretized with lowest order Nedelec finite elements (Example 3). + +- Added parallel versions of all examples codes (files ex1p.cpp, ex2p.cpp and + ex3p.cpp) based on hypre's BoomerAMG and AMS preconditioners. + +- Added support for saving and reading linear and curved quadratic meshes in VTK + format. The format is automatically recognized when opening a mesh file, and + the boundary is reconstructed based on the actual domain boundary. + +- The 'data' directory now contains a collection of various mesh files in the + MFEM and VTK formats, including curved meshes and the mesh files that were + previously in the 'examples' directory. + +- Updated the default integration rule order for most of the linear form + integrators. + +- Added support for cubic hex elements. + +- Bugfixes in the face orientation of 3D RT0 elements and in the VectorFEDomain + linear form integrator. + +- Various small fixes and styling updates. + + Version 1.1, released on Sep 13, 2010 ===================================== diff --git a/GNUmakefile b/GNUmakefile index 281a918059..e594dcfeaf 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,33 +9,42 @@ # terms of the GNU Lesser General Public License (as published by the Free # Software Foundation) version 2.1 dated February 1999. +# Serial compiler CC = g++ CCOPTS = DEBUG_OPTS = -g -DMFEM_DEBUG OPTIM_OPTS = -O3 -DEPCC = g++ +DEPCC = $(CC) -# internal mfem options -USE_MEMALLOC = YES -USE_LAPACK = YES +# Parallel compiler +MPICC = mpiCC +MPIOPTS = $(CCOPTS) -I$(HYPRE_DIR)/include -USE_MEMALLOC_NO = -USE_MEMALLOC_YES = -DMFEM_USE_MEMALLOC -USE_MEMALLOC_DEF = $(USE_MEMALLOC_$(USE_MEMALLOC)) +# The HYPRE library (needed to build the parallel version) +HYPRE_DIR = ../../hypre-2.7.0b/src/hypre + +# Internal mfem options +USE_LAPACK = YES +USE_MEMALLOC = YES USE_LAPACK_NO = USE_LAPACK_YES = -DMFEM_USE_LAPACK USE_LAPACK_DEF = $(USE_LAPACK_$(USE_LAPACK)) -DEFS = $(USE_MEMALLOC_DEF) $(USE_LAPACK_DEF) +USE_MEMALLOC_NO = +USE_MEMALLOC_YES = -DMFEM_USE_MEMALLOC +USE_MEMALLOC_DEF = $(USE_MEMALLOC_$(USE_MEMALLOC)) -CCC = $(CC) $(CCOPTS) $(MODE_OPTS) $(DEFS) -# compiler and options used for generating deps.mk +DEFS = $(USE_LAPACK_DEF) $(USE_MEMALLOC_DEF) + +CCC = $(CC) $(MODE_OPTS) $(DEFS) $(CCOPTS) + +# Compiler and options used for generating deps.mk DEPCCC = $(DEPCC) $(CCOPTS) $(MODE_OPTS) $(DEFS) DEFINES = $(subst -D,,$(filter -D%,$(CCC))) -# source dirs in logical order +# Source dirs in logical order DIRS = general linalg mesh fem SOURCE_FILES = $(foreach dir,$(DIRS),$(wildcard $(dir)/*.cpp)) OBJECT_FILES = $(SOURCE_FILES:.cpp=.o) @@ -44,15 +53,21 @@ OBJECT_FILES = $(SOURCE_FILES:.cpp=.o) .cpp.o: cd $( Builds the libmfem.a library -make debug -> Builds a debug version -make clean -> Cleans the build +make -> Builds the serial libmfem.a library +make debug -> Builds a serial debug version +make parallel -> Builds the parallel libmfem.a library +make pdebug -> Builds a parallel debug version +make clean -> Cleans the build Building with 'gmake' @@ -40,9 +56,11 @@ GNUmakefile will be used instead of the makefile. Some of the available 'gmake' targets are: -gmake -> Builds the libmfem.a library -gmake debug -> Builds a debug version -gmake clean -> Cleans the build +gmake -> Builds the serial libmfem.a library +gmake debug -> Builds a serial debug version +gmake parallel -> Builds the parallel libmfem.a library +gmake pdebug -> Builds a parallel debug version +gmake clean -> Cleans the build Building with 'SCons' @@ -53,6 +71,7 @@ file will automatically detect the availability of LAPACK. Some of the available 'SCons' targets are: -scons -> Builds the libmfem.a library -scons debug=1 -> Builds a debug version -scons -c -> Cleans the build +scons -> Builds the serial libmfem.a library +scons debug=1 -> Builds a serial debug version +scons parallel=1 -> Builds the parallel libmfem.a library +scons -c -> Cleans the build diff --git a/README b/README index ccb3eab9fd..8a33d3f1ce 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ Finite Element Discretization Library - version 1.1 + version 1.2 __ _ __ ___ / _| ___ _ __ ___ | '_ ` _ \ | |_ / _ \| '_ ` _ \ @@ -8,7 +8,7 @@ http://mfem.googlecode.com -MFEM is a general, modular C++ library for finite element methods. +MFEM is a general, modular, parallel C++ library for finite element methods. For building instructions, see the file INSTALL. Copyright information and licensing restrictions can be found in the file COPYRIGHT. @@ -30,5 +30,9 @@ to facilitate this, MFEM uses compressed sparse row (CSR) sparse matrix storage and includes simple smoothers and Krylov solvers, such as PCG, GMRES and BiCGStab. +The MPI-based parallel version of MFEM can be used as a scalable unstructured +finite element problem generator, which supports parallel local refinement and +parallel curved meshes, as well as several solvers from the hypre library. + For examples of using MFEM, see the examples/ directory, as well as the OpenGL visualization tool GLVis which is available at http://glvis.googlecode.com. diff --git a/SConstruct b/SConstruct index fd2a41f109..2efef187c1 100644 --- a/SConstruct +++ b/SConstruct @@ -12,14 +12,21 @@ Help(""" Type: 'scons' to build the production library, 'scons -c' to clean the build, - 'scons debug=1' to build the debug version. + 'scons debug=1' to build the debug version, + 'scons parallel=1' to build the parallel version. """) -env = Environment() +import os + +# Export the shell environment variables +env = Environment(ENV=os.environ) CC_OPTS = '-O3' DEBUG_OPTS = '-g -Wall' +# External libraries +HYPRE_DIR = "../hypre-2.7.0b/src/hypre" + # MFEM-specific options env.Append(CPPDEFINES = ['MFEM_USE_MEMALLOC']) @@ -31,6 +38,16 @@ if int(debug): else: env.Append(CCFLAGS = CC_OPTS) +# Parallel version +parallel = ARGUMENTS.get('parallel', 0) +if int(parallel): + env.Append(CPPDEFINES = ['MFEM_USE_MPI']) + env.Replace(CXX = 'mpiCC') + env.Append(CPPPATH = [HYPRE_DIR+"/include"]) + print 'Building parallel version' +else: + print 'Building serial version' + conf = Configure(env) # Check for LAPACK diff --git a/data/beam-hex.mesh b/data/beam-hex.mesh new file mode 100644 index 0000000000..28d7b33625 --- /dev/null +++ b/data/beam-hex.mesh @@ -0,0 +1,103 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +8 +1 5 0 1 10 9 18 19 28 27 +1 5 1 2 11 10 19 20 29 28 +1 5 2 3 12 11 20 21 30 29 +1 5 3 4 13 12 21 22 31 30 +2 5 4 5 14 13 22 23 32 31 +2 5 5 6 15 14 23 24 33 32 +2 5 6 7 16 15 24 25 34 33 +2 5 7 8 17 16 25 26 35 34 + +boundary +34 +3 3 9 10 1 0 +3 3 0 1 19 18 +3 3 10 9 27 28 +1 3 9 0 18 27 +3 3 18 19 28 27 +3 3 10 11 2 1 +3 3 1 2 20 19 +3 3 11 10 28 29 +3 3 19 20 29 28 +3 3 11 12 3 2 +3 3 2 3 21 20 +3 3 12 11 29 30 +3 3 20 21 30 29 +3 3 12 13 4 3 +3 3 3 4 22 21 +3 3 13 12 30 31 +3 3 21 22 31 30 +3 3 13 14 5 4 +3 3 4 5 23 22 +3 3 14 13 31 32 +3 3 22 23 32 31 +3 3 14 15 6 5 +3 3 5 6 24 23 +3 3 15 14 32 33 +3 3 23 24 33 32 +3 3 15 16 7 6 +3 3 6 7 25 24 +3 3 16 15 33 34 +3 3 24 25 34 33 +3 3 16 17 8 7 +3 3 7 8 26 25 +2 3 8 17 35 26 +3 3 17 16 34 35 +3 3 25 26 35 34 + +vertices +36 +3 +0 0 0 +1 0 0 +2 0 0 +3 0 0 +4 0 0 +5 0 0 +6 0 0 +7 0 0 +8 0 0 +0 1 0 +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 1 0 +6 1 0 +7 1 0 +8 1 0 +0 0 1 +1 0 1 +2 0 1 +3 0 1 +4 0 1 +5 0 1 +6 0 1 +7 0 1 +8 0 1 +0 1 1 +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 diff --git a/data/beam-hex.vtk b/data/beam-hex.vtk new file mode 100644 index 0000000000..c7506f726c --- /dev/null +++ b/data/beam-hex.vtk @@ -0,0 +1,70 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 36 double +0 0 0 +1 0 0 +2 0 0 +3 0 0 +4 0 0 +5 0 0 +6 0 0 +7 0 0 +8 0 0 +0 1 0 +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 1 0 +6 1 0 +7 1 0 +8 1 0 +0 0 1 +1 0 1 +2 0 1 +3 0 1 +4 0 1 +5 0 1 +6 0 1 +7 0 1 +8 0 1 +0 1 1 +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 +CELLS 8 72 +8 0 1 10 9 18 19 28 27 +8 1 2 11 10 19 20 29 28 +8 2 3 12 11 20 21 30 29 +8 3 4 13 12 21 22 31 30 +8 4 5 14 13 22 23 32 31 +8 5 6 15 14 23 24 33 32 +8 6 7 16 15 24 25 34 33 +8 7 8 17 16 25 26 35 34 +CELL_TYPES 8 +12 +12 +12 +12 +12 +12 +12 +12 +CELL_DATA 8 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +2 +2 +2 +2 diff --git a/data/beam-quad.mesh b/data/beam-quad.mesh new file mode 100644 index 0000000000..36916c42e8 --- /dev/null +++ b/data/beam-quad.mesh @@ -0,0 +1,69 @@ +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 +8 +1 3 0 1 10 9 +1 3 1 2 11 10 +1 3 2 3 12 11 +1 3 3 4 13 12 +2 3 4 5 14 13 +2 3 5 6 15 14 +2 3 6 7 16 15 +2 3 7 8 17 16 + +boundary +18 +3 1 1 0 +3 1 2 1 +3 1 3 2 +3 1 4 3 +3 1 5 4 +3 1 6 5 +3 1 7 6 +3 1 8 7 +3 1 9 10 +3 1 10 11 +3 1 11 12 +3 1 12 13 +3 1 13 14 +3 1 14 15 +3 1 15 16 +3 1 16 17 +1 1 0 9 +2 1 17 8 + +vertices +18 +2 +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +0 1 +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 diff --git a/data/beam-quad.vtk b/data/beam-quad.vtk new file mode 100644 index 0000000000..f6e7e50511 --- /dev/null +++ b/data/beam-quad.vtk @@ -0,0 +1,52 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 18 double +0 0 0 +1 0 0 +2 0 0 +3 0 0 +4 0 0 +5 0 0 +6 0 0 +7 0 0 +8 0 0 +0 1 0 +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 1 0 +6 1 0 +7 1 0 +8 1 0 +CELLS 8 40 +4 0 1 10 9 +4 1 2 11 10 +4 2 3 12 11 +4 3 4 13 12 +4 4 5 14 13 +4 5 6 15 14 +4 6 7 16 15 +4 7 8 17 16 +CELL_TYPES 8 +9 +9 +9 +9 +9 +9 +9 +9 +CELL_DATA 8 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +2 +2 +2 +2 diff --git a/data/beam-tet.mesh b/data/beam-tet.mesh new file mode 100644 index 0000000000..68a2edea0a --- /dev/null +++ b/data/beam-tet.mesh @@ -0,0 +1,177 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +48 +1 4 28 0 19 18 +1 4 0 28 19 1 +1 4 28 0 10 1 +1 4 28 0 18 27 +1 4 0 28 9 27 +1 4 28 0 9 10 +1 4 29 1 20 19 +1 4 1 29 20 2 +1 4 29 1 11 2 +1 4 29 1 19 28 +1 4 1 29 10 28 +1 4 29 1 10 11 +1 4 30 2 21 20 +1 4 2 30 21 3 +1 4 30 2 12 3 +1 4 30 2 20 29 +1 4 2 30 11 29 +1 4 30 2 11 12 +1 4 31 3 22 21 +1 4 3 31 22 4 +1 4 31 3 13 4 +1 4 31 3 21 30 +1 4 3 31 12 30 +1 4 31 3 12 13 +2 4 32 4 23 22 +2 4 4 32 23 5 +2 4 32 4 14 5 +2 4 32 4 22 31 +2 4 4 32 13 31 +2 4 32 4 13 14 +2 4 33 5 24 23 +2 4 5 33 24 6 +2 4 33 5 15 6 +2 4 33 5 23 32 +2 4 5 33 14 32 +2 4 33 5 14 15 +2 4 34 6 25 24 +2 4 6 34 25 7 +2 4 34 6 16 7 +2 4 34 6 24 33 +2 4 6 34 15 33 +2 4 34 6 15 16 +2 4 35 7 26 25 +2 4 7 35 26 8 +2 4 35 7 17 8 +2 4 35 7 25 34 +2 4 7 35 16 34 +2 4 35 7 16 17 + +boundary +68 +3 2 28 18 19 +3 2 0 19 18 +3 2 19 0 1 +3 2 0 10 1 +3 2 18 28 27 +1 2 27 0 18 +3 2 28 9 27 +1 2 0 27 9 +3 2 9 28 10 +3 2 10 0 9 +3 2 29 19 20 +3 2 1 20 19 +3 2 20 1 2 +3 2 1 11 2 +3 2 19 29 28 +3 2 29 10 28 +3 2 10 29 11 +3 2 11 1 10 +3 2 30 20 21 +3 2 2 21 20 +3 2 21 2 3 +3 2 2 12 3 +3 2 20 30 29 +3 2 30 11 29 +3 2 11 30 12 +3 2 12 2 11 +3 2 31 21 22 +3 2 3 22 21 +3 2 22 3 4 +3 2 3 13 4 +3 2 21 31 30 +3 2 31 12 30 +3 2 12 31 13 +3 2 13 3 12 +3 2 32 22 23 +3 2 4 23 22 +3 2 23 4 5 +3 2 4 14 5 +3 2 22 32 31 +3 2 32 13 31 +3 2 13 32 14 +3 2 14 4 13 +3 2 33 23 24 +3 2 5 24 23 +3 2 24 5 6 +3 2 5 15 6 +3 2 23 33 32 +3 2 33 14 32 +3 2 14 33 15 +3 2 15 5 14 +3 2 34 24 25 +3 2 6 25 24 +3 2 25 6 7 +3 2 6 16 7 +3 2 24 34 33 +3 2 34 15 33 +3 2 15 34 16 +3 2 16 6 15 +3 2 35 25 26 +3 2 7 26 25 +2 2 8 35 26 +3 2 26 7 8 +2 2 35 8 17 +3 2 7 17 8 +3 2 25 35 34 +3 2 35 16 34 +3 2 16 35 17 +3 2 17 7 16 + +vertices +36 +3 +0 0 0 +1 0 0 +2 0 0 +3 0 0 +4 0 0 +5 0 0 +6 0 0 +7 0 0 +8 0 0 +0 1 0 +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 1 0 +6 1 0 +7 1 0 +8 1 0 +0 0 1 +1 0 1 +2 0 1 +3 0 1 +4 0 1 +5 0 1 +6 0 1 +7 0 1 +8 0 1 +0 1 1 +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 diff --git a/data/beam-tet.vtk b/data/beam-tet.vtk new file mode 100644 index 0000000000..4b1a5a9b1d --- /dev/null +++ b/data/beam-tet.vtk @@ -0,0 +1,190 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 36 double +0 0 0 +1 0 0 +2 0 0 +3 0 0 +4 0 0 +5 0 0 +6 0 0 +7 0 0 +8 0 0 +0 1 0 +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 1 0 +6 1 0 +7 1 0 +8 1 0 +0 0 1 +1 0 1 +2 0 1 +3 0 1 +4 0 1 +5 0 1 +6 0 1 +7 0 1 +8 0 1 +0 1 1 +1 1 1 +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +8 1 1 +CELLS 48 240 +4 0 18 19 28 +4 1 0 19 28 +4 0 1 10 28 +4 0 18 28 27 +4 9 0 28 27 +4 0 10 9 28 +4 1 19 20 29 +4 2 1 20 29 +4 1 2 11 29 +4 1 19 29 28 +4 10 1 29 28 +4 1 11 10 29 +4 2 20 21 30 +4 3 2 21 30 +4 2 3 12 30 +4 2 20 30 29 +4 11 2 30 29 +4 2 12 11 30 +4 3 21 22 31 +4 4 3 22 31 +4 3 4 13 31 +4 3 21 31 30 +4 12 3 31 30 +4 3 13 12 31 +4 4 22 23 32 +4 5 4 23 32 +4 4 5 14 32 +4 4 22 32 31 +4 13 4 32 31 +4 4 14 13 32 +4 5 23 24 33 +4 6 5 24 33 +4 5 6 15 33 +4 5 23 33 32 +4 14 5 33 32 +4 5 15 14 33 +4 6 24 25 34 +4 7 6 25 34 +4 6 7 16 34 +4 6 24 34 33 +4 15 6 34 33 +4 6 16 15 34 +4 7 25 26 35 +4 8 7 26 35 +4 7 8 17 35 +4 7 25 35 34 +4 16 7 35 34 +4 7 17 16 35 +CELL_TYPES 48 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +CELL_DATA 48 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 diff --git a/data/beam-tri.mesh b/data/beam-tri.mesh new file mode 100644 index 0000000000..682cde377d --- /dev/null +++ b/data/beam-tri.mesh @@ -0,0 +1,77 @@ +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 +16 +1 2 10 0 1 +1 2 0 10 9 +1 2 11 1 2 +1 2 1 11 10 +1 2 12 2 3 +1 2 2 12 11 +1 2 13 3 4 +1 2 3 13 12 +2 2 14 4 5 +2 2 4 14 13 +2 2 15 5 6 +2 2 5 15 14 +2 2 16 6 7 +2 2 6 16 15 +2 2 17 7 8 +2 2 7 17 16 + +boundary +18 +3 1 1 0 +3 1 2 1 +3 1 3 2 +3 1 4 3 +3 1 5 4 +3 1 6 5 +3 1 7 6 +3 1 8 7 +3 1 9 10 +3 1 10 11 +3 1 11 12 +3 1 12 13 +3 1 13 14 +3 1 14 15 +3 1 15 16 +3 1 16 17 +1 1 0 9 +2 1 17 8 + +vertices +18 +2 +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +0 1 +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 diff --git a/data/beam-tri.vtk b/data/beam-tri.vtk new file mode 100644 index 0000000000..299c7ebd10 --- /dev/null +++ b/data/beam-tri.vtk @@ -0,0 +1,76 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 18 double +0 0 0 +1 0 0 +2 0 0 +3 0 0 +4 0 0 +5 0 0 +6 0 0 +7 0 0 +8 0 0 +0 1 0 +1 1 0 +2 1 0 +3 1 0 +4 1 0 +5 1 0 +6 1 0 +7 1 0 +8 1 0 +CELLS 16 64 +3 10 0 1 +3 0 10 9 +3 11 1 2 +3 1 11 10 +3 12 2 3 +3 2 12 11 +3 13 3 4 +3 3 13 12 +3 14 4 5 +3 4 14 13 +3 15 5 6 +3 5 15 14 +3 16 6 7 +3 6 16 15 +3 17 7 8 +3 7 17 16 +CELL_TYPES 16 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +CELL_DATA 16 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 diff --git a/data/escher-p2.mesh b/data/escher-p2.mesh new file mode 100644 index 0000000000..6a91aa875b --- /dev/null +++ b/data/escher-p2.mesh @@ -0,0 +1,472 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +42 +1 4 21 0 13 12 +1 4 4 11 12 0 +1 4 0 21 13 3 +1 4 5 6 0 7 +1 4 0 21 3 8 +1 4 0 21 20 12 +1 4 17 18 13 12 +1 4 21 0 20 7 +1 4 0 13 12 4 +1 4 20 0 12 6 +1 4 23 6 20 12 +1 4 1 10 8 3 +1 4 11 6 12 0 +1 4 10 9 8 3 +1 4 18 24 13 21 +1 4 0 8 3 1 +1 4 21 0 7 8 +1 4 7 21 8 15 +1 4 22 15 8 21 +1 4 1 2 3 0 +1 4 15 25 20 21 +1 4 4 14 3 13 +1 4 21 3 8 9 +1 4 18 23 20 12 +1 4 21 7 20 15 +1 4 24 9 13 21 +1 4 12 21 20 18 +1 4 2 4 3 0 +1 4 15 16 8 7 +1 4 1 5 0 7 +1 4 19 15 20 7 +1 4 4 17 13 12 +1 4 21 12 13 18 +1 4 3 21 13 9 +1 4 8 0 7 1 +1 4 6 19 20 7 +1 4 9 14 13 3 +1 4 16 1 8 7 +1 4 0 20 7 6 +1 4 13 0 3 4 +1 4 9 22 8 21 +1 4 25 18 20 21 + +boundary +48 +1 2 1 2 0 +2 2 2 1 3 +3 2 4 2 3 +4 2 2 4 0 +5 2 5 1 0 +6 2 6 5 0 +7 2 5 6 7 +8 2 1 5 7 +9 2 9 10 8 +10 2 10 9 3 +11 2 1 10 3 +12 2 10 1 8 +13 2 4 11 0 +14 2 11 4 12 +15 2 6 11 12 +16 2 11 6 0 +17 2 14 9 13 +18 2 4 14 13 +19 2 14 4 3 +20 2 9 14 3 +21 2 16 15 8 +22 2 1 16 8 +23 2 16 1 7 +24 2 15 16 7 +25 2 4 17 12 +26 2 17 4 13 +27 2 18 17 13 +28 2 17 18 12 +29 2 6 19 7 +30 2 19 6 20 +31 2 15 19 20 +32 2 19 15 7 +33 2 22 15 21 +34 2 9 22 21 +35 2 22 9 8 +36 2 15 22 8 +37 2 23 6 12 +38 2 18 23 12 +39 2 23 18 20 +40 2 6 23 20 +41 2 18 24 21 +42 2 24 18 13 +43 2 9 24 13 +44 2 24 9 21 +45 2 25 18 21 +46 2 15 25 21 +47 2 25 15 20 +48 2 18 25 20 + +vertices +26 + +nodes +FiniteElementSpace +FiniteElementCollection: Quadratic +VDim: 3 +Ordering: 0 + +-0.760829 +-0.815218 +-1.66544 +-0.800961 +-0.839706 +-0.807181 +0.0104972 +-0.0366123 +-0.00727995 +0.006645 +-0.824793 +-0.819801 +-0.0211731 +-0.0352077 +-0.884674 +0.839928 +0.024138 +-0.0404726 +0.809725 +0.863387 +0.803029 +0.836421 +0.7921 +0.874337 +0.797709 +1.667 +0.056823 +0.434913 +0.355216 +-0.364828 +-0.393384 +-0.0616594 +-0.854753 +-0.418851 +-0.798325 +-0.404239 +-0.866131 +-0.852123 +0.0491733 +-0.381889 +-0.390018 +-0.822251 +-0.43248 +-0.458402 +0.0410868 +-0.381003 +-0.370676 +0.408504 +-0.356051 +-0.0334942 +0.762853 +0.382683 +0.46043 +-0.0496363 +0.0614858 +0.469819 +0.386979 +0.448823 +0.432189 +-0.418255 +0.427949 +-0.0254903 +0.418764 +0.768561 +0.455359 +-0.889626 +-0.386653 +-0.754655 +-0.451884 +-0.827936 +-0.401754 +-0.481698 +-0.0458223 +-0.454599 +0.793791 +0.876057 +0.472834 +0.898585 +-0.820977 +0.0330922 +0.372662 +0.822668 +0.35148 +0.784027 +0.4492 +0.77154 +-1.31431 +-1.32611 +-1.21611 +1.29834 +0.807437 +1.25989 +1.20598 +-0.785357 +-0.817412 +-0.794406 +-0.365997 +0.364634 +0.872261 +0.786042 +0.454281 +-0.00377456 +-1.28148 +0.455186 +0.0145766 +0.00479858 +-0.792529 +-0.413184 +0.837242 +0.805911 +0.38917 +-0.376068 +0.470152 +-0.45578 +-0.360495 +0.426864 +1.23459 +0.0588346 +-0.815047 +-0.0476612 +0.0308944 +0.873182 +-0.835261 +0.041759 +-0.776244 +-0.864761 +0.0165312 +-0.817076 +0.824317 +0.805347 +0.756369 +0.918393 +-0.767126 +-1.72164 +1.75188 +0.815742 +-0.798005 +0.0217941 +0.0586046 +-0.861501 +0.912571 +0.809662 +-0.0427693 +0.0459792 +0.402102 +0.348799 +0.380951 +0.440786 +0.880177 +0.874146 +0.866999 +0.438528 +0.866317 +0.429589 +0.007743 +0.00679464 +0.427431 +-0.467517 +-0.449882 +-0.777095 +0.0131247 +-0.426959 +-0.352784 +-0.410048 +-0.378463 +-0.371881 +0.0617411 +0.0186508 +0.402115 +1.3186 +1.20518 +1.24837 +0.766423 +0.785011 +-0.448272 +-0.400174 +0.789856 +-0.00302677 +0.384566 +0.398307 +0.396642 +0.796043 +-0.897627 +-0.87883 +-0.378276 +-0.82352 +-0.417338 +0.410772 +-0.3903 +-0.358075 +-0.0235408 +0.818001 +0.375416 +0.801294 +0.474043 +-0.347001 +-0.876796 +-0.772686 +-0.392645 +-0.818634 +-0.798007 +-0.808164 +-0.374977 +-0.357031 +0.060182 +-0.0559456 +-0.414866 +-0.440683 +0.00708236 +0.0351619 +0.839332 +0.450553 +0.489099 +0.842441 +0.0442669 +0.862038 +0.362346 +0.414751 +0.35549 +0.463216 +-1.28706 +-1.27329 +-1.28871 +-0.828351 +-0.796577 +-0.880808 +-0.423237 +-0.809991 +1.32594 +-0.473327 +0.38261 +-1.2255 +-0.380755 +0.34974 +-0.557402 +0.0385256 +-0.0483124 +0.526571 +-0.0582038 +-1.18098 +-1.10701 +-0.566654 +0.579576 +1.1991 +1.1586 +-1.2242 +-0.570567 +0.549771 +1.24212 +0.01832 +-0.0395452 +-0.0560313 +-0.0579788 +-1.20706 +-0.561452 +0.603587 +1.22465 +-1.25257 +1.19134 +0.0176146 +-0.0337011 +0.584988 +-0.0127168 +-0.0467247 +-0.562292 +-0.0570638 +-0.545238 +-0.256285 +-0.332223 +-0.827647 +-0.89953 +-0.0601472 +0.585938 +0.636182 +-1.13035 +-0.863936 +-0.915554 +-0.874989 +-0.802399 +-0.629689 +-0.0549384 +0.53824 +0.534839 +-0.625972 +0.024047 +-0.539668 +0.0431132 +0.266029 +-0.230447 +0.252148 +-0.229271 +-0.0344415 +-0.541944 +0.271067 +-0.882897 +-0.879856 +-1.19097 +-0.91741 +-0.93867 +0.613613 +0.261497 +0.299545 +0.906555 +0.938637 +-1.17473 +1.17903 +0.874346 +0.912462 +0.658603 +0.296327 +0.95169 +0.956903 +-0.255837 +-0.0484137 +-0.338132 +0.281265 +0.342238 +0.661323 +0.927492 +0.938808 +-0.0453402 +0.319515 +-0.34306 +0.0572244 +-0.340599 +-0.294273 +0.26553 +0.604997 +0.322458 +0.887567 +0.838199 +0.808335 +-0.661958 +-0.261792 +1.23411 +0.878362 +-0.0397493 +-0.00377074 +0.282995 +-0.338908 +-0.664986 +-0.3001 +-0.654037 +-0.853738 +-0.887035 +-0.0358273 +-1.21618 +1.17384 +-0.0435913 +1.24643 +-0.0254092 diff --git a/data/escher-p2.vtk b/data/escher-p2.vtk new file mode 100644 index 0000000000..81d39c53bc --- /dev/null +++ b/data/escher-p2.vtk @@ -0,0 +1,253 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 117 double +-0.760829 0.0588346 -0.557402 +-0.815218 -0.815047 0.0385256 +-1.66544 -0.0476612 -0.0483124 +-0.800961 0.0308944 0.526571 +-0.839706 0.873182 -0.0582038 +-0.807181 -0.835261 -1.18098 +0.0104972 0.041759 -1.10701 +-0.0366123 -0.776244 -0.566654 +-0.00727995 -0.864761 0.579576 +0.006645 0.0165312 1.1991 +-0.824793 -0.817076 1.1586 +-0.819801 0.824317 -1.2242 +-0.0211731 0.805347 -0.570567 +-0.0352077 0.756369 0.549771 +-0.884674 0.918393 1.24212 +0.839928 -0.767126 0.01832 +0.024138 -1.72164 -0.0395452 +-0.0404726 1.75188 -0.0560313 +0.809725 0.815742 -0.0579788 +0.863387 -0.798005 -1.20706 +0.803029 0.0217941 -0.561452 +0.836421 0.0586046 0.603587 +0.7921 -0.861501 1.22465 +0.874337 0.912571 -1.25257 +0.797709 0.809662 1.19134 +1.667 -0.0427693 0.0176146 +0.056823 0.0459792 -0.0337011 +0.434913 0.402102 0.584988 +0.355216 0.348799 -0.0127168 +-0.364828 0.380951 -0.0467247 +-0.393384 0.440786 -0.562292 +-0.0616594 0.880177 -0.0570638 +-0.854753 0.874146 -0.545238 +-0.418851 0.866999 -0.256285 +-0.798325 0.438528 -0.332223 +-0.404239 0.866317 -0.827647 +-0.866131 0.429589 -0.89953 +-0.852123 0.007743 -0.0601472 +0.0491733 0.00679464 0.585938 +-0.381889 0.427431 0.636182 +-0.390018 -0.467517 -1.13035 +-0.822251 -0.449882 -0.863936 +-0.43248 -0.777095 -0.915554 +-0.458402 0.0131247 -0.874989 +0.0410868 -0.426959 -0.802399 +-0.381003 -0.352784 -0.629689 +-0.370676 -0.410048 -0.0549384 +0.408504 -0.378463 0.53824 +-0.356051 -0.371881 0.534839 +-0.0334942 0.0617411 -0.625972 +0.762853 0.0186508 0.024047 +0.382683 0.402115 -0.539668 +0.46043 1.3186 0.0431132 +-0.0496363 1.20518 0.266029 +0.0614858 1.24837 -0.230447 +0.469819 0.766423 0.252148 +0.386979 0.785011 -0.229271 +0.448823 -0.448272 -0.0344415 +0.432189 -0.400174 -0.541944 +-0.418255 0.789856 0.271067 +0.427949 -0.00302677 -0.882897 +-0.0254903 0.384566 -0.879856 +0.418764 0.398307 -1.19097 +0.768561 0.396642 -0.91741 +0.455359 0.796043 -0.93867 +-0.889626 -0.897627 0.613613 +-0.386653 -0.87883 0.261497 +-0.754655 -0.378276 0.299545 +-0.451884 -0.82352 0.906555 +-0.827936 -0.417338 0.938637 +-0.401754 0.410772 -1.17473 +-0.481698 -0.3903 1.17903 +-0.0458223 -0.358075 0.874346 +-0.454599 -0.0235408 0.912462 +0.793791 0.818001 0.658603 +0.876057 0.375416 0.296327 +0.472834 0.801294 0.95169 +0.898585 0.474043 0.956903 +-0.820977 -0.347001 -0.255837 +0.0330922 -0.876796 -0.0484137 +0.372662 -0.772686 -0.338132 +0.822668 -0.392645 0.281265 +0.35148 -0.818634 0.342238 +0.784027 -0.798007 0.661323 +0.4492 -0.808164 0.927492 +0.77154 -0.374977 0.938808 +-1.31431 -0.357031 -0.0453402 +-1.32611 0.060182 0.319515 +-1.21611 -0.0559456 -0.34306 +1.29834 -0.414866 0.0572244 +0.807437 -0.440683 -0.340599 +1.25989 0.00708236 -0.294273 +1.20598 0.0351619 0.26553 +-0.785357 0.839332 0.604997 +-0.817412 0.450553 0.322458 +-0.794406 0.489099 0.887567 +-0.365997 0.842441 0.838199 +0.364634 0.0442669 0.808335 +0.872261 0.862038 -0.661958 +0.786042 0.362346 -0.261792 +0.454281 0.414751 1.23411 +-0.00377456 0.35549 0.878362 +-1.28148 0.463216 -0.0397493 +0.455186 -1.28706 -0.00377074 +0.0145766 -1.27329 0.282995 +0.00479858 -1.28871 -0.338908 +-0.792529 -0.828351 -0.664986 +-0.413184 -0.796577 -0.3001 +0.837242 -0.880808 -0.654037 +0.805911 -0.423237 -0.853738 +0.38917 -0.809991 -0.887035 +-0.376068 1.32594 -0.0358273 +0.470152 -0.473327 -1.21618 +-0.45578 0.38261 1.17384 +-0.360495 -1.2255 -0.0435913 +0.426864 -0.380755 1.24643 +1.23459 0.34974 -0.0254092 +CELLS 42 462 +10 21 0 13 12 26 29 27 28 30 31 +10 4 11 12 0 32 35 33 34 36 30 +10 0 21 13 3 26 27 29 37 38 39 +10 5 6 0 7 40 43 41 42 44 45 +10 0 21 3 8 26 38 37 46 47 48 +10 0 21 20 12 26 50 49 30 28 51 +10 17 18 13 12 52 55 53 54 56 31 +10 21 0 20 7 26 49 50 57 45 58 +10 0 13 12 4 29 31 30 34 59 33 +10 20 0 12 6 49 30 51 60 43 61 +10 23 6 20 12 62 60 63 64 61 51 +10 1 10 8 3 65 68 66 67 69 48 +10 11 6 12 0 70 61 35 36 43 30 +10 10 9 8 3 71 72 68 69 73 48 +10 18 24 13 21 74 76 55 75 77 27 +10 0 8 3 1 46 48 37 78 66 67 +10 21 0 7 8 26 45 57 47 46 79 +10 7 21 8 15 57 47 79 80 81 82 +10 22 15 8 21 83 82 84 85 81 47 +10 1 2 3 0 86 87 67 78 88 37 +10 15 25 20 21 89 91 90 81 92 50 +10 4 14 3 13 93 95 94 59 96 39 +10 21 3 8 9 38 48 47 97 73 72 +10 18 23 20 12 98 63 99 56 64 51 +10 21 7 20 15 57 58 50 81 80 90 +10 24 9 13 21 100 101 76 77 97 27 +10 12 21 20 18 28 50 51 56 75 99 +10 2 4 3 0 102 94 87 88 34 37 +10 15 16 8 7 103 104 82 80 105 79 +10 1 5 0 7 106 41 78 107 42 45 +10 19 15 20 7 108 90 109 110 80 58 +10 4 17 13 12 111 53 59 33 54 31 +10 21 12 13 18 28 31 27 75 56 55 +10 3 21 13 9 38 27 39 73 97 101 +10 8 0 7 1 46 45 79 66 78 107 +10 6 19 20 7 112 109 60 44 110 58 +10 9 14 13 3 113 96 101 73 95 39 +10 16 1 8 7 114 66 104 105 107 79 +10 0 20 7 6 49 58 45 43 60 44 +10 13 0 3 4 29 37 39 59 34 94 +10 9 22 8 21 115 84 72 97 85 47 +10 25 18 20 21 116 99 91 92 75 50 +CELL_TYPES 42 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +24 +CELL_DATA 42 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/data/escher-p3.mesh b/data/escher-p3.mesh new file mode 100644 index 0000000000..eb1925f041 --- /dev/null +++ b/data/escher-p3.mesh @@ -0,0 +1,1069 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +42 +1 4 21 0 13 12 +1 4 4 11 12 0 +1 4 0 21 13 3 +1 4 5 6 0 7 +1 4 0 21 3 8 +1 4 0 21 20 12 +1 4 17 18 13 12 +1 4 21 0 20 7 +1 4 0 13 12 4 +1 4 20 0 12 6 +1 4 23 6 20 12 +1 4 1 10 8 3 +1 4 11 6 12 0 +1 4 10 9 8 3 +1 4 18 24 13 21 +1 4 0 8 3 1 +1 4 21 0 7 8 +1 4 7 21 8 15 +1 4 22 15 8 21 +1 4 1 2 3 0 +1 4 15 25 20 21 +1 4 4 14 3 13 +1 4 21 3 8 9 +1 4 18 23 20 12 +1 4 21 7 20 15 +1 4 24 9 13 21 +1 4 12 21 20 18 +1 4 2 4 3 0 +1 4 15 16 8 7 +1 4 1 5 0 7 +1 4 19 15 20 7 +1 4 4 17 13 12 +1 4 21 12 13 18 +1 4 3 21 13 9 +1 4 8 0 7 1 +1 4 6 19 20 7 +1 4 9 14 13 3 +1 4 16 1 8 7 +1 4 0 20 7 6 +1 4 13 0 3 4 +1 4 9 22 8 21 +1 4 25 18 20 21 + +boundary +48 +1 2 1 2 0 +2 2 2 1 3 +3 2 4 2 3 +4 2 2 4 0 +5 2 5 1 0 +6 2 6 5 0 +7 2 5 6 7 +8 2 1 5 7 +9 2 9 10 8 +10 2 10 9 3 +11 2 1 10 3 +12 2 10 1 8 +13 2 4 11 0 +14 2 11 4 12 +15 2 6 11 12 +16 2 11 6 0 +17 2 14 9 13 +18 2 4 14 13 +19 2 14 4 3 +20 2 9 14 3 +21 2 16 15 8 +22 2 1 16 8 +23 2 16 1 7 +24 2 15 16 7 +25 2 4 17 12 +26 2 17 4 13 +27 2 18 17 13 +28 2 17 18 12 +29 2 6 19 7 +30 2 19 6 20 +31 2 15 19 20 +32 2 19 15 7 +33 2 22 15 21 +34 2 9 22 21 +35 2 22 9 8 +36 2 15 22 8 +37 2 23 6 12 +38 2 18 23 12 +39 2 23 18 20 +40 2 6 23 20 +41 2 18 24 21 +42 2 24 18 13 +43 2 9 24 13 +44 2 24 9 21 +45 2 25 18 21 +46 2 15 25 21 +47 2 25 15 20 +48 2 18 25 20 + +vertices +26 + +nodes +FiniteElementSpace +FiniteElementCollection: Cubic +VDim: 3 +Ordering: 0 + +-0.823779 +-0.834944 +-1.68318 +-0.783154 +-0.851471 +-0.831658 +0.0327184 +0.0264235 +-0.039079 +-0.028778 +-0.835612 +-0.835055 +-0.0369275 +0.0237682 +-0.888956 +0.840981 +-0.0420482 +0.000577899 +0.797682 +0.829561 +0.853157 +0.858568 +0.881703 +0.866528 +0.853548 +1.71349 +-0.296085 +0.286579 +0.298747 +0.515945 +0.300726 +0.520767 +-0.548301 +-0.264883 +-0.577416 +-0.268246 +-0.015133 +0.0424967 +-0.841442 +-0.852302 +-0.573476 +-0.310945 +-0.853564 +-0.839706 +-0.53981 +-0.314531 +-0.871345 +-0.809929 +-0.802526 +-0.834036 +-0.307674 +0.279933 +-0.562663 +-0.23661 +-0.59073 +-0.25814 +-0.827974 +-0.838332 +-0.574697 +-0.300392 +-0.527622 +-0.29253 +0.00358899 +-0.0301242 +-0.514549 +-0.258798 +-0.527672 +-0.30038 +0.285166 +0.505607 +-0.54103 +-0.245446 +-0.306806 +0.281263 +0.777144 +0.852573 +0.294673 +0.506254 +0.295882 +0.537763 +-0.0131191 +0.0312822 +-0.0426718 +0.0121172 +0.295266 +0.524068 +0.266444 +0.525141 +0.296997 +0.575412 +0.280128 +0.543009 +-0.576478 +-0.303478 +0.283582 +0.584831 +0.0249189 +-0.0147879 +0.252775 +0.563376 +0.817608 +0.856662 +0.262538 +0.565967 +-0.847264 +-0.858709 +-0.553545 +-0.310701 +-0.829288 +-0.84552 +-0.286347 +-0.550644 +-0.871231 +-0.841321 +-0.298391 +-0.543272 +-0.261676 +-0.544414 +-0.0375677 +0.00389379 +-0.532737 +-0.258907 +0.787113 +0.863579 +0.841307 +0.830485 +0.304751 +0.575524 +0.871834 +0.873785 +-0.857439 +-0.827946 +0.0049548 +-0.0191662 +0.301154 +0.57397 +0.822617 +0.793409 +0.306132 +0.580525 +0.819049 +0.829359 +0.295187 +0.560374 +0.860694 +0.881518 +-1.13979 +-1.3985 +-1.38824 +-1.13434 +-1.14229 +-1.42041 +1.14898 +1.38224 +0.784938 +0.833621 +1.14443 +1.44124 +1.09338 +1.4399 +-0.80735 +-0.858067 +-0.84086 +-0.833786 +-0.821624 +-0.879964 +-0.315621 +-0.599322 +0.253703 +0.50492 +0.790841 +0.856215 +0.808995 +0.833342 +0.247636 +0.548782 +0.0137303 +-0.0189497 +-1.37408 +-1.12192 +0.547386 +0.233583 +0.0236465 +-0.00485117 +-0.0213397 +0.0352755 +-0.859892 +-0.874429 +-0.521653 +-0.278631 +0.869665 +0.841075 +0.860631 +0.800508 +0.310987 +0.551309 +-0.567627 +-0.232705 +0.280313 +0.570267 +-0.241219 +-0.566007 +-0.571033 +-0.280965 +0.25992 +0.54926 +1.12841 +1.443 +-0.266918 +0.278512 +-0.0236524 +-0.0436513 +-0.544357 +-0.582981 +-0.82496 +-0.521602 +0.0385041 +-0.528421 +-0.324954 +-0.253847 +-0.590776 +-0.242135 +-0.581199 +0.0288894 +-0.573545 +-0.0516109 +0.513684 +-0.00899557 +0.322889 +0.280572 +0.036646 +0.312499 +0.239174 +-0.0331965 +0.532121 +-0.0161773 +-0.281165 +-0.584225 +-0.294908 +0.311277 +0.00931575 +0.557784 +0.24473 +0.533925 +-0.550675 +-0.536364 +-0.860333 +-0.55516 +-0.575928 +-0.315009 +-0.295508 +-0.566213 +-0.317007 +0.551677 +0.520815 +0.809828 +0.553631 +-0.827798 +-0.528674 +-0.277459 +0.312135 +0.552748 +0.263216 +0.509367 +0.574999 +0.85089 +0.551314 +-1.14754 +-1.08741 +-1.09718 +1.07418 +0.807623 +1.0857 +1.07878 +-0.543902 +-0.522241 +-0.538122 +-0.803744 +0.252595 +0.0416414 +0.581401 +0.556346 +0.817489 +0.506677 +0.310391 +0.565226 +0.270856 +0.809171 +0.584477 +-0.856705 +-1.08168 +-1.07447 +0.0113892 +0.249978 +0.230424 +-0.55804 +-0.600351 +-0.831292 +0.551639 +0.581919 +0.797354 +-0.271438 +-0.299866 +-0.285974 +-0.261661 +0.300247 +0.248656 +0.541383 +-0.546785 +-0.295845 +-0.288437 +-0.268514 +0.588826 +0.300981 +1.1218 +1.14045 +-0.0179979 +-0.777877 +-0.0239725 +-0.0207154 +0.857772 +-0.889647 +-0.0263269 +-0.807014 +-0.831124 +-0.0240395 +-0.812946 +0.837786 +0.832667 +0.807646 +0.819214 +-0.7878 +-1.66967 +1.6883 +0.788522 +-0.850265 +-0.03139 +-0.0196939 +-0.821184 +0.874108 +0.864914 +-0.0288568 +-0.0233047 +0.000680925 +0.575426 +0.305291 +0.528895 +0.242399 +0.301048 +0.548455 +0.264547 +0.571625 +0.827562 +0.825415 +0.822301 +0.881058 +0.844239 +0.806185 +0.254113 +0.54538 +0.865008 +0.820606 +0.270736 +0.584465 +0.0185212 +0.00177013 +-0.0249471 +0.0299947 +0.297105 +0.50715 +-0.560286 +-0.290449 +-0.307243 +-0.53522 +-0.802195 +-0.863681 +0.0225762 +-0.0209402 +-0.293207 +-0.535736 +-0.246119 +-0.530127 +-0.27914 +-0.550083 +-0.564073 +-0.242364 +-0.28148 +-0.579194 +-0.0233738 +0.0154964 +0.00904907 +-0.0425372 +0.50923 +0.31096 +1.42543 +1.13983 +1.11043 +1.44386 +1.12659 +1.38829 +0.855978 +0.794997 +0.833094 +0.790745 +-0.576381 +-0.261072 +-0.561358 +-0.238776 +0.849513 +0.821293 +-0.000878391 +0.0161998 +0.248302 +0.579342 +0.250885 +0.567699 +0.30681 +0.569629 +0.83603 +0.883256 +-0.855549 +-0.867946 +-0.774732 +-0.834967 +-0.574956 +-0.257382 +-0.864619 +-0.830402 +-0.278348 +-0.546624 +0.317748 +0.570865 +-0.240417 +-0.561966 +-0.524884 +-0.304487 +-0.0254557 +-0.0404425 +0.785567 +0.804311 +0.551548 +0.272356 +0.853005 +0.867598 +0.276348 +0.603653 +-0.289554 +-0.572909 +-0.824018 +-0.783763 +-0.846499 +-0.807388 +-0.581016 +-0.303267 +-0.782995 +-0.840943 +-0.801254 +-0.798125 +-0.79939 +-0.851531 +-0.263985 +-0.549868 +-0.508737 +-0.2522 +-0.0190044 +0.011506 +0.0308101 +-0.00109678 +-0.530335 +-0.240256 +-0.537837 +-0.294206 +-0.0119896 +-0.0129704 +-0.0397983 +0.0242217 +0.806688 +0.827036 +0.309997 +0.55841 +0.260219 +0.532421 +0.808322 +0.822972 +-0.0232721 +-0.0290361 +0.829853 +0.799901 +0.513747 +0.258915 +0.276696 +0.60134 +0.234126 +0.528744 +0.280915 +0.53029 +-1.07323 +-1.41362 +-1.08384 +-1.39962 +-1.12951 +-1.41755 +-0.797674 +-0.825243 +-0.794463 +-0.782295 +-0.833051 +-0.88393 +-0.590963 +-0.293896 +-0.813286 +-0.843046 +1.11118 +1.44822 +-0.26021 +-0.549919 +0.249397 +0.549679 +-1.09088 +-1.43129 +-0.272551 +-0.598181 +0.510913 +0.288808 +0.542718 +0.563214 +0.221346 +0.264586 +0.527192 +0.575007 +0.515581 +0.826731 +0.251756 +0.305379 +-0.037405 +-0.313405 +-0.53114 +-0.547332 +-0.325862 +-0.31235 +-0.229886 +-0.250439 +0.272494 +0.270016 +0.0156466 +0.797312 +1.08503 +1.13483 +1.11837 +-0.234991 +-0.229464 +-0.305038 +0.781919 +0.511685 +0.305116 +0.278837 +0.0290993 +0.592894 +0.512977 +0.240867 +-0.532438 +-0.583351 +-0.557497 +-0.869694 +0.322352 +0.568849 +-0.310525 +-0.264947 +-0.578973 +0.519399 +0.565756 +0.53322 +0.853399 +-0.293277 +-0.526147 +-0.550633 +-0.541764 +-0.510272 +-0.844241 +-0.579209 +-0.527212 +-0.585104 +-0.847187 +0.0377078 +-0.290363 +-0.300988 +0.000476773 +-0.303619 +-0.308585 +-0.271014 +0.524771 +0.575082 +0.833668 +0.567764 +-0.238535 +-0.000843653 +0.524623 +0.867793 +0.530718 +-0.543122 +0.231473 +0.324686 +0.578558 +0.29848 +0.519683 +0.269029 +0.248659 +0.293544 +-1.12508 +-1.12075 +-1.0832 +-0.570766 +-0.821128 +-0.589522 +-0.589977 +-0.795231 +-0.574249 +1.12378 +1.06967 +0.262272 +-0.847557 +-0.301961 +-0.579036 +-0.266983 +0.309042 +0.52426 +-1.14051 +-1.15235 +-0.321232 +-0.565695 +0.277947 +0.237398 +-0.589926 +-0.0157012 +0.0363972 +0.582989 +0.0240253 +-1.23709 +-1.17114 +-0.608129 +0.582149 +1.12416 +1.19113 +-1.23761 +-0.597225 +0.573221 +1.1634 +0.00563393 +-0.0373515 +-0.0415116 +0.0386035 +-1.2311 +-0.604635 +0.551083 +1.24202 +-1.16505 +1.19083 +-0.0356747 +-0.244887 +0.182689 +0.576496 +0.584214 +-0.19113 +0.221883 +-0.158424 +0.186287 +-0.585142 +-0.562162 +-0.186082 +0.211079 +-0.373908 +-0.836534 +-0.161496 +-0.414841 +-0.404571 +-0.224235 +-0.987331 +-0.805492 +-0.769671 +-0.980588 +-0.208048 +0.204903 +0.611056 +0.577331 +0.606399 +0.603317 +-1.1921 +-1.20104 +-0.75173 +-0.998373 +-0.989526 +-0.796703 +-0.807741 +-0.997135 +-0.985246 +-0.730851 +-0.575534 +-0.565274 +-0.181176 +0.15777 +0.565192 +0.573033 +0.553837 +0.553282 +-0.568745 +-0.577671 +-0.205439 +0.166984 +-0.552916 +-0.61649 +0.0336853 +-0.035004 +0.401541 +0.216715 +-0.375829 +-0.19002 +0.391591 +0.155219 +-0.368131 +-0.19447 +-0.188758 +0.173015 +-0.546072 +-0.568735 +0.180993 +0.350319 +-0.95755 +-0.736578 +-0.941892 +-0.796689 +-1.12917 +-1.22449 +-0.774871 +-1.02206 +-0.803186 +-1.01963 +0.420041 +0.818336 +0.187246 +0.384044 +0.210181 +0.369577 +0.795073 +0.987164 +0.751271 +0.969563 +-1.13445 +-1.17344 +1.15075 +1.19929 +0.739873 +0.988374 +0.803404 +0.920738 +0.393605 +0.782615 +0.15922 +0.42434 +0.755634 +1.02723 +0.755681 +0.963649 +-0.346708 +-0.168241 +-0.20637 +0.171912 +-0.426156 +-0.231661 +0.228783 +0.381303 +0.387697 +0.203651 +0.426595 +0.770919 +0.745078 +1.02951 +0.771137 +1.036 +0.00442507 +0.00734874 +0.198444 +0.402633 +-0.394772 +-0.195982 +0.0191218 +0.0258644 +-0.173736 +-0.356679 +-0.362557 +-0.160334 +0.40069 +0.227704 +0.445446 +0.814911 +0.400515 +0.177935 +0.820814 +1.01409 +0.775689 +1.02361 +0.933013 +0.804598 +-0.407303 +-0.765277 +-0.232602 +-0.387845 +1.19945 +1.17589 +0.954957 +0.758155 +0.0385062 +0.0425857 +-0.0383422 +-0.0154603 +0.37986 +0.217324 +-0.41859 +-0.222334 +-0.392152 +-0.77118 +-0.233143 +-0.402877 +-0.378057 +-0.8464 +-0.959791 +-0.790987 +-0.800174 +-0.969934 +-0.0305009 +0.0196101 +-1.16218 +-1.20531 +1.18308 +1.14897 +-0.0219282 +0.0141027 +1.17298 +1.15049 +-0.0429287 +0.0378027 +-0.198496 +0.231014 +-0.147999 +0.191878 +-0.806746 +-0.397382 +-0.614101 +-0.603892 +0.578682 +0.225713 +0.166943 +-0.766298 +-0.815233 +-1.02033 +-0.974089 +0.542473 +0.191435 +0.236551 +-0.15876 +-0.565151 +-0.178336 +0.000139963 +0.0401609 +-0.213707 +0.196835 +-0.60249 +-0.156542 +-0.2396 +-0.0195396 +0.0370416 +-0.727612 +-0.752522 +-0.737058 +-0.751264 +-1.0061 +-1.00961 +0.765527 +0.382586 +0.598735 +0.618542 +-0.99157 +-0.951724 +0.753894 +0.982781 +1.00998 +0.819819 +0.396257 +0.579944 +0.619283 +0.0021839 +0.0409979 +-0.199936 +0.15191 +0.422074 +0.0147138 +0.00658677 +0.755149 +0.602395 +0.606786 +-0.00772069 +-0.190457 +0.204128 +-0.0340408 +-0.00818377 +0.195632 +-0.209184 +0.792245 +0.410117 +0.619394 +0.560021 +0.775609 +0.739306 +-0.348649 +-0.560707 +-0.578221 +-0.3617 +0.791738 +0.963094 +0.944617 +0.00325004 +0.0292808 +-0.0355936 +-0.152713 +0.224962 +-0.0424685 +-0.181671 +0.187644 +-0.414148 +-0.619747 +-0.630941 +-0.780578 +-0.57366 +-0.575169 +-0.176111 +0.16069 +0.748738 +0.0424799 +-0.752579 +-1.01913 +-0.954727 +1.00673 +0.989562 +-0.15514 +0.213066 +0.979174 +0.988721 +0.192838 +-0.214116 diff --git a/data/escher.mesh b/data/escher.mesh new file mode 100644 index 0000000000..032f43f30d --- /dev/null +++ b/data/escher.mesh @@ -0,0 +1,141 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +42 +1 4 21 0 13 12 +1 4 4 11 12 0 +1 4 0 21 13 3 +1 4 5 6 0 7 +1 4 0 21 3 8 +1 4 0 21 20 12 +1 4 17 18 13 12 +1 4 21 0 20 7 +1 4 0 13 12 4 +1 4 20 0 12 6 +1 4 23 6 20 12 +1 4 1 10 8 3 +1 4 11 6 12 0 +1 4 10 9 8 3 +1 4 18 24 13 21 +1 4 0 8 3 1 +1 4 21 0 7 8 +1 4 7 21 8 15 +1 4 22 15 8 21 +1 4 1 2 3 0 +1 4 15 25 20 21 +1 4 4 14 3 13 +1 4 21 3 8 9 +1 4 18 23 20 12 +1 4 21 7 20 15 +1 4 24 9 13 21 +1 4 12 21 20 18 +1 4 2 4 3 0 +1 4 15 16 8 7 +1 4 1 5 0 7 +1 4 19 15 20 7 +1 4 4 17 13 12 +1 4 21 12 13 18 +1 4 3 21 13 9 +1 4 8 0 7 1 +1 4 6 19 20 7 +1 4 9 14 13 3 +1 4 16 1 8 7 +1 4 0 20 7 6 +1 4 13 0 3 4 +1 4 9 22 8 21 +1 4 25 18 20 21 + +boundary +48 +1 2 1 2 0 +2 2 2 1 3 +3 2 4 2 3 +4 2 2 4 0 +5 2 5 1 0 +6 2 6 5 0 +7 2 5 6 7 +8 2 1 5 7 +9 2 9 10 8 +10 2 10 9 3 +11 2 1 10 3 +12 2 10 1 8 +13 2 4 11 0 +14 2 11 4 12 +15 2 6 11 12 +16 2 11 6 0 +17 2 14 9 13 +18 2 4 14 13 +19 2 14 4 3 +20 2 9 14 3 +21 2 16 15 8 +22 2 1 16 8 +23 2 16 1 7 +24 2 15 16 7 +25 2 4 17 12 +26 2 17 4 13 +27 2 18 17 13 +28 2 17 18 12 +29 2 6 19 7 +30 2 19 6 20 +31 2 15 19 20 +32 2 19 15 7 +33 2 22 15 21 +34 2 9 22 21 +35 2 22 9 8 +36 2 15 22 8 +37 2 23 6 12 +38 2 18 23 12 +39 2 23 18 20 +40 2 6 23 20 +41 2 18 24 21 +42 2 24 18 13 +43 2 9 24 13 +44 2 24 9 21 +45 2 25 18 21 +46 2 15 25 21 +47 2 25 15 20 +48 2 18 25 20 + +vertices +26 +3 +-0.816497 0 -0.57735 +-0.816497 -0.816497 0 +-1.70538 0 0 +-0.816497 0 0.57735 +-0.816497 0.816497 0 +-0.852693 -0.852693 -1.20589 +0 0 -1.1547 +0 -0.816497 -0.57735 +0 -0.816497 0.57735 +0 0 1.1547 +-0.852693 -0.852693 1.20589 +-0.852693 0.852693 -1.20589 +0 0.816497 -0.57735 +0 0.816497 0.57735 +-0.852693 0.852693 1.20589 +0.816497 -0.816497 0 +0 -1.70538 0 +0 1.70538 0 +0.816497 0.816497 0 +0.852693 -0.852693 -1.20589 +0.816497 0 -0.57735 +0.816497 0 0.57735 +0.852693 -0.852693 1.20589 +0.852693 0.852693 -1.20589 +0.852693 0.852693 1.20589 +1.70538 0 0 diff --git a/data/escher.vtk b/data/escher.vtk new file mode 100644 index 0000000000..c966727488 --- /dev/null +++ b/data/escher.vtk @@ -0,0 +1,162 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 26 double +-0.816497 0 -0.57735 +-0.816497 -0.816497 0 +-1.705385 0 0 +-0.816497 0 0.57735 +-0.816497 0.816497 0 +-0.852693 -0.852693 -1.20589 +0 0 -1.154701 +0 -0.816497 -0.57735 +0 -0.816497 0.57735 +0 0 1.154701 +-0.852693 -0.852693 1.20589 +-0.852693 0.852693 -1.20589 +0 0.816497 -0.57735 +0 0.816497 0.57735 +-0.852693 0.852693 1.20589 +0.816497 -0.816497 0 +0 -1.705385 0 +0 1.705385 0 +0.816497 0.816497 0 +0.852693 -0.852693 -1.20589 +0.816497 0 -0.57735 +0.816497 0 0.57735 +0.852693 -0.852693 1.20589 +0.852693 0.852693 -1.20589 +0.852693 0.852693 1.20589 +1.705385 0 0 +CELLS 42 210 +4 13 21 0 12 +4 11 12 4 0 +4 21 3 13 0 +4 6 7 0 5 +4 21 3 0 8 +4 21 20 0 12 +4 17 18 13 12 +4 7 21 20 0 +4 12 13 4 0 +4 6 20 12 0 +4 6 20 23 12 +4 10 3 8 1 +4 11 6 12 0 +4 3 10 8 9 +4 21 18 13 24 +4 3 1 0 8 +4 7 21 0 8 +4 7 21 8 15 +4 21 22 8 15 +4 2 3 1 0 +4 25 21 20 15 +4 14 3 4 13 +4 21 3 8 9 +4 20 18 23 12 +4 7 21 15 20 +4 13 21 24 9 +4 18 21 12 20 +4 3 2 4 0 +4 16 7 8 15 +4 5 7 0 1 +4 20 7 19 15 +4 17 13 4 12 +4 21 18 12 13 +4 21 3 9 13 +4 1 7 0 8 +4 7 6 20 19 +4 14 3 13 9 +4 7 16 8 1 +4 6 7 20 0 +4 13 3 4 0 +4 22 21 8 9 +4 25 18 20 21 +CELL_TYPES 42 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +CELL_DATA 42 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/data/fichera-q2.mesh b/data/fichera-q2.mesh new file mode 100644 index 0000000000..ce03d407ef --- /dev/null +++ b/data/fichera-q2.mesh @@ -0,0 +1,413 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +7 +1 5 0 1 4 3 9 10 13 12 +1 5 3 4 7 6 12 13 16 15 +1 5 2 3 6 5 11 12 15 14 +1 5 8 9 12 11 17 18 21 20 +1 5 9 10 13 12 18 19 22 21 +1 5 12 13 16 15 21 22 25 24 +1 5 11 12 15 14 20 21 24 23 + +boundary +24 +1 3 5 6 3 2 +2 3 6 7 4 3 +3 3 3 4 1 0 +4 3 11 12 9 8 +5 3 2 3 12 11 +6 3 0 1 10 9 +7 3 9 10 19 18 +8 3 8 9 18 17 +9 3 1 4 13 10 +10 3 4 7 16 13 +11 3 13 16 25 22 +12 3 10 13 22 19 +13 3 7 6 15 16 +14 3 6 5 14 15 +15 3 15 14 23 24 +16 3 16 15 24 25 +17 3 5 2 11 14 +18 3 3 0 9 12 +19 3 11 8 17 20 +20 3 14 11 20 23 +21 3 17 18 21 20 +22 3 18 19 22 21 +23 3 21 22 25 24 +24 3 20 21 24 23 + +vertices +26 + +nodes +FiniteElementSpace +FiniteElementCollection: Quadratic +VDim: 3 +Ordering: 0 + +0.00628329 +0.963257 +-1.0248 +-0.0270451 +0.976458 +-1.03322 +0.0373603 +1.05313 +-0.99363 +0.0334328 +0.946167 +-1.01254 +0.0104008 +0.961519 +-1.00773 +-0.0442042 +1.01027 +-1.0331 +0.0361332 +0.966214 +-0.982013 +-0.035459 +0.968524 +-1.02938 +0.0388312 +0.990383 +0.54004 +1.01734 +0.512914 +0.0326975 +0.440887 +0.956698 +0.558455 +-0.0214104 +-0.00784735 +0.972413 +1.00787 +-0.0329871 +0.963045 +0.451745 +-0.0620543 +0.971711 +0.501704 +0.0108465 +0.99573 +0.0564777 +-0.470858 +-0.556498 +-1.03913 +-0.497225 +-0.527783 +-0.95864 +-0.970184 +-0.996759 +-0.550521 +-0.993852 +-0.443876 +0.0520186 +-0.539011 +-0.993462 +-0.977784 +-0.0356244 +0.0257358 +-0.981829 +0.505465 +0.955388 +0.553084 +0.95084 +0.984901 +0.953629 +0.465084 +-0.0146529 +0.98784 +0.0292889 +-0.441306 +-0.95393 +-0.976733 +0.525336 +0.552072 +1.04664 +0.465611 +-0.0382111 +0.5255 +0.557928 +1.02753 +0.537479 +0.00157517 +0.521154 +-0.473002 +-0.474936 +-0.534808 +-1.01329 +-0.448061 +-0.446572 +-0.557615 +-0.00509539 +-0.553684 +-0.942031 +-0.491756 +0.493718 +0.949098 +0.535829 +0.541565 +0.999438 +0.502618 +0.0377584 +0.483008 +-0.536616 +-0.999406 +-0.52742 +0.447524 +0.528705 +-0.503131 +-0.464476 +0.524133 +0.461899 +-0.489497 +-1.03679 +-0.954447 +-0.0249993 +0.0507721 +-0.0517551 +1.02421 +1.04021 +0.939173 +-0.970901 +-1.02738 +-1.05201 +0.0245686 +0.0433603 +0.0042067 +1.03617 +1.01669 +0.983272 +-1.0269 +-1.04319 +-1.04147 +0.0186122 +-0.0173093 +0.0216241 +1.05369 +0.992715 +0.98783 +-1.01194 +-0.534261 +-0.0505374 +-0.487539 +-0.961258 +-0.524829 +-0.00448644 +-0.548757 +-1.03656 +-0.993742 +0.0379572 +-0.0588457 +0.507931 +1.00456 +0.47627 +0.51842 +0.966625 +0.457131 +0.960127 +0.940292 +0.0363197 +1.0059 +0.475896 +0.0556263 +1.02693 +0.557008 +-0.024183 +0.986052 +-0.951799 +-0.468968 +-0.963618 +-0.526238 +0.0592706 +-0.451655 +-0.951278 +-0.964487 +-0.0389845 +-0.018264 +-0.950745 +-0.513042 +0.0504945 +-0.975288 +-0.00938734 +0.495926 +0.966769 +0.529383 +0.951846 +0.995894 +1.04901 +0.474473 +0.998686 +-0.477166 +-0.957129 +-0.462918 +0.0159598 +-0.4927 +-0.46841 +0.554277 +0.555852 +1.01729 +0.522809 +0.529734 +0.553553 +0.0195791 +1.01558 +0.539775 +0.492592 +-0.460906 +-1.04099 +-0.520653 +-0.0364473 +-0.552994 +-0.558441 +-0.983335 +-0.494568 +-0.0291716 +-0.516452 +0.519777 +1.02922 +0.470062 +0.55675 +0.965409 +0.555396 +0.537122 +-0.560009 +0.508856 +0.481921 +-0.465918 +-0.499368 +0.475273 +0.488873 +-1.03906 +-1.05749 +-1.02007 +-0.95698 +-0.979414 +-1.0428 +-1.02689 +-1.00282 +-0.0212876 +0.0149584 +0.0232333 +-0.0117818 +0.0190177 +-0.0226014 +0.0561498 +0.0523461 +0.0234471 +1.01343 +1.01907 +1.05601 +1.00768 +1.04698 +1.04891 +0.982299 +1.04947 +0.995261 +-0.97328 +-0.978948 +-0.941607 +-1.06051 +-0.0525756 +-0.0431664 +-0.0554992 +-0.0101499 +-0.437646 +-0.472413 +-0.490449 +-0.527035 +-1.03773 +-0.949236 +-0.949577 +0.0480009 +-0.0235182 +0.00694111 +-0.5371 +-0.529868 +-1.00321 +-0.951153 +-0.953941 +-0.0466438 +0.0423559 +-0.00876341 +-0.562166 +-0.471239 +0.0360357 +0.0498041 +0.961521 +1.00026 +1.00836 +0.957414 +0.502249 +0.51828 +0.476748 +0.50925 +0.94563 +0.976601 +0.974337 +0.517681 +0.512066 +0.999105 +1.00595 +0.99999 +0.484606 +0.544927 +0.944431 +1.01001 +0.452558 +-0.996282 +-0.503648 +-0.438883 +-0.480426 +-0.523792 +-0.010146 +-0.980091 +-0.557531 +-0.53661 +-0.492787 +-0.0335099 +-0.973854 +-0.546931 +-0.513596 +-0.534105 +0.0338487 +0.0256522 +0.537646 +0.541979 +0.439754 +0.449483 +0.99716 +0.51432 +0.511088 +0.440605 +0.95181 +0.558194 +0.548032 +0.458741 +1.0057 +0.438091 +0.524959 +0.939551 +-0.438292 +-0.517967 +-0.521741 +0.489062 +0.439442 +0.483228 +0.514952 diff --git a/data/fichera-q2.vtk b/data/fichera-q2.vtk new file mode 100644 index 0000000000..a7a6294e84 --- /dev/null +++ b/data/fichera-q2.vtk @@ -0,0 +1,148 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 117 double +0.00628329 -1.03679 -1.03906 +0.963257 -0.954447 -1.05749 +-1.0248 -0.0249993 -1.02007 +-0.0270451 0.0507721 -0.95698 +0.976458 -0.0517551 -0.979414 +-1.03322 1.02421 -1.0428 +0.0373603 1.04021 -1.02689 +1.05313 0.939173 -1.00282 +-0.99363 -0.970901 -0.0212876 +0.0334328 -1.02738 0.0149584 +0.946167 -1.05201 0.0232333 +-1.01254 0.0245686 -0.0117818 +0.0104008 0.0433603 0.0190177 +0.961519 0.0042067 -0.0226014 +-1.00773 1.03617 0.0561498 +-0.0442042 1.01669 0.0523461 +1.01027 0.983272 0.0234471 +-1.0331 -1.0269 1.01343 +0.0361332 -1.04319 1.01907 +0.966214 -1.04147 1.05601 +-0.982013 0.0186122 1.00768 +-0.035459 -0.0173093 1.04698 +0.968524 0.0216241 1.04891 +-1.02938 1.05369 0.982299 +0.0388312 0.992715 1.04947 +0.990383 0.98783 0.995261 +0.54004 -1.01194 -0.97328 +1.01734 -0.534261 -0.978948 +0.512914 -0.0505374 -0.941607 +0.0326975 -0.487539 -1.06051 +0.440887 -0.961258 -0.0525756 +0.956698 -0.524829 -0.0431664 +0.558455 -0.00448644 -0.0554992 +-0.0214104 -0.548757 -0.0101499 +-0.00784735 -1.03656 -0.437646 +0.972413 -0.993742 -0.472413 +1.00787 0.0379572 -0.490449 +-0.0329871 -0.0588457 -0.527035 +0.963045 0.507931 -1.03773 +0.451745 1.00456 -0.949236 +-0.0620543 0.47627 -0.949577 +0.971711 0.51842 0.0480009 +0.501704 0.966625 -0.0235182 +0.0108465 0.457131 0.00694111 +0.99573 0.960127 -0.5371 +0.0564777 0.940292 -0.529868 +-0.470858 0.0363197 -1.00321 +-0.556498 1.0059 -0.951153 +-1.03913 0.475896 -0.953941 +-0.497225 0.0556263 -0.0466438 +-0.527783 1.02693 0.0423559 +-0.95864 0.557008 -0.00876341 +-0.970184 -0.024183 -0.562166 +-0.996759 0.986052 -0.471239 +-0.550521 -0.951799 0.0360357 +-0.993852 -0.468968 0.0498041 +-0.443876 -0.963618 0.961521 +0.0520186 -0.526238 1.00026 +-0.539011 0.0592706 1.00836 +-0.993462 -0.451655 0.957414 +-0.977784 -0.951278 0.502249 +-0.0356244 -0.964487 0.51828 +0.0257358 -0.0389845 0.476748 +-0.981829 -0.018264 0.50925 +0.505465 -0.950745 0.94563 +0.955388 -0.513042 0.976601 +0.553084 0.0504945 0.974337 +0.95084 -0.975288 0.517681 +0.984901 -0.00938734 0.512066 +0.953629 0.495926 0.999105 +0.465084 0.966769 1.00595 +-0.0146529 0.529383 0.99999 +0.98784 0.951846 0.484606 +0.0292889 0.995894 0.544927 +-0.441306 1.04901 0.944431 +-0.95393 0.474473 1.01001 +-0.976733 0.998686 0.452558 +0.525336 -0.477166 -0.996282 +0.552072 -0.957129 -0.503648 +1.04664 -0.462918 -0.438883 +0.465611 0.0159598 -0.480426 +-0.0382111 -0.4927 -0.523792 +0.5255 -0.46841 -0.010146 +0.557928 0.554277 -0.980091 +1.02753 0.555852 -0.557531 +0.537479 1.01729 -0.53661 +0.00157517 0.522809 -0.492787 +0.521154 0.529734 -0.0335099 +-0.473002 0.553553 -0.973854 +-0.474936 0.0195791 -0.546931 +-0.534808 1.01558 -0.513596 +-1.01329 0.539775 -0.534105 +-0.448061 0.492592 0.0338487 +-0.446572 -0.460906 0.0256522 +-0.557615 -1.04099 0.537646 +-0.00509539 -0.520653 0.541979 +-0.553684 -0.0364473 0.439754 +-0.942031 -0.552994 0.449483 +-0.491756 -0.558441 0.99716 +0.493718 -0.983335 0.51432 +0.949098 -0.494568 0.511088 +0.535829 -0.0291716 0.440605 +0.541565 -0.516452 0.95181 +0.999438 0.519777 0.558194 +0.502618 1.02922 0.548032 +0.0377584 0.470062 0.458741 +0.483008 0.55675 1.0057 +-0.536616 0.965409 0.438091 +-0.999406 0.555396 0.524959 +-0.52742 0.537122 0.939551 +0.447524 -0.560009 -0.438292 +0.528705 0.508856 -0.517967 +-0.503131 0.481921 -0.521741 +-0.464476 -0.465918 0.489062 +0.524133 -0.499368 0.439442 +0.461899 0.475273 0.483228 +-0.489497 0.488873 0.514952 +CELLS 7 196 +27 0 1 4 3 9 10 13 12 26 27 28 29 30 31 32 33 34 35 36 37 81 79 78 80 77 82 110 +27 3 4 7 6 12 13 16 15 28 38 39 40 32 41 42 43 37 36 44 45 86 84 80 85 83 87 111 +27 2 3 6 5 11 12 15 14 46 40 47 48 49 43 50 51 52 37 45 53 91 86 89 90 88 92 112 +27 8 9 12 11 17 18 21 20 54 33 49 55 56 57 58 59 60 61 62 63 97 95 94 96 93 98 113 +27 9 10 13 12 18 19 22 21 30 31 32 33 64 65 66 57 61 67 68 62 95 100 99 101 82 102 114 +27 12 13 16 15 21 22 25 24 32 41 42 43 66 69 70 71 62 68 72 73 105 103 101 104 87 106 115 +27 11 12 15 14 20 21 24 23 49 43 50 51 58 71 74 75 63 62 73 76 108 105 96 107 92 109 116 +CELL_TYPES 7 +29 +29 +29 +29 +29 +29 +29 +CELL_DATA 7 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 diff --git a/data/fichera-q3.mesh b/data/fichera-q3.mesh new file mode 100644 index 0000000000..b1d3ec683d --- /dev/null +++ b/data/fichera-q3.mesh @@ -0,0 +1,1010 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +7 +1 5 0 1 4 3 9 10 13 12 +1 5 3 4 7 6 12 13 16 15 +1 5 2 3 6 5 11 12 15 14 +1 5 8 9 12 11 17 18 21 20 +1 5 9 10 13 12 18 19 22 21 +1 5 12 13 16 15 21 22 25 24 +1 5 11 12 15 14 20 21 24 23 + +boundary +24 +1 3 5 6 3 2 +2 3 6 7 4 3 +3 3 3 4 1 0 +4 3 11 12 9 8 +5 3 2 3 12 11 +6 3 0 1 10 9 +7 3 9 10 19 18 +8 3 8 9 18 17 +9 3 1 4 13 10 +10 3 4 7 16 13 +11 3 13 16 25 22 +12 3 10 13 22 19 +13 3 7 6 15 16 +14 3 6 5 14 15 +15 3 15 14 23 24 +16 3 16 15 24 25 +17 3 5 2 11 14 +18 3 3 0 9 12 +19 3 11 8 17 20 +20 3 14 11 20 23 +21 3 17 18 21 20 +22 3 18 19 22 21 +23 3 21 22 25 24 +24 3 20 21 24 23 + +vertices +26 + +nodes +FiniteElementSpace +FiniteElementCollection: Cubic +VDim: 3 +Ordering: 0 + +0.0236349 +0.981393 +-1.02459 +0.0361568 +0.972101 +-1.03818 +0.0275115 +1.0163 +-0.964464 +-0.0141065 +1.02499 +-1.00106 +0.0089068 +0.964875 +-0.993002 +0.024033 +0.985637 +-1.01586 +0.0223488 +1.00255 +-0.986949 +0.0237325 +1.02343 +-0.983467 +-0.000693864 +1.04046 +0.330667 +0.648847 +1.01087 +0.985013 +0.298462 +0.659509 +0.0080726 +-0.01779 +0.320665 +0.688507 +0.985695 +0.973177 +0.329811 +0.646231 +0.000737089 +-0.0201989 +0.0201752 +-0.0320228 +0.986343 +0.985507 +1.03368 +1.01365 +0.0113084 +0.0143591 +0.974527 +0.982693 +0.329758 +0.706294 +0.0408931 +0.0373977 +1.03842 +0.99656 +0.311245 +0.674298 +0.0232392 +-0.0152927 +0.958806 +0.989645 +0.00858399 +-0.0121949 +-0.696848 +-0.297388 +-0.664018 +-0.32537 +-1.02616 +-1.03828 +-0.637236 +-0.297648 +-0.695304 +-0.359226 +-1.02047 +-1.03663 +-0.97058 +-0.967499 +-0.980601 +-1.03772 +-0.69314 +-0.359176 +-1.03976 +-1.02725 +-0.696778 +-0.293002 +0.0109798 +-0.0105334 +-0.660371 +-0.340781 +-0.984159 +-0.993231 +-0.976136 +-1.01724 +0.036241 +0.0353497 +-0.0229631 +-0.00277697 +-0.998354 +-1.00745 +0.333942 +0.656077 +0.986566 +1.01364 +0.338517 +0.674425 +1.01868 +0.992937 +0.998592 +0.996411 +0.996884 +1.01379 +0.345568 +0.665458 +0.0282059 +0.0237899 +0.997456 +0.997519 +-0.0284102 +-0.0379144 +-0.634929 +-0.304236 +-0.989479 +-0.986065 +-1.02981 +-0.994904 +0.340952 +0.655559 +0.293985 +0.634264 +0.356439 +0.669594 +0.332008 +0.634672 +0.9749 +0.962191 +1.01743 +1.03524 +0.663462 +0.307689 +0.656656 +0.368679 +0.029808 +-0.0394429 +-0.00753004 +0.0163472 +0.359347 +0.698259 +0.305533 +0.705937 +0.368678 +0.628938 +0.360034 +0.670866 +1.01787 +1.03856 +0.967629 +0.983825 +0.652447 +0.303281 +0.659756 +0.300553 +0.0145419 +0.0334298 +-0.0231084 +0.0311081 +0.370621 +0.702655 +0.358019 +0.659082 +-0.697989 +-0.360325 +-0.680572 +-0.293182 +-0.691435 +-0.313102 +-0.651834 +-0.373754 +-0.323176 +-0.637968 +-0.292817 +-0.662831 +-0.967364 +-0.97445 +-1.03363 +-0.991158 +-0.644228 +-0.357669 +-0.632333 +-0.366781 +-0.679388 +-0.347577 +-0.691228 +-0.373179 +-0.689148 +-0.339336 +-0.633738 +-0.360193 +-0.0116811 +0.0159482 +0.00722246 +-0.00133724 +-0.30271 +-0.631683 +-0.336185 +-0.702478 +-0.986452 +-1.02969 +-1.03457 +-1.01796 +-0.625988 +-0.36905 +-0.639126 +-0.301685 +0.364833 +0.702243 +0.332158 +0.678939 +0.969574 +0.991491 +1.02049 +0.998519 +0.68558 +0.37093 +0.667007 +0.371433 +0.323261 +0.658269 +0.302906 +0.68658 +0.965884 +1.01846 +0.976909 +1.03817 +0.678446 +0.349057 +0.627362 +0.316994 +0.0277039 +-0.0322036 +0.00736581 +0.0267162 +0.30708 +0.659907 +0.350031 +0.630247 +-0.346183 +-0.692811 +-0.315815 +-0.668276 +-0.992987 +-1.00366 +-0.961423 +-1.01574 +-0.674393 +-0.336083 +-0.685973 +-0.309466 +0.363852 +0.6586 +0.668781 +0.371403 +0.302062 +0.687356 +0.701243 +0.355507 +0.32808 +0.703605 +0.630834 +0.314117 +0.296401 +0.679867 +0.6325 +0.311815 +-0.701893 +-0.309135 +-0.349605 +-0.673076 +-0.626946 +-0.373753 +-0.299686 +-0.6616 +-0.669077 +-0.302775 +-0.302339 +-0.635137 +-0.680525 +-0.363312 +-0.319603 +-0.691672 +0.336954 +0.640845 +0.638064 +0.347349 +0.369868 +0.630973 +0.661189 +0.322948 +0.292911 +0.667024 +0.678732 +0.297646 +0.305224 +0.686232 +0.651127 +0.311664 +-0.66457 +-0.323478 +-0.319746 +-0.666517 +-0.655565 +-0.327765 +-0.369783 +-0.699641 +-1.00554 +-0.963789 +0.0402218 +0.0222687 +-0.0354344 +1.01229 +1.03893 +1.00985 +-0.97187 +-1.03134 +-1.0178 +0.0229981 +-0.0253668 +0.0183911 +0.970946 +0.975878 +0.977081 +-0.975323 +-1.01814 +-1.00936 +0.00257558 +0.00798474 +0.0106359 +0.963005 +0.976173 +0.982557 +-0.995178 +-0.971058 +-0.636874 +-0.323294 +0.0376341 +-0.017414 +-0.662083 +-0.297144 +-1.03681 +-0.989184 +-0.659858 +-0.372882 +-0.0209981 +-0.00672776 +-0.695889 +-0.330463 +-1.0254 +-1.01292 +-1.02041 +-1.01278 +0.00462217 +-0.00165724 +-0.0297734 +0.0281462 +0.363981 +0.681136 +0.994464 +0.999617 +0.352474 +0.678971 +0.357174 +0.648963 +0.99958 +1.01197 +0.367335 +0.662214 +1.03622 +0.996919 +0.99007 +1.04107 +-0.0339321 +0.0385449 +0.959858 +0.986736 +0.323484 +0.638969 +0.0312734 +0.00642084 +1.00105 +0.969201 +0.368637 +0.630669 +0.00921086 +-0.0361366 +1.03382 +0.998192 +-0.980001 +-1.01339 +-0.627191 +-0.33586 +-0.959416 +-0.97835 +-0.645231 +-0.334836 +-0.00804985 +0.0137712 +-0.630956 +-0.346831 +-1.03098 +-1.01589 +-1.01409 +-1.02324 +-0.0190075 +-0.0125652 +0.00516096 +0.0128096 +-0.998596 +-1.00523 +-0.689103 +-0.372549 +0.00563583 +-0.0287993 +-1.03355 +-1.02682 +-0.0232692 +-0.0413986 +0.346372 +0.705063 +0.986881 +1.01085 +0.327536 +0.652465 +0.990832 +0.973972 +1.02596 +1.02445 +1.02941 +1.02001 +0.302618 +0.706767 +0.962453 +0.996861 +-0.358142 +-0.348221 +-0.640704 +-0.644648 +-0.960411 +-1.0143 +-1.02488 +-1.02451 +-0.678516 +-0.310911 +-0.678313 +-0.337063 +0.0372689 +0.00675085 +-0.00346147 +0.00864113 +-0.329853 +-0.641581 +-0.355511 +-0.627317 +-0.697449 +-0.656346 +-0.361678 +-0.296488 +0.65977 +0.626066 +0.348518 +0.337388 +0.374499 +0.685972 +0.292582 +0.641357 +0.962751 +1.02688 +1.03838 +0.960673 +0.637579 +0.305162 +0.644492 +0.334063 +0.369251 +0.341179 +0.705333 +0.698186 +0.639597 +0.660205 +0.331827 +0.351411 +-0.0230423 +0.0179834 +0.0157607 +-0.0121584 +0.986638 +1.02908 +0.98302 +1.02141 +0.696815 +0.373205 +0.650462 +0.362981 +0.350843 +0.318044 +0.629337 +0.688594 +-0.363411 +-0.373954 +-0.6424 +-0.684166 +-1.02713 +-1.03957 +-0.975103 +-1.03287 +-0.656728 +-0.311436 +-0.626355 +-0.308798 +-0.0262311 +-0.00286134 +0.000945915 +-0.00760666 +-0.359878 +-0.691627 +-0.311432 +-0.664907 +-0.70421 +-0.703411 +-0.351833 +-0.299062 +-1.03854 +-0.993037 +-0.977748 +-0.979363 +-0.633326 +-0.306744 +-0.665769 +-0.371737 +0.0276356 +-0.0165018 +-0.014236 +-0.0411567 +-0.681076 +-0.697672 +-0.365698 +-0.296137 +0.365892 +0.632946 +0.353398 +0.631327 +1.00508 +0.979344 +0.998721 +1.02021 +0.662718 +0.312289 +0.646967 +0.333507 +0.317211 +0.336801 +0.659445 +0.653671 +0.968764 +0.973364 +0.965975 +0.960437 +0.708287 +0.341873 +0.630367 +0.360923 +0.367038 +0.324464 +0.694766 +0.644296 +-0.664875 +-0.629266 +-0.360175 +-0.34065 +-0.704653 +-0.631776 +-0.334322 +-0.324568 +0.305901 +0.372732 +0.653973 +0.676952 +0.310021 +0.342606 +0.63546 +0.668898 +0.304407 +0.336572 +0.69757 +0.648171 +0.351602 +0.371878 +0.650275 +0.68489 +-0.661249 +-0.677692 +-0.329188 +-0.335878 +-0.644894 +-0.676088 +-0.316583 +-0.351436 +-0.680354 +-0.635091 +-0.317086 +-0.34334 +-0.641867 +-0.693075 +-0.292908 +-0.294299 +0.304657 +0.319398 +0.674321 +0.656344 +0.370337 +0.351447 +0.700242 +0.633078 +0.313018 +0.356145 +0.656249 +0.706288 +0.353023 +0.34819 +0.682844 +0.650107 +-1.03784 +-1.02134 +-0.977437 +-0.974396 +-0.989099 +-1.00235 +-1.03417 +-0.96112 +-0.0124438 +0.0237489 +-0.0127932 +-0.0293106 +0.0390076 +-0.0140345 +-0.0319425 +-0.0313353 +0.0136967 +1.01738 +1.00001 +1.00903 +0.993825 +0.991918 +1.01711 +1.01518 +0.973063 +0.965027 +-0.986869 +-0.96558 +-0.97845 +-1.01236 +-1.02381 +-0.974618 +-0.992036 +-0.959577 +0.00931885 +-0.0228014 +-0.00359675 +0.0168199 +-0.0255878 +0.0256261 +-0.00109785 +0.00328571 +-0.628685 +-0.33709 +-0.635749 +-0.36896 +-0.660092 +-0.330385 +-0.643249 +-0.368416 +-1.02968 +-1.02442 +-1.0015 +-0.970906 +-0.967581 +-0.986768 +0.0357876 +0.00388336 +0.00598512 +0.0156714 +0.0331914 +0.0238458 +-0.66728 +-0.333844 +-0.644064 +-0.366295 +-0.981646 +-1.02266 +-0.974475 +-0.965567 +-1.0387 +-1.01724 +-0.00394777 +0.0409472 +0.0206707 +-0.0146966 +-0.0363465 +-0.0144215 +-0.636749 +-0.304596 +-0.674505 +-0.374767 +-0.037353 +0.0323303 +0.0293273 +0.0367328 +1.0039 +1.02345 +0.998949 +0.968214 +0.997453 +0.990474 +1.03373 +1.03851 +0.364963 +0.681329 +0.297212 +0.674984 +0.367001 +0.697737 +0.334417 +0.703299 +0.972165 +1.0388 +1.03591 +1.0345 +0.98244 +1.04123 +0.311747 +0.637358 +0.361638 +0.678909 +0.970925 +1.03262 +1.00291 +0.958585 +1.02768 +0.965135 +0.357033 +0.651634 +0.308349 +0.646153 +1.01711 +0.967075 +0.976326 +1.00707 +0.356737 +0.648538 +-1.02628 +-0.984595 +-1.02872 +-0.983527 +-0.656296 +-0.68156 +-0.319724 +-0.328716 +-0.688725 +-0.628951 +-0.329149 +-0.335311 +-0.699927 +-0.675845 +-0.364735 +-0.354002 +-0.684893 +-0.653495 +-0.35375 +-0.365543 +0.0199734 +-0.0383834 +-0.00557559 +0.0366557 +-1.01723 +-1.03013 +-1.03794 +-0.999237 +-0.648063 +-0.639532 +-0.309033 +-0.299341 +-0.665793 +-0.629424 +-0.324535 +-0.363756 +-0.685984 +-0.685926 +-0.317472 +-0.333042 +-0.0232101 +-0.0216208 +0.0399803 +-0.0148034 +-0.989132 +-1.03309 +-0.993805 +-0.965693 +-0.644916 +-0.639222 +-0.372902 +-0.333276 +-0.635939 +-0.670144 +-0.338287 +-0.361503 +-0.658612 +-0.667889 +-0.319073 +-0.348341 +-0.0157543 +-0.00310621 +-0.0226824 +0.0267858 +-0.00753051 +0.0277829 +0.0380302 +0.0148184 +0.300191 +0.345559 +0.640109 +0.651981 +0.365605 +0.30509 +0.678844 +0.668139 +0.313669 +0.310038 +0.66078 +0.627086 +0.295816 +0.329544 +0.66881 +0.701544 +1.0344 +1.03886 +0.965041 +1.00079 +0.3293 +0.354301 +0.694114 +0.688546 +0.309528 +0.296431 +0.673665 +0.676997 +0.365881 +0.336695 +0.650149 +0.707738 +0.97392 +0.998592 +0.984719 +0.964525 +0.345348 +0.371896 +0.674331 +0.700684 +0.306934 +0.293444 +0.70277 +0.644417 +0.331321 +0.329913 +0.637627 +0.657388 +0.993769 +0.977668 +1.03318 +1.0314 +0.373635 +0.352291 +0.678281 +0.641497 +0.357056 +0.310279 +0.693494 +0.68127 +1.02197 +0.968643 +1.01401 +1.03756 +-0.657765 +-0.626273 +-0.706247 +-0.687417 +-0.296044 +-0.323583 +-0.361733 +-0.364109 +-0.655139 +-0.70063 +-0.678026 +-0.698818 +-0.329051 +-0.332065 +-0.333097 +-0.293616 +-0.646064 +-0.67492 +-0.637214 +-0.647428 +-0.364296 +-0.333933 +-0.297598 +-0.298907 +0.351346 +0.354229 +0.340697 +0.331654 +0.697872 +0.646371 +0.660882 +0.665107 +0.311765 +0.329635 +0.35269 +0.307388 +0.631052 +0.699291 +0.651612 +0.684246 +0.373661 +0.348587 +0.360428 +0.336277 +0.641522 +0.652331 +0.667661 +0.703791 +0.352412 +0.322114 +0.348029 +0.363116 +0.696515 +0.675431 +0.689209 +0.672861 diff --git a/data/fichera.mesh b/data/fichera.mesh new file mode 100644 index 0000000000..b73ace77b5 --- /dev/null +++ b/data/fichera.mesh @@ -0,0 +1,82 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +7 +1 5 0 1 4 3 9 10 13 12 +1 5 3 4 7 6 12 13 16 15 +1 5 2 3 6 5 11 12 15 14 +1 5 8 9 12 11 17 18 21 20 +1 5 9 10 13 12 18 19 22 21 +1 5 12 13 16 15 21 22 25 24 +1 5 11 12 15 14 20 21 24 23 + +boundary +24 +1 3 5 6 3 2 +2 3 6 7 4 3 +3 3 3 4 1 0 +4 3 11 12 9 8 +5 3 2 3 12 11 +6 3 0 1 10 9 +7 3 9 10 19 18 +8 3 8 9 18 17 +9 3 1 4 13 10 +10 3 4 7 16 13 +11 3 13 16 25 22 +12 3 10 13 22 19 +13 3 7 6 15 16 +14 3 6 5 14 15 +15 3 15 14 23 24 +16 3 16 15 24 25 +17 3 5 2 11 14 +18 3 3 0 9 12 +19 3 11 8 17 20 +20 3 14 11 20 23 +21 3 17 18 21 20 +22 3 18 19 22 21 +23 3 21 22 25 24 +24 3 20 21 24 23 + +vertices +26 +3 +0 -1 -1 +1 -1 -1 +-1 0 -1 +0 0 -1 +1 0 -1 +-1 1 -1 +0 1 -1 +1 1 -1 +-1 -1 0 +0 -1 0 +1 -1 0 +-1 0 0 +0 0 0 +1 0 0 +-1 1 0 +0 1 0 +1 1 0 +-1 -1 1 +0 -1 1 +1 -1 1 +-1 0 1 +0 0 1 +1 0 1 +-1 1 1 +0 1 1 +1 1 1 diff --git a/data/fichera.vtk b/data/fichera.vtk new file mode 100644 index 0000000000..4883d2371b --- /dev/null +++ b/data/fichera.vtk @@ -0,0 +1,57 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 26 double +0 -1 -1 +1 -1 -1 +-1 0 -1 +0 0 -1 +1 0 -1 +-1 1 -1 +0 1 -1 +1 1 -1 +-1 -1 0 +0 -1 0 +1 -1 0 +-1 0 0 +0 0 0 +1 0 0 +-1 1 0 +0 1 0 +1 1 0 +-1 -1 1 +0 -1 1 +1 -1 1 +-1 0 1 +0 0 1 +1 0 1 +-1 1 1 +0 1 1 +1 1 1 +CELLS 7 63 +8 0 1 4 3 9 10 13 12 +8 3 4 7 6 12 13 16 15 +8 2 3 6 5 11 12 15 14 +8 8 9 12 11 17 18 21 20 +8 9 10 13 12 18 19 22 21 +8 12 13 16 15 21 22 25 24 +8 11 12 15 14 20 21 24 23 +CELL_TYPES 7 +12 +12 +12 +12 +12 +12 +12 +CELL_DATA 7 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 diff --git a/data/square-disc-p2.mesh b/data/square-disc-p2.mesh new file mode 100644 index 0000000000..3c40186324 --- /dev/null +++ b/data/square-disc-p2.mesh @@ -0,0 +1,945 @@ +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 +154 +1 2 1 23 0 +1 2 48 1 2 +1 2 4 49 3 +1 2 7 5 6 +1 2 7 8 50 +1 2 8 9 51 +1 2 9 10 52 +1 2 10 11 53 +1 2 13 11 12 +1 2 11 13 53 +1 2 49 88 58 +1 2 63 99 64 +1 2 14 15 54 +1 2 55 16 17 +1 2 19 17 18 +1 2 17 19 55 +1 2 52 91 99 +1 2 69 98 70 +1 2 20 21 56 +1 2 22 23 57 +1 2 24 58 25 +1 2 25 59 26 +1 2 60 27 26 +1 2 27 61 28 +1 2 28 62 29 +1 2 29 63 30 +1 2 64 31 30 +1 2 65 32 31 +1 2 32 66 33 +1 2 67 34 33 +1 2 34 68 35 +1 2 35 69 36 +1 2 70 37 36 +1 2 37 71 38 +1 2 38 72 39 +1 2 39 73 40 +1 2 40 74 41 +1 2 41 75 42 +1 2 76 43 42 +1 2 77 44 43 +1 2 44 78 45 +1 2 45 79 46 +1 2 46 80 47 +1 2 47 81 24 +1 2 50 5 7 +1 2 48 2 82 +1 2 3 82 2 +1 2 4 5 83 +1 2 51 50 8 +1 2 51 9 52 +1 2 53 52 10 +1 2 13 14 84 +1 2 53 13 84 +1 2 54 84 14 +1 2 54 15 85 +1 2 55 85 16 +1 2 15 16 85 +1 2 24 81 58 +1 2 19 20 86 +1 2 55 19 86 +1 2 56 86 20 +1 2 21 87 56 +1 2 21 22 87 +1 2 25 58 59 +1 2 60 26 59 +1 2 60 61 27 +1 2 61 62 28 +1 2 63 29 62 +1 2 30 63 64 +1 2 64 65 31 +1 2 65 66 32 +1 2 67 33 66 +1 2 67 68 34 +1 2 69 35 68 +1 2 36 69 70 +1 2 70 71 37 +1 2 72 38 71 +1 2 39 72 73 +1 2 74 40 73 +1 2 75 41 74 +1 2 76 42 75 +1 2 43 76 77 +1 2 44 77 78 +1 2 79 45 78 +1 2 46 79 80 +1 2 81 47 80 +1 2 23 1 57 +1 2 83 49 4 +1 2 82 3 49 +1 2 5 50 83 +1 2 82 49 81 +1 2 82 79 48 +1 2 52 63 51 +1 2 56 87 76 +1 2 57 87 22 +1 2 57 1 48 +1 2 85 69 54 +1 2 88 60 59 +1 2 60 89 61 +1 2 88 89 60 +1 2 61 90 62 +1 2 91 66 65 +1 2 66 92 67 +1 2 66 91 92 +1 2 68 67 93 +1 2 94 72 71 +1 2 95 73 72 +1 2 72 94 95 +1 2 73 96 74 +1 2 97 78 77 +1 2 83 50 89 +1 2 50 51 90 +1 2 51 63 90 +1 2 87 57 97 +1 2 85 55 94 +1 2 90 63 62 +1 2 86 56 96 +1 2 58 88 59 +1 2 69 85 98 +1 2 98 94 71 +1 2 99 91 65 +1 2 80 82 81 +1 2 87 77 76 +1 2 89 90 61 +1 2 99 65 64 +1 2 92 93 67 +1 2 68 54 69 +1 2 98 71 70 +1 2 73 95 96 +1 2 78 100 79 +1 2 50 90 89 +1 2 54 68 93 +1 2 97 100 78 +1 2 81 49 58 +1 2 48 79 100 +1 2 57 100 97 +1 2 84 54 93 +1 2 57 48 100 +1 2 85 94 98 +1 2 95 86 96 +1 2 92 84 93 +1 2 53 84 92 +1 2 56 74 96 +1 2 55 95 94 +1 2 55 86 95 +1 2 63 52 99 +1 2 52 53 91 +1 2 74 56 75 +1 2 53 92 91 +1 2 49 83 88 +1 2 83 89 88 +1 2 77 87 97 +1 2 79 82 80 +1 2 56 76 75 + +boundary +48 +1 1 1 0 +1 1 2 1 +1 1 3 2 +1 1 4 3 +1 1 5 4 +1 1 6 5 +2 1 7 6 +2 1 8 7 +2 1 9 8 +2 1 10 9 +2 1 11 10 +2 1 12 11 +3 1 13 12 +3 1 14 13 +3 1 15 14 +3 1 16 15 +3 1 17 16 +3 1 18 17 +4 1 19 18 +4 1 20 19 +4 1 21 20 +4 1 22 21 +4 1 23 22 +4 1 0 23 +5 1 24 25 +5 1 25 26 +5 1 26 27 +5 1 27 28 +5 1 28 29 +5 1 29 30 +6 1 30 31 +6 1 31 32 +6 1 32 33 +6 1 33 34 +6 1 34 35 +6 1 35 36 +7 1 36 37 +7 1 37 38 +7 1 38 39 +7 1 39 40 +7 1 40 41 +7 1 41 42 +8 1 42 43 +8 1 43 44 +8 1 44 45 +8 1 45 46 +8 1 46 47 +8 1 47 24 + +vertices +101 + +nodes +FiniteElementSpace +FiniteElementCollection: Quadratic +VDim: 2 +Ordering: 0 + +0 +0.166667 +0.333333 +0.5 +0.666667 +0.833333 +1 +1 +1 +1 +1 +1 +1 +0.833333 +0.666667 +0.5 +0.333333 +0.166667 +0 +0 +0 +0 +0 +0 +0.5 +0.551762 +0.599999 +0.641421 +0.673203 +0.69318 +0.7 +0.69318 +0.673203 +0.641421 +0.599999 +0.551762 +0.5 +0.448238 +0.400001 +0.358579 +0.326797 +0.30682 +0.3 +0.30682 +0.326797 +0.358579 +0.400001 +0.448238 +0.283142 +0.548789 +0.882118 +0.88527 +0.905416 +0.87936 +0.564817 +0.210856 +0.125091 +0.135714 +0.545741 +0.599544 +0.662018 +0.718425 +0.740156 +0.790723 +0.748159 +0.736961 +0.706584 +0.665854 +0.590107 +0.526686 +0.469252 +0.389672 +0.334277 +0.297269 +0.25415 +0.236733 +0.226416 +0.257327 +0.301712 +0.34691 +0.404021 +0.470887 +0.404451 +0.736593 +0.73378 +0.439854 +0.119158 +0.122736 +0.630612 +0.742273 +0.810191 +0.800441 +0.736116 +0.657185 +0.313848 +0.255276 +0.209253 +0.204509 +0.439847 +0.797924 +0.26324 +0.0927216 +0 +0.0833335 +0.227725 +0.25 +0.315417 +0.6095 +0.515396 +0.583333 +0.91465 +0.916667 +1 +1 +0.937818 +0.938729 +1 +0.947728 +0.940856 +1 +0.942444 +0.950136 +1 +0.929712 +0.934912 +0.910161 +1 +0.916667 +0.853346 +0.587515 +0.591219 +0.54936 +0.793416 +0.776406 +0.762998 +0.583333 +0.529318 +0.610391 +0.28139 +0.25 +0.182178 +0.0778147 +0.0833335 +0 +0.104465 +0.847056 +0.803113 +0.846008 +0.48125 +0.451797 +0.501563 +0 +0.0683646 +0.0639236 +0 +0.0557862 +0.0682914 +0.520982 +0.551582 +0.525881 +0.57653 +0.600077 +0.575881 +0.648497 +0.62071 +0.626526 +0.677152 +0.695451 +0.657312 +0.703248 +0.718408 +0.683191 +0.739512 +0.746835 +0.69659 +0.721715 +0.69659 +0.721022 +0.708116 +0.683191 +0.714089 +0.689142 +0.673635 +0.657312 +0.62808 +0.62071 +0.649719 +0.596269 +0.567658 +0.575881 +0.544365 +0.518598 +0.525881 +0.461919 +0.474119 +0.483042 +0.420408 +0.393297 +0.424119 +0.369154 +0.345985 +0.37929 +0.324537 +0.308268 +0.342688 +0.292927 +0.284541 +0.316808 +0.274578 +0.270829 +0.30341 +0.263108 +0.30341 +0.263056 +0.29064 +0.316808 +0.282607 +0.313695 +0.32704 +0.342688 +0.353066 +0.370023 +0.37929 +0.40002 +0.422101 +0.424119 +0.459821 +0.489815 +0.474119 +0.852688 +0.374425 +0.33578 +0.459512 +0.416666 +0.75 +0.785713 +0.706647 +0.878125 +0.886596 +0.891795 +0.75 +0.701422 +0.778266 +0.810343 +0.648895 +0.468913 +0.498105 +0.332012 +0.379936 +0.416666 +0.512091 +0 +0.061206 +0.0598641 +0.159023 +0.125497 +0.0647223 +0.128052 +0 +0.0547752 +0.574639 +0.62874 +0.685483 +0.728548 +0.762144 +0.741667 +0.718472 +0.68151 +0.628362 +0.559982 +0.433468 +0.362384 +0.316851 +0.271443 +0.24559 +0.225235 +0.239178 +0.277986 +0.325654 +0.376116 +0.434079 +0.151321 +0.641362 +0.477795 +0.805407 +0.510948 +0.437279 +0.377428 +0.309067 +0.83767 +0.8382 +0.168064 +0.175381 +0.121991 +0.208731 +0.47751 +0.552142 +0.640585 +0.611517 +0.703559 +0.732681 +0.685001 +0.759601 +0.773108 +0.750827 +0.773641 +0.719944 +0.700546 +0.767877 +0.659953 +0.622201 +0.325108 +0.349038 +0.270538 +0.291444 +0.284487 +0.255772 +0.237261 +0.251616 +0.226821 +0.807833 +0.737883 +0.837676 +0.845785 +0.795754 +0.173182 +0.167299 +0.261056 +0.382069 +0.17355 +0.165779 +0.438585 +0.372045 +0.40843 +0.766418 +0.402036 +0.184893 +0.781861 +0.690849 +0.580697 +0.232772 +0.286006 +0.303493 +0.617219 +0.231027 +0.277101 +0.196594 +0.703362 +0.189273 +0.741686 +0.81115 +0.196684 +0.229495 +0.832366 +0.181378 +0.684592 +0 +0 +0 +0 +0 +0 +0 +0.166667 +0.333333 +0.5 +0.666667 +0.833333 +1 +1 +1 +1 +1 +1 +1 +0.833333 +0.666667 +0.5 +0.333333 +0.166667 +0.3 +0.30682 +0.326797 +0.358579 +0.400001 +0.448238 +0.5 +0.551762 +0.599999 +0.641421 +0.673203 +0.69318 +0.7 +0.69318 +0.673203 +0.641421 +0.599999 +0.551762 +0.5 +0.448238 +0.400001 +0.358579 +0.326797 +0.30682 +0.154544 +0.124376 +0.254739 +0.419089 +0.560804 +0.769308 +0.872114 +0.860529 +0.556112 +0.225357 +0.231738 +0.272346 +0.29451 +0.342211 +0.411268 +0.466083 +0.531285 +0.597282 +0.656478 +0.701875 +0.748713 +0.785233 +0.748535 +0.747415 +0.71235 +0.652318 +0.599907 +0.531735 +0.469983 +0.400931 +0.345846 +0.265652 +0.259955 +0.213543 +0.143931 +0.129724 +0.871678 +0.91127 +0.725777 +0.408188 +0.205633 +0.256969 +0.374898 +0.665571 +0.728836 +0.784094 +0.806475 +0.734376 +0.65763 +0.331601 +0.8159 +0.549556 +0.262243 +0.0849488 +0.0833335 +0 +0.0813443 +0 +0.0729204 +0.0593516 +0.0699098 +0 +0.0872193 +0 +0.0833335 +0.25 +0.29361 +0.202295 +0.416666 +0.466225 +0.377137 +0.583333 +0.606075 +0.528514 +0.75 +0.808365 +0.722676 +0.922993 +0.916667 +1 +0.890832 +0.160995 +0.218601 +0.183779 +0.51164 +0.539662 +0.498303 +1 +0.931324 +0.943193 +0.93946 +1 +0.924603 +0.918672 +1 +0.916667 +0.839548 +0.61038 +0.606055 +0.553428 +0.800349 +0.788102 +0.76676 +0.583333 +0.529772 +0.619005 +0.25 +0.192482 +0.282634 +0.268534 +0.272654 +0.30341 +0.291394 +0.297058 +0.316808 +0.326033 +0.342688 +0.309748 +0.34933 +0.373464 +0.37929 +0.404618 +0.433718 +0.424119 +0.45871 +0.485511 +0.474119 +0.544523 +0.525881 +0.514387 +0.597229 +0.575881 +0.572341 +0.632247 +0.651712 +0.62071 +0.690906 +0.657312 +0.676246 +0.710171 +0.718002 +0.683191 +0.738502 +0.743874 +0.69659 +0.722708 +0.69659 +0.72282 +0.718144 +0.71258 +0.683191 +0.694195 +0.671497 +0.657312 +0.648867 +0.629648 +0.62071 +0.60032 +0.577803 +0.575881 +0.544455 +0.512407 +0.525881 +0.455706 +0.474119 +0.481756 +0.40202 +0.424119 +0.424048 +0.373043 +0.347998 +0.37929 +0.310627 +0.2985 +0.342688 +0.288527 +0.28078 +0.316808 +0.2573 +0.257346 +0.30341 +0.11825 +0.0710588 +0.14973 +0.0625299 +0 +0 +0.0683812 +0.0671846 +0.332635 +0.481136 +0.664984 +1 +0.935849 +0.942172 +0.823939 +0.872004 +0.95439 +0.886349 +0.877 +0.94902 +1 +0.224018 +0.75 +0.691982 +0.790245 +0.796817 +0.646262 +0.462963 +0.491845 +0.416666 +0.375485 +0.250234 +0.283452 +0.317065 +0.375963 +0.434634 +0.561505 +0.623603 +0.68357 +0.728456 +0.762864 +0.747366 +0.724067 +0.682061 +0.624027 +0.56705 +0.496947 +0.436564 +0.367819 +0.301259 +0.264652 +0.234202 +0.119404 +0.122784 +0.1365 +0.189145 +0.173903 +0.172937 +0.204163 +0.211444 +0.510332 +0.438917 +0.445468 +0.513904 +0.324341 +0.183498 +0.843272 +0.829151 +0.24325 +0.233073 +0.274751 +0.299405 +0.231157 +0.35739 +0.395467 +0.66177 +0.626576 +0.696449 +0.715291 +0.692398 +0.741646 +0.766346 +0.760716 +0.778374 +0.696927 +0.724168 +0.770535 +0.654624 +0.630687 +0.344949 +0.365688 +0.251665 +0.187607 +0.390673 +0.312587 +0.412196 +0.280202 +0.368434 +0.839321 +0.856431 +0.604894 +0.691056 +0.867228 +0.815471 +0.787472 +0.576888 +0.198591 +0.401808 +0.316403 +0.761681 +0.809953 +0.699149 +0.297108 +0.261212 +0.827293 +0.300261 +0.209609 +0.24964 +0.827699 +0.738437 +0.807258 +0.748675 +0.577051 +0.79535 +0.718126 +0.55124 +0.157692 diff --git a/data/square-disc-p2.vtk b/data/square-disc-p2.vtk new file mode 100644 index 0000000000..a87a44fb01 --- /dev/null +++ b/data/square-disc-p2.vtk @@ -0,0 +1,828 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 356 double +0 0 0 +0.166667 0 0 +0.333333 0 0 +0.5 0 0 +0.666667 0 0 +0.833333 0 0 +1 0 0 +1 0.166667 0 +1 0.333333 0 +1 0.5 0 +1 0.666667 0 +1 0.833333 0 +1 1 0 +0.833333 1 0 +0.666667 1 0 +0.5 1 0 +0.333333 1 0 +0.166667 1 0 +0 1 0 +0 0.833333 0 +0 0.666667 0 +0 0.5 0 +0 0.333333 0 +0 0.166667 0 +0.5 0.3 0 +0.551762 0.30682 0 +0.599999 0.326797 0 +0.641421 0.358579 0 +0.673203 0.400001 0 +0.69318 0.448238 0 +0.7 0.5 0 +0.69318 0.551762 0 +0.673203 0.599999 0 +0.641421 0.641421 0 +0.599999 0.673203 0 +0.551762 0.69318 0 +0.5 0.7 0 +0.448238 0.69318 0 +0.400001 0.673203 0 +0.358579 0.641421 0 +0.326797 0.599999 0 +0.30682 0.551762 0 +0.3 0.5 0 +0.30682 0.448238 0 +0.326797 0.400001 0 +0.358579 0.358579 0 +0.400001 0.326797 0 +0.448238 0.30682 0 +0.283142 0.154544 0 +0.548789 0.124376 0 +0.882118 0.254739 0 +0.88527 0.419089 0 +0.905416 0.560804 0 +0.87936 0.769308 0 +0.564817 0.872114 0 +0.210856 0.860529 0 +0.125091 0.556112 0 +0.135714 0.225357 0 +0.545741 0.231738 0 +0.599544 0.272346 0 +0.662018 0.29451 0 +0.718425 0.342211 0 +0.740156 0.411268 0 +0.790723 0.466083 0 +0.748159 0.531285 0 +0.736961 0.597282 0 +0.706584 0.656478 0 +0.665854 0.701875 0 +0.590107 0.748713 0 +0.526686 0.785233 0 +0.469252 0.748535 0 +0.389672 0.747415 0 +0.334277 0.71235 0 +0.297269 0.652318 0 +0.25415 0.599907 0 +0.236733 0.531735 0 +0.226416 0.469983 0 +0.257327 0.400931 0 +0.301712 0.345846 0 +0.34691 0.265652 0 +0.404021 0.259955 0 +0.470887 0.213543 0 +0.404451 0.143931 0 +0.736593 0.129724 0 +0.73378 0.871678 0 +0.439854 0.91127 0 +0.119158 0.725777 0 +0.122736 0.408188 0 +0.630612 0.205633 0 +0.742273 0.256969 0 +0.810191 0.374898 0 +0.800441 0.665571 0 +0.736116 0.728836 0 +0.657185 0.784094 0 +0.313848 0.806475 0 +0.255276 0.734376 0 +0.209253 0.65763 0 +0.204509 0.331601 0 +0.439847 0.8159 0 +0.797924 0.549556 0 +0.26324 0.262243 0 +0.0927216 0.0849488 0 +0 0.0833335 0 +0.0833335 0 0 +0.227725 0.0813443 0 +0.25 0 0 +0.315417 0.0729204 0 +0.6095 0.0593516 0 +0.515396 0.0699098 0 +0.583333 0 0 +0.91465 0.0872193 0 +0.916667 0 0 +1 0.0833335 0 +1 0.25 0 +0.937818 0.29361 0 +0.938729 0.202295 0 +1 0.416666 0 +0.947728 0.466225 0 +0.940856 0.377137 0 +1 0.583333 0 +0.942444 0.606075 0 +0.950136 0.528514 0 +1 0.75 0 +0.929712 0.808365 0 +0.934912 0.722676 0 +0.910161 0.922993 0 +1 0.916667 0 +0.916667 1 0 +0.853346 0.890832 0 +0.587515 0.160995 0 +0.591219 0.218601 0 +0.54936 0.183779 0 +0.793416 0.51164 0 +0.776406 0.539662 0 +0.762998 0.498303 0 +0.583333 1 0 +0.529318 0.931324 0 +0.610391 0.943193 0 +0.28139 0.93946 0 +0.25 1 0 +0.182178 0.924603 0 +0.0778147 0.918672 0 +0.0833335 1 0 +0 0.916667 0 +0.104465 0.839548 0 +0.847056 0.61038 0 +0.803113 0.606055 0 +0.846008 0.553428 0 +0.48125 0.800349 0 +0.451797 0.788102 0 +0.501563 0.76676 0 +0 0.583333 0 +0.0683646 0.529772 0 +0.0639236 0.619005 0 +0 0.25 0 +0.0557862 0.192482 0 +0.0682914 0.282634 0 +0.520982 0.268534 0 +0.551582 0.272654 0 +0.525881 0.30341 0 +0.57653 0.291394 0 +0.600077 0.297058 0 +0.575881 0.316808 0 +0.648497 0.326033 0 +0.62071 0.342688 0 +0.626526 0.309748 0 +0.677152 0.34933 0 +0.695451 0.373464 0 +0.657312 0.37929 0 +0.703248 0.404618 0 +0.718408 0.433718 0 +0.683191 0.424119 0 +0.739512 0.45871 0 +0.746835 0.485511 0 +0.69659 0.474119 0 +0.721715 0.544523 0 +0.69659 0.525881 0 +0.721022 0.514387 0 +0.708116 0.597229 0 +0.683191 0.575881 0 +0.714089 0.572341 0 +0.689142 0.632247 0 +0.673635 0.651712 0 +0.657312 0.62071 0 +0.62808 0.690906 0 +0.62071 0.657312 0 +0.649719 0.676246 0 +0.596269 0.710171 0 +0.567658 0.718002 0 +0.575881 0.683191 0 +0.544365 0.738502 0 +0.518598 0.743874 0 +0.525881 0.69659 0 +0.461919 0.722708 0 +0.474119 0.69659 0 +0.483042 0.72282 0 +0.420408 0.718144 0 +0.393297 0.71258 0 +0.424119 0.683191 0 +0.369154 0.694195 0 +0.345985 0.671497 0 +0.37929 0.657312 0 +0.324537 0.648867 0 +0.308268 0.629648 0 +0.342688 0.62071 0 +0.292927 0.60032 0 +0.284541 0.577803 0 +0.316808 0.575881 0 +0.274578 0.544455 0 +0.270829 0.512407 0 +0.30341 0.525881 0 +0.263108 0.455706 0 +0.30341 0.474119 0 +0.263056 0.481756 0 +0.29064 0.40202 0 +0.316808 0.424119 0 +0.282607 0.424048 0 +0.313695 0.373043 0 +0.32704 0.347998 0 +0.342688 0.37929 0 +0.353066 0.310627 0 +0.370023 0.2985 0 +0.37929 0.342688 0 +0.40002 0.288527 0 +0.422101 0.28078 0 +0.424119 0.316808 0 +0.459821 0.2573 0 +0.489815 0.257346 0 +0.474119 0.30341 0 +0.852688 0.11825 0 +0.374425 0.0710588 0 +0.33578 0.14973 0 +0.459512 0.0625299 0 +0.416666 0 0 +0.75 0 0 +0.785713 0.0683812 0 +0.706647 0.0671846 0 +0.878125 0.332635 0 +0.886596 0.481136 0 +0.891795 0.664984 0 +0.75 1 0 +0.701422 0.935849 0 +0.778266 0.942172 0 +0.810343 0.823939 0 +0.648895 0.872004 0 +0.468913 0.95439 0 +0.498105 0.886349 0 +0.332012 0.877 0 +0.379936 0.94902 0 +0.416666 1 0 +0.512091 0.224018 0 +0 0.75 0 +0.061206 0.691982 0 +0.0598641 0.790245 0 +0.159023 0.796817 0 +0.125497 0.646262 0 +0.0647223 0.462963 0 +0.128052 0.491845 0 +0 0.416666 0 +0.0547752 0.375485 0 +0.574639 0.250234 0 +0.62874 0.283452 0 +0.685483 0.317065 0 +0.728548 0.375963 0 +0.762144 0.434634 0 +0.741667 0.561505 0 +0.718472 0.623603 0 +0.68151 0.68357 0 +0.628362 0.728456 0 +0.559982 0.762864 0 +0.433468 0.747366 0 +0.362384 0.724067 0 +0.316851 0.682061 0 +0.271443 0.624027 0 +0.24559 0.56705 0 +0.225235 0.496947 0 +0.239178 0.436564 0 +0.277986 0.367819 0 +0.325654 0.301259 0 +0.376116 0.264652 0 +0.434079 0.234202 0 +0.151321 0.119404 0 +0.641362 0.122784 0 +0.477795 0.1365 0 +0.805407 0.189145 0 +0.510948 0.173903 0 +0.437279 0.172937 0 +0.377428 0.204163 0 +0.309067 0.211444 0 +0.83767 0.510332 0 +0.8382 0.438917 0 +0.168064 0.445468 0 +0.175381 0.513904 0 +0.121991 0.324341 0 +0.208731 0.183498 0 +0.47751 0.843272 0 +0.552142 0.829151 0 +0.640585 0.24325 0 +0.611517 0.233073 0 +0.703559 0.274751 0 +0.732681 0.299405 0 +0.685001 0.231157 0 +0.759601 0.35739 0 +0.773108 0.395467 0 +0.750827 0.66177 0 +0.773641 0.626576 0 +0.719944 0.696449 0 +0.700546 0.715291 0 +0.767877 0.692398 0 +0.659953 0.741646 0 +0.622201 0.766346 0 +0.325108 0.760716 0 +0.349038 0.778374 0 +0.270538 0.696927 0 +0.291444 0.724168 0 +0.284487 0.770535 0 +0.255772 0.654624 0 +0.237261 0.630687 0 +0.251616 0.344949 0 +0.226821 0.365688 0 +0.807833 0.251665 0 +0.737883 0.187607 0 +0.837676 0.390673 0 +0.845785 0.312587 0 +0.795754 0.412196 0 +0.173182 0.280202 0 +0.167299 0.368434 0 +0.261056 0.839321 0 +0.382069 0.856431 0 +0.17355 0.604894 0 +0.165779 0.691056 0 +0.438585 0.867228 0 +0.372045 0.815471 0 +0.40843 0.787472 0 +0.766418 0.576888 0 +0.402036 0.198591 0 +0.184893 0.401808 0 +0.781861 0.316403 0 +0.690849 0.761681 0 +0.580697 0.809953 0 +0.232772 0.699149 0 +0.286006 0.297108 0 +0.303493 0.261212 0 +0.617219 0.827293 0 +0.231027 0.300261 0 +0.277101 0.209609 0 +0.196594 0.24964 0 +0.703362 0.827699 0 +0.189273 0.738437 0 +0.741686 0.807258 0 +0.81115 0.748675 0 +0.196684 0.577051 0 +0.229495 0.79535 0 +0.832366 0.718126 0 +0.181378 0.55124 0 +0.684592 0.157692 0 +CELLS 154 1078 +6 1 23 0 101 102 103 +6 48 1 2 104 105 106 +6 4 49 3 107 108 109 +6 7 5 6 110 111 112 +6 7 8 50 113 114 115 +6 8 9 51 116 117 118 +6 9 10 52 119 120 121 +6 10 11 53 122 123 124 +6 13 11 12 125 126 127 +6 11 13 53 125 128 123 +6 49 88 58 129 130 131 +6 63 99 64 132 133 134 +6 14 15 54 135 136 137 +6 55 16 17 138 139 140 +6 19 17 18 141 142 143 +6 17 19 55 141 144 140 +6 52 91 99 145 146 147 +6 69 98 70 148 149 150 +6 20 21 56 151 152 153 +6 22 23 57 154 155 156 +6 24 58 25 157 158 159 +6 25 59 26 160 161 162 +6 60 27 26 163 164 165 +6 27 61 28 166 167 168 +6 28 62 29 169 170 171 +6 29 63 30 172 173 174 +6 64 31 30 175 176 177 +6 65 32 31 178 179 180 +6 32 66 33 181 182 183 +6 67 34 33 184 185 186 +6 34 68 35 187 188 189 +6 35 69 36 190 191 192 +6 70 37 36 193 194 195 +6 37 71 38 196 197 198 +6 38 72 39 199 200 201 +6 39 73 40 202 203 204 +6 40 74 41 205 206 207 +6 41 75 42 208 209 210 +6 76 43 42 211 212 213 +6 77 44 43 214 215 216 +6 44 78 45 217 218 219 +6 45 79 46 220 221 222 +6 46 80 47 223 224 225 +6 47 81 24 226 227 228 +6 50 5 7 229 110 115 +6 48 2 82 106 230 231 +6 3 82 2 232 230 233 +6 4 5 83 234 235 236 +6 51 50 8 237 114 118 +6 51 9 52 117 121 238 +6 53 52 10 239 120 124 +6 13 14 84 240 241 242 +6 53 13 84 128 242 243 +6 54 84 14 244 241 137 +6 54 15 85 136 245 246 +6 55 85 16 247 248 138 +6 15 16 85 249 248 245 +6 24 81 58 227 250 157 +6 19 20 86 251 252 253 +6 55 19 86 144 253 254 +6 56 86 20 255 252 153 +6 21 87 56 256 257 152 +6 21 22 87 258 259 256 +6 25 58 59 158 260 160 +6 60 26 59 165 161 261 +6 60 61 27 262 166 163 +6 61 62 28 263 169 167 +6 63 29 62 172 170 264 +6 30 63 64 173 134 177 +6 64 65 31 265 180 175 +6 65 66 32 266 181 178 +6 67 33 66 186 182 267 +6 67 68 34 268 187 184 +6 69 35 68 190 188 269 +6 36 69 70 191 150 195 +6 70 71 37 270 196 193 +6 72 38 71 199 197 271 +6 39 72 73 200 272 202 +6 74 40 73 205 203 273 +6 75 41 74 208 206 274 +6 76 42 75 213 209 275 +6 43 76 77 211 276 216 +6 44 77 78 214 277 217 +6 79 45 78 220 218 278 +6 46 79 80 221 279 223 +6 81 47 80 226 224 280 +6 23 1 57 101 281 155 +6 83 49 4 282 107 236 +6 82 3 49 232 108 283 +6 5 50 83 229 284 235 +6 82 49 81 283 285 286 +6 82 79 48 287 288 231 +6 52 63 51 289 290 238 +6 56 87 76 257 291 292 +6 57 87 22 293 259 156 +6 57 1 48 281 104 294 +6 85 69 54 295 296 246 +6 88 60 59 297 261 298 +6 60 89 61 299 300 262 +6 88 89 60 301 299 297 +6 61 90 62 302 303 263 +6 91 66 65 304 266 305 +6 66 92 67 306 307 267 +6 66 91 92 304 308 306 +6 68 67 93 268 309 310 +6 94 72 71 311 271 312 +6 95 73 72 313 272 314 +6 72 94 95 311 315 314 +6 73 96 74 316 317 273 +6 97 78 77 318 277 319 +6 83 50 89 284 320 321 +6 50 51 90 237 322 323 +6 51 63 90 290 324 322 +6 87 57 97 293 325 326 +6 85 55 94 247 327 328 +6 90 63 62 324 264 303 +6 86 56 96 255 329 330 +6 58 88 59 130 298 260 +6 69 85 98 295 331 148 +6 98 94 71 332 312 333 +6 99 91 65 146 305 334 +6 80 82 81 335 286 280 +6 87 77 76 336 276 291 +6 89 90 61 337 302 300 +6 99 65 64 334 265 133 +6 92 93 67 338 309 307 +6 68 54 69 339 296 269 +6 98 71 70 333 270 149 +6 73 95 96 313 340 316 +6 78 100 79 341 342 278 +6 50 90 89 323 337 320 +6 54 68 93 339 310 343 +6 97 100 78 344 341 318 +6 81 49 58 285 131 250 +6 48 79 100 288 342 345 +6 57 100 97 346 344 325 +6 84 54 93 244 343 347 +6 57 48 100 294 345 346 +6 85 94 98 328 332 331 +6 95 86 96 348 330 340 +6 92 84 93 349 347 338 +6 53 84 92 243 349 350 +6 56 74 96 351 317 329 +6 55 95 94 352 315 327 +6 55 86 95 254 348 352 +6 63 52 99 289 147 132 +6 52 53 91 239 353 145 +6 74 56 75 351 354 274 +6 53 92 91 350 308 353 +6 49 83 88 282 355 129 +6 83 89 88 321 301 355 +6 77 87 97 336 326 319 +6 79 82 80 287 335 279 +6 56 76 75 292 275 354 +CELL_TYPES 154 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +22 +CELL_DATA 154 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/data/square-disc-p3.mesh b/data/square-disc-p3.mesh new file mode 100644 index 0000000000..b91986b0f4 --- /dev/null +++ b/data/square-disc-p3.mesh @@ -0,0 +1,1763 @@ +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 +154 +1 2 1 23 0 +1 2 48 1 2 +1 2 4 49 3 +1 2 7 5 6 +1 2 7 8 50 +1 2 8 9 51 +1 2 9 10 52 +1 2 10 11 53 +1 2 13 11 12 +1 2 11 13 53 +1 2 49 88 58 +1 2 63 99 64 +1 2 14 15 54 +1 2 55 16 17 +1 2 19 17 18 +1 2 17 19 55 +1 2 52 91 99 +1 2 69 98 70 +1 2 20 21 56 +1 2 22 23 57 +1 2 24 58 25 +1 2 25 59 26 +1 2 60 27 26 +1 2 27 61 28 +1 2 28 62 29 +1 2 29 63 30 +1 2 64 31 30 +1 2 65 32 31 +1 2 32 66 33 +1 2 67 34 33 +1 2 34 68 35 +1 2 35 69 36 +1 2 70 37 36 +1 2 37 71 38 +1 2 38 72 39 +1 2 39 73 40 +1 2 40 74 41 +1 2 41 75 42 +1 2 76 43 42 +1 2 77 44 43 +1 2 44 78 45 +1 2 45 79 46 +1 2 46 80 47 +1 2 47 81 24 +1 2 50 5 7 +1 2 48 2 82 +1 2 3 82 2 +1 2 4 5 83 +1 2 51 50 8 +1 2 51 9 52 +1 2 53 52 10 +1 2 13 14 84 +1 2 53 13 84 +1 2 54 84 14 +1 2 54 15 85 +1 2 55 85 16 +1 2 15 16 85 +1 2 24 81 58 +1 2 19 20 86 +1 2 55 19 86 +1 2 56 86 20 +1 2 21 87 56 +1 2 21 22 87 +1 2 25 58 59 +1 2 60 26 59 +1 2 60 61 27 +1 2 61 62 28 +1 2 63 29 62 +1 2 30 63 64 +1 2 64 65 31 +1 2 65 66 32 +1 2 67 33 66 +1 2 67 68 34 +1 2 69 35 68 +1 2 36 69 70 +1 2 70 71 37 +1 2 72 38 71 +1 2 39 72 73 +1 2 74 40 73 +1 2 75 41 74 +1 2 76 42 75 +1 2 43 76 77 +1 2 44 77 78 +1 2 79 45 78 +1 2 46 79 80 +1 2 81 47 80 +1 2 23 1 57 +1 2 83 49 4 +1 2 82 3 49 +1 2 5 50 83 +1 2 82 49 81 +1 2 82 79 48 +1 2 52 63 51 +1 2 56 87 76 +1 2 57 87 22 +1 2 57 1 48 +1 2 85 69 54 +1 2 88 60 59 +1 2 60 89 61 +1 2 88 89 60 +1 2 61 90 62 +1 2 91 66 65 +1 2 66 92 67 +1 2 66 91 92 +1 2 68 67 93 +1 2 94 72 71 +1 2 95 73 72 +1 2 72 94 95 +1 2 73 96 74 +1 2 97 78 77 +1 2 83 50 89 +1 2 50 51 90 +1 2 51 63 90 +1 2 87 57 97 +1 2 85 55 94 +1 2 90 63 62 +1 2 86 56 96 +1 2 58 88 59 +1 2 69 85 98 +1 2 98 94 71 +1 2 99 91 65 +1 2 80 82 81 +1 2 87 77 76 +1 2 89 90 61 +1 2 99 65 64 +1 2 92 93 67 +1 2 68 54 69 +1 2 98 71 70 +1 2 73 95 96 +1 2 78 100 79 +1 2 50 90 89 +1 2 54 68 93 +1 2 97 100 78 +1 2 81 49 58 +1 2 48 79 100 +1 2 57 100 97 +1 2 84 54 93 +1 2 57 48 100 +1 2 85 94 98 +1 2 95 86 96 +1 2 92 84 93 +1 2 53 84 92 +1 2 56 74 96 +1 2 55 95 94 +1 2 55 86 95 +1 2 63 52 99 +1 2 52 53 91 +1 2 74 56 75 +1 2 53 92 91 +1 2 49 83 88 +1 2 83 89 88 +1 2 77 87 97 +1 2 79 82 80 +1 2 56 76 75 + +boundary +48 +1 1 1 0 +1 1 2 1 +1 1 3 2 +1 1 4 3 +1 1 5 4 +1 1 6 5 +2 1 7 6 +2 1 8 7 +2 1 9 8 +2 1 10 9 +2 1 11 10 +2 1 12 11 +3 1 13 12 +3 1 14 13 +3 1 15 14 +3 1 16 15 +3 1 17 16 +3 1 18 17 +4 1 19 18 +4 1 20 19 +4 1 21 20 +4 1 22 21 +4 1 23 22 +4 1 0 23 +5 1 24 25 +5 1 25 26 +5 1 26 27 +5 1 27 28 +5 1 28 29 +5 1 29 30 +6 1 30 31 +6 1 31 32 +6 1 32 33 +6 1 33 34 +6 1 34 35 +6 1 35 36 +7 1 36 37 +7 1 37 38 +7 1 38 39 +7 1 39 40 +7 1 40 41 +7 1 41 42 +8 1 42 43 +8 1 43 44 +8 1 44 45 +8 1 45 46 +8 1 46 47 +8 1 47 24 + +vertices +101 + +nodes +FiniteElementSpace +FiniteElementCollection: Cubic +VDim: 2 +Ordering: 0 + +0 +0.166667 +0.333333 +0.5 +0.666667 +0.833333 +1 +1 +1 +1 +1 +1 +1 +0.833333 +0.666667 +0.5 +0.333333 +0.166667 +0 +0 +0 +0 +0 +0 +0.5 +0.551762 +0.599999 +0.641421 +0.673203 +0.69318 +0.7 +0.69318 +0.673203 +0.641421 +0.599999 +0.551762 +0.5 +0.448238 +0.400001 +0.358579 +0.326797 +0.30682 +0.3 +0.30682 +0.326797 +0.358579 +0.400001 +0.448238 +0.279991 +0.542938 +0.883276 +0.880537 +0.896176 +0.876247 +0.56708 +0.214021 +0.1299 +0.128123 +0.546957 +0.595941 +0.659375 +0.713067 +0.738724 +0.788944 +0.748056 +0.734295 +0.701733 +0.664196 +0.5873 +0.532263 +0.47118 +0.388673 +0.332617 +0.293213 +0.254423 +0.236519 +0.223994 +0.255449 +0.299483 +0.344106 +0.404605 +0.470624 +0.405302 +0.738879 +0.742095 +0.433637 +0.113182 +0.125165 +0.628595 +0.74788 +0.804906 +0.802986 +0.733131 +0.651834 +0.316268 +0.253731 +0.208423 +0.208303 +0.438192 +0.800877 +0.266012 +0.104828 +0.0536141 +9.25188e-18 +9.25188e-18 +0.0555557 +0.111111 +0.209921 +0.23889 +0.222222 +0.277778 +0.310494 +0.295485 +0.622618 +0.58981 +0.519974 +0.526775 +0.555556 +0.611111 +0.890448 +0.947238 +0.888889 +0.944444 +1 +1 +1 +1 +0.956663 +0.924658 +0.963538 +0.92345 +1 +1 +0.963823 +0.924326 +0.963502 +0.920293 +1 +1 +0.969444 +0.932575 +0.961716 +0.936118 +1 +1 +0.960574 +0.919527 +0.957594 +0.919367 +0.937943 +0.882426 +1 +1 +0.944444 +0.888889 +0.849438 +0.859293 +0.576916 +0.602663 +0.576663 +0.602612 +0.543862 +0.544588 +0.790905 +0.794311 +0.763119 +0.781287 +0.774176 +0.759914 +0.611111 +0.555556 +0.528103 +0.551078 +0.631637 +0.604829 +0.289934 +0.259977 +0.277778 +0.222222 +0.184084 +0.198241 +0.112264 +0.0618555 +0.111111 +0.0555557 +0 +0 +0.0682874 +0.147503 +0.867199 +0.831718 +0.801353 +0.803062 +0.86648 +0.836767 +0.50165 +0.469782 +0.457751 +0.449701 +0.508946 +0.488412 +0 +0 +0.0372791 +0.0837324 +0.048044 +0.0817945 +0 +0 +0.0457626 +0.0901352 +0.0463411 +0.0838291 +0.517165 +0.533393 +0.548876 +0.549001 +0.517254 +0.534508 +0.566857 +0.58171 +0.599964 +0.600335 +0.567841 +0.58392 +0.64909 +0.656324 +0.613806 +0.627614 +0.620525 +0.638108 +0.668054 +0.691358 +0.686136 +0.703283 +0.652015 +0.662609 +0.692961 +0.715081 +0.708415 +0.724268 +0.679862 +0.686521 +0.722625 +0.757713 +0.728061 +0.757299 +0.695453 +0.697727 +0.712406 +0.73049 +0.697727 +0.695453 +0.716997 +0.730664 +0.694913 +0.716098 +0.686521 +0.679862 +0.70782 +0.719943 +0.683395 +0.693505 +0.66307 +0.684234 +0.662609 +0.652015 +0.618633 +0.641882 +0.627614 +0.613806 +0.647813 +0.653481 +0.598405 +0.592206 +0.566137 +0.575292 +0.58392 +0.567841 +0.544151 +0.538697 +0.509962 +0.521653 +0.534508 +0.517254 +0.455133 +0.465503 +0.482746 +0.465492 +0.490073 +0.481291 +0.429351 +0.40939 +0.393646 +0.391249 +0.432159 +0.41608 +0.375266 +0.354591 +0.346829 +0.337877 +0.386194 +0.372386 +0.335852 +0.315369 +0.317876 +0.303942 +0.347985 +0.337391 +0.303604 +0.277171 +0.290015 +0.270816 +0.320138 +0.313479 +0.283155 +0.258032 +0.280266 +0.25745 +0.304547 +0.302273 +0.277216 +0.25229 +0.302273 +0.304547 +0.273381 +0.25042 +0.304539 +0.279187 +0.313479 +0.320138 +0.290345 +0.274382 +0.316134 +0.309141 +0.33732 +0.316629 +0.337391 +0.347985 +0.35606 +0.349743 +0.383846 +0.363073 +0.372386 +0.386194 +0.400376 +0.400773 +0.431353 +0.416937 +0.41608 +0.432159 +0.456454 +0.461841 +0.493517 +0.483093 +0.482746 +0.465492 +0.852879 +0.8635 +0.360635 +0.377381 +0.316824 +0.362263 +0.464816 +0.43312 +0.388889 +0.444444 +0.722222 +0.777778 +0.799156 +0.766245 +0.693661 +0.7102 +0.885458 +0.881498 +0.882935 +0.889543 +0.894226 +0.880976 +0.777778 +0.722222 +0.689568 +0.720233 +0.803004 +0.769532 +0.8323 +0.790697 +0.628437 +0.681697 +0.47556 +0.458842 +0.526625 +0.479032 +0.285519 +0.367182 +0.368683 +0.402775 +0.444444 +0.388889 +0.523943 +0.498649 +0 +0 +0.0331449 +0.0731249 +0.0350478 +0.0733036 +0.179631 +0.153367 +0.122877 +0.121077 +0.0409829 +0.086285 +0.127124 +0.131199 +0 +0 +0.0463594 +0.0863207 +0.563103 +0.578559 +0.617666 +0.641735 +0.677264 +0.696399 +0.724379 +0.731829 +0.756095 +0.768725 +0.744411 +0.740679 +0.727487 +0.713024 +0.689565 +0.67842 +0.636701 +0.613454 +0.566311 +0.549473 +0.442717 +0.414314 +0.365883 +0.351131 +0.316607 +0.307244 +0.283485 +0.266818 +0.249508 +0.243126 +0.232805 +0.229253 +0.234329 +0.241713 +0.271697 +0.286113 +0.313798 +0.330967 +0.365748 +0.383362 +0.429037 +0.450009 +0.148865 +0.146475 +0.611176 +0.672397 +0.499713 +0.446116 +0.830236 +0.788534 +0.521487 +0.496957 +0.446921 +0.427194 +0.363355 +0.381861 +0.299887 +0.32105 +0.861426 +0.827391 +0.85153 +0.81593 +0.193114 +0.158741 +0.158631 +0.193217 +0.128234 +0.130265 +0.230649 +0.177217 +0.497159 +0.468496 +0.558988 +0.542458 +0.649366 +0.640319 +0.610586 +0.616778 +0.69033 +0.720971 +0.728536 +0.734639 +0.668351 +0.70467 +0.748122 +0.777864 +0.759813 +0.781223 +0.733936 +0.771245 +0.755795 +0.782996 +0.711039 +0.719959 +0.686193 +0.708513 +0.78075 +0.752537 +0.658521 +0.656625 +0.60959 +0.632278 +0.322283 +0.319047 +0.365605 +0.338569 +0.283472 +0.26866 +0.304747 +0.279182 +0.29657 +0.273476 +0.268965 +0.237597 +0.241117 +0.22718 +0.266344 +0.23497 +0.236517 +0.222175 +0.842674 +0.789451 +0.73762 +0.738053 +0.852944 +0.833153 +0.857673 +0.827821 +0.790024 +0.800633 +0.15515 +0.180334 +0.15132 +0.180318 +0.25042 +0.279519 +0.400269 +0.357172 +0.152023 +0.182807 +0.145476 +0.18171 +0.441132 +0.435285 +0.353936 +0.398122 +0.406973 +0.420473 +0.758872 +0.777318 +0.404654 +0.403362 +0.210227 +0.165853 +0.767034 +0.785686 +0.708856 +0.677178 +0.576252 +0.585311 +0.240348 +0.221283 +0.286533 +0.273094 +0.318804 +0.289051 +0.596017 +0.625995 +0.228203 +0.244021 +0.27871 +0.266255 +0.170719 +0.223891 +0.708824 +0.680996 +0.162538 +0.204225 +0.73954 +0.733071 +0.825666 +0.779571 +0.173659 +0.213077 +0.228123 +0.240291 +0.855614 +0.826735 +0.164561 +0.199844 +0.700335 +0.66328 +0.0564867 +0.26543 +0.569643 +0.939742 +0.956352 +0.96179 +0.968222 +0.962113 +0.950232 +0.905372 +0.575989 +0.775447 +0.580522 +0.244294 +0.0532731 +0.123881 +0.831154 +0.477005 +0.0435138 +0.0414965 +0.532797 +0.583121 +0.635701 +0.674384 +0.703438 +0.728566 +0.713345 +0.70119 +0.672195 +0.632758 +0.582041 +0.529514 +0.471001 +0.410893 +0.360934 +0.324805 +0.294021 +0.281918 +0.278112 +0.29828 +0.327419 +0.368604 +0.419389 +0.471019 +0.907666 +0.336523 +0.409338 +0.748251 +0.919625 +0.929942 +0.920738 +0.750816 +0.81439 +0.653256 +0.506011 +0.326271 +0.427147 +0.505983 +0.0428886 +0.106968 +0.0815212 +0.0881164 +0.0379996 +0.565499 +0.617755 +0.670908 +0.708932 +0.737385 +0.746852 +0.724684 +0.702418 +0.66874 +0.614247 +0.554272 +0.499882 +0.436161 +0.371684 +0.329063 +0.291967 +0.26707 +0.252873 +0.261578 +0.293624 +0.336175 +0.383001 +0.440909 +0.0940626 +0.648084 +0.486414 +0.811701 +0.474535 +0.341042 +0.85879 +0.161721 +0.0893522 +0.184729 +0.508039 +0.628596 +0.705182 +0.675038 +0.754537 +0.745646 +0.698915 +0.747827 +0.633798 +0.346081 +0.292383 +0.300585 +0.253654 +0.255578 +0.787723 +0.852638 +0.823218 +0.158343 +0.327462 +0.779276 +0.150288 +0.589269 +0.467341 +0.37808 +0.777712 +0.429646 +0.201694 +0.752583 +0.762605 +0.682492 +0.559923 +0.43399 +0.254951 +0.300894 +0.815626 +0.605009 +0.256504 +0.519541 +0.296171 +0.20267 +0.650369 +0.228473 +0.396377 +0.193364 +0.710994 +0.786714 +0.198913 +0.258141 +0.197578 +0.829669 +0.854592 +0.20387 +0.805148 +0.636004 +0.702492 +0.199202 +0.383055 +0.198383 +0 +0 +0 +0 +0 +0 +0 +0.166667 +0.333333 +0.5 +0.666667 +0.833333 +1 +1 +1 +1 +1 +1 +1 +0.833333 +0.666667 +0.5 +0.333333 +0.166667 +0.3 +0.30682 +0.326797 +0.358579 +0.400001 +0.448238 +0.5 +0.551762 +0.599999 +0.641421 +0.673203 +0.69318 +0.7 +0.69318 +0.673203 +0.641421 +0.599999 +0.551762 +0.5 +0.448238 +0.400001 +0.358579 +0.326797 +0.30682 +0.152867 +0.129267 +0.247427 +0.416223 +0.554631 +0.767429 +0.866228 +0.858218 +0.563695 +0.232756 +0.233336 +0.270766 +0.292532 +0.341465 +0.415204 +0.462022 +0.531489 +0.596912 +0.656979 +0.703352 +0.749757 +0.781722 +0.750356 +0.748623 +0.710417 +0.654113 +0.597383 +0.529691 +0.470237 +0.397507 +0.342517 +0.266474 +0.25821 +0.212312 +0.140125 +0.121403 +0.879671 +0.910102 +0.72739 +0.413443 +0.201956 +0.258207 +0.368798 +0.660841 +0.727297 +0.78553 +0.8051 +0.740752 +0.656628 +0.338855 +0.816321 +0.5514 +0.256931 +0.0594471 +0.104536 +0.0555557 +0.111111 +0 +0 +0.0531625 +0.0945164 +8.28804e-18 +8.28804e-18 +0.0549444 +0.0978266 +0.0454757 +0.0813077 +0.0405096 +0.0849014 +0 +0 +0.0501223 +0.115832 +9.25188e-18 +9.25188e-18 +0.0555557 +0.111111 +0.222222 +0.277778 +0.305315 +0.28149 +0.193241 +0.222275 +0.388889 +0.444444 +0.474323 +0.446721 +0.362047 +0.392531 +0.555556 +0.611111 +0.632451 +0.59345 +0.518653 +0.539577 +0.722222 +0.777778 +0.817262 +0.78763 +0.704246 +0.734337 +0.888535 +0.949668 +0.888889 +0.944444 +1 +1 +0.927192 +0.845591 +0.155171 +0.175515 +0.223438 +0.2121 +0.166386 +0.200972 +0.494507 +0.524109 +0.537785 +0.544235 +0.485136 +0.507482 +1 +1 +0.958794 +0.915828 +0.958949 +0.914349 +0.949914 +0.910494 +1 +1 +0.949661 +0.906951 +0.949131 +0.88805 +1 +1 +0.944444 +0.888889 +0.845722 +0.858758 +0.5917 +0.622919 +0.624469 +0.589754 +0.557755 +0.55788 +0.791732 +0.804213 +0.770288 +0.794725 +0.770358 +0.760239 +0.611111 +0.555556 +0.518925 +0.536319 +0.635588 +0.596684 +0.277778 +0.222222 +0.187736 +0.214253 +0.295521 +0.262569 +0.277927 +0.257588 +0.283491 +0.258901 +0.302273 +0.304547 +0.29469 +0.282988 +0.30801 +0.290965 +0.313479 +0.320138 +0.337408 +0.3119 +0.337391 +0.347985 +0.314982 +0.304507 +0.352905 +0.350328 +0.378793 +0.36343 +0.372386 +0.386194 +0.403554 +0.410303 +0.437385 +0.426238 +0.41608 +0.432159 +0.451696 +0.457214 +0.488317 +0.477401 +0.465492 +0.482746 +0.543278 +0.536543 +0.517254 +0.534508 +0.512157 +0.518922 +0.600494 +0.598856 +0.567841 +0.58392 +0.56725 +0.582796 +0.617709 +0.640492 +0.647268 +0.650773 +0.613806 +0.627614 +0.681771 +0.692131 +0.652015 +0.662609 +0.664017 +0.682513 +0.699649 +0.726862 +0.711863 +0.729955 +0.679862 +0.686521 +0.723481 +0.753628 +0.725431 +0.754953 +0.695453 +0.697727 +0.712489 +0.729382 +0.697727 +0.695453 +0.716444 +0.732499 +0.71091 +0.729424 +0.696759 +0.720053 +0.686521 +0.679862 +0.686176 +0.699024 +0.661807 +0.684769 +0.662609 +0.652015 +0.645101 +0.648958 +0.619435 +0.637377 +0.627614 +0.613806 +0.601438 +0.597975 +0.566682 +0.585916 +0.58392 +0.567841 +0.542653 +0.537336 +0.511582 +0.522182 +0.534508 +0.517254 +0.453662 +0.463554 +0.482746 +0.465492 +0.491237 +0.481142 +0.399891 +0.399377 +0.432159 +0.41608 +0.43237 +0.414435 +0.380863 +0.364284 +0.353516 +0.347374 +0.386194 +0.372386 +0.329193 +0.297555 +0.30463 +0.284229 +0.347985 +0.337391 +0.303881 +0.28018 +0.288505 +0.272585 +0.320138 +0.313479 +0.275374 +0.242986 +0.272795 +0.240456 +0.302273 +0.304547 +0.0773849 +0.164725 +0.0421094 +0.0954396 +0.141389 +0.144568 +0.0512226 +0.0926822 +0 +0 +0 +0 +0.039844 +0.081805 +0.0456493 +0.0822241 +0.304796 +0.361443 +0.462831 +0.506173 +0.631947 +0.69758 +1 +1 +0.961453 +0.922602 +0.961721 +0.919041 +0.803704 +0.842531 +0.86883 +0.873312 +0.966177 +0.937982 +0.87907 +0.89191 +0.872795 +0.889233 +0.970685 +0.940455 +1 +1 +0.230226 +0.221966 +0.777778 +0.722222 +0.686415 +0.704867 +0.795909 +0.766054 +0.815033 +0.77053 +0.613564 +0.674807 +0.470385 +0.444785 +0.512317 +0.458746 +0.444444 +0.388889 +0.353492 +0.389678 +0.247789 +0.257676 +0.276895 +0.286031 +0.307672 +0.325295 +0.364232 +0.387416 +0.428039 +0.447676 +0.552414 +0.572995 +0.617326 +0.635116 +0.675271 +0.691286 +0.718574 +0.733284 +0.761525 +0.771086 +0.747865 +0.748985 +0.731989 +0.723629 +0.691579 +0.673944 +0.634438 +0.616541 +0.578799 +0.552463 +0.50913 +0.490528 +0.446109 +0.423123 +0.380173 +0.363605 +0.320221 +0.291622 +0.264662 +0.262204 +0.244336 +0.223858 +0.083778 +0.153638 +0.122491 +0.128822 +0.131022 +0.134463 +0.201731 +0.160809 +0.157499 +0.182472 +0.189959 +0.167078 +0.222964 +0.182174 +0.190313 +0.227297 +0.527064 +0.495537 +0.435596 +0.452171 +0.447388 +0.427258 +0.530176 +0.500319 +0.293554 +0.348469 +0.179807 +0.204375 +0.822169 +0.868676 +0.840656 +0.808947 +0.260463 +0.23337 +0.246049 +0.226657 +0.278502 +0.267753 +0.318011 +0.284308 +0.221486 +0.241939 +0.34927 +0.363419 +0.39753 +0.38602 +0.657925 +0.657065 +0.617707 +0.636965 +0.683142 +0.704145 +0.710507 +0.719188 +0.68649 +0.708589 +0.733385 +0.76182 +0.763461 +0.777588 +0.742305 +0.772069 +0.764199 +0.782945 +0.680435 +0.709298 +0.721283 +0.727924 +0.783158 +0.762826 +0.654542 +0.653205 +0.61903 +0.636818 +0.33865 +0.341405 +0.377277 +0.357148 +0.256457 +0.25722 +0.168782 +0.21797 +0.400589 +0.387117 +0.286496 +0.326176 +0.433208 +0.403826 +0.260944 +0.298377 +0.388556 +0.362731 +0.843475 +0.820522 +0.876383 +0.841731 +0.592104 +0.625745 +0.702236 +0.676085 +0.879245 +0.849883 +0.807432 +0.812352 +0.76873 +0.793183 +0.581026 +0.567998 +0.219141 +0.176565 +0.400804 +0.404625 +0.292754 +0.331896 +0.749188 +0.766043 +0.828925 +0.788982 +0.708582 +0.682945 +0.315494 +0.283536 +0.26176 +0.258334 +0.838642 +0.810535 +0.313269 +0.284777 +0.187417 +0.2188 +0.240597 +0.247364 +0.849077 +0.819966 +0.73369 +0.7315 +0.82326 +0.780175 +0.756027 +0.745108 +0.570698 +0.588629 +0.817529 +0.776165 +0.729835 +0.701109 +0.550634 +0.54206 +0.148101 +0.177341 +0.0508624 +0.0551099 +0.0454948 +0.0538455 +0.244753 +0.422664 +0.573056 +0.750885 +0.945517 +0.862774 +0.185467 +0.514986 +0.956784 +0.948304 +0.939664 +0.894804 +0.586961 +0.782282 +0.571592 +0.245604 +0.279469 +0.300299 +0.325228 +0.366698 +0.419738 +0.471226 +0.526915 +0.583999 +0.631724 +0.673752 +0.705248 +0.724221 +0.714453 +0.702736 +0.675736 +0.632421 +0.58206 +0.525919 +0.473588 +0.416947 +0.3665 +0.319021 +0.298851 +0.274753 +0.143502 +0.0922062 +0.0419053 +0.0467851 +0.332975 +0.489269 +0.66595 +0.96066 +0.880775 +0.909982 +0.921158 +0.926721 +0.971488 +0.247985 +0.743199 +0.813697 +0.65786 +0.495259 +0.412179 +0.271147 +0.294434 +0.328351 +0.383701 +0.440618 +0.49675 +0.561381 +0.620438 +0.667862 +0.710209 +0.744069 +0.742989 +0.729598 +0.707025 +0.668022 +0.617622 +0.560736 +0.501603 +0.437023 +0.379312 +0.320862 +0.281898 +0.256561 +0.138128 +0.0891123 +0.0900245 +0.122971 +0.162467 +0.186031 +0.47832 +0.47722 +0.319614 +0.12586 +0.849728 +0.253015 +0.299106 +0.249397 +0.372648 +0.639683 +0.698374 +0.682991 +0.74813 +0.751466 +0.698063 +0.751543 +0.637111 +0.360094 +0.206111 +0.344392 +0.418808 +0.323442 +0.85836 +0.418008 +0.648596 +0.235457 +0.838336 +0.787047 +0.606138 +0.203757 +0.428078 +0.321719 +0.562219 +0.741498 +0.800954 +0.768473 +0.679151 +0.28825 +0.290969 +0.798433 +0.309185 +0.188947 +0.225768 +0.275754 +0.842145 +0.214932 +0.841852 +0.711692 +0.79495 +0.789112 +0.604087 +0.805329 +0.77792 +0.526974 +0.66563 +0.56143 +0.717011 +0.152127 +0.192365 +0.379008 +0.219656 +0.52366 diff --git a/data/square-disc.mesh b/data/square-disc.mesh new file mode 100644 index 0000000000..8499522d44 --- /dev/null +++ b/data/square-disc.mesh @@ -0,0 +1,328 @@ +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 +154 +1 2 1 23 0 +1 2 48 1 2 +1 2 4 49 3 +1 2 7 5 6 +1 2 7 8 50 +1 2 8 9 51 +1 2 9 10 52 +1 2 10 11 53 +1 2 13 11 12 +1 2 11 13 53 +1 2 49 88 58 +1 2 63 99 64 +1 2 14 15 54 +1 2 55 16 17 +1 2 19 17 18 +1 2 17 19 55 +1 2 52 91 99 +1 2 69 98 70 +1 2 20 21 56 +1 2 22 23 57 +1 2 24 58 25 +1 2 25 59 26 +1 2 60 27 26 +1 2 27 61 28 +1 2 28 62 29 +1 2 29 63 30 +1 2 64 31 30 +1 2 65 32 31 +1 2 32 66 33 +1 2 67 34 33 +1 2 34 68 35 +1 2 35 69 36 +1 2 70 37 36 +1 2 37 71 38 +1 2 38 72 39 +1 2 39 73 40 +1 2 40 74 41 +1 2 41 75 42 +1 2 76 43 42 +1 2 77 44 43 +1 2 44 78 45 +1 2 45 79 46 +1 2 46 80 47 +1 2 47 81 24 +1 2 50 5 7 +1 2 48 2 82 +1 2 3 82 2 +1 2 4 5 83 +1 2 51 50 8 +1 2 51 9 52 +1 2 53 52 10 +1 2 13 14 84 +1 2 53 13 84 +1 2 54 84 14 +1 2 54 15 85 +1 2 55 85 16 +1 2 15 16 85 +1 2 24 81 58 +1 2 19 20 86 +1 2 55 19 86 +1 2 56 86 20 +1 2 21 87 56 +1 2 21 22 87 +1 2 25 58 59 +1 2 60 26 59 +1 2 60 61 27 +1 2 61 62 28 +1 2 63 29 62 +1 2 30 63 64 +1 2 64 65 31 +1 2 65 66 32 +1 2 67 33 66 +1 2 67 68 34 +1 2 69 35 68 +1 2 36 69 70 +1 2 70 71 37 +1 2 72 38 71 +1 2 39 72 73 +1 2 74 40 73 +1 2 75 41 74 +1 2 76 42 75 +1 2 43 76 77 +1 2 44 77 78 +1 2 79 45 78 +1 2 46 79 80 +1 2 81 47 80 +1 2 23 1 57 +1 2 83 49 4 +1 2 82 3 49 +1 2 5 50 83 +1 2 82 49 81 +1 2 82 79 48 +1 2 52 63 51 +1 2 56 87 76 +1 2 57 87 22 +1 2 57 1 48 +1 2 85 69 54 +1 2 88 60 59 +1 2 60 89 61 +1 2 88 89 60 +1 2 61 90 62 +1 2 91 66 65 +1 2 66 92 67 +1 2 66 91 92 +1 2 68 67 93 +1 2 94 72 71 +1 2 95 73 72 +1 2 72 94 95 +1 2 73 96 74 +1 2 97 78 77 +1 2 83 50 89 +1 2 50 51 90 +1 2 51 63 90 +1 2 87 57 97 +1 2 85 55 94 +1 2 90 63 62 +1 2 86 56 96 +1 2 58 88 59 +1 2 69 85 98 +1 2 98 94 71 +1 2 99 91 65 +1 2 80 82 81 +1 2 87 77 76 +1 2 89 90 61 +1 2 99 65 64 +1 2 92 93 67 +1 2 68 54 69 +1 2 98 71 70 +1 2 73 95 96 +1 2 78 100 79 +1 2 50 90 89 +1 2 54 68 93 +1 2 97 100 78 +1 2 81 49 58 +1 2 48 79 100 +1 2 57 100 97 +1 2 84 54 93 +1 2 57 48 100 +1 2 85 94 98 +1 2 95 86 96 +1 2 92 84 93 +1 2 53 84 92 +1 2 56 74 96 +1 2 55 95 94 +1 2 55 86 95 +1 2 63 52 99 +1 2 52 53 91 +1 2 74 56 75 +1 2 53 92 91 +1 2 49 83 88 +1 2 83 89 88 +1 2 77 87 97 +1 2 79 82 80 +1 2 56 76 75 + +boundary +48 +1 1 1 0 +1 1 2 1 +1 1 3 2 +1 1 4 3 +1 1 5 4 +1 1 6 5 +2 1 7 6 +2 1 8 7 +2 1 9 8 +2 1 10 9 +2 1 11 10 +2 1 12 11 +3 1 13 12 +3 1 14 13 +3 1 15 14 +3 1 16 15 +3 1 17 16 +3 1 18 17 +4 1 19 18 +4 1 20 19 +4 1 21 20 +4 1 22 21 +4 1 23 22 +4 1 0 23 +5 1 24 25 +5 1 25 26 +5 1 26 27 +5 1 27 28 +5 1 28 29 +5 1 29 30 +6 1 30 31 +6 1 31 32 +6 1 32 33 +6 1 33 34 +6 1 34 35 +6 1 35 36 +7 1 36 37 +7 1 37 38 +7 1 38 39 +7 1 39 40 +7 1 40 41 +7 1 41 42 +8 1 42 43 +8 1 43 44 +8 1 44 45 +8 1 45 46 +8 1 46 47 +8 1 47 24 + +vertices +101 +2 +0 0 +0.166667 0 +0.333333 0 +0.5 0 +0.666667 0 +0.833333 0 +1 0 +1 0.166667 +1 0.333333 +1 0.5 +1 0.666667 +1 0.833333 +1 1 +0.833333 1 +0.666667 1 +0.5 1 +0.333333 1 +0.166667 1 +0 1 +0 0.833333 +0 0.666667 +0 0.5 +0 0.333333 +0 0.166667 +0.5 0.3 +0.551762 0.30682 +0.599999 0.326797 +0.641421 0.358579 +0.673203 0.400001 +0.69318 0.448238 +0.7 0.5 +0.69318 0.551762 +0.673203 0.599999 +0.641421 0.641421 +0.599999 0.673203 +0.551762 0.69318 +0.5 0.7 +0.448238 0.69318 +0.400001 0.673203 +0.358579 0.641421 +0.326797 0.599999 +0.30682 0.551762 +0.3 0.5 +0.30682 0.448238 +0.326797 0.400001 +0.358579 0.358579 +0.400001 0.326797 +0.448238 0.30682 +0.280005 0.149304 +0.545138 0.127037 +0.884465 0.248218 +0.879775 0.419399 +0.89969 0.555741 +0.87616 0.769211 +0.569868 0.867996 +0.215449 0.861969 +0.12837 0.560993 +0.128875 0.229852 +0.546717 0.235246 +0.597968 0.271088 +0.660382 0.290877 +0.715238 0.343348 +0.737642 0.413364 +0.786693 0.464086 +0.746158 0.531455 +0.736367 0.596942 +0.703803 0.657558 +0.66278 0.704986 +0.588288 0.750518 +0.529824 0.781611 +0.47111 0.74969 +0.386777 0.746482 +0.330365 0.70905 +0.29514 0.654214 +0.255436 0.599614 +0.235453 0.531229 +0.222251 0.470237 +0.25499 0.399563 +0.298249 0.343499 +0.344976 0.266622 +0.403251 0.256459 +0.472569 0.21125 +0.402398 0.139935 +0.73572 0.124022 +0.740675 0.875314 +0.437281 0.908261 +0.116116 0.729319 +0.125999 0.410478 +0.629053 0.201535 +0.746593 0.259041 +0.805509 0.369895 +0.801713 0.661291 +0.731831 0.727419 +0.653956 0.787078 +0.315356 0.804965 +0.252498 0.737911 +0.210181 0.65531 +0.207207 0.336529 +0.438101 0.818434 +0.801007 0.553492 +0.264878 0.257489 diff --git a/data/square-disc.vtk b/data/square-disc.vtk new file mode 100644 index 0000000000..9214bcc58e --- /dev/null +++ b/data/square-disc.vtk @@ -0,0 +1,573 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 101 double +0 0 0 +0.166667 0 0 +0.333333 0 0 +0.5 0 0 +0.666667 0 0 +0.833333 0 0 +1 0 0 +1 0.166667 0 +1 0.333333 0 +1 0.5 0 +1 0.666667 0 +1 0.833333 0 +1 1 0 +0.833333 1 0 +0.666667 1 0 +0.5 1 0 +0.333333 1 0 +0.166667 1 0 +0 1 0 +0 0.833333 0 +0 0.666667 0 +0 0.5 0 +0 0.333333 0 +0 0.166667 0 +0.5 0.3 0 +0.551762 0.30682 0 +0.599999 0.326797 0 +0.641421 0.358579 0 +0.673203 0.400001 0 +0.69318 0.448238 0 +0.7 0.5 0 +0.69318 0.551762 0 +0.673203 0.599999 0 +0.641421 0.641421 0 +0.599999 0.673203 0 +0.551762 0.69318 0 +0.5 0.7 0 +0.448238 0.69318 0 +0.400001 0.673203 0 +0.358579 0.641421 0 +0.326797 0.599999 0 +0.30682 0.551762 0 +0.3 0.5 0 +0.30682 0.448238 0 +0.326797 0.400001 0 +0.358579 0.358579 0 +0.400001 0.326797 0 +0.448238 0.30682 0 +0.280005 0.149304 0 +0.545138 0.127037 0 +0.884465 0.248218 0 +0.879775 0.419399 0 +0.89969 0.555741 0 +0.87616 0.769211 0 +0.569868 0.867996 0 +0.215449 0.861969 0 +0.12837 0.560993 0 +0.128875 0.229852 0 +0.546717 0.235246 0 +0.597968 0.271088 0 +0.660382 0.290877 0 +0.715238 0.343348 0 +0.737642 0.413364 0 +0.786693 0.464086 0 +0.746158 0.531455 0 +0.736367 0.596942 0 +0.703803 0.657558 0 +0.66278 0.704986 0 +0.588288 0.750518 0 +0.529824 0.781611 0 +0.47111 0.74969 0 +0.386777 0.746482 0 +0.330365 0.70905 0 +0.29514 0.654214 0 +0.255436 0.599614 0 +0.235453 0.531229 0 +0.222251 0.470237 0 +0.25499 0.399563 0 +0.298249 0.343499 0 +0.344976 0.266622 0 +0.403251 0.256459 0 +0.472569 0.21125 0 +0.402398 0.139935 0 +0.73572 0.124022 0 +0.740675 0.875314 0 +0.437281 0.908261 0 +0.116116 0.729319 0 +0.125999 0.410478 0 +0.629053 0.201535 0 +0.746593 0.259041 0 +0.805509 0.369895 0 +0.801713 0.661291 0 +0.731831 0.727419 0 +0.653956 0.787078 0 +0.315356 0.804965 0 +0.252498 0.737911 0 +0.210181 0.65531 0 +0.207207 0.336529 0 +0.438101 0.818434 0 +0.801007 0.553492 0 +0.264878 0.257489 0 +CELLS 154 616 +3 0 1 23 +3 1 2 48 +3 3 4 49 +3 5 6 7 +3 7 8 50 +3 8 9 51 +3 9 10 52 +3 10 11 53 +3 11 12 13 +3 53 11 13 +3 58 49 88 +3 99 64 63 +3 14 15 54 +3 16 17 55 +3 17 18 19 +3 55 17 19 +3 99 52 91 +3 70 69 98 +3 20 21 56 +3 22 23 57 +3 25 24 58 +3 26 25 59 +3 27 26 60 +3 28 27 61 +3 29 28 62 +3 30 29 63 +3 31 30 64 +3 32 31 65 +3 33 32 66 +3 34 33 67 +3 35 34 68 +3 36 35 69 +3 37 36 70 +3 38 37 71 +3 39 38 72 +3 40 39 73 +3 41 40 74 +3 42 41 75 +3 43 42 76 +3 44 43 77 +3 45 44 78 +3 46 45 79 +3 47 46 80 +3 24 47 81 +3 5 7 50 +3 48 2 82 +3 2 3 82 +3 4 5 83 +3 50 8 51 +3 9 52 51 +3 10 53 52 +3 13 14 84 +3 53 13 84 +3 14 54 84 +3 54 15 85 +3 16 55 85 +3 15 16 85 +3 58 24 81 +3 19 20 86 +3 55 19 86 +3 20 56 86 +3 56 21 87 +3 21 22 87 +3 25 58 59 +3 26 59 60 +3 27 60 61 +3 28 61 62 +3 29 62 63 +3 30 63 64 +3 31 64 65 +3 32 65 66 +3 33 66 67 +3 34 67 68 +3 35 68 69 +3 36 69 70 +3 37 70 71 +3 38 71 72 +3 39 72 73 +3 40 73 74 +3 41 74 75 +3 42 75 76 +3 43 76 77 +3 44 77 78 +3 45 78 79 +3 46 79 80 +3 47 80 81 +3 23 1 57 +3 49 4 83 +3 82 3 49 +3 83 5 50 +3 82 49 81 +3 48 82 79 +3 51 52 63 +3 56 87 76 +3 87 22 57 +3 1 48 57 +3 54 85 69 +3 60 59 88 +3 61 60 89 +3 60 88 89 +3 62 61 90 +3 66 65 91 +3 67 66 92 +3 66 91 92 +3 68 67 93 +3 72 71 94 +3 73 72 95 +3 72 94 95 +3 74 73 96 +3 78 77 97 +3 83 50 89 +3 50 51 90 +3 51 63 90 +3 87 57 97 +3 85 55 94 +3 63 62 90 +3 86 56 96 +3 88 59 58 +3 69 85 98 +3 94 71 98 +3 91 65 99 +3 82 81 80 +3 76 87 77 +3 61 89 90 +3 65 64 99 +3 67 92 93 +3 69 68 54 +3 71 70 98 +3 73 95 96 +3 79 78 100 +3 50 90 89 +3 54 68 93 +3 100 78 97 +3 81 49 58 +3 48 79 100 +3 97 57 100 +3 84 54 93 +3 48 100 57 +3 85 94 98 +3 86 96 95 +3 93 92 84 +3 84 92 53 +3 96 56 74 +3 94 55 95 +3 55 86 95 +3 63 52 99 +3 52 53 91 +3 74 56 75 +3 91 53 92 +3 49 83 88 +3 88 83 89 +3 77 87 97 +3 79 82 80 +3 56 76 75 +CELL_TYPES 154 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +CELL_DATA 154 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/data/star-q2.mesh b/data/star-q2.mesh new file mode 100644 index 0000000000..af3c57c899 --- /dev/null +++ b/data/star-q2.mesh @@ -0,0 +1,273 @@ +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 +20 +1 3 0 11 26 14 +1 3 0 14 27 17 +1 3 0 17 28 20 +1 3 0 20 29 23 +1 3 0 23 30 11 +1 3 11 1 12 26 +1 3 26 12 3 13 +1 3 14 26 13 2 +1 3 14 2 15 27 +1 3 27 15 5 16 +1 3 17 27 16 4 +1 3 17 4 18 28 +1 3 28 18 7 19 +1 3 20 28 19 6 +1 3 20 6 21 29 +1 3 29 21 9 22 +1 3 23 29 22 8 +1 3 23 8 24 30 +1 3 30 24 10 25 +1 3 11 30 25 1 + +boundary +20 +1 1 2 13 +1 1 3 12 +1 1 4 16 +1 1 5 15 +1 1 6 19 +1 1 7 18 +1 1 8 22 +1 1 9 21 +1 1 1 25 +1 1 10 24 +1 1 13 3 +1 1 12 1 +1 1 16 5 +1 1 15 2 +1 1 19 7 +1 1 18 4 +1 1 22 9 +1 1 21 6 +1 1 25 10 +1 1 24 8 + +vertices +31 + +nodes +FiniteElementSpace +FiniteElementCollection: Quadratic +VDim: 2 +Ordering: 0 + +-0.0245438 +1 +0.309017 +1.30902 +-0.809017 +-0.5 +-0.809017 +-1.61803 +0.309017 +-0.5 +1.30902 +0.530062 +1.15451 +0.809019 +0.162852 +-0.0954915 +-0.654508 +-0.392502 +-1.21352 +-1.21352 +-0.382536 +-0.654508 +-0.0954915 +0.17213 +0.809019 +1.15451 +0.674866 +-0.252108 +-0.811904 +-0.255765 +0.626374 +0.253043 +0.555063 +0.389229 +0.0741029 +-0.0343828 +-0.34493 +-0.189873 +-0.584229 +-0.630465 +-0.227089 +-0.333183 +-0.0718634 +0.100232 +0.38111 +0.591956 +0.766212 +1.07726 +0.900741 +1.23176 +1.05902 +0.719492 +0.559018 +0.222384 +0.106763 +-0.1537 +-0.297746 +-0.577254 +-0.465791 +-0.731762 +-0.617295 +-1.01127 +-1.03752 +-1.41578 +-1.41578 +-1.01019 +-1.01127 +-0.589963 +-0.731762 +-0.479558 +-0.577254 +-0.297746 +-0.175503 +0.106763 +0.212886 +0.559018 +0.74592 +1.05902 +1.23176 +0.884421 +1.07726 +0.331829 +-0.126884 +-0.412924 +-0.0993283 +0.33072 +0.807409 +1.01151 +0.480461 +0.026601 +-0.37455 +-0.510868 +-0.792644 +-1.20885 +-0.823099 +-0.539613 +-0.399725 +0.026539 +0.457982 +0.970496 +0.827457 +0.0302653 +0 +0.951057 +0.951057 +0.587785 +1.53884 +-0.587785 +0 +-0.951057 +-1.53884 +-0.951057 +0.00119899 +0.475529 +0.951057 +0.471924 +1.24495 +1.06331 +0.289555 +0.293893 +-0.293892 +-0.267306 +-1.06331 +-1.24495 +-0.474741 +-0.951057 +-0.475529 +0.482068 +0.795075 +-0.0034822 +-0.743674 +-0.480148 +-0.00369251 +0.240863 +0.468354 +0.233316 +0.614526 +0.556722 +0.125421 +0.125286 +-0.125257 +-0.17516 +-0.53859 +-0.630061 +-0.244076 +-0.445676 +-0.21848 +-0.011418 +0.237764 +0.459999 +0.713293 +0.951057 +0.693875 +0.951057 +0.743574 +1.098 +0.999738 +1.39189 +1.30107 +0.904096 +0.825547 +0.424018 +0.440839 +0.129401 +0.146947 +-0.146946 +-0.138465 +-0.440839 +-0.470312 +-0.825547 +-0.929222 +-1.30107 +-1.39189 +-0.996501 +-1.098 +-0.730387 +-0.951057 +-0.739855 +-0.951057 +-0.713293 +-0.487144 +-0.237764 +0.233544 +0.384153 +-0.0214581 +-0.389126 +-0.256952 +0.239334 +0.728982 +0.71249 +0.880016 +1.15597 +0.691453 +0.29678 +0.014766 +-0.294765 +-0.669302 +-1.16136 +-0.852308 +-0.702991 +-0.733566 +-0.212215 diff --git a/data/star-q2.vtk b/data/star-q2.vtk new file mode 100644 index 0000000000..efb8584403 --- /dev/null +++ b/data/star-q2.vtk @@ -0,0 +1,171 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 101 double +-0.0245438 0.0302653 0 +1 0 0 +0.309017 0.951057 0 +1.30902 0.951057 0 +-0.809017 0.587785 0 +-0.5 1.53884 0 +-0.809017 -0.587785 0 +-1.61803 0 0 +0.309017 -0.951057 0 +-0.5 -1.53884 0 +1.30902 -0.951057 0 +0.530062 0.00119899 0 +1.15451 0.475529 0 +0.809019 0.951057 0 +0.162852 0.471924 0 +-0.0954915 1.24495 0 +-0.654508 1.06331 0 +-0.392502 0.289555 0 +-1.21352 0.293893 0 +-1.21352 -0.293892 0 +-0.382536 -0.267306 0 +-0.654508 -1.06331 0 +-0.0954915 -1.24495 0 +0.17213 -0.474741 0 +0.809019 -0.951057 0 +1.15451 -0.475529 0 +0.674866 0.482068 0 +-0.252108 0.795075 0 +-0.811904 -0.0034822 0 +-0.255765 -0.743674 0 +0.626374 -0.480148 0 +0.253043 -0.00369251 0 +0.555063 0.240863 0 +0.389229 0.468354 0 +0.0741029 0.233316 0 +-0.0343828 0.614526 0 +-0.34493 0.556722 0 +-0.189873 0.125421 0 +-0.584229 0.125286 0 +-0.630465 -0.125257 0 +-0.227089 -0.17516 0 +-0.333183 -0.53859 0 +-0.0718634 -0.630061 0 +0.100232 -0.244076 0 +0.38111 -0.445676 0 +0.591956 -0.21848 0 +0.766212 -0.011418 0 +1.07726 0.237764 0 +0.900741 0.459999 0 +1.23176 0.713293 0 +1.05902 0.951057 0 +0.719492 0.693875 0 +0.559018 0.951057 0 +0.222384 0.743574 0 +0.106763 1.098 0 +-0.1537 0.999738 0 +-0.297746 1.39189 0 +-0.577254 1.30107 0 +-0.465791 0.904096 0 +-0.731762 0.825547 0 +-0.617295 0.424018 0 +-1.01127 0.440839 0 +-1.03752 0.129401 0 +-1.41578 0.146947 0 +-1.41578 -0.146946 0 +-1.01019 -0.138465 0 +-1.01127 -0.440839 0 +-0.589963 -0.470312 0 +-0.731762 -0.825547 0 +-0.479558 -0.929222 0 +-0.577254 -1.30107 0 +-0.297746 -1.39189 0 +-0.175503 -0.996501 0 +0.106763 -1.098 0 +0.212886 -0.730387 0 +0.559018 -0.951057 0 +0.74592 -0.739855 0 +1.05902 -0.951057 0 +1.23176 -0.713293 0 +0.884421 -0.487144 0 +1.07726 -0.237764 0 +0.331829 0.233544 0 +-0.126884 0.384153 0 +-0.412924 -0.0214581 0 +-0.0993283 -0.389126 0 +0.33072 -0.256952 0 +0.807409 0.239334 0 +1.01151 0.728982 0 +0.480461 0.71249 0 +0.026601 0.880016 0 +-0.37455 1.15597 0 +-0.510868 0.691453 0 +-0.792644 0.29678 0 +-1.20885 0.014766 0 +-0.823099 -0.294765 0 +-0.539613 -0.669302 0 +-0.399725 -1.16136 0 +0.026539 -0.852308 0 +0.457982 -0.702991 0 +0.970496 -0.733566 0 +0.827457 -0.212215 0 +CELLS 20 200 +9 0 11 26 14 31 32 33 34 81 +9 0 14 27 17 34 35 36 37 82 +9 0 17 28 20 37 38 39 40 83 +9 0 20 29 23 40 41 42 43 84 +9 0 23 30 11 43 44 45 31 85 +9 11 1 12 26 46 47 48 32 86 +9 26 12 3 13 48 49 50 51 87 +9 14 26 13 2 33 51 52 53 88 +9 14 2 15 27 53 54 55 35 89 +9 27 15 5 16 55 56 57 58 90 +9 17 27 16 4 36 58 59 60 91 +9 17 4 18 28 60 61 62 38 92 +9 28 18 7 19 62 63 64 65 93 +9 20 28 19 6 39 65 66 67 94 +9 20 6 21 29 67 68 69 41 95 +9 29 21 9 22 69 70 71 72 96 +9 23 29 22 8 42 72 73 74 97 +9 23 8 24 30 74 75 76 44 98 +9 30 24 10 25 76 77 78 79 99 +9 11 30 25 1 45 79 80 46 100 +CELL_TYPES 20 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +28 +CELL_DATA 20 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/data/star-q3.mesh b/data/star-q3.mesh new file mode 100644 index 0000000000..c802d7c321 --- /dev/null +++ b/data/star-q3.mesh @@ -0,0 +1,493 @@ +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 +20 +1 3 0 11 26 14 +1 3 0 14 27 17 +1 3 0 17 28 20 +1 3 0 20 29 23 +1 3 0 23 30 11 +1 3 11 1 12 26 +1 3 26 12 3 13 +1 3 14 26 13 2 +1 3 14 2 15 27 +1 3 27 15 5 16 +1 3 17 27 16 4 +1 3 17 4 18 28 +1 3 28 18 7 19 +1 3 20 28 19 6 +1 3 20 6 21 29 +1 3 29 21 9 22 +1 3 23 29 22 8 +1 3 23 8 24 30 +1 3 30 24 10 25 +1 3 11 30 25 1 + +boundary +20 +1 1 2 13 +1 1 3 12 +1 1 4 16 +1 1 5 15 +1 1 6 19 +1 1 7 18 +1 1 8 22 +1 1 9 21 +1 1 1 25 +1 1 10 24 +1 1 13 3 +1 1 12 1 +1 1 16 5 +1 1 15 2 +1 1 19 7 +1 1 18 4 +1 1 22 9 +1 1 21 6 +1 1 25 10 +1 1 24 8 + +vertices +31 + +nodes +FiniteElementSpace +FiniteElementCollection: Cubic +VDim: 2 +Ordering: 0 + +-0.0168856 +1 +0.309017 +1.30902 +-0.809017 +-0.5 +-0.809017 +-1.61803 +0.309017 +-0.5 +1.30902 +0.51942 +1.15451 +0.809019 +0.14768 +-0.0954915 +-0.654508 +-0.415586 +-1.21352 +-1.21352 +-0.39221 +-0.654508 +-0.0954915 +0.139949 +0.809019 +1.15451 +0.660184 +-0.264063 +-0.800064 +-0.23106 +0.663691 +0.183114 +0.317639 +0.543082 +0.598483 +0.345112 +0.478298 +0.0277034 +0.095229 +0.0123679 +-0.0925342 +-0.334412 +-0.313767 +-0.140526 +-0.293881 +-0.534056 +-0.66029 +-0.537646 +-0.65559 +-0.121396 +-0.274504 +-0.346497 +-0.29657 +0.00473749 +-0.0988346 +0.0692873 +0.0826746 +0.318799 +0.467183 +0.564505 +0.59519 +0.846237 +0.671735 +1.0515 +1.10301 +0.964008 +0.821603 +1.25752 +1.20601 +1.14235 +0.975686 +0.781273 +0.717257 +0.475684 +0.642352 +0.26893 +0.211049 +0.174181 +0.0393447 +-0.147746 +-0.177481 +-0.365164 +-0.230328 +-0.551503 +-0.603005 +-0.497587 +-0.389864 +-0.757514 +-0.706011 +-0.675487 +-0.528946 +-0.943851 +-1.07869 +-1.0876 +-0.955467 +-1.48319 +-1.34836 +-1.48319 +-1.34836 +-1.08593 +-0.93801 +-0.943851 +-1.07869 +-0.681476 +-0.540944 +-0.757514 +-0.706011 +-0.540614 +-0.367058 +-0.551503 +-0.603005 +-0.365164 +-0.230328 +-0.138552 +-0.206896 +0.174181 +0.0393447 +0.268468 +0.222269 +0.475684 +0.642352 +0.759791 +0.719381 +1.14235 +0.975686 +1.25752 +1.20601 +0.972837 +0.836119 +1.0515 +1.10301 +0.214572 +0.407449 +0.288323 +0.449827 +-0.0867004 +-0.0273582 +-0.20056 +-0.166595 +-0.271802 +-0.418426 +-0.426131 +-0.551441 +-0.0961166 +-0.206969 +-0.0279459 +-0.184969 +0.211136 +0.260131 +0.407172 +0.430781 +0.718277 +0.885068 +0.753103 +0.957692 +0.866273 +1.02453 +0.934099 +1.09382 +0.348422 +0.524463 +0.404903 +0.587376 +0.0545246 +0.146431 +-0.0780258 +-0.00779516 +-0.329488 +-0.302967 +-0.488115 +-0.439332 +-0.498515 +-0.453527 +-0.633059 +-0.570251 +-0.655787 +-0.791132 +-0.802013 +-0.956872 +-1.09472 +-1.20856 +-1.20772 +-1.33991 +-0.693371 +-0.795404 +-0.803594 +-0.945068 +-0.464668 +-0.631721 +-0.458968 +-0.547876 +-0.332878 +-0.485696 +-0.286385 +-0.408481 +0.053021 +-0.0581995 +0.110846 +-0.00208619 +0.381384 +0.416784 +0.551133 +0.613261 +0.872474 +0.901208 +1.0383 +1.08466 +0.737459 +0.75125 +0.890002 +0.91521 +0.0109149 +0 +0.951057 +0.951057 +0.587785 +1.53884 +-0.587785 +0 +-0.951057 +-1.53884 +-0.951057 +-0.0158469 +0.475529 +0.951057 +0.492248 +1.24495 +1.06331 +0.274399 +0.293893 +-0.293892 +-0.296404 +-1.06331 +-1.24495 +-0.453865 +-0.951057 +-0.475529 +0.46662 +0.792932 +-0.0139132 +-0.748783 +-0.497528 +0.0213822 +-0.0171579 +0.172591 +0.330125 +0.458568 +0.457971 +0.13774 +0.299049 +0.588394 +0.667324 +0.432341 +0.634346 +0.117322 +0.193603 +0.211702 +0.0982775 +-0.199438 +-0.0773045 +-0.0822428 +-0.216296 +-0.458634 +-0.592374 +-0.563926 +-0.680404 +-0.135751 +-0.302942 +-0.469005 +-0.45364 +-0.182727 +-0.31424 +0.0242701 +0.0215458 +0.15851 +0.317019 +0.485799 +0.492951 +0.792548 +0.634038 +0.951057 +0.951057 +0.777915 +0.61343 +0.951057 +0.951057 +0.793994 +0.6358 +1.04902 +1.14699 +1.08448 +0.92431 +1.44088 +1.34291 +1.38033 +1.22182 +0.948209 +0.856297 +0.746293 +0.904802 +0.476242 +0.393234 +0.489821 +0.391857 +0.194471 +0.0757513 +0.0979643 +0.195929 +-0.097964 +-0.195928 +-0.173234 +-0.0789219 +-0.489821 +-0.391856 +-0.467007 +-0.397859 +-0.746293 +-0.904802 +-0.945206 +-0.849559 +-1.38033 +-1.22182 +-1.44088 +-1.34291 +-1.10083 +-0.923191 +-1.04902 +-1.14699 +-0.774515 +-0.621542 +-0.951057 +-0.951057 +-0.803055 +-0.635255 +-0.951057 +-0.951057 +-0.792548 +-0.634038 +-0.454301 +-0.479369 +-0.15851 +-0.317019 +0.149331 +0.178643 +0.29586 +0.306275 +0.246225 +0.40661 +0.367954 +0.498458 +-0.0149293 +0.0849168 +-0.0942722 +-0.000726032 +-0.245374 +-0.340755 +-0.435351 +-0.490564 +-0.176355 +-0.294974 +-0.14801 +-0.328246 +0.136248 +0.182883 +0.328957 +0.309903 +0.646446 +0.622546 +0.800859 +0.801803 +0.643087 +0.654473 +0.796963 +0.816799 +0.748189 +0.898148 +0.819092 +0.970033 +1.04954 +1.16266 +1.11531 +1.2667 +0.53996 +0.728396 +0.656318 +0.783152 +0.302716 +0.403858 +0.219006 +0.309252 +0.00966689 +0.107161 +-0.118211 +0.011786 +-0.284704 +-0.179858 +-0.411567 +-0.296676 +-0.570168 +-0.635348 +-0.726784 +-0.793211 +-1.01686 +-1.11297 +-1.17091 +-1.28153 +-0.73786 +-0.851723 +-0.883732 +-0.99507 +-0.653153 +-0.769939 +-0.631918 +-0.797688 +-0.616289 +-0.806819 +-0.638485 +-0.790356 +-0.136399 +-0.322769 +-0.165339 +-0.309622 diff --git a/data/star.mesh b/data/star.mesh new file mode 100644 index 0000000000..d9e1b9c97c --- /dev/null +++ b/data/star.mesh @@ -0,0 +1,96 @@ +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 +20 +1 3 0 11 26 14 +1 3 0 14 27 17 +1 3 0 17 28 20 +1 3 0 20 29 23 +1 3 0 23 30 11 +1 3 11 1 12 26 +1 3 26 12 3 13 +1 3 14 26 13 2 +1 3 14 2 15 27 +1 3 27 15 5 16 +1 3 17 27 16 4 +1 3 17 4 18 28 +1 3 28 18 7 19 +1 3 20 28 19 6 +1 3 20 6 21 29 +1 3 29 21 9 22 +1 3 23 29 22 8 +1 3 23 8 24 30 +1 3 30 24 10 25 +1 3 11 30 25 1 + +boundary +20 +1 1 2 13 +1 1 3 12 +1 1 4 16 +1 1 5 15 +1 1 6 19 +1 1 7 18 +1 1 8 22 +1 1 9 21 +1 1 1 25 +1 1 10 24 +1 1 13 3 +1 1 12 1 +1 1 16 5 +1 1 15 2 +1 1 19 7 +1 1 18 4 +1 1 22 9 +1 1 21 6 +1 1 25 10 +1 1 24 8 + +vertices +31 +2 +0 0 +1 0 +0.309017 0.951057 +1.30902 0.951057 +-0.809017 0.587785 +-0.5 1.53884 +-0.809017 -0.587785 +-1.61803 0 +0.309017 -0.951057 +-0.5 -1.53884 +1.30902 -0.951057 +0.5 0 +1.15451 0.475529 +0.809019 0.951057 +0.154508 0.475529 +-0.0954915 1.24495 +-0.654508 1.06331 +-0.404508 0.293893 +-1.21352 0.293893 +-1.21352 -0.293892 +-0.404508 -0.293893 +-0.654508 -1.06331 +-0.0954915 -1.24495 +0.154508 -0.475529 +0.809019 -0.951057 +1.15451 -0.475529 +0.654509 0.475529 +-0.25 0.769421 +-0.809016 0 +-0.25 -0.76942 +0.654509 -0.475529 diff --git a/data/star.vtk b/data/star.vtk new file mode 100644 index 0000000000..a6094c6aea --- /dev/null +++ b/data/star.vtk @@ -0,0 +1,101 @@ +# vtk DataFile Version 3.0 +Generated by MFEM +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 31 double +0 0 0 +1 0 0 +0.309017 0.951057 0 +1.30902 0.951057 0 +-0.809017 0.587785 0 +-0.5 1.53884 0 +-0.809017 -0.587785 0 +-1.61803 0 0 +0.309017 -0.951057 0 +-0.5 -1.53884 0 +1.30902 -0.951057 0 +0.5 0 0 +1.15451 0.475529 0 +0.809019 0.951057 0 +0.154508 0.475529 0 +-0.0954915 1.24495 0 +-0.654508 1.06331 0 +-0.404508 0.293893 0 +-1.21352 0.293893 0 +-1.21352 -0.293892 0 +-0.404508 -0.293893 0 +-0.654508 -1.06331 0 +-0.0954915 -1.24495 0 +0.154508 -0.475529 0 +0.809019 -0.951057 0 +1.15451 -0.475529 0 +0.654509 0.475529 0 +-0.25 0.769421 0 +-0.809016 0 0 +-0.25 -0.76942 0 +0.654509 -0.475529 0 +CELLS 20 100 +4 0 11 26 14 +4 0 14 27 17 +4 0 17 28 20 +4 0 20 29 23 +4 0 23 30 11 +4 11 1 12 26 +4 26 12 3 13 +4 14 26 13 2 +4 14 2 15 27 +4 27 15 5 16 +4 17 27 16 4 +4 17 4 18 28 +4 28 18 7 19 +4 20 28 19 6 +4 20 6 21 29 +4 29 21 9 22 +4 23 29 22 8 +4 23 8 24 30 +4 30 24 10 25 +4 11 30 25 1 +CELL_TYPES 20 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +CELL_DATA 20 +SCALARS material int +LOOKUP_TABLE default +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/examples/SConstruct b/examples/SConstruct index 9b37667cf0..1132552bb5 100644 --- a/examples/SConstruct +++ b/examples/SConstruct @@ -10,18 +10,24 @@ # Software Foundation) version 2.1 dated February 1999. Help(""" - Type: 'scons' to build the production library, + Type: 'scons' to build the example codes, 'scons -c' to clean the build, - 'scons debug=1' to build the debug version. + 'scons debug=1' to build the debug version, + 'scons parallel=1' to build the parallel version. """) import os -env = Environment() +# Export the shell environment variables +env = Environment(ENV=os.environ) CC_OPTS = '-O3' DEBUG_OPTS = '-g -Wall' +# External libraries +HYPRE_DIR = "../../hypre-2.7.0b/src/hypre" +METIS_DIR = "../../metis-4.0" + # Debug options debug = ARGUMENTS.get('debug', 0) if int(debug): @@ -29,6 +35,23 @@ if int(debug): else: env.Append(CCFLAGS = CC_OPTS) +env.Append(LIBS = ['mfem']) +env.Append(LIBPATH = ['..']) +env.Append(CPPPATH = ['..']) + +# Parallel version +parallel = ARGUMENTS.get('parallel', 0) +if int(parallel): + env.Replace(CXX = 'mpiCC') + env.Append(LIBS = ['HYPRE']) + env.Append(CPPPATH = [HYPRE_DIR+"/include"]) + env.Append(LIBPATH = [HYPRE_DIR+"/lib"]) + env.Append(LIBS = ['metis']) + env.Append(LIBPATH = [METIS_DIR]) + print 'Building parallel version' +else: + print 'Building serial version' + conf = Configure(env) # Check for LAPACK @@ -40,10 +63,12 @@ else: env = conf.Finish() -env.Append(LIBS = ['mfem']) -env.Append(LIBPATH = ['..']) -env.Append(CPPPATH = ['..']) - -# libmfem.a library -ex1 = env.Program('ex1',['ex1.cpp']) -ex2 = env.Program('ex2',['ex2.cpp']) +# Example codes +if int(parallel): + ex1p = env.Program('ex1p',['ex1p.cpp']) + ex2p = env.Program('ex2p',['ex2p.cpp']) + ex3p = env.Program('ex3p',['ex3p.cpp']) +else: + ex1 = env.Program('ex1',['ex1.cpp']) + ex2 = env.Program('ex2',['ex2.cpp']) + ex3 = env.Program('ex3',['ex3.cpp']) diff --git a/examples/ex1.cpp b/examples/ex1.cpp index 4f900944c3..fe0311c2dd 100644 --- a/examples/ex1.cpp +++ b/examples/ex1.cpp @@ -2,10 +2,12 @@ // // Compile with: make ex1 // -// Sample runs: ex1 square-disc.mesh2d -// ex1 star.mesh2d -// ex1 escher.mesh3d -// ex1 fichera.mesh3d +// Sample runs: ex1 ../data/square-disc.mesh +// ex1 ../data/star.mesh +// ex1 ../data/escher.mesh +// ex1 ../data/fichera.mesh +// ex1 ../data/square-disc-p2.vtk +// ex1 ../data/square-disc-p3.mesh // // Description: This example code demonstrates the use of MFEM to define a // simple linear finite element discretization of the Laplace @@ -28,7 +30,7 @@ int main (int argc, char *argv[]) if (argc == 1) { - cout << "Usage: ex1 " << endl; + cout << "\nUsage: ex1 \n" << endl; return 1; } @@ -37,7 +39,7 @@ int main (int argc, char *argv[]) ifstream imesh(argv[1]); if (!imesh) { - cerr << "can not open mesh file: " << argv[1] << endl; + cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; return 2; } mesh = new Mesh(imesh, 1, 1); @@ -120,4 +122,6 @@ int main (int argc, char *argv[]) delete fespace; delete fec; delete mesh; + + return 0; } diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp new file mode 100644 index 0000000000..ce248ed49b --- /dev/null +++ b/examples/ex1p.cpp @@ -0,0 +1,194 @@ +// MFEM Example 1 - Parallel Version +// +// Compile with: make ex1p +// +// Sample runs: mpirun -np 4 ex1p ../data/square-disc.mesh +// mpirun -np 4 ex1p ../data/star.mesh +// mpirun -np 4 ex1p ../data/escher.mesh +// mpirun -np 4 ex1p ../data/fichera.mesh +// mpirun -np 4 ex1p ../data/square-disc-p2.vtk +// mpirun -np 4 ex1p ../data/square-disc-p3.mesh +// +// Description: This example code demonstrates the use of MFEM to define a +// simple linear finite element discretization of the Laplace +// problem -Delta u = 1 with homogeneous Dirichlet boundary +// conditions. +// +// 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 boundary conditions on all boundary edges, and the optional +// connection to the GLVis tool for visualization. + +#include +#include "mfem.hpp" + +int main (int argc, char *argv[]) +{ + int num_procs, myid; + + // 1. Initialize MPI + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + Mesh *mesh; + + if (argc == 1) + { + if (myid == 0) + cout << "\nUsage: mpirun -np ex1p \n" << endl; + MPI_Finalize(); + return 1; + } + + // 2. Read the (serial) mesh from the given mesh file on all processors. + // We can handle triangular, quadrilateral, tetrahedral or hexahedral + // elements with the same code. + ifstream imesh(argv[1]); + if (!imesh) + { + if (myid == 0) + cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; + MPI_Finalize(); + return 2; + } + mesh = new Mesh(imesh, 1, 1); + imesh.close(); + + // 3. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 10,000 elements. + { + int ref_levels = + (int)floor(log(10000./mesh->GetNE())/log(2.)/mesh->Dimension()); + for (int l = 0; l < ref_levels; l++) + mesh->UniformRefinement(); + } + + // 4. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + { + int par_ref_levels = 2; + for (int l = 0; l < par_ref_levels; l++) + pmesh->UniformRefinement(); + } + + // 5. Define a parallel finite element space on the parallel mesh. Here we + // use linear finite elements. + FiniteElementCollection *fec = new LinearFECollection; + ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); + + // 6. 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(); + + // 7. 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); + (Vector &)x = 0.0; + + // 8. Set up the parallel bilinear form a(.,.) on the finite element space + // corresponding to the Laplacian operator -Delta, by adding the Diffusion + // domain integrator and imposing homogeneous Dirichlet boundary + // conditions. The boundary conditions are implemented by marking all the + // boundary attributes from the mesh as essential. After serial and + // parallel assembly we extract the corresponding parallel matrix A. + ParBilinearForm *a = new ParBilinearForm(fespace); + a->AddDomainIntegrator(new DiffusionIntegrator(one)); + a->Assemble(); + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 1; + Array ess_dofs; + fespace->GetEssentialVDofs(ess_bdr, ess_dofs); + a->EliminateEssentialBCFromDofs(ess_dofs, x, *b); + } + a->Finalize(); + + // 9. Define the parallel (hypre) matrix and vectors representing a(.,.), + // b(.) and the finite element approximation. + HypreParMatrix *A = a->ParallelAssemble(); + HypreParVector *B = b->ParallelAssemble(); + HypreParVector *X = x.ParallelAverage(); + + delete a; + delete b; + + // 10. 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); + + // 11. Extract the parallel grid function corresponding to the finite element + // approximation X. This is the local solution on each processor. + x = *X; + + // 12. 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; + if (myid == 0) + mesh_ofs.open("refined.mesh"); + pmesh->PrintAsOne(mesh_ofs); + if (myid == 0) + mesh_ofs.close(); + + ofstream sol_ofs; + if (myid == 0) + sol_ofs.open("sol.gf"); + x.SaveAsOne(sol_ofs); + if (myid == 0) + sol_ofs.close(); + } + + // 13. (Optional) Send the solution by socket to a GLVis server. + char vishost[] = "localhost"; + int visport = 19916; + osockstream *sol_sock; + if (myid == 0) + { + sol_sock = new osockstream(visport, vishost); + if (pmesh->Dimension() == 2) + *sol_sock << "fem2d_gf_data\n"; + else + *sol_sock << "fem3d_gf_data\n"; + } + pmesh->PrintAsOne(*sol_sock); + x.SaveAsOne(*sol_sock); + if (myid == 0) + { + sol_sock->send(); + delete sol_sock; + } + + // 14. Free the used memory. + delete pcg; + delete amg; + delete X; + delete B; + delete A; + + delete fespace; + delete fec; + delete pmesh; + + MPI_Finalize(); + + return 0; +} diff --git a/examples/ex2.cpp b/examples/ex2.cpp index 883852d585..0a01dd96ad 100644 --- a/examples/ex2.cpp +++ b/examples/ex2.cpp @@ -2,7 +2,10 @@ // // Compile with: make ex2 // -// Sample runs: ex2 beam.mesh3d +// Sample runs: ex2 ../data/beam-tri.mesh +// ex2 ../data/beam-quad.mesh +// ex2 ../data/beam-tet.mesh +// ex2 ../data/beam-hex.mesh // // Description: This example code solves a simple linear elasticity problem // describing a multi-material Cantilever beam. @@ -38,7 +41,7 @@ int main (int argc, char *argv[]) if (argc == 1) { - cout << "Usage: ex2 " << endl; + cout << "\nUsage: ex2 \n" << endl; return 1; } @@ -47,7 +50,7 @@ int main (int argc, char *argv[]) ifstream imesh(argv[1]); if (!imesh) { - cerr << "can not open mesh file: " << argv[1] << endl; + cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; return 2; } mesh = new Mesh(imesh, 1, 1); @@ -61,7 +64,7 @@ int main (int argc, char *argv[]) // elements. { int ref_levels = - (int)floor(log(5000./mesh->GetNE())/log(2.)/mesh->Dimension()); + (int)floor(log(5000./mesh->GetNE())/log(2.)/dim); for (int l = 0; l < ref_levels; l++) mesh->UniformRefinement(); } @@ -99,17 +102,15 @@ int main (int argc, char *argv[]) // 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. - Coefficient *f_coeff[dim]; - for (int i = 0; i < dim-1; i++) - f_coeff[i] = new ConstantCoefficient(0.0); - Vector pull_force(mesh->bdr_attributes.Max()); - pull_force = 0.0; - pull_force(1) = -1.0e-2; - f_coeff[dim-1] = new PWConstCoefficient(pull_force); - VectorArrayCoefficient f(dim); - for (int i = 0; i < dim; i++) - f.Set(i,f_coeff[i]); + 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) = -1.0e-2; + f.Set(dim-1, new PWConstCoefficient(pull_force)); + } LinearForm *b = new LinearForm(fespace); b->AddDomainIntegrator(new VectorBoundaryLFIntegrator(f)); @@ -181,7 +182,7 @@ int main (int argc, char *argv[]) char vishost[] = "localhost"; int visport = 19916; osockstream sol_sock (visport, vishost); - if (mesh->Dimension() == 2) + if (dim == 2) sol_sock << "vfem2d_gf_data\n"; else sol_sock << "vfem3d_gf_data\n"; @@ -195,4 +196,6 @@ int main (int argc, char *argv[]) delete fespace; delete fec; delete mesh; + + return 0; } diff --git a/examples/ex2p.cpp b/examples/ex2p.cpp new file mode 100644 index 0000000000..a39f74d3b5 --- /dev/null +++ b/examples/ex2p.cpp @@ -0,0 +1,279 @@ +// MFEM Example 2 - Parallel Version +// +// Compile with: make ex2p +// +// Sample runs: mpirun -np 4 ex2p ../data/beam-tri.mesh +// mpirun -np 4 ex2p ../data/beam-quad.mesh +// mpirun -np 4 ex2p ../data/beam-tet.mesh +// mpirun -np 4 ex2p ../data/beam-hex.mesh +// +// 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 --->| material | material |<--- boundary +// attribute 1 | 1 | 2 | attribute 2 +// (fixed) +----------+----------+ (pull down) +// +// The example demonstrates the use of (high-order) 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. +// +// We recommend viewing example 1 before viewing this example. + +#include +#include "mfem.hpp" + +int main (int argc, char *argv[]) +{ + int num_procs, myid; + + // 1. Initialize MPI + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + Mesh *mesh; + + if (argc == 1) + { + if (myid == 0) + cout << "\nUsage: mpirun -np ex2p \n" << endl; + MPI_Finalize(); + return 1; + } + + // 2. Read the (serial) mesh from the given mesh file on all processors. + // We can handle triangular, quadrilateral, tetrahedral or hexahedral + // elements with the same code. + ifstream imesh(argv[1]); + if (!imesh) + { + if (myid == 0) + cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; + MPI_Finalize(); + return 2; + } + mesh = new Mesh(imesh, 1, 1); + imesh.close(); + + int dim = mesh->Dimension(); + + // 3. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 1,000 elements. + { + int ref_levels = + (int)floor(log(1000./mesh->GetNE())/log(2.)/dim); + for (int l = 0; l < ref_levels; l++) + mesh->UniformRefinement(); + } + + // 4. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + { + int par_ref_levels = 1; + for (int l = 0; l < par_ref_levels; l++) + pmesh->UniformRefinement(); + } + + // 5. Define a parallel finite element space on the parallel mesh. Here we + // use vector finite elements, i.e. dim copies of a scalar finite element + // space. We use the ordering by vector dimension (the last argument of + // the FiniteElementSpace constructor) which is expected in the systems + // version of BoomerAMG preconditioner. + FiniteElementCollection *fec; + int fec_type; + if (myid == 0) + { + cout << "Choose the finite element space:\n" + << " 1) Linear\n" + << " 2) Quadratic\n" + << " 3) Cubic\n" + << " ---> "; + cin >> fec_type; + } + MPI_Bcast(&fec_type, 1, MPI_INT, 0, MPI_COMM_WORLD); + switch (fec_type) + { + default: + case 1: + fec = new LinearFECollection; break; + case 2: + fec = new QuadraticFECollection; break; + case 3: + fec = new CubicFECollection; break; + } + if (myid == 0) + cout << "Assembling: " << flush; + ParFiniteElementSpace *fespace = + new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM); + + // 6. Set up the parallel 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 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(pmesh->bdr_attributes.Max()); + pull_force = 0.0; + pull_force(1) = -1.0e-2; + f.Set(dim-1, new PWConstCoefficient(pull_force)); + } + + ParLinearForm *b = new ParLinearForm(fespace); + b->AddDomainIntegrator(new VectorBoundaryLFIntegrator(f)); + if (myid == 0) + cout << "r.h.s. ... " << flush; + b->Assemble(); + + // 7. 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); + (Vector &)x = 0.0; + + // 8. Set up the parallel bilinear form a(.,.) on the finite element space + // corresponding to the linear elasticity integrator with piece-wise + // constants coefficient lambda and mu. The boundary conditions are + // implemented by marking only boundary attribute 1 as essential. After + // serial/parallel assembly we extract the corresponding parallel matrix. + Vector lambda(pmesh->attributes.Max()); + lambda = 1.0; + lambda(0) = lambda(1)*50; + PWConstCoefficient lambda_func(lambda); + Vector mu(pmesh->attributes.Max()); + mu = 1.0; + mu(0) = mu(1)*50; + PWConstCoefficient mu_func(mu); + + ParBilinearForm *a = new ParBilinearForm(fespace); + a->AddDomainIntegrator(new ElasticityIntegrator(lambda_func, mu_func)); + if (myid == 0) + cout << "matrix ... " << flush; + a->Assemble(); + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 0; + ess_bdr[0] = 1; + Array ess_dofs; + fespace->GetEssentialVDofs(ess_bdr, ess_dofs); + a->EliminateEssentialBCFromDofs(ess_dofs, x, *b); + } + a->Finalize(); + if (myid == 0) + cout << "done." << endl; + + // 9. Define the parallel (hypre) matrix and vectors representing a(.,.), + // b(.) and the finite element approximation. + HypreParMatrix *A = a->ParallelAssemble(); + HypreParVector *B = b->ParallelAssemble(); + HypreParVector *X = x.ParallelAverage(); + + delete a; + delete b; + + // 10. Define and apply a parallel PCG solver for AX=B with the BoomerAMG + // preconditioner from hypre. + HypreBoomerAMG *amg = new HypreBoomerAMG(*A); + amg->SetSystemsOptions(dim); + HyprePCG *pcg = new HyprePCG(*A); + pcg->SetTol(1e-8); + pcg->SetMaxIter(500); + pcg->SetPrintLevel(2); + pcg->SetPreconditioner(*amg); + pcg->Mult(*B, *X); + + // 11. Extract the parallel grid function corresponding to the finite element + // approximation X. This is the local solution on each processor. + x = *X; + + // 12. 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 FE space chosen + // from the menu. + pmesh->SetNodalFESpace(fespace); + + // 13. 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 = pmesh->GetNodes(); + *nodes += x; + x *= -1; + ofstream mesh_ofs; + if (myid == 0) + mesh_ofs.open("displaced.mesh"); + pmesh->PrintAsOne(mesh_ofs); + if (myid == 0) + mesh_ofs.close(); + + ofstream sol_ofs; + if (myid == 0) + sol_ofs.open("sol.gf"); + x.SaveAsOne(sol_ofs); + if (myid == 0) + sol_ofs.close(); + } + + // 14. (Optional) Send the above data by socket to a GLVis server. Note that + // we use "vfem" instead of "fem" in the initial string, to indicate + // vector grid function. Use the "n" and "b" keys in GLVis to visualize + // the displacements. + char vishost[] = "localhost"; + int visport = 19916; + osockstream *sol_sock; + if (myid == 0) + { + sol_sock = new osockstream(visport, vishost); + if (dim == 2) + *sol_sock << "vfem2d_gf_data\n"; + else + *sol_sock << "vfem3d_gf_data\n"; + } + pmesh->PrintAsOne(*sol_sock); + x.SaveAsOne(*sol_sock); + if (myid == 0) + { + sol_sock->send(); + delete sol_sock; + } + + // 15. Free the used memory. + delete pcg; + delete amg; + delete X; + delete B; + delete A; + + delete fespace; + delete fec; + + MPI_Finalize(); + + return 0; +} diff --git a/examples/ex3.cpp b/examples/ex3.cpp new file mode 100644 index 0000000000..7cc7a534b4 --- /dev/null +++ b/examples/ex3.cpp @@ -0,0 +1,176 @@ +// MFEM Example 3 +// +// Compile with: make ex3 +// +// Sample runs: ex3 ../data/beam-tet.mesh +// ex3 ../data/beam-hex.mesh +// ex3 ../data/escher.mesh +// ex3 ../data/fichera.mesh +// ex3 ../data/fichera-q2.vtk +// ex3 ../data/fichera-q3.mesh +// +// Description: This example code solves a simple 3D electromagnetic diffusion +// problem corresponding to the second order definite Maxwell +// equation curl curl E + E = f with boundary condition +// E x n = . Here, we use a given exact +// solution E and compute the corresponding r.h.s. f. +// We discretize with the lowest order Nedelec finite elements. +// +// The example demonstrates the use of H(curl) finite element +// spaces with the curl-curl and the (vector finite element) mass +// bilinear form, the projection of grid functions between finite +// element spaces and the computation of discretization error when +// the exact solution is known. +// +// We recommend viewing examples 1-2 before viewing this example. + +#include +#include "mfem.hpp" + +// Exact solution, E, and r.h.s., f. See below for implementation. +void E_exact(const Vector &, Vector &); +void f_exact(const Vector &, Vector &); + +int main (int argc, char *argv[]) +{ + Mesh *mesh; + + if (argc == 1) + { + cout << "\nUsage: ex3 \n" << endl; + return 1; + } + + // 1. Read the mesh from the given mesh file. In this 3D example, we can + // handle tetrahedral or hexahedral meshes with the same code. + ifstream imesh(argv[1]); + if (!imesh) + { + cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; + return 2; + } + mesh = new Mesh(imesh, 1, 1); + imesh.close(); + if (mesh -> Dimension() != 3) + { + cerr << "\nThis example requires a 3D mesh\n" << endl; + return 3; + } + + // 2. 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.)/mesh->Dimension()); + for (int l = 0; l < ref_levels; l++) + mesh->UniformRefinement(); + } + + // 3. Define a finite element space on the mesh. Here we use the lowest order + // Nedelec finite elements. + FiniteElementCollection *fec = new ND1_3DFECollection; + FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); + + // 4. Set up the linear form b(.) which corresponds to the right-hand side + // of the FEM linear system, which in this case is (f,phi_i) where f is + // given by the function f_exact and phi_i are the basis functions in the + // finite element fespace. + VectorFunctionCoefficient f(3, f_exact); + LinearForm *b = new LinearForm(fespace); + b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f)); + b->Assemble(); + + // 5. Define the solution vector x as a finite element grid function + // corresponding to fespace. Initialize x by projecting the exact + // solution. Note that only values from the boundary edges will be used + // when eliminating the non-homogenious boundary condition to modify the + // r.h.s. vector b. + GridFunction x(fespace); + VectorFunctionCoefficient E(3, E_exact); + x.ProjectCoefficient(E); + + // 6. Set up the bilinear form corresponding to the EM diffusion operator + // curl muinv curl + sigma I, by adding the curl-curl and the mass domain + // integrators and finally imposing the non-homogeneous Dirichlet boundary + // conditions. The boundary conditions are implemented by marking all the + // boundary attributes from the mesh as essential (Dirichlet). After + // assembly and finalizing we extract the corresponding sparse matrix A. + Coefficient *muinv = new ConstantCoefficient(1.0); + Coefficient *sigma = new ConstantCoefficient(1.0); + BilinearForm *a = new BilinearForm(fespace); + a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv)); + a->AddDomainIntegrator(new VectorFEMassIntegrator(sigma)); + a->Assemble(); + Array ess_bdr(mesh->bdr_attributes.Max()); + ess_bdr = 1; + a->EliminateEssentialBC(ess_bdr, x, *b); + a->Finalize(); + const SparseMatrix &A = a->SpMat(); + + // 7. Define a simple symmetric Gauss-Seidel preconditioner and use it to + // solve the system Ax=b with PCG. + GSSmoother M(A); + x = 0.0; + PCG(A, M, *b, x, 1, 500, 1e-12, 0.0); + + // 8. Compute and print the L^2 norm of the error. + cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl; + + // 9. In order to visualize the solution, we first represent it in the space + // of linear discontinuous vector finite elements. The representation in + // this space is obtained by (exact) projection with ProjectVectorFieldOn. + FiniteElementCollection *dfec = new LinearDiscont3DFECollection; + FiniteElementSpace *dfespace = new FiniteElementSpace(mesh, dfec, 3); + GridFunction dx(dfespace); + x.ProjectVectorFieldOn(dx); + + // 10. 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->Print(mesh_ofs); + ofstream sol_ofs("sol.gf"); + dx.Save(sol_ofs); + } + + // 11. (Optional) Send the solution by socket to a GLVis server. + char vishost[] = "localhost"; + int visport = 19916; + osockstream sol_sock (visport, vishost); + sol_sock << "vfem3d_gf_data\n"; + mesh->Print(sol_sock); + dx.Save(sol_sock); + sol_sock.send(); + + // 12. Free the used memory. + delete dfespace; + delete dfec; + delete a; + delete sigma; + delete muinv; + delete b; + delete fespace; + delete fec; + delete mesh; + + return 0; +} + +// A parameter for the exact solution. +const double kappa = M_PI; + +void E_exact(const Vector &x, Vector &E) +{ + E(0) = sin(kappa * x(1)); + E(1) = sin(kappa * x(2)); + E(2) = sin(kappa * x(0)); +} + +void f_exact(const Vector &x, Vector &f) +{ + f(0) = (1. + kappa * kappa) * sin(kappa * x(1)); + f(1) = (1. + kappa * kappa) * sin(kappa * x(2)); + f(2) = (1. + kappa * kappa) * sin(kappa * x(0)); +} diff --git a/examples/ex3p.cpp b/examples/ex3p.cpp new file mode 100644 index 0000000000..dc197166cf --- /dev/null +++ b/examples/ex3p.cpp @@ -0,0 +1,249 @@ +// MFEM Example 3 - Parallel Version +// +// Compile with: make ex3p +// +// Sample runs: mpirun -np 4 ex3p ../data/beam-tet.mesh +// mpirun -np 4 ex3p ../data/beam-hex.mesh +// mpirun -np 4 ex3p ../data/escher.mesh +// mpirun -np 4 ex3p ../data/fichera.mesh +// mpirun -np 4 ex3p ../data/fichera-q2.vtk +// mpirun -np 4 ex3p ../data/fichera-q3.mesh +// +// Description: This example code solves a simple 3D electromagnetic diffusion +// problem corresponding to the second order definite Maxwell +// equation curl curl E + E = f with boundary condition +// E x n = . Here, we use a given exact +// solution E and compute the corresponding r.h.s. f. +// We discretize with the lowest order Nedelec finite elements. +// +// The example demonstrates the use of H(curl) finite element +// spaces with the curl-curl and the (vector finite element) mass +// bilinear form, the projection of grid functions between finite +// element spaces and the computation of discretization error when +// the exact solution is known. +// +// We recommend viewing examples 1-2 before viewing this example. + +#include +#include "mfem.hpp" + +// Exact solution, E, and r.h.s., f. See below for implementation. +void E_exact(const Vector &, Vector &); +void f_exact(const Vector &, Vector &); + +int main (int argc, char *argv[]) +{ + int num_procs, myid; + + // 1. Initialize MPI + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + Mesh *mesh; + + if (argc == 1) + { + if (myid == 0) + cout << "\nUsage: ex3 \n" << endl; + MPI_Finalize(); + return 1; + } + + // 2. Read the (serial) mesh from the given mesh file on all processors. + // In this 3D example, we can handle tetrahedral or hexahedral meshes + // with the same code. + ifstream imesh(argv[1]); + if (!imesh) + { + if (myid == 0) + cerr << "\nCan not open mesh file: " << argv[1] << '\n' << endl; + MPI_Finalize(); + return 2; + } + mesh = new Mesh(imesh, 1, 1); + imesh.close(); + if (mesh -> Dimension() != 3) + { + if (myid == 0) + cerr << "\nThis example requires a 3D mesh\n" << endl; + MPI_Finalize(); + return 3; + } + + // 3. Refine the serial mesh on all processors to increase the resolution. In + // this example we do 'ref_levels' of uniform refinement. We choose + // 'ref_levels' to be the largest number that gives a final mesh with no + // more than 1,000 elements. + { + int ref_levels = + (int)floor(log(1000./mesh->GetNE())/log(2.)/mesh->Dimension()); + for (int l = 0; l < ref_levels; l++) + mesh->UniformRefinement(); + } + + // 4. Define a parallel mesh by a partitioning of the serial mesh. Refine + // this mesh further in parallel to increase the resolution. Once the + // parallel mesh is defined, the serial mesh can be deleted. + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + { + int par_ref_levels = 2; + for (int l = 0; l < par_ref_levels; l++) + pmesh->UniformRefinement(); + } + + // 5. Define a parallel finite element space on the parallel mesh. Here we + // use the lowest order Nedelec finite elements. + FiniteElementCollection *fec = new ND1_3DFECollection; + ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); + + // 6. Set up the parallel linear form b(.) which corresponds to the + // right-hand side of the FEM linear system, which in this case is + // (f,phi_i) where f is given by the function f_exact and phi_i are the + // basis functions in the finite element fespace. + VectorFunctionCoefficient f(3, f_exact); + ParLinearForm *b = new ParLinearForm(fespace); + b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f)); + b->Assemble(); + + // 7. Define the solution vector x as a parallel finite element grid function + // corresponding to fespace. Initialize x by projecting the exact + // solution. Note that only values from the boundary edges will be used + // when eliminating the non-homogenious boundary condition to modify the + // r.h.s. vector b. + ParGridFunction x(fespace); + VectorFunctionCoefficient E(3, E_exact); + x.ProjectCoefficient(E); + + // 8. Set up the parallel bilinear form corresponding to the EM diffusion + // operator curl muinv curl + sigma I, by adding the curl-curl and the + // mass domain integrators and finally imposing non-homogeneous Dirichlet + // boundary conditions. The boundary conditions are implemented by + // marking all the boundary attributes from the mesh as essential + // (Dirichlet). After serial and parallel assembly we extract the + // parallel matrix A. + Coefficient *muinv = new ConstantCoefficient(1.0); + Coefficient *sigma = new ConstantCoefficient(1.0); + ParBilinearForm *a = new ParBilinearForm(fespace); + a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv)); + a->AddDomainIntegrator(new VectorFEMassIntegrator(sigma)); + a->Assemble(); + { + Array ess_bdr(pmesh->bdr_attributes.Max()); + ess_bdr = 1; + Array ess_dofs; + fespace->GetEssentialVDofs(ess_bdr, ess_dofs); + a->EliminateEssentialBCFromDofs(ess_dofs, x, *b); + } + a->Finalize(); + + // 9. Define the parallel (hypre) matrix and vectors representing a(.,.), + // b(.) and the finite element approximation. + HypreParMatrix *A = a->ParallelAssemble(); + HypreParVector *B = b->ParallelAssemble(); + HypreParVector *X = x.ParallelAverage(); + *X = 0.0; + + delete a; + delete sigma; + delete muinv; + delete b; + + // 10. Define and apply a parallel PCG solver for AX=B with the AMS + // preconditioner from hypre. + HypreSolver *ams = new HypreAMS(*A, fespace); + HyprePCG *pcg = new HyprePCG(*A); + pcg->SetTol(1e-12); + pcg->SetMaxIter(500); + pcg->SetPrintLevel(2); + pcg->SetPreconditioner(*ams); + pcg->Mult(*B, *X); + + // 11. Extract the parallel grid function corresponding to the finite element + // approximation X. This is the local solution on each processor. + x = *X; + + // 12. Compute and print the L^2 norm of the error. + { + double err = x.ComputeL2Error(E); + if (myid == 0) + cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl; + } + + // 13. In order to visualize the solution, we first represent it in the space + // of linear discontinuous vector finite elements. The representation in + // this space is given by (exact) projection with ProjectVectorFieldOn. + FiniteElementCollection *dfec = new LinearDiscont3DFECollection; + ParFiniteElementSpace *dfespace = new ParFiniteElementSpace(pmesh, dfec, 3); + ParGridFunction dx(dfespace); + x.ProjectVectorFieldOn(dx); + + // 14. Save the refined mesh and the solution. This output can be viewed + // later using GLVis: "glvis -m refined.mesh -g sol.gf". + { + ofstream mesh_ofs; + if (myid == 0) + mesh_ofs.open("refined.mesh"); + pmesh->PrintAsOne(mesh_ofs); + if (myid == 0) + mesh_ofs.close(); + + ofstream sol_ofs; + if (myid == 0) + sol_ofs.open("sol.gf"); + dx.SaveAsOne(sol_ofs); + if (myid == 0) + sol_ofs.close(); + } + + // 15. (Optional) Send the solution by socket to a GLVis server. + char vishost[] = "localhost"; + int visport = 19916; + osockstream *sol_sock; + if (myid == 0) + { + sol_sock = new osockstream(visport, vishost); + *sol_sock << "vfem3d_gf_data\n"; + } + pmesh->PrintAsOne(*sol_sock); + dx.SaveAsOne(*sol_sock); + if (myid == 0) + { + sol_sock->send(); + delete sol_sock; + } + + // 16. Free the used memory. + delete dfespace; + delete dfec; + delete pcg; + delete ams; + delete X; + delete B; + delete A; + delete fespace; + delete fec; + delete pmesh; + + MPI_Finalize(); + + return 0; +} + +// A parameter for the exact solution. +const double kappa = M_PI; + +void E_exact(const Vector &x, Vector &E) +{ + E(0) = sin(kappa * x(1)); + E(1) = sin(kappa * x(2)); + E(2) = sin(kappa * x(0)); +} + +void f_exact(const Vector &x, Vector &f) +{ + f(0) = (1. + kappa * kappa) * sin(kappa * x(1)); + f(1) = (1. + kappa * kappa) * sin(kappa * x(2)); + f(2) = (1. + kappa * kappa) * sin(kappa * x(0)); +} diff --git a/examples/makefile b/examples/makefile index 5155953b6d..5e72d688c5 100644 --- a/examples/makefile +++ b/examples/makefile @@ -9,17 +9,28 @@ # terms of the GNU Lesser General Public License (as published by the Free # Software Foundation) version 2.1 dated February 1999. +# Serial compiler CC = g++ -OPTS = -O3 -DEBUG_OPTS = -g -DDEBUG +OPTS = -O3 -I$(MFEM_DIR) +DEBUG_OPTS = -g -I$(MFEM_DIR) +LIBS = $(MFEM_LIB) $(LAPACK_LIBS) +# Parallel compiler +MPICC = mpiCC +MPIOPTS = $(OPTS) -I$(HYPRE_DIR)/include +MPIDEBUG_OPTS = $(DEBUG_OPTS) -I$(HYPRE_DIR)/include +MPILIBS = $(LIBS) -L$(METIS_DIR) -lmetis -L$(HYPRE_DIR)/lib -lHYPRE + +# The MFEM library MFEM_DIR = .. MFEM_LIB = -L$(MFEM_DIR) -lmfem -# Link with LAPACK? (needed if MFEM was compiled with LAPACK support) -USE_LAPACK = YES +# The METIS and HYPRE libraries (needed for the parallel examples) +METIS_DIR = ../../metis-4.0 +HYPRE_DIR = ../../hypre-2.7.0b/src/hypre -# LAPACK and BLAS +# The LAPACK and BLAS libraries (needed if MFEM was compiled with LAPACK support) +USE_LAPACK = YES LAPACK_DIR = $(HOME)/lapack LAPACK_LIB = -L$(LAPACK_DIR) -llapack BLAS_DIR = $(HOME)/lapack @@ -30,18 +41,34 @@ LAPACK_LIBS_NO = LAPACK_LIBS_YES = $(LAPACK_LIB) $(BLAS_LIB) LAPACK_LIBS = $(LAPACK_LIBS_$(USE_LAPACK)) -LIBS = $(MFEM_LIB) $(LAPACK_LIBS) +serial: ex1 ex2 ex3 -all: ex1 ex2 +parallel: ex1p ex2p ex3p ex1: ex1.cpp - $(CC) $(OPTS) -I$(MFEM_DIR) ex1.cpp -o ex1 $(LIBS) + $(CC) $(OPTS) ex1.cpp -o ex1 $(LIBS) + +ex1p: ex1p.cpp + $(MPICC) $(MPIOPTS) ex1p.cpp -o ex1p $(MPILIBS) ex2: ex2.cpp - $(CC) $(OPTS) -I$(MFEM_DIR) ex2.cpp -o ex2 $(LIBS) + $(CC) $(OPTS) ex2.cpp -o ex2 $(LIBS) + +ex2p: ex2p.cpp + $(MPICC) $(MPIOPTS) ex2p.cpp -o ex2p $(MPILIBS) + +ex3: ex3.cpp + $(CC) $(OPTS) ex3.cpp -o ex3 $(LIBS) + +ex3p: ex3p.cpp + $(MPICC) $(MPIOPTS) ex3p.cpp -o ex3p $(MPILIBS) debug: - make "OPTS=$(DEBUG_OPTS)" + make "OPTS=$(DEBUG_OPTS)" serial + +pdebug: + make "MPIOPTS=$(MPIDEBUG_OPTS)" parallel clean: - rm -f *.o ex1 ex2 refined.mesh displaced.mesh sol.gf *~ + rm -f *.o *~ ex1 ex1p ex2 ex2p ex3 ex3p + rm -f refined.mesh displaced.mesh sol.gf diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index a945b1c20e..42984c6262 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -222,7 +222,6 @@ void BilinearForm::EliminateEssentialBC ( Array &bdr_attr_is_ess, Vector &sol, Vector &rhs, int d ) { int i, j, k; - Array vdofs; for (i = 0; i < fes -> GetNBE(); i++) if (bdr_attr_is_ess[fes -> GetBdrAttribute (i)-1]) diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index 8cb59f4173..4f1ed3f221 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -19,13 +19,13 @@ class BilinearForm : public Matrix { protected: /// Sparse matrix to be associated with the form. - SparseMatrix * mat; + SparseMatrix *mat; // Matrix used to eliminate b.c. SparseMatrix *mat_e; /// FE space on which the form lives. - FiniteElementSpace * fes; + FiniteElementSpace *fes; int extern_bfs; @@ -54,59 +54,64 @@ public: BilinearForm (FiniteElementSpace * f, BilinearForm * bf); - Array *GetDBFI() { return &dbfi; }; + Array *GetDBFI() { return &dbfi; } - Array *GetBBFI() { return &bbfi; }; + Array *GetBBFI() { return &bbfi; } - Array *GetFBFI() { return &fbfi; }; + Array *GetFBFI() { return &fbfi; } - Array *GetBFBFI() { return &bfbfi; }; + Array *GetBFBFI() { return &bfbfi; } - const double &operator() (int i, int j) { return (*mat)(i,j); } + const double &operator()(int i, int j) { return (*mat)(i,j); } /// Returns reference to a_{ij}. Index i, j = 0 .. size-1 - virtual double& Elem (int i, int j); + virtual double &Elem(int i, int j); /// Returns constant reference to a_{ij}. Index i, j = 0 .. size-1 - virtual const double& Elem (int i, int j) const; + virtual const double &Elem(int i, int j) const; /// Matrix vector multiplication. - virtual void Mult (const Vector & x, Vector & y) const; + virtual void Mult(const Vector &x, Vector &y) const; - virtual void AddMult (const Vector & x, Vector & y, - const double a = 1.0) const + void FullMult(const Vector &x, Vector &y) const + { mat->Mult(x, y); mat_e->AddMult(x, y); } + + virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const { mat -> AddMult (x, y, a); } - double InnerProduct (const Vector &x, const Vector &y) const - { return mat -> InnerProduct (x, y); } + void FullAddMult(const Vector &x, Vector &y) const + { mat->AddMult(x, y); mat_e->AddMult(x, y); } + + double InnerProduct(const Vector &x, const Vector &y) const + { return mat->InnerProduct (x, y); } /// Returns a pointer to (approximation) of the matrix inverse. - virtual MatrixInverse * Inverse() const; + virtual MatrixInverse *Inverse() const; /// Finalizes the matrix initialization. - virtual void Finalize (int skip_zeros = 1); + virtual void Finalize(int skip_zeros = 1); /// Returns a reference to the sparse martix - const SparseMatrix &SpMat() const { return *mat; }; - SparseMatrix &SpMat() { return *mat; }; + const SparseMatrix &SpMat() const { return *mat; } + SparseMatrix &SpMat() { return *mat; } /// Adds new Domain Integrator. - void AddDomainIntegrator (BilinearFormIntegrator * bfi); + void AddDomainIntegrator(BilinearFormIntegrator *bfi); /// Adds new Boundary Integrator. - void AddBoundaryIntegrator (BilinearFormIntegrator * bfi); + void AddBoundaryIntegrator(BilinearFormIntegrator *bfi); /// Adds new interior Face Integrator. - void AddInteriorFaceIntegrator (BilinearFormIntegrator * bfi); + void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi); /// Adds new boundary Face Integrator. - void AddBdrFaceIntegrator (BilinearFormIntegrator * bfi); + void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi); - void operator= (const double a) + void operator=(const double a) { if (mat != NULL) *mat = a; if (mat_e != NULL) *mat_e = a; } /// Assembles the form i.e. sums over all domain/bdr integrators. - virtual void Assemble (int skip_zeros = 1); + void Assemble(int skip_zeros = 1); void ComputeElementMatrix(int i, DenseMatrix &elmat); void AssembleElementMatrix(int i, const DenseMatrix &elmat, @@ -114,29 +119,37 @@ public: /** If d == 0 the diagonal at the ess. b.c. is set to 1.0, otherwise leave it the same. */ - void EliminateEssentialBC (Array &bdr_attr_is_ess, - Vector &sol, Vector &rhs, int d = 0); + void EliminateEssentialBC(Array &bdr_attr_is_ess, + Vector &sol, Vector &rhs, int d = 0); - void EliminateVDofs (Array &vdofs, - Vector &sol, Vector &rhs, int d = 0); + /// Here, vdofs is a list of DOFs. + void EliminateVDofs(Array &vdofs, Vector &sol, Vector &rhs, int d = 0); - // Eliminate the given vdofs storing the eliminated part internally + /** Eliminate the given vdofs storing the eliminated part internally; + vdofs is a list of DOFs. */ void EliminateVDofs(Array &vdofs, int d = 0); - // Use the stored eliminated part of the matrix to modify r.h.s. + + /** Use the stored eliminated part of the matrix to modify r.h.s.; + vdofs is a list of DOFs (non-directional, i.e. >= 0). */ void EliminateVDofsInRHS(Array &vdofs, const Vector &x, Vector &b); + double FullInnerProduct(const Vector &x, const Vector &y) const { return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); } - virtual void EliminateEssentialBC (Array &bdr_attr_is_ess, int d = 0); + void EliminateEssentialBC(Array &bdr_attr_is_ess, int d = 0); - void EliminateEssentialBCFromDofs (Array &ess_dofs, - Vector &sol, Vector &rhs, int d = 0); + /** Similar to EliminateVDofs but here ess_dofs is a marker + (boolean) array on all vdofs (ess_dofs[i] < 0 is true). */ + void EliminateEssentialBCFromDofs(Array &ess_dofs, Vector &sol, + Vector &rhs, int d = 0); - virtual void EliminateEssentialBCFromDofs (Array &ess_dofs, int d = 0); + /** Similar to EliminateVDofs but here ess_dofs is a marker + (boolean) array on all vdofs (ess_dofs[i] < 0 is true). */ + void EliminateEssentialBCFromDofs(Array &ess_dofs, int d = 0); - void Update (FiniteElementSpace *nfes = NULL); + void Update(FiniteElementSpace *nfes = NULL); - FiniteElementSpace *GetFES() { return fes; }; + FiniteElementSpace *GetFES() { return fes; } /// Destroys bilinear form. virtual ~BilinearForm(); diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp index 7994009a36..ad5f1f5a75 100644 --- a/fem/bilininteg.cpp +++ b/fem/bilininteg.cpp @@ -475,7 +475,7 @@ void CurlCurlIntegrator::AssembleElementMatrix { int nd = el.GetDof(); int dim = el.GetDim(); - double det, constant; + double w; elmat.SetSize(nd); Curlshape.SetSize(nd,dim); @@ -490,23 +490,21 @@ void CurlCurlIntegrator::AssembleElementMatrix const IntegrationRule &ir = IntRules.Get(el.GetGeomType(), order); elmat = 0.0; - for(int i=0;i Eval(Trans,ip); - else - constant = 1.0; + w *= Q->Eval(Trans, ip); - AddMult_a_AAt (constant*ip.weight/det, Curlshape_dFt, elmat); + AddMult_a_AAt(w, Curlshape_dFt, elmat); } } diff --git a/fem/bilininteg.hpp b/fem/bilininteg.hpp index f7163e9f5c..d4f5a02f4d 100644 --- a/fem/bilininteg.hpp +++ b/fem/bilininteg.hpp @@ -16,8 +16,7 @@ class BilinearFormIntegrator { public: - /** Given a particular Finite Element - computes the element matrix elmat. */ + /// Given a particular Finite Element computes the element matrix elmat. virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat); @@ -255,7 +254,7 @@ private: public: CurlCurlIntegrator() { Q = NULL; }; - // Construct a bilinear form integrator for Nedelec elements + /// Construct a bilinear form integrator for Nedelec elements CurlCurlIntegrator(Coefficient &q):Q(&q) {}; /* Given a particular Finite Element, compute the @@ -311,7 +310,7 @@ public: DenseMatrix &elmat); }; -/// (Q div u, div v) for RT elements +/// (Q div u, div v) for RT elements class DivDivIntegrator: public BilinearFormIntegrator { private: diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index da06fb8013..abd3813022 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -12,6 +12,7 @@ // Implementation of Coefficient class #include +#include #include "fem.hpp" double PWConstCoefficient::Eval(ElementTransformation & T, @@ -135,3 +136,42 @@ void MatrixArrayCoefficient::Eval (DenseMatrix &K, ElementTransformation &T, for (j = 0; j < vdim; j++) K(i,j) = Coeff[i*vdim+j] -> Eval(T, ip); } + +double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh, + const IntegrationRule *irs[]) +{ + double norm = 0.0; + ElementTransformation *tr; + + for (int i = 0; i < mesh.GetNE(); i++) + { + tr = mesh.GetElementTransformation(i); + const IntegrationRule &ir = *irs[mesh.GetElementType(i)]; + for (int j = 0; j < ir.GetNPoints(); j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + tr->SetIntPoint(&ip); + double val = fabs(coeff.Eval(*tr, ip)); + if (p < numeric_limits::infinity()) + { + norm += ip.weight * tr->Weight() * pow(val, p); + } + else + { + if (norm < val) + norm = val; + } + } + } + + if (p < numeric_limits::infinity()) + { + // negative quadrature weights may cause norm to be negative + if (norm < 0.) + norm = -pow(-norm, 1. / p); + else + norm = pow(norm, 1. / p); + } + + return norm; +} diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index 92a2e39120..b15f08f5e5 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -318,4 +318,7 @@ public: virtual ~MatrixArrayCoefficient(); }; +double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh, + const IntegrationRule *irs[]); + #endif diff --git a/fem/fe.cpp b/fem/fe.cpp index 9774f06c62..addf181016 100644 --- a/fem/fe.cpp +++ b/fem/fe.cpp @@ -313,7 +313,7 @@ void GaussLinear2DFiniteElement::ProjectDelta(int vertex, Vector &dofs) const } -// 0.5-0.5/sqrt(3) and 0.5+0.5/sqrt(3) +// 0.5-0.5/sqrt(3) and 0.5+0.5/sqrt(3) const double GaussBiLinear2DFiniteElement::p[] = { 0.2113248654051871177454256, 0.7886751345948128822545744 }; @@ -823,6 +823,25 @@ void BiQuadPos2DFiniteElement::CalcDShape(const IntegrationPoint &ip, dshape(2,1) = l3x * d3y; } +void BiQuadPos2DFiniteElement::Project( + Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const +{ + double *d = dofs; + + for (int i = 0; i < 9; i++) + { + const IntegrationPoint &ip = Nodes.IntPoint(i); + Trans.SetIntPoint(&ip); + d[i] = coeff.Eval(Trans, ip); + } + d[4] = 2. * d[4] - 0.5 * (d[0] + d[1]); + d[5] = 2. * d[5] - 0.5 * (d[1] + d[2]); + d[6] = 2. * d[6] - 0.5 * (d[2] + d[3]); + d[7] = 2. * d[7] - 0.5 * (d[3] + d[0]); + d[8] = 4. * d[8] - 0.5 * (d[4] + d[5] + d[6] + d[7]) - + 0.25 * (d[0] + d[1] + d[2] + d[3]); +} + void BiQuadPos2DFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const @@ -2442,7 +2461,8 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) : NodalFiniteElement(3, Geometry::CUBE, (degree+1)*(degree+1)*(degree+1), degree, FunctionSpace::Qk) { - if (degree == 2) { + if (degree == 2) + { I = new int[Dof]; J = new int[Dof]; K = new int[Dof]; @@ -2477,7 +2497,83 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) I[25] = 2; J[25] = 2; K[25] = 1; // element I[26] = 2; J[26] = 2; K[26] = 2; - } else { + } + else if (degree == 3) + { + I = new int[Dof]; + J = new int[Dof]; + K = new int[Dof]; + // nodes + I[ 0] = 0; J[ 0] = 0; K[ 0] = 0; + I[ 1] = 1; J[ 1] = 0; K[ 1] = 0; + I[ 2] = 1; J[ 2] = 1; K[ 2] = 0; + I[ 3] = 0; J[ 3] = 1; K[ 3] = 0; + I[ 4] = 0; J[ 4] = 0; K[ 4] = 1; + I[ 5] = 1; J[ 5] = 0; K[ 5] = 1; + I[ 6] = 1; J[ 6] = 1; K[ 6] = 1; + I[ 7] = 0; J[ 7] = 1; K[ 7] = 1; + // edges + I[ 8] = 2; J[ 8] = 0; K[ 8] = 0; + I[ 9] = 3; J[ 9] = 0; K[ 9] = 0; + I[10] = 1; J[10] = 2; K[10] = 0; + I[11] = 1; J[11] = 3; K[11] = 0; + I[12] = 2; J[12] = 1; K[12] = 0; + I[13] = 3; J[13] = 1; K[13] = 0; + I[14] = 0; J[14] = 2; K[14] = 0; + I[15] = 0; J[15] = 3; K[15] = 0; + I[16] = 2; J[16] = 0; K[16] = 1; + I[17] = 3; J[17] = 0; K[17] = 1; + I[18] = 1; J[18] = 2; K[18] = 1; + I[19] = 1; J[19] = 3; K[19] = 1; + I[20] = 2; J[20] = 1; K[20] = 1; + I[21] = 3; J[21] = 1; K[21] = 1; + I[22] = 0; J[22] = 2; K[22] = 1; + I[23] = 0; J[23] = 3; K[23] = 1; + I[24] = 0; J[24] = 0; K[24] = 2; + I[25] = 0; J[25] = 0; K[25] = 3; + I[26] = 1; J[26] = 0; K[26] = 2; + I[27] = 1; J[27] = 0; K[27] = 3; + I[28] = 1; J[28] = 1; K[28] = 2; + I[29] = 1; J[29] = 1; K[29] = 3; + I[30] = 0; J[30] = 1; K[30] = 2; + I[31] = 0; J[31] = 1; K[31] = 3; + // faces + I[32] = 2; J[32] = 3; K[32] = 0; + I[33] = 3; J[33] = 3; K[33] = 0; + I[34] = 2; J[34] = 2; K[34] = 0; + I[35] = 3; J[35] = 2; K[35] = 0; + I[36] = 2; J[36] = 0; K[36] = 2; + I[37] = 3; J[37] = 0; K[37] = 2; + I[38] = 2; J[38] = 0; K[38] = 3; + I[39] = 3; J[39] = 0; K[39] = 3; + I[40] = 1; J[40] = 2; K[40] = 2; + I[41] = 1; J[41] = 3; K[41] = 2; + I[42] = 1; J[42] = 2; K[42] = 3; + I[43] = 1; J[43] = 3; K[43] = 3; + I[44] = 3; J[44] = 1; K[44] = 2; + I[45] = 2; J[45] = 1; K[45] = 2; + I[46] = 3; J[46] = 1; K[46] = 3; + I[47] = 2; J[47] = 1; K[47] = 3; + I[48] = 0; J[48] = 3; K[48] = 2; + I[49] = 0; J[49] = 2; K[49] = 2; + I[50] = 0; J[50] = 3; K[50] = 3; + I[51] = 0; J[51] = 2; K[51] = 3; + I[52] = 2; J[52] = 2; K[52] = 1; + I[53] = 3; J[53] = 2; K[53] = 1; + I[54] = 2; J[54] = 3; K[54] = 1; + I[55] = 3; J[55] = 3; K[55] = 1; + // element + I[56] = 2; J[56] = 2; K[56] = 2; + I[57] = 3; J[57] = 2; K[57] = 2; + I[58] = 3; J[58] = 3; K[58] = 2; + I[59] = 2; J[59] = 3; K[59] = 2; + I[60] = 2; J[60] = 2; K[60] = 3; + I[61] = 3; J[61] = 2; K[61] = 3; + I[62] = 3; J[62] = 3; K[62] = 3; + I[63] = 2; J[63] = 3; K[63] = 3; + } + else + { mfem_error ("LagrangeHexFiniteElement::LagrangeHexFiniteElement"); } @@ -2492,7 +2588,8 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) dshape1dy.SetSize(dof1d,1); dshape1dz.SetSize(dof1d,1); - for (int n = 0; n < Dof; n++) { + for (int n = 0; n < Dof; n++) + { Nodes.IntPoint(n).x = fe1d -> GetNodes().IntPoint(I[n]).x; Nodes.IntPoint(n).y = fe1d -> GetNodes().IntPoint(J[n]).x; Nodes.IntPoint(n).z = fe1d -> GetNodes().IntPoint(K[n]).x; diff --git a/fem/fe.hpp b/fem/fe.hpp index 432685c383..82f404871f 100644 --- a/fem/fe.hpp +++ b/fem/fe.hpp @@ -399,8 +399,12 @@ public: virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const; virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const; - void Project(VectorCoefficient &vc, ElementTransformation &Trans, - Vector &dofs) const; + virtual void Project(Coefficient &coeff, ElementTransformation &Trans, + Vector &dofs) const; + virtual void Project(VectorCoefficient &vc, ElementTransformation &Trans, + Vector &dofs) const; + virtual void ProjectDelta(int vertex, Vector &dofs) const + { dofs = 0.; dofs(vertex) = 1.; } }; /// Bi-quadratic element on quad with nodes at the 9 Gaussian points @@ -606,6 +610,8 @@ public: virtual void GetLocalInterpolation (ElementTransformation &Trans, DenseMatrix &I) const; + using FiniteElement::Project; + virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; }; @@ -631,6 +637,8 @@ public: virtual void GetLocalInterpolation (ElementTransformation &Trans, DenseMatrix &I) const; + using FiniteElement::Project; + virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; }; @@ -861,6 +869,7 @@ public: DenseMatrix &curl_shape) const; virtual void GetLocalInterpolation (ElementTransformation &Trans, DenseMatrix &I) const; + using FiniteElement::Project; virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; }; @@ -882,6 +891,7 @@ public: DenseMatrix &curl_shape) const; virtual void GetLocalInterpolation (ElementTransformation &Trans, DenseMatrix &I) const; + using FiniteElement::Project; virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; }; @@ -908,6 +918,8 @@ public: virtual void GetLocalInterpolation (ElementTransformation &Trans, DenseMatrix &I) const; + using FiniteElement::Project; + virtual void Project (VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; }; diff --git a/fem/fe_coll.cpp b/fem/fe_coll.cpp index 1ab39152f5..a4bd513035 100644 --- a/fem/fe_coll.cpp +++ b/fem/fe_coll.cpp @@ -11,6 +11,7 @@ #include "fem.hpp" #include +#include int FiniteElementCollection::HasFaceDofs (int GeomType) const { @@ -25,6 +26,53 @@ int FiniteElementCollection::HasFaceDofs (int GeomType) const return 0; } +FiniteElementCollection *FiniteElementCollection::New(const char *name) +{ + FiniteElementCollection *fec = NULL; + + if (!strcmp(name, "Linear")) + fec = new LinearFECollection; + else if (!strcmp(name, "Quadratic")) + fec = new QuadraticFECollection; + else if (!strcmp(name, "QuadraticPos")) + fec = new QuadraticPosFECollection; + else if (!strcmp(name, "Cubic")) + fec = new CubicFECollection; + else if (!strcmp(name, "Const3D")) + fec = new Const3DFECollection; + else if (!strcmp(name, "Const2D")) + fec = new Const2DFECollection; + else if (!strcmp(name, "LinearDiscont2D")) + fec = new LinearDiscont2DFECollection; + else if (!strcmp(name, "GaussLinearDiscont2D")) + fec = new GaussLinearDiscont2DFECollection; + else if (!strcmp(name, "P1OnQuad")) + fec = new P1OnQuadFECollection; + else if (!strcmp(name, "QuadraticDiscont2D")) + fec = new QuadraticDiscont2DFECollection; + else if (!strcmp(name, "QuadraticPosDiscont2D")) + fec = new QuadraticPosDiscont2DFECollection; + else if (!strcmp(name, "GaussQuadraticDiscont2D")) + fec = new GaussQuadraticDiscont2DFECollection; + else if (!strcmp(name, "CubicDiscont2D")) + fec = new CubicDiscont2DFECollection; + else if (!strcmp(name, "LinearDiscont3D")) + fec = new LinearDiscont3DFECollection; + else if (!strcmp(name, "QuadraticDiscont3D")) + fec = new QuadraticDiscont3DFECollection; + else if (!strcmp(name, "LinearNonConf3D")) + fec = new LinearNonConf3DFECollection; + else if (!strcmp(name, "CrouzeixRaviart")) + fec = new CrouzeixRaviartFECollection; + else if (!strcmp(name, "ND1_3D")) + fec = new ND1_3DFECollection; + else + mfem_error ("FiniteElementCollection::New : " + "Unknown FiniteElementCollection!"); + + return fec; +} + const FiniteElement * LinearFECollection::FiniteElementForGeometry(int GeomType) const { @@ -150,7 +198,7 @@ CubicFECollection::FiniteElementForGeometry(int GeomType) const case Geometry::TRIANGLE: return &TriangleFE; case Geometry::SQUARE: return &QuadrilateralFE; case Geometry::TETRAHEDRON: return &TetrahedronFE; - // case Geometry::CUBE: return &ParallelepipedFE; + case Geometry::CUBE: return &ParallelepipedFE; default: mfem_error ("CubicFECollection: unknown geometry type."); } @@ -166,7 +214,7 @@ int CubicFECollection::DofForGeometry(int GeomType) const case Geometry::TRIANGLE: return 1; case Geometry::SQUARE: return 4; case Geometry::TETRAHEDRON: return 0; - // case Geometry::CUBE: return 8; + case Geometry::CUBE: return 8; default: mfem_error ("CubicFECollection: unknown geometry type."); } @@ -175,13 +223,7 @@ int CubicFECollection::DofForGeometry(int GeomType) const int * CubicFECollection::DofOrderForOrientation(int GeomType, int Or) const { - if (GeomType == Geometry::TRIANGLE) - { - static int indexes[] = { 0 }; - - return indexes; - } - else if (GeomType == Geometry::SEGMENT) + if (GeomType == Geometry::SEGMENT) { static int ind_pos[] = { 0, 1 }; static int ind_neg[] = { 1, 0 }; @@ -190,6 +232,20 @@ int * CubicFECollection::DofOrderForOrientation(int GeomType, int Or) const return ind_neg; return ind_pos; } + else if (GeomType == Geometry::TRIANGLE) + { + static int indexes[] = { 0 }; + + return indexes; + } + else if (GeomType == Geometry::SQUARE) + { + static int sq_ind[8][4] = {{0, 1, 2, 3}, {0, 2, 1, 3}, + {1, 3, 0, 2}, {1, 0, 3, 2}, + {3, 2, 1, 0}, {3, 1, 2, 0}, + {2, 0, 3, 1}, {2, 3, 0, 1}}; + return sq_ind[Or]; + } return NULL; } @@ -875,7 +931,11 @@ int * RT0_3DFECollection::DofOrderForOrientation(int GeomType, int Or) static int ind_pos[] = { 0 }; static int ind_neg[] = { -1 }; - if (Or > 0) - return ind_pos; - return ind_neg; + if (GeomType == Geometry::TRIANGLE) + { + if (Or % 2 == 0) + return ind_pos; + return ind_neg; + } + return NULL; } diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index e735aebfd3..ecc6a478b9 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -27,6 +27,8 @@ public: int HasFaceDofs (int GeomType) const; virtual ~FiniteElementCollection() { }; + + static FiniteElementCollection *New(const char *name); }; class LinearFECollection : public FiniteElementCollection @@ -102,10 +104,10 @@ private: const Cubic2DFiniteElement TriangleFE; const BiCubic2DFiniteElement QuadrilateralFE; const Cubic3DFiniteElement TetrahedronFE; - // const LagrangeHexFiniteElement ParallelepipedFE; + const LagrangeHexFiniteElement ParallelepipedFE; public: - CubicFECollection() { }; + CubicFECollection() : ParallelepipedFE(3) { }; virtual const FiniteElement * FiniteElementForGeometry(int GeomType) const; diff --git a/fem/fem.hpp b/fem/fem.hpp index 1391f85d44..f15d0f9ad0 100644 --- a/fem/fem.hpp +++ b/fem/fem.hpp @@ -29,4 +29,12 @@ #include "linearform.hpp" #include "bilinearform.hpp" +#ifdef MFEM_USE_MPI +#include +#include "pfespace.hpp" +#include "plinearform.hpp" +#include "pbilinearform.hpp" +#include "pgridfunc.hpp" +#endif + #endif diff --git a/fem/fespace.cpp b/fem/fespace.cpp index e4c870a0a8..2307e232ae 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -806,7 +806,7 @@ void FiniteElementSpace::ConstructRefinementData (int k, int num_c_dofs, RefData.Append(data); } -void FiniteElementSpace::Save (ostream &out) +void FiniteElementSpace::Save (ostream &out) const { out << "FiniteElementSpace\n" << "FiniteElementCollection: " << fec -> Name() << '\n' diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 6276f1aa1d..1c2d0af3ee 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -148,10 +148,10 @@ public: int GetBdrAttribute(int i) { return mesh -> GetBdrAttribute(i); }; /// Returns indexes of degrees of freedom in array dofs for i'th element. - void GetElementDofs (int i, Array &dofs) const; + virtual void GetElementDofs (int i, Array &dofs) const; /// Returns indexes of degrees of freedom for i'th boundary element. - void GetBdrElementDofs (int i, Array &dofs) const; + virtual void GetBdrElementDofs (int i, Array &dofs) const; /** Returns the indexes of the degrees of freedom for i'th face including the dofs for the edges and the vertices of the face. */ @@ -204,22 +204,20 @@ public: /// Returns pointer to the FiniteElement for the i'th boundary element. const FiniteElement * GetBE (int i) const; - /** Return the restriction matrix from this FE space to the - coarse FE space 'cfes'. Both FE spaces must use the same FE - collection and be defined on the same Mesh which must be in - TWO_LEVEL_* state. When vdim > 1, 'one_vdim' specifies - whether the restriction matrix built should be the scalar - restriction (one_vdim=1) or the full vector restriction - (one_vdim=0); if one_vdim=-1 then the behavior depends on - the ordering of this FE space: if ordering=byNodes then the - scalar restriction matrix is built and if ordering=byVDim -- - the full vector restriction matrix. */ + /** Return the restriction matrix from this FE space to the coarse FE space + 'cfes'. Both FE spaces must use the same FE collection and be defined on + the same Mesh which must be in TWO_LEVEL_* state. When vdim > 1, + 'one_vdim' specifies whether the restriction matrix built should be the + scalar restriction (one_vdim=1) or the full vector restriction + (one_vdim=0); if one_vdim=-1 then the behavior depends on the ordering of + this FE space: if ordering=byNodes then the scalar restriction matrix is + built and if ordering=byVDim -- the full vector restriction matrix. */ SparseMatrix * GlobalRestrictionMatrix (FiniteElementSpace *cfes, int one_vdim = -1); /// Determine the boundary degrees of freedom - void GetEssentialVDofs (Array &bdr_attr_is_ess, - Array &ess_dofs); + virtual void GetEssentialVDofs(Array &bdr_attr_is_ess, + Array &ess_dofs); void EliminateEssentialBCFromGRM (FiniteElementSpace *cfes, Array &bdr_attr_is_ess, @@ -243,13 +241,13 @@ public: is defined on the same mesh. */ SparseMatrix * H2L_GlobalRestrictionMatrix (FiniteElementSpace *lfes); - void Update(); + virtual void Update(); /// Return a copy of the current FE space and update - FiniteElementSpace *SaveUpdate(); + virtual FiniteElementSpace *SaveUpdate(); - void Save (ostream &out); + void Save (ostream &out) const; - ~FiniteElementSpace(); + virtual ~FiniteElementSpace(); }; #endif diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index acf9354543..9680551aa1 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -13,72 +13,33 @@ #include "fem.hpp" #include -#include -GridFunction::GridFunction (Mesh *m, istream &input) +GridFunction::GridFunction(Mesh *m, istream &input) : Vector() { const int bufflen = 256; char buff[bufflen]; int vdim; - input.getline (buff, bufflen); // 'FiniteElementSpace' + input.getline(buff, bufflen); // 'FiniteElementSpace' if (strcmp(buff, "FiniteElementSpace")) - mfem_error ("GridFunction::GridFunction ():" - " input stream is not a GridFunction!"); - input.getline (buff, bufflen, ' '); // 'FiniteElementCollection:' + mfem_error("GridFunction::GridFunction():" + " input stream is not a GridFunction!"); + input.getline(buff, bufflen, ' '); // 'FiniteElementCollection:' input >> ws; - input.getline (buff, bufflen); - if (!strcmp(buff, "Linear")) - fec = new LinearFECollection; - else if (!strcmp(buff, "Quadratic")) - fec = new QuadraticFECollection; - else if (!strcmp(buff, "QuadraticPos")) - fec = new QuadraticPosFECollection; - else if (!strcmp(buff, "Cubic")) - fec = new CubicFECollection; - else if (!strcmp(buff, "Const3D")) - fec = new Const3DFECollection; - else if (!strcmp(buff, "Const2D")) - fec = new Const2DFECollection; - else if (!strcmp(buff, "LinearDiscont2D")) - fec = new LinearDiscont2DFECollection; - else if (!strcmp(buff, "GaussLinearDiscont2D")) - fec = new GaussLinearDiscont2DFECollection; - else if (!strcmp(buff, "P1OnQuad")) - fec = new P1OnQuadFECollection; - else if (!strcmp(buff, "QuadraticDiscont2D")) - fec = new QuadraticDiscont2DFECollection; - else if (!strcmp(buff, "QuadraticPosDiscont2D")) - fec = new QuadraticPosDiscont2DFECollection; - else if (!strcmp(buff, "GaussQuadraticDiscont2D")) - fec = new GaussQuadraticDiscont2DFECollection; - else if (!strcmp(buff, "CubicDiscont2D")) - fec = new CubicDiscont2DFECollection; - else if (!strcmp(buff, "LinearDiscont3D")) - fec = new LinearDiscont3DFECollection; - else if (!strcmp(buff, "QuadraticDiscont3D")) - fec = new QuadraticDiscont3DFECollection; - else if (!strcmp(buff, "LinearNonConf3D")) - fec = new LinearNonConf3DFECollection; - else if (!strcmp(buff, "CrouzeixRaviart")) - fec = new CrouzeixRaviartFECollection; - else if (!strcmp(buff, "ND1_3D")) - fec = new ND1_3DFECollection; - else - mfem_error ("GridFunction::GridFunction (): " - "Unknown FiniteElementCollection!"); - input.getline (buff, bufflen, ' '); // 'VDim:' + input.getline(buff, bufflen); + fec = FiniteElementCollection::New(buff); + input.getline(buff, bufflen, ' '); // 'VDim:' input >> vdim; - input.getline (buff, bufflen, ' '); // 'Ordering:' + input.getline(buff, bufflen, ' '); // 'Ordering:' int ordering; input >> ordering; - input.getline (buff, bufflen); // read the empty line - fes = new FiniteElementSpace (m, fec, vdim, ordering); - Vector::Load (input, fes -> GetVSize()); + input.getline(buff, bufflen); // read the empty line + fes = new FiniteElementSpace(m, fec, vdim, ordering); + Vector::Load(input, fes->GetVSize()); } -GridFunction::~GridFunction () +GridFunction::~GridFunction() { if (fec) { @@ -114,69 +75,69 @@ void GridFunction::Update(FiniteElementSpace *f, Vector &v, int v_offset) int GridFunction::VectorDim() const { - const FiniteElement *fe = fes -> GetFE(0); + const FiniteElement *fe = fes->GetFE(0); - if (fe -> GetRangeType() == FiniteElement::SCALAR) - return fes -> GetVDim(); - return fe -> GetDim(); + if (fe->GetRangeType() == FiniteElement::SCALAR) + return fes->GetVDim(); + return fe->GetDim(); } -void GridFunction::GetNodalValues (int i, Array & nval, int vdim) const +void GridFunction::GetNodalValues(int i, Array &nval, int vdim) const { Array dofs; int k; - fes -> GetElementVDofs (i, dofs); - const FiniteElement * FElem = fes -> GetFE (i); - const IntegrationRule * ElemVert = - Geometries.GetVertices (FElem -> GetGeomType ()); - int dof = FElem -> GetDof (); - Vector DofVal (dof); - int n = ElemVert -> GetNPoints (); - nval.SetSize (n); + fes->GetElementVDofs(i, dofs); + const FiniteElement *FElem = fes->GetFE(i); + const IntegrationRule *ElemVert = + Geometries.GetVertices(FElem->GetGeomType()); + int dof = FElem->GetDof(); + Vector DofVal(dof); + int n = ElemVert->GetNPoints(); + nval.SetSize(n); vdim--; for (k = 0; k < n; k++) { - FElem -> CalcShape (ElemVert -> IntPoint (k), DofVal); + FElem->CalcShape(ElemVert->IntPoint(k), DofVal); nval[k] = 0.0; for (int j = 0; j < dof; j++) if (dofs[dof*vdim+j] >= 0) - nval[k] += DofVal (j) * data[dofs[dof*vdim+j]]; + nval[k] += DofVal(j) * data[dofs[dof*vdim+j]]; else - nval[k] -= DofVal (j) * data[-1-dofs[dof*vdim+j]]; + nval[k] -= DofVal(j) * data[-1-dofs[dof*vdim+j]]; } } -double GridFunction::GetValue (int i, const IntegrationPoint &ip, int vdim) +double GridFunction::GetValue(int i, const IntegrationPoint &ip, int vdim) const { Array dofs; - fes -> GetElementDofs (i, dofs); - fes -> DofsToVDofs (vdim-1, dofs); - Vector DofVal (dofs.Size()), LocVec; - fes -> GetFE (i) -> CalcShape (ip, DofVal); - GetSubVector (dofs, LocVec); + fes->GetElementDofs(i, dofs); + fes->DofsToVDofs(vdim-1, dofs); + Vector DofVal(dofs.Size()), LocVec; + fes->GetFE(i)->CalcShape(ip, DofVal); + GetSubVector(dofs, LocVec); return (DofVal * LocVec); } -void GridFunction::GetVectorValue (int i, const IntegrationPoint &ip, - Vector &val) const +void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip, + Vector &val) const { - const FiniteElement *FElem = fes -> GetFE (i); - int dof = FElem -> GetDof(); + const FiniteElement *FElem = fes->GetFE(i); + int dof = FElem->GetDof(); Array vdofs; - fes -> GetElementVDofs (i, vdofs); + fes->GetElementVDofs(i, vdofs); Vector loc_data; - GetSubVector (vdofs, loc_data); - if (FElem -> GetRangeType() == FiniteElement::SCALAR) + GetSubVector(vdofs, loc_data); + if (FElem->GetRangeType() == FiniteElement::SCALAR) { - Vector shape (dof); - FElem -> CalcShape (ip, shape); - int vdim = fes -> GetVDim(); - val.SetSize (vdim); + Vector shape(dof); + FElem->CalcShape(ip, shape); + int vdim = fes->GetVDim(); + val.SetSize(vdim); for (int k = 0; k < vdim; k++) { val(k) = shape * ((const double *)loc_data + dof * k); @@ -184,61 +145,61 @@ void GridFunction::GetVectorValue (int i, const IntegrationPoint &ip, } else { - int dim = FElem -> GetDim(); - DenseMatrix vshape (dof, dim); - ElementTransformation *Tr = fes -> GetElementTransformation (i); - Tr -> SetIntPoint (&ip); - FElem -> CalcVShape (*Tr, vshape); - val.SetSize (dim); - vshape.MultTranspose (loc_data, val); + int dim = FElem->GetDim(); + DenseMatrix vshape(dof, dim); + ElementTransformation *Tr = fes->GetElementTransformation(i); + Tr->SetIntPoint(&ip); + FElem->CalcVShape(*Tr, vshape); + val.SetSize(dim); + vshape.MultTranspose(loc_data, val); } } -void GridFunction::GetValues (int i, const IntegrationRule &ir, Vector &vals, - DenseMatrix &tr, int vdim) +void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals, + DenseMatrix &tr, int vdim) const { Array dofs; int k, n; - n = ir.GetNPoints (); - vals.SetSize (n); - fes -> GetElementVDofs (i, dofs); - const FiniteElement * FElem = fes -> GetFE (i); + n = ir.GetNPoints(); + vals.SetSize(n); + fes->GetElementVDofs(i, dofs); + const FiniteElement *FElem = fes->GetFE(i); ElementTransformation *ET; - ET = fes -> GetElementTransformation (i); - ET -> Transform (ir, tr); - int dof = FElem -> GetDof (); - Vector DofVal (dof); + ET = fes->GetElementTransformation(i); + ET->Transform(ir, tr); + int dof = FElem->GetDof(); + Vector DofVal(dof); vdim--; for (k = 0; k < n; k++) { - FElem -> CalcShape (ir.IntPoint (k), DofVal); + FElem->CalcShape(ir.IntPoint(k), DofVal); vals(k) = 0.0; for (int j = 0; j < dof; j++) if (dofs[dof*vdim+j] >= 0) - vals(k) += DofVal (j) * data[dofs[dof*vdim+j]]; + vals(k) += DofVal(j) * data[dofs[dof*vdim+j]]; else - vals(k) -= DofVal (j) * data[-1-dofs[dof*vdim+j]]; + vals(k) -= DofVal(j) * data[-1-dofs[dof*vdim+j]]; } } -int GridFunction::GetFaceValues (int i, int side, const IntegrationRule &ir, - Vector &vals, DenseMatrix &tr, - int vdim) const +int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir, + Vector &vals, DenseMatrix &tr, + int vdim) const { int n, di; FaceElementTransformations *Transf; n = ir.GetNPoints(); - IntegrationRule eir (n); // --- - Transf = fes -> GetMesh() -> GetFaceElementTransformations (i); - if (Transf -> Elem2No < 0) + IntegrationRule eir(n); // --- + Transf = fes->GetMesh()->GetFaceElementTransformations(i); + if (Transf->Elem2No < 0) di = 0; else - if ( fes -> GetAttribute (Transf -> Elem1No) <= - fes -> GetAttribute (Transf -> Elem2No) ) + if ( fes->GetAttribute(Transf->Elem1No) <= + fes->GetAttribute(Transf->Elem2No) ) di = 0; else di = 1; @@ -246,56 +207,64 @@ int GridFunction::GetFaceValues (int i, int side, const IntegrationRule &ir, side = di; if (side == 0) { - Transf -> Loc1.Transform (ir, eir); - GetValues (Transf -> Elem1No, eir, vals, tr, vdim); + Transf->Loc1.Transform(ir, eir); + GetValues(Transf->Elem1No, eir, vals, tr, vdim); } else { - Transf -> Loc2.Transform (ir, eir); - GetValues (Transf -> Elem2No, eir, vals, tr, vdim); + Transf->Loc2.Transform(ir, eir); + GetValues(Transf->Elem2No, eir, vals, tr, vdim); } return di; } -void GridFunction::GetVectorValues (int i, const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix &tr) +void GridFunction::GetVectorValues(int i, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix &tr) const { - Array dofs; - - int k, n, vdim; - - n = ir.GetNPoints (); - vdim = fes->GetVDim(); - vals.SetSize (vdim, n); - fes -> GetElementVDofs (i, dofs); - const FiniteElement * FElem = fes -> GetFE (i); - ElementTransformation *ET; - ET = fes -> GetElementTransformation (i); - ET -> Transform (ir, tr); - int dof = FElem -> GetDof (); - Vector DofVal (dof); - for (k = 0; k < n; k++) + const FiniteElement *FElem = fes->GetFE(i); + int dof = FElem->GetDof(); + Array vdofs; + fes->GetElementVDofs(i, vdofs); + Vector loc_data; + GetSubVector(vdofs, loc_data); + int nip = ir.GetNPoints(); + ElementTransformation *Tr = fes->GetElementTransformation(i); + Tr->Transform(ir, tr); + if (FElem->GetRangeType() == FiniteElement::SCALAR) { - FElem -> CalcShape (ir.IntPoint (k), DofVal); - for (int d = 0; d < vdim; d++) + Vector shape(dof); + int vdim = fes->GetVDim(); + vals.SetSize(vdim, nip); + for (int j = 0; j < nip; j++) { - double v = 0.0; - for (int j = 0; j < dof; j++) + const IntegrationPoint &ip = ir.IntPoint(j); + FElem->CalcShape(ip, shape); + for (int k = 0; k < vdim; k++) { - int ind = dofs[dof*d+j]; - if (ind >= 0) - v += DofVal (j) * data[ind]; - else - v -= DofVal (j) * data[-1-ind]; + vals(k,j) = shape * ((const double *)loc_data + dof * k); } - vals(d,k) = v; + } + } + else + { + int dim = FElem->GetDim(); + DenseMatrix vshape(dof, dim); + vals.SetSize(dim, nip); + Vector val_j; + for (int j = 0; j < nip; j++) + { + const IntegrationPoint &ip = ir.IntPoint(j); + Tr->SetIntPoint(&ip); + FElem->CalcVShape(*Tr, vshape); + vals.GetColumnReference(j, val_j); + vshape.MultTranspose(loc_data, val_j); } } } -int GridFunction::GetFaceVectorValues ( +int GridFunction::GetFaceVectorValues( int i, int side, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const { @@ -303,13 +272,13 @@ int GridFunction::GetFaceVectorValues ( FaceElementTransformations *Transf; n = ir.GetNPoints(); - IntegrationRule eir (n); // --- - Transf = fes -> GetMesh() -> GetFaceElementTransformations (i); - if (Transf -> Elem2No < 0) + IntegrationRule eir(n); // --- + Transf = fes->GetMesh()->GetFaceElementTransformations(i); + if (Transf->Elem2No < 0) di = 0; else - if ( fes -> GetAttribute (Transf -> Elem1No) <= - fes -> GetAttribute (Transf -> Elem2No) ) + if ( fes->GetAttribute(Transf->Elem1No) <= + fes->GetAttribute(Transf->Elem2No) ) di = 0; else di = 1; @@ -317,19 +286,19 @@ int GridFunction::GetFaceVectorValues ( side = di; if (side == 0) { - Transf -> Loc1.Transform (ir, eir); - GetVectorValues (Transf -> Elem1No, eir, vals, tr); + Transf->Loc1.Transform(ir, eir); + GetVectorValues(Transf->Elem1No, eir, vals, tr); } else { - Transf -> Loc2.Transform (ir, eir); - GetVectorValues (Transf -> Elem2No, eir, vals, tr); + Transf->Loc2.Transform(ir, eir); + GetVectorValues(Transf->Elem2No, eir, vals, tr); } return di; } -void GridFunction::GetValuesFrom (GridFunction &orig_func) +void GridFunction::GetValuesFrom(GridFunction &orig_func) { // Without averaging ... @@ -338,35 +307,35 @@ void GridFunction::GetValuesFrom (GridFunction &orig_func) Vector shape, loc_values, orig_loc_values; int i, j, d, ne, dof, odof, vdim; - ne = fes -> GetNE(); - vdim = fes -> GetVDim(); + ne = fes->GetNE(); + vdim = fes->GetVDim(); for (i = 0; i < ne; i++) { - fes -> GetElementVDofs (i, vdofs); - orig_fes -> GetElementVDofs (i, orig_vdofs); + fes->GetElementVDofs(i, vdofs); + orig_fes->GetElementVDofs(i, orig_vdofs); orig_func.GetSubVector(orig_vdofs, orig_loc_values); - const FiniteElement *fe = fes -> GetFE (i); - const FiniteElement *orig_fe = orig_fes -> GetFE (i); - dof = fe -> GetDof(); - odof = orig_fe -> GetDof(); - loc_values.SetSize (dof * vdim); - shape.SetSize (odof); - const IntegrationRule &ir = fe -> GetNodes(); + const FiniteElement *fe = fes->GetFE(i); + const FiniteElement *orig_fe = orig_fes->GetFE(i); + dof = fe->GetDof(); + odof = orig_fe->GetDof(); + loc_values.SetSize(dof * vdim); + shape.SetSize(odof); + const IntegrationRule &ir = fe->GetNodes(); for (j = 0; j < dof; j++) { - const IntegrationPoint &ip = ir.IntPoint (j); - orig_fe -> CalcShape (ip, shape); + const IntegrationPoint &ip = ir.IntPoint(j); + orig_fe->CalcShape(ip, shape); for (d = 0; d < vdim; d++) { loc_values(d*dof+j) = shape * ((const double *)orig_loc_values + d * odof) ; } } - SetSubVector (vdofs, loc_values); + SetSubVector(vdofs, loc_values); } } -void GridFunction::GetBdrValuesFrom (GridFunction &orig_func) +void GridFunction::GetBdrValuesFrom(GridFunction &orig_func) { // Without averaging ... @@ -375,35 +344,35 @@ void GridFunction::GetBdrValuesFrom (GridFunction &orig_func) Vector shape, loc_values, orig_loc_values; int i, j, d, nbe, dof, odof, vdim; - nbe = fes -> GetNBE(); - vdim = fes -> GetVDim(); + nbe = fes->GetNBE(); + vdim = fes->GetVDim(); for (i = 0; i < nbe; i++) { - fes -> GetBdrElementVDofs (i, vdofs); - orig_fes -> GetBdrElementVDofs (i, orig_vdofs); + fes->GetBdrElementVDofs(i, vdofs); + orig_fes->GetBdrElementVDofs(i, orig_vdofs); orig_func.GetSubVector(orig_vdofs, orig_loc_values); - const FiniteElement *fe = fes -> GetBE (i); - const FiniteElement *orig_fe = orig_fes -> GetBE (i); - dof = fe -> GetDof(); - odof = orig_fe -> GetDof(); - loc_values.SetSize (dof * vdim); - shape.SetSize (odof); - const IntegrationRule &ir = fe -> GetNodes(); + const FiniteElement *fe = fes->GetBE(i); + const FiniteElement *orig_fe = orig_fes->GetBE(i); + dof = fe->GetDof(); + odof = orig_fe->GetDof(); + loc_values.SetSize(dof * vdim); + shape.SetSize(odof); + const IntegrationRule &ir = fe->GetNodes(); for (j = 0; j < dof; j++) { - const IntegrationPoint &ip = ir.IntPoint (j); - orig_fe -> CalcShape (ip, shape); + const IntegrationPoint &ip = ir.IntPoint(j); + orig_fe->CalcShape(ip, shape); for (d = 0; d < vdim; d++) { loc_values(d*dof+j) = shape * ((const double *)orig_loc_values + d * odof); } } - SetSubVector (vdofs, loc_values); + SetSubVector(vdofs, loc_values); } } -void GridFunction::GetVectorFieldValues ( +void GridFunction::GetVectorFieldValues( int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr, int comp) const { @@ -412,22 +381,22 @@ void GridFunction::GetVectorFieldValues ( int d, j, k, n, dim, dof, ind; - n = ir.GetNPoints (); - fes -> GetElementVDofs (i, vdofs); - const FiniteElement *fe = fes -> GetFE(i); - dof = fe -> GetDof (); - dim = fe -> GetDim(); + n = ir.GetNPoints(); + fes->GetElementVDofs(i, vdofs); + const FiniteElement *fe = fes->GetFE(i); + dof = fe->GetDof(); + dim = fe->GetDim(); int *dofs = &vdofs[comp*dof]; - transf = fes -> GetElementTransformation (i); - transf -> Transform (ir, tr); - vals.SetSize (n, dim); - DenseMatrix vshape (dof, dim); + transf = fes->GetElementTransformation(i); + transf->Transform(ir, tr); + vals.SetSize(n, dim); + DenseMatrix vshape(dof, dim); double a; for (k = 0; k < n; k++) { - const IntegrationPoint &ip = ir.IntPoint (k); - transf -> SetIntPoint (&ip); - fe -> CalcVShape (*transf, vshape); + const IntegrationPoint &ip = ir.IntPoint(k); + transf->SetIntPoint(&ip); + fe->CalcVShape(*transf, vshape); for (d = 0; d < dim; d++) { a = 0.0; @@ -447,8 +416,8 @@ void GridFunction::ReorderByNodes() return; int i, j, k; - int vdim = fes -> GetVDim(); - int ndofs = fes -> GetNDofs(); + int vdim = fes->GetVDim(); + int ndofs = fes->GetNDofs(); double *temp = new double[size]; k = 0; @@ -462,26 +431,25 @@ void GridFunction::ReorderByNodes() delete [] temp; } -void GridFunction::GetVectorFieldNodalValues (Vector &val, int comp) const +void GridFunction::GetVectorFieldNodalValues(Vector &val, int comp) const { int i, k; - Array overlap (fes -> GetNV()); + Array overlap(fes->GetNV()); Array vertices; DenseMatrix vals, tr; - val.SetSize (overlap.Size()); - for (i = 0; i < overlap.Size(); i++) - overlap[i] = 0; + val.SetSize(overlap.Size()); + overlap = 0; val = 0.0; comp--; - for (i = 0; i < fes -> GetNE(); i++) + for (i = 0; i < fes->GetNE(); i++) { const IntegrationRule *ir = - Geometries.GetVertices (fes -> GetFE(i) -> GetGeomType ()); - fes -> GetElementVertices (i, vertices); - GetVectorFieldValues (i, *ir, vals, tr); - for (k = 0; k < ir -> GetNPoints(); k++) + Geometries.GetVertices(fes->GetFE(i)->GetGeomType()); + fes->GetElementVertices(i, vertices); + GetVectorFieldValues(i, *ir, vals, tr); + for (k = 0; k < ir->GetNPoints(); k++) { val(vertices[k]) += vals(k, comp); overlap[vertices[k]]++; @@ -492,27 +460,26 @@ void GridFunction::GetVectorFieldNodalValues (Vector &val, int comp) const val(i) /= overlap[i]; } -void GridFunction::ProjectVectorFieldOn (GridFunction &vec_field, int comp) +void GridFunction::ProjectVectorFieldOn(GridFunction &vec_field, int comp) { - FiniteElementSpace * new_fes = vec_field.FESpace(); + FiniteElementSpace *new_fes = vec_field.FESpace(); int d, i, k, ind, dof; - Array overlap (new_fes -> GetVSize()); + Array overlap(new_fes->GetVSize()); Array new_vdofs; DenseMatrix vals, tr; - for (i = 0; i < overlap.Size(); i++) - overlap[i] = 0; + overlap = 0; vec_field = 0.0; - for (i = 0; i < new_fes -> GetNE(); i++) + for (i = 0; i < new_fes->GetNE(); i++) { - const FiniteElement *fe = new_fes -> GetFE(i); - const IntegrationRule &ir = fe -> GetNodes(); - GetVectorFieldValues (i, ir, vals, tr, comp); - new_fes -> GetElementVDofs (i, new_vdofs); - dof = fe -> GetDof(); - for (d = 0; d < fe -> GetDim(); d++) + const FiniteElement *fe = new_fes->GetFE(i); + const IntegrationRule &ir = fe->GetNodes(); + GetVectorFieldValues(i, ir, vals, tr, comp); + new_fes->GetElementVDofs(i, new_vdofs); + dof = fe->GetDof(); + for (d = 0; d < fe->GetDim(); d++) for (k = 0; k < dof; k++) { if ( (ind=new_vdofs[dof*d+k]) < 0 ) @@ -530,7 +497,7 @@ void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der) { FiniteElementSpace * der_fes = der.FESpace(); ElementTransformation * transf; - Array overlap (der_fes -> GetVSize()); + Array overlap(der_fes->GetVSize()); Array der_dofs, vdofs; DenseMatrix dshape, inv_jac; Vector pt_grad, loc_func; @@ -542,33 +509,33 @@ void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der) der = 0.0; comp--; - for (i = 0; i < der_fes -> GetNE(); i++) + for (i = 0; i < der_fes->GetNE(); i++) { - const FiniteElement *der_fe = der_fes -> GetFE(i); - const FiniteElement *fe = fes -> GetFE(i); - const IntegrationRule &ir = der_fe -> GetNodes(); - der_fes -> GetElementDofs (i, der_dofs); - fes -> GetElementVDofs (i, vdofs); - dim = fe -> GetDim(); - dof = fe -> GetDof(); - der_dof = der_fe -> GetDof(); - dshape.SetSize (dof, dim); - inv_jac.SetSize (dim); - pt_grad.SetSize (dim); - loc_func.SetSize (dof); - transf = fes -> GetElementTransformation (i); + const FiniteElement *der_fe = der_fes->GetFE(i); + const FiniteElement *fe = fes->GetFE(i); + const IntegrationRule &ir = der_fe->GetNodes(); + der_fes->GetElementDofs(i, der_dofs); + fes->GetElementVDofs(i, vdofs); + dim = fe->GetDim(); + dof = fe->GetDof(); + der_dof = der_fe->GetDof(); + dshape.SetSize(dof, dim); + inv_jac.SetSize(dim); + pt_grad.SetSize(dim); + loc_func.SetSize(dof); + transf = fes->GetElementTransformation(i); for (j = 0; j < dof; j++) loc_func(j) = ( (ind=vdofs[comp*dof+j]) >= 0 ) ? (data[ind]) : (-data[-1-ind]); for (k = 0; k < der_dof; k++) { - const IntegrationPoint &ip = ir.IntPoint (k); - fe -> CalcDShape (ip, dshape); - dshape.MultTranspose (loc_func, pt_grad); - transf -> SetIntPoint (&ip); - CalcInverse (transf -> Jacobian(), inv_jac); + const IntegrationPoint &ip = ir.IntPoint(k); + fe->CalcDShape(ip, dshape); + dshape.MultTranspose(loc_func, pt_grad); + transf->SetIntPoint(&ip); + CalcInverse(transf->Jacobian(), inv_jac); a = 0.0; - for (j = 0; j < dim; j++) + for (j = 0; j < dim; j++) a += inv_jac(j, der_comp) * pt_grad(j); der(der_dofs[k]) += a; overlap[der_dofs[k]]++; @@ -584,15 +551,15 @@ void GridFunction::GetVectorGradientHat( ElementTransformation &T, DenseMatrix &gh) { int elNo = T.ElementNo; - const FiniteElement *FElem = fes -> GetFE (elNo); - int dim = FElem -> GetDim(), dof = FElem -> GetDof(); + const FiniteElement *FElem = fes->GetFE(elNo); + int dim = FElem->GetDim(), dof = FElem->GetDof(); Array vdofs; - fes -> GetElementVDofs (elNo, vdofs); + fes->GetElementVDofs(elNo, vdofs); Vector loc_data; - GetSubVector (vdofs, loc_data); + GetSubVector(vdofs, loc_data); // assuming scalar FE - DenseMatrix dshape (dof, dim); - FElem -> CalcDShape (T.GetIntPoint(), dshape); + DenseMatrix dshape(dof, dim); + FElem->CalcDShape(T.GetIntPoint(), dshape); gh.SetSize(dim); for (int i = 0; i < dim; i++) for (int j = 0; j < dim; j++) @@ -659,53 +626,51 @@ void GridFunction::GetVectorGradient( Mult(grad_hat, Jinv, grad); } -void GridFunction::GetElementAverages (GridFunction &avgs) +void GridFunction::GetElementAverages(GridFunction &avgs) { MassIntegrator Mi; DenseMatrix loc_mass; Array te_dofs, tr_dofs; Vector loc_avgs, loc_this; - Vector int_psi (avgs.Size()); + Vector int_psi(avgs.Size()); avgs = 0.0; int_psi = 0.0; - for (int i = 0; i < fes -> GetNE(); i++) + for (int i = 0; i < fes->GetNE(); i++) { - Mi.AssembleElementMatrix2 (*fes -> GetFE (i), - *avgs.FESpace() -> GetFE (i), - *fes -> GetElementTransformation (i), - loc_mass); - fes -> GetElementDofs (i, tr_dofs); - avgs.FESpace() -> GetElementDofs (i, te_dofs); - GetSubVector (tr_dofs, loc_this); - loc_avgs.SetSize (te_dofs.Size()); - loc_mass.Mult (loc_this, loc_avgs); - avgs.AddElementVector (te_dofs, loc_avgs); + Mi.AssembleElementMatrix2(*fes->GetFE(i), *avgs.FESpace()->GetFE(i), + *fes->GetElementTransformation(i), loc_mass); + fes->GetElementDofs(i, tr_dofs); + avgs.FESpace()->GetElementDofs(i, te_dofs); + GetSubVector(tr_dofs, loc_this); + loc_avgs.SetSize(te_dofs.Size()); + loc_mass.Mult(loc_this, loc_avgs); + avgs.AddElementVector(te_dofs, loc_avgs); loc_this = 1.0; // assume the local basis for 'this' sums to 1 - loc_mass.Mult (loc_this, loc_avgs); - int_psi.AddElementVector (te_dofs, loc_avgs); + loc_mass.Mult(loc_this, loc_avgs); + int_psi.AddElementVector(te_dofs, loc_avgs); } for (int i = 0; i < avgs.Size(); i++) avgs(i) /= int_psi(i); } -void GridFunction::GetNodalValues (Vector & nval, int vdim) const +void GridFunction::GetNodalValues(Vector &nval, int vdim) const { int i, j; Array vertices; Array values; Array overlap(fes->GetNV()); - nval.SetSize (fes -> GetNV()); + nval.SetSize(fes->GetNV()); for (i = 0; i < overlap.Size(); i++) { nval(i) = 0.0; overlap[i] = 0; } - for (i = 0; i < fes -> GetNE(); i++) + for (i = 0; i < fes->GetNE(); i++) { - fes -> GetElementVertices (i, vertices); - GetNodalValues (i, values, vdim); + fes->GetElementVertices(i, vertices); + GetNodalValues(i, values, vdim); for (j = 0; j < vertices.Size(); j++) { nval(vertices[j]) += values[j]; @@ -716,7 +681,7 @@ void GridFunction::GetNodalValues (Vector & nval, int vdim) const nval(i) /= overlap[i]; } -void GridFunction::ProjectCoefficient (Coefficient &coeff) +void GridFunction::ProjectCoefficient(Coefficient &coeff) { int i; Array vdofs; @@ -726,13 +691,12 @@ void GridFunction::ProjectCoefficient (Coefficient &coeff) if (delta_c == NULL) { - for (i = 0; i < fes -> GetNE(); i++) + for (i = 0; i < fes->GetNE(); i++) { - fes -> GetElementVDofs (i, vdofs); - vals.SetSize (vdofs.Size()); - fes -> GetFE (i) -> Project ( - coeff, *fes -> GetElementTransformation(i), vals); - SetSubVector (vdofs, vals); + fes->GetElementVDofs(i, vdofs); + vals.SetSize(vdofs.Size()); + fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals); + SetSubVector(vdofs, vals); } } else @@ -772,8 +736,7 @@ void GridFunction::ProjectCoefficient (Coefficient &coeff) if (vertices[j] == v_idx) { const FiniteElement *fe = fes->GetFE(i); - Mi.AssembleElementMatrix(*fe, - *fes->GetElementTransformation(i), + Mi.AssembleElementMatrix(*fe, *fes->GetElementTransformation(i), loc_mass); vals.SetSize(fe->GetDof()); fe->ProjectDelta(j, vals); @@ -791,7 +754,7 @@ void GridFunction::ProjectCoefficient (Coefficient &coeff) } } -void GridFunction::ProjectCoefficient ( +void GridFunction::ProjectCoefficient( Coefficient &coeff, Array &dofs, int vd) { int el = -1; @@ -800,38 +763,37 @@ void GridFunction::ProjectCoefficient ( for (int i = 0; i < dofs.Size(); i++) { - int dof = dofs[i], j = fes -> GetElementForDof (dof); + int dof = dofs[i], j = fes->GetElementForDof(dof); if (el != j) { el = j; - T = fes -> GetElementTransformation (el); - fe = fes -> GetFE (el); + T = fes->GetElementTransformation(el); + fe = fes->GetFE(el); } - int vdof = fes -> DofToVDof (dof, vd); - int ld = fes -> GetLocalDofForDof (dof); - const IntegrationPoint &ip = fe -> GetNodes().IntPoint(ld); + int vdof = fes->DofToVDof(dof, vd); + int ld = fes->GetLocalDofForDof(dof); + const IntegrationPoint &ip = fe->GetNodes().IntPoint(ld); T->SetIntPoint(&ip); - (*this)(vdof) = coeff.Eval (*T, ip); + (*this)(vdof) = coeff.Eval(*T, ip); } } -void GridFunction::ProjectCoefficient (VectorCoefficient &vcoeff) +void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff) { int i; Array vdofs; Vector vals; - for (i = 0; i < fes -> GetNE(); i++) + for (i = 0; i < fes->GetNE(); i++) { - fes -> GetElementVDofs (i, vdofs); - vals.SetSize (vdofs.Size()); - fes -> GetFE(i) -> Project ( - vcoeff, *fes->GetElementTransformation(i), vals); - SetSubVector (vdofs, vals); + fes->GetElementVDofs(i, vdofs); + vals.SetSize(vdofs.Size()); + fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals); + SetSubVector(vdofs, vals); } } -void GridFunction::ProjectCoefficient (Coefficient *coeff[]) +void GridFunction::ProjectCoefficient(Coefficient *coeff[]) { int i, j, fdof, d, ind; double val; @@ -861,8 +823,8 @@ void GridFunction::ProjectCoefficient (Coefficient *coeff[]) } } -void GridFunction::ProjectBdrCoefficient ( - Coefficient *coeff[], Array &attr ) +void GridFunction::ProjectBdrCoefficient( + Coefficient *coeff[], Array &attr) { int i, j, fdof, d, ind; double val; @@ -895,7 +857,7 @@ void GridFunction::ProjectBdrCoefficient ( } } -double GridFunction::ComputeL2Error ( +double GridFunction::ComputeL2Error( Coefficient *exsol[], const IntegrationRule *irs[]) const { double error = 0.0, a; @@ -917,7 +879,7 @@ double GridFunction::ComputeL2Error ( ir = irs[fe->GetGeomType()]; else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); - fes->GetElementVDofs (i, vdofs); + fes->GetElementVDofs(i, vdofs); for (j = 0; j < ir->GetNPoints(); j++) { const IntegrationPoint &ip = ir->IntPoint(j); @@ -930,7 +892,7 @@ double GridFunction::ComputeL2Error ( a += (*this)(vdofs[fdof*d+k]) * shape(k); else a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k); - transf->SetIntPoint (&ip); + transf->SetIntPoint(&ip); a -= exsol[d]->Eval(*transf, ip); error += ip.weight * transf->Weight() * a * a; } @@ -942,48 +904,37 @@ double GridFunction::ComputeL2Error ( return sqrt(error); } -double GridFunction::ComputeL2Error ( +double GridFunction::ComputeL2Error( VectorCoefficient &exsol, const IntegrationRule *irs[], Array *elems) const { - double error = 0.0, a; + double error = 0.0; const FiniteElement *fe; - ElementTransformation *transf; - Vector shape, sol (exsol.GetVDim()); - Array vdofs; - int fdof, d, i, intorder, j, k; + ElementTransformation *T; + DenseMatrix vals, exact_vals, tr; + Vector loc_errs; - for (i = 0; i < fes->GetNE(); i++) + for (int i = 0; i < fes->GetNE(); i++) { if (elems != NULL && (*elems)[i] == 0) continue; fe = fes->GetFE(i); - fdof = fe->GetDof(); - transf = fes->GetElementTransformation(i); - shape.SetSize(fdof); - intorder = fe->GetOrder()+2; // <---------- + int intorder = fe->GetOrder()+2; // <---------- const IntegrationRule *ir; if (irs) ir = irs[fe->GetGeomType()]; else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); - fes->GetElementVDofs (i, vdofs); - for (j = 0; j < ir->GetNPoints(); j++) + GetVectorValues(i, *ir, vals, tr); + T = fes->GetElementTransformation(i); + exsol.Eval(exact_vals, *T, *ir); + vals -= exact_vals; + loc_errs.SetSize(vals.Width()); + vals.Norm2(loc_errs); + for (int j = 0; j < ir->GetNPoints(); j++) { const IntegrationPoint &ip = ir->IntPoint(j); - fe->CalcShape(ip, shape); - transf->SetIntPoint(&ip); - exsol.Eval (sol, *transf, ip); - for (d = 0; d < fes->GetVDim(); d++) - { - a = 0; - for (k = 0; k < fdof; k++) - if (vdofs[fdof*d+k] >= 0) - a += (*this)(vdofs[fdof*d+k]) * shape(k); - else - a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k); - a -= sol(d); - error += ip.weight * transf->Weight() * a * a; - } + T->SetIntPoint(&ip); + error += ip.weight * T->Weight() * (loc_errs(j) * loc_errs(j)); } } @@ -992,7 +943,7 @@ double GridFunction::ComputeL2Error ( return sqrt(error); } -double GridFunction::ComputeH1Error ( +double GridFunction::ComputeH1Error( Coefficient *exsol, VectorCoefficient *exgrad, Coefficient *ell_coeff, double Nu, int norm_type) const { @@ -1008,25 +959,24 @@ double GridFunction::ComputeH1Error ( IntegrationPoint eip; double error = 0.0; - mesh = fes -> GetMesh(); - dim = mesh -> Dimension(); - e_grad.SetSize (dim); - a_grad.SetSize (dim); - Jinv.SetSize (dim); + mesh = fes->GetMesh(); + dim = mesh->Dimension(); + e_grad.SetSize(dim); + a_grad.SetSize(dim); + Jinv.SetSize(dim); if (norm_type & 1) - for (i = 0; i < mesh -> GetNE(); i++) + for (i = 0; i < mesh->GetNE(); i++) { - fe = fes -> GetFE (i); - fdof = fe -> GetDof(); - transf = mesh -> GetElementTransformation (i); - el_dofs.SetSize (fdof); - dshape.SetSize (fdof, dim); - dshapet.SetSize (fdof, dim); - intorder = 2 * fe -> GetOrder(); // <---------- - const IntegrationRule &ir = IntRules.Get (fe -> GetGeomType(), - intorder); - fes -> GetElementVDofs (i, vdofs); + fe = fes->GetFE(i); + fdof = fe->GetDof(); + transf = mesh->GetElementTransformation(i); + el_dofs.SetSize(fdof); + dshape.SetSize(fdof, dim); + dshapet.SetSize(fdof, dim); + intorder = 2 * fe->GetOrder(); // <---------- + const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder); + fes->GetElementVDofs(i, vdofs); for (k = 0; k < fdof; k++) if (vdofs[k] >= 0) el_dofs(k) = (*this)(vdofs[k]); @@ -1034,42 +984,42 @@ double GridFunction::ComputeH1Error ( el_dofs(k) = - (*this)(-1-vdofs[k]); for (j = 0; j < ir.GetNPoints(); j++) { - const IntegrationPoint &ip = ir.IntPoint (j); - fe -> CalcDShape (ip, dshape); - transf -> SetIntPoint (&ip); - exgrad -> Eval (e_grad, *transf, ip); - CalcInverse (transf -> Jacobian(), Jinv); - Mult (dshape, Jinv, dshapet); - dshapet.MultTranspose (el_dofs, a_grad); + const IntegrationPoint &ip = ir.IntPoint(j); + fe->CalcDShape(ip, dshape); + transf->SetIntPoint(&ip); + exgrad->Eval(e_grad, *transf, ip); + CalcInverse(transf->Jacobian(), Jinv); + Mult(dshape, Jinv, dshapet); + dshapet.MultTranspose(el_dofs, a_grad); e_grad -= a_grad; - error += (ip.weight * transf -> Weight() * - ell_coeff -> Eval (*transf, ip) * + error += (ip.weight * transf->Weight() * + ell_coeff->Eval(*transf, ip) * (e_grad * e_grad)); } } if (norm_type & 2) - for (i = 0; i < mesh -> GetNFaces(); i++) + for (i = 0; i < mesh->GetNFaces(); i++) { - face_elem_transf = mesh -> GetFaceElementTransformations (i); - int i1 = face_elem_transf -> Elem1No; - int i2 = face_elem_transf -> Elem2No; - intorder = fes -> GetFE (i1) -> GetOrder(); + face_elem_transf = mesh->GetFaceElementTransformations(i); + int i1 = face_elem_transf->Elem1No; + int i2 = face_elem_transf->Elem2No; + intorder = fes->GetFE(i1)->GetOrder(); if (i2 >= 0) - if ( (k = fes -> GetFE (i2) -> GetOrder()) > intorder ) + if ( (k = fes->GetFE(i2)->GetOrder()) > intorder ) intorder = k; intorder = 2 * intorder; // <------------- const IntegrationRule &ir = - IntRules.Get (face_elem_transf -> FaceGeom, intorder); - err_val.SetSize (ir.GetNPoints()); - ell_coeff_val.SetSize (ir.GetNPoints()); + IntRules.Get(face_elem_transf->FaceGeom, intorder); + err_val.SetSize(ir.GetNPoints()); + ell_coeff_val.SetSize(ir.GetNPoints()); // side 1 - transf = face_elem_transf -> Elem1; - fe = fes -> GetFE (i1); - fdof = fe -> GetDof(); - fes -> GetElementVDofs (i1, vdofs); - shape.SetSize (fdof); - el_dofs.SetSize (fdof); + transf = face_elem_transf->Elem1; + fe = fes->GetFE(i1); + fdof = fe->GetDof(); + fes->GetElementVDofs(i1, vdofs); + shape.SetSize(fdof); + el_dofs.SetSize(fdof); for (k = 0; k < fdof; k++) if (vdofs[k] >= 0) el_dofs(k) = (*this)(vdofs[k]); @@ -1077,21 +1027,21 @@ double GridFunction::ComputeH1Error ( el_dofs(k) = - (*this)(-1-vdofs[k]); for (j = 0; j < ir.GetNPoints(); j++) { - face_elem_transf -> Loc1.Transform (ir.IntPoint (j), eip); - fe -> CalcShape (eip, shape); + face_elem_transf->Loc1.Transform(ir.IntPoint(j), eip); + fe->CalcShape(eip, shape); transf->SetIntPoint(&eip); - ell_coeff_val(j) = ell_coeff -> Eval (*transf, eip); - err_val(j) = exsol -> Eval (*transf, eip) - (shape * el_dofs); + ell_coeff_val(j) = ell_coeff->Eval(*transf, eip); + err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs); } if (i2 >= 0) { // side 2 - transf = face_elem_transf -> Elem2; - fe = fes -> GetFE (i2); - fdof = fe -> GetDof(); - fes -> GetElementVDofs (i2, vdofs); - shape.SetSize (fdof); - el_dofs.SetSize (fdof); + transf = face_elem_transf->Elem2; + fe = fes->GetFE(i2); + fdof = fe->GetDof(); + fes->GetElementVDofs(i2, vdofs); + shape.SetSize(fdof); + el_dofs.SetSize(fdof); for (k = 0; k < fdof; k++) if (vdofs[k] >= 0) el_dofs(k) = (*this)(vdofs[k]); @@ -1099,22 +1049,21 @@ double GridFunction::ComputeH1Error ( el_dofs(k) = - (*this)(-1-vdofs[k]); for (j = 0; j < ir.GetNPoints(); j++) { - face_elem_transf -> Loc2.Transform (ir.IntPoint (j), eip); - fe -> CalcShape (eip, shape); + face_elem_transf->Loc2.Transform(ir.IntPoint(j), eip); + fe->CalcShape(eip, shape); transf->SetIntPoint(&eip); - ell_coeff_val(j) += ell_coeff -> Eval (*transf, eip); + ell_coeff_val(j) += ell_coeff->Eval(*transf, eip); ell_coeff_val(j) *= 0.5; - err_val(j) -= (exsol -> Eval (*transf, eip) - - (shape * el_dofs)); + err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs)); } } - transf = face_elem_transf -> Face; + transf = face_elem_transf->Face; for (j = 0; j < ir.GetNPoints(); j++) { - const IntegrationPoint &ip = ir.IntPoint (j); - transf -> SetIntPoint (&ip); + const IntegrationPoint &ip = ir.IntPoint(j); + transf->SetIntPoint(&ip); error += (ip.weight * Nu * ell_coeff_val(j) * - pow (transf -> Weight(), 1.0-1.0/(dim-1)) * + pow(transf->Weight(), 1.0-1.0/(dim-1)) * err_val(j) * err_val(j)); } } @@ -1124,7 +1073,7 @@ double GridFunction::ComputeH1Error ( return sqrt(error); } -double GridFunction::ComputeMaxError ( +double GridFunction::ComputeMaxError( Coefficient *exsol[], const IntegrationRule *irs[]) const { double error = 0.0, a; @@ -1146,7 +1095,7 @@ double GridFunction::ComputeMaxError ( ir = irs[fe->GetGeomType()]; else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); - fes->GetElementVDofs (i, vdofs); + fes->GetElementVDofs(i, vdofs); for (j = 0; j < ir->GetNPoints(); j++) { const IntegrationPoint &ip = ir->IntPoint(j); @@ -1161,7 +1110,7 @@ double GridFunction::ComputeMaxError ( else a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k); a -= exsol[d]->Eval(*transf, ip); - a = fabs (a); + a = fabs(a); if (error < a) error = a; } @@ -1176,14 +1125,13 @@ double GridFunction::ComputeMaxError( { double error = 0.0; const FiniteElement *fe; - ElementTransformation *transf; + ElementTransformation *T; DenseMatrix vals, exact_vals, tr; Vector loc_errs; for (int i = 0; i < fes->GetNE(); i++) { fe = fes->GetFE(i); - transf = fes->GetElementTransformation(i); int intorder = fe->GetOrder()+2; // <---------- const IntegrationRule *ir; if (irs) @@ -1191,7 +1139,8 @@ double GridFunction::ComputeMaxError( else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); GetVectorValues(i, *ir, vals, tr); - exsol.Eval(exact_vals, *transf, *ir); + T = fes->GetElementTransformation(i); + exsol.Eval(exact_vals, *T, *ir); vals -= exact_vals; loc_errs.SetSize(vals.Width()); // compute the lengths of the errors at the integration points @@ -1205,7 +1154,7 @@ double GridFunction::ComputeMaxError( return error; } -double GridFunction::ComputeW11Error ( +double GridFunction::ComputeW11Error( Coefficient *exsol, VectorCoefficient *exgrad, int norm_type, Array *elems, const IntegrationRule *irs[]) const { @@ -1219,76 +1168,76 @@ double GridFunction::ComputeW11Error ( Array vdofs; double a, error = 0.0; - mesh = fes -> GetMesh(); - dim = mesh -> Dimension(); - e_grad.SetSize (dim); - a_grad.SetSize (dim); - Jinv.SetSize (dim); + mesh = fes->GetMesh(); + dim = mesh->Dimension(); + e_grad.SetSize(dim); + a_grad.SetSize(dim); + Jinv.SetSize(dim); if (norm_type & 1) // L_1 norm - for (i = 0; i < mesh -> GetNE(); i++) + for (i = 0; i < mesh->GetNE(); i++) { if (elems != NULL && (*elems)[i] == 0) continue; - fe = fes -> GetFE (i); - fdof = fe -> GetDof(); - transf = fes -> GetElementTransformation (i); - el_dofs.SetSize (fdof); - shape.SetSize (fdof); - intorder = fe -> GetOrder() + 1; // <---------- + fe = fes->GetFE(i); + fdof = fe->GetDof(); + transf = fes->GetElementTransformation(i); + el_dofs.SetSize(fdof); + shape.SetSize(fdof); + intorder = fe->GetOrder() + 1; // <---------- const IntegrationRule *ir; if (irs) ir = irs[fe->GetGeomType()]; else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); - fes -> GetElementVDofs (i, vdofs); + fes->GetElementVDofs(i, vdofs); for (k = 0; k < fdof; k++) if (vdofs[k] >= 0) - el_dofs(k) = (*this)(vdofs[k]); + el_dofs(k) = (*this)(vdofs[k]); else - el_dofs(k) = - (*this)(-1-vdofs[k]); + el_dofs(k) = -(*this)(-1-vdofs[k]); for (j = 0; j < ir->GetNPoints(); j++) { - const IntegrationPoint &ip = ir->IntPoint (j); - fe -> CalcShape (ip, shape); - transf -> SetIntPoint (&ip); - a = (el_dofs * shape) - (exsol -> Eval (*transf, ip)); - error += ip.weight * transf -> Weight() * fabs (a); + const IntegrationPoint &ip = ir->IntPoint(j); + fe->CalcShape(ip, shape); + transf->SetIntPoint(&ip); + a = (el_dofs * shape) - (exsol->Eval(*transf, ip)); + error += ip.weight * transf->Weight() * fabs(a); } } if (norm_type & 2) // W^1_1 seminorm - for (i = 0; i < mesh -> GetNE(); i++) + for (i = 0; i < mesh->GetNE(); i++) { if (elems != NULL && (*elems)[i] == 0) continue; - fe = fes -> GetFE (i); - fdof = fe -> GetDof(); - transf = mesh -> GetElementTransformation (i); - el_dofs.SetSize (fdof); - dshape.SetSize (fdof, dim); - dshapet.SetSize (fdof, dim); - intorder = fe -> GetOrder() + 1; // <---------- + fe = fes->GetFE(i); + fdof = fe->GetDof(); + transf = mesh->GetElementTransformation(i); + el_dofs.SetSize(fdof); + dshape.SetSize(fdof, dim); + dshapet.SetSize(fdof, dim); + intorder = fe->GetOrder() + 1; // <---------- const IntegrationRule *ir; if (irs) ir = irs[fe->GetGeomType()]; else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); - fes -> GetElementVDofs (i, vdofs); + fes->GetElementVDofs(i, vdofs); for (k = 0; k < fdof; k++) if (vdofs[k] >= 0) - el_dofs(k) = (*this)(vdofs[k]); + el_dofs(k) = (*this)(vdofs[k]); else - el_dofs(k) = - (*this)(-1-vdofs[k]); + el_dofs(k) = -(*this)(-1-vdofs[k]); for (j = 0; j < ir->GetNPoints(); j++) { - const IntegrationPoint &ip = ir->IntPoint (j); - fe -> CalcDShape (ip, dshape); - transf -> SetIntPoint (&ip); - exgrad -> Eval (e_grad, *transf, ip); - CalcInverse (transf -> Jacobian(), Jinv); - Mult (dshape, Jinv, dshapet); - dshapet.MultTranspose (el_dofs, a_grad); + const IntegrationPoint &ip = ir->IntPoint(j); + fe->CalcDShape(ip, dshape); + transf->SetIntPoint(&ip); + exgrad->Eval(e_grad, *transf, ip); + CalcInverse(transf->Jacobian(), Jinv); + Mult(dshape, Jinv, dshapet); + dshapet.MultTranspose(el_dofs, a_grad); e_grad -= a_grad; - error += ip.weight * transf -> Weight() * e_grad.Norml1(); + error += ip.weight * transf->Weight() * e_grad.Norml1(); } } @@ -1300,14 +1249,13 @@ double GridFunction::ComputeL1Error( { double error = 0.0; const FiniteElement *fe; - ElementTransformation *transf; + ElementTransformation *T; DenseMatrix vals, exact_vals, tr; Vector loc_errs; for (int i = 0; i < fes->GetNE(); i++) { fe = fes->GetFE(i); - transf = fes->GetElementTransformation(i); int intorder = fe->GetOrder()+2; // <---------- const IntegrationRule *ir; if (irs) @@ -1315,7 +1263,8 @@ double GridFunction::ComputeL1Error( else ir = &(IntRules.Get(fe->GetGeomType(), intorder)); GetVectorValues(i, *ir, vals, tr); - exsol.Eval(exact_vals, *transf, *ir); + T = fes->GetElementTransformation(i); + exsol.Eval(exact_vals, *T, *ir); vals -= exact_vals; loc_errs.SetSize(vals.Width()); // compute the lengths of the errors at the integration points @@ -1323,39 +1272,39 @@ double GridFunction::ComputeL1Error( vals.Norm2(loc_errs); for (int j = 0; j < ir->GetNPoints(); j++) { - const IntegrationPoint &ip = ir->IntPoint (j); - transf->SetIntPoint(&ip); - error += ip.weight * transf->Weight() * loc_errs(j); + const IntegrationPoint &ip = ir->IntPoint(j); + T->SetIntPoint(&ip); + error += ip.weight * T->Weight() * loc_errs(j); } } return error; } -GridFunction & GridFunction::operator= (double value) +GridFunction & GridFunction::operator=(double value) { - for(int i = 0; i < size; i++) + for (int i = 0; i < size; i++) data[i] = value; return *this; } -GridFunction & GridFunction::operator= (const Vector &v) +GridFunction & GridFunction::operator=(const Vector &v) { - for(int i = 0; i < size; i++) + for (int i = 0; i < size; i++) data[i] = v(i); return *this; } -GridFunction & GridFunction::operator= (const GridFunction &v) +GridFunction & GridFunction::operator=(const GridFunction &v) { return this->operator=((const Vector &)v); } -void GridFunction::Save (ostream &out) +void GridFunction::Save(ostream &out) { - fes -> Save (out); + fes->Save(out); out << endl; - Vector::Print (out, 1); + Vector::Print(out, 1); } void GridFunction::SaveVTK(ostream &out, const string &field_name, int ref) @@ -1407,15 +1356,15 @@ void GridFunction::SaveVTK(ostream &out, const string &field_name, int ref) } } -void GridFunction::SaveSTLTri (ostream &out, double p1[], double p2[], - double p3[]) +void GridFunction::SaveSTLTri(ostream &out, double p1[], double p2[], + double p3[]) { double v1[3] = { p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2] }; double v2[3] = { p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2] }; double n[] = { v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0] }; - double rl = 1.0 / sqrt (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); + double rl = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); n[0] *= rl; n[1] *= rl; n[2] *= rl; out << " facet normal " << n[0] << ' ' << n[1] << ' ' << n[2] @@ -1426,11 +1375,11 @@ void GridFunction::SaveSTLTri (ostream &out, double p1[], double p2[], << "\n endloop\n endfacet\n"; } -void GridFunction::SaveSTL (ostream &out, int TimesToRefine) +void GridFunction::SaveSTL(ostream &out, int TimesToRefine) { - Mesh *mesh = fes -> GetMesh(); + Mesh *mesh = fes->GetMesh(); - if (mesh -> Dimension() != 2) + if (mesh->Dimension() != 2) return; int i, j, k, l, n; @@ -1443,13 +1392,13 @@ void GridFunction::SaveSTL (ostream &out, int TimesToRefine) bbox[0][0] = bbox[0][1] = bbox[1][0] = bbox[1][1] = bbox[2][0] = bbox[2][1] = 0.0; - for (i = 0; i < mesh -> GetNE(); i++) + for (i = 0; i < mesh->GetNE(); i++) { - n = fes -> GetFE(i) -> GetGeomType(); - RefG = GlobGeometryRefiner.Refine (n, TimesToRefine); - GetValues (i, RefG -> RefPts, values, pointmat); - Array &RG = RefG -> RefGeoms; - n = Geometries.NumBdr (n); + n = fes->GetFE(i)->GetGeomType(); + RefG = GlobGeometryRefiner.Refine(n, TimesToRefine); + GetValues(i, RefG->RefPts, values, pointmat); + Array &RG = RefG->RefGeoms; + n = Geometries.NumBdr(n); for (k = 0; k < RG.Size()/n; k++) { for (j = 0; j < n; j++) @@ -1462,12 +1411,12 @@ void GridFunction::SaveSTL (ostream &out, int TimesToRefine) if (n == 3) { - SaveSTLTri (out, pts[0], pts[1], pts[2]); + SaveSTLTri(out, pts[0], pts[1], pts[2]); } else { - SaveSTLTri (out, pts[0], pts[1], pts[2]); - SaveSTLTri (out, pts[0], pts[2], pts[3]); + SaveSTLTri(out, pts[0], pts[1], pts[2]); + SaveSTLTri(out, pts[0], pts[2], pts[3]); } } diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 99a1aab5cb..968a8cc04b 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -15,14 +15,14 @@ /// Class for grid function - Vector with asociated FE space. class GridFunction : public Vector { -private: +protected: /// FE space on which grid function lives. - FiniteElementSpace * fes; + FiniteElementSpace *fes; /// Used when the grid function is read from a file FiniteElementCollection *fec; - void SaveSTLTri (ostream &out, double p1[], double p2[], double p3[]); + void SaveSTLTri(ostream &out, double p1[], double p2[], double p3[]); void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh); @@ -31,55 +31,55 @@ public: GridFunction() { fes = NULL; fec = NULL; } /// Creates grid function associated with *f. - GridFunction (FiniteElementSpace * f) : Vector(f->GetVSize()) + GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize()) { fes = f; fec = NULL; } - GridFunction (Mesh *m, istream &input); + GridFunction(Mesh *m, istream &input); - // Make the GridFunction the owner of 'fec' and 'fes' + /// Make the GridFunction the owner of 'fec' and 'fes' void MakeOwner(FiniteElementCollection *_fec) { fec = _fec; } int VectorDim() const; /// Returns the values in the vertices of i'th element for dimension vdim. - void GetNodalValues (int i, Array &nval, int vdim = 1) const; + void GetNodalValues(int i, Array &nval, int vdim = 1) const; - double GetValue (int i, const IntegrationPoint &ip, int vdim = 1) const; + double GetValue(int i, const IntegrationPoint &ip, int vdim = 1) const; - void GetVectorValue (int i, const IntegrationPoint &ip, Vector &val) const; + void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const; - void GetValues (int i, const IntegrationRule &ir, Vector &vals, - DenseMatrix &tr, int vdim = 1) const; + void GetValues(int i, const IntegrationRule &ir, Vector &vals, + DenseMatrix &tr, int vdim = 1) const; - int GetFaceValues (int i, int side, const IntegrationRule &ir, Vector &vals, - DenseMatrix &tr, int vdim = 1) const; + int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, + DenseMatrix &tr, int vdim = 1) const; - void GetVectorValues (int i, const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix &tr) const; + void GetVectorValues(int i, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix &tr) const; - int GetFaceVectorValues (int i, int side, const IntegrationRule &ir, - DenseMatrix &vals, DenseMatrix &tr) const; + int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, + DenseMatrix &vals, DenseMatrix &tr) const; - void GetValuesFrom (GridFunction &); + void GetValuesFrom(GridFunction &); - void GetBdrValuesFrom (GridFunction &); + void GetBdrValuesFrom(GridFunction &); - void GetVectorFieldValues (int i, const IntegrationRule &ir, - DenseMatrix &vals, - DenseMatrix &tr, int comp = 0) const; + void GetVectorFieldValues(int i, const IntegrationRule &ir, + DenseMatrix &vals, + DenseMatrix &tr, int comp = 0) const; /// For a vector grid function, makes sure that the ordering is byNODES. void ReorderByNodes(); /// Return the values as a vector on mesh vertices for dimension vdim. - void GetNodalValues (Vector &nval, int vdim = 1) const; + void GetNodalValues(Vector &nval, int vdim = 1) const; void GetVectorFieldNodalValues(Vector &val, int comp) const; - void ProjectVectorFieldOn (GridFunction &vec_field, int comp = 0); + void ProjectVectorFieldOn(GridFunction &vec_field, int comp = 0); - void GetDerivative (int comp, int der_comp, GridFunction &der); + void GetDerivative(int comp, int der_comp, GridFunction &der); double GetDivergence(ElementTransformation &tr); @@ -93,19 +93,18 @@ public: /** Compute \f$ (\int_{\Omega} (*this) \psi_i)/(\int_{\Omega} \psi_i) \f$, where \f$ \psi_i \f$ are the basis functions for the FE space of avgs. Both FE spaces should be scalar and on the same mesh. */ - void GetElementAverages (GridFunction &avgs); + void GetElementAverages(GridFunction &avgs); - void ProjectCoefficient (Coefficient &coeff); + void ProjectCoefficient(Coefficient &coeff); // call fes -> BuildDofToArrays() before using this projection - void ProjectCoefficient (Coefficient &coeff, Array &dofs, - int vd = 0); + void ProjectCoefficient(Coefficient &coeff, Array &dofs, int vd = 0); - void ProjectCoefficient (VectorCoefficient &vcoeff); + void ProjectCoefficient(VectorCoefficient &vcoeff); - void ProjectCoefficient (Coefficient *coeff[]); + void ProjectCoefficient(Coefficient *coeff[]); - void ProjectBdrCoefficient (Coefficient *coeff[], Array &attr); + void ProjectBdrCoefficient(Coefficient *coeff[], Array &attr); double ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[] = NULL) const; @@ -124,40 +123,40 @@ public: double ComputeMaxError(VectorCoefficient &exsol, const IntegrationRule *irs[] = NULL) const; - double ComputeW11Error (Coefficient *exsol, VectorCoefficient *exgrad, - int norm_type, Array *elems = NULL, - const IntegrationRule *irs[] = NULL) const; + double ComputeW11Error(Coefficient *exsol, VectorCoefficient *exgrad, + int norm_type, Array *elems = NULL, + const IntegrationRule *irs[] = NULL) const; double ComputeL1Error(VectorCoefficient &exsol, const IntegrationRule *irs[] = NULL) const; /// Redefine '=' for GridFunction = constant. - GridFunction & operator= (double value); + GridFunction &operator=(double value); - GridFunction & operator= (const Vector &v); + GridFunction &operator=(const Vector &v); - GridFunction & operator= (const GridFunction &v); + GridFunction &operator=(const GridFunction &v); - FiniteElementSpace *FESpace() { return fes; }; + FiniteElementSpace *FESpace() { return fes; } - void Update() { SetSize (fes->GetVSize()); }; + void Update() { SetSize(fes->GetVSize()); } - void Update (FiniteElementSpace *f); + void Update(FiniteElementSpace *f); - void Update (FiniteElementSpace *f, Vector &v, int v_offset); + void Update(FiniteElementSpace *f, Vector &v, int v_offset); /// Save the GridFunction to an output stream. - void Save (ostream &out); + void Save(ostream &out); /** Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be called first. The parameter ref must match the one used in Mesh::PrintVTK. */ void SaveVTK(ostream &out, const string &field_name, int ref); - void SaveSTL (ostream &out, int TimesToRefine = 1); + void SaveSTL(ostream &out, int TimesToRefine = 1); /// Destroys grid function. - ~GridFunction(); + virtual ~GridFunction(); }; void ComputeFlux(BilinearFormIntegrator &blfi, diff --git a/fem/intrules.hpp b/fem/intrules.hpp index 9afdd1fcae..9b6290671a 100644 --- a/fem/intrules.hpp +++ b/fem/intrules.hpp @@ -22,7 +22,7 @@ public: double x, y, z, weight; }; -// Class for integration rule +/// Class for integration rule class IntegrationRule { private: diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 7849c8a8f1..91639653ff 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -13,10 +13,10 @@ #include #include "fem.hpp" -void LinearFormIntegrator::AssembleRHSElementVect (const FiniteElement &el, - FaceElementTransformations &Tr, Vector &elvect) +void LinearFormIntegrator::AssembleRHSElementVect( + const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { - mfem_error ("LinearFormIntegrator::AssembleRHSElementVect (...)"); + mfem_error("LinearFormIntegrator::AssembleRHSElementVect(...)"); } @@ -37,8 +37,9 @@ void DomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el, } else { - ir = &IntRules.Get(el.GetGeomType(), - oa * el.GetOrder() + ob + Tr.OrderW()); + // ir = &IntRules.Get(el.GetGeomType(), + // oa * el.GetOrder() + ob + Tr.OrderW()); + ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob); } for (int i = 0; i < ir->GetNPoints(); i++) @@ -59,8 +60,8 @@ inline double sqr(double x) return x * x; } -void BoundaryLFIntegrator::AssembleRHSElementVect(const FiniteElement &el, - ElementTransformation &Tr, Vector &elvect) +void BoundaryLFIntegrator::AssembleRHSElementVect( + const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); @@ -84,8 +85,8 @@ void BoundaryLFIntegrator::AssembleRHSElementVect(const FiniteElement &el, } } -void VectorDomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el, - ElementTransformation &Tr, Vector &elvect) +void VectorDomainLFIntegrator::AssembleRHSElementVect( + const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int vdim = Q.GetVDim(); int dof = el.GetDof(); @@ -97,7 +98,7 @@ void VectorDomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el, elvect.SetSize(dof * vdim); elvect = 0.0; - int intorder = el.GetOrder(); + int intorder = el.GetOrder() + 1; const IntegrationRule &ir = IntRules.Get(el.GetGeomType(), intorder); for (int i = 0; i < ir.GetNPoints(); i++) @@ -132,7 +133,7 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect( elvect.SetSize(dof * vdim); elvect = 0.0; - int intorder = el.GetOrder(); + int intorder = el.GetOrder() + 1; const IntegrationRule &ir = IntRules.Get(el.GetGeomType(), intorder); for (int i = 0; i < ir.GetNPoints(); i++) @@ -155,14 +156,14 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect( int dof = el.GetDof(); int dim = el.GetDim(); - Jinv.SetSize(dim); vshape.SetSize(dof,dim); vec.SetSize(dim); elvect.SetSize(dof); elvect = 0.0; - const IntegrationRule &ir = IntRules.Get(el.GetGeomType(), el.GetOrder()); + const IntegrationRule &ir = IntRules.Get(el.GetGeomType(), + el.GetOrder() + 1); for (int i = 0; i < ir.GetNPoints(); i++) { @@ -172,7 +173,7 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect( el.CalcVShape(Tr, vshape); QF.Eval (vec, Tr, ip); - vec *= ip.weight; + vec *= ip.weight * Tr.Weight(); vshape.AddMult (vec, elvect); } @@ -192,7 +193,7 @@ void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect( const IntegrationRule *ir; if (!IntRule) - ir = &IntRules.Get(el.GetGeomType(), el.GetOrder()); + ir = &IntRules.Get(el.GetGeomType(), el.GetOrder() + 1); else ir = IntRule; diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index e9728e4a4f..5a260e07cf 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -49,6 +49,8 @@ public: virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; }; /// Class for boundary integration L(v) := (g, v) @@ -59,7 +61,7 @@ class BoundaryLFIntegrator : public LinearFormIntegrator int oa, ob; public: /// Constructs a boundary integrator with a given Coefficient QG - BoundaryLFIntegrator(Coefficient &QG, int a = 2, int b = 0) + BoundaryLFIntegrator(Coefficient &QG, int a = 1, int b = 1) : Q(QG), oa(a), ob(b) {}; /** Given a particular boundary Finite Element and a transformation (Tr) @@ -67,6 +69,8 @@ public: virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; }; /** Class for domain integration of L(v) := (f, v), where @@ -86,6 +90,8 @@ public: virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; }; /** Class for boundary integration of L(v) := (g, v), where @@ -105,14 +111,16 @@ public: virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; }; -/// \f$ (f, v)_{\Omega} \f$ for VectorFiniteElements (Nedelec, Raviart-Thomas) +/// \f$ (f, v)_{\Omega} \f$ for VectorFiniteElements (Nedelec, Raviart-Thomas) class VectorFEDomainLFIntegrator : public LinearFormIntegrator { private: VectorCoefficient &QF; - DenseMatrix Jinv, vshape; + DenseMatrix vshape; Vector vec; public: @@ -121,12 +129,14 @@ public: virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; }; -/** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function - v=(v1,...,vn) where all vi are in the same scalar FE space and f is a - scalar function. */ +/** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function + v=(v1,...,vn) where all vi are in the same scalar FE space and f is a + scalar function. */ class VectorBoundaryFluxLFIntegrator : public LinearFormIntegrator { private: @@ -142,6 +152,8 @@ public: virtual void AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect); + + using LinearFormIntegrator::AssembleRHSElementVect; }; #endif diff --git a/fem/pbilinearform.cpp b/fem/pbilinearform.cpp new file mode 100644 index 0000000000..448c0f05be --- /dev/null +++ b/fem/pbilinearform.cpp @@ -0,0 +1,35 @@ +// 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.googlecode.com. +// +// 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. + +#ifdef MFEM_USE_MPI + +#include "fem.hpp" + +HypreParMatrix *ParBilinearForm::ParallelAssemble() +{ + int nproc = pfes -> GetNRanks(); + int *dof_off = pfes -> GetDofOffsets(); + + // construct the block-diagonal matrix A + HypreParMatrix *A; + if (HYPRE_AssumedPartitionCheck()) + A = new HypreParMatrix(dof_off[2], dof_off, mat); + else + A = new HypreParMatrix(dof_off[nproc], dof_off, mat); + + HypreParMatrix *rap = RAP(A, pfes -> Dof_TrueDof_Matrix()); + + delete A; + + return rap; +} + +#endif diff --git a/fem/pbilinearform.hpp b/fem/pbilinearform.hpp new file mode 100644 index 0000000000..1f831840e8 --- /dev/null +++ b/fem/pbilinearform.hpp @@ -0,0 +1,34 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_PBILINEARFORM +#define MFEM_PBILINEARFORM + +/// Class for parallel bilinear form +class ParBilinearForm : public BilinearForm +{ +protected: + ParFiniteElementSpace *pfes; + +public: + ParBilinearForm(ParFiniteElementSpace *pf) + : BilinearForm(pf) { pfes = pf; } + + ParBilinearForm(ParFiniteElementSpace *pf, ParBilinearForm *bf) + : BilinearForm(pf, bf) { pfes = pf; } + + /// Returns the matrix assembled on the true dofs, i.e. P^t A P. + HypreParMatrix *ParallelAssemble(); + + virtual ~ParBilinearForm() { } +}; + +#endif diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp new file mode 100644 index 0000000000..48ccf24e33 --- /dev/null +++ b/fem/pfespace.cpp @@ -0,0 +1,571 @@ +// 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.googlecode.com. +// +// 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. + +#ifdef MFEM_USE_MPI + +#include "fem.hpp" +#include "../general/sort_pairs.hpp" + +ParFiniteElementSpace::ParFiniteElementSpace(ParFiniteElementSpace &pf) + : FiniteElementSpace(pf) +{ + MyComm = pf.MyComm; + NRanks = pf.NRanks; + MyRank = pf.MyRank; + pmesh = pf.pmesh; + ltdof_size = pf.ltdof_size; + Swap(ldof_group, pf.ldof_group); + Swap(ldof_ltdof, pf.ldof_ltdof); + Swap(dof_offsets, pf.dof_offsets); + Swap(tdof_offsets, pf.tdof_offsets); + Swap(ldof_sign, pf.ldof_sign); + P = pf.P; + pf.P = NULL; +} + +ParFiniteElementSpace::ParFiniteElementSpace( + ParMesh *pm, FiniteElementCollection *f, int dim, int order) + : FiniteElementSpace(pm, f, dim, order) +{ + mesh = pmesh = pm; + + MyComm = pmesh->GetComm(); + MPI_Comm_size(MyComm, &NRanks); + MPI_Comm_rank(MyComm, &MyRank); + + P = NULL; + + ConstructTrueDofs(); + + GenerateGlobalOffsets(); +} + +void ParFiniteElementSpace::GetElementDofs(int i, Array &dofs) const +{ + if (elem_dof) + { + elem_dof->GetRow(i, dofs); + return; + } + FiniteElementSpace::GetElementDofs(i, dofs); + for (i = 0; i < dofs.Size(); i++) + if (dofs[i] < 0) + { + if (ldof_sign[-1-dofs[i]] < 0) + dofs[i] = -1-dofs[i]; + } + else + { + if (ldof_sign[dofs[i]] < 0) + dofs[i] = -1-dofs[i]; + } +} + +void ParFiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const +{ + FiniteElementSpace::GetBdrElementDofs(i, dofs); + for (i = 0; i < dofs.Size(); i++) + if (dofs[i] < 0) + { + if (ldof_sign[-1-dofs[i]] < 0) + dofs[i] = -1-dofs[i]; + } + else + { + if (ldof_sign[dofs[i]] < 0) + dofs[i] = -1-dofs[i]; + } +} + +void ParFiniteElementSpace::GenerateGlobalOffsets() +{ + if (HYPRE_AssumedPartitionCheck()) + { + int ldof[2]; + + ldof[0] = GetVSize(); + ldof[1] = TrueVSize(); + + dof_offsets.SetSize(3); + tdof_offsets.SetSize(3); + + MPI_Scan(&ldof, &dof_offsets[0], 2, MPI_INT, MPI_SUM, MyComm); + + tdof_offsets[1] = dof_offsets[1]; + tdof_offsets[0] = tdof_offsets[1] - ldof[1]; + + dof_offsets[1] = dof_offsets[0]; + dof_offsets[0] = dof_offsets[1] - ldof[0]; + + // get the global sizes in (t)dof_offsets[2] + if (MyRank == NRanks-1) + { + ldof[0] = dof_offsets[1]; + ldof[1] = tdof_offsets[1]; + } + + MPI_Bcast(&ldof, 2, MPI_INT, NRanks-1, MyComm); + dof_offsets[2] = ldof[0]; + tdof_offsets[2] = ldof[1]; + } + else + { + int i; + int ldof = GetVSize(); + int ltdof = TrueVSize(); + + dof_offsets.SetSize (NRanks+1); + tdof_offsets.SetSize(NRanks+1); + + MPI_Allgather(&ldof, 1, MPI_INT, &dof_offsets[1], 1, MPI_INT, MyComm); + MPI_Allgather(<dof, 1, MPI_INT, &tdof_offsets[1], 1, MPI_INT, MyComm); + + dof_offsets[0] = tdof_offsets[0] = 0; + for (i = 1; i < NRanks; i++) + { + dof_offsets [i+1] += dof_offsets [i]; + tdof_offsets[i+1] += tdof_offsets[i]; + } + } +} + +HypreParMatrix *ParFiniteElementSpace::Dof_TrueDof_Matrix() // matrix P +{ + int i; + + if (P) + return P; + + int ldof = GetVSize(); + + int ltdof = TrueVSize(); + + int *lproc_proc = pmesh -> lproc_proc; + int *groupmaster_lproc = pmesh -> groupmaster_lproc; + + int *i_diag; + int *j_diag; + int diag_counter; + + int *i_offd; + int *j_offd; + int offd_counter; + + int *cmap; + int *col_starts; + int *row_starts; + + col_starts = GetTrueDofOffsets(); + row_starts = GetDofOffsets(); + + i_diag = new int[ldof+1]; + j_diag = new int[ltdof]; + + i_offd = new int[ldof+1]; + j_offd = new int[ldof-ltdof]; + + cmap = new int[ldof-ltdof]; + + Array > cmap_j_offd(ldof-ltdof); + + int *ncol_starts = NULL; + if (HYPRE_AssumedPartitionCheck()) + { + int nsize = pmesh -> lproc_proc.Size()-1; + MPI_Request *requests = new MPI_Request[2*nsize]; + MPI_Status *statuses = new MPI_Status[2*nsize]; + ncol_starts = hypre_CTAlloc(int, nsize+1); + + int request_counter = 0; + // send and receive neighbors' local tdof offsets + for (i = 1; i < nsize+1; i++) + MPI_Irecv(&ncol_starts[i], 1, MPI_INT, lproc_proc[i], 5365, + MyComm, &requests[request_counter++]); + + for (i = 1; i < nsize+1; i++) + MPI_Isend(&col_starts[0], 1, MPI_INT, lproc_proc[i], 5365, + MyComm, &requests[request_counter++]); + + MPI_Waitall(request_counter, requests, statuses); + + delete [] statuses; + delete [] requests; + } + + i_diag[0] = i_offd[0] = 0; + diag_counter = offd_counter = 0; + for (i = 0; i < ldof; i++) + { + int proc = lproc_proc[groupmaster_lproc[ldof_group[i]]]; + if (proc == MyRank) + { + j_diag[diag_counter++] = ldof_ltdof[i]; + } + else + { + if (HYPRE_AssumedPartitionCheck()) + cmap_j_offd[offd_counter].one = + ncol_starts[groupmaster_lproc[ldof_group[i]]] + ldof_ltdof[i]; + else + cmap_j_offd[offd_counter].one = col_starts[proc] + ldof_ltdof[i]; + cmap_j_offd[offd_counter].two = offd_counter; + offd_counter++; + } + i_diag[i+1] = diag_counter; + i_offd[i+1] = offd_counter; + } + + if (HYPRE_AssumedPartitionCheck()) + delete [] ncol_starts; + + SortPairs(cmap_j_offd, offd_counter); + + for (i = 0; i < offd_counter; i++) + { + cmap[i] = cmap_j_offd[i].one; + j_offd[cmap_j_offd[i].two] = i; + } + + P = new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts, + i_diag, j_diag, i_offd, j_offd, cmap, offd_counter); + + return P; +} + +void ParFiniteElementSpace::DivideByGroupSize(double * vec) +{ + for (int i = 0; i < ldof_group.Size(); i++) + if (pmesh -> groupmaster_lproc[ldof_group[i]] == 0) // we are the master + vec[ldof_ltdof[i]] /= pmesh -> group_lproc.RowSize(ldof_group[i]); +} + +void ParFiniteElementSpace::GetEssentialVDofs(Array &bdr_attr_is_ess, + Array &ess_dofs) +{ + FiniteElementSpace::GetEssentialVDofs(bdr_attr_is_ess, ess_dofs); + + // Make sure that processors without boundary elements mark + // their boundary dofs (if they have any). + Vector d_ess_dofs(ess_dofs.Size()); + for (int i = 0; i < ess_dofs.Size(); i++) + d_ess_dofs(i) = ess_dofs[i]; + + // vector on (all) dofs + HypreParVector *v_ess_dofs; + if (HYPRE_AssumedPartitionCheck()) + v_ess_dofs = new HypreParVector(dof_offsets[2], d_ess_dofs, dof_offsets); + else + v_ess_dofs = new HypreParVector(dof_offsets[NRanks], d_ess_dofs, + dof_offsets); + + // vector on true dofs + HypreParVector *v_ess_tdofs; + if (HYPRE_AssumedPartitionCheck()) + v_ess_tdofs = new HypreParVector(tdof_offsets[2], tdof_offsets); + else + v_ess_tdofs = new HypreParVector(tdof_offsets[NRanks], tdof_offsets); + + Dof_TrueDof_Matrix()->MultTranspose(*v_ess_dofs, *v_ess_tdofs); + Dof_TrueDof_Matrix()->Mult(*v_ess_tdofs, *v_ess_dofs); + + for (int i = 0; i < ess_dofs.Size(); i++) + if (d_ess_dofs(i) < 0.0) + ess_dofs[i] = -1; + + delete v_ess_tdofs; + delete v_ess_dofs; +} + +int ParFiniteElementSpace::GetLocalTDofNumber(int ldof) +{ + if (pmesh -> groupmaster_lproc[ldof_group[ldof]] == 0) + return ldof_ltdof[ldof]; + else + return -1; +} + +int ParFiniteElementSpace::GetGlobalTDofNumber(int ldof) +{ + if (HYPRE_AssumedPartitionCheck()) + { + if (MyRank == 0) + cerr << "ParFiniteElementSpace::GetGlobalTDofNumber " + << "does not support Assumed Partitioning!\n" << endl; + MPI_Finalize(); + mfem_error(); + } + + if (pmesh -> groupmaster_lproc[ldof_group[ldof]] == 0) + return ldof_ltdof[ldof] + tdof_offsets[MyRank]; + else + return ldof_ltdof[ldof] + + tdof_offsets[pmesh->lproc_proc[ + pmesh->groupmaster_lproc[ldof_group[ldof]]]]; +} + +void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix() +{ + hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P); + hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1; + hypre_ParCSRMatrixOwnsColStarts(csrP) = 1; + P -> StealData(); + dof_offsets.LoseData(); + tdof_offsets.LoseData(); +} + +void ParFiniteElementSpace::ConstructTrueDofs() +{ + int i, gr; + int n = GetVSize(); + int ng = pmesh -> GetNGroups(); + + int nvd, ned, nfd; + Array dofs; + + Table group_ldof; + int group_ldof_counter; + Array j_group_ltdof; + + int request_counter; + MPI_Request *requests; + MPI_Status *statuses; + +#if 0 + MPI_Barrier (MPI_COMM_WORLD); + cout << MyRank << ": group_lproc :" << endl; + pmesh -> group_lproc.Print (cout); + cout << MyRank << ": lproc_proc :" << endl; + pmesh -> lproc_proc.Print (cout, 1); + cout << MyRank << ": groupmaster_lproc :" << endl; + pmesh -> groupmaster_lproc.Print (cout, 1); + MPI_Barrier (MPI_COMM_WORLD); +#endif + + nvd = fec->DofForGeometry(Geometry::POINT); + ned = fec->DofForGeometry(Geometry::SEGMENT); + nfd = (fdofs) ? (fdofs[1]-fdofs[0]) : (0); + + // Define ldof_group and mark ldof_ltdof with + // -1 for ldof that is ours + // -2 for ldof that is in a group with another master + ldof_group.SetSize(n); + ldof_ltdof.SetSize(n); + group_ldof.SetDims(ng, n); + + ldof_group = 0; + ldof_ltdof = -1; + + ldof_sign.SetSize(GetNDofs()); + ldof_sign = 1; + + request_counter = 0; + group_ldof_counter = 0; + group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0; + for (gr = 1; gr < ng; gr++) + { + int j, k, l, m, o, nv, ne, nf; + const int *ind; + + nv = pmesh -> GroupNVertices(gr); + ne = pmesh -> GroupNEdges(gr); + nf = pmesh -> GroupNFaces(gr); + + // vertices + if (nvd > 0) + for (j = 0; j < nv; j++) + { + k = pmesh -> GroupVertex(gr, j); + + dofs.SetSize(nvd); + m = nvd * k; + for (l = 0; l < nvd; l++, m++) + dofs[l] = m; + + DofsToVDofs(dofs); + + for (l = 0; l < dofs.Size(); l++) + ldof_group[dofs[l]] = gr; + + if (pmesh -> groupmaster_lproc[gr] != 0) // we are not the master + for (l = 0; l < dofs.Size(); l++) + ldof_ltdof[dofs[l]] = -2; + + for (l = 0; l < dofs.Size(); l++) + group_ldof.GetJ()[group_ldof_counter++] = dofs[l]; + } + + // edges + if (ned > 0) + for (j = 0; j < ne; j++) + { + pmesh -> GroupEdge(gr, j, k, o); + + dofs.SetSize(ned); + m = nvdofs+k*ned; + ind = fec->DofOrderForOrientation(Geometry::SEGMENT, o); + for (l = 0; l < ned; l++) + if (ind[l] < 0) + { + dofs[l] = m + (-1-ind[l]); + ldof_sign[dofs[l]] = -1; + } + else + dofs[l] = m + ind[l]; + + DofsToVDofs(dofs); + + for (l = 0; l < dofs.Size(); l++) + ldof_group[dofs[l]] = gr; + + if (pmesh -> groupmaster_lproc[gr] != 0) // we are not the master + for (l = 0; l < dofs.Size(); l++) + ldof_ltdof[dofs[l]] = -2; + + for (l = 0; l < dofs.Size(); l++) + group_ldof.GetJ()[group_ldof_counter++] = dofs[l]; + } + + // faces + if (nfd > 0) + for (j = 0; j < nf; j++) + { + pmesh -> GroupFace(gr, j, k, o); + + dofs.SetSize(nfd); + m = nvdofs+nedofs+fdofs[k]; + ind = fec->DofOrderForOrientation( + mesh->GetFaceBaseGeometry(k), o); + for (l = 0; l < nfd; l++) + if (ind[l] < 0) + { + dofs[l] = m + (-1-ind[l]); + ldof_sign[dofs[l]] = -1; + } + else + dofs[l] = m + ind[l]; + + DofsToVDofs(dofs); + + for (l = 0; l < dofs.Size(); l++) + ldof_group[dofs[l]] = gr; + + if (pmesh -> groupmaster_lproc[gr] != 0) // we are not the master + for (l = 0; l < dofs.Size(); l++) + ldof_ltdof[dofs[l]] = -2; + + for (l = 0; l < dofs.Size(); l++) + group_ldof.GetJ()[group_ldof_counter++] = dofs[l]; + } + + group_ldof.GetI()[gr+1] = group_ldof_counter; + + if (group_ldof.RowSize(gr) != 0) + if (pmesh -> groupmaster_lproc[gr] != 0) // we are not the master + request_counter++; + else + request_counter += pmesh -> group_lproc.RowSize(gr)-1; + } + + // count ltdof_size + ltdof_size = 0; + for (i = 0; i < n; i++) + if (ldof_ltdof[i] == -1) + ldof_ltdof[i] = ltdof_size++; + + j_group_ltdof.SetSize(group_ldof_counter); // send and receive buffers + + if (group_ldof_counter > 0) + { + requests = new MPI_Request[request_counter]; + statuses = new MPI_Status[request_counter]; + + request_counter = 0; + for (gr = 1; gr < ng; gr++) { + + // ignore groups without dofs + if (group_ldof.RowSize(gr) == 0) + continue; + + if (pmesh -> groupmaster_lproc[gr] != 0) // we are not the master + { + MPI_Irecv(&j_group_ltdof[group_ldof.GetI()[gr]], + group_ldof.RowSize(gr), + MPI_INT, + pmesh -> lproc_proc[pmesh -> groupmaster_lproc[gr]], + 40822 + pmesh -> group_mgroup[gr], + MyComm, + &requests[request_counter]); + request_counter++; + } + else // we are the master + { + // fill send buffer + for (i = group_ldof.GetI()[gr]; i < group_ldof.GetI()[gr+1]; i++) + j_group_ltdof[i] = ldof_ltdof[group_ldof.GetJ()[i]]; + + for (i = pmesh -> group_lproc.GetI()[gr]; + i < pmesh -> group_lproc.GetI()[gr+1]; i++) + { + if (pmesh -> group_lproc.GetJ()[i] != 0) + { + MPI_Isend(&j_group_ltdof[group_ldof.GetI()[gr]], + group_ldof.RowSize (gr), + MPI_INT, + pmesh -> lproc_proc[pmesh -> group_lproc.GetJ()[i]], + 40822 + pmesh -> group_mgroup[gr], + MyComm, + &requests[request_counter]); + request_counter++; + } + } + } + } + + MPI_Waitall(request_counter, requests, statuses); + + delete [] statuses; + delete [] requests; + } + + // set ldof_ltdof for groups that have another master + for (gr = 1; gr < ng; gr++) + if (pmesh -> groupmaster_lproc[gr] != 0) // we are not the master + { + for (i = group_ldof.GetI()[gr]; i < group_ldof.GetI()[gr+1]; i++) + ldof_ltdof[group_ldof.GetJ()[i]] = j_group_ltdof[i]; + } +} + +void ParFiniteElementSpace::Update() +{ + FiniteElementSpace::Update(); + + ldof_group.DeleteAll(); + ldof_ltdof.DeleteAll(); + dof_offsets.DeleteAll(); + tdof_offsets.DeleteAll(); + ldof_sign.DeleteAll(); + delete P; + P = NULL; + ConstructTrueDofs(); + GenerateGlobalOffsets(); +} + +FiniteElementSpace *ParFiniteElementSpace::SaveUpdate() +{ + ParFiniteElementSpace *cpfes = new ParFiniteElementSpace(*this); + Constructor(); + ConstructTrueDofs(); + GenerateGlobalOffsets(); + return cpfes; +} + +#endif diff --git a/fem/pfespace.hpp b/fem/pfespace.hpp new file mode 100644 index 0000000000..0f1137f93c --- /dev/null +++ b/fem/pfespace.hpp @@ -0,0 +1,103 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_PFESPACE +#define MFEM_PFESPACE + +/// Abstract parallel finite element space. +class ParFiniteElementSpace : public FiniteElementSpace +{ +private: + /// MPI data. + MPI_Comm MyComm; + int NRanks, MyRank; + + /// Parallel mesh. + ParMesh *pmesh; + + /// Number of true dofs in this processor (local true dofs). + int ltdof_size; + + /// The group of each local dof. + Array ldof_group; + + /// For a local dof: the local true dof number in the master of its group. + Array ldof_ltdof; + + /// Offsets for the dofs in each processor in global numbering. + Array dof_offsets; + + /// Offsets for the true dofs in each processor in global numbering. + Array tdof_offsets; + + /// The sign of the basis functions at the local dofs. + Array ldof_sign; + + /// The matrix P (interpolation from true dof to dof). + HypreParMatrix *P; + + /** Create a parallel FE space stealing all data (except RefData) from the + given FE space. This is used in SaveUpdate(). */ + ParFiniteElementSpace(ParFiniteElementSpace &pf); + +public: + ParFiniteElementSpace(ParMesh *pm, FiniteElementCollection *f, + int dim = 1, int order = Ordering::byNODES); + + MPI_Comm GetComm() { return MyComm; } + int GetNRanks() { return NRanks; } + int GetMyRank() { return MyRank; } + + int TrueVSize() { return ltdof_size; } + int *GetDofOffsets() { return dof_offsets; } + int *GetTrueDofOffsets() { return tdof_offsets; } + int GetDofSign(int i) { return ldof_sign[i]; } + + /// Returns indexes of degrees of freedom in array dofs for i'th element. + virtual void GetElementDofs(int i, Array &dofs) const; + + /// Returns indexes of degrees of freedom for i'th boundary element. + virtual void GetBdrElementDofs(int i, Array &dofs) const; + + /// Construct dof_offsets and tdof_offsets using global communication. + void GenerateGlobalOffsets(); + + /// Construct ldof_group and ldof_ltdof. + void ConstructTrueDofs(); + + /// The dof-to-true dof interpolation matrix + HypreParMatrix *Dof_TrueDof_Matrix(); + + /// Scale a vector in the range of P + void DivideByGroupSize(double * vec); + + /// Determine the boundary degrees of freedom + virtual void GetEssentialVDofs(Array &bdr_attr_is_ess, + Array &ess_dofs); + + /** If the given ldof is owned by the current processor, return its local + tdof number, otherwise return -1 */ + int GetLocalTDofNumber(int ldof); + /// Returns the global tdof number of the given local degree of freedom + int GetGlobalTDofNumber(int ldof); + + void Lose_Dof_TrueDof_Matrix(); + void LoseDofOffsets() { dof_offsets.LoseData(); } + void LoseTrueDofOffsets() { tdof_offsets.LoseData(); } + + virtual void Update(); + /// Return a copy of the current FE space and update + virtual FiniteElementSpace *SaveUpdate(); + + virtual ~ParFiniteElementSpace() { if (P) delete P; } +}; + +#endif diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp new file mode 100644 index 0000000000..f747028738 --- /dev/null +++ b/fem/pgridfunc.cpp @@ -0,0 +1,223 @@ +// 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.googlecode.com. +// +// 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. + +#ifdef MFEM_USE_MPI + +#include "fem.hpp" + +ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf) +{ + fes = pfes = pf; + SetDataAndSize(gf->GetData(), gf->Size()); +} + +ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf, HypreParVector *tv) + : GridFunction(pf), pfes(pf) +{ + Distribute(tv); +} + +ParGridFunction::ParGridFunction(ParMesh *pmesh, GridFunction *gf) +{ + // duplicate the FiniteElementCollection from 'gf' + fec = FiniteElementCollection::New(gf->FESpace()->FEColl()->Name()); + fes = pfes = new ParFiniteElementSpace(pmesh, fec, gf->FESpace()->GetVDim(), + gf->FESpace()->GetOrdering()); + SetSize(pfes->GetVSize()); +} + +void ParGridFunction::Distribute(HypreParVector *tv) +{ + int nproc = pfes->GetNRanks(); + int *dof_off = pfes->GetDofOffsets(); + + // vector on (all) dofs + HypreParVector *v; + if (HYPRE_AssumedPartitionCheck()) + v = new HypreParVector(dof_off[2], data, dof_off); + else + v = new HypreParVector(dof_off[nproc], data, dof_off); + + pfes->Dof_TrueDof_Matrix()->Mult(*tv, *v); + + delete v; +} + +HypreParVector * ParGridFunction::ParallelAverage() +{ + int nproc = pfes->GetNRanks(); + int *dof_off = pfes->GetDofOffsets(); + int *tdof_off = pfes->GetTrueDofOffsets(); + + // vector on true dofs + HypreParVector *tv; + if (HYPRE_AssumedPartitionCheck()) + tv = new HypreParVector(tdof_off[2], tdof_off); + else + tv = new HypreParVector(tdof_off[nproc], tdof_off); + + // vector on (all) dofs + HypreParVector *v; + if (HYPRE_AssumedPartitionCheck()) + v = new HypreParVector(dof_off[2], data, dof_off); + else + v = new HypreParVector(dof_off[nproc], data, dof_off); + + pfes->Dof_TrueDof_Matrix()->MultTranspose(*v, *tv); + + delete v; + + pfes->DivideByGroupSize(*tv); + + return tv; +} + +double ParGridFunction::ComputeL2Error(Coefficient *exsol[], + const IntegrationRule *irs[]) const +{ + double lerr, gerr; + + lerr = GridFunction::ComputeL2Error(exsol, irs); + lerr *= lerr; + + MPI_Allreduce(&lerr, &gerr, 1, MPI_DOUBLE, MPI_SUM, pfes->GetComm()); + + return sqrt(gerr); +} + +double ParGridFunction::ComputeL2Error(VectorCoefficient &exsol, + const IntegrationRule *irs[], + Array *elems) const +{ + double lerr, gerr; + + lerr = GridFunction::ComputeL2Error(exsol, irs, elems); + lerr *= lerr; + + MPI_Allreduce(&lerr, &gerr, 1, MPI_DOUBLE, MPI_SUM, pfes->GetComm()); + + return sqrt(gerr); +} + +void ParGridFunction::SaveAsOne(ostream &out) +{ + int i, p; + + MPI_Comm MyComm; + MPI_Status status; + int MyRank, NRanks; + + MyComm = pfes -> GetComm(); + + MPI_Comm_size(MyComm, &NRanks); + MPI_Comm_rank(MyComm, &MyRank); + + double **values = new double*[NRanks]; + int *nv = new int[NRanks]; + int *nvdofs = new int[NRanks]; + int *nedofs = new int[NRanks]; + int *nfdofs = new int[NRanks]; + int *nrdofs = new int[NRanks]; + + values[0] = data; + nv[0] = pfes -> GetVSize(); + nvdofs[0] = pfes -> GetNVDofs(); + nedofs[0] = pfes -> GetNEDofs(); + nfdofs[0] = pfes -> GetNFDofs(); + + if (MyRank == 0) + { + pfes -> Save(out); + out << endl; + + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv[p], 1, MPI_INT, p, 455, MyComm, &status); + MPI_Recv(&nvdofs[p], 1, MPI_INT, p, 456, MyComm, &status); + MPI_Recv(&nedofs[p], 1, MPI_INT, p, 457, MyComm, &status); + MPI_Recv(&nfdofs[p], 1, MPI_INT, p, 458, MyComm, &status); + values[p] = new double[nv[p]]; + MPI_Recv(values[p], nv[p], MPI_DOUBLE, p, 460, MyComm, &status); + } + + int vdim = pfes -> GetVDim(); + + for (p = 0; p < NRanks; p++) + nrdofs[p] = nv[p]/vdim - nvdofs[p] - nedofs[p] - nfdofs[p]; + + if (pfes->GetOrdering() == Ordering::byNODES) + { + for (int d = 0; d < vdim; d++) + { + for (p = 0; p < NRanks; p++) + for (i = 0; i < nvdofs[p]; i++) + out << *values[p]++ << endl; + + for (p = 0; p < NRanks; p++) + for (i = 0; i < nedofs[p]; i++) + out << *values[p]++ << endl; + + for (p = 0; p < NRanks; p++) + for (i = 0; i < nfdofs[p]; i++) + out << *values[p]++ << endl; + + for (p = 0; p < NRanks; p++) + for (i = 0; i < nrdofs[p]; i++) + out << *values[p]++ << endl; + } + } + else + { + for (p = 0; p < NRanks; p++) + for (i = 0; i < nvdofs[p]; i++) + for (int d = 0; d < vdim; d++) + out << *values[p]++ << endl; + + for (p = 0; p < NRanks; p++) + for (i = 0; i < nedofs[p]; i++) + for (int d = 0; d < vdim; d++) + out << *values[p]++ << endl; + + for (p = 0; p < NRanks; p++) + for (i = 0; i < nfdofs[p]; i++) + for (int d = 0; d < vdim; d++) + out << *values[p]++ << endl; + + for (p = 0; p < NRanks; p++) + for (i = 0; i < nrdofs[p]; i++) + for (int d = 0; d < vdim; d++) + out << *values[p]++ << endl; + } + + for (p = 1; p < NRanks; p++) + { + values[p] -= nv[p]; + delete [] values[p]; + } + } + else + { + MPI_Send(&nv[0], 1, MPI_INT, 0, 455, MyComm); + MPI_Send(&nvdofs[0], 1, MPI_INT, 0, 456, MyComm); + MPI_Send(&nedofs[0], 1, MPI_INT, 0, 457, MyComm); + MPI_Send(&nfdofs[0], 1, MPI_INT, 0, 458, MyComm); + MPI_Send(data, nv[0], MPI_DOUBLE, 0, 460, MyComm); + } + + delete [] values; + delete [] nv; + delete [] nvdofs; + delete [] nedofs; + delete [] nfdofs; + delete [] nrdofs; +} + +#endif diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp new file mode 100644 index 0000000000..c8eb273f12 --- /dev/null +++ b/fem/pgridfunc.hpp @@ -0,0 +1,60 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_PGRIDFUNC +#define MFEM_PGRIDFUNC + +/// Class for parallel grid function +class ParGridFunction : public GridFunction +{ +protected: + ParFiniteElementSpace *pfes; + +public: + ParGridFunction(ParFiniteElementSpace *pf) : GridFunction(pf), pfes(pf) { } + + /** Construct a ParGridFunction corresponding to *pf and the data from *gf + which is a local GridFunction on each processor. */ + ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf); + + /** Creates grid function on (all) dofs from a given vector on the true dofs, + i.e. P tv. */ + ParGridFunction(ParFiniteElementSpace *pf, HypreParVector *tv); + + /** Construct a ParGridFunction from the given serial GridFunction. + The data from 'gf' is NOT copied. */ + ParGridFunction(ParMesh *pmesh, GridFunction *gf); + + /** Set the grid function on (all) dofs from a given vector on the + true dofs, i.e. P tv. */ + void Distribute(HypreParVector *tv); + + /// Short semantic for Distribute + ParGridFunction &operator=(HypreParVector &tv) + { Distribute(&tv); return (*this); } + + /// Returns the vector averaged on the true dofs. + HypreParVector *ParallelAverage(); + + double ComputeL2Error(Coefficient *exsol[], + const IntegrationRule *irs[] = NULL) const; + + double ComputeL2Error(VectorCoefficient &exsol, + const IntegrationRule *irs[] = NULL, + Array *elems = NULL) const; + + /// Merge the local grid functions + void SaveAsOne(ostream &out = cout); + + virtual ~ParGridFunction() { } +}; + +#endif diff --git a/fem/plinearform.cpp b/fem/plinearform.cpp new file mode 100644 index 0000000000..007da1b112 --- /dev/null +++ b/fem/plinearform.cpp @@ -0,0 +1,50 @@ +// 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.googlecode.com. +// +// 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. + +#ifdef MFEM_USE_MPI + +#include "fem.hpp" + +void ParLinearForm::Update(ParFiniteElementSpace *pf) +{ + if (pf) pfes = pf; + + LinearForm::Update(pfes); +} + +HypreParVector *ParLinearForm::ParallelAssemble() +{ + int nproc = pfes -> GetNRanks(); + int *dof_off = pfes -> GetDofOffsets(); + int *tdof_off = pfes -> GetTrueDofOffsets(); + + // vector on (all) dofs + HypreParVector *v; + if (HYPRE_AssumedPartitionCheck()) + v = new HypreParVector(dof_off[2], data, dof_off); + else + v = new HypreParVector(dof_off[nproc], data, dof_off); + + // vector on true dofs + HypreParVector *tv; + if (HYPRE_AssumedPartitionCheck()) + tv = new HypreParVector(tdof_off[2], tdof_off); + else + tv = new HypreParVector(tdof_off[nproc], tdof_off); + + pfes -> Dof_TrueDof_Matrix() -> MultTranspose(*v,*tv); + + delete v; + + return tv; +} + +#endif diff --git a/fem/plinearform.hpp b/fem/plinearform.hpp new file mode 100644 index 0000000000..8240a3c893 --- /dev/null +++ b/fem/plinearform.hpp @@ -0,0 +1,30 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_PLINEARFORM +#define MFEM_PLINEARFORM + +/// Class for parallel linear form +class ParLinearForm : public LinearForm +{ +protected: + ParFiniteElementSpace *pfes; + +public: + ParLinearForm(ParFiniteElementSpace *pf) : LinearForm(pf) { pfes = pf; } + + void Update(ParFiniteElementSpace *pf = NULL); + + /// Returns the vector assembled on the true dofs, i.e. P^t v. + HypreParVector *ParallelAssemble(); +}; + +#endif diff --git a/general/array.cpp b/general/array.cpp index 05bd96b048..b0f974375d 100644 --- a/general/array.cpp +++ b/general/array.cpp @@ -37,15 +37,15 @@ BaseArray::~BaseArray() delete [] (char*)data; } -void BaseArray::GrowSize (int minsize, int elementsize) +void BaseArray::GrowSize(int minsize, int elementsize) { void *p; int nsize = (inc > 0) ? abs(allocsize) + inc : 2 * abs(allocsize); if (nsize < minsize) nsize = minsize; - p = new char [nsize * elementsize]; + p = new char[nsize * elementsize]; if (size > 0) - memcpy (p, data, size * elementsize); + memcpy(p, data, size * elementsize); if (allocsize > 0) delete [] (char*)data; data = p; @@ -53,7 +53,7 @@ void BaseArray::GrowSize (int minsize, int elementsize) } template -void Array::Print (ostream & out, int width) +void Array::Print(ostream &out, int width) { for (int i = 0; i < size; i++) { @@ -66,25 +66,21 @@ void Array::Print (ostream & out, int width) } template -void Array::Save(ostream & out) +void Array::Save(ostream &out) { - int i; - out << size << '\n'; - - for (i = 0; i < size; i++) + for (int i = 0; i < size; i++) out << operator[](i) << '\n'; } template T Array::Max() { - int i; T max; if (size > 0) max = operator[](0); - for (i = 1; i < size; i++) + for (int i = 1; i < size; i++) if (max < operator[](i)) max = operator[](i); @@ -92,7 +88,7 @@ T Array::Max() } template -int Compare (const void *p, const void *q) +int Compare(const void *p, const void *q) { if (*((T*)p) < *((T*)q)) return -1; if (*((T*)q) < *((T*)p)) return +1; @@ -103,7 +99,7 @@ template void Array::Sort() { // qsort((T*)data,0,size-1); - qsort (data, size, sizeof(T), Compare); // use qsort from stdlib.h + qsort(data, size, sizeof(T), Compare); // use qsort from stdlib.h } template class Array; diff --git a/general/array.hpp b/general/array.hpp index 754b14f4a4..96034b29a7 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -25,7 +25,7 @@ class BaseArray { protected: /// Pointer to data - void * data; + void *data; /// Size of the array int size; /// Size of the allocated memory @@ -42,14 +42,14 @@ protected: /** Increases the allocsize of the array to be at least minsize. The current content of the array is copied to the newly allocated space. minsize must be > abs(allocsize). */ - void GrowSize (int minsize, int elementsize); + void GrowSize(int minsize, int elementsize); }; template class Array; template -void Swap (Array &, Array &); +void Swap(Array &, Array &); /** Abstract data type Array. @@ -63,11 +63,11 @@ template class Array : public BaseArray { public: - friend void Swap (Array &, Array &); + friend void Swap(Array &, Array &); /// Creates array of asize elements inline Array(int asize = 0, int ainc = 0) - : BaseArray (asize, ainc, sizeof (T)) { } + : BaseArray(asize, ainc, sizeof (T)) { } /** Creates array using an existing c-array of asize elements; allocsize is set to -asize to indicate that the data will not @@ -101,25 +101,25 @@ public: inline void SetSize(int nsize); /// Access element - inline T & operator[] (int i); + inline T & operator[](int i); /// Access const element - inline const T & operator[] (int i) const; + inline const T &operator[](int i) const; /// Append element to array, resize if necessary - inline int Append (const T & el); + inline int Append(const T & el); /// Append another array to this array, resize if necessary - inline int Append (const Array & els); + inline int Append(const Array &els); /// Prepend an element to the array, resize if necessary - inline int Prepend (const T & el); + inline int Prepend(const T &el); /// Return the last element in the array - inline T & Last(); + inline T &Last(); /// Append element when it is not yet in the array, return index - inline int Union (const T & el); + inline int Union(const T & el); /// Delete the last entry inline void DeleteLast() { size--; } @@ -134,16 +134,16 @@ public: inline void Copy(Array ©) { copy.SetSize(Size()); - memcpy(copy.GetData(),GetData(),Size()*sizeof(T)); + memcpy(copy.GetData(), GetData(), Size()*sizeof(T)); } - inline void GetSubArray (int offset, int sa_size, Array &sa); + inline void GetSubArray(int offset, int sa_size, Array &sa); /// Prints array to stream with width elements per row - inline void Print(ostream & out, int width); + void Print(ostream &out, int width); /// Prints array to stream out - void Save(ostream & out); + void Save(ostream &out); /** Finds the maximal element in the array. (uses the comparison operator '<' for class T) */ @@ -152,18 +152,18 @@ public: /// Sorts the array. void Sort(); - inline void operator= (const T &a); + inline void operator=(const T &a); private: /// Array copy is not supported - Array & operator= (Array &); + Array &operator=(Array &); /// Array copy is not supported - Array (const Array &); + Array(const Array &); }; template -inline void Swap (Array &a, Array &b) +inline void Swap(Array &a, Array &b) { int s; void *data; @@ -175,15 +175,15 @@ inline void Swap (Array &a, Array &b) } template -inline void Array :: SetSize(int nsize) +inline void Array::SetSize(int nsize) { if (nsize > abs(allocsize)) - GrowSize (nsize, sizeof(T)); + GrowSize(nsize, sizeof(T)); size = nsize; } template -inline T & Array :: operator[] (int i) +inline T &Array::operator[](int i) { #ifdef MFEM_DEBUG if (i < 0 || i >= size) @@ -196,7 +196,7 @@ inline T & Array :: operator[] (int i) } template -inline const T & Array :: operator[] (int i) const +inline const T &Array::operator[](int i) const { #ifdef MFEM_DEBUG if (i < 0 || i >= size) @@ -209,19 +209,19 @@ inline const T & Array :: operator[] (int i) const } template -inline int Array :: Append (const T & el) +inline int Array::Append(const T &el) { - SetSize (size+1); + SetSize(size+1); ((T*)data)[size-1] = el; return size; } template -inline int Array :: Append (const Array & els) +inline int Array::Append(const Array & els) { int old_size = size; - SetSize (size + els.Size()); + SetSize(size + els.Size()); for (int i = 0; i < els.Size(); i++) ((T*)data)[old_size+i] = els[i]; return size; @@ -229,9 +229,9 @@ inline int Array :: Append (const Array & els) template -inline int Array :: Prepend (const T & el) +inline int Array::Prepend(const T &el) { - SetSize (size+1); + SetSize(size+1); for (int i = size-1; i > 0; i--) ((T*)data)[i] = ((T*)data)[i-1]; ((T*)data)[0] = el; @@ -240,21 +240,21 @@ inline int Array :: Prepend (const T & el) template -inline T & Array :: Last() +inline T &Array::Last() { #ifdef MFEM_DEBUG if (size < 1) - mfem_error ("Array :: Last()"); + mfem_error("Array::Last()"); #endif return ((T*)data)[size-1]; } template -inline int Array :: Union (const T & el) +inline int Array::Union(const T &el) { - int i=0; - while ((i::DeleteFirst(const T &el) } template -inline void Array :: DeleteAll () +inline void Array::DeleteAll() { if (allocsize > 0) delete [] (char*)data; @@ -282,15 +282,15 @@ inline void Array :: DeleteAll () } template -inline void Array::GetSubArray (int offset, int sa_size, Array &sa) +inline void Array::GetSubArray(int offset, int sa_size, Array &sa) { - sa.SetSize (sa_size); + sa.SetSize(sa_size); for (int i = 0; i < sa_size; i++) sa[i] = (*this)[offset+i]; } template -inline void Array::operator= (const T &a) +inline void Array::operator=(const T &a) { for (int i = 0; i < size; i++) ((T*)data)[i] = a; diff --git a/general/sets.cpp b/general/sets.cpp new file mode 100644 index 0000000000..e688e540e8 --- /dev/null +++ b/general/sets.cpp @@ -0,0 +1,114 @@ +// 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.googlecode.com. +// +// 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. + +#include "array.hpp" +#include "table.hpp" +#include "sets.hpp" + + +IntegerSet::IntegerSet(IntegerSet &s) + : me(s.me.Size()) +{ + for (int i = 0; i < me.Size(); i++) + me[i] = s.me[i]; +} + + +int IntegerSet::operator== (IntegerSet &s) +{ + if (me.Size() != s.me.Size()) + return 0; + + for (int i = 0; i < me.Size(); i++) + if (me[i] != s.me[i]) + return 0; + + return 1; +} + +int IntegerSet::PickRandomElement() +{ + int i, size = me.Size(); + unsigned int seed = 0; + + for (i = 0; i < size; i++) + seed += me[i]; + + srand(seed); + + return me[rand()/(RAND_MAX/size)]; +} + +void IntegerSet::Recreate(const int n, const int *p) +{ + int i, j; + + me.SetSize(n); + + for (i = 0; i < n; i++) + me[i] = p[i]; + + me.Sort(); + + for (j = 0, i = 1; i < n; i++) + if (me[i] != me[j]) + me[++j] = me[i]; + + me.SetSize(j+1); +} + + +int ListOfIntegerSets::Insert(IntegerSet &s) +{ + for (int i = 0; i < TheList.Size(); i++) + if (*TheList[i] == s) + return i; + + TheList.Append(new IntegerSet(s)); + + return TheList.Size()-1; +} + +int ListOfIntegerSets::Lookup(IntegerSet &s) +{ + for (int i = 0; i < TheList.Size(); i++) + if (*TheList[i] == s) + return i; + + mfem_error("ListOfIntegerSets::Lookup ()"); + return -1; +} + +void ListOfIntegerSets::AsTable(Table & t) +{ + int i; + + t.MakeI(Size()); + + for (i = 0; i < Size(); i++) + t.AddColumnsInRow(i, TheList[i] -> Size()); + + t.MakeJ(); + + for (i = 0; i < Size(); i++) + { + Array &row = *TheList[i]; + t.AddConnections(i, row.GetData(), row.Size()); + } + + t.ShiftUpI(); +} + +ListOfIntegerSets::~ListOfIntegerSets() +{ + for (int i = 0; i < TheList.Size(); i++) + delete TheList[i]; +} diff --git a/general/sets.hpp b/general/sets.hpp new file mode 100644 index 0000000000..19a7950216 --- /dev/null +++ b/general/sets.hpp @@ -0,0 +1,65 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_SETS +#define MFEM_SETS + +/// A set of integers +class IntegerSet +{ +private: + Array me; + +public: + IntegerSet() { } + + IntegerSet(IntegerSet &s); + + IntegerSet(const int n, const int *p) { Recreate(n, p); } + + int Size() { return me.Size(); } + + operator Array& () { return me; } + + int PickElement() { return me[0]; } + + int PickRandomElement(); + + int operator==(IntegerSet &s); + + void Recreate(const int n, const int *p); +}; + +/// List of integer sets +class ListOfIntegerSets +{ +private: + Array TheList; + +public: + + int Size() { return TheList.Size(); } + + int PickElementInSet(int i) { return TheList[i]->PickElement(); } + + int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); } + + int Insert(IntegerSet &s); + + int Lookup(IntegerSet &s); + + void AsTable(Table &t); + + ~ListOfIntegerSets(); +}; + +#endif + diff --git a/general/table.cpp b/general/table.cpp index ce9c549bc4..d56079c5c0 100644 --- a/general/table.cpp +++ b/general/table.cpp @@ -149,6 +149,16 @@ void Table::GetRow(int i, Array &row) const row[i] = jp[i]; } +void Table::SetIJ(int *newI, int *newJ, int newsize) +{ + delete [] I; + delete [] J; + I = newI; + J = newJ; + if (newsize >= 0) + size = newsize; +} + int Table::Push(int i, int j) { #ifdef MFEM_DEBUG @@ -214,7 +224,7 @@ int Table::Width() const return width + 1; } -void Table::Print(ostream & out, int width) +void Table::Print(ostream & out, int width) const { int i, j; @@ -232,7 +242,7 @@ void Table::Print(ostream & out, int width) out << endl; } -void Table::Save(ostream & out) +void Table::Save(ostream & out) const { int i; diff --git a/general/table.hpp b/general/table.hpp index 0d0dd2d1de..ad6f005589 100644 --- a/general/table.hpp +++ b/general/table.hpp @@ -75,15 +75,18 @@ public: /// Return row i in array row (the Table must be finalized) void GetRow(int i, Array &row) const; - int RowSize (int i) const { return I[i+1]-I[i]; }; + int RowSize(int i) const { return I[i+1]-I[i]; } - const int *GetRow (int i) const { return J+I[i]; }; + const int *GetRow(int i) const { return J+I[i]; } + int *GetRow(int i) { return J+I[i]; } int *GetI() { return I; }; int *GetJ() { return J; }; const int *GetI() const { return I; }; const int *GetJ() const { return J; }; + void SetIJ(int *newI, int *newJ, int newsize = -1); + /** Establish connection between element i and element j in the table. The return value is the index of the connection. It returns -1 if it fails to establish the connection. Possibilities are there is not @@ -105,9 +108,9 @@ public: void LoseData() { size = -1; I = J = NULL; } /// Prints the table to stream out. - void Print(ostream & out = cout, int width = 4); + void Print(ostream & out = cout, int width = 4) const; - void Save(ostream & out); + void Save(ostream & out) const; /// Destroys Table. ~Table(); diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp new file mode 100644 index 0000000000..16331548a8 --- /dev/null +++ b/linalg/hypre.cpp @@ -0,0 +1,1012 @@ +// 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.googlecode.com. +// +// 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. + +#ifdef MFEM_USE_MPI + +#include +#include +#include +#include +#include + +#include "linalg.hpp" + +HypreParVector::HypreParVector(int glob_size, int *col) : Vector() +{ + x = hypre_ParVectorCreate(MPI_COMM_WORLD,glob_size,col); + hypre_ParVectorInitialize(x); + hypre_ParVectorSetPartitioningOwner(x,0); + // The data will be destroyed by hypre (this is the default) + hypre_ParVectorSetDataOwner(x,1); + hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1); + SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), + hypre_VectorSize(hypre_ParVectorLocalVector(x))); + own_ParVector = 1; +} + +HypreParVector::HypreParVector(int glob_size, double *_data, int *col) + : Vector() +{ + x = hypre_ParVectorCreate(MPI_COMM_WORLD,glob_size,col); + hypre_ParVectorSetDataOwner(x,1); // owns the seq vector + hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),0); + hypre_ParVectorSetPartitioningOwner(x,0); + hypre_VectorData(hypre_ParVectorLocalVector(x)) = _data; + // If hypre_ParVectorLocalVector(x) is non-NULL, hypre_ParVectorInitialize(x) + // does not allocate memory! + hypre_ParVectorInitialize(x); + SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), + hypre_VectorSize(hypre_ParVectorLocalVector(x))); + own_ParVector = 1; +} + +HypreParVector::HypreParVector(const HypreParVector &y) : Vector() +{ + x = hypre_ParVectorCreate(MPI_COMM_WORLD, y.x -> global_size, + y.x -> partitioning); + hypre_ParVectorInitialize(x); + hypre_ParVectorSetPartitioningOwner(x,0); + hypre_ParVectorSetDataOwner(x,1); + hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1); + SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), + hypre_VectorSize(hypre_ParVectorLocalVector(x))); + own_ParVector = 1; +} + +HypreParVector::HypreParVector(HYPRE_ParVector y) : Vector() +{ + x = (hypre_ParVector *) y; + SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), + hypre_VectorSize(hypre_ParVectorLocalVector(x))); + own_ParVector = 0; +} + +HypreParVector::operator hypre_ParVector*() const +{ + return x; +} + +HypreParVector::operator HYPRE_ParVector() const +{ + return (HYPRE_ParVector) x; +} + +Vector * HypreParVector::GlobalVector() +{ + hypre_Vector *hv = hypre_ParVectorToVectorAll(*this); + Vector *v = new Vector(hv->data, hv->size); + v->MakeDataOwner(); + hypre_SeqVectorSetDataOwner(hv,0); + hypre_SeqVectorDestroy(hv); + return v; +} + +HypreParVector& HypreParVector::operator=(double d) +{ + hypre_ParVectorSetConstantValues(x,d); + return *this; +} + +HypreParVector& HypreParVector::operator=(const HypreParVector &y) +{ +#ifdef MFEM_DEBUG + if (size != y.Size()) + cerr << "HypreParVector::operator=" << endl; +#endif + + for (int i = 0; i < size; i++) + data[i] = y.data[i]; + return *this; +} + +void HypreParVector::SetData(double *_data) +{ + Vector::data = hypre_VectorData(hypre_ParVectorLocalVector(x)) = _data; +} + +int HypreParVector::Randomize(int seed) +{ + return hypre_ParVectorSetRandomValues(x,seed); +} + +void HypreParVector::Print(const char *fname) +{ + hypre_ParVectorPrint(x,fname); +} + +HypreParVector::~HypreParVector() +{ + if (own_ParVector) + hypre_ParVectorDestroy(x); +} + + +double InnerProduct(HypreParVector *x, HypreParVector *y) +{ + return hypre_ParVectorInnerProd(*x, *y); +} + +double InnerProduct(HypreParVector &x, HypreParVector &y) +{ + return hypre_ParVectorInnerProd(x, y); +} + + +HypreParMatrix::HypreParMatrix(int size, int *row, SparseMatrix *diag) + : Operator(size) +{ + A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, size, size, row, row, + 0, diag->NumNonZeroElems(), 0); + hypre_ParCSRMatrixSetDataOwner(A,0); + hypre_ParCSRMatrixSetRowStartsOwner(A,0); + hypre_ParCSRMatrixSetColStartsOwner(A,0); + + hypre_CSRMatrixSetDataOwner(A->diag,0); + hypre_CSRMatrixI(A->diag) = diag->GetI(); + hypre_CSRMatrixJ(A->diag) = diag->GetJ(); + hypre_CSRMatrixData(A->diag) = diag->GetData(); + hypre_CSRMatrixSetRownnz(A->diag); + + hypre_CSRMatrixSetDataOwner(A->offd,1); + hypre_CSRMatrixI(A->offd) = new int[diag->Size()+1]; + hypre_CSRMatrixJ(A->offd) = NULL; + for (int k = 0; k < diag->Size()+1; k++) + (A->offd)->i[k] = 0; + + /* Don't need to call these, since they allocate memory only + if it was not already allocated */ + // hypre_CSRMatrixInitialize(A->diag); + // hypre_ParCSRMatrixInitialize(A); + + hypre_ParCSRMatrixSetNumNonzeros(A); + + hypre_MatvecCommPkgCreate(A); + + CommPkg = NULL; + X = Y = NULL; +} + + +HypreParMatrix::HypreParMatrix(int M, int N, int *row, int *col, + SparseMatrix *diag) +{ + A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, M, N, row, col, + 0, diag->NumNonZeroElems(), 0); + hypre_ParCSRMatrixSetDataOwner(A,0); + hypre_ParCSRMatrixSetRowStartsOwner(A,0); + hypre_ParCSRMatrixSetColStartsOwner(A,0); + + hypre_CSRMatrixSetDataOwner(A->diag,0); + hypre_CSRMatrixI(A->diag) = diag->GetI(); + hypre_CSRMatrixJ(A->diag) = diag->GetJ(); + hypre_CSRMatrixData(A->diag) = diag->GetData(); + hypre_CSRMatrixSetRownnz(A->diag); + + hypre_CSRMatrixSetDataOwner(A->offd,1); + hypre_CSRMatrixI(A->offd) = new int[diag->Size()+1]; + for (int k = 0; k < diag->Size()+1; k++) (A->offd)->i[k] = 0; + + hypre_ParCSRMatrixSetNumNonzeros(A); + + hypre_MatvecCommPkgCreate(A); + + CommPkg = NULL; + X = Y = NULL; + + size = GetNumRows(); +} + +HypreParMatrix::HypreParMatrix(int M, int N, int *row, int *col, + SparseMatrix *diag, SparseMatrix *offd, + int *cmap) +{ + A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, M, N, row, col, + offd->Width(), diag->NumNonZeroElems(), + offd->NumNonZeroElems()); + hypre_ParCSRMatrixSetDataOwner(A,0); + hypre_ParCSRMatrixSetRowStartsOwner(A,0); + hypre_ParCSRMatrixSetColStartsOwner(A,0); + + hypre_CSRMatrixSetDataOwner(A->diag,0); + hypre_CSRMatrixI(A->diag) = diag->GetI(); + hypre_CSRMatrixJ(A->diag) = diag->GetJ(); + hypre_CSRMatrixData(A->diag) = diag->GetData(); + hypre_CSRMatrixSetRownnz(A->diag); + + hypre_CSRMatrixSetDataOwner(A->offd,0); + hypre_CSRMatrixI(A->offd) = offd->GetI(); + hypre_CSRMatrixJ(A->offd) = offd->GetJ(); + hypre_CSRMatrixData(A->offd) = offd->GetData(); + hypre_CSRMatrixSetRownnz(A->offd); + + hypre_ParCSRMatrixColMapOffd(A) = cmap; + + hypre_ParCSRMatrixSetNumNonzeros(A); + + hypre_MatvecCommPkgCreate(A); + + CommPkg = NULL; + X = Y = NULL; + + size = GetNumRows(); +} + +HypreParMatrix::HypreParMatrix(int *row, int *col, SparseMatrix *sm_a) +{ +#ifdef MFEM_DEBUG + if (sm_a == NULL) + mfem_error("HypreParMatrix::HypreParMatrix: sm_a==NULL"); +#endif + + hypre_CSRMatrix *csr_a; + + csr_a = hypre_CSRMatrixCreate(sm_a -> Size(), sm_a -> Width(), + sm_a -> NumNonZeroElems()); + + hypre_CSRMatrixSetDataOwner(csr_a,0); + hypre_CSRMatrixI(csr_a) = sm_a -> GetI(); + hypre_CSRMatrixJ(csr_a) = sm_a -> GetJ(); + hypre_CSRMatrixData(csr_a) = sm_a -> GetData(); + hypre_CSRMatrixSetRownnz(csr_a); + + A = hypre_CSRMatrixToParCSRMatrix(MPI_COMM_WORLD,csr_a,row,col); + + CommPkg = NULL; + X = Y = NULL; + + size = GetNumRows(); + + hypre_MatvecCommPkgCreate(A); +} + +HypreParMatrix::HypreParMatrix(int M, int N, int *row, int *col, + Table *diag) +{ + int nnz = diag->Size_of_connections(); + A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, M, N, row, col, + 0, nnz, 0); + hypre_ParCSRMatrixSetDataOwner(A,1); + hypre_ParCSRMatrixSetRowStartsOwner(A,0); + hypre_ParCSRMatrixSetColStartsOwner(A,0); + + hypre_CSRMatrixSetDataOwner(A->diag,1); + hypre_CSRMatrixI(A->diag) = diag->GetI(); + hypre_CSRMatrixJ(A->diag) = diag->GetJ(); + + hypre_CSRMatrixData(A->diag) = new double[nnz]; + for (int k = 0; k < nnz; k++) + (hypre_CSRMatrixData(A->diag))[k] = 1.0; + + hypre_CSRMatrixSetRownnz(A->diag); + + hypre_CSRMatrixSetDataOwner(A->offd,1); + hypre_CSRMatrixI(A->offd) = new int[diag->Size()+1]; + for (int k = 0; k < diag->Size()+1; k++) (A->offd)->i[k] = 0; + + hypre_ParCSRMatrixSetNumNonzeros(A); + + hypre_MatvecCommPkgCreate(A); + + CommPkg = NULL; + X = Y = NULL; + + size = GetNumRows(); +} + +HypreParMatrix::HypreParMatrix(MPI_Comm comm, int id, int np, + int *row, int *col, + int *i_diag, int *j_diag, + int *i_offd, int *j_offd, + int *cmap, int cmap_size) +{ + int diag_col, offd_col; + + if (HYPRE_AssumedPartitionCheck()) + { + diag_col = i_diag[row[1]-row[0]]; + offd_col = i_offd[row[1]-row[0]]; + + A = hypre_ParCSRMatrixCreate(comm, row[2], col[2], row, col, + cmap_size, diag_col, offd_col); + } + else + { + diag_col = i_diag[row[id+1]-row[id]]; + offd_col = i_offd[row[id+1]-row[id]]; + + A = hypre_ParCSRMatrixCreate(comm, row[np], col[np], row, col, + cmap_size, diag_col, offd_col); + } + + hypre_ParCSRMatrixSetDataOwner(A,1); + hypre_ParCSRMatrixSetRowStartsOwner(A,0); + hypre_ParCSRMatrixSetColStartsOwner(A,0); + + int i; + + double * a_diag = new double[diag_col]; + for (i = 0; i < diag_col; i++) + a_diag[i] = 1.0; + + double * a_offd = new double[offd_col]; + for (i = 0; i < offd_col; i++) + a_offd[i] = 1.0; + + hypre_CSRMatrixSetDataOwner(A->diag,1); + hypre_CSRMatrixI(A->diag) = i_diag; + hypre_CSRMatrixJ(A->diag) = j_diag; + hypre_CSRMatrixData(A->diag) = a_diag; + hypre_CSRMatrixSetRownnz(A->diag); + + hypre_CSRMatrixSetDataOwner(A->offd,1); + hypre_CSRMatrixI(A->offd) = i_offd; + hypre_CSRMatrixJ(A->offd) = j_offd; + hypre_CSRMatrixData(A->offd) = a_offd; + hypre_CSRMatrixSetRownnz(A->offd); + + hypre_ParCSRMatrixColMapOffd(A) = cmap; + + hypre_ParCSRMatrixSetNumNonzeros(A); + + hypre_MatvecCommPkgCreate(A); + + CommPkg = NULL; + X = Y = NULL; + + size = GetNumRows(); +} + +void HypreParMatrix::SetCommPkg(hypre_ParCSRCommPkg *comm_pkg) +{ + CommPkg = comm_pkg; + + if (hypre_ParCSRMatrixCommPkg(A)) + hypre_MatvecCommPkgDestroy(hypre_ParCSRMatrixCommPkg(A)); + + hypre_ParCSRMatrixCommPkg(A) = comm_pkg; +} + +void HypreParMatrix::CheckCommPkg() +{ +#ifdef MFEM_DEBUG + if (CommPkg == NULL || CommPkg != hypre_ParCSRMatrixCommPkg(A)) + cerr << endl << "HypreParMatrix::CheckCommPkg()" << endl; +#endif +} + +void HypreParMatrix::DestroyCommPkg() +{ + if (CommPkg == NULL) + return; + hypre_TFree(CommPkg->send_procs); + hypre_TFree(CommPkg->send_map_starts); + hypre_TFree(CommPkg->send_map_elmts); + hypre_TFree(CommPkg->recv_procs); + hypre_TFree(CommPkg->recv_vec_starts); + if (CommPkg->send_mpi_types) + hypre_TFree(CommPkg->send_mpi_types); + if (CommPkg->recv_mpi_types) + hypre_TFree(CommPkg->recv_mpi_types); + if (hypre_ParCSRMatrixCommPkg(A) == CommPkg) + hypre_ParCSRMatrixCommPkg(A) = NULL; + delete CommPkg; + CommPkg = NULL; +} + +HypreParMatrix::operator hypre_ParCSRMatrix*() +{ + return A; +} + +HypreParMatrix::operator HYPRE_ParCSRMatrix() +{ + return (HYPRE_ParCSRMatrix) A; +} + +hypre_ParCSRMatrix* HypreParMatrix::StealData() +{ + hypre_ParCSRMatrix *R = A; + A = NULL; + return R; +} + +HypreParMatrix * HypreParMatrix::Transpose() +{ + hypre_ParCSRMatrix * At; + hypre_ParCSRMatrixTranspose(A, &At, 1); + hypre_ParCSRMatrixSetNumNonzeros(At); + + hypre_MatvecCommPkgCreate(At); + + return new HypreParMatrix(At); +} + +int HypreParMatrix::Mult(HypreParVector &x, HypreParVector &y, + double a, double b) +{ + return hypre_ParCSRMatrixMatvec(a, A, x, b, y); +} + +void HypreParMatrix::Mult(const Vector &x, Vector &y) const +{ + if (X == NULL) + { + X = new HypreParVector(GetGlobalNumCols(), + x.GetData(), + GetColStarts()); + Y = new HypreParVector(GetGlobalNumRows(), + y.GetData(), + GetRowStarts()); + } + else + { + X -> SetData(x.GetData()); + Y -> SetData(y.GetData()); + } + + hypre_ParCSRMatrixMatvec(1.0, A, *X, 0.0, *Y); +} + +int HypreParMatrix::Mult(HYPRE_ParVector x, HYPRE_ParVector y, + double a, double b) +{ + return hypre_ParCSRMatrixMatvec(a,A,(hypre_ParVector *)x,b,(hypre_ParVector *)y); +} + +int HypreParMatrix::MultTranspose(HypreParVector & x, HypreParVector & y, + double a, double b) +{ + return hypre_ParCSRMatrixMatvecT(a,A,x,b,y); +} + +void HypreParMatrix::Print(const char *fname, int offi, int offj) +{ + hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname); +} + +void HypreParMatrix::Read(const char *fname) +{ + if (A) hypre_ParCSRMatrixDestroy(A); + int io,jo; + hypre_ParCSRMatrixReadIJ(MPI_COMM_WORLD, fname, &io, &jo, &A); + hypre_ParCSRMatrixSetNumNonzeros(A); + + hypre_MatvecCommPkgCreate(A); +} + +HypreParMatrix::~HypreParMatrix() +{ + DestroyCommPkg(); + + if (A) + { + if (hypre_ParCSRMatrixCommPkg(A)) + hypre_MatvecCommPkgDestroy(hypre_ParCSRMatrixCommPkg(A)); + hypre_ParCSRMatrixCommPkg(A) = NULL; + + if (hypre_CSRMatrixOwnsData(A->diag)) + { + hypre_CSRMatrixDestroy(A->diag); + A->diag = NULL; + } + else + { + hypre_TFree(A->diag); + A->diag = NULL; + } + + if (hypre_CSRMatrixOwnsData(A->offd)) + { + hypre_CSRMatrixDestroy(A->offd); + A->offd = NULL; + } + hypre_ParCSRMatrixDestroy(A); + } + + delete X; + delete Y; +} + +HypreParMatrix * ParMult(HypreParMatrix *A, HypreParMatrix *B) +{ + hypre_ParCSRMatrix * ab; + ab = hypre_ParMatmul(*A,*B); + + hypre_MatvecCommPkgCreate(ab); + + return new HypreParMatrix(ab); +} + +HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P) +{ + int P_owns_its_col_starts = + hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P)); + hypre_ParCSRMatrix * rap; + hypre_BoomerAMGBuildCoarseOperator(*P,*A,*P,&rap); + + hypre_ParCSRMatrixSetNumNonzeros(rap); + // hypre_MatvecCommPkgCreate(rap); + if (!P_owns_its_col_starts) + { + /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts + from P (even if it does not own them)! */ + hypre_ParCSRMatrixSetRowStartsOwner(rap,0); + hypre_ParCSRMatrixSetColStartsOwner(rap,0); + } + return new HypreParMatrix(rap); +} + + +HypreSolver::HypreSolver() +{ + size = 0; + + A = NULL; + setup_called = 0; + B = X = NULL; +} + +HypreSolver::HypreSolver(HypreParMatrix *_A) +{ + size = _A -> GetNumRows(); + + A = _A; + setup_called = 0; + B = X = NULL; +} + +void HypreSolver::Mult(const HypreParVector &b, HypreParVector &x) const +{ + if (A == NULL) + { + cerr << "HypreSolver::Mult (...) : HypreParMatrix A is missing" << endl; + return; + } + if (!setup_called) + { + SetupFcn()(*this, *A, b, x); + setup_called = 1; + } + + SolveFcn()(*this, *A, b, x); +} + +void HypreSolver::Mult(const Vector &b, Vector &x) const +{ + if (A == NULL) + { + cerr << "HypreSolver::Mult (...) : HypreParMatrix A is missing" << endl; + return; + } + if (B == NULL) + { + B = new HypreParVector(A -> GetGlobalNumRows(), + b.GetData(), + A -> GetRowStarts()); + X = new HypreParVector(A -> GetGlobalNumCols(), + x.GetData(), + A -> GetColStarts()); + } + else + { + B -> SetData(b.GetData()); + X -> SetData(x.GetData()); + } + + Mult(*B, *X); +} + +HypreSolver::~HypreSolver() +{ + if (B) delete B; + if (X) delete X; +} + + +HyprePCG::HyprePCG(HypreParMatrix &_A) : HypreSolver(&_A) +{ + MPI_Comm comm; + + print_level = 0; + use_zero_initial_iterate = 0; + + HYPRE_ParCSRMatrixGetComm(*A, &comm); + + HYPRE_ParCSRPCGCreate(comm, &pcg_solver); +} + +void HyprePCG::SetTol(double tol) +{ + HYPRE_ParCSRPCGSetTol(pcg_solver, tol); +} + +void HyprePCG::SetMaxIter(int max_iter) +{ + HYPRE_ParCSRPCGSetMaxIter(pcg_solver, max_iter); +} + +void HyprePCG::SetLogging(int logging) +{ + HYPRE_ParCSRPCGSetLogging(pcg_solver, logging); +} + +void HyprePCG::SetPrintLevel(int print_lvl) +{ + print_level = print_lvl; + HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_level); +} + +void HyprePCG::SetPreconditioner(HypreSolver &precond) +{ + HYPRE_ParCSRPCGSetPrecond(pcg_solver, + precond.SolveFcn(), + precond.SetupFcn(), + precond); +} + +void HyprePCG::Mult(const HypreParVector &b, HypreParVector &x) const +{ + int myid; + int time_index; + int num_iterations; + double final_res_norm; + MPI_Comm comm; + + HYPRE_ParCSRMatrixGetComm(*A, &comm); + + if (!setup_called) + { + HYPRE_ParCSRPCGSetup(pcg_solver, *A, b, x); + setup_called = 1; + } + + if (print_level > 0) + { + time_index = hypre_InitializeTiming("PCG Solve"); + hypre_BeginTiming(time_index); + } + + if (use_zero_initial_iterate) + x = 0.0; + + HYPRE_ParCSRPCGSolve(pcg_solver, *A, b, x); + + if (print_level > 0) + { + hypre_EndTiming(time_index); + hypre_PrintTiming("Solve phase times", comm); + hypre_FinalizeTiming(time_index); + hypre_ClearTiming(); + + HYPRE_ParCSRPCGGetNumIterations(pcg_solver, &num_iterations); + HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(pcg_solver, + &final_res_norm); + + MPI_Comm_rank(comm, &myid); + + if (myid == 0) + { + cout << "PCG Iterations = " << num_iterations << endl + << "Final PCG Relative Residual Norm = " << final_res_norm + << endl; + } + } +} + +HyprePCG::~HyprePCG() +{ + HYPRE_ParCSRPCGDestroy(pcg_solver); +} + + +HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A) +{ + MPI_Comm comm; + + int k_dim = 50; + int max_iter = 100; + double tol = 1e-6; + + print_level = 0; + use_zero_initial_iterate = 0; + + HYPRE_ParCSRMatrixGetComm(*A, &comm); + + HYPRE_ParCSRGMRESCreate(comm, &gmres_solver); + HYPRE_ParCSRGMRESSetKDim(gmres_solver, k_dim); + HYPRE_ParCSRGMRESSetMaxIter(gmres_solver, max_iter); + HYPRE_ParCSRGMRESSetTol(gmres_solver, tol); +} + +void HypreGMRES::SetTol(double tol) +{ + HYPRE_ParCSRGMRESSetTol(gmres_solver, tol); +} + +void HypreGMRES::SetMaxIter(int max_iter) +{ + HYPRE_ParCSRGMRESSetMaxIter(gmres_solver, max_iter); +} + +void HypreGMRES::SetKDim(int k_dim) +{ + HYPRE_ParCSRGMRESSetKDim(gmres_solver, k_dim); +} + +void HypreGMRES::SetLogging(int logging) +{ + HYPRE_ParCSRGMRESSetLogging(gmres_solver, logging); +} + +void HypreGMRES::SetPrintLevel(int print_lvl) +{ + print_level = print_lvl; + HYPRE_ParCSRGMRESSetPrintLevel(gmres_solver, print_level); +} + +void HypreGMRES::SetPreconditioner(HypreSolver &precond) +{ + HYPRE_ParCSRGMRESSetPrecond(gmres_solver, + precond.SolveFcn(), + precond.SetupFcn(), + precond); +} + +void HypreGMRES::Mult(const HypreParVector &b, HypreParVector &x) const +{ + int myid; + int time_index; + int num_iterations; + double final_res_norm; + MPI_Comm comm; + + HYPRE_ParCSRMatrixGetComm(*A, &comm); + + if (!setup_called) + { + HYPRE_ParCSRGMRESSetup(gmres_solver, *A, b, x); + setup_called = 1; + } + + if (print_level > 0) + { + time_index = hypre_InitializeTiming("GMRES Solve"); + hypre_BeginTiming(time_index); + } + + if (use_zero_initial_iterate) + x = 0.0; + + HYPRE_ParCSRGMRESSolve(gmres_solver, *A, b, x); + + if (print_level > 0) + { + hypre_EndTiming(time_index); + hypre_PrintTiming("Solve phase times", comm); + hypre_FinalizeTiming(time_index); + hypre_ClearTiming(); + + HYPRE_ParCSRGMRESGetNumIterations(gmres_solver, &num_iterations); + HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(gmres_solver, + &final_res_norm); + + MPI_Comm_rank(comm, &myid); + + if (myid == 0) + { + cout << "GMRES Iterations = " << num_iterations << endl + << "Final GMRES Relative Residual Norm = " << final_res_norm + << endl; + } + } +} + +HypreGMRES::~HypreGMRES() +{ + HYPRE_ParCSRGMRESDestroy(gmres_solver); +} + + +HypreParaSails::HypreParaSails(HypreParMatrix &A) : HypreSolver(&A) +{ + MPI_Comm comm; + + int sai_max_levels = 1; + double sai_threshold = 0.1; + double sai_filter = 0.1; + int sai_sym = 0; + double sai_loadbal = 0.0; + int sai_reuse = 0; + int sai_logging = 1; + + HYPRE_ParCSRMatrixGetComm(A, &comm); + + HYPRE_ParaSailsCreate(comm, &sai_precond); + HYPRE_ParaSailsSetParams(sai_precond, sai_threshold, sai_max_levels); + HYPRE_ParaSailsSetFilter(sai_precond, sai_filter); + HYPRE_ParaSailsSetSym(sai_precond, sai_sym); + HYPRE_ParaSailsSetLoadbal(sai_precond, sai_loadbal); + HYPRE_ParaSailsSetReuse(sai_precond, sai_reuse); + HYPRE_ParaSailsSetLogging(sai_precond, sai_logging); +} + +void HypreParaSails::SetSymmetry(int sym) +{ + HYPRE_ParaSailsSetSym(sai_precond, sym); +} + +HypreParaSails::~HypreParaSails() +{ + HYPRE_ParaSailsDestroy(sai_precond); +} + + +HypreBoomerAMG::HypreBoomerAMG(HypreParMatrix &A) : HypreSolver(&A) +{ + int coarsen_type = 10; + int agg_levels = 1; + int relax_type = 8; + int relax_sweeps = 1; + double theta = 0.25; + int interp_type = 6; + int Pmax = 4; + int print_level = 1; + + HYPRE_BoomerAMGCreate(&amg_precond); + + HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type); + HYPRE_BoomerAMGSetAggNumLevels(amg_precond, agg_levels); + HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type); + HYPRE_BoomerAMGSetNumSweeps(amg_precond, relax_sweeps); + HYPRE_BoomerAMGSetMaxLevels(amg_precond, 25); + HYPRE_BoomerAMGSetTol(amg_precond, 0.0); + HYPRE_BoomerAMGSetMaxIter(amg_precond, 1); // one V-cycle + HYPRE_BoomerAMGSetStrongThreshold(amg_precond, theta); + HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type); + HYPRE_BoomerAMGSetPMaxElmts(amg_precond, Pmax); + HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level); +} + +void HypreBoomerAMG::SetSystemsOptions(int dim) +{ + HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim); + + // More robust options with respect to convergence + HYPRE_BoomerAMGSetAggNumLevels(amg_precond, 0); + HYPRE_BoomerAMGSetStrongThreshold(amg_precond, 0.5); +} + +HypreBoomerAMG::~HypreBoomerAMG() +{ + HYPRE_BoomerAMGDestroy(amg_precond); +} + + +#include "../fem/fem.hpp" + +HypreAMS::HypreAMS(HypreParMatrix &A, ParFiniteElementSpace *edge_fespace) + : HypreSolver(&A) +{ + int cycle_type = 13; + int rlx_type = 2; + int rlx_sweeps = 1; + double rlx_weight = 1.0; + double rlx_omega = 1.0; + int amg_coarsen_type = 10; + int amg_agg_levels = 1; + int amg_agg_npaths = 1; + int amg_rlx_type = 8; + double theta = 0.25; + int amg_interp_type = 6; + int amg_Pmax = 4; + int print_level = 1; + + HYPRE_AMSCreate(&ams); + + HYPRE_AMSSetDimension(ams, 3); // 3D problems + HYPRE_AMSSetTol(ams, 0.0); + HYPRE_AMSSetMaxIter(ams, 1); // use as a preconditioner + HYPRE_AMSSetCycleType(ams, cycle_type); + HYPRE_AMSSetPrintLevel(ams, 1); + + /// define the nodal linear finite element space associated with edge_fespace + ParMesh *pmesh = (ParMesh *) edge_fespace->GetMesh(); + FiniteElementCollection *vert_fec = new LinearFECollection; + ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh, vert_fec); + + // generate and set the vertex coordinates + ParGridFunction x_coord(vert_fespace); + ParGridFunction y_coord(vert_fespace); + ParGridFunction z_coord(vert_fespace); + double *coord; + for (int i = 0; i < pmesh->GetNV(); i++) + { + coord = pmesh -> GetVertex(i); + x_coord(i) = coord[0]; + y_coord(i) = coord[1]; + z_coord(i) = coord[2]; + } + x = x_coord.ParallelAverage(); + y = y_coord.ParallelAverage(); + z = z_coord.ParallelAverage(); + HYPRE_AMSSetCoordinateVectors(ams, *x, *y, *z); + + // generate and set the discrete gradient + HYPRE_ParCSRMatrix Gh; + { + int *edge_vertex = new int[2*edge_fespace->TrueVSize()]; + Array vert; + // set orientation of locally owned edges (tdofs in edge_fespace) + for (int i = 0; i < pmesh->GetNEdges(); i++) + { + int j = edge_fespace->GetLocalTDofNumber(i); + if (j >= 0) + { + pmesh->GetEdgeVertices(i,vert); + if (vert[0] < vert[1]) + { + edge_vertex[2*j] = vert_fespace->GetGlobalTDofNumber(vert[0]); + edge_vertex[2*j+1] = vert_fespace->GetGlobalTDofNumber(vert[1]); + } + else + { + edge_vertex[2*j] = vert_fespace->GetGlobalTDofNumber(vert[1]); + edge_vertex[2*j+1] = vert_fespace->GetGlobalTDofNumber(vert[0]); + } + } + } + // fix the orientation of shared edges + for (int gr = 1; gr < pmesh->GetNGroups(); gr++) + { + if (pmesh->groupmaster_lproc[gr] == 0) + for (int j = 0; j < pmesh->GroupNEdges(gr); j++) + { + int k, o; + pmesh->GroupEdge(gr, j, k, o); + if (edge_fespace->GetDofSign(k) < 0) + { + k = edge_fespace->GetLocalTDofNumber(k); + int tmp = edge_vertex[2*k]; + edge_vertex[2*k] = edge_vertex[2*k+1]; + edge_vertex[2*k+1] = tmp; + } + } + } + HYPRE_AMSConstructDiscreteGradient(A, *x, edge_vertex, 1, &Gh); + delete edge_vertex; + } + G = new HypreParMatrix((hypre_ParCSRMatrix *)Gh); + HYPRE_AMSSetDiscreteGradient(ams, *G); + + delete vert_fec; + delete vert_fespace; + + // set additional AMS options + HYPRE_AMSSetSmoothingOptions(ams, rlx_type, rlx_sweeps, rlx_weight, rlx_omega); + HYPRE_AMSSetAlphaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type, + theta, amg_interp_type, amg_Pmax); + HYPRE_AMSSetBetaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type, + theta, amg_interp_type, amg_Pmax); + +} + +HypreAMS::~HypreAMS() +{ + HYPRE_AMSDestroy(ams); + + delete x; + delete y; + delete z; + + delete G; +} + +#endif diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp new file mode 100644 index 0000000000..63a0dcc8fa --- /dev/null +++ b/linalg/hypre.hpp @@ -0,0 +1,394 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_HYPRE +#define MFEM_HYPRE + +// Enable internal hypre timing routines +#define HYPRE_TIMING + +// hypre header files +#include "seq_mv.h" +#include "_hypre_parcsr_mv.h" +#include "_hypre_parcsr_ls.h" + +/// Wrapper for hypre's parallel vector class +class HypreParVector : public Vector +{ +private: + int own_ParVector; + + /// The actual object + hypre_ParVector *x; + + friend class HypreParMatrix; + +public: + /** Creates vector with given global size and partitioning of the columns. + Processor P owns columns [col[P],col[P+1]) */ + HypreParVector(int glob_size, int *col); + /** Creates vector with given global size, partitioning of the columns, + and data. The data must be allocated and destroyed outside. */ + HypreParVector(int glob_size, double *_data, int *col); + /// Creates vector compatible with y + HypreParVector(const HypreParVector &y); + /// Creates vector wrapping y + HypreParVector(HYPRE_ParVector y); + + /// Typecasting to hypre's hypre_ParVector* + operator hypre_ParVector*() const; + /// Typecasting to hypre's HYPRE_ParVector, a.k.a. void * + operator HYPRE_ParVector() const; + /// Changes the ownership of the the vector + hypre_ParVector *StealParVector() { own_ParVector = 0; return x; } + + /// Returns the global vector in each processor + Vector *GlobalVector(); + + /// Set constant values + HypreParVector& operator= (double d); + /// Define '=' for hypre vectors. + HypreParVector& operator= (const HypreParVector &y); + + /** Sets the data of the Vector and the hypre_ParVector to _data. + Must be used only for HypreParVectors that do not own the data, + e.g. created with the constructor: + HypreParVector(int glob_size, double *_data, int *col). */ + void SetData(double *_data); + + /// Set random values + int Randomize(int seed); + + /// Prints the locally owned rows in parallel + void Print(const char *fname); + + /// Calls hypre's destroy function + ~HypreParVector(); +}; + +/// Returns the inner product of x and y +double InnerProduct(HypreParVector &x, HypreParVector &y); +double InnerProduct(HypreParVector *x, HypreParVector *y); + + +/// Wrapper for hypre's ParCSR matrix class +class HypreParMatrix : public Operator +{ +private: + /// The actual object + hypre_ParCSRMatrix *A; + + /// Internal communication object associated with A + hypre_ParCSRCommPkg *CommPkg; + + /// Auxiliary vectors for typecasting + mutable HypreParVector *X, *Y; + +public: + /// Converts hypre's format to HypreParMatrix + HypreParMatrix(hypre_ParCSRMatrix *a) : A(a) + { X = Y = 0; CommPkg = 0; } + /// Creates block-diagonal square parallel matrix. Diagonal given by diag. + HypreParMatrix(int size, int *row, SparseMatrix *diag); + /** Creates block-diagonal rectangular parallel matrix. Diagonal + given by diag. */ + HypreParMatrix(int M, int N, int *row, int *col, SparseMatrix *diag); + /// Creates general (rectangular) parallel matrix + HypreParMatrix(int M, int N, int *row, int *col, SparseMatrix *diag, + SparseMatrix *offd, int *cmap); + + /// Creates a parallel matrix from SparseMatrix on processor 0. + HypreParMatrix(int *row, int *col, SparseMatrix *a); + + /// Creates boolean block-diagonal rectangular parallel matrix. + HypreParMatrix(int M, int N, int *row, int *col, Table *diag); + /// Creates boolean rectangular parallel matrix (which owns its data) + HypreParMatrix(MPI_Comm comm, int id, int np, int *row, int *col, + int *i_diag, int *j_diag, int *i_offd, int *j_offd, + int *cmap, int cmap_size); + + // hypre's communication package object + void SetCommPkg(hypre_ParCSRCommPkg *comm_pkg); + void CheckCommPkg(); + void DestroyCommPkg(); + + /// Typecasting to hypre's hypre_ParCSRMatrix* + operator hypre_ParCSRMatrix*(); + /// Typecasting to hypre's HYPRE_ParCSRMatrix, a.k.a. void * + operator HYPRE_ParCSRMatrix(); + /// Changes the ownership of the the matrix + hypre_ParCSRMatrix* StealData(); + + /// Returns the number of nonzeros + inline int NNZ() { return A->num_nonzeros; } + /// Returns the row partitioning + inline int * RowPart() { return A->row_starts; } + /// Returns the row partitioning + inline int * ColPart() { return A->col_starts; } + /// Returns the global number of rows + inline int M() { return A -> global_num_rows; } + /// Returns the global number of columns + inline int N() { return A -> global_num_cols; } + + /// Returns the transpose of *this + HypreParMatrix * Transpose(); + + /// Returns the number of rows in the diagonal block of the ParCSRMatrix + int GetNumRows() const + { return hypre_CSRMatrixNumRows(hypre_ParCSRMatrixDiag(A)); } + + int GetGlobalNumRows() const { return hypre_ParCSRMatrixGlobalNumRows(A); } + + int GetGlobalNumCols() const { return hypre_ParCSRMatrixGlobalNumCols(A); } + + int *GetRowStarts() const { return hypre_ParCSRMatrixRowStarts(A); } + + int *GetColStarts() const { return hypre_ParCSRMatrixColStarts(A); } + + /// Computes y = alpha * A * x + beta * y + int Mult(HypreParVector &x, HypreParVector &y, + double alpha = 1.0, double beta = 0.0); + /// Computes y = alpha * A * x + beta * y + int Mult(HYPRE_ParVector x, HYPRE_ParVector y, + double alpha = 1.0, double beta = 0.0); + /// Computes y = alpha * A^t * x + beta * y + int MultTranspose(HypreParVector &x, HypreParVector &y, + double alpha = 1.0, double beta = 0.0); + + virtual void Mult(const Vector &x, Vector &y) const; + + /// Prints the locally owned rows in parallel + void Print(const char *fname, int offi = 0, int offj = 0); + /// Reads the matrix from a file + void Read(const char *fname); + + /// Calls hypre's destroy function + virtual ~HypreParMatrix(); +}; + +/// Returns the matrix A * B +HypreParMatrix * ParMult(HypreParMatrix *A, HypreParMatrix *B); + +/// Returns the matrix P^t * A * P +HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P); + + +/// Abstract class for hypre's solvers and preconditioners +class HypreSolver : public Operator +{ +protected: + /// The linear system matrix + HypreParMatrix *A; + + /// Right-hand side and solution vector + mutable HypreParVector *B, *X; + + /// Was hypre's Setup function called already? + mutable int setup_called; + +public: + HypreSolver(); + + HypreSolver(HypreParMatrix *_A); + + /// Typecast to HYPRE_Solver -- return the solver + virtual operator HYPRE_Solver() const = 0; + + /// hypre's internal Setup function + virtual HYPRE_PtrToParSolverFcn SetupFcn() const = 0; + /// hypre's internal Solve function + virtual HYPRE_PtrToParSolverFcn SolveFcn() const = 0; + + /// Solve the linear system Ax=b + virtual void Mult(const HypreParVector &b, HypreParVector &x) const; + virtual void Mult(const Vector &b, Vector &x) const; + + virtual ~HypreSolver(); +}; + +/// PCG solver in hypre +class HyprePCG : public HypreSolver +{ +private: + int print_level, use_zero_initial_iterate; + HYPRE_Solver pcg_solver; + +public: + HyprePCG(HypreParMatrix &_A); + + void SetTol(double tol); + void SetMaxIter(int max_iter); + void SetLogging(int logging); + void SetPrintLevel(int print_lvl); + + /// Set the hypre solver to be used as a preconditioner + void SetPreconditioner(HypreSolver &precond); + + /// non-hypre setting + void SetZeroInintialIterate() { use_zero_initial_iterate = 1; } + + /// The typecast to HYPRE_Solver returns the internal pcg_solver + virtual operator HYPRE_Solver() const { return pcg_solver; } + + /// PCG Setup function + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRPCGSetup; } + /// PCG Solve function + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRPCGSolve; } + + /// Solve Ax=b with hypre's PCG + virtual void Mult(const HypreParVector &b, HypreParVector &x) const; + + virtual ~HyprePCG(); +}; + +/// GMRES solver in hypre +class HypreGMRES : public HypreSolver +{ +private: + int print_level, use_zero_initial_iterate; + HYPRE_Solver gmres_solver; + +public: + HypreGMRES(HypreParMatrix &_A); + + void SetTol(double tol); + void SetMaxIter(int max_iter); + void SetKDim(int dim); + void SetLogging(int logging); + void SetPrintLevel(int print_lvl); + + /// Set the hypre solver to be used as a preconditioner + void SetPreconditioner(HypreSolver &precond); + + /// non-hypre setting + void SetZeroInintialIterate() { use_zero_initial_iterate = 1; } + + /// The typecast to HYPRE_Solver returns the internal gmres_solver + virtual operator HYPRE_Solver() const { return gmres_solver; } + + /// GMRES Setup function + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRGMRESSetup; } + /// GMRES Solve function + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRGMRESSolve; } + + /// Solve Ax=b with hypre's GMRES + virtual void Mult (const HypreParVector &b, HypreParVector &x) const; + + virtual ~HypreGMRES(); +}; + +/// The identity operator as a hypre solver +class HypreIdentity : public HypreSolver +{ +public: + virtual operator HYPRE_Solver() const { return NULL; } + + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) hypre_ParKrylovIdentitySetup; } + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) hypre_ParKrylovIdentity; } + + virtual ~HypreIdentity() { } +}; + +/// Jacobi preconditioner in hypre +class HypreDiagScale : public HypreSolver +{ +public: + virtual operator HYPRE_Solver() const { return NULL; } + + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRDiagScaleSetup; } + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRDiagScale; } + + virtual ~HypreDiagScale() { } +}; + +/// The ParaSails preconditioner in hypre +class HypreParaSails : public HypreSolver +{ +private: + HYPRE_Solver sai_precond; + +public: + HypreParaSails(HypreParMatrix &A); + + void SetSymmetry(int sym); + + /// The typecast to HYPRE_Solver returns the internal sai_precond + virtual operator HYPRE_Solver() const { return sai_precond; } + + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParaSailsSetup; } + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParaSailsSolve; } + + virtual ~HypreParaSails(); +}; + +/// The BoomerAMG solver in hypre +class HypreBoomerAMG : public HypreSolver +{ +private: + HYPRE_Solver amg_precond; + +public: + HypreBoomerAMG(HypreParMatrix &A); + + /** More robust options for systems, such as elastisity. Note that BoomerAMG + assumes Ordering::byVDIM in the finite element space used to generate the + matrix A. */ + void SetSystemsOptions(int dim); + + /// The typecast to HYPRE_Solver returns the internal amg_precond + virtual operator HYPRE_Solver() const { return amg_precond; } + + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSetup; } + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSolve; } + + virtual ~HypreBoomerAMG(); +}; + +class ParFiniteElementSpace; + +/// The Auxiliary-space Maxwell Solver in hypre +class HypreAMS : public HypreSolver +{ +private: + HYPRE_Solver ams; + + /// Vertex coordinates + HypreParVector *x, *y, *z; + /// Discrete gradient matrix + HypreParMatrix *G; + +public: + HypreAMS(HypreParMatrix &A, ParFiniteElementSpace *edge_fespace); + + /// The typecast to HYPRE_Solver returns the internal ams object + virtual operator HYPRE_Solver() const { return ams; } + + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_AMSSetup; } + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_AMSSolve; } + + virtual ~HypreAMS(); +}; + +#endif diff --git a/linalg/linalg.hpp b/linalg/linalg.hpp index 6f5c84de7a..b8aa765cd7 100644 --- a/linalg/linalg.hpp +++ b/linalg/linalg.hpp @@ -22,4 +22,9 @@ #include "densemat.hpp" #include "solvers.hpp" +#ifdef MFEM_USE_MPI +#include +#include "hypre.hpp" +#endif + #endif diff --git a/linalg/matrix.cpp b/linalg/matrix.cpp index 2044bd247e..d4473038b8 100644 --- a/linalg/matrix.cpp +++ b/linalg/matrix.cpp @@ -16,7 +16,7 @@ #include "matrix.hpp" -void Matrix::Print (ostream & out, int width) +void Matrix::Print (ostream & out, int width) const { // output flags = scientific + show sign out << setiosflags(ios::scientific | ios::showpos); diff --git a/linalg/matrix.hpp b/linalg/matrix.hpp index 6d3369e74e..b4ee5b586c 100644 --- a/linalg/matrix.hpp +++ b/linalg/matrix.hpp @@ -37,10 +37,10 @@ public: virtual MatrixInverse * Inverse() const = 0; /// Finalizes the matrix initialization. - virtual void Finalize() { } + virtual void Finalize(int) { } /// Prints matrix to stream out. - virtual void Print (ostream & out = cout, int width = 4); + virtual void Print (ostream & out = cout, int width = 4) const; /// Destroys matrix. virtual ~Matrix() { } diff --git a/linalg/solvers.hpp b/linalg/solvers.hpp index d370be4b49..022d836bf1 100644 --- a/linalg/solvers.hpp +++ b/linalg/solvers.hpp @@ -16,8 +16,7 @@ x, iteratively solve A x = b. When the default arguments are used CG doesn't print current residual and number of iterations, maximum number of iterations is 1000, the relative tolerance is 10e-12 and - the absolute tolerance is 10e-24 **/ - + the absolute tolerance is 10e-24. */ void CG ( const Operator &A, const Vector &b, Vector &x, int print_iter=0, int max_num_iter=1000, double RTOLERANCE=10e-12, double ATOLERANCE=10e-24); @@ -29,12 +28,12 @@ void CG ( const Operator &A, const Vector &b, Vector &x, and number of iterations, maximum number of iterations is 1000, the relative tolerance is 10e-12 and the absolute tolerance is 10e-24. Remark : if no better initial guess is available, the user may set - it as B b (since not done in PCG routine). **/ - + it as B b (since not done in PCG routine). */ void PCG ( const Operator &A, const Operator &B, const Vector &b,Vector &x, int print_iter=0, int max_num_iter=1000, double RTOLERANCE=10e-12, double ATOLERANCE=10e-24, int save = 0); +/// A GMRES solver int GMRES(const Operator &A, Vector &x, const Vector &b, const Operator &M, int &max_iter, int m, double &tol, double &atol, int printit); @@ -42,18 +41,18 @@ int GMRES(const Operator &A, Vector &x, const Vector &b, /** Adaptive restarted GMRES. m_max and m_min(=1) are the maximal and minimal restart parameters. m_step(=1) is the step to use for going from m_max and m_min. - cf(=0.4) is a desired convergance factor. -*/ + cf(=0.4) is a desired convergance factor. */ int aGMRES(const Operator &A, Vector &x, const Vector &b, const Operator &M, int &max_iter, int m_max, int m_min, int m_step, double cf, double &tol, double &atol, int printit); +/// A BiCG-Stab solver int BiCGSTAB(const Operator &A, Vector &x, const Vector &b, const Operator &M, int &max_iter, double &tol, double atol, int printit); -/** Stationary linear iteration: x <- x + B (b - A x) */ +/// Stationary linear iteration: x <- x + B (b - A x) void SLI (const Operator &A, const Operator &B, const Vector &b, Vector &x, int print_iter=0, int max_num_iter=1000, diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index b55c818eee..3c50b55655 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -326,7 +326,7 @@ void SparseMatrix::Symmetrize() } } -int SparseMatrix::NumNonZeroElems () +int SparseMatrix::NumNonZeroElems() const { if (A != NULL) // matrix is finalized return I[size]; @@ -994,7 +994,7 @@ SparseMatrix & SparseMatrix::operator= (double a) return (*this); } -void SparseMatrix::Print(ostream & out, int _width) +void SparseMatrix::Print(ostream & out, int _width) const { int i, j; @@ -1015,7 +1015,7 @@ void SparseMatrix::Print(ostream & out, int _width) out << endl; } -void SparseMatrix::PrintMatlab(ostream & out) +void SparseMatrix::PrintMatlab(ostream & out) const { int i, j; ios::fmtflags old_fmt = out.setf(ios::scientific); @@ -1028,7 +1028,7 @@ void SparseMatrix::PrintMatlab(ostream & out) out.setf(old_fmt); } -void SparseMatrix::PrintMM(ostream & out) +void SparseMatrix::PrintMM(ostream & out) const { int i, j; ios::fmtflags old_fmt = out.setf(ios::scientific); @@ -1045,7 +1045,7 @@ void SparseMatrix::PrintMM(ostream & out) out.setf(old_fmt); } -void SparseMatrix::PrintCSR(ostream & out) +void SparseMatrix::PrintCSR(ostream & out) const { if (A == NULL) mfem_error ("SparseMatrix::PrintCSR()"); @@ -1069,7 +1069,7 @@ void SparseMatrix::PrintCSR(ostream & out) out.setf(old_fmt); } -void SparseMatrix::PrintCSR2(ostream & out) +void SparseMatrix::PrintCSR2(ostream & out) const { if (A == NULL) mfem_error ("SparseMatrix::PrintCSR2()"); diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index b50b60b878..bfd71092a5 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -172,19 +172,19 @@ public: SparseMatrix & operator= (double a); /// Prints matrix to stream out. - void Print(ostream & out = cout, int width = 4); + void Print(ostream & out = cout, int width = 4) const; /// Prints matrix in matlab format. - void PrintMatlab(ostream & out = cout); + void PrintMatlab(ostream & out = cout) const; /// Prints matrix in Matrix Market sparse format. - void PrintMM(ostream & out = cout); + void PrintMM(ostream & out = cout) const; /// Prints matrix to stream out in hypre_CSRMatrix format. - void PrintCSR(ostream & out); + void PrintCSR(ostream & out) const; /// Prints a sparse matrix to stream out in CSR format. - void PrintCSR2(ostream & out); + void PrintCSR2(ostream & out) const; /// Walks the sparse matrix int Walk (int & i, int & j, double & a); @@ -196,7 +196,7 @@ public: void Symmetrize(); /// Returns the number of the nonzero elements in the matrix - int NumNonZeroElems (); + int NumNonZeroElems() const; /// Count the number of entries with |a_ij| < tol int CountSmallElems (double tol); @@ -208,14 +208,14 @@ public: virtual ~SparseMatrix(); }; -// Applies f() to each element of the matrix (after it is finalized). +/// Applies f() to each element of the matrix (after it is finalized). void SparseMatrixFunction (SparseMatrix & S, double (*f)(double)); -/* Transpose of a sparse matrix. A must be finalized. */ +/// Transpose of a sparse matrix. A must be finalized. SparseMatrix *Transpose (SparseMatrix &A); -/* Matrix product A.B. +/** Matrix product A.B. If OAB is not NULL, we assume it has the structure of A.B and store the result in OAB. If OAB is NULL, we create a new SparseMatrix to store @@ -225,12 +225,12 @@ SparseMatrix *Mult (SparseMatrix &A, SparseMatrix &B, SparseMatrix *OAB = NULL); -/* RAP matrix product. ORAP is like OAB above. +/** RAP matrix product. ORAP is like OAB above. All matrices must be finalized. */ SparseMatrix *RAP (SparseMatrix &A, SparseMatrix &R, SparseMatrix *ORAP = NULL); -/* Matrix multiplication A^t D A. +/** Matrix multiplication A^t D A. All matrices must be finalized. */ SparseMatrix *Mult_AtDA (SparseMatrix &A, Vector &D, SparseMatrix *OAtDA = NULL); diff --git a/linalg/vector.cpp b/linalg/vector.cpp index 14056b1602..83f2acde49 100644 --- a/linalg/vector.cpp +++ b/linalg/vector.cpp @@ -92,16 +92,17 @@ double Vector::operator*(const Vector & v) const{ Vector & Vector::operator=(const Vector &v) { - SetSize (v.Size()); - for(int i=0; i #include "mesh_headers.hpp" -void Element::SetVertices (const int *ind) +void Element::SetVertices(const int *ind) { int i, n, *v; diff --git a/mesh/element.hpp b/mesh/element.hpp index e507042337..0e8f962a98 100644 --- a/mesh/element.hpp +++ b/mesh/element.hpp @@ -17,7 +17,7 @@ class Element { protected: - /* Element's attribute (specifying material property, etc). */ + /// Element's attribute (specifying material property, etc). int attribute, base_geom; public: @@ -27,18 +27,18 @@ public: HEXAHEDRON, BISECTED, QUADRISECTED, OCTASECTED }; /// Default element constructor. - Element (int bg = Geometry::POINT) { attribute = -1; base_geom = bg; } + Element(int bg = Geometry::POINT) { attribute = -1; base_geom = bg; } /// Set the indices the element according to the input. - virtual void SetVertices (const int *ind); + virtual void SetVertices(const int *ind); /// Returns element's type virtual int GetType() const = 0; - int GetGeometryType() const { return base_geom; }; + int GetGeometryType() const { return base_geom; } /// Returns element's vertices. - virtual void GetVertices ( Array &v ) const = 0; + virtual void GetVertices(Array &v) const = 0; virtual int *GetVertices() = 0; @@ -55,20 +55,20 @@ public: virtual void MarkEdge(const DSTable &v_to_v, const int *length) {} /// Return 1 if the element needs refinement in order to get conforming mesh. - virtual int NeedRefinement ( DSTable &v_to_v, int *middle) const {return 0;} + virtual int NeedRefinement(DSTable &v_to_v, int *middle) const { return 0; } /// Return element's attribute. inline int GetAttribute() const { return attribute; } /// Set element's attribute. - inline void SetAttribute (const int attr) { attribute = attr; } + inline void SetAttribute(const int attr) { attribute = attr; } - virtual int GetRefinementFlag() { return 0; }; + virtual int GetRefinementFlag() { return 0; } virtual Element *Duplicate() const = 0; /// Destroys element. - virtual ~Element() {}; + virtual ~Element() { } }; class RefinedElement : public Element @@ -82,54 +82,51 @@ public: Element *CoarseElem, *FirstChild; - RefinedElement () { }; + RefinedElement() { } - RefinedElement (Element *ce) - : Element (ce->GetGeometryType()) - { attribute = ce->GetAttribute(); CoarseElem = ce; }; + RefinedElement(Element *ce) : Element(ce->GetGeometryType()) + { attribute = ce->GetAttribute(); CoarseElem = ce; } // Assumes that the coarse element and its first child have the // same attribute and the same base geometry ... - void SetCoarseElem (Element *ce) + void SetCoarseElem(Element *ce) { base_geom = ce->GetGeometryType(); attribute = ce->GetAttribute(); CoarseElem = ce; - }; + } Element *IAm() { if (State == RefinedElement::COARSE) return CoarseElem; return FirstChild; - }; + } const Element *IAm() const { if (State == RefinedElement::COARSE) return CoarseElem; return FirstChild; - }; + } - virtual void SetVertices(const int *ind) { IAm()->SetVertices (ind); }; + virtual void SetVertices(const int *ind) { IAm()->SetVertices(ind); } - virtual void GetVertices ( Array &v ) const - { IAm()->GetVertices (v); }; + virtual void GetVertices(Array &v) const { IAm()->GetVertices(v); } - virtual int * GetVertices () { return IAm()->GetVertices(); }; + virtual int *GetVertices() { return IAm()->GetVertices(); } - virtual int GetNVertices() const { return IAm()->GetNVertices(); }; + virtual int GetNVertices() const { return IAm()->GetNVertices(); } virtual int GetNEdges() const { return(IAm()->GetNEdges()); } virtual const int *GetEdgeVertices(int ei) const { return(IAm()->GetEdgeVertices(ei)); } - virtual void MarkEdge(DenseMatrix &pmat) - { IAm()->MarkEdge (pmat); }; + virtual void MarkEdge(DenseMatrix &pmat) { IAm()->MarkEdge(pmat); } virtual void MarkEdge(const DSTable &v_to_v, const int *length) - { IAm()->MarkEdge (v_to_v, length); }; + { IAm()->MarkEdge(v_to_v, length); } - virtual int NeedRefinement ( DSTable &v_to_v, int *middle) const - { return IAm()->NeedRefinement (v_to_v, middle); }; + virtual int NeedRefinement(DSTable &v_to_v, int *middle) const + { return IAm()->NeedRefinement(v_to_v, middle); } }; class BisectedElement : public RefinedElement @@ -137,13 +134,13 @@ class BisectedElement : public RefinedElement public: int SecondChild; - BisectedElement () { }; - BisectedElement (Element *ce) : RefinedElement (ce) { }; + BisectedElement() { } + BisectedElement(Element *ce) : RefinedElement(ce) { } - virtual int GetType() const { return Element::BISECTED; }; + virtual int GetType() const { return Element::BISECTED; } virtual Element *Duplicate() const - { mfem_error ("BisectedElement::Duplicate()"); return NULL; }; + { mfem_error("BisectedElement::Duplicate()"); return NULL; } }; class QuadrisectedElement : public RefinedElement @@ -151,12 +148,12 @@ class QuadrisectedElement : public RefinedElement public: int Child2, Child3, Child4; - QuadrisectedElement (Element *ce) : RefinedElement (ce) { }; + QuadrisectedElement(Element *ce) : RefinedElement(ce) { } - virtual int GetType() const { return Element::QUADRISECTED; }; + virtual int GetType() const { return Element::QUADRISECTED; } virtual Element *Duplicate() const - { mfem_error ("QuadrisectedElement::Duplicate()"); return NULL; }; + { mfem_error("QuadrisectedElement::Duplicate()"); return NULL; } }; class OctasectedElement : public RefinedElement @@ -164,12 +161,12 @@ class OctasectedElement : public RefinedElement public: int Child[7]; - OctasectedElement (Element *ce) : RefinedElement (ce) { }; + OctasectedElement(Element *ce) : RefinedElement(ce) { } - virtual int GetType() const { return Element::OCTASECTED; }; + virtual int GetType() const { return Element::OCTASECTED; } virtual Element *Duplicate() const - { mfem_error ("OctasectedElement::Duplicate()"); return NULL; }; + { mfem_error("OctasectedElement::Duplicate()"); return NULL; } }; #ifdef MFEM_USE_MEMALLOC diff --git a/mesh/hexahedron.cpp b/mesh/hexahedron.cpp index 6245a717d8..f525378004 100644 --- a/mesh/hexahedron.cpp +++ b/mesh/hexahedron.cpp @@ -17,7 +17,7 @@ const int Hexahedron::edges[12][2] = {4, 5}, {5, 6}, {7, 6}, {4, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; -Hexahedron::Hexahedron( const int *ind, int attr ) +Hexahedron::Hexahedron(const int *ind, int attr) : Element(Geometry::CUBE) { attribute = attr; @@ -25,9 +25,10 @@ Hexahedron::Hexahedron( const int *ind, int attr ) indices[i] = ind[i]; } -Hexahedron::Hexahedron( int ind1, int ind2, int ind3, int ind4, - int ind5, int ind6, int ind7, int ind8, - int attr ) : Element(Geometry::CUBE) { +Hexahedron::Hexahedron(int ind1, int ind2, int ind3, int ind4, + int ind5, int ind6, int ind7, int ind8, + int attr) : Element(Geometry::CUBE) +{ attribute = attr; indices[0] = ind1; indices[1] = ind2; @@ -39,7 +40,8 @@ Hexahedron::Hexahedron( int ind1, int ind2, int ind3, int ind4, indices[7] = ind8; } -void Hexahedron::GetVertices( Array &v ) const { +void Hexahedron::GetVertices(Array &v) const +{ v.SetSize( 8 ); for (int i=0; i<8; i++) v[i] = indices[i]; diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index e1701d4671..d5be79f0f0 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -15,9 +15,11 @@ #include #include #include +#include #include "mesh_headers.hpp" #include "../fem/fem.hpp" +#include "../general/sort_pairs.hpp" void Mesh::GetElementJacobian(int i, DenseMatrix &J) { @@ -67,7 +69,7 @@ double Mesh::GetElementVolume(int i) return volume; } -void Mesh::PrintCharacteristics (Vector *Vh, Vector *Vk) +void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk) { int i, dim; DenseMatrix J; @@ -81,25 +83,25 @@ void Mesh::PrintCharacteristics (Vector *Vh, Vector *Vk) cout << "Mesh Characteristics:" << flush; dim = Dimension(); - J.SetSize (dim); + J.SetSize(dim); #ifndef MFEM_USE_LAPACK - Jinv.SetSize (dim); + Jinv.SetSize(dim); #endif - if (Vh) Vh -> SetSize (NumOfElements); - if (Vk) Vk -> SetSize (NumOfElements); + if (Vh) Vh->SetSize(NumOfElements); + if (Vk) Vk->SetSize(NumOfElements); for (i = 0; i < NumOfElements; i++) { GetElementJacobian(i, J); - h = pow (fabs (J.Det()), 1.0/double(dim)); + h = pow(fabs(J.Det()), 1.0/double(dim)); #ifdef MFEM_USE_LAPACK // J's condition number in spectral norm J.SingularValues(sv); kappa = sv(0) / sv(dim-1); #else // J's condition number in Frobenius norm - CalcInverse (J, Jinv); + CalcInverse(J, Jinv); kappa = J.FNorm() * Jinv.FNorm(); #endif if (Vh) (*Vh)(i) = h; @@ -145,9 +147,9 @@ void Mesh::PrintCharacteristics (Vector *Vh, Vector *Vk) << endl; } -FiniteElement *Mesh::GetTransformationFEforElementType (int ElemType) +FiniteElement *Mesh::GetTransformationFEforElementType(int ElemType) { - switch(ElemType) + switch (ElemType) { case Element::POINT : return &PointFE; case Element::SEGMENT : return &SegmentFE; @@ -156,19 +158,19 @@ FiniteElement *Mesh::GetTransformationFEforElementType (int ElemType) case Element::TETRAHEDRON : return &TetrahedronFE; case Element::HEXAHEDRON : return &HexahedronFE; } - mfem_error ("Mesh::GetTransformationFEforElement - unknown ElementType"); + mfem_error("Mesh::GetTransformationFEforElement - unknown ElementType"); return &TriangleFE; } -void Mesh::GetElementTransformation (int i, IsoparametricTransformation *ElTr) +void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr) { - ElTr -> Attribute = GetAttribute(i); - ElTr -> ElementNo = i; + ElTr->Attribute = GetAttribute(i); + ElTr->ElementNo = i; if (Nodes == NULL) { - GetPointMatrix(i, ElTr -> GetPointMat()); - ElTr -> SetFE (GetTransformationFEforElementType (GetElementType(i))); + GetPointMatrix(i, ElTr->GetPointMat()); + ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i))); } else { @@ -184,22 +186,22 @@ void Mesh::GetElementTransformation (int i, IsoparametricTransformation *ElTr) } } -void Mesh::GetElementTransformation (int i, const Vector &nodes, - IsoparametricTransformation *ElTr) +void Mesh::GetElementTransformation(int i, const Vector &nodes, + IsoparametricTransformation *ElTr) { - ElTr -> Attribute = GetAttribute(i); - ElTr -> ElementNo = i; + ElTr->Attribute = GetAttribute(i); + ElTr->ElementNo = i; DenseMatrix &pm = ElTr->GetPointMat(); if (Nodes == NULL) { - int nv = elements[i] -> GetNVertices(); - const int *v = elements[i] -> GetVertices(); + int nv = elements[i]->GetNVertices(); + const int *v = elements[i]->GetVertices(); int n = vertices.Size(); - pm.SetSize (Dim, nv); + pm.SetSize(Dim, nv); for (int k = 0; k < Dim; k++) for (int j = 0; j < nv; j++) pm(k, j) = nodes(k*n+v[j]); - ElTr -> SetFE (GetTransformationFEforElementType (GetElementType(i))); + ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i))); } else { @@ -214,22 +216,22 @@ void Mesh::GetElementTransformation (int i, const Vector &nodes, } } -ElementTransformation * Mesh :: GetElementTransformation(int i) +ElementTransformation *Mesh::GetElementTransformation(int i) { - GetElementTransformation (i, &Transformation); + GetElementTransformation(i, &Transformation); return &Transformation; } -ElementTransformation * Mesh :: GetBdrElementTransformation(int i) +ElementTransformation *Mesh::GetBdrElementTransformation(int i) { FaceTransformation.Attribute = GetBdrAttribute(i); FaceTransformation.ElementNo = i; // boundary element number if (Nodes == NULL) { GetBdrPointMatrix(i, FaceTransformation.GetPointMat()); - FaceTransformation.SetFE ( - GetTransformationFEforElementType (GetBdrElementType(i))); + FaceTransformation.SetFE( + GetTransformationFEforElementType(GetBdrElementType(i))); } else { @@ -247,7 +249,7 @@ ElementTransformation * Mesh :: GetBdrElementTransformation(int i) return &FaceTransformation; } -void Mesh::GetLocalSegToTriTransformation ( +void Mesh::GetLocalSegToTriTransformation( IsoparametricTransformation &Transf, int i) { static const int tri_faces[3][2] = {{1, 0}, {2, 1}, {0, 2}}; @@ -257,19 +259,19 @@ void Mesh::GetLocalSegToTriTransformation ( const IntegrationRule *TriVert; DenseMatrix &locpm = Transf.GetPointMat(); - Transf.SetFE (&SegmentFE); + Transf.SetFE(&SegmentFE); tv = tri_faces[i/64]; // (i/64) is the local face no. in the triangle so = seg_inv_orient[i%64]; // (i%64) is the orientation of the segment - TriVert = Geometries.GetVertices (Geometry::TRIANGLE); - locpm.SetSize (2, 2); + TriVert = Geometries.GetVertices(Geometry::TRIANGLE); + locpm.SetSize(2, 2); for (j = 0; j < 2; j++) { - locpm (0, so[j]) = TriVert -> IntPoint(tv[j]).x; - locpm (1, so[j]) = TriVert -> IntPoint(tv[j]).y; + locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x; + locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y; } } -void Mesh::GetLocalSegToQuadTransformation ( +void Mesh::GetLocalSegToQuadTransformation( IsoparametricTransformation &Transf, int i) { static const int quad_faces[4][2] = {{1, 0}, {2, 1}, {3, 2}, {0, 3}}; @@ -279,19 +281,19 @@ void Mesh::GetLocalSegToQuadTransformation ( const IntegrationRule *QuadVert; DenseMatrix &locpm = Transf.GetPointMat(); - Transf.SetFE (&SegmentFE); + Transf.SetFE(&SegmentFE); qv = quad_faces[i/64]; // (i/64) is the local face no. in the quad so = seg_inv_orient[i%64]; // (i%64) is the orientation of the segment - QuadVert = Geometries.GetVertices (Geometry::SQUARE); - locpm.SetSize (2, 2); + QuadVert = Geometries.GetVertices(Geometry::SQUARE); + locpm.SetSize(2, 2); for (j = 0; j < 2; j++) { - locpm (0, so[j]) = QuadVert -> IntPoint(qv[j]).x; - locpm (1, so[j]) = QuadVert -> IntPoint(qv[j]).y; + locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x; + locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y; } } -void Mesh::GetLocalTriToTetTransformation ( +void Mesh::GetLocalTriToTetTransformation( IsoparametricTransformation &Transf, int i) { static const int tet_faces[4][3] = {{1, 2, 3}, {0, 3, 2}, @@ -304,22 +306,22 @@ void Mesh::GetLocalTriToTetTransformation ( const IntegrationRule *TetVert; DenseMatrix &locpm = Transf.GetPointMat(); - Transf.SetFE (&TriangleFE); + Transf.SetFE(&TriangleFE); tv = tet_faces[i/64]; // (i/64) is the local face no. in the tet // (i%64) is the orientation of the tetrahedron face // w.r.t. the face element to = tri_inv_orient[i%64]; - TetVert = Geometries.GetVertices (Geometry::TETRAHEDRON); - locpm.SetSize (3, 3); + TetVert = Geometries.GetVertices(Geometry::TETRAHEDRON); + locpm.SetSize(3, 3); for (j = 0; j < 3; j++) { - locpm (0, to[j]) = TetVert -> IntPoint(tv[j]).x; - locpm (1, to[j]) = TetVert -> IntPoint(tv[j]).y; - locpm (2, to[j]) = TetVert -> IntPoint(tv[j]).z; + locpm(0, to[j]) = TetVert->IntPoint(tv[j]).x; + locpm(1, to[j]) = TetVert->IntPoint(tv[j]).y; + locpm(2, to[j]) = TetVert->IntPoint(tv[j]).z; } } -void Mesh::GetLocalQuadToHexTransformation ( +void Mesh::GetLocalQuadToHexTransformation( IsoparametricTransformation &Transf, int i) { static const int hex_faces[6][4] = {{3, 2, 1, 0}, {0, 1, 5, 4}, @@ -335,27 +337,27 @@ void Mesh::GetLocalQuadToHexTransformation ( const IntegrationRule *HexVert; DenseMatrix &locpm = Transf.GetPointMat(); - Transf.SetFE (&QuadrilateralFE); + Transf.SetFE(&QuadrilateralFE); hv = hex_faces[i/64]; // (i/64) is the local face no. in the hex qo = quad_orient[i%64]; // (i%64) is the orientation of the quad - HexVert = Geometries.GetVertices (Geometry::CUBE); - locpm.SetSize (3, 4); + HexVert = Geometries.GetVertices(Geometry::CUBE); + locpm.SetSize(3, 4); for (j = 0; j < 4; j++) { - locpm (0, qo[j]) = HexVert -> IntPoint(hv[j]).x; - locpm (1, qo[j]) = HexVert -> IntPoint(hv[j]).y; - locpm (2, qo[j]) = HexVert -> IntPoint(hv[j]).z; + locpm(0, qo[j]) = HexVert->IntPoint(hv[j]).x; + locpm(1, qo[j]) = HexVert->IntPoint(hv[j]).y; + locpm(2, qo[j]) = HexVert->IntPoint(hv[j]).z; } } -FaceElementTransformations *Mesh::GetFaceElementTransformations (int FaceNo) +FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo) { int i, j, *v, nv; FiniteElement *FaceFE; // setup the transformation for the first element FaceElemTr.Elem1No = faces_info[FaceNo].Elem1No; - GetElementTransformation (FaceElemTr.Elem1No, &Transformation); + GetElementTransformation(FaceElemTr.Elem1No, &Transformation); FaceElemTr.Elem1 = &Transformation; // setup the transformation for the second element @@ -363,69 +365,69 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations (int FaceNo) // the face is on the "boundary" if ( (FaceElemTr.Elem2No = faces_info[FaceNo].Elem2No) >= 0 ) { - GetElementTransformation (FaceElemTr.Elem2No, &Transformation2); + GetElementTransformation(FaceElemTr.Elem2No, &Transformation2); FaceElemTr.Elem2 = &Transformation2; } else FaceElemTr.Elem2 = NULL; - FaceElemTr.FaceGeom = faces[FaceNo] -> GetGeometryType(); - FaceFE = GetTransformationFEforElementType (faces[FaceNo] -> GetType()); + FaceElemTr.FaceGeom = faces[FaceNo]->GetGeometryType(); + FaceFE = GetTransformationFEforElementType(faces[FaceNo]->GetType()); // setup the face transformation - FaceTransformation.Attribute = faces[FaceNo] -> GetAttribute(); + FaceTransformation.Attribute = faces[FaceNo]->GetAttribute(); FaceTransformation.ElementNo = FaceNo; - v = faces[FaceNo] -> GetVertices(); - nv = faces[FaceNo] -> GetNVertices(); + v = faces[FaceNo]->GetVertices(); + nv = faces[FaceNo]->GetNVertices(); DenseMatrix &pm = FaceTransformation.GetPointMat(); - pm.SetSize (Dim, nv); + pm.SetSize(Dim, nv); for (i = 0; i < Dim; i++) for (j = 0; j < nv; j++) - pm (i, j) = vertices[v[j]](i); - FaceTransformation.SetFE (FaceFE); + pm(i, j) = vertices[v[j]](i); + FaceTransformation.SetFE(FaceFE); FaceElemTr.Face = &FaceTransformation; // setup Loc1 & Loc2 - switch (faces[FaceNo] -> GetType()) + switch (faces[FaceNo]->GetType()) { case Element::SEGMENT: - if (GetElementType (faces_info[FaceNo].Elem1No) == Element::TRIANGLE) - GetLocalSegToTriTransformation (FaceElemTr.Loc1.Transf, - faces_info[FaceNo].Elem1Inf); + if (GetElementType(faces_info[FaceNo].Elem1No) == Element::TRIANGLE) + GetLocalSegToTriTransformation(FaceElemTr.Loc1.Transf, + faces_info[FaceNo].Elem1Inf); else // assume the element is a quad - GetLocalSegToQuadTransformation (FaceElemTr.Loc1.Transf, - faces_info[FaceNo].Elem1Inf); + GetLocalSegToQuadTransformation(FaceElemTr.Loc1.Transf, + faces_info[FaceNo].Elem1Inf); if (FaceElemTr.Elem2No >= 0) - if (GetElementType (faces_info[FaceNo].Elem2No) + if (GetElementType(faces_info[FaceNo].Elem2No) == Element::TRIANGLE) - GetLocalSegToTriTransformation (FaceElemTr.Loc2.Transf, - faces_info[FaceNo].Elem2Inf); + GetLocalSegToTriTransformation(FaceElemTr.Loc2.Transf, + faces_info[FaceNo].Elem2Inf); else // assume the element is a quad - GetLocalSegToQuadTransformation (FaceElemTr.Loc2.Transf, - faces_info[FaceNo].Elem2Inf); + GetLocalSegToQuadTransformation(FaceElemTr.Loc2.Transf, + faces_info[FaceNo].Elem2Inf); break; case Element::TRIANGLE: // --------- assumes the face is a triangle -- face of a tetrahedron - GetLocalTriToTetTransformation (FaceElemTr.Loc1.Transf, - faces_info[FaceNo].Elem1Inf); + GetLocalTriToTetTransformation(FaceElemTr.Loc1.Transf, + faces_info[FaceNo].Elem1Inf); if (FaceElemTr.Elem2No >= 0) - GetLocalTriToTetTransformation (FaceElemTr.Loc2.Transf, - faces_info[FaceNo].Elem2Inf); + GetLocalTriToTetTransformation(FaceElemTr.Loc2.Transf, + faces_info[FaceNo].Elem2Inf); break; case Element::QUADRILATERAL: // --------- assumes the face is a quad -- face of a hexahedron - GetLocalQuadToHexTransformation (FaceElemTr.Loc1.Transf, - faces_info[FaceNo].Elem1Inf); + GetLocalQuadToHexTransformation(FaceElemTr.Loc1.Transf, + faces_info[FaceNo].Elem1Inf); if (FaceElemTr.Elem2No >= 0) - GetLocalQuadToHexTransformation (FaceElemTr.Loc2.Transf, - faces_info[FaceNo].Elem2Inf); + GetLocalQuadToHexTransformation(FaceElemTr.Loc2.Transf, + faces_info[FaceNo].Elem2Inf); break; } return &FaceElemTr; } -FaceElementTransformations *Mesh::GetBdrFaceTransformations (int BdrElemNo) +FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) { FaceElementTransformations *tr; int fn; @@ -435,12 +437,12 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations (int BdrElemNo) fn = be_to_edge[BdrElemNo]; if (faces_info[fn].Elem2No >= 0) return NULL; - tr = GetFaceElementTransformations (fn); - tr -> Face -> Attribute = boundary[BdrElemNo] -> GetAttribute(); + tr = GetFaceElementTransformations(fn); + tr->Face->Attribute = boundary[BdrElemNo]->GetAttribute(); return tr; } -void Mesh::GetFaceElements (int Face, int *Elem1, int *Elem2) +void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) { *Elem1 = faces_info[Face].Elem1No; *Elem2 = faces_info[Face].Elem2No; @@ -504,7 +506,7 @@ void Mesh::SetAttributes() int i, j, nattr; Array attribs; - attribs.SetSize (GetNBE()); + attribs.SetSize(GetNBE()); for (i = 0; i < attribs.Size(); i++) attribs[i] = GetBdrAttribute(i); attribs.Sort(); @@ -517,7 +519,7 @@ void Mesh::SetAttributes() if (attribs[i] != attribs[i-1]) nattr++; - bdr_attributes.SetSize (nattr); + bdr_attributes.SetSize(nattr); if (nattr > 0) { bdr_attributes[0] = attribs[0]; @@ -531,7 +533,7 @@ void Mesh::SetAttributes() } - attribs.SetSize (GetNE()); + attribs.SetSize(GetNE()); for (i = 0; i < attribs.Size(); i++) attribs[i] = GetAttribute(i); attribs.Sort(); @@ -544,7 +546,7 @@ void Mesh::SetAttributes() if (attribs[i] != attribs[i-1]) nattr++; - attributes.SetSize (nattr); + attributes.SetSize(nattr); if (nattr > 0) { attributes[0] = attribs[0]; @@ -558,7 +560,7 @@ void Mesh::SetAttributes() } } -Mesh::Mesh (int _Dim, int NVert, int NElem, int NBdrElem) +Mesh::Mesh(int _Dim, int NVert, int NElem, int NBdrElem) { Dim = _Dim; @@ -566,16 +568,16 @@ Mesh::Mesh (int _Dim, int NVert, int NElem, int NBdrElem) InitTables(); NumOfVertices = 0; - vertices.SetSize (NVert); // just allocate space for vertices + vertices.SetSize(NVert); // just allocate space for vertices NumOfElements = 0; - elements.SetSize (NElem); // just allocate space for Element * + elements.SetSize(NElem); // just allocate space for Element * NumOfBdrElements = 0; - boundary.SetSize (NBdrElem); // just allocate space for Element * + boundary.SetSize(NBdrElem); // just allocate space for Element * } -void Mesh::AddVertex (double *x) +void Mesh::AddVertex(double *x) { double *y = vertices[NumOfVertices](); @@ -584,52 +586,52 @@ void Mesh::AddVertex (double *x) NumOfVertices++; } -void Mesh::AddTri (int *vi, int attr) +void Mesh::AddTri(int *vi, int attr) { - elements[NumOfElements++] = new Triangle (vi, attr); + elements[NumOfElements++] = new Triangle(vi, attr); } -void Mesh::AddTriangle (int *vi, int attr) +void Mesh::AddTriangle(int *vi, int attr) { - elements[NumOfElements++] = new Triangle (vi, attr); + elements[NumOfElements++] = new Triangle(vi, attr); } -void Mesh::AddQuad (int *vi, int attr) +void Mesh::AddQuad(int *vi, int attr) { - elements[NumOfElements++] = new Quadrilateral (vi, attr); + elements[NumOfElements++] = new Quadrilateral(vi, attr); } -void Mesh::AddTet (int *vi, int attr) +void Mesh::AddTet(int *vi, int attr) { #ifdef MFEM_USE_MEMALLOC Tetrahedron *tet; tet = TetMemory.Alloc(); - tet -> SetVertices (vi); - tet -> SetAttribute (attr); + tet->SetVertices(vi); + tet->SetAttribute(attr); elements[NumOfElements++] = tet; #else - elements[NumOfElements++] = new Tetrahedron (vi, attr); + elements[NumOfElements++] = new Tetrahedron(vi, attr); #endif } -void Mesh::AddHex (int *vi, int attr) +void Mesh::AddHex(int *vi, int attr) { - elements[NumOfElements++] = new Hexahedron (vi, attr); + elements[NumOfElements++] = new Hexahedron(vi, attr); } -void Mesh::AddBdrSegment (int *vi, int attr) +void Mesh::AddBdrSegment(int *vi, int attr) { boundary[NumOfBdrElements++] = new Segment(vi, attr); } -void Mesh::AddBdrTriangle (int *vi, int attr) +void Mesh::AddBdrTriangle(int *vi, int attr) { boundary[NumOfBdrElements++] = new Triangle(vi, attr); } -void Mesh::AddBdrQuad (int *vi, int attr) +void Mesh::AddBdrQuad(int *vi, int attr) { - boundary[NumOfBdrElements++] = new Quadrilateral (vi, attr); + boundary[NumOfBdrElements++] = new Quadrilateral(vi, attr); } void Mesh::GenerateBoundaryElements() @@ -639,7 +641,7 @@ void Mesh::GenerateBoundaryElements() // GenerateFaces(); for (i = 0; i < boundary.Size(); i++) - FreeElement (boundary[i]); + FreeElement(boundary[i]); // count the 'NumOfBdrElements' NumOfBdrElements = 0; @@ -647,19 +649,19 @@ void Mesh::GenerateBoundaryElements() if (faces_info[i].Elem2No == -1) NumOfBdrElements++; - boundary.SetSize (NumOfBdrElements); + boundary.SetSize(NumOfBdrElements); if (Dim == 3) { - be_to_face.SetSize (NumOfBdrElements); + be_to_face.SetSize(NumOfBdrElements); delete bel_to_edge; bel_to_edge = NULL; } if (Dim == 2) - be_to_edge.SetSize (NumOfBdrElements); + be_to_edge.SetSize(NumOfBdrElements); for (j = i = 0; i < faces_info.Size(); i++) if (faces_info[i].Elem2No == -1) { - boundary[j] = faces[i] -> Duplicate(); + boundary[j] = faces[i]->Duplicate(); if (Dim == 3) be_to_face[j] = i; if (Dim == 2) @@ -675,14 +677,15 @@ typedef struct { } edge_length; // Used by qsort to sort edges in increasing (according their length) order. -static int edge_compare(const void *ii, const void *jj){ +static int edge_compare(const void *ii, const void *jj) +{ edge_length *i = (edge_length *)ii, *j = (edge_length *)jj; if (i->length > j->length) return (1); if (i->length < j->length) return (-1); return (0); } -void Mesh::FinalizeTriMesh (int generate_edges, int refine) +void Mesh::FinalizeTriMesh(int generate_edges, int refine) { CheckElementOrientation(); @@ -692,7 +695,7 @@ void Mesh::FinalizeTriMesh (int generate_edges, int refine) if (generate_edges) { el_to_edge = new Table; - NumOfEdges = GetElementToEdgeTable (*el_to_edge, be_to_edge); + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); GenerateFaces(); CheckBdrElementOrientation(); } @@ -706,14 +709,14 @@ void Mesh::FinalizeTriMesh (int generate_edges, int refine) meshgen = 1; } -void Mesh::FinalizeQuadMesh (int generate_edges, int refine) +void Mesh::FinalizeQuadMesh(int generate_edges, int refine) { CheckElementOrientation(); if (generate_edges) { el_to_edge = new Table; - NumOfEdges = GetElementToEdgeTable (*el_to_edge, be_to_edge); + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); GenerateFaces(); CheckBdrElementOrientation(); } @@ -751,7 +754,7 @@ void Mesh::MarkTriMeshForRefinement() } } -void Mesh::MarkTetMeshForRefinement(int mark_faces) +void Mesh::MarkTetMeshForRefinement() { // Mark the longest tetrahedral edge by rotating the indices so that // vertex 0 - vertex 1 is the longest edge in the element. @@ -784,23 +787,13 @@ void Mesh::MarkTetMeshForRefinement(int mark_faces) if (boundary[i]->GetType() == Element::TRIANGLE) boundary[i]->MarkEdge(v_to_v, order); - if (mark_faces) - { - for (int i = 0; i < NumOfFaces; i++) - if (faces[i]->GetType() == Element::TRIANGLE) - faces[i]->MarkEdge(v_to_v, order); - - if (el_to_edge != NULL) - GetElementToEdgeTable(*el_to_edge, be_to_edge); - } - delete [] order; delete [] length; } -void Mesh::FinalizeTetMesh (int generate_edges, int refine) +void Mesh::FinalizeTetMesh(int generate_edges, int refine) { - CheckElementOrientation (); + CheckElementOrientation(); if (refine) { @@ -817,7 +810,8 @@ void Mesh::FinalizeTetMesh (int generate_edges, int refine) el_to_edge = new Table; NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); } - else{ + else + { el_to_edge = NULL; // Not really necessary -- InitTables was called bel_to_edge = NULL; NumOfEdges = 0; @@ -828,9 +822,9 @@ void Mesh::FinalizeTetMesh (int generate_edges, int refine) meshgen = 1; } -void Mesh::FinalizeHexMesh (int generate_edges, int refine) +void Mesh::FinalizeHexMesh(int generate_edges, int refine) { - CheckElementOrientation (); + CheckElementOrientation(); GetElementToFaceTable(); GenerateFaces(); @@ -843,7 +837,7 @@ void Mesh::FinalizeHexMesh (int generate_edges, int refine) if (generate_edges) { el_to_edge = new Table; - NumOfEdges = GetElementToEdgeTable (*el_to_edge, be_to_edge); + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); } else NumOfEdges = 0; @@ -853,8 +847,8 @@ void Mesh::FinalizeHexMesh (int generate_edges, int refine) meshgen = 2; } -Mesh :: Mesh ( int nx, int ny, Element::Type type, int generate_edges, - double sx, double sy ) +Mesh::Mesh(int nx, int ny, Element::Type type, int generate_edges, + double sx, double sy) { int i, j, k; @@ -864,24 +858,24 @@ Mesh :: Mesh ( int nx, int ny, Element::Type type, int generate_edges, InitTables(); // Creates quadrilateral mesh - if( type == Element::QUADRILATERAL ) + if (type == Element::QUADRILATERAL) { meshgen = 2; NumOfVertices = (nx+1) * (ny+1); NumOfElements = nx * ny; NumOfBdrElements = 2 * nx + 2 * ny; - vertices.SetSize (NumOfVertices); - elements.SetSize (NumOfElements); - boundary.SetSize (NumOfBdrElements); + vertices.SetSize(NumOfVertices); + elements.SetSize(NumOfElements); + boundary.SetSize(NumOfBdrElements); double cx, cy; int ind[4]; // Sets vertices and the corresponding coordinates k = 0; - for( j=0; j> ws; - meshin.getline (buffer, buflen); - if (!strcmp(buffer, "MFEM mesh v1.0")) - dim = 0; - else if (!strcmp(buffer, "areamesh2") || !strcmp(buffer, "curved_areamesh2")) - dim = 2; - else if (!strcmp(buffer, "TrueGrid")) - dim = 3; - else if (!strcmp(buffer, "NETGEN")) - dim = 3; - else if (!strcmp(buffer, "NETGEN_Neutral_Format")) - dim = 3; - else - // Unknown type of mesh - dim = -1; + getline(meshin, buff); + if (buff == "MFEM mesh v1.0") + type = 0; + if (buff == "linemesh") + type = 1; + else if (buff == "areamesh2" || buff == "curved_areamesh2") + type = 2; + else if (buff == "NETGEN" || buff == "NETGEN_Neutral_Format") + type = 3; + else if (buff == "TrueGrid") + type = 4; + else if (buff == "# vtk DataFile Version 3.0") + type = 5; + meshin.seekg(start_pos); - meshin.seekg (start_pos); - - return dim; + return type; } Element *NewElement(int geom) @@ -1091,37 +1090,46 @@ Element *NewElement(int geom) return NULL; } -void Mesh::Load( istream &input, int generate_edges, int refine ) +// see Tetrahedron::edges +static const int vtk_quadratic_tet[10] = +{ 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 }; + +// see Hexahedron::edges & Mesh::GenerateFaces +static const int vtk_quadratic_hex[27] = +{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 24, 22, 21, 23, 20, 25, 26 }; + +void Mesh::Load(istream &input, int generate_edges, int refine) { - int i, j, ints[32], n, attr, curved = 0; + int i, j, ints[32], n, attr, curved = 0, read_gf = 1; const int buflen = 1024; char buf[buflen]; #ifdef MFEM_DEBUG - if ( !input ) - mfem_error ("Input file stream not opened : Mesh::Load"); + if (!input) + mfem_error("Input file stream not opened : Mesh::Load"); #endif if (NumOfVertices != -1) { // Delete the elements. - for(i=0; i> buf; input >> NumOfVertices; - vertices.SetSize (NumOfVertices); + vertices.SetSize(NumOfVertices); // Sets vertices and the corresponding coordinates - for(j = 0; j < NumOfVertices; j++) + for (j = 0; j < NumOfVertices; j++) input >> vertices[j](0); input >> NumOfElements; - elements.SetSize (NumOfElements); + elements.SetSize(NumOfElements); // Sets elements and the corresponding indices of vertices - for(j = 0; j < NumOfElements; j++) { + for (j = 0; j < NumOfElements; j++) + { input >> a >> p1 >> p2; elements[j] = new Segment(p1-1, p2-1, a); } int ind[1]; input >> NumOfBdrElements; - boundary.SetSize (NumOfBdrElements); - for(j = 0; j < NumOfBdrElements; j++) { + boundary.SetSize(NumOfBdrElements); + for (j = 0; j < NumOfBdrElements; j++) + { input >> a >> ind[0]; ind[0]--; boundary[j] = new Point(ind,a); } } - else if (Dim == 2) + else if (mesh_type == 2) { + // Read planar mesh in Netgen format. + Dim = 2; + // Read the type of the mesh. + input >> buf; + if (!strcmp("curved_areamesh2", buf)) + curved = 1; + + // Read the boundary elements. + input >> NumOfBdrElements; + boundary.SetSize(NumOfBdrElements); + for (i = 0; i < NumOfBdrElements; i++) + { + input >> attr + >> ints[0] >> ints[1]; + ints[0]--; ints[1]--; + boundary[i] = new Segment(ints, attr); + } + + // Read the elements. + input >> NumOfElements; + elements.SetSize(NumOfElements); + for (i = 0; i < NumOfElements; i++) + { + input >> attr >> n; + for (j = 0; j < n; j++) + { + input >> ints[j]; + ints[j]--; + } + switch (n) + { + case 2: + elements[i] = new Segment(ints, attr); + break; + case 3: + elements[i] = new Triangle(ints, attr); + break; + case 4: + elements[i] = new Quadrilateral(ints, attr); + break; + } + } + + if (!curved) + { + // Read the vertices. + input >> NumOfVertices; + vertices.SetSize(NumOfVertices); + for (i = 0; i < NumOfVertices; i++) + for (j = 0; j < Dim; j++) + input >> vertices[i](j); + } + else + { + input >> NumOfVertices; + vertices.SetSize(NumOfVertices); + input >> ws; + } + } + else if (mesh_type == 3) + { + // Read a netgen format mesh of tetrahedra. + Dim = 3; // Read the type of the mesh. input >> buf; + // Read the vertices + input >> NumOfVertices; + + vertices.SetSize(NumOfVertices); + for (i = 0; i < NumOfVertices; i++) + for (j = 0; j < Dim; j++) + input >> vertices[i](j); + + // Read the elements + input >> NumOfElements; + elements.SetSize(NumOfElements); + for (i = 0; i < NumOfElements; i++) + { + input >> attr; + for (j = 0; j < 4; j++) + { + input >> ints[j]; + ints[j]--; + } +#ifdef MFEM_USE_MEMALLOC + Tetrahedron *tet; + tet = TetMemory.Alloc(); + tet->SetVertices(ints); + tet->SetAttribute(attr); + elements[i] = tet; +#else + elements[i] = new Tetrahedron(ints, attr); +#endif + } + + // Read the boundary information. + input >> NumOfBdrElements; + boundary.SetSize(NumOfBdrElements); + for (i = 0; i < NumOfBdrElements; i++) + { + input >> attr; + for (j = 0; j < 3; j++) + { + input >> ints[j]; + ints[j]--; + } + boundary[i] = new Triangle(ints, attr); + } + } + else if (mesh_type == 4) + { // Reading TrueGrid mesh. - if (strcmp("TrueGrid", buf)==0) + + // Read the type of the mesh. + input >> buf; + + // TODO: find the actual dimension + Dim = 3; + + if (Dim == 2) { int vari; double varf; @@ -1261,17 +1388,20 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) input.getline(buf, buflen); // Read the vertices. - vertices.SetSize (NumOfVertices); - for (i=0; i> vari >> varf >> vertices[i](0) >> vertices[i](1); input.getline(buf, buflen); } // Read the elements. - elements.SetSize (NumOfElements); - for (i=0; i < NumOfElements; i++){ + elements.SetSize(NumOfElements); + for (i = 0; i < NumOfElements; i++) + { input >> vari >> attr; - for(j=0; j<4; j++){ + for (j = 0; j < 4; j++) + { input >> ints[j]; ints[j]--; } @@ -1280,70 +1410,7 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) elements[i] = new Quadrilateral(ints, attr); } } - // Read planar mesh in Netgen format. - else - { - if (!strcmp("curved_areamesh2", buf)) - curved = 1; - - // Read the boundary elements. - input >> NumOfBdrElements; - boundary.SetSize (NumOfBdrElements); - for(i=0; i> attr - >> ints[0] >> ints[1]; - ints[0]--; ints[1]--; - boundary[i] = new Segment(ints, attr); - } - - // Read the elements. - input >> NumOfElements; - elements.SetSize (NumOfElements); - for(i=0; i> attr >> n; - for(j=0; j> ints[j]; - ints[j]--; - } - switch (n){ - case 2: - elements[i] = new Segment(ints, attr); - break; - case 3: - elements[i] = new Triangle(ints, attr); - break; - case 4: - elements[i] = new Quadrilateral(ints, attr); - break; - } - } - - if (!curved) - { - // Read the vertices. - input >> NumOfVertices; - vertices.SetSize (NumOfVertices); - for(i=0; i> vertices[i](j); - } - else - { - input >> NumOfVertices; - vertices.SetSize (NumOfVertices); - input >> ws; - } - - // Read the boundary information... - } - } - else // --- Dim=3. - { - // Read the type of the mesh. - input >> buf; - - // Read a TrueGrid format mesh of hexahedrons. - if (strcmp("TrueGrid", buf)==0) + else if (Dim == 3) { int vari; double varf; @@ -1355,17 +1422,20 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) input.getline(buf, buflen); input.getline(buf, buflen); // Read the vertices. - vertices.SetSize (NumOfVertices); - for (i=0; i> vari >> varf >> vertices[i](0) >> vertices[i](1) >> vertices[i](2); input.getline(buf, buflen); } // Read the elements. - elements.SetSize (NumOfElements); - for (i=0; i < NumOfElements; i++){ + elements.SetSize(NumOfElements); + for (i = 0; i < NumOfElements; i++) + { input >> vari >> attr; - for(j=0; j<8; j++){ + for (j = 0; j < 8; j++) + { input >> ints[j]; ints[j]--; } @@ -1373,10 +1443,12 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) elements[i] = new Hexahedron(ints, attr); } // Read the boundary elements. - boundary.SetSize (NumOfBdrElements); - for (i=0; i < NumOfBdrElements; i++){ + boundary.SetSize(NumOfBdrElements); + for (i = 0; i < NumOfBdrElements; i++) + { input >> attr; - for(j=0; j<4; j++){ + for (j = 0; j < 4; j++) + { input >> ints[j]; ints[j]--; } @@ -1384,48 +1456,274 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) boundary[i] = new Quadrilateral(ints, attr); } } - // Read a netgen format mesh of tetrahedra. - else + } + else if (mesh_type == 5) + { + // Reading VTK mesh + + string buff; + getline(input, buff); // "# vtk DataFile Version 3.0" + getline(input, buff); // comment line + getline(input, buff); + if (buff != "ASCII") { - // Read the vertices - input >> NumOfVertices; + mfem_error("Mesh::Load : VTK mesh is not in ASCII format!"); + return; + } + getline(input, buff); + if (buff != "DATASET UNSTRUCTURED_GRID") + { + mfem_error("Mesh::Load : VTK mesh is not UNSTRUCTURED_GRID!"); + return; + } - vertices.SetSize( NumOfVertices); - for(i=0; i> vertices[i](j); + // Read the points + int np = 0; + Vector points; + input >> buff; + if (buff == "POINTS") + { + input >> np >> ws; + points.SetSize(3*np); + getline(input, buff); // "double" + for (i = 0; i < points.Size(); i++) + input >> points(i); + } - // Read the elements + // Read the cells + NumOfElements = n = 0; + Array cells_data; + input >> ws >> buff; + if (buff == "CELLS") + { + input >> NumOfElements >> n >> ws; + cells_data.SetSize(n); + for (i = 0; i < n; i++) + input >> cells_data[i]; + } + + // Read the cell types + Dim = 0; + int order = 1; + input >> ws >> buff; + if (buff == "CELL_TYPES") + { input >> NumOfElements; - elements.SetSize (NumOfElements); - for(i=0; i> attr; - for(j=0; j<4; j++){ - input >> ints[j]; - ints[j]--; - } + elements.SetSize(NumOfElements); + for (j = i = 0; i < NumOfElements; i++) + { + int ct; + input >> ct; + switch (ct) + { + case 5: // triangle + Dim = 2; + elements[i] = new Triangle(&cells_data[j+1]); + break; + case 9: // quadrilateral + Dim = 2; + elements[i] = new Quadrilateral(&cells_data[j+1]); + break; + case 10: // tetrahedron + Dim = 3; #ifdef MFEM_USE_MEMALLOC - Tetrahedron *tet; - tet = TetMemory.Alloc(); - tet -> SetVertices (ints); - tet -> SetAttribute (attr); - elements[i] = tet; + elements[i] = TetMemory.Alloc(); + elements[i]->SetVertices(&cells_data[j+1]); #else - elements[i] = new Tetrahedron(ints, attr); + elements[i] = new Tetrahedron(&cells_data[j+1]); #endif + break; + case 12: // hexahedron + Dim = 3; + elements[i] = new Hexahedron(&cells_data[j+1]); + break; + + case 22: // quadratic triangle + Dim = 2; + order = 2; + elements[i] = new Triangle(&cells_data[j+1]); + break; + case 28: // biquadratic quadrilateral + Dim = 2; + order = 2; + elements[i] = new Quadrilateral(&cells_data[j+1]); + break; + case 24: // quadratic tetrahedron + Dim = 3; + order = 2; +#ifdef MFEM_USE_MEMALLOC + elements[i] = TetMemory.Alloc(); + elements[i]->SetVertices(&cells_data[j+1]); +#else + elements[i] = new Tetrahedron(&cells_data[j+1]); +#endif + break; + case 29: // triquadratic hexahedron + Dim = 3; + order = 2; + elements[i] = new Hexahedron(&cells_data[j+1]); + break; + default: + cerr << "Mesh::Load : VTK mesh : cell type " << ct + << " is not supported!" << endl; + mfem_error(); + return; + } + j += cells_data[j] + 1; + } + } + + // Read attributes + streampos sp = input.tellg(); + input >> ws >> buff; + if (buff == "CELL_DATA") + { + input >> n >> ws; + getline(input, buff); + if (buff == "SCALARS material int") + { + getline(input, buff); // "LOOKUP_TABLE default" + for (i = 0; i < NumOfElements; i++) + { + input >> attr; + elements[i]->SetAttribute(attr); + } + } + else + input.seekg(sp); + } + else + input.seekg(sp); + + if (order == 1) + { + cells_data.DeleteAll(); + NumOfVertices = np; + vertices.SetSize(np); + for (i = 0; i < np; i++) + { + vertices[i](0) = points(3*i+0); + vertices[i](1) = points(3*i+1); + vertices[i](2) = points(3*i+2); + } + points.Destroy(); + + // No boundary is defined in a VTK mesh + NumOfBdrElements = 0; + } + else if (order == 2) + { + curved = 1; + + // generate new enumeration for the vertices + Array pts_dof(np); + pts_dof = -1; + for (n = i = 0; i < NumOfElements; i++) + { + int *v = elements[i]->GetVertices(); + int nv = elements[i]->GetNVertices(); + for (j = 0; j < nv; j++) + if (pts_dof[v[j]] == -1) + pts_dof[v[j]] = n++; + } + // keep the original ordering of the vertices + for (n = i = 0; i < np; i++) + if (pts_dof[i] != -1) + pts_dof[i] = n++; + // update the element vertices + for (i = 0; i < NumOfElements; i++) + { + int *v = elements[i]->GetVertices(); + int nv = elements[i]->GetNVertices(); + for (j = 0; j < nv; j++) + v[j] = pts_dof[v[j]]; + } + // Define the 'vertices' from the 'points' through the 'pts_dof' map + NumOfVertices = n; + vertices.SetSize(n); + for (i = 0; i < np; i++) + { + if ((j = pts_dof[i]) != -1) + { + vertices[j](0) = points(3*i+0); + vertices[j](1) = points(3*i+1); + vertices[j](2) = points(3*i+2); + } } - // Read the boundary information. - input >> NumOfBdrElements; - boundary.SetSize(NumOfBdrElements); - for(i=0; i< NumOfBdrElements; i++){ - input >> attr; - for(j=0; j<3; j++){ - input >> ints[j]; - ints[j]--; - } - boundary[i] = new Triangle(ints, attr); + // No boundary is defined in a VTK mesh + NumOfBdrElements = 0; + + // Generate faces and edges so that we can define quadratic + // FE space on the mesh + + // Generate faces + if (Dim > 2) + { + GetElementToFaceTable(); + GenerateFaces(); } + else + NumOfFaces = 0; + + // Generate edges + el_to_edge = new Table; + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); + if (Dim == 2) + GenerateFaces(); // 'Faces' in 2D refers to the edges + + // Define quadratic FE space + FiniteElementCollection *fec = new QuadraticFECollection; + FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim); + Nodes = new GridFunction(fes); + Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes' + own_nodes = 1; + + // Map vtk points to edge/face/element dofs + Array dofs; + for (n = i = 0; i < NumOfElements; i++) + { + fes->GetElementDofs(i, dofs); + const int *vtk_mfem; + switch (elements[i]->GetGeometryType()) + { + case Geometry::TRIANGLE: + case Geometry::SQUARE: + vtk_mfem = vtk_quadratic_hex; break; // identity map + case Geometry::TETRAHEDRON: + vtk_mfem = vtk_quadratic_tet; break; + case Geometry::CUBE: + vtk_mfem = vtk_quadratic_hex; break; + } + + for (n++, j = 0; j < dofs.Size(); j++, n++) + { + if (pts_dof[cells_data[n]] == -1) + { + pts_dof[cells_data[n]] = dofs[vtk_mfem[j]]; + } + else + { + if (pts_dof[cells_data[n]] != dofs[vtk_mfem[j]]) + mfem_error("Mesh::Load : VTK mesh : " + "inconsistent quadratic mesh!"); + } + } + } + + // Define the 'Nodes' from the 'points' through the 'pts_dof' map + for (i = 0; i < np; i++) + { + dofs.SetSize(1); + if ((dofs[0] = pts_dof[i]) != -1) + { + fes->DofsToVDofs(dofs); + for (j = 0; j < dofs.Size(); j++) + (*Nodes)(dofs[j]) = points(3*i+j); + } + } + + read_gf = 0; } } @@ -1436,7 +1734,10 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) // 4) NumOfVertices, with allocated space in vertices // 5) curved // 5a) if curved == 0, vertices must be defined - // 5b) if curved != 1, 'input' must point to a GridFunction + // 5b) if curved != 0 and read_gf != 0, + // 'input' must point to a GridFunction + // 5c) if curved != 0 and read_gf == 0, + // vertices and Nodes must be defined // set the mesh type ('meshgen') meshgen = 0; @@ -1455,9 +1756,6 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) } } - // generate the arrays 'attributes' and ' bdr_attributes' - SetAttributes(); - if (!curved) { // check and fix element orientation @@ -1467,6 +1765,20 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) MarkForRefinement(); } + // generate the faces + if (Dim > 2) + { + GetElementToFaceTable(); + GenerateFaces(); + if (NumOfBdrElements == 0) + GenerateBoundaryElements(); + // check and fix boundary element orientation + if ( !(curved && (meshgen & 1)) ) + CheckBdrElementOrientation(); + } + else + NumOfFaces = 0; + // generate edges if requested if (Dim > 1 && generate_edges == 1) { @@ -1475,52 +1787,219 @@ void Mesh::Load( istream &input, int generate_edges, int refine ) if (Dim == 2) { GenerateFaces(); // 'Faces' in 2D refers to the edges + if (NumOfBdrElements == 0) + GenerateBoundaryElements(); // check and fix boundary element orientation - CheckBdrElementOrientation(); + if ( !(curved && (meshgen & 1)) ) + CheckBdrElementOrientation(); } c_el_to_edge = NULL; } else NumOfEdges = 0; - // generate the faces - if (Dim > 2) - { - GetElementToFaceTable(); - GenerateFaces(); - // check and fix boundary element orientation - CheckBdrElementOrientation(); - } - else - NumOfFaces = 0; + // generate the arrays 'attributes' and ' bdr_attributes' + SetAttributes(); if (curved) { - Nodes = new GridFunction(this, input); - own_nodes = 1; - for (i = 0; i < Nodes->VectorDim(); i++) + if (read_gf) { - Vector vert_val; - Nodes->GetNodalValues(vert_val, i+1); - for (j = 0; j < NumOfVertices; j++) - vertices[j](i) = vert_val(j); + Nodes = new GridFunction(this, input); + own_nodes = 1; + for (i = 0; i < Nodes->VectorDim(); i++) + { + Vector vert_val; + Nodes->GetNodalValues(vert_val, i+1); + for (j = 0; j < NumOfVertices; j++) + vertices[j](i) = vert_val(j); + } } - // CheckElementOrientation(); - // if (refine) - // MarkForRefinement(); // uses the vertices! changes topology! + // Check orientation and mark edges; only for triangles / tets + if (meshgen & 1) + { + FiniteElementSpace *fes = Nodes->FESpace(); + const FiniteElementCollection *fec = fes->FEColl(); + int num_edge_dofs = fec->DofForGeometry(Geometry::SEGMENT); + DSTable *old_v_to_v = NULL; + if (num_edge_dofs) + { + old_v_to_v = new DSTable(NumOfVertices); + GetVertexToVertexTable(*old_v_to_v); + } + // assuming all faces have the same geometry + int num_face_dofs = + (Dim < 3) ? 0 : fec->DofForGeometry(GetFaceBaseGeometry(0)); + // assuming all elements have the same geometry + int num_elem_dofs = fec->DofForGeometry(GetElementBaseGeometry(0)); + + // check orientation and mark for refinement using just vertices + // (i.e. higher order curvature is not used) + CheckElementOrientation(); + if (refine) + MarkForRefinement(); // changes topology! + + // reorder the Nodes + Vector onodes = *Nodes; + + Array old_dofs, new_dofs; + int offset; +#ifdef MFEM_DEBUG + int redges = 0; +#endif + + // vertex dofs do not need to be moved + offset = NumOfVertices * fec->DofForGeometry(Geometry::POINT); + + // edge dofs: + // edge enumeration may be different but edge orientation is + // the same + if (num_edge_dofs > 0) + { + DSTable new_v_to_v(NumOfVertices); + GetVertexToVertexTable(new_v_to_v); + + for (i = 0; i < NumOfVertices; i++) + { + for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it) + { + int old_i = (*old_v_to_v)(i, it.Column()); + int new_i = it.Index(); +#ifdef MFEM_DEBUG + if (old_i != new_i) + redges++; +#endif + old_dofs.SetSize(num_edge_dofs); + new_dofs.SetSize(num_edge_dofs); + for (j = 0; j < num_edge_dofs; j++) + { + old_dofs[j] = offset + old_i * num_edge_dofs + j; + new_dofs[j] = offset + new_i * num_edge_dofs + j; + } + fes->DofsToVDofs(old_dofs); + fes->DofsToVDofs(new_dofs); + for (j = 0; j < old_dofs.Size(); j++) + (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]); + } + } + offset += NumOfEdges * num_edge_dofs; + delete old_v_to_v; + } +#ifdef MFEM_DEBUG + cout << "Mesh::Load : redges = " << redges << endl; +#endif + + // face dofs: + // both enumeration and orientation of the faces + // may be different + if (num_face_dofs > 0) + { + // generate the old face-vertex table + Table old_face_vertex; + old_face_vertex.MakeI(NumOfFaces); + for (i = 0; i < NumOfFaces; i++) + old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices()); + old_face_vertex.MakeJ(); + for (i = 0; i < NumOfFaces; i++) + old_face_vertex.AddConnections(i, faces[i]->GetVertices(), + faces[i]->GetNVertices()); + old_face_vertex.ShiftUpI(); + + // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info' + STable3D *faces_tbl = GetElementToFaceTable(1); + GenerateFaces(); + + // loop over the old face numbers + for (i = 0; i < NumOfFaces; i++) + { + int *old_v = old_face_vertex.GetRow(i), *new_v; + int new_i, new_or, *dof_ord; + switch (old_face_vertex.RowSize(i)) + { + case 3: + new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]); + new_v = faces[new_i]->GetVertices(); + new_or = GetTriOrientation(old_v, new_v); + dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, + new_or); + break; + case 4: + new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]); + new_v = faces[new_i]->GetVertices(); + new_or = GetQuadOrientation(old_v, new_v); + dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, + new_or); + break; + } + + old_dofs.SetSize(num_face_dofs); + new_dofs.SetSize(num_face_dofs); + for (j = 0; j < num_face_dofs; j++) + { + old_dofs[j] = offset + i * num_face_dofs + j; + new_dofs[j] = offset + new_i * num_face_dofs + dof_ord[j]; + // we assumed the dofs are non-directional + // i.e. dof_ord[j] is >= 0 + } + fes->DofsToVDofs(old_dofs); + fes->DofsToVDofs(new_dofs); + for (j = 0; j < old_dofs.Size(); j++) + (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]); + } + + offset += NumOfFaces * num_face_dofs; + delete faces_tbl; + } + + // element dofs: + // element orientation may be different + if (num_elem_dofs > 0) + { + // matters when the 'fec' is + // - Pk on triangles, k >= 4 + // - Qk on quads, k >= 3 + // - Pk on tets, k >= 5 + // - Qk on hexes, k >= 3 + // - ... + } + + // Update Tables, faces, etc + if (Dim > 2) + { + if (num_face_dofs == 0) + { + // needed for FE spaces that have face dofs, even if + // the 'Nodes' do not have face dofs. + GetElementToFaceTable(); + GenerateFaces(); + } + CheckBdrElementOrientation(); + } + if (el_to_edge) + { + // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D) + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); + if (Dim == 2) + { + // update 'faces' and 'faces_info' + GenerateFaces(); + CheckBdrElementOrientation(); + } + } + } } } -Mesh::Mesh ( istream &input, Vector **data, int nprocessors, - int currentprocessor, int generate_edges ) +Mesh::Mesh(istream &input, Vector **data, int nprocessors, + int currentprocessor, int generate_edges) { Init(); InitTables(); - Load ( input, data, nprocessors, currentprocessor, generate_edges ); + Load(input, data, nprocessors, currentprocessor, generate_edges); } -Mesh::Mesh (istream ** in, int np, int * dim) +Mesh::Mesh(istream ** in, int np, int * dim) { int i,p,j,attr,ints[8]; int * shift = new int[np]; @@ -1531,12 +2010,14 @@ Mesh::Mesh (istream ** in, int np, int * dim) InitTables(); char first_line[1000]; - for (p = 0; p < np; p++) { + for (p = 0; p < np; p++) + { *in[p] >> first_line; } - shift[0]=0; + shift[0] = 0; NumOfVertices = 0; - for (p = 0; p < np; p++) { + for (p = 0; p < np; p++) + { *in[p] >> dim[p]; NumOfVertices += dim[p]; if (p < (np-1)) @@ -1546,27 +2027,31 @@ Mesh::Mesh (istream ** in, int np, int * dim) vertices.SetSize(NumOfVertices); // Read the vertices - for (p = 0; p < np; p++) { - for(i=0; i> vertices[shift[p]+i](j); } int * edim = new int[np]; NumOfElements = 0; - for (p = 0; p < np; p++) { + for (p = 0; p < np; p++) + { *in[p] >> edim[p]; NumOfElements += edim[p]; } - elements.SetSize (NumOfElements); + elements.SetSize(NumOfElements); - int e=0; + int e = 0; // Read the elements for (p = 0; p < np; p++) - for(i=0; i> attr; - for(j=0; j<4; j++) { + for (j = 0; j<4; j++) + { *in[p] >> ints[j]; ints[j]--; ints[j] += shift[p]; @@ -1574,8 +2059,8 @@ Mesh::Mesh (istream ** in, int np, int * dim) #ifdef MFEM_USE_MEMALLOC Tetrahedron *tet; tet = TetMemory.Alloc(); - tet -> SetVertices (ints); - tet -> SetAttribute (attr); + tet->SetVertices(ints); + tet->SetAttribute(attr); elements[e++] = tet; #else elements[e++] = new Tetrahedron(ints, attr); @@ -1584,7 +2069,8 @@ Mesh::Mesh (istream ** in, int np, int * dim) int * bdim = new int[np]; NumOfBdrElements = 0; - for (p = 0; p < np; p++) { + for (p = 0; p < np; p++) + { *in[p] >> bdim[p]; NumOfBdrElements += bdim[p]; } @@ -1594,9 +2080,11 @@ Mesh::Mesh (istream ** in, int np, int * dim) int be=0; // Read the boundary information. for (p = 0; p < np; p++) - for(i=0; i> attr; - for(j=0; j<3; j++){ + for (j = 0; j < 3; j++) + { *in[p] >> ints[j]; ints[j]--; ints[j] += shift[p]; @@ -1611,15 +2099,15 @@ Mesh::Mesh (istream ** in, int np, int * dim) delete [] edim; } -void Mesh::Load( istream &input, Vector **data, int nprocessors, - int currentprocessor, int generate_edges ) +void Mesh::Load(istream &input, Vector **data, int nprocessors, + int currentprocessor, int generate_edges) { int i, j, ints[32], attr; static int elems = 0, bdrelems = 0, totalNumberOfVertices = 0, np = 0; #ifdef MFEM_DEBUG - if ( !input ) - mfem_error ("Input file stream not opened : Mesh::Load"); + if (!input) + mfem_error("Input file stream not opened : Mesh::Load"); #endif Dim = 3; @@ -1637,34 +2125,37 @@ void Mesh::Load( istream &input, Vector **data, int nprocessors, // Read the vertices input >> NumOfVertices >> totalNumberOfVertices; - if (np == 0){ - vertices.SetSize( totalNumberOfVertices ); - for(c=0; cSetSize( totalNumberOfVertices ); + if (np == 0) + { + vertices.SetSize(totalNumberOfVertices); + for (c = 0; c < components; c++) + data[c]->SetSize(totalNumberOfVertices); } - for(i=0; i> gid; - for(j=0; j> vertices[gid](j); - for(c=0; c> (*(data[c]))(gid); } // Read the elements input >> NumOfElements >> totalNumberOfElements; if (np == 0) - elements.SetSize( totalNumberOfElements ); + elements.SetSize(totalNumberOfElements); - for(i=0; i> attr; - for(j=0; j<4; j++) + for (j = 0; j < 4; j++) input >> ints[j]; #ifdef MFEM_USE_MEMALLOC Tetrahedron *tet; tet = TetMemory.Alloc(); - tet -> SetVertices (ints); - tet -> SetAttribute (attr); + tet->SetVertices(ints); + tet->SetAttribute(attr); elements[i+elems] = tet; #else elements[i+elems] = new Tetrahedron(ints, attr); @@ -1677,9 +2168,10 @@ void Mesh::Load( istream &input, Vector **data, int nprocessors, if (np == 0) boundary.SetSize(totalNumberOfBdrElements); - for(i=0; i< NumOfBdrElements; i++){ + for (i = 0; i < NumOfBdrElements; i++) + { input >> attr; - for(j=0; j<3; j++) + for (j = 0; j < 3; j++) input >> ints[j]; boundary[i+bdrelems] = new Triangle(ints, attr); } @@ -1687,7 +2179,8 @@ void Mesh::Load( istream &input, Vector **data, int nprocessors, np++; - if (np == nprocessors){ + if (np == nprocessors) + { NumOfVertices = totalNumberOfVertices; NumOfElements = elems; NumOfBdrElements = bdrelems; @@ -1698,19 +2191,22 @@ void Mesh::Load( istream &input, Vector **data, int nprocessors, { GetElementToFaceTable(); GenerateFaces(); + CheckBdrElementOrientation(); } - if (generate_edges == 1){ + if (generate_edges == 1) + { el_to_edge = new Table; NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); if (Dim == 2) + { GenerateFaces(); + CheckBdrElementOrientation(); + } } else NumOfEdges = 0; - CheckBdrElementOrientation(); - SetAttributes(); np = elems = bdrelems = totalNumberOfVertices = 0; @@ -1760,18 +2256,18 @@ void Mesh::CheckElementOrientation() if (Dim == 2) { - DenseMatrix tri (2, 2); + DenseMatrix tri(2, 2); for (i = 0; i < NumOfElements; i++) { - vi = elements[i] -> GetVertices(); + vi = elements[i]->GetVertices(); for (j = 0; j < 3; j++) v[j] = vertices[vi[j]](); for (j = 0; j < 2; j++) for (k = 0; k < 2; k++) - tri (j, k) = v[j+1][k] - v[0][k]; + tri(j, k) = v[j+1][k] - v[0][k]; if (tri.Det() < 0.0) - switch (GetElementType (i)) + switch (GetElementType(i)) { case Element::TRIANGLE: k = vi[0], vi[0] = vi[1], vi[1] = k, wo++; @@ -1785,19 +2281,19 @@ void Mesh::CheckElementOrientation() if (Dim == 3) { - DenseMatrix tet (3, 3); + DenseMatrix tet(3, 3); for (i = 0; i < NumOfElements; i++) { - vi = elements[i] -> GetVertices(); - switch (GetElementType (i)) + vi = elements[i]->GetVertices(); + switch (GetElementType(i)) { case Element::TETRAHEDRON: for (j = 0; j < 4; j++) v[j] = vertices[vi[j]](); for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) - tet (j, k) = v[j+1][k] - v[0][k]; + tet(j, k) = v[j+1][k] - v[0][k]; if (tet.Det() < 0.0) k = vi[0], vi[0] = vi[1], vi[1] = k, wo++; break; @@ -1814,7 +2310,7 @@ void Mesh::CheckElementOrientation() //#endif } -int Mesh::GetTriOrientation (const int * base, const int * test) +int Mesh::GetTriOrientation(const int *base, const int *test) { int orient; @@ -1841,13 +2337,13 @@ int Mesh::GetTriOrientation (const int * base, const int * test) const int *aor = tri_orient[orient]; for (int j = 0; j < 3; j++) if (test[aor[j]] != base[j]) - mfem_error ("Mesh::GetTriOrientation (...)"); + mfem_error("Mesh::GetTriOrientation(...)"); #endif return orient; } -int Mesh::GetQuadOrientation (const int * base, const int * test) +int Mesh::GetQuadOrientation(const int *base, const int *test) { int i; @@ -1869,7 +2365,7 @@ int Mesh::GetQuadOrientation (const int * base, const int * test) for (int j = 0; j < 4; j++) if (test[aor[j]] != base[j]) { - cerr << "Mesh::GetQuadOrientation (...)" << endl; + cerr << "Mesh::GetQuadOrientation(...)" << endl; cerr << " base = ["; for (int k = 0; k < 4; k++) cerr << " " << base[k]; @@ -1897,8 +2393,8 @@ void Mesh::CheckBdrElementOrientation() { if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face { - int *bv = boundary[i] -> GetVertices(); - int *fv = faces[be_to_edge[i]] -> GetVertices(); + int *bv = boundary[i]->GetVertices(); + int *fv = faces[be_to_edge[i]]->GetVertices(); if (bv[0] != fv[0]) { j = bv[0]; bv[0] = bv[1]; bv[1] = j; @@ -1908,22 +2404,26 @@ void Mesh::CheckBdrElementOrientation() } } - if (Dim == 3) { + if (Dim == 3) + { int el, *bv, *ev; int v[4]; - for (i = 0; i < NumOfBdrElements; i++) { - if (faces_info[be_to_face[i]].Elem2No < 0) { // boundary face - bv = boundary[i] -> GetVertices(); + for (i = 0; i < NumOfBdrElements; i++) + { + if (faces_info[be_to_face[i]].Elem2No < 0) + { // boundary face + bv = boundary[i]->GetVertices(); el = faces_info[be_to_face[i]].Elem1No; - ev = elements[el] -> GetVertices(); - switch (GetElementType (el)) { + ev = elements[el]->GetVertices(); + switch (GetElementType(el)) + { case Element::TETRAHEDRON: { - int *fv = faces[be_to_face[i]] -> GetVertices(); + int *fv = faces[be_to_face[i]]->GetVertices(); int orientation; // orientation of the bdr. elem. w.r.t. the // corresponding face element (that's the base) - orientation = GetTriOrientation (fv, bv); + orientation = GetTriOrientation(fv, bv); if (orientation % 2) { // wrong orientation -- swap vertices 0 and 1 so that @@ -1935,7 +2435,8 @@ void Mesh::CheckBdrElementOrientation() break; case Element::HEXAHEDRON: - switch (faces_info[be_to_face[i]].Elem1Inf/64) { + switch (faces_info[be_to_face[i]].Elem1Inf/64) + { case 0: v[0] = ev[3]; v[1] = ev[2]; v[2] = ev[1]; v[3] = ev[0]; break; @@ -1955,7 +2456,8 @@ void Mesh::CheckBdrElementOrientation() v[0] = ev[4]; v[1] = ev[5]; v[2] = ev[6]; v[3] = ev[7]; break; } - if (GetQuadOrientation (v, bv) % 2) { + if (GetQuadOrientation(v, bv) % 2) + { j = bv[0]; bv[0] = bv[2]; bv[2] = j; wo++; } @@ -1971,14 +2473,14 @@ void Mesh::CheckBdrElementOrientation() //#endif } -void Mesh::GetElementEdges (int i, Array &edges, Array &cor) +void Mesh::GetElementEdges(int i, Array &edges, Array &cor) const { if (el_to_edge) el_to_edge->GetRow(i, edges); else - mfem_error ("Mesh::GetElementEdges(...) element to edge table " - "is not generated."); + mfem_error("Mesh::GetElementEdges(...) element to edge table " + "is not generated."); const int *v = elements[i]->GetVertices(); const int ne = elements[i]->GetNEdges(); @@ -2006,7 +2508,7 @@ void Mesh::GetBdrElementEdges(int i, Array &edges, Array &cor) if (bel_to_edge) bel_to_edge->GetRow(i, edges); else - mfem_error ("Mesh::GetBdrElementEdges(...)"); + mfem_error("Mesh::GetBdrElementEdges(...)"); const int *v = boundary[i]->GetVertices(); const int ne = boundary[i]->GetNEdges(); @@ -2026,16 +2528,23 @@ void Mesh::GetFaceEdges(int i, Array &edges, Array &o) const GetFaceEdgeTable(); // generate face_edge Table (if not generated) - face_edge -> GetRow (i, edges); + face_edge->GetRow(i, edges); // to do: set the orientation 'o' } -void Mesh::GetEdgeVertices (int i, Array &vert) const +void Mesh::GetEdgeVertices(int i, Array &vert) const { - GetEdgeVertexTable(); // generate edge_vertex Table (if not generated) + if (Dim == 2 && faces.Size() == NumOfEdges) + { + faces[i]->GetVertices(vert); + } + else + { + GetEdgeVertexTable(); // generate edge_vertex Table (if not generated) - edge_vertex -> GetRow (i, vert); + edge_vertex->GetRow(i, vert); + } } Table *Mesh::GetFaceEdgeTable() const @@ -2047,7 +2556,7 @@ Table *Mesh::GetFaceEdgeTable() const return NULL; DSTable v_to_v(NumOfVertices); - GetVertexToVertexTable (v_to_v); + GetVertexToVertexTable(v_to_v); face_edge = new Table; GetElementArrayEdgeTable(faces, v_to_v, *face_edge); @@ -2061,20 +2570,20 @@ Table *Mesh::GetEdgeVertexTable() const return edge_vertex; DSTable v_to_v(NumOfVertices); - GetVertexToVertexTable (v_to_v); + GetVertexToVertexTable(v_to_v); int nedges = v_to_v.NumberOfEntries(); - edge_vertex = new Table (nedges, 2); + edge_vertex = new Table(nedges, 2); for (int i = 0; i < NumOfVertices; i++) { for (DSTable::RowIterator it(v_to_v, i); !it; ++it) { int j = it.Index(); - edge_vertex -> Push (j, i); - edge_vertex -> Push (j, it.Column()); + edge_vertex->Push(j, i); + edge_vertex->Push(j, it.Column()); } } - edge_vertex -> Finalize(); + edge_vertex->Finalize(); return edge_vertex; } @@ -2085,32 +2594,32 @@ Table *Mesh::GetVertexToElementTable() Table *vert_elem = new Table; - vert_elem -> MakeI (NumOfVertices); + vert_elem->MakeI(NumOfVertices); for (i = 0; i < NumOfElements; i++) { - nv = elements[i] -> GetNVertices(); - v = elements[i] -> GetVertices(); + nv = elements[i]->GetNVertices(); + v = elements[i]->GetVertices(); for (j = 0; j < nv; j++) - vert_elem -> AddAColumnInRow (v[j]); + vert_elem->AddAColumnInRow(v[j]); } - vert_elem -> MakeJ(); + vert_elem->MakeJ(); for (i = 0; i < NumOfElements; i++) { - nv = elements[i] -> GetNVertices(); - v = elements[i] -> GetVertices(); + nv = elements[i]->GetNVertices(); + v = elements[i]->GetVertices(); for (j = 0; j < nv; j++) - vert_elem -> AddConnection (v[j], i); + vert_elem->AddConnection(v[j], i); } - vert_elem -> ShiftUpI(); + vert_elem->ShiftUpI(); return vert_elem; } -void Mesh::GetElementFaces (int i, Array &fcs, Array &cor) +void Mesh::GetElementFaces(int i, Array &fcs, Array &cor) const { int n, j; @@ -2118,7 +2627,7 @@ void Mesh::GetElementFaces (int i, Array &fcs, Array &cor) if (el_to_face) el_to_face->GetRow(i, fcs); else - mfem_error ("Mesh::GetElementFaces (...) : el_to_face not generated."); + mfem_error("Mesh::GetElementFaces(...) : el_to_face not generated."); n = fcs.Size(); cor.SetSize(n); @@ -2129,39 +2638,39 @@ void Mesh::GetElementFaces (int i, Array &fcs, Array &cor) else if (faces_info[fcs[j]].Elem2No == i) cor[j] = faces_info[fcs[j]].Elem2Inf % 64; else - mfem_error ("Mesh::GetElementFaces (...) : 2"); + mfem_error("Mesh::GetElementFaces(...) : 2"); #else else cor[j] = faces_info[fcs[j]].Elem2Inf % 64; #endif } -void Mesh::GetBdrElementFace (int i, int *f, int *o) const +void Mesh::GetBdrElementFace(int i, int *f, int *o) const { const int *bv, *fv; if (State == Mesh::TWO_LEVEL_COARSE) { // the coarse level 'be_to_face' and 'faces' are destroyed - mfem_error ("Mesh::GetBdrElementFace (...)"); + mfem_error("Mesh::GetBdrElementFace (...)"); } *f = be_to_face[i]; - bv = boundary[i] -> GetVertices(); - fv = faces[be_to_face[i]] -> GetVertices(); + bv = boundary[i]->GetVertices(); + fv = faces[be_to_face[i]]->GetVertices(); // find the orientation of the bdr. elem. w.r.t. // the corresponding face element (that's the base) - switch (GetBdrElementType (i)) + switch (GetBdrElementType(i)) { case Element::TRIANGLE: - *o = GetTriOrientation (fv, bv); + *o = GetTriOrientation(fv, bv); break; case Element::QUADRILATERAL: - *o = GetQuadOrientation (fv, bv); + *o = GetQuadOrientation(fv, bv); break; default: - mfem_error ("Mesh::GetBdrElementFace(...) 2"); + mfem_error("Mesh::GetBdrElementFace(...) 2"); } } @@ -2179,32 +2688,33 @@ int Mesh::GetFaceBaseGeometry(int i) const case Element::HEXAHEDRON: return Geometry::SQUARE; default: - mfem_error ("Mesh::GetFaceBaseGeometry(...) #1"); + mfem_error("Mesh::GetFaceBaseGeometry(...) #1"); } return(-1); #if 0 if (faces[i] == NULL) - switch (GetElementType(faces_info[i].Elem1No)) { + switch (GetElementType(faces_info[i].Elem1No)) + { case Element::TETRAHEDRON: return Geometry::TRIANGLE; case Element::HEXAHEDRON: return Geometry::SQUARE; default: - mfem_error ("Mesh::GetFaceBaseGeometry(...) #2"); + mfem_error("Mesh::GetFaceBaseGeometry(...) #2"); } else - return faces[i] -> GetGeometryType(); + return faces[i]->GetGeometryType(); #endif } -int Mesh::GetBdrElementEdgeIndex (int i) const +int Mesh::GetBdrElementEdgeIndex(int i) const { if (Dim == 2) return be_to_edge[i]; return be_to_face[i]; } -int Mesh::GetElementType (int i) const +int Mesh::GetElementType(int i) const { Element *El = elements[i]; int t = El->GetType(); @@ -2219,7 +2729,8 @@ int Mesh::GetElementType (int i) const return t; } -int Mesh::GetBdrElementType (int i) const { +int Mesh::GetBdrElementType(int i) const +{ Element *El = boundary[i]; int t = El->GetType(); @@ -2231,15 +2742,15 @@ int Mesh::GetBdrElementType (int i) const { return t; } -void Mesh::GetPointMatrix( int i, DenseMatrix &pointmat ) const +void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const { int k, j, nv; const int *v; - v = elements[i] -> GetVertices(); - nv = elements[i] -> GetNVertices(); + v = elements[i]->GetVertices(); + nv = elements[i]->GetNVertices(); - pointmat.SetSize (Dim, nv); + pointmat.SetSize(Dim, nv); for (k = 0; k < Dim; k++) for (j = 0; j < nv; j++) pointmat(k, j) = vertices[v[j]](k); @@ -2250,10 +2761,10 @@ void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const int k, j, nv; const int *v; - v = boundary[i] -> GetVertices(); - nv = boundary[i] -> GetNVertices(); + v = boundary[i]->GetVertices(); + nv = boundary[i]->GetNVertices(); - pointmat.SetSize (Dim, nv); + pointmat.SetSize(Dim, nv); for (k = 0; k < Dim; k++) for (j = 0; j < nv; j++) pointmat(k, j) = vertices[v[j]](k); @@ -2265,7 +2776,7 @@ double Mesh::GetLength(int i, int j) const const double *vj = vertices[j](); double length = 0.; - for(int k = 0; k < Dim; k++) + for (int k = 0; k < Dim; k++) length += (vi[k]-vj[k])*(vi[k]-vj[k]); return sqrt(length); @@ -2332,13 +2843,12 @@ int Mesh::GetElementToEdgeTable(Table & e_to_f, Array &be_to_f) } else if (Dim == 3) { - if (bel_to_edge != NULL) - delete bel_to_edge; - bel_to_edge = new Table; + if (bel_to_edge == NULL) + bel_to_edge = new Table; GetElementArrayEdgeTable(boundary, v_to_v, *bel_to_edge); } else - mfem_error ("1D GetElementToEdgeTable is not yet implemented."); + mfem_error("1D GetElementToEdgeTable is not yet implemented."); // Return the number of edges return NumberOfEdges; @@ -2353,34 +2863,34 @@ const Table & Mesh::ElementToElementTable() { Table edge_el; - Transpose (ElementToEdgeTable(), edge_el); - el_to_el = new Table (NumOfElements, 4); // 4 is the max. # of edges + Transpose(ElementToEdgeTable(), edge_el); + el_to_el = new Table(NumOfElements, 4); // 4 is the max. # of edges for (int i = 0; i < edge_el.Size(); i++) - if (edge_el.RowSize (i) > 1) + if (edge_el.RowSize(i) > 1) { - const int *el = edge_el.GetRow (i); - el_to_el -> Push (el[0], el[1]); - el_to_el -> Push (el[1], el[0]); + const int *el = edge_el.GetRow(i); + el_to_el->Push(el[0], el[1]); + el_to_el->Push(el[1], el[0]); } - el_to_el -> Finalize(); + el_to_el->Finalize(); } else if (Dim == 3) { - el_to_el = new Table (NumOfElements, 6); // 6 is the max. # of faces + el_to_el = new Table(NumOfElements, 6); // 6 is the max. # of faces for (int i = 0; i < faces_info.Size(); i++) if (faces_info[i].Elem2No >= 0) { - el_to_el -> Push (faces_info[i].Elem1No, faces_info[i].Elem2No); - el_to_el -> Push (faces_info[i].Elem2No, faces_info[i].Elem1No); + el_to_el->Push(faces_info[i].Elem1No, faces_info[i].Elem2No); + el_to_el->Push(faces_info[i].Elem2No, faces_info[i].Elem1No); } - el_to_el -> Finalize(); + el_to_el->Finalize(); } else - mfem_error ("Mesh::ElementToElementTable() in 1D is not implemented!"); + mfem_error("Mesh::ElementToElementTable() in 1D is not implemented!"); return *el_to_el; } @@ -2388,22 +2898,22 @@ const Table & Mesh::ElementToElementTable() const Table & Mesh::ElementToFaceTable() const { if (el_to_face == NULL) - mfem_error ("Mesh::ElementToFaceTable()"); + mfem_error("Mesh::ElementToFaceTable()"); return *el_to_face; } const Table & Mesh::ElementToEdgeTable() const { if (el_to_edge == NULL) - mfem_error ("Mesh::ElementToEdgeTable()"); + mfem_error("Mesh::ElementToEdgeTable()"); return *el_to_edge; } -void Mesh::AddSegmentFaceElement (int lf, int gf, int el, int v0, int v1) +void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1) { if (faces[gf] == NULL) // this will be elem1 { - faces[gf] = new Segment (v0, v1); + faces[gf] = new Segment(v0, v1); faces_info[gf].Elem1No = el; faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0 faces_info[gf].Elem2No = -1; // in case there's no other side @@ -2411,21 +2921,21 @@ void Mesh::AddSegmentFaceElement (int lf, int gf, int el, int v0, int v1) else // this will be elem2 { #ifdef MFEM_DEBUG - int *v = faces[gf] -> GetVertices(); + int *v = faces[gf]->GetVertices(); if (v[1] != v0 || v[0] != v1) - mfem_error ("Mesh::AddSegmentFaceElement (...)"); + mfem_error("Mesh::AddSegmentFaceElement(...)"); #endif faces_info[gf].Elem2No = el; faces_info[gf].Elem2Inf = 64 * lf + 1; } } -void Mesh::AddTriangleFaceElement (int lf, int gf, int el, - int v0, int v1, int v2) +void Mesh::AddTriangleFaceElement(int lf, int gf, int el, + int v0, int v1, int v2) { if (faces[gf] == NULL) // this will be elem1 { - faces[gf] = new Triangle (v0, v1, v2); + faces[gf] = new Triangle(v0, v1, v2); faces_info[gf].Elem1No = el; faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0 faces_info[gf].Elem2No = -1; // in case there's no other side @@ -2433,22 +2943,22 @@ void Mesh::AddTriangleFaceElement (int lf, int gf, int el, else // this will be elem2 { int orientation, vv[3] = { v0, v1, v2 }; - orientation = GetTriOrientation (faces[gf] -> GetVertices(), vv); + orientation = GetTriOrientation(faces[gf]->GetVertices(), vv); #ifdef MFEM_DEBUG if (orientation % 2 == 0) - mfem_error ("Mesh::AddTriangleFaceElement (...)"); + mfem_error("Mesh::AddTriangleFaceElement(...)"); #endif faces_info[gf].Elem2No = el; faces_info[gf].Elem2Inf = 64 * lf + orientation; } } -void Mesh::AddQuadFaceElement (int lf, int gf, int el, - int v0, int v1, int v2, int v3) +void Mesh::AddQuadFaceElement(int lf, int gf, int el, + int v0, int v1, int v2, int v3) { if (faces_info[gf].Elem1No < 0) // this will be elem1 { - faces[gf] = new Quadrilateral (v0, v1, v2, v3); + faces[gf] = new Quadrilateral(v0, v1, v2, v3); faces_info[gf].Elem1No = el; faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0 faces_info[gf].Elem2No = -1; // in case there's no other side @@ -2456,10 +2966,10 @@ void Mesh::AddQuadFaceElement (int lf, int gf, int el, else // this will be elem2 { int vv[4] = { v0, v1, v2, v3 }; - int oo = GetQuadOrientation (faces[gf] -> GetVertices(), vv); + int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv); #ifdef MFEM_DEBUG if (oo % 2 == 0) - mfem_error ("Mesh::AddQuadFaceElement (...)"); + mfem_error("Mesh::AddQuadFaceElement(...)"); #endif faces_info[gf].Elem2No = el; faces_info[gf].Elem2Inf = 64 * lf + oo; @@ -2473,11 +2983,11 @@ void Mesh::GenerateFaces() nfaces = (Dim == 2) ? NumOfEdges : NumOfFaces; for (i = 0; i < faces.Size(); i++) - FreeElement (faces[i]); + FreeElement(faces[i]); // (re)generate the interior faces and the info for them - faces.SetSize (nfaces); - faces_info.SetSize (nfaces); + faces.SetSize(nfaces); + faces_info.SetSize(nfaces); for (i = 0; i < nfaces; i++) { faces[i] = NULL; @@ -2494,78 +3004,78 @@ void Mesh::GenerateFaces() for (int j = 0; j < ne; j++) { const int *e = elements[i]->GetEdgeVertices(j); - AddSegmentFaceElement (j, ef[j], i, v[e[1]], v[e[0]]); + AddSegmentFaceElement(j, ef[j], i, v[e[1]], v[e[0]]); } } else { ef = el_to_face->GetRow(i); - switch (GetElementType (i)) + switch (GetElementType(i)) { case Element::TETRAHEDRON: - AddTriangleFaceElement (0, ef[0], i, v[1], v[2], v[3]); - AddTriangleFaceElement (1, ef[1], i, v[0], v[3], v[2]); - AddTriangleFaceElement (2, ef[2], i, v[0], v[1], v[3]); - AddTriangleFaceElement (3, ef[3], i, v[0], v[2], v[1]); + AddTriangleFaceElement(0, ef[0], i, v[1], v[2], v[3]); + AddTriangleFaceElement(1, ef[1], i, v[0], v[3], v[2]); + AddTriangleFaceElement(2, ef[2], i, v[0], v[1], v[3]); + AddTriangleFaceElement(3, ef[3], i, v[0], v[2], v[1]); break; case Element::HEXAHEDRON: - AddQuadFaceElement (0, ef[0], i, v[3], v[2], v[1], v[0]); - AddQuadFaceElement (1, ef[1], i, v[0], v[1], v[5], v[4]); - AddQuadFaceElement (2, ef[2], i, v[1], v[2], v[6], v[5]); - AddQuadFaceElement (3, ef[3], i, v[2], v[3], v[7], v[6]); - AddQuadFaceElement (4, ef[4], i, v[3], v[0], v[4], v[7]); - AddQuadFaceElement (5, ef[5], i, v[4], v[5], v[6], v[7]); + AddQuadFaceElement(0, ef[0], i, v[3], v[2], v[1], v[0]); + AddQuadFaceElement(1, ef[1], i, v[0], v[1], v[5], v[4]); + AddQuadFaceElement(2, ef[2], i, v[1], v[2], v[6], v[5]); + AddQuadFaceElement(3, ef[3], i, v[2], v[3], v[7], v[6]); + AddQuadFaceElement(4, ef[4], i, v[3], v[0], v[4], v[7]); + AddQuadFaceElement(5, ef[5], i, v[4], v[5], v[6], v[7]); break; } } } } -STable3D *Mesh::GetElementToFaceTable (int ret_ftbl) +STable3D *Mesh::GetElementToFaceTable(int ret_ftbl) { int i, *v; STable3D *faces_tbl; if (el_to_face != NULL) delete el_to_face; - el_to_face = new Table (NumOfElements, 6); // must be 6 for hexahedra - faces_tbl = new STable3D (NumOfVertices); + el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra + faces_tbl = new STable3D(NumOfVertices); for (i = 0; i < NumOfElements; i++) { - v = elements[i]->GetVertices (); - switch (GetElementType (i)) + v = elements[i]->GetVertices(); + switch (GetElementType(i)) { case Element::TETRAHEDRON: - el_to_face -> Push (i, faces_tbl -> Push (v[1], v[2], v[3])); - el_to_face -> Push (i, faces_tbl -> Push (v[0], v[3], v[2])); - el_to_face -> Push (i, faces_tbl -> Push (v[0], v[1], v[3])); - el_to_face -> Push (i, faces_tbl -> Push (v[0], v[2], v[1])); + el_to_face->Push(i, faces_tbl->Push(v[1], v[2], v[3])); + el_to_face->Push(i, faces_tbl->Push(v[0], v[3], v[2])); + el_to_face->Push(i, faces_tbl->Push(v[0], v[1], v[3])); + el_to_face->Push(i, faces_tbl->Push(v[0], v[2], v[1])); break; case Element::HEXAHEDRON: // find the face by the vertices with the smallest 3 numbers // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1 - el_to_face -> Push (i, faces_tbl->Push4 (v[3], v[2], v[1], v[0])); - el_to_face -> Push (i, faces_tbl->Push4 (v[0], v[1], v[5], v[4])); - el_to_face -> Push (i, faces_tbl->Push4 (v[1], v[2], v[6], v[5])); - el_to_face -> Push (i, faces_tbl->Push4 (v[2], v[3], v[7], v[6])); - el_to_face -> Push (i, faces_tbl->Push4 (v[3], v[0], v[4], v[7])); - el_to_face -> Push (i, faces_tbl->Push4 (v[4], v[5], v[6], v[7])); + el_to_face->Push(i, faces_tbl->Push4(v[3], v[2], v[1], v[0])); + el_to_face->Push(i, faces_tbl->Push4(v[0], v[1], v[5], v[4])); + el_to_face->Push(i, faces_tbl->Push4(v[1], v[2], v[6], v[5])); + el_to_face->Push(i, faces_tbl->Push4(v[2], v[3], v[7], v[6])); + el_to_face->Push(i, faces_tbl->Push4(v[3], v[0], v[4], v[7])); + el_to_face->Push(i, faces_tbl->Push4(v[4], v[5], v[6], v[7])); break; } } - el_to_face -> Finalize (); - NumOfFaces = faces_tbl -> NumberOfElements (); - be_to_face.SetSize (NumOfBdrElements); + el_to_face->Finalize(); + NumOfFaces = faces_tbl->NumberOfElements(); + be_to_face.SetSize(NumOfBdrElements); for (i = 0; i < NumOfBdrElements; i++) { - v = boundary[i]->GetVertices (); - switch (GetBdrElementType (i)) + v = boundary[i]->GetVertices(); + switch (GetBdrElementType(i)) { case Element::TRIANGLE: - be_to_face[i] = (*faces_tbl) (v[0], v[1], v[2]); + be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]); break; case Element::QUADRILATERAL: - be_to_face[i] = (*faces_tbl) (v[0], v[1], v[2], v[3]); + be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]); break; } } @@ -2576,11 +3086,173 @@ STable3D *Mesh::GetElementToFaceTable (int ret_ftbl) return NULL; } +#ifdef MFEM_USE_MPI +// auxiliary function for qsort +static int mfem_less(const void *x, const void *y) +{ + if (*(int*)x < *(int*)y) + return 1; + if (*(int*)x > *(int*)y) + return -1; + return 0; +} +// METIS prototypes +typedef int idxtype; +extern "C" { + void METIS_PartGraphRecursive(int*, idxtype*, idxtype*, idxtype*, idxtype*, + int*, int*, int*, int*, int*, idxtype*); + void METIS_PartGraphKway(int*, idxtype*, idxtype*, idxtype*, idxtype*, + int*, int*, int*, int*, int*, idxtype*); + void METIS_PartGraphVKway(int*, idxtype*, idxtype*, idxtype*, idxtype*, + int*, int*, int*, int*, int*, idxtype*); +} +#endif + +int *Mesh::GeneratePartitioning(int nparts, int part_method) +{ +#ifdef MFEM_USE_MPI + int i, *partitioning; + + ElementToElementTable(); + + partitioning = new int[NumOfElements]; + + if (nparts == 1) + { + for (i = 0; i < NumOfElements; i++) + partitioning[i] = 0; + } + else + { + int *I, *J, n; + int wgtflag = 0; + int numflag = 0; + int options[5]; + int edgecut; + + n = NumOfElements; + I = el_to_el->GetI(); + J = el_to_el->GetJ(); + options[0] = 0; + + // Sort the neighbor lists + if (part_method >= 0 && part_method <= 2) + for (i = 0; i < n; i++) + qsort(&J[I[i]], I[i+1]-I[i], sizeof(int), &mfem_less); + + // This function should be used to partition a graph into a small + // number of partitions (less than 8). + if (part_method == 0 || part_method == 3) + METIS_PartGraphRecursive(&n, + (idxtype *) I, + (idxtype *) J, + (idxtype *) NULL, + (idxtype *) NULL, + &wgtflag, + &numflag, + &nparts, + options, + &edgecut, + (idxtype *) partitioning); + + // This function should be used to partition a graph into a large + // number of partitions (greater than 8). + if (part_method == 1 || part_method == 4) + METIS_PartGraphKway(&n, + (idxtype *) I, + (idxtype *) J, + (idxtype *) NULL, + (idxtype *) NULL, + &wgtflag, + &numflag, + &nparts, + options, + &edgecut, + (idxtype *) partitioning); + + // The objective of this partitioning is to minimize the total + // communication volume + if (part_method == 2 || part_method == 5) + METIS_PartGraphVKway(&n, + (idxtype *) I, + (idxtype *) J, + (idxtype *) NULL, + (idxtype *) NULL, + &wgtflag, + &numflag, + &nparts, + options, + &edgecut, + (idxtype *) partitioning); + +#ifdef MFEM_DEBUG + cout << "Mesh::GeneratePartitioning(...): edgecut = " + << edgecut << endl; +#endif + } + + if (el_to_el) + delete el_to_el; + el_to_el = NULL; + + // Check for empty partitionings (a "feature" in METIS) + { + Array< Pair > psize(nparts); + for (i = 0; i < nparts; i++) + { + psize[i].one = 0; + psize[i].two = i; + } + + for (i = 0; i < NumOfElements; i++) + psize[partitioning[i]].one++; + + int empty_parts = 0; + for (i = 0; i < nparts; i++) + if (psize[i].one == 0) + empty_parts++; + + // This code just split the largest partitionings in two. + // Do we need to replace it with something better? + if (empty_parts) + { + cerr << "Mesh::GeneratePartitioning returned " << empty_parts + << " empty parts!" << endl; + + SortPairs(psize, nparts); + + for (i = nparts-1; i > nparts-1-empty_parts; i--) + psize[i].one /= 2; + + for (int j = 0; j < NumOfElements; j++) + for (i = nparts-1; i > nparts-1-empty_parts; i--) + if (psize[i].one == 0 || partitioning[j] != psize[i].two) + continue; + else + { + partitioning[j] = psize[nparts-1-i].two; + psize[i].one--; + } + } + } + + return partitioning; + +#else + + mfem_error("Mesh::GeneratePartitioning(...): " + "MFEM was compiled without Metis."); + + return NULL; + +#endif +} + /* required: 0 <= partitioning[i] < num_part */ -void FindPartitioningComponents (Table &elem_elem, - const Array &partitioning, - Array &component, - Array &num_comp) +void FindPartitioningComponents(Table &elem_elem, + const Array &partitioning, + Array &component, + Array &num_comp) { int i, j, k; int num_elem, *i_elem_elem, *j_elem_elem; @@ -2589,9 +3261,9 @@ void FindPartitioningComponents (Table &elem_elem, i_elem_elem = elem_elem.GetI(); j_elem_elem = elem_elem.GetJ(); - component.SetSize (num_elem); + component.SetSize(num_elem); - Array elem_stack (num_elem); + Array elem_stack(num_elem); int stack_p, stack_top_p, elem; int num_part; @@ -2604,7 +3276,7 @@ void FindPartitioningComponents (Table &elem_elem, } num_part++; - num_comp.SetSize (num_part); + num_comp.SetSize(num_part); for (i = 0; i < num_part; i++) num_comp[i] = 0; @@ -2633,22 +3305,22 @@ void FindPartitioningComponents (Table &elem_elem, } else if (component[k] != component[i]) { - mfem_error ("FindPartitioningComponents"); + mfem_error("FindPartitioningComponents"); } } } } } -void Mesh::CheckPartitioning (int *partitioning) +void Mesh::CheckPartitioning(int *partitioning) { int i, n_empty, n_mcomp; Array component, num_comp; - const Array _partitioning (partitioning, GetNE()); + const Array _partitioning(partitioning, GetNE()); ElementToElementTable(); - FindPartitioningComponents (*el_to_el, _partitioning, component, num_comp); + FindPartitioningComponents(*el_to_el, _partitioning, component, num_comp); n_empty = n_mcomp = 0; for (i = 0; i < num_comp.Size(); i++) @@ -2659,7 +3331,7 @@ void Mesh::CheckPartitioning (int *partitioning) if (n_empty > 0) { - cout << "Mesh::CheckPartitioning (...) :\n" + cout << "Mesh::CheckPartitioning(...) :\n" << "The following subdomains are empty :\n"; for (i = 0; i < num_comp.Size(); i++) if (num_comp[i] == 0) @@ -2668,15 +3340,15 @@ void Mesh::CheckPartitioning (int *partitioning) } if (n_mcomp > 0) { - cout << "Mesh::CheckPartitioning (...) :\n" - << "The following subdomains have are NOT connected :\n"; + cout << "Mesh::CheckPartitioning(...) :\n" + << "The following subdomains are NOT connected :\n"; for (i = 0; i < num_comp.Size(); i++) if (num_comp[i] > 1) cout << ' ' << i; cout << endl; } if (n_empty == 0 && n_mcomp == 0) - cout << "Mesh::CheckPartitioning (...) : " + cout << "Mesh::CheckPartitioning(...) : " "All subdomains are connected." << endl; if (el_to_el) @@ -2935,7 +3607,7 @@ void FindTMax(Vector &c, Vector &x, double &tmax, } } -void Mesh::CheckDisplacements (const Vector &displacements, double &tmax) +void Mesh::CheckDisplacements(const Vector &displacements, double &tmax) { int nvs = vertices.Size(); DenseMatrix P, V, DS, PDS(Dim), VDS(Dim); @@ -3002,7 +3674,7 @@ void Mesh::CheckDisplacements (const Vector &displacements, double &tmax) } } -void Mesh::MoveVertices (const Vector &displacements) +void Mesh::MoveVertices(const Vector &displacements) { for (int i = 0, nv = vertices.Size(); i < nv; i++) for (int j = 0; j < Dim; j++) @@ -3056,7 +3728,7 @@ void Mesh::NewNodes(GridFunction &nodes) own_nodes = 0; } -void Mesh::AverageVertices (int * indexes, int n, int result) +void Mesh::AverageVertices(int * indexes, int n, int result) { int j, k; @@ -3104,7 +3776,7 @@ void Mesh::QuadUniformRefinement() if (el_to_edge == NULL) { el_to_edge = new Table; - NumOfEdges = GetElementToEdgeTable (*el_to_edge, be_to_edge); + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); } int oedge = NumOfVertices; @@ -3112,46 +3784,46 @@ void Mesh::QuadUniformRefinement() DeleteCoarseTables(); - vertices.SetSize (oelem + NumOfElements); + vertices.SetSize(oelem + NumOfElements); for (i = 0; i < NumOfElements; i++) { - v = elements[i] -> GetVertices(); + v = elements[i]->GetVertices(); - AverageVertices (v, 4, oelem+i); + AverageVertices(v, 4, oelem+i); - e = el_to_edge -> GetRow(i); + e = el_to_edge->GetRow(i); - vv[0] = v[0], vv[1] = v[1]; AverageVertices (vv, 2, oedge+e[0]); - vv[0] = v[1], vv[1] = v[2]; AverageVertices (vv, 2, oedge+e[1]); - vv[0] = v[2], vv[1] = v[3]; AverageVertices (vv, 2, oedge+e[2]); - vv[0] = v[3], vv[1] = v[0]; AverageVertices (vv, 2, oedge+e[3]); + vv[0] = v[0], vv[1] = v[1]; AverageVertices(vv, 2, oedge+e[0]); + vv[0] = v[1], vv[1] = v[2]; AverageVertices(vv, 2, oedge+e[1]); + vv[0] = v[2], vv[1] = v[3]; AverageVertices(vv, 2, oedge+e[2]); + vv[0] = v[3], vv[1] = v[0]; AverageVertices(vv, 2, oedge+e[3]); } - elements.SetSize (4 * NumOfElements); + elements.SetSize(4 * NumOfElements); for (i = 0; i < NumOfElements; i++) { - attr = elements[i] -> GetAttribute(); - v = elements[i] -> GetVertices(); - e = el_to_edge -> GetRow(i); + attr = elements[i]->GetAttribute(); + v = elements[i]->GetVertices(); + e = el_to_edge->GetRow(i); j = NumOfElements + 3 * i; - elements[j+0] = new Quadrilateral (oedge+e[0], v[1], oedge+e[1], - oelem+i, attr); - elements[j+1] = new Quadrilateral (oelem+i, oedge+e[1], v[2], - oedge+e[2], attr); - elements[j+2] = new Quadrilateral (oedge+e[3], oelem+i, oedge+e[2], - v[3], attr); + elements[j+0] = new Quadrilateral(oedge+e[0], v[1], oedge+e[1], + oelem+i, attr); + elements[j+1] = new Quadrilateral(oelem+i, oedge+e[1], v[2], + oedge+e[2], attr); + elements[j+2] = new Quadrilateral(oedge+e[3], oelem+i, oedge+e[2], + v[3], attr); if (WantTwoLevelState) { QuadrisectedElement *qe; - qe = new QuadrisectedElement (elements[i] -> Duplicate()); - qe -> FirstChild = elements[i]; - qe -> Child2 = j; - qe -> Child3 = j+1; - qe -> Child4 = j+2; + qe = new QuadrisectedElement(elements[i]->Duplicate()); + qe->FirstChild = elements[i]; + qe->Child2 = j; + qe->Child3 = j+1; + qe->Child4 = j+2; elements[i] = qe; } @@ -3160,14 +3832,14 @@ void Mesh::QuadUniformRefinement() v[3] = oedge+e[3]; } - boundary.SetSize (2 * NumOfBdrElements); + boundary.SetSize(2 * NumOfBdrElements); for (i = 0; i < NumOfBdrElements; i++) { - attr = boundary[i] -> GetAttribute(); - v = boundary[i] -> GetVertices(); + attr = boundary[i]->GetAttribute(); + v = boundary[i]->GetVertices(); j = NumOfBdrElements + i; - boundary[j] = new Segment (oedge+be_to_edge[i], v[1], attr); + boundary[j] = new Segment(oedge+be_to_edge[i], v[1], attr); if (WantTwoLevelState) { @@ -3176,9 +3848,9 @@ void Mesh::QuadUniformRefinement() #else BisectedElement *be = new BisectedElement; #endif - be -> SetCoarseElem (boundary[i] -> Duplicate()); - be -> FirstChild = boundary[i]; - be -> SecondChild = j; + be->SetCoarseElem(boundary[i]->Duplicate()); + be->FirstChild = boundary[i]; + be->SecondChild = j; boundary[i] = be; } @@ -3213,7 +3885,7 @@ void Mesh::QuadUniformRefinement() if (WantTwoLevelState) { c_el_to_edge = el_to_edge; - Swap (be_to_edge, fc_be_to_edge); // save coarse be_to_edge + Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge f_el_to_edge = new Table; NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); el_to_edge = f_el_to_edge; @@ -3253,7 +3925,7 @@ void Mesh::HexUniformRefinement() if (el_to_edge == NULL) { el_to_edge = new Table; - NumOfEdges = GetElementToEdgeTable (*el_to_edge, be_to_edge); + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); } if (el_to_face == NULL) GetElementToFaceTable(); @@ -3264,83 +3936,84 @@ void Mesh::HexUniformRefinement() DeleteCoarseTables(); - vertices.SetSize (oelem + NumOfElements); - for (i = 0; i < NumOfElements; i++) { - v = elements[i] -> GetVertices(); + vertices.SetSize(oelem + NumOfElements); + for (i = 0; i < NumOfElements; i++) + { + v = elements[i]->GetVertices(); - AverageVertices (v, 8, oelem+i); + AverageVertices(v, 8, oelem+i); - f = el_to_face -> GetRow(i); + f = el_to_face->GetRow(i); vv[0] = v[3], vv[1] = v[2], vv[2] = v[1], vv[3] = v[0]; - AverageVertices (vv, 4, oface+f[0]); + AverageVertices(vv, 4, oface+f[0]); vv[0] = v[0], vv[1] = v[1], vv[2] = v[5], vv[3] = v[4]; - AverageVertices (vv, 4, oface+f[1]); + AverageVertices(vv, 4, oface+f[1]); vv[0] = v[1], vv[1] = v[2], vv[2] = v[6], vv[3] = v[5]; - AverageVertices (vv, 4, oface+f[2]); + AverageVertices(vv, 4, oface+f[2]); vv[0] = v[2], vv[1] = v[3], vv[2] = v[7], vv[3] = v[6]; - AverageVertices (vv, 4, oface+f[3]); + AverageVertices(vv, 4, oface+f[3]); vv[0] = v[3], vv[1] = v[0], vv[2] = v[4], vv[3] = v[7]; - AverageVertices (vv, 4, oface+f[4]); + AverageVertices(vv, 4, oface+f[4]); vv[0] = v[4], vv[1] = v[5], vv[2] = v[6], vv[3] = v[7]; - AverageVertices (vv, 4, oface+f[5]); + AverageVertices(vv, 4, oface+f[5]); - e = el_to_edge -> GetRow(i); + e = el_to_edge->GetRow(i); - vv[0] = v[0], vv[1] = v[1]; AverageVertices (vv, 2, oedge+e[0]); - vv[0] = v[1], vv[1] = v[2]; AverageVertices (vv, 2, oedge+e[1]); - vv[0] = v[2], vv[1] = v[3]; AverageVertices (vv, 2, oedge+e[2]); - vv[0] = v[3], vv[1] = v[0]; AverageVertices (vv, 2, oedge+e[3]); - vv[0] = v[4], vv[1] = v[5]; AverageVertices (vv, 2, oedge+e[4]); - vv[0] = v[5], vv[1] = v[6]; AverageVertices (vv, 2, oedge+e[5]); - vv[0] = v[6], vv[1] = v[7]; AverageVertices (vv, 2, oedge+e[6]); - vv[0] = v[7], vv[1] = v[4]; AverageVertices (vv, 2, oedge+e[7]); - vv[0] = v[0], vv[1] = v[4]; AverageVertices (vv, 2, oedge+e[8]); - vv[0] = v[1], vv[1] = v[5]; AverageVertices (vv, 2, oedge+e[9]); - vv[0] = v[2], vv[1] = v[6]; AverageVertices (vv, 2, oedge+e[10]); - vv[0] = v[3], vv[1] = v[7]; AverageVertices (vv, 2, oedge+e[11]); + vv[0] = v[0], vv[1] = v[1]; AverageVertices(vv, 2, oedge+e[0]); + vv[0] = v[1], vv[1] = v[2]; AverageVertices(vv, 2, oedge+e[1]); + vv[0] = v[2], vv[1] = v[3]; AverageVertices(vv, 2, oedge+e[2]); + vv[0] = v[3], vv[1] = v[0]; AverageVertices(vv, 2, oedge+e[3]); + vv[0] = v[4], vv[1] = v[5]; AverageVertices(vv, 2, oedge+e[4]); + vv[0] = v[5], vv[1] = v[6]; AverageVertices(vv, 2, oedge+e[5]); + vv[0] = v[6], vv[1] = v[7]; AverageVertices(vv, 2, oedge+e[6]); + vv[0] = v[7], vv[1] = v[4]; AverageVertices(vv, 2, oedge+e[7]); + vv[0] = v[0], vv[1] = v[4]; AverageVertices(vv, 2, oedge+e[8]); + vv[0] = v[1], vv[1] = v[5]; AverageVertices(vv, 2, oedge+e[9]); + vv[0] = v[2], vv[1] = v[6]; AverageVertices(vv, 2, oedge+e[10]); + vv[0] = v[3], vv[1] = v[7]; AverageVertices(vv, 2, oedge+e[11]); } int attr, j, k; - elements.SetSize (8 * NumOfElements); + elements.SetSize(8 * NumOfElements); for (i = 0; i < NumOfElements; i++) { - attr = elements[i] -> GetAttribute(); - v = elements[i] -> GetVertices(); - e = el_to_edge -> GetRow(i); - f = el_to_face -> GetRow(i); + attr = elements[i]->GetAttribute(); + v = elements[i]->GetVertices(); + e = el_to_edge->GetRow(i); + f = el_to_face->GetRow(i); j = NumOfElements + 7 * i; - elements[j+0] = new Hexahedron (oedge+e[0], v[1], oedge+e[1], oface+f[0], - oface+f[1], oedge+e[9], oface+f[2], - oelem+i, attr); - elements[j+1] = new Hexahedron (oface+f[0], oedge+e[1], v[2], oedge+e[2], - oelem+i, oface+f[2], oedge+e[10], - oface+f[3], attr); - elements[j+2] = new Hexahedron (oedge+e[3], oface+f[0], oedge+e[2], v[3], - oface+f[4], oelem+i, oface+f[3], - oedge+e[11], attr); - elements[j+3] = new Hexahedron (oedge+e[8], oface+f[1], oelem+i, - oface+f[4], v[4], oedge+e[4], oface+f[5], - oedge+e[7], attr); - elements[j+4] = new Hexahedron (oface+f[1], oedge+e[9], oface+f[2], - oelem+i, oedge+e[4], v[5], oedge+e[5], - oface+f[5], attr); - elements[j+5] = new Hexahedron (oelem+i, oface+f[2], oedge+e[10], - oface+f[3], oface+f[5], oedge+e[5], v[6], - oedge+e[6], attr); - elements[j+6] = new Hexahedron (oface+f[4], oelem+i, oface+f[3], - oedge+e[11], oedge+e[7], oface+f[5], - oedge+e[6], v[7], attr); + elements[j+0] = new Hexahedron(oedge+e[0], v[1], oedge+e[1], oface+f[0], + oface+f[1], oedge+e[9], oface+f[2], + oelem+i, attr); + elements[j+1] = new Hexahedron(oface+f[0], oedge+e[1], v[2], oedge+e[2], + oelem+i, oface+f[2], oedge+e[10], + oface+f[3], attr); + elements[j+2] = new Hexahedron(oedge+e[3], oface+f[0], oedge+e[2], v[3], + oface+f[4], oelem+i, oface+f[3], + oedge+e[11], attr); + elements[j+3] = new Hexahedron(oedge+e[8], oface+f[1], oelem+i, + oface+f[4], v[4], oedge+e[4], oface+f[5], + oedge+e[7], attr); + elements[j+4] = new Hexahedron(oface+f[1], oedge+e[9], oface+f[2], + oelem+i, oedge+e[4], v[5], oedge+e[5], + oface+f[5], attr); + elements[j+5] = new Hexahedron(oelem+i, oface+f[2], oedge+e[10], + oface+f[3], oface+f[5], oedge+e[5], v[6], + oedge+e[6], attr); + elements[j+6] = new Hexahedron(oface+f[4], oelem+i, oface+f[3], + oedge+e[11], oedge+e[7], oface+f[5], + oedge+e[6], v[7], attr); if (WantTwoLevelState) { OctasectedElement *oe; - oe = new OctasectedElement (elements[i] -> Duplicate()); - oe -> FirstChild = elements[i]; + oe = new OctasectedElement(elements[i]->Duplicate()); + oe->FirstChild = elements[i]; for (k = 0; k < 7; k++) - oe -> Child[k] = j + k; + oe->Child[k] = j + k; elements[i] = oe; } @@ -3353,31 +4026,31 @@ void Mesh::HexUniformRefinement() v[7] = oface+f[4]; } - boundary.SetSize (4 * NumOfBdrElements); + boundary.SetSize(4 * NumOfBdrElements); for (i = 0; i < NumOfBdrElements; i++) { - attr = boundary[i] -> GetAttribute(); - v = boundary[i] -> GetVertices(); - e = bel_to_edge -> GetRow(i); + attr = boundary[i]->GetAttribute(); + v = boundary[i]->GetVertices(); + e = bel_to_edge->GetRow(i); f = & be_to_face[i]; j = NumOfBdrElements + 3 * i; - boundary[j+0] = new Quadrilateral (oedge+e[0], v[1], oedge+e[1], - oface+f[0], attr); - boundary[j+1] = new Quadrilateral (oface+f[0], oedge+e[1], v[2], - oedge+e[2], attr); - boundary[j+2] = new Quadrilateral (oedge+e[3], oface+f[0], oedge+e[2], - v[3], attr); + boundary[j+0] = new Quadrilateral(oedge+e[0], v[1], oedge+e[1], + oface+f[0], attr); + boundary[j+1] = new Quadrilateral(oface+f[0], oedge+e[1], v[2], + oedge+e[2], attr); + boundary[j+2] = new Quadrilateral(oedge+e[3], oface+f[0], oedge+e[2], + v[3], attr); if (WantTwoLevelState) { QuadrisectedElement *qe; - qe = new QuadrisectedElement (boundary[i] -> Duplicate()); - qe -> FirstChild = boundary[i]; - qe -> Child2 = j; - qe -> Child3 = j+1; - qe -> Child4 = j+2; + qe = new QuadrisectedElement(boundary[i]->Duplicate()); + qe->FirstChild = boundary[i]; + qe->Child2 = j; + qe->Child3 = j+1; + qe->Child4 = j+2; boundary[i] = qe; } @@ -3431,7 +4104,7 @@ void Mesh::HexUniformRefinement() { c_el_to_face = el_to_face; el_to_face = NULL; - Swap (faces_info, fc_faces_info); + Swap(faces_info, fc_faces_info); } GetElementToFaceTable(); GenerateFaces(); @@ -3475,16 +4148,16 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) int cne = NumOfElements, cnv = NumOfVertices; NumOfVertices += marked_el.Size(); NumOfElements += marked_el.Size(); - vertices.SetSize (NumOfVertices); - elements.SetSize (NumOfElements); + vertices.SetSize(NumOfVertices); + elements.SetSize(NumOfElements); for (j = 0; j < marked_el.Size(); j++) { i = marked_el[j]; - int *vert = elements[i] -> GetVertices(); + int *vert = elements[i]->GetVertices(); vertices[cnv+j](0) = 0.5 * ( vertices[vert[0]](0) + vertices[vert[1]](0) ); - elements[cne+j] = new Segment (cnv+j, vert[1], - elements[i] -> GetAttribute()); + elements[cne+j] = new Segment(cnv+j, vert[1], + elements[i]->GetAttribute()); vert[1] = cnv+j; } } // end of 'if (Dim == 1)' @@ -3508,13 +4181,13 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) int *edge2 = new int[nedges]; int *middle = new int[nedges]; - for(i=0; iGetVertices(v); - for(j=1; j &marked_el, int type) } // 3. Do the red refinement. - for(i=0; iGetVertices(v); - bisect = v_to_v(v[0],v[1]); + bisect = v_to_v(v[0], v[1]); if (middle[bisect] != -1) // the element was refined (needs updating) { if (boundary[i]->GetType() == Element::SEGMENT) @@ -3558,25 +4233,25 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) boundary.Append(new Segment(v2, boundary[i]->GetAttribute())); #ifdef MFEM_USE_MEMALLOC BisectedElement *aux = BEMemory.Alloc(); - aux -> SetCoarseElem (boundary[i]); + aux->SetCoarseElem(boundary[i]); #else - BisectedElement *aux = new BisectedElement (boundary[i]); + BisectedElement *aux = new BisectedElement(boundary[i]); #endif aux->FirstChild = new Segment(v1, boundary[i]->GetAttribute()); aux->SecondChild = NumOfBdrElements; boundary[i] = aux; - NumOfBdrElements ++; + NumOfBdrElements++; } else { - boundary[i]->SetVertices( v1 ); + boundary[i]->SetVertices(v1); boundary.Append(new Segment(v2, boundary[i]->GetAttribute())); } } else - mfem_error ("Only bisection of segment is implemented" - " for bdr elem."); + mfem_error("Only bisection of segment is implemented" + " for bdr elem."); } } NumOfBdrElements = boundary.Size(); @@ -3604,7 +4279,7 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) if (WantTwoLevelState) { c_el_to_edge = el_to_edge; - Swap (be_to_edge, fc_be_to_edge); // save coarse be_to_edge + Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge f_el_to_edge = new Table; NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); el_to_edge = f_el_to_edge; @@ -3635,7 +4310,7 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) nedges = v_to_v.NumberOfEntries(); int *middle = new int[nedges]; - for(i=0; i &marked_el, int type) switch (type) { case 1: - for(i=0; i &marked_el, int type) // 4. Do the green refinement (to get conforming mesh). int need_refinement; // int need_refinement, onoe, max_gen = 0; - do { + do + { // int redges[2], type, flag; need_refinement = 0; // onoe = NumOfElements; - // for(i=0; iParseRefinementFlag(redges, type, flag); // if (flag > max_gen) max_gen = flag; if (elements[i]->NeedRefinement(v_to_v, middle)) { need_refinement = 1; - Bisection ( i, v_to_v, NULL, NULL, middle); + Bisection(i, v_to_v, NULL, NULL, middle); } } - } while (need_refinement == 1); + } + while (need_refinement == 1); // cout << "Maximum generation: " << max_gen << endl; // 5. Update the boundary elements. - do { + do + { need_refinement = 0; - for(i=0; iNeedRefinement(v_to_v, middle)) { need_refinement = 1; - Bisection ( i, v_to_v, middle); + Bisection(i, v_to_v, middle); } - } while (need_refinement == 1); + } + while (need_refinement == 1); // 6. Un-mark the Pf elements. int refinement_edges[2], type, flag; - for(i=0; iGetType() == Element::BISECTED) @@ -3732,7 +4411,7 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) delete [] middle; #ifdef MFEM_DEBUG - CheckElementOrientation (); + CheckElementOrientation(); #endif if (el_to_edge != NULL) @@ -3756,7 +4435,7 @@ void Mesh::LocalRefinement(const Array &marked_el, int type) { c_el_to_face = el_to_face; el_to_face = NULL; - Swap (faces_info, fc_faces_info); + Swap(faces_info, fc_faces_info); } GetElementToFaceTable(); GenerateFaces(); @@ -3802,19 +4481,13 @@ void Mesh::UniformRefinement() mfem_error("Mesh::UniformRefinement()"); } -void Mesh::MarkEdges() -{ - const int mark_faces = 1; - MarkTetMeshForRefinement(mark_faces); -} - void Mesh::Bisection(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle) { int *vert; int v[2][4], v_new, bisect, t; - double coord[3]; Element **pce; + Vertex V; if (WantTwoLevelState) { @@ -3846,17 +4519,17 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, vert = tri->GetVertices(); // 1. Get the index for the new vertex in v_new. - bisect = v_to_v(vert[0],vert[1]); + bisect = v_to_v(vert[0], vert[1]); #ifdef MFEM_DEBUG if (bisect < 0) - mfem_error ("Mesh::Bisection (...): ERROR"); + mfem_error("Mesh::Bisection(...): ERROR"); #endif if (middle[bisect] == -1) { v_new = NumOfVertices++; - coord[0] = (vertices[vert[0]](0) + vertices[vert[1]](0))/2.; - coord[1] = (vertices[vert[0]](1) + vertices[vert[1]](1))/2.; - Vertex V(coord[0], coord[1]); + V(0) = 0.5 * (vertices[vert[0]](0) + vertices[vert[1]](0)); + V(1) = 0.5 * (vertices[vert[0]](1) + vertices[vert[1]](1)); + V(2) = 0.0; vertices.Append(V); // Put the element that may need refinement (because of this @@ -3898,10 +4571,10 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, // 3. edge1 and edge2 may have to be changed for the second triangle. if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows()) { - bisect = v_to_v(v[1][0],v[1][1]); + bisect = v_to_v(v[1][0], v[1][1]); #ifdef MFEM_DEBUG if (bisect < 0) - mfem_error ("Mesh::Bisection (...): ERROR 2"); + mfem_error("Mesh::Bisection(...): ERROR 2"); #endif if (edge1[bisect] == i) edge1[bisect] = NumOfElements; @@ -3942,11 +4615,9 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, if (middle[bisect] == -1) { v_new = NumOfVertices++; - for(j=0; j<3; j++) - coord[j] = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j)); - - Vertex V( coord[0], coord[1], coord[2] ); - vertices.Append( V ); + for (j = 0; j < 3; j++) + V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j)); + vertices.Append(V); middle[bisect] = v_new; } @@ -3993,27 +4664,27 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, { #ifdef MFEM_USE_MEMALLOC BisectedElement *aux = BEMemory.Alloc(); - aux -> SetCoarseElem (tet); + aux->SetCoarseElem(tet); tet = TetMemory.Alloc(); - tet -> SetVertices (v[0]); - tet -> SetAttribute (attr); + tet->SetVertices(v[0]); + tet->SetAttribute(attr); #else - BisectedElement *aux = new BisectedElement (tet); - tet = new Tetrahedron (v[0], attr); + BisectedElement *aux = new BisectedElement(tet); + tet = new Tetrahedron(v[0], attr); #endif aux->FirstChild = tet; aux->SecondChild = NumOfElements; pce[0] = aux; } else - tet->SetVertices( v[0] ); + tet->SetVertices(v[0]); // 'tet' now points to the first child { #ifdef MFEM_USE_MEMALLOC Tetrahedron *tet2 = TetMemory.Alloc(); - tet2 -> SetVertices (v[1]); - tet2 -> SetAttribute (attr); - elements.Append (tet2); + tet2->SetVertices(v[1]); + tet2->SetAttribute(attr); + elements.Append(tet2); #else elements.Append(new Tetrahedron(v[1], attr)); #endif @@ -4030,21 +4701,20 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, new_type = Tetrahedron::TYPE_PU; } - tet->CreateRefinementFlag (new_redges[0], new_type, flag+1); + tet->CreateRefinementFlag(new_redges[0], new_type, flag+1); ((Tetrahedron *)elements[NumOfElements])-> - CreateRefinementFlag (new_redges[1], new_type, flag+1); + CreateRefinementFlag(new_redges[1], new_type, flag+1); NumOfElements++; } else - mfem_error ("Bisection for now works only for triangles & tetrahedra."); + mfem_error("Bisection for now works only for triangles & tetrahedra."); } void Mesh::Bisection(int i, const DSTable &v_to_v, int *middle) { int *vert; int v[2][3], v_new, bisect, t; - // double coord[3]; Element **pce; if (WantTwoLevelState) @@ -4075,9 +4745,9 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, int *middle) vert = tri->GetVertices(); // 1. Get the index for the new vertex in v_new. - bisect = v_to_v(vert[0],vert[1]); + bisect = v_to_v(vert[0], vert[1]); if (middle[bisect] == -1) - mfem_error ("Error in Bisection(...) of boundary triangle!"); + mfem_error("Error in Bisection(...) of boundary triangle!"); else v_new = middle[bisect]; @@ -4089,23 +4759,23 @@ void Mesh::Bisection(int i, const DSTable &v_to_v, int *middle) { #ifdef MFEM_USE_MEMALLOC BisectedElement *aux = BEMemory.Alloc(); - aux->SetCoarseElem (tri); + aux->SetCoarseElem(tri); #else - BisectedElement *aux = new BisectedElement (tri); + BisectedElement *aux = new BisectedElement(tri); #endif - aux->FirstChild = tri = new Triangle (v[0], tri->GetAttribute()); + aux->FirstChild = tri = new Triangle(v[0], tri->GetAttribute()); aux->SecondChild = NumOfBdrElements; pce[0] = aux; } else - boundary[i]->SetVertices( v[0] ); + boundary[i]->SetVertices(v[0]); // 'tri' now points to the first child - boundary.Append( new Triangle (v[1], tri->GetAttribute()) ); + boundary.Append(new Triangle(v[1], tri->GetAttribute())); NumOfBdrElements++; } else - mfem_error ("Bisection of boundary elements works only for triangles!"); + mfem_error("Bisection of boundary elements works only for triangles!"); } void Mesh::UniformRefinement(int i, const DSTable &v_to_v, @@ -4125,7 +4795,7 @@ void Mesh::UniformRefinement(int i, const DSTable &v_to_v, bisect[2] = v_to_v(v[0],v[2]); #ifdef MFEM_DEBUG if (bisect[0] < 0 || bisect[1] < 0 || bisect[2] < 0) - mfem_error ("Mesh::UniformRefinement (...): ERROR"); + mfem_error("Mesh::UniformRefinement(...): ERROR"); #endif for (j = 0; j < 3; j++) // for the 3 edges fix v_new @@ -4179,10 +4849,10 @@ void Mesh::UniformRefinement(int i, const DSTable &v_to_v, NumOfElements += 3; } else - mfem_error ("Uniform refinement for now works only for triangles."); + mfem_error("Uniform refinement for now works only for triangles."); } -void Mesh::SetState (int s) +void Mesh::SetState(int s) { if (State != Mesh::NORMAL && s == Mesh::NORMAL) { @@ -4198,14 +4868,14 @@ void Mesh::SetState (int s) { RefinedElement *aux = (RefinedElement *) elements[i]; elements[i] = aux->FirstChild; - FreeElement (aux->CoarseElem); - FreeElement (aux); + FreeElement(aux->CoarseElem); + FreeElement(aux); } else i++; } - for (i=0; iGetType(); if (t == Element::BISECTED || @@ -4214,8 +4884,8 @@ void Mesh::SetState (int s) { RefinedElement *aux = (RefinedElement *) boundary[i]; boundary[i] = aux->FirstChild; - FreeElement (aux->CoarseElem); - FreeElement (aux); + FreeElement(aux->CoarseElem); + FreeElement(aux); } else i++; @@ -4228,10 +4898,11 @@ void Mesh::SetState (int s) if (Dim == 2) { if (State == Mesh::TWO_LEVEL_COARSE) - Swap (be_to_edge, fc_be_to_edge); + Swap(be_to_edge, fc_be_to_edge); fc_be_to_edge.DeleteAll(); } - if (Dim == 3) { + if (Dim == 3) + { delete c_bel_to_edge; bel_to_edge = f_bel_to_edge; } @@ -4241,7 +4912,7 @@ void Mesh::SetState (int s) delete c_el_to_face; el_to_face = f_el_to_face; if (State == Mesh::TWO_LEVEL_COARSE) - Swap (faces_info, fc_faces_info); + Swap(faces_info, fc_faces_info); fc_faces_info.DeleteAll(); } @@ -4259,14 +4930,14 @@ void Mesh::SetState (int s) { el_to_edge = f_el_to_edge; if (Dim == 2) - Swap (be_to_edge, fc_be_to_edge); + Swap(be_to_edge, fc_be_to_edge); if (Dim == 3) bel_to_edge = f_bel_to_edge; } if (el_to_face != NULL) { el_to_face = f_el_to_face; - Swap (faces_info, fc_faces_info); + Swap(faces_info, fc_faces_info); } NumOfVertices = f_NumOfVertices; NumOfEdges = f_NumOfEdges; @@ -4282,14 +4953,14 @@ void Mesh::SetState (int s) { el_to_edge = c_el_to_edge; if (Dim == 2) - Swap (be_to_edge, fc_be_to_edge); + Swap(be_to_edge, fc_be_to_edge); if (Dim == 3) bel_to_edge = c_bel_to_edge; } if (el_to_face != NULL) { el_to_face = c_el_to_face; - Swap (faces_info, fc_faces_info); + Swap(faces_info, fc_faces_info); } NumOfVertices = c_NumOfVertices; NumOfEdges = c_NumOfEdges; @@ -4300,10 +4971,10 @@ void Mesh::SetState (int s) State = s; } else if (State != s) - mfem_error ("Oops! Mesh::SetState"); + mfem_error("Oops! Mesh::SetState"); } -int Mesh::GetNumFineElems (int i) +int Mesh::GetNumFineElems(int i) { int t; @@ -4318,8 +4989,9 @@ int Mesh::GetNumFineElems (int i) // regular elements int n = 1; BisectedElement *aux = (BisectedElement *) elements[i]; - do { - n += GetNumFineElems (aux->SecondChild); + do + { + n += GetNumFineElems(aux->SecondChild); if (aux->FirstChild->GetType() != Element::BISECTED) break; aux = (BisectedElement *) (aux->FirstChild); @@ -4356,15 +5028,15 @@ int Mesh::GetNumFineElems (int i) return 1; // the element is not refined } -int Mesh::GetBisectionHierarchy (Element *E) +int Mesh::GetBisectionHierarchy(Element *E) { if (E->GetType() == Element::BISECTED) { int L, R, n, s, lb, rb; - L = GetBisectionHierarchy (((BisectedElement *)E)->FirstChild); + L = GetBisectionHierarchy(((BisectedElement *)E)->FirstChild); n = ((BisectedElement *)E)->SecondChild; - R = GetBisectionHierarchy (elements[n]); + R = GetBisectionHierarchy(elements[n]); n = 1; s = 1; lb = rb = 1; do @@ -4389,13 +5061,13 @@ int Mesh::GetBisectionHierarchy (Element *E) } lb = 2 * nlb; rb = 2 * nrb; } - while ( lb > 0 || rb > 0 ); + while (lb > 0 || rb > 0); return n; } return 0; } -int Mesh::GetRefinementType (int i) +int Mesh::GetRefinementType(int i) { int t; @@ -4404,7 +5076,7 @@ int Mesh::GetRefinementType (int i) t = elements[i]->GetType(); if (t == Element::QUADRISECTED) { - t = ((QuadrisectedElement *)elements[i]) -> CoarseElem -> GetType(); + t = ((QuadrisectedElement *)elements[i])->CoarseElem->GetType(); if (t == Element::QUADRILATERAL) return 1; // refinement type for quadrisected QUADRILATERAL else @@ -4413,9 +5085,9 @@ int Mesh::GetRefinementType (int i) else if (t == Element::BISECTED) { int type; - type = GetBisectionHierarchy (elements[i]); + type = GetBisectionHierarchy(elements[i]); if (type == 0) - mfem_error ("Mesh::GetRefinementType (...)"); + mfem_error("Mesh::GetRefinementType(...)"); return type+2; } } @@ -4433,13 +5105,13 @@ int Mesh::GetRefinementType (int i) return 0; // Bisected TETRAHEDRON tet = (Tetrahedron *) (((BisectedElement *) E)->CoarseElem); - tet->ParseRefinementFlag (redges, type, flag); + tet->ParseRefinementFlag(redges, type, flag); if (type == Tetrahedron::TYPE_A && redges[0] == 2) type = 5; else if (type == Tetrahedron::TYPE_M && redges[0] == 2) type = 6; type++; - type |= ( GetBisectionHierarchy (E) << 3 ); + type |= ( GetBisectionHierarchy(E) << 3 ); if (type < 8) type = 0; return type; @@ -4448,7 +5120,7 @@ int Mesh::GetRefinementType (int i) return 0; // no refinement } -int Mesh::GetFineElem (int i, int j) +int Mesh::GetFineElem(int i, int j) { int t; @@ -4458,7 +5130,7 @@ int Mesh::GetFineElem (int i, int j) if (t == Element::QUADRISECTED) { QuadrisectedElement *aux = (QuadrisectedElement *) elements[i]; - if (aux -> CoarseElem -> GetType() == Element::QUADRILATERAL) + if (aux->CoarseElem->GetType() == Element::QUADRILATERAL) switch (j) { case 0: return i; @@ -4483,7 +5155,7 @@ int Mesh::GetFineElem (int i, int j) BisectedElement *aux = (BisectedElement *) elements[i]; do { - int k = GetFineElem (aux->SecondChild, j-n); + int k = GetFineElem(aux->SecondChild, j-n); if (k >= 0) return k; n -= k; // (-k) is the number of the leaves in this SecondChild @@ -4508,7 +5180,7 @@ int Mesh::GetFineElem (int i, int j) BisectedElement *aux = (BisectedElement *) elements[i]; do { - int k = GetFineElem (aux->SecondChild, j-n); + int k = GetFineElem(aux->SecondChild, j-n); if (k >= 0) return k; n -= k; // (-k) is the number of the leaves in this SecondChild @@ -4526,7 +5198,7 @@ int Mesh::GetFineElem (int i, int j) else if (t == Element::OCTASECTED) { if (j == 0) return i; - return ((OctasectedElement *) elements[i]) -> Child[j-1]; + return ((OctasectedElement *) elements[i])->Child[j-1]; } } @@ -4536,7 +5208,7 @@ int Mesh::GetFineElem (int i, int j) return i; // no refinement } -void Mesh::BisectTriTrans (DenseMatrix &pointmat, Triangle *tri, int child) +void Mesh::BisectTriTrans(DenseMatrix &pointmat, Triangle *tri, int child) { double np[2]; @@ -4560,12 +5232,12 @@ void Mesh::BisectTriTrans (DenseMatrix &pointmat, Triangle *tri, int child) } } -void Mesh::BisectTetTrans (DenseMatrix &pointmat, Tetrahedron *tet, int child) +void Mesh::BisectTetTrans(DenseMatrix &pointmat, Tetrahedron *tet, int child) { int i, j, redges[2], type, flag, ind[4]; double t[4]; - tet->ParseRefinementFlag (redges, type, flag); + tet->ParseRefinementFlag(redges, type, flag); if (child == 0) // left tetrahedron { @@ -4605,7 +5277,7 @@ void Mesh::BisectTetTrans (DenseMatrix &pointmat, Tetrahedron *tet, int child) } } -int Mesh::GetFineElemPath (int i, int j) +int Mesh::GetFineElemPath(int i, int j) { // if (Dim == 3) { @@ -4615,7 +5287,7 @@ int Mesh::GetFineElemPath (int i, int j) BisectedElement *aux = (BisectedElement *) elements[i]; do { - int k = GetFineElemPath (aux->SecondChild, j-n); + int k = GetFineElemPath(aux->SecondChild, j-n); if (k >= 0) return ((k << 1)+1) << l; n -= k; // (-k) is the number of the leaves in this SecondChild @@ -4638,7 +5310,7 @@ int Mesh::GetFineElemPath (int i, int j) return 0; } -ElementTransformation * Mesh::GetFineElemTrans (int i, int j) +ElementTransformation * Mesh::GetFineElemTrans(int i, int j) { int t; @@ -4650,12 +5322,12 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) t = elements[i]->GetType(); if (t == Element::QUADRISECTED) { - t = ((QuadrisectedElement *)elements[i]) -> CoarseElem -> GetType(); + t = ((QuadrisectedElement *)elements[i])->CoarseElem->GetType(); if (t == Element::QUADRILATERAL) { // quadrisected QUADRILATERAL - Transformation.SetFE (&QuadrilateralFE); - pm.SetSize (2, 4); + Transformation.SetFE(&QuadrilateralFE); + pm.SetSize(2, 4); switch (j) { case 0: @@ -4689,8 +5361,8 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) else { // quadrisected TRIANGLE - Transformation.SetFE (&TriangleFE); - pm.SetSize (2, 3); + Transformation.SetFE(&TriangleFE); + pm.SetSize(2, 3); switch (j) { case 0: @@ -4717,8 +5389,8 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) else if (t == Element::BISECTED) { // bisected TRIANGLE - Transformation.SetFE (&TriangleFE); - pm.SetSize (2, 3); + Transformation.SetFE(&TriangleFE); + pm.SetSize(2, 3); int path; Element *E; @@ -4728,14 +5400,14 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0; pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; - path = GetFineElemPath (i, j); + path = GetFineElemPath(i, j); E = elements[i]; while (E->GetType() == Element::BISECTED) { BisectedElement *aux = (BisectedElement *) E; - BisectTriTrans (pm, (Triangle *) aux->CoarseElem, path & 1); + BisectTriTrans(pm, (Triangle *) aux->CoarseElem, path & 1); E = (path & 1) ? elements[aux->SecondChild] : aux->FirstChild; path = path >> 1; } @@ -4743,8 +5415,8 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) else { // identity transformation - Transformation.SetFE (&TriangleFE); - pm.SetSize (2, 3); + Transformation.SetFE(&TriangleFE); + pm.SetSize(2, 3); pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0; pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; } @@ -4757,10 +5429,10 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) int jj; double dx, dy, dz; DenseMatrix &pm = Transformation.GetPointMat(); - Transformation.SetFE (&HexahedronFE); + Transformation.SetFE(&HexahedronFE); Transformation.Attribute = 0; Transformation.ElementNo = 0; - pm.SetSize (3, 8); + pm.SetSize(3, 8); if (j < 4) dz = 0.0; else dz = 0.5; jj = j % 4; @@ -4781,10 +5453,10 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) int path; Element *E; DenseMatrix &pm = Transformation.GetPointMat(); - Transformation.SetFE (&TetrahedronFE); + Transformation.SetFE(&TetrahedronFE); Transformation.Attribute = 0; Transformation.ElementNo = 0; - pm.SetSize (3, 4); + pm.SetSize(3, 4); // pm is initialzed with the coordinates of the vertices of the // reference tetrahedron @@ -4792,14 +5464,14 @@ ElementTransformation * Mesh::GetFineElemTrans (int i, int j) pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; pm(1,3) = 0.0; pm(2,0) = 0.0; pm(2,1) = 0.0; pm(2,2) = 0.0; pm(2,3) = 1.0; - path = GetFineElemPath (i, j); + path = GetFineElemPath(i, j); E = elements[i]; while (E->GetType() == Element::BISECTED) { BisectedElement *aux = (BisectedElement *) E; - BisectTetTrans (pm, (Tetrahedron *) aux->CoarseElem, path & 1); + BisectTetTrans(pm, (Tetrahedron *) aux->CoarseElem, path & 1); E = (path & 1) ? elements[aux->SecondChild] : aux->FirstChild; path = path >> 1; } @@ -4823,24 +5495,24 @@ void Mesh::PrintXG(ostream &out) const // Print the boundary elements. out << NumOfBdrElements << '\n'; - for(i=0; iGetVertices(v); out << boundary[i]->GetAttribute(); - for(j=0; jGetVertices( v); + elements[i]->GetVertices(v); out << elements[i]->GetAttribute() << ' ' << v.Size(); - for(j=0; j GetNVertices (); - ind = elements[i] -> GetVertices (); - out << elements[i] -> GetAttribute(); - for(j=0; jGetNVertices(); + ind = elements[i]->GetVertices(); + out << elements[i]->GetAttribute(); + for (j = 0; j < nv; j++) out << ' ' << ind[j]+1; out << '\n'; } // print the boundary information. out << NumOfBdrElements << '\n'; - for(i=0; i< NumOfBdrElements; i++) + for (i = 0; i < NumOfBdrElements; i++) { - nv = boundary[i] -> GetNVertices (); - ind = boundary[i] -> GetVertices (); - out << boundary[i] -> GetAttribute(); - for(j=0; jGetNVertices(); + ind = boundary[i]->GetVertices(); + out << boundary[i]->GetAttribute(); + for (j = 0; j < nv; j++) out << ' ' << ind[j]+1; out << '\n'; } @@ -4928,20 +5600,20 @@ void Mesh::PrintXG(ostream &out) const for (i = 0; i < NumOfElements; i++) { - nv = elements[i] -> GetNVertices (); - ind = elements[i] -> GetVertices (); - out << i+1 << ' ' << elements[i] -> GetAttribute(); - for(j = 0; j < nv; j++) + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); + out << i+1 << ' ' << elements[i]->GetAttribute(); + for (j = 0; j < nv; j++) out << ' ' << ind[j]+1; out << '\n'; } - for(i=0; i< NumOfBdrElements; i++) + for (i = 0; i < NumOfBdrElements; i++) { - nv = boundary[i] -> GetNVertices (); - ind = boundary[i] -> GetVertices (); - out << boundary[i] -> GetAttribute(); - for(j=0; jGetNVertices(); + ind = boundary[i]->GetVertices(); + out << boundary[i]->GetAttribute(); + for (j = 0; j < nv; j++) out << ' ' << ind[j]+1; out << " 1.0 1.0 1.0 1.0\n"; } @@ -5010,6 +5682,153 @@ void Mesh::Print(ostream &out) const } } +void Mesh::PrintVTK(ostream &out) +{ + out << + "# vtk DataFile Version 3.0\n" + "Generated by MFEM\n" + "ASCII\n" + "DATASET UNSTRUCTURED_GRID\n"; + + if (Nodes == NULL) + { + out << "POINTS " << NumOfVertices << " double\n"; + for (int i = 0; i < NumOfVertices; i++) + { + out << vertices[i](0); + int j; + for (j = 1; j < Dim; j++) + out << ' ' << vertices[i](j); + for ( ; j < 3; j++) + out << ' ' << 0.0; + out << '\n'; + } + } + else + { + Array vdofs(3); + out << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n"; + for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++) + { + vdofs.SetSize(1); + vdofs[0] = i; + Nodes->FESpace()->DofsToVDofs(vdofs); + out << (*Nodes)(vdofs[0]); + int j; + for (j = 1; j < Dim; j++) + out << ' ' << (*Nodes)(vdofs[j]); + for ( ; j < 3; j++) + out << ' ' << 0.0; + out << '\n'; + } + } + + int order = -1; + if (Nodes == NULL) + { + int size = 0; + for (int i = 0; i < NumOfElements; i++) + size += elements[i]->GetNVertices() + 1; + out << "CELLS " << NumOfElements << ' ' << size << '\n'; + for (int i = 0; i < NumOfElements; i++) + { + const int *v = elements[i]->GetVertices(); + const int nv = elements[i]->GetNVertices(); + out << nv; + for (int j = 0; j < nv; j++) + out << ' ' << v[j]; + out << '\n'; + } + order = 1; + } + else + { + Array dofs; + int size = 0; + for (int i = 0; i < NumOfElements; i++) + { + Nodes->FESpace()->GetElementDofs(i, dofs); + size += dofs.Size() + 1; + } + out << "CELLS " << NumOfElements << ' ' << size << '\n'; + const char *fec_name = Nodes->FESpace()->FEColl()->Name(); + if (!strcmp(fec_name, "Linear")) + order = 1; + else if (!strcmp(fec_name, "Quadratic")) + order = 2; + if (order == -1) + { + cerr << "Mesh::PrintVTK : can not save '" + << fec_name << "' elements!" << endl; + mfem_error(); + } + for (int i = 0; i < NumOfElements; i++) + { + Nodes->FESpace()->GetElementDofs(i, dofs); + out << dofs.Size(); + if (order == 1) + { + for (int j = 0; j < dofs.Size(); j++) + out << ' ' << dofs[j]; + } + else if (order == 2) + { + const int *vtk_mfem; + switch (elements[i]->GetGeometryType()) + { + case Geometry::TRIANGLE: + case Geometry::SQUARE: + vtk_mfem = vtk_quadratic_hex; break; // identity map + case Geometry::TETRAHEDRON: + vtk_mfem = vtk_quadratic_tet; break; + case Geometry::CUBE: + vtk_mfem = vtk_quadratic_hex; break; + } + for (int j = 0; j < dofs.Size(); j++) + out << ' ' << dofs[vtk_mfem[j]]; + } + out << '\n'; + } + } + + out << "CELL_TYPES " << NumOfElements << '\n'; + for (int i = 0; i < NumOfElements; i++) + { + int vtk_cell_type; + if (order == 1) + { + switch (elements[i]->GetGeometryType()) + { + case Geometry::TRIANGLE: vtk_cell_type = 5; break; + case Geometry::SQUARE: vtk_cell_type = 9; break; + case Geometry::TETRAHEDRON: vtk_cell_type = 10; break; + case Geometry::CUBE: vtk_cell_type = 12; break; + } + } + else if (order == 2) + { + switch (elements[i]->GetGeometryType()) + { + case Geometry::TRIANGLE: vtk_cell_type = 22; break; + case Geometry::SQUARE: vtk_cell_type = 28; break; + case Geometry::TETRAHEDRON: vtk_cell_type = 24; break; + case Geometry::CUBE: vtk_cell_type = 29; break; + } + } + + out << vtk_cell_type << '\n'; + } + + // write attributes + out << "CELL_DATA " << NumOfElements << '\n' + << "SCALARS material int\n" + << "LOOKUP_TABLE default\n"; + for (int i = 0; i < NumOfElements; i++) + { + out << elements[i]->GetAttribute() << '\n'; + } +} + void Mesh::PrintVTK(ostream &out, int ref) { int np, nc, size; @@ -5293,9 +6112,9 @@ void Mesh::PrintWithPartitioning(int *partitioning, ostream &out) const } } -void Mesh::PrintElementsWithPartitioning (int *partitioning, - ostream &out, - int interior_faces) +void Mesh::PrintElementsWithPartitioning(int *partitioning, + ostream &out, + int interior_faces) { if (Dim != 3 && Dim != 2) return; @@ -5309,8 +6128,8 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, vcount[i] = 0; for (i = 0; i < NumOfElements; i++) { - nv = elements[i] -> GetNVertices (); - ind = elements[i] -> GetVertices (); + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); for (j = 0; j < nv; j++) vcount[ind[j]]++; } @@ -5331,10 +6150,10 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, int *ind; Table edge_el; - Transpose (ElementToEdgeTable(), edge_el); + Transpose(ElementToEdgeTable(), edge_el); // Fake printing of the elements. - for(i = 0; i < NumOfElements; i++) + for (i = 0; i < NumOfElements; i++) { nv = elements[i]->GetNVertices(); ind = elements[i]->GetVertices(); @@ -5351,8 +6170,8 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, nbe = 0; for (i = 0; i < edge_el.Size(); i++) { - const int *el = edge_el.GetRow (i); - if (edge_el.RowSize (i) > 1) + const int *el = edge_el.GetRow(i); + if (edge_el.RowSize(i) > 1) { k = partitioning[el[0]]; l = partitioning[el[1]]; @@ -5368,32 +6187,36 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, for (i = 0; i < edge_el.Size(); i++) { - const int *el = edge_el.GetRow (i); - if (edge_el.RowSize (i) > 1) { + const int *el = edge_el.GetRow(i); + if (edge_el.RowSize(i) > 1) + { k = partitioning[el[0]]; l = partitioning[el[1]]; - if (interior_faces || k != l) { + if (interior_faces || k != l) + { Array ev; GetEdgeVertices(i,ev); out << k+1; // attribute - for(j = 0; j < 2; j++) + for (j = 0; j < 2; j++) for (s = 0; s < vcount[ev[j]]; s++) if (vown[ev[j]][s] == el[0]) out << ' ' << voff[ev[j]]+s+1; out << '\n'; out << l+1; // attribute - for(j = 1; j >= 0; j--) + for (j = 1; j >= 0; j--) for (s = 0; s < vcount[ev[j]]; s++) if (vown[ev[j]][s] == el[1]) out << ' ' << voff[ev[j]]+s+1; out << '\n'; } - } else { + } + else + { k = partitioning[el[0]]; Array ev; GetEdgeVertices(i,ev); out << k+1; // attribute - for(j = 0; j < 2; j++) + for (j = 0; j < 2; j++) for (s = 0; s < vcount[ev[j]]; s++) if (vown[ev[j]][s] == el[0]) out << ' ' << voff[ev[j]]+s+1; @@ -5403,13 +6226,13 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, // Print the elements. out << NumOfElements << '\n'; - for(i = 0; i < NumOfElements; i++) + for (i = 0; i < NumOfElements; i++) { nv = elements[i]->GetNVertices(); ind = elements[i]->GetVertices(); out << partitioning[i]+1 << ' '; // use subdomain number as attribute out << nv << ' '; - for(j = 0; j < nv; j++) + for (j = 0; j < nv; j++) { out << ' ' << voff[ind[j]]+vcount[ind[j]]--; vown[ind[j]][vcount[ind[j]]] = i; @@ -5422,8 +6245,8 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, // Print the vertices. out << voff[NumOfVertices] << '\n'; - for(i = 0; i < NumOfVertices; i++) - for(k = 0; k < vcount[i]; k++) + for (i = 0; i < NumOfVertices; i++) + for (k = 0; k < vcount[i]; k++) { for (j = 0; j < Dim; j++) out << vertices[i](j) << ' '; @@ -5440,19 +6263,22 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, // print the vertices out << voff[NumOfVertices] << '\n'; for (i = 0; i < NumOfVertices; i++) - for(k = 0; k < vcount[i]; k++) { - for(j=0; j GetNVertices (); - ind = elements[i] -> GetVertices (); + for (i = 0; i < NumOfElements; i++) + { + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); out << partitioning[i]+1; // use subdomain number as attribute - for (j = 0; j < nv; j++) { + for (j = 0; j < nv; j++) + { out << ' ' << voff[ind[j]]+vcount[ind[j]]--; vown[ind[j]][vcount[ind[j]]] = i; } @@ -5466,7 +6292,8 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, int k, l, nbe; nbe = 0; for (i = 0; i < NumOfFaces; i++) - if ((l = faces_info[i].Elem2No) >= 0) { + if ((l = faces_info[i].Elem2No) >= 0) + { k = partitioning[faces_info[i].Elem1No]; l = partitioning[l]; if (interior_faces || k != l) @@ -5477,31 +6304,35 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, out << nbe << '\n'; for (i = 0; i < NumOfFaces; i++) - if ((l = faces_info[i].Elem2No) >= 0) { + if ((l = faces_info[i].Elem2No) >= 0) + { k = partitioning[faces_info[i].Elem1No]; l = partitioning[l]; - if (interior_faces || k != l) { - nv = faces[i] -> GetNVertices(); - ind = faces[i] -> GetVertices(); + if (interior_faces || k != l) + { + nv = faces[i]->GetNVertices(); + ind = faces[i]->GetVertices(); out << k+1; // attribute - for(j = 0; j < nv; j++) + for (j = 0; j < nv; j++) for (s = 0; s < vcount[ind[j]]; s++) if (vown[ind[j]][s] == faces_info[i].Elem1No) out << ' ' << voff[ind[j]]+s+1; out << '\n'; out << l+1; // attribute - for(j = nv-1; j >= 0; j--) + for (j = nv-1; j >= 0; j--) for (s = 0; s < vcount[ind[j]]; s++) if (vown[ind[j]][s] == faces_info[i].Elem2No) out << ' ' << voff[ind[j]]+s+1; out << '\n'; } - } else { + } + else + { k = partitioning[faces_info[i].Elem1No]; - nv = faces[i] -> GetNVertices(); - ind = faces[i] -> GetVertices(); + nv = faces[i]->GetNVertices(); + ind = faces[i]->GetVertices(); out << k+1; // attribute - for(j = 0; j < nv; j++) + for (j = 0; j < nv; j++) for (s = 0; s < vcount[ind[j]]; s++) if (vown[ind[j]][s] == faces_info[i].Elem1No) out << ' ' << voff[ind[j]]+s+1; @@ -5543,10 +6374,10 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, for (i = 0; i < NumOfElements; i++) { - nv = elements[i] -> GetNVertices (); - ind = elements[i] -> GetVertices (); + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); out << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute - for(j = 0; j < nv; j++) + for (j = 0; j < nv; j++) { out << ' ' << voff[ind[j]]+vcount[ind[j]]--; vown[ind[j]][vcount[ind[j]]] = i; @@ -5565,16 +6396,16 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, l = partitioning[l]; if (interior_faces || k != l) { - nv = faces[i] -> GetNVertices(); - ind = faces[i] -> GetVertices(); + nv = faces[i]->GetNVertices(); + ind = faces[i]->GetVertices(); out << k+1; // attribute - for(j = 0; j < nv; j++) + for (j = 0; j < nv; j++) for (s = 0; s < vcount[ind[j]]; s++) if (vown[ind[j]][s] == faces_info[i].Elem1No) out << ' ' << voff[ind[j]]+s+1; out << " 1.0 1.0 1.0 1.0\n"; out << l+1; // attribute - for(j = nv-1; j >= 0; j--) + for (j = nv-1; j >= 0; j--) for (s = 0; s < vcount[ind[j]]; s++) if (vown[ind[j]][s] == faces_info[i].Elem2No) out << ' ' << voff[ind[j]]+s+1; @@ -5584,10 +6415,10 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, else { k = partitioning[faces_info[i].Elem1No]; - nv = faces[i] -> GetNVertices(); - ind = faces[i] -> GetVertices(); + nv = faces[i]->GetNVertices(); + ind = faces[i]->GetVertices(); out << k+1; // attribute - for(j = 0; j < nv; j++) + for (j = 0; j < nv; j++) for (s = 0; s < vcount[ind[j]]; s++) if (vown[ind[j]][s] == faces_info[i].Elem1No) out << ' ' << voff[ind[j]]+s+1; @@ -5602,7 +6433,7 @@ void Mesh::PrintElementsWithPartitioning (int *partitioning, delete [] vown; } -void Mesh::ScaleSubdomains (double sf) +void Mesh::ScaleSubdomains(double sf) { int i,j,k; Array vert; @@ -5614,25 +6445,29 @@ void Mesh::ScaleSubdomains (double sf) int *vn = new int[NumOfVertices]; for (i = 0; i < NumOfVertices; i++) vn[i] = 0; - for (i = 0; i < na; i++) { + for (i = 0; i < na; i++) + { for (j = 0; j < Dim; j++) cg[i*Dim+j] = 0.0; nbea[i] = 0; } - for (i = 0; i < NumOfElements; i++) { - GetElementVertices (i, vert); + for (i = 0; i < NumOfElements; i++) + { + GetElementVertices(i, vert); for (k = 0; k < vert.Size(); k++) vn[vert[k]] = 1; } - for (i = 0; i < NumOfElements; i++) { + for (i = 0; i < NumOfElements; i++) + { int bea = GetAttribute(i)-1; - GetPointMatrix (i, pointmat); - GetElementVertices (i, vert); + GetPointMatrix(i, pointmat); + GetElementVertices(i, vert); for (k = 0; k < vert.Size(); k++) - if (vn[vert[k]] == 1) { + if (vn[vert[k]] == 1) + { nbea[bea]++; for (j = 0; j < Dim; j++) cg[bea*Dim+j] += pointmat(j,k); @@ -5640,12 +6475,14 @@ void Mesh::ScaleSubdomains (double sf) } } - for (i = 0; i < NumOfElements; i++) { + for (i = 0; i < NumOfElements; i++) + { int bea = GetAttribute(i)-1; GetElementVertices (i, vert); for (k = 0; k < vert.Size(); k++) - if (vn[vert[k]]) { + if (vn[vert[k]]) + { for (j = 0; j < Dim; j++) vertices[vert[k]](j) = sf*vertices[vert[k]](j) + (1-sf)*cg[bea*Dim+j]/nbea[bea]; @@ -5658,7 +6495,7 @@ void Mesh::ScaleSubdomains (double sf) delete [] vn; } -void Mesh::ScaleElements (double sf) +void Mesh::ScaleElements(double sf) { int i,j,k; Array vert; @@ -5670,25 +6507,29 @@ void Mesh::ScaleElements (double sf) int *vn = new int[NumOfVertices]; for (i = 0; i < NumOfVertices; i++) vn[i] = 0; - for (i = 0; i < na; i++) { + for (i = 0; i < na; i++) + { for (j = 0; j < Dim; j++) cg[i*Dim+j] = 0.0; nbea[i] = 0; } - for (i = 0; i < NumOfElements; i++) { - GetElementVertices (i, vert); + for (i = 0; i < NumOfElements; i++) + { + GetElementVertices(i, vert); for (k = 0; k < vert.Size(); k++) vn[vert[k]] = 1; } - for (i = 0; i < NumOfElements; i++) { + for (i = 0; i < NumOfElements; i++) + { int bea = i; - GetPointMatrix (i, pointmat); - GetElementVertices (i, vert); + GetPointMatrix(i, pointmat); + GetElementVertices(i, vert); for (k = 0; k < vert.Size(); k++) - if (vn[vert[k]] == 1) { + if (vn[vert[k]] == 1) + { nbea[bea]++; for (j = 0; j < Dim; j++) cg[bea*Dim+j] += pointmat(j,k); @@ -5696,12 +6537,14 @@ void Mesh::ScaleElements (double sf) } } - for (i = 0; i < NumOfElements; i++) { + for (i = 0; i < NumOfElements; i++) + { int bea = i; - GetElementVertices (i, vert); + GetElementVertices(i, vert); for (k = 0; k < vert.Size(); k++) - if (vn[vert[k]]) { + if (vn[vert[k]]) + { for (j = 0; j < Dim; j++) vertices[vert[k]](j) = sf*vertices[vert[k]](j) + (1-sf)*cg[bea*Dim+j]/nbea[bea]; @@ -5736,14 +6579,14 @@ void Mesh::Transform(void (*f)(const Vector&, Vector&)) } } -void Mesh::FreeElement (Element *E) +void Mesh::FreeElement(Element *E) { #ifdef MFEM_USE_MEMALLOC if (E) - switch (E -> GetType()) + switch (E->GetType()) { - case Element::TETRAHEDRON: TetMemory.Free ((Tetrahedron *)E); break; - case Element::BISECTED: BEMemory.Free ((BisectedElement *)E); break; + case Element::TETRAHEDRON: TetMemory.Free((Tetrahedron *)E); break; + case Element::BISECTED: BEMemory.Free((BisectedElement *)E); break; default: delete E; break; } #else @@ -5758,13 +6601,13 @@ Mesh::~Mesh() if (own_nodes) delete Nodes; for (i = 0; i < NumOfElements; i++) - FreeElement (elements[i]); + FreeElement(elements[i]); for (i = 0; i < NumOfBdrElements; i++) - FreeElement (boundary[i]); + FreeElement(boundary[i]); for (i = 0; i < faces.Size(); i++) - FreeElement (faces[i]); + FreeElement(faces[i]); DeleteTables(); } diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 40336ca033..bc6f3075e0 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -17,8 +17,15 @@ class FiniteElementSpace; class GridFunction; +#ifdef MFEM_USE_MPI +class ParMesh; +#endif + class Mesh { +#ifdef MFEM_USE_MPI + friend class ParMesh; +#endif protected: int Dim; @@ -83,9 +90,9 @@ protected: void MarkForRefinement(); void MarkTriMeshForRefinement(); - void MarkTetMeshForRefinement(int mark_faces = 0); + void MarkTetMeshForRefinement(); - STable3D *GetElementToFaceTable (int ret_ftbl = 0); + STable3D *GetElementToFaceTable(int ret_ftbl = 0); /** Red refinement. Element with index i is refined. The default red refinement for now is Uniform. */ @@ -116,14 +123,10 @@ protected: void UpdateNodes(); /// Refine quadrilateral mesh. - void QuadUniformRefinement(); + virtual void QuadUniformRefinement(); /// Refine hexahedral mesh. - void HexUniformRefinement(); - - /** Mark the edges in the elements, boundary elements and faces for - refinement. */ - void MarkEdges(); + virtual void HexUniformRefinement(); void BisectTriTrans (DenseMatrix &pointmat, Triangle *tri, int child); @@ -294,6 +297,8 @@ public: const Element *GetBdrElement (int i) const { return boundary[i]; }; + Element *GetBdrElement (int i) { return boundary[i]; }; + const Element *GetFace (int i) const { return faces[i]; }; int GetFaceBaseGeometry(int i) const; @@ -417,7 +422,8 @@ public: /// The returned Table must be destroyed by the caller Table *GetVertexToElementTable(); - void CheckPartitioning (int *partitioning); + int *GeneratePartitioning(int nparts, int part_method = 1); + void CheckPartitioning(int *partitioning); void CheckDisplacements(const Vector &displacements, double &tmax); void MoveVertices(const Vector &displacements); @@ -437,11 +443,11 @@ public: void NewNodes(GridFunction &nodes); /// Refine the marked elements. - void LocalRefinement(const Array &marked_el, int type = 3); + virtual void LocalRefinement(const Array &marked_el, int type = 3); void UniformRefinement(); - /** Sets or clears the flag that indicates that 'LocalRefinement (...)' + /** Sets or clears the flag that indicates that mesh refinement methods should put the mesh in two-level state. */ void UseTwoLevelState (int use) { @@ -473,7 +479,10 @@ public: void PrintXG(ostream &out = cout) const; /// Print the mesh to the given stream using the default MFEM mesh format. - void Print(ostream &out = cout) const; + virtual void Print(ostream &out = cout) const; + + /// Print the mesh in VTK format (linear and quadratic meshes only). + void PrintVTK(ostream &out); /** Print the mesh in VTK format. The parameter ref specifies an element subdivision number (useful for high order fields and curved meshes). */ @@ -507,7 +516,7 @@ public: void PrintCharacteristics (Vector *Vh = NULL, Vector *Vk = NULL); /// Destroys mesh. - ~Mesh(); + virtual ~Mesh(); }; #endif diff --git a/mesh/mesh_headers.hpp b/mesh/mesh_headers.hpp index bd31e94457..91786821a5 100644 --- a/mesh/mesh_headers.hpp +++ b/mesh/mesh_headers.hpp @@ -37,4 +37,9 @@ #include "tetrahedron.hpp" #include "mesh.hpp" +#ifdef MFEM_USE_MPI +#include +#include "pmesh.hpp" +#endif + #endif diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp new file mode 100644 index 0000000000..ac885475d9 --- /dev/null +++ b/mesh/pmesh.cpp @@ -0,0 +1,2503 @@ +// 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.googlecode.com. +// +// 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. + +#ifdef MFEM_USE_MPI + +#include "mesh_headers.hpp" +#include "../fem/fem.hpp" +#include "../general/sets.hpp" + +ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_, + int part_method) +{ + int i, j; + int *partitioning; + + MyComm = comm; + MPI_Comm_size(MyComm, &NRanks); + MPI_Comm_rank(MyComm, &MyRank); + + Dim = mesh.Dim; + + if (partitioning_) + partitioning = partitioning_; + else + partitioning = mesh.GeneratePartitioning(NRanks, part_method); + + // re-enumerate the partitions to better map to actual processor + // interconnect topology !? + + Array vert; + Array vert_global_local(mesh.GetNV()); + int vert_counter, element_counter, bdrelem_counter; + + // build vert_global_local + for (i = 0; i < vert_global_local.Size(); i++) + vert_global_local[i] = -1; + + element_counter = 0; + vert_counter = 0; + for (i = 0; i < mesh.GetNE(); i++) + if (partitioning[i] == MyRank) + { + mesh.GetElementVertices(i, vert); + element_counter++; + for (j = 0; j < vert.Size(); j++) + if (vert_global_local[vert[j]] < 0) + vert_global_local[vert[j]] = vert_counter++; + } + + NumOfVertices = vert_counter; + NumOfElements = element_counter; + vertices.SetSize(NumOfVertices); + + // preserve ordering when running in serial + if (NRanks == 1) + for (i = 0; i < vert_global_local.Size(); i++) + vert_global_local[i] = i; + + // determine vertices + for (i = 0; i < vert_global_local.Size(); i++) + if (vert_global_local[i] >= 0) + vertices[vert_global_local[i]].SetCoords(mesh.GetVertex(i)); + + // determine elements + element_counter = 0; + elements.SetSize(NumOfElements); + for (i = 0; i < mesh.GetNE(); i++) + if (partitioning[i] == MyRank) + { + elements[element_counter] = mesh.GetElement(i)->Duplicate(); + int *v = elements[element_counter]->GetVertices(); + int nv = elements[element_counter]->GetNVertices(); + for (j = 0; j < nv; j++) + v[j] = vert_global_local[v[j]]; + element_counter++; + } + + Table *edge_element = NULL; + + // build boundary elements + if (Dim == 3) + { + NumOfBdrElements = 0; + for (i = 0; i < mesh.GetNBE(); i++) + { + int face = mesh.GetBdrElementEdgeIndex(i); + int el1, el2; + mesh.GetFaceElements(face, &el1, &el2); + if (partitioning[el1] == MyRank || + (el2 >= 0 && partitioning[el2] == MyRank)) + NumOfBdrElements++; + } + + bdrelem_counter = 0; + boundary.SetSize(NumOfBdrElements); + for (i = 0; i < mesh.GetNBE(); i++) + { + int face = mesh.GetBdrElementEdgeIndex(i); + int el1, el2; + mesh.GetFaceElements(face, &el1, &el2); + if (partitioning[el1] == MyRank || + (el2 >= 0 && partitioning[el2] == MyRank)) + { + boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(); + int *v = boundary[bdrelem_counter]->GetVertices(); + int nv = boundary[bdrelem_counter]->GetNVertices(); + for (j = 0; j < nv; j++) + v[j] = vert_global_local[v[j]]; + bdrelem_counter++; + } + } + + } + else if (Dim == 2) + { + edge_element = new Table; + Transpose(mesh.ElementToEdgeTable(), *edge_element, mesh.GetNEdges()); + + NumOfBdrElements = 0; + for (i = 0; i < mesh.GetNBE(); i++) + { + int edge = mesh.GetBdrElementEdgeIndex(i); + int el1, el2 = -1; + el1 = edge_element->GetRow(edge)[0]; + if (edge_element->RowSize(edge) == 2) + el2 = edge_element->GetRow(edge)[1]; + if (partitioning[el1] == MyRank || + (el2 >= 0 && partitioning[el2] == MyRank)) + NumOfBdrElements++; + } + + bdrelem_counter = 0; + boundary.SetSize(NumOfBdrElements); + for (i = 0; i < mesh.GetNBE(); i++) + { + int edge = mesh.GetBdrElementEdgeIndex(i); + int el1, el2 = -1; + el1 = edge_element->GetRow(edge)[0]; + if (edge_element->RowSize(edge) == 2) + el2 = edge_element->GetRow(edge)[1]; + if (partitioning[el1] == MyRank || + (el2 >= 0 && partitioning[el2] == MyRank)) + { + boundary[bdrelem_counter] = mesh.GetBdrElement(i)->Duplicate(); + int *v = boundary[bdrelem_counter]->GetVertices(); + int nv = boundary[bdrelem_counter]->GetNVertices(); + for (j = 0; j < nv; j++) + v[j] = vert_global_local[v[j]]; + bdrelem_counter++; + } + } + } + + meshgen = mesh.MeshGenerator(); + + attributes.SetSize(mesh.attributes.Size()); + for (i = 0; i < attributes.Size(); i++) + attributes[i] = mesh.attributes[i]; + bdr_attributes.SetSize(mesh.bdr_attributes.Size()); + for (i = 0; i < bdr_attributes.Size(); i++) + bdr_attributes[i] = mesh.bdr_attributes[i]; + + // this is called by the default Mesh constructor + // InitTables(); + + el_to_edge = new Table; + NumOfEdges = Mesh::GetElementToEdgeTable(*el_to_edge, be_to_edge); + + STable3D *faces_tbl = NULL; + if (Dim == 3) + faces_tbl = GetElementToFaceTable(1); + else + NumOfFaces = 0; + GenerateFaces(); + + c_el_to_edge = NULL; + + ListOfIntegerSets groups; + IntegerSet group; + + // the first group is the local one + group.Recreate(1, &MyRank); + groups.Insert(group); + +#ifdef MFEM_DEBUG + if (Dim < 3 && mesh.GetNFaces() != 0) + { + cerr << "ParMesh::ParMesh (proc " << MyRank << ") : " + "(Dim < 3 && mesh.GetNFaces() != 0) is true!" << endl; + mfem_error(); + } +#endif + // determine shared faces + int sface_counter = 0; + Array face_group(mesh.GetNFaces()); + for (i = 0; i < face_group.Size(); i++) + { + int el[2]; + face_group[i] = -1; + mesh.GetFaceElements(i, &el[0], &el[1]); + if (el[1] >= 0) + { + el[0] = partitioning[el[0]]; + el[1] = partitioning[el[1]]; + if ((el[0] == MyRank && el[1] != MyRank) || + (el[0] != MyRank && el[1] == MyRank)) + { + group.Recreate(2, el); + face_group[i] = groups.Insert(group) - 1; + sface_counter++; + } + } + } + + // determine shared edges + int sedge_counter = 0; + if (!edge_element) + { + edge_element = new Table; + Transpose(mesh.ElementToEdgeTable(), *edge_element, mesh.GetNEdges()); + } + for (i = 0; i < edge_element->Size(); i++) + { + int me = 0, others = 0; + for (j = edge_element->GetI()[i]; j < edge_element->GetI()[i+1]; j++) + { + edge_element->GetJ()[j] = partitioning[edge_element->GetJ()[j]]; + if (edge_element->GetJ()[j] == MyRank) + me = 1; + else + others = 1; + } + + if (me && others) + { + sedge_counter++; + group.Recreate(edge_element->RowSize(i), edge_element->GetRow(i)); + edge_element->GetRow(i)[0] = groups.Insert(group) - 1; + } + else + edge_element->GetRow(i)[0] = -1; + } + + // determine shared vertices + int svert_counter = 0; + Table *vert_element = mesh.GetVertexToElementTable(); // we must delete this + + for (i = 0; i < vert_element->Size(); i++) + { + int me = 0, others = 0; + for (j = vert_element->GetI()[i]; j < vert_element->GetI()[i+1]; j++) + { + vert_element->GetJ()[j] = partitioning[vert_element->GetJ()[j]]; + if (vert_element->GetJ()[j] == MyRank) + me = 1; + else + others = 1; + } + + if (me && others) + { + svert_counter++; + group.Recreate(vert_element->RowSize(i), vert_element->GetRow(i)); + vert_element->GetRow(i)[0] = groups.Insert(group) - 1; + } + else + vert_element->GetRow(i)[0] = -1; + } + + // build group_sface + group_sface.MakeI(groups.Size()-1); + + for (i = 0; i < face_group.Size(); i++) + if (face_group[i] >= 0) + group_sface.AddAColumnInRow(face_group[i]); + + group_sface.MakeJ(); + + sface_counter = 0; + for (i = 0; i < face_group.Size(); i++) + if (face_group[i] >= 0) + group_sface.AddConnection(face_group[i], sface_counter++); + + group_sface.ShiftUpI(); + + // build group_sedge + group_sedge.MakeI(groups.Size()-1); + + for (i = 0; i < edge_element->Size(); i++) + if (edge_element->GetRow(i)[0] >= 0) + group_sedge.AddAColumnInRow(edge_element->GetRow(i)[0]); + + group_sedge.MakeJ(); + + sedge_counter = 0; + for (i = 0; i < edge_element->Size(); i++) + if (edge_element->GetRow(i)[0] >= 0) + group_sedge.AddConnection(edge_element->GetRow(i)[0], + sedge_counter++); + + group_sedge.ShiftUpI(); + + // build group_svert + group_svert.MakeI(groups.Size()-1); + + for (i = 0; i < vert_element->Size(); i++) + if (vert_element->GetRow(i)[0] >= 0) + group_svert.AddAColumnInRow(vert_element->GetRow(i)[0]); + + group_svert.MakeJ(); + + svert_counter = 0; + for (i = 0; i < vert_element->Size(); i++) + if (vert_element->GetRow(i)[0] >= 0) + group_svert.AddConnection(vert_element->GetRow(i)[0], + svert_counter++); + + group_svert.ShiftUpI(); + + // build shared_faces and sface_lface + shared_faces.SetSize(sface_counter); + sface_lface. SetSize(sface_counter); + + if (Dim == 3) + { + sface_counter = 0; + for (i = 0; i < face_group.Size(); i++) + if (face_group[i] >= 0) + { + shared_faces[sface_counter] = mesh.GetFace(i)->Duplicate(); + int *v = shared_faces[sface_counter]->GetVertices(); + int nv = shared_faces[sface_counter]->GetNVertices(); + for (j = 0; j < nv; j++) + v[j] = vert_global_local[v[j]]; + switch (shared_faces[sface_counter]->GetType()) + { + case Element::TRIANGLE: + sface_lface[sface_counter] = (*faces_tbl)(v[0], v[1], v[2]); + // mark the shared face for refinement by reorienting + // it according to the refinement flag in the tetradron + // to which this shared face belongs to. + { + int lface = sface_lface[sface_counter]; + Tetrahedron *tet = + (Tetrahedron *)(elements[faces_info[lface].Elem1No]); + int re[2], type, flag, *tv; + tet->ParseRefinementFlag(re, type, flag); + tv = tet->GetVertices(); + switch (faces_info[lface].Elem1Inf/64) + { + case 0: + switch (re[1]) + { + case 1: v[0] = tv[1]; v[1] = tv[2]; v[2] = tv[3]; break; + case 4: v[0] = tv[3]; v[1] = tv[1]; v[2] = tv[2]; break; + case 5: v[0] = tv[2]; v[1] = tv[3]; v[2] = tv[1]; break; + } + break; + case 1: + switch (re[0]) + { + case 2: v[0] = tv[2]; v[1] = tv[0]; v[2] = tv[3]; break; + case 3: v[0] = tv[0]; v[1] = tv[3]; v[2] = tv[2]; break; + case 5: v[0] = tv[3]; v[1] = tv[2]; v[2] = tv[0]; break; + } + break; + case 2: + v[0] = tv[0]; v[1] = tv[1]; v[2] = tv[3]; + break; + case 3: + v[0] = tv[1]; v[1] = tv[0]; v[2] = tv[2]; + break; + } + // flip the shared face in the processor that owns the + // second element (in 'mesh') + { + int gl_el1, gl_el2; + mesh.GetFaceElements(i, &gl_el1, &gl_el2); + if (MyRank == partitioning[gl_el2]) + { + const int t = v[0]; v[0] = v[1]; v[1] = t; + } + } + } + break; + case Element::QUADRILATERAL: + sface_lface[sface_counter] = + (*faces_tbl)(v[0], v[1], v[2], v[3]); + break; + } + sface_counter++; + } + + delete faces_tbl; + } + + // build shared_edges and sedge_ledge + shared_edges.SetSize(sedge_counter); + sedge_ledge. SetSize(sedge_counter); + + { + DSTable v_to_v(NumOfVertices); + GetVertexToVertexTable(v_to_v); + + sedge_counter = 0; + for (i = 0; i < edge_element->Size(); i++) + if (edge_element->GetRow(i)[0] >= 0) + { + mesh.GetEdgeVertices(i, vert); + + shared_edges[sedge_counter] = + new Segment(vert_global_local[vert[0]], + vert_global_local[vert[1]], 1); + + if ((sedge_ledge[sedge_counter] = + v_to_v(vert_global_local[vert[0]], + vert_global_local[vert[1]])) < 0) + { + cerr << "\n\n\n" << MyRank << ": ParMesh::ParMesh: " + << "ERROR in v_to_v\n\n" << endl; + mfem_error(); + } + + sedge_counter++; + } + } + + delete edge_element; + + // build svert_lvert + svert_lvert.SetSize(svert_counter); + + svert_counter = 0; + for (i = 0; i < vert_element->Size(); i++) + if (vert_element->GetRow(i)[0] >= 0) + svert_lvert[svert_counter++] = vert_global_local[i]; + + delete vert_element; + + // build group_lproc, group_mgroupandproc and lproc_proc + groups.AsTable(group_lproc); // group_lproc = group_proc + + Table group_mgroupandproc; + group_mgroupandproc.SetDims(group_lproc.Size(), + group_lproc.Size_of_connections() + + group_lproc.Size()); + for (i = 0; i < group_mgroupandproc.Size(); i++) + { + j = group_mgroupandproc.GetI()[i]; + group_mgroupandproc.GetI()[i+1] = j + group_lproc.RowSize(i) + 1; + group_mgroupandproc.GetJ()[j] = i; + j++; + for (int k = group_lproc.GetI()[i]; + j < group_mgroupandproc.GetI()[i+1]; j++, k++) + group_mgroupandproc.GetJ()[j] = group_lproc.GetJ()[k]; + } + + Array proc_lproc(NRanks); // array of size number of processors! + proc_lproc = -1; + + int lproc_counter = 0; + for (i = 0; i < group_lproc.Size_of_connections(); i++) + if (proc_lproc[group_lproc.GetJ()[i]] < 0) + proc_lproc[group_lproc.GetJ()[i]] = lproc_counter++; + + lproc_proc.SetSize(lproc_counter); + for (i = 0; i < NRanks; i++) + if (proc_lproc[i] >= 0) + lproc_proc[proc_lproc[i]] = i; + + for (i = 0; i < group_lproc.Size_of_connections(); i++) + group_lproc.GetJ()[i] = proc_lproc[group_lproc.GetJ()[i]]; + + // build groupmaster_lproc + groupmaster_lproc.SetSize(groups.Size()); + + // simplest choice of the group owner + for (i = 0; i < groups.Size(); i++) + groupmaster_lproc[i] = proc_lproc[groups.PickElementInSet(i)]; + + // load-balanced choice of the group owner, which however can lead to + // isolated dofs + // for (i = 0; i < groups.Size(); i++) + // groupmaster_lproc[i] = proc_lproc[groups.PickRandomElementInSet(i)]; + proc_lproc.DeleteAll(); + + // build group_mgroup + group_mgroup.SetSize(groups.Size()); + + int send_counter = 0; + int recv_counter = 0; + for (i = 1; i < groups.Size(); i++) + if (groupmaster_lproc[i] != 0) // we are not the master + recv_counter++; + else + send_counter += group_lproc.RowSize(i)-1; + + MPI_Request *requests = new MPI_Request[send_counter]; + MPI_Status *statuses = new MPI_Status[send_counter]; + + int max_recv_size = 0; + send_counter = 0; + for (i = 1; i < groups.Size(); i++) + { + if (groupmaster_lproc[i] == 0) // we are the master + { + group_mgroup[i] = i; + + for (j = group_lproc.GetI()[i]; + j < group_lproc.GetI()[i+1]; j++) + { + if (group_lproc.GetJ()[j] != 0) + { + MPI_Isend(group_mgroupandproc.GetRow (i), + group_mgroupandproc.RowSize (i), + MPI_INT, + lproc_proc[group_lproc.GetJ()[j]], + 822, + MyComm, + &requests[send_counter]); + send_counter++; + } + } + } + else // we are not the master + if (max_recv_size < group_lproc.RowSize(i)) + max_recv_size = group_lproc.RowSize(i); + } + max_recv_size++; + + if (recv_counter > 0) + { + int count; + MPI_Status status; + int *recv_buf = new int[max_recv_size]; + for ( ; recv_counter > 0; recv_counter--) + { + MPI_Recv(recv_buf, max_recv_size, MPI_INT, + MPI_ANY_SOURCE, 822, MyComm, &status); + + MPI_Get_count(&status, MPI_INT, &count); + + group.Recreate(count-1, recv_buf+1); + group_mgroup[i=groups.Lookup(group)] = recv_buf[0]; + + if (lproc_proc[groupmaster_lproc[i]] != status.MPI_SOURCE) + { + cerr << "\n\n\nParMesh::ParMesh: " << MyRank + << ": ERROR\n\n\n" << endl; + mfem_error(); + } + } + delete [] recv_buf; + } + + MPI_Waitall(send_counter, requests, statuses); + + delete [] statuses; + delete [] requests; + + if (mesh.GetNodes()) // curved mesh + { + Nodes = new ParGridFunction(this, mesh.GetNodes()); + own_nodes = 1; + + Array gvdofs, lvdofs; + Vector lnodes; + element_counter = 0; + for (i = 0; i < mesh.GetNE(); i++) + if (partitioning[i] == MyRank) + { + Nodes->FESpace()->GetElementVDofs(element_counter, lvdofs); + mesh.GetNodes()->FESpace()->GetElementVDofs(i, gvdofs); + mesh.GetNodes()->GetSubVector(gvdofs, lnodes); + Nodes->SetSubVector(lvdofs, lnodes); + element_counter++; + } + } + + if (partitioning_ == NULL) + delete [] partitioning; +} + +void ParMesh::GroupEdge(int group, int i, int &edge, int &o) +{ + int sedge = group_sedge.GetJ()[group_sedge.GetI()[group-1]+i]; + edge = sedge_ledge[sedge]; + int *v = shared_edges[sedge]->GetVertices(); + o = (v[0] < v[1]) ? (+1) : (-1); +} + +void ParMesh::GroupFace(int group, int i, int &face, int &o) +{ + int sface = group_sface.GetJ()[group_sface.GetI()[group-1]+i]; + face = sface_lface[sface]; + // face gives the base orientation + if (faces[face]->GetType() == Element::TRIANGLE) + o = GetTriOrientation(faces[face]->GetVertices(), + shared_faces[sface]->GetVertices()); + if (faces[face]->GetType() == Element::QUADRILATERAL) + o = GetQuadOrientation(faces[face]->GetVertices(), + shared_faces[sface]->GetVertices()); +} + + +// For a line segment with vertices v[0] and v[1], return a number with +// the following meaning: +// 0 - the edge was not refined +// 1 - the edge e was refined once by splitting v[0],v[1] +int ParMesh::GetEdgeSplittings(Element *edge, const DSTable &v_to_v, + int *middle) +{ + int m, *v = edge->GetVertices(); + + if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1) + return 1; + else + return 0; +} + +// For a triangular face with (correctly ordered) vertices v[0], v[1], v[2] +// return a number with the following meaning: +// 0 - the face was not refined +// 1 - the face was refined once by splitting v[0],v[1] +// 2 - the face was refined twice by splitting v[0],v[1] and then v[1],v[2] +// 3 - the face was refined twice by splitting v[0],v[1] and then v[0],v[2] +// 4 - the face was refined three times (as in 2+3) +int ParMesh::GetFaceSplittings(Element *face, const DSTable &v_to_v, + int *middle) +{ + int m, right = 0; + int number_of_splittings = 0; + int *v = face->GetVertices(); + + if ((m = v_to_v(v[0], v[1])) != -1 && middle[m] != -1) + { + number_of_splittings++; + if ((m = v_to_v(v[1], v[2])) != -1 && middle[m] != -1) + { + right = 1; + number_of_splittings++; + } + if ((m = v_to_v(v[2], v[0])) != -1 && middle[m] != -1) + number_of_splittings++; + + switch (number_of_splittings) + { + case 2: + if (right == 0) + number_of_splittings++; + break; + case 3: + number_of_splittings++; + break; + } + } + + return number_of_splittings; +} + +void ParMesh::LocalRefinement(const Array &marked_el, int type) +{ + int i, j, wtls = WantTwoLevelState; + + if (Nodes) // curved mesh + { + UseTwoLevelState(1); + } + + SetState(Mesh::NORMAL); + DeleteCoarseTables(); + + if (Dim == 3) + { + if (WantTwoLevelState) + { + c_NumOfVertices = NumOfVertices; + c_NumOfEdges = NumOfEdges; + c_NumOfFaces = NumOfFaces; + c_NumOfElements = NumOfElements; + c_NumOfBdrElements = NumOfBdrElements; + } + + int uniform_refinement = 0; + if (type < 0) + { + type = -type; + uniform_refinement = 1; + } + + // 1. Get table of vertex to vertex connections. + DSTable v_to_v(NumOfVertices); + GetVertexToVertexTable(v_to_v); + + // 2. Get edge to element connections in arrays edge1 and edge2 + Array middle(v_to_v.NumberOfEntries()); + middle = -1; + + // 3. Do the red refinement. + switch (type) + { + case 1: + for (i = 0; i < marked_el.Size(); i++) + Bisection(marked_el[i], v_to_v, NULL, NULL, middle); + break; + case 2: + for (i = 0; i < marked_el.Size(); i++) + { + Bisection(marked_el[i], v_to_v, NULL, NULL, middle); + + Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle); + Bisection(marked_el[i], v_to_v, NULL, NULL, middle); + } + break; + case 3: + for (i = 0; i < marked_el.Size(); i++) + { + Bisection(marked_el[i], v_to_v, NULL, NULL, middle); + + j = NumOfElements - 1; + Bisection(j, v_to_v, NULL, NULL, middle); + Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle); + Bisection(j, v_to_v, NULL, NULL, middle); + + Bisection(marked_el[i], v_to_v, NULL, NULL, middle); + Bisection(NumOfElements-1, v_to_v, NULL, NULL, middle); + Bisection(marked_el[i], v_to_v, NULL, NULL, middle); + } + break; + } + + if (WantTwoLevelState) + { + RefinedElement::State = RefinedElement::FINE; + State = Mesh::TWO_LEVEL_FINE; + } + + // 4. Do the green refinement (to get conforming mesh). + int need_refinement; + int refined_edge[5][3] = {{0, 0, 0}, + {1, 0, 0}, + {1, 1, 0}, + {1, 0, 1}, + {1, 1, 1}}; + int faces_in_group, max_faces_in_group = 0; + // face_splittings identify how the shared faces have been split + int **face_splittings = new int*[GetNGroups()-1]; + for (i = 0; i < GetNGroups()-1; i++) + { + faces_in_group = GroupNFaces(i+1); + face_splittings[i] = new int[faces_in_group]; + if (faces_in_group > max_faces_in_group) + max_faces_in_group = faces_in_group; + } + int neighbor, *iBuf = new int[max_faces_in_group]; + + Array group_faces; + Vertex V; + + MPI_Request request; + MPI_Status status; + +#ifdef MFEM_DEBUG + int ref_loops_all = 0, ref_loops_par = 0; +#endif + do + { + need_refinement = 0; + for (i = 0; i < NumOfElements; i++) + { + if (elements[i]->NeedRefinement(v_to_v, middle)) + { + need_refinement = 1; + Bisection(i, v_to_v, NULL, NULL, middle); + } + } +#ifdef MFEM_DEBUG + ref_loops_all++; +#endif + + if (uniform_refinement) + continue; + + // if the mesh is locally conforming start making it globally + // conforming + if (need_refinement == 0) + { +#ifdef MFEM_DEBUG + ref_loops_par++; +#endif + // MPI_Barrier(MyComm); + + // (a) send the type of interface splitting + for (i = 0; i < GetNGroups()-1; i++) + { + group_sface.GetRow(i, group_faces); + faces_in_group = group_faces.Size(); + // it is enough to communicate through the faces + if (faces_in_group != 0) + { + for (j = 0; j < faces_in_group; j++) + face_splittings[i][j] = + GetFaceSplittings(shared_faces[group_faces[j]], v_to_v, + middle); + j = group_lproc.GetI()[i+1]; + if (group_lproc.GetJ()[j] == 0) + neighbor = lproc_proc[group_lproc.GetJ()[j+1]]; + else + neighbor = lproc_proc[group_lproc.GetJ()[j]]; + MPI_Isend(face_splittings[i], faces_in_group, MPI_INT, + neighbor, 0, MyComm, &request); + } + } + + // (b) receive the type of interface splitting + for (i = 0; i < GetNGroups()-1; i++) + { + group_sface.GetRow(i, group_faces); + faces_in_group = group_faces.Size(); + if (faces_in_group != 0) + { + j = group_lproc.GetI()[i+1]; + if (group_lproc.GetJ()[j] == 0) + neighbor = lproc_proc[group_lproc.GetJ()[j+1]]; + else + neighbor = lproc_proc[group_lproc.GetJ()[j]]; + MPI_Recv(iBuf, faces_in_group, MPI_INT, neighbor, + MPI_ANY_TAG, MyComm, &status); + + for (j = 0; j < faces_in_group; j++) + if (iBuf[j] != face_splittings[i][j]) + { + int *v = shared_faces[group_faces[j]]->GetVertices(); + for (int k = 0; k < 3; k++) + if (refined_edge[iBuf[j]][k] == 1 && + refined_edge[face_splittings[i][j]][k] == 0) + { + int ii = v_to_v(v[k], v[(k+1)%3]); + if (middle[ii] == -1) + { + need_refinement = 1; + middle[ii] = NumOfVertices++; + for (int c = 0; c < 3; c++) + V(c) = 0.5 * (vertices[v[k]](c) + + vertices[v[(k+1)%3]](c)); + vertices.Append(V); + } + } + } + } + } + + i = need_refinement; + MPI_Allreduce(&i, &need_refinement, 1, MPI_INT, MPI_LOR, MyComm); + } + } + while (need_refinement == 1); + +#ifdef MFEM_DEBUG + i = ref_loops_all; + MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0, MyComm); + if (MyRank == 0) + { + cout << "\n\nParMesh::LocalRefinement : max. ref_loops_all = " + << ref_loops_all << ", ref_loops_par = " << ref_loops_par + << '\n' << endl; + } +#endif + + delete [] iBuf; + for (i = 0; i < GetNGroups()-1; i++) + delete [] face_splittings[i]; + delete [] face_splittings; + + + // 5. Update the boundary elements. + do + { + need_refinement = 0; + for (i = 0; i < NumOfBdrElements; i++) + if (boundary[i]->NeedRefinement(v_to_v, middle)) + { + need_refinement = 1; + Bisection(i, v_to_v, middle); + } + } + while (need_refinement == 1); + + if (NumOfBdrElements != boundary.Size()) + mfem_error("ParMesh::LocalRefinement :" + " (NumOfBdrElements != boundary.Size())"); + + // 5a. Update the groups after refinement. + if (el_to_face != NULL) + { + if (WantTwoLevelState) + { + c_el_to_face = el_to_face; + el_to_face = NULL; + Swap(faces_info, fc_faces_info); + } + RefineGroups(v_to_v, middle); + // GetElementToFaceTable(); // Called by RefineGroups + GenerateFaces(); + if (WantTwoLevelState) + { + f_el_to_face = el_to_face; + } + } + + // 6. Un-mark the Pf elements. + int refinement_edges[2], type, flag; + for (i = 0; i < NumOfElements; i++) + { + Element *El = elements[i]; + while (El->GetType() == Element::BISECTED) + El = ((BisectedElement *) El)->FirstChild; + ((Tetrahedron *) El)->ParseRefinementFlag(refinement_edges, + type, flag); + if (type == Tetrahedron::TYPE_PF) + ((Tetrahedron *) El)->CreateRefinementFlag(refinement_edges, + Tetrahedron::TYPE_PU, + flag); + } + + // 7. Free the allocated memory. + middle.DeleteAll(); + +#ifdef MFEM_DEBUG + CheckElementOrientation(); +#endif + + if (el_to_edge != NULL) + { + if (WantTwoLevelState) + { + c_el_to_edge = el_to_edge; + f_el_to_edge = new Table; + c_bel_to_edge = bel_to_edge; + bel_to_edge = NULL; + NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); + el_to_edge = f_el_to_edge; + f_bel_to_edge = bel_to_edge; + } + else + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); + } + + if (WantTwoLevelState) + { + f_NumOfVertices = NumOfVertices; + f_NumOfEdges = NumOfEdges; + f_NumOfFaces = NumOfFaces; + f_NumOfElements = NumOfElements; + f_NumOfBdrElements = NumOfBdrElements; + } + } // 'if (Dim == 3)' + + + if (Dim == 2) + { + if (WantTwoLevelState) + { + c_NumOfVertices = NumOfVertices; + c_NumOfEdges = NumOfEdges; + c_NumOfElements = NumOfElements; + c_NumOfBdrElements = NumOfBdrElements; + } + + int uniform_refinement = 0; + if (type < 0) + { + type = -type; + uniform_refinement = 1; + } + + // 1. Get table of vertex to vertex connections. + DSTable v_to_v(NumOfVertices); + GetVertexToVertexTable(v_to_v); + + // 2. Get edge to element connections in arrays edge1 and edge2 + int nedges = v_to_v.NumberOfEntries(); + int *edge1 = new int[nedges]; + int *edge2 = new int[nedges]; + int *middle = new int[nedges]; + + for (i = 0; i < nedges; i++) + edge1[i] = edge2[i] = middle[i] = -1; + + for (i = 0; i < NumOfElements; i++) + { + int *v = elements[i]->GetVertices(); + for (j = 0; j < 3; j++) + { + int ind = v_to_v(v[j], v[(j+1)%3]); + (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i); + } + } + + // 3. Do the red refinement. + for (i = 0; i < marked_el.Size(); i++) + RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle); + + if (WantTwoLevelState) + { + RefinedElement::State = RefinedElement::FINE; + State = Mesh::TWO_LEVEL_FINE; + } + + // 4. Do the green refinement (to get conforming mesh). + int need_refinement; + int edges_in_group, max_edges_in_group = 0; + // edge_splittings identify how the shared edges have been split + int **edge_splittings = new int*[GetNGroups()-1]; + for (i = 0; i < GetNGroups()-1; i++) + { + edges_in_group = GroupNEdges(i+1); + edge_splittings[i] = new int[edges_in_group]; + if (edges_in_group > max_edges_in_group) + max_edges_in_group = edges_in_group; + } + int neighbor, *iBuf = new int[max_edges_in_group]; + + Array group_edges; + + MPI_Request request; + MPI_Status status; + Vertex V; + V(2) = 0.0; + +#ifdef MFEM_DEBUG + int ref_loops_all = 0, ref_loops_par = 0; +#endif + do + { + need_refinement = 0; + for (i = 0; i < nedges; i++) + if (middle[i] != -1 && edge1[i] != -1) + { + need_refinement = 1; + GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle); + } +#ifdef MFEM_DEBUG + ref_loops_all++; +#endif + + if (uniform_refinement) + continue; + + // if the mesh is locally conforming start making it globally + // conforming + if (need_refinement == 0) + { +#ifdef MFEM_DEBUG + ref_loops_par++; +#endif + // MPI_Barrier(MyComm); + + // (a) send the type of interface splitting + for (i = 0; i < GetNGroups()-1; i++) + { + group_sedge.GetRow(i, group_edges); + edges_in_group = group_edges.Size(); + // it is enough to communicate through the edges + if (edges_in_group != 0) + { + for (j = 0; j < edges_in_group; j++) + edge_splittings[i][j] = + GetEdgeSplittings(shared_edges[group_edges[j]], v_to_v, + middle); + j = group_lproc.GetI()[i+1]; + if (group_lproc.GetJ()[j] == 0) + neighbor = lproc_proc[group_lproc.GetJ()[j+1]]; + else + neighbor = lproc_proc[group_lproc.GetJ()[j]]; + MPI_Isend(edge_splittings[i], edges_in_group, MPI_INT, + neighbor, 0, MyComm, &request); + } + } + + // (b) receive the type of interface splitting + for (i = 0; i < GetNGroups()-1; i++) + { + group_sedge.GetRow(i, group_edges); + edges_in_group = group_edges.Size(); + if (edges_in_group != 0) + { + j = group_lproc.GetI()[i+1]; + if (group_lproc.GetJ()[j] == 0) + neighbor = lproc_proc[group_lproc.GetJ()[j+1]]; + else + neighbor = lproc_proc[group_lproc.GetJ()[j]]; + MPI_Recv(iBuf, edges_in_group, MPI_INT, neighbor, + MPI_ANY_TAG, MyComm, &status); + + for (j = 0; j < edges_in_group; j++) + if (iBuf[j] == 1 && edge_splittings[i][j] == 0) + { + int *v = shared_edges[group_edges[j]]->GetVertices(); + int ii = v_to_v(v[0], v[1]); +#ifdef MFEM_DEBUG + if (middle[ii] != -1) + mfem_error("ParMesh::LocalRefinement (triangles) : " + "Oops!"); +#endif + need_refinement = 1; + middle[ii] = NumOfVertices++; + for (int c = 0; c < 2; c++) + V(c) = 0.5 * (vertices[v[0]](c) + vertices[v[1]](c)); + vertices.Append(V); + } + } + } + + i = need_refinement; + MPI_Allreduce(&i, &need_refinement, 1, MPI_INT, MPI_LOR, MyComm); + } + } + while (need_refinement == 1); + +#ifdef MFEM_DEBUG + i = ref_loops_all; + MPI_Reduce(&i, &ref_loops_all, 1, MPI_INT, MPI_MAX, 0, MyComm); + if (MyRank == 0) + { + cout << "\n\nParMesh::LocalRefinement : max. ref_loops_all = " + << ref_loops_all << ", ref_loops_par = " << ref_loops_par + << '\n' << endl; + } +#endif + + for (i = 0; i < GetNGroups()-1; i++) + delete [] edge_splittings[i]; + delete [] edge_splittings; + + delete [] iBuf; + + // 5. Update the boundary elements. + int v1[2], v2[2], bisect, temp; + temp = NumOfBdrElements; + for (i = 0; i < temp; i++) + { + int *v = boundary[i]->GetVertices(); + bisect = v_to_v(v[0], v[1]); + if (middle[bisect] != -1) + { // the element was refined (needs updating) + if (boundary[i]->GetType() == Element::SEGMENT) + { + v1[0] = v[0]; v1[1] = middle[bisect]; + v2[0] = middle[bisect]; v2[1] = v[1]; + + if (WantTwoLevelState) + { + boundary.Append(new Segment(v2, boundary[i]->GetAttribute())); +#ifdef MFEM_USE_MEMALLOC + BisectedElement *aux = BEMemory.Alloc(); + aux->SetCoarseElem(boundary[i]); +#else + BisectedElement *aux = new BisectedElement(boundary[i]); +#endif + aux->FirstChild = + new Segment(v1, boundary[i]->GetAttribute()); + aux->SecondChild = NumOfBdrElements; + boundary[i] = aux; + NumOfBdrElements++; + } + else + { + boundary[i]->SetVertices(v1); + boundary.Append(new Segment(v2, boundary[i]->GetAttribute())); + } + } + else + mfem_error("Only bisection of segment is implemented for bdr" + " elem."); + } + } + NumOfBdrElements = boundary.Size(); + + // 5a. Update the groups after refinement. + RefineGroups(v_to_v, middle); + + // 6. Free the allocated memory. + delete [] edge1; + delete [] edge2; + delete [] middle; + +#ifdef MFEM_DEBUG + CheckElementOrientation(); +#endif + + if (WantTwoLevelState) + { + f_NumOfVertices = NumOfVertices; + f_NumOfElements = NumOfElements; + f_NumOfBdrElements = NumOfBdrElements; + RefinedElement::State = RefinedElement::FINE; + State = Mesh::TWO_LEVEL_FINE; + } + + if (el_to_edge != NULL) + { + if (WantTwoLevelState) + { + c_el_to_edge = el_to_edge; + Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge + f_el_to_edge = new Table; + NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); + el_to_edge = f_el_to_edge; + f_NumOfEdges = NumOfEdges; + } + else + NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); + GenerateFaces(); + } + } // 'if (Dim == 2)' + + if (Nodes) // curved mesh + { + UpdateNodes(); + UseTwoLevelState(wtls); + } +} + +void ParMesh::RefineGroups(const DSTable &v_to_v, int *middle) +{ + int i, attr, newv[3], ind, f_ind, *v; + + int group; + Array group_verts, group_edges, group_faces; + + // To update the groups after a refinement, we observe that: + // - every (new and old) vertex, edge and face belongs to exactly one group + // - the refinement does not create new groups + // - a new vertex appears only as the middle of a refined edge + // - a face can be refined 2, 3 or 4 times producing new edges and faces + + int *I_group_svert, *J_group_svert; + int *I_group_sedge, *J_group_sedge; + int *I_group_sface, *J_group_sface; + + I_group_svert = new int[GetNGroups()+1]; + I_group_sedge = new int[GetNGroups()+1]; + if (Dim == 3) + I_group_sface = new int[GetNGroups()+1]; + + I_group_svert[0] = I_group_svert[1] = 0; + I_group_sedge[0] = I_group_sedge[1] = 0; + if (Dim == 3) + I_group_sface[0] = I_group_sface[1] = 0; + + // overestimate the size of the J arrays + if (Dim == 3) + { + J_group_svert = new int[group_svert.Size_of_connections() + + group_sedge.Size_of_connections()]; + J_group_sedge = new int[2*group_sedge.Size_of_connections() + + 3*group_sface.Size_of_connections()]; + J_group_sface = new int[4*group_sface.Size_of_connections()]; + } + else if (Dim == 2) + { + J_group_svert = new int[group_svert.Size_of_connections() + + group_sedge.Size_of_connections()]; + J_group_sedge = new int[2*group_sedge.Size_of_connections()]; + } + + for (group = 0; group < GetNGroups()-1; group++) + { + // Get the group shared objects + group_svert.GetRow(group, group_verts); + group_sedge.GetRow(group, group_edges); + group_sface.GetRow(group, group_faces); + + // Check which edges have been refined + for (i = 0; i < group_sedge.RowSize(group); i++) + { + v = shared_edges[group_edges[i]]->GetVertices(); + ind = middle[v_to_v(v[0], v[1])]; + if (ind != -1) + { + // add a vertex + group_verts.Append(svert_lvert.Append(ind)-1); + // update the edges + attr = shared_edges[group_edges[i]]->GetAttribute(); + shared_edges.Append(new Segment(v[1], ind, attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + v[1] = ind; + } + } + + // Check which faces have been refined + for (i = 0; i < group_sface.RowSize(group); i++) + { + v = shared_faces[group_faces[i]]->GetVertices(); + ind = middle[v_to_v(v[0], v[1])]; + if (ind != -1) + { + attr = shared_faces[group_faces[i]]->GetAttribute(); + // add the refinement edge + shared_edges.Append(new Segment(v[2], ind, attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + // add a face + f_ind = group_faces.Size(); + shared_faces.Append(new Triangle(v[1], v[2], ind, attr)); + group_faces.Append(sface_lface.Append(-1)-1); + newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind; + shared_faces[group_faces[i]]->SetVertices(newv); + + // check if the left face has also been refined + // v = shared_faces[group_faces[i]]->GetVertices(); + ind = middle[v_to_v(v[0], v[1])]; + if (ind != -1) + { + // add the refinement edge + shared_edges.Append(new Segment(v[2], ind, attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + // add a face + shared_faces.Append(new Triangle(v[1], v[2], ind, attr)); + group_faces.Append(sface_lface.Append(-1)-1); + newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind; + shared_faces[group_faces[i]]->SetVertices(newv); + } + + // check if the right face has also been refined + v = shared_faces[group_faces[f_ind]]->GetVertices(); + ind = middle[v_to_v(v[0], v[1])]; + if (ind != -1) + { + // add the refinement edge + shared_edges.Append(new Segment(v[2], ind, attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + // add a face + shared_faces.Append(new Triangle(v[1], v[2], ind, attr)); + group_faces.Append(sface_lface.Append(-1)-1); + newv[0] = v[2]; newv[1] = v[0]; newv[2] = ind; + shared_faces[group_faces[f_ind]]->SetVertices(newv); + } + } + } + + I_group_svert[group+1] = I_group_svert[group] + group_verts.Size(); + I_group_sedge[group+1] = I_group_sedge[group] + group_edges.Size(); + if (Dim == 3) + I_group_sface[group+1] = I_group_sface[group] + group_faces.Size(); + + int *J; + J = J_group_svert+I_group_svert[group]; + for (i = 0; i < group_verts.Size(); i++) + J[i] = group_verts[i]; + J = J_group_sedge+I_group_sedge[group]; + for (i = 0; i < group_edges.Size(); i++) + J[i] = group_edges[i]; + if (Dim == 3) + { + J = J_group_sface+I_group_sface[group]; + for (i = 0; i < group_faces.Size(); i++) + J[i] = group_faces[i]; + } + } + + // Fix the local numbers of shared edges and faces + { + DSTable new_v_to_v(NumOfVertices); + GetVertexToVertexTable(new_v_to_v); + for (i = 0; i < shared_edges.Size(); i++) + { + v = shared_edges[i]->GetVertices(); + sedge_ledge[i] = new_v_to_v(v[0], v[1]); + } + } + if (Dim == 3) + { + STable3D *faces_tbl = GetElementToFaceTable(1); + for (i = 0; i < shared_faces.Size(); i++) + { + v = shared_faces[i]->GetVertices(); + sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2]); + } + delete faces_tbl; + } + + group_svert.SetIJ(I_group_svert, J_group_svert); + group_sedge.SetIJ(I_group_sedge, J_group_sedge); + if (Dim == 3) + group_sface.SetIJ(I_group_sface, J_group_sface); +} + +void ParMesh::QuadUniformRefinement() +{ + int oedge = NumOfVertices, wtls = WantTwoLevelState; + + if (Nodes) // curved mesh + UseTwoLevelState(1); + + // call Mesh::QuadUniformRefinement so that it won't update the nodes + { + GridFunction *nodes = Nodes; + Nodes = NULL; + Mesh::QuadUniformRefinement(); + Nodes = nodes; + } + + // update the groups + { + int i, attr, ind, *v; + + int group; + Array sverts, sedges; + + int *I_group_svert, *J_group_svert; + int *I_group_sedge, *J_group_sedge; + + I_group_svert = new int[GetNGroups()+1]; + I_group_sedge = new int[GetNGroups()+1]; + + I_group_svert[0] = I_group_svert[1] = 0; + I_group_sedge[0] = I_group_sedge[1] = 0; + + // compute the size of the J arrays + J_group_svert = new int[group_svert.Size_of_connections() + + group_sedge.Size_of_connections()]; + J_group_sedge = new int[2*group_sedge.Size_of_connections()]; + + for (group = 0; group < GetNGroups()-1; group++) + { + // Get the group shared objects + group_svert.GetRow(group, sverts); + group_sedge.GetRow(group, sedges); + + // Process all the edges + for (i = 0; i < group_sedge.RowSize(group); i++) + { + v = shared_edges[sedges[i]]->GetVertices(); + ind = oedge + sedge_ledge[sedges[i]]; + // add a vertex + sverts.Append(svert_lvert.Append(ind)-1); + // update the edges + attr = shared_edges[sedges[i]]->GetAttribute(); + shared_edges.Append(new Segment(v[1], ind, attr)); + sedges.Append(sedge_ledge.Append(-1)-1); + v[1] = ind; + } + + I_group_svert[group+1] = I_group_svert[group] + sverts.Size(); + I_group_sedge[group+1] = I_group_sedge[group] + sedges.Size(); + + int *J; + J = J_group_svert+I_group_svert[group]; + for (i = 0; i < sverts.Size(); i++) + J[i] = sverts[i]; + J = J_group_sedge+I_group_sedge[group]; + for (i = 0; i < sedges.Size(); i++) + J[i] = sedges[i]; + } + + // Fix the local numbers of shared edges + DSTable v_to_v(NumOfVertices); + GetVertexToVertexTable(v_to_v); + for (i = 0; i < shared_edges.Size(); i++) + { + v = shared_edges[i]->GetVertices(); + sedge_ledge[i] = v_to_v(v[0], v[1]); + } + + group_svert.SetIJ(I_group_svert, J_group_svert); + group_sedge.SetIJ(I_group_sedge, J_group_sedge); + } + + if (Nodes) // curved mesh + { + UpdateNodes(); + UseTwoLevelState(wtls); + } +} + +void ParMesh::HexUniformRefinement() +{ + int wtls = WantTwoLevelState; + int oedge = NumOfVertices; + int oface = oedge + NumOfEdges; + + DSTable v_to_v(NumOfVertices); + GetVertexToVertexTable(v_to_v); + STable3D *faces_tbl = GetElementToFaceTable(1); + + if (Nodes) // curved mesh + UseTwoLevelState(1); + + // call Mesh::HexUniformRefinement so that it won't update the nodes + { + GridFunction *nodes = Nodes; + Nodes = NULL; + Mesh::HexUniformRefinement(); + Nodes = nodes; + } + + // update the groups + { + int i, attr, newv[4], ind, m[5]; + Array v; + + int group; + Array group_verts, group_edges, group_faces; + + int *I_group_svert, *J_group_svert; + int *I_group_sedge, *J_group_sedge; + int *I_group_sface, *J_group_sface; + + I_group_svert = new int[GetNGroups()+1]; + I_group_sedge = new int[GetNGroups()+1]; + I_group_sface = new int[GetNGroups()+1]; + + I_group_svert[0] = I_group_svert[1] = 0; + I_group_sedge[0] = I_group_sedge[1] = 0; + I_group_sface[0] = I_group_sface[1] = 0; + + // compute the size of the J arrays + J_group_svert = new int[group_svert.Size_of_connections() + + group_sedge.Size_of_connections() + + group_sface.Size_of_connections()]; + J_group_sedge = new int[2*group_sedge.Size_of_connections() + + 4*group_sface.Size_of_connections()]; + J_group_sface = new int[4*group_sface.Size_of_connections()]; + + for (group = 0; group < GetNGroups()-1; group++) + { + // Get the group shared objects + group_svert.GetRow(group, group_verts); + group_sedge.GetRow(group, group_edges); + group_sface.GetRow(group, group_faces); + + // Process the edges that have been refined + for (i = 0; i < group_sedge.RowSize(group); i++) + { + shared_edges[group_edges[i]]->GetVertices(v); + ind = oedge + v_to_v(v[0], v[1]); + // add a vertex + group_verts.Append(svert_lvert.Append(ind)-1); + // update the edges + attr = shared_edges[group_edges[i]]->GetAttribute(); + shared_edges.Append(new Segment(v[1], ind, attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + newv[0] = v[0]; newv[1] = ind; + shared_edges[group_edges[i]]->SetVertices(newv); + } + + // Process the faces that have been refined + for (i = 0; i < group_sface.RowSize(group); i++) + { + shared_faces[group_faces[i]]->GetVertices(v); + m[0] = oface+(*faces_tbl)(v[0], v[1], v[2], v[3]); + // add a vertex + group_verts.Append(svert_lvert.Append(m[0])-1); + // add the refinement edges + attr = shared_faces[group_faces[i]]->GetAttribute(); + m[1] = oedge + v_to_v(v[0], v[1]); + m[2] = oedge + v_to_v(v[1], v[2]); + m[3] = oedge + v_to_v(v[2], v[3]); + m[4] = oedge + v_to_v(v[3], v[0]); + shared_edges.Append(new Segment(m[1], m[0], attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + shared_edges.Append(new Segment(m[2], m[0], attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + shared_edges.Append(new Segment(m[3], m[0], attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + shared_edges.Append(new Segment(m[4], m[0], attr)); + group_edges.Append(sedge_ledge.Append(-1)-1); + // update faces + newv[0] = v[0]; newv[1] = m[1]; newv[2] = m[0]; newv[3] = m[4]; + shared_faces[group_faces[i]]->SetVertices(newv); + shared_faces.Append(new Quadrilateral(m[1],v[1],m[2],m[0],attr)); + group_faces.Append(sface_lface.Append(-1)-1); + shared_faces.Append(new Quadrilateral(m[0],m[2],v[2],m[3],attr)); + group_faces.Append(sface_lface.Append(-1)-1); + shared_faces.Append(new Quadrilateral(m[4],m[0],m[3],v[3],attr)); + group_faces.Append(sface_lface.Append(-1)-1); + } + + I_group_svert[group+1] = I_group_svert[group] + group_verts.Size(); + I_group_sedge[group+1] = I_group_sedge[group] + group_edges.Size(); + I_group_sface[group+1] = I_group_sface[group] + group_faces.Size(); + + int *J; + J = J_group_svert+I_group_svert[group]; + for (i = 0; i < group_verts.Size(); i++) + J[i] = group_verts[i]; + J = J_group_sedge+I_group_sedge[group]; + for (i = 0; i < group_edges.Size(); i++) + J[i] = group_edges[i]; + J = J_group_sface+I_group_sface[group]; + for (i = 0; i < group_faces.Size(); i++) + J[i] = group_faces[i]; + } + + // Fix the local numbers of shared edges and faces + DSTable new_v_to_v(NumOfVertices); + GetVertexToVertexTable(new_v_to_v); + for (i = 0; i < shared_edges.Size(); i++) + { + shared_edges[i]->GetVertices(v); + sedge_ledge[i] = new_v_to_v(v[0], v[1]); + } + + delete faces_tbl; + faces_tbl = GetElementToFaceTable(1); + for (i = 0; i < shared_faces.Size(); i++) + { + shared_faces[i]->GetVertices(v); + sface_lface[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]); + } + delete faces_tbl; + + group_svert.SetIJ(I_group_svert, J_group_svert); + group_sedge.SetIJ(I_group_sedge, J_group_sedge); + group_sface.SetIJ(I_group_sface, J_group_sface); + } + + if (Nodes) // curved mesh + { + UpdateNodes(); + UseTwoLevelState(wtls); + } +} + +void ParMesh::Print(ostream &out) const +{ + if (Dim == 3 && meshgen == 1) + { + int i, j, nv; + const int *ind; + + out << "NETGEN_Neutral_Format\n"; + // print the vertices + out << NumOfVertices << '\n'; + for (i = 0; i < NumOfVertices; i++) + { + for (j = 0; j < Dim; j++) + out << " " << vertices[i](j); + out << '\n'; + } + + // print the elements + out << NumOfElements << '\n'; + for (i = 0; i < NumOfElements; i++) + { + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); + out << elements[i]->GetAttribute(); + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + + // print the boundary + shared faces information + out << NumOfBdrElements + shared_faces.Size() << '\n'; + // boundary + for (i = 0; i < NumOfBdrElements; i++) + { + nv = boundary[i]->GetNVertices(); + ind = boundary[i]->GetVertices(); + out << boundary[i]->GetAttribute(); + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + // shared faces + for (i = 0; i < shared_faces.Size(); i++) + { + nv = shared_faces[i]->GetNVertices(); + ind = shared_faces[i]->GetVertices(); + out << shared_faces[i]->GetAttribute(); + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + } + + if (Dim == 3 && meshgen == 2) + { + int i, j, nv; + const int *ind; + + out << "TrueGrid\n" + << "1 " << NumOfVertices << " " << NumOfElements << " 0 0 0 0 0 0 0\n" + << "0 0 0 1 0 0 0 0 0 0 0\n" + << "0 0 " << NumOfBdrElements+shared_faces.Size() + << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n" + << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; + + // print the vertices + for (i = 0; i < NumOfVertices; i++) + out << i+1 << " 0.0 " << vertices[i](0) << " " << vertices[i](1) + << " " << vertices[i](2) << " 0.0\n"; + + // print the elements + for (i = 0; i < NumOfElements; i++) + { + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); + out << i+1 << " " << elements[i]->GetAttribute(); + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + + // print the boundary information + for (i = 0; i < NumOfBdrElements; i++) + { + nv = boundary[i]->GetNVertices(); + ind = boundary[i]->GetVertices(); + out << boundary[i]->GetAttribute(); + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << " 1.0 1.0 1.0 1.0\n"; + } + + // print the shared faces information + for (i = 0; i < shared_faces.Size(); i++) + { + nv = shared_faces[i]->GetNVertices(); + ind = shared_faces[i]->GetVertices(); + out << shared_faces[i]->GetAttribute(); + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << " 1.0 1.0 1.0 1.0\n"; + } + } + + if (Dim == 2) + { + int i, j, attr; + Array v; + + out << "areamesh2\n\n"; + + // print the boundary + shared edges information + out << NumOfBdrElements + shared_edges.Size() << '\n'; + // boundary + for (i = 0; i < NumOfBdrElements; i++) + { + attr = boundary[i]->GetAttribute(); + boundary[i]->GetVertices(v); + out << attr << " "; + for (j = 0; j < v.Size(); j++) + out << v[j] + 1 << " "; + out << '\n'; + } + // shared edges + for (i = 0; i < shared_edges.Size(); i++) + { + attr = shared_edges[i]->GetAttribute(); + shared_edges[i]->GetVertices(v); + out << attr << " "; + for (j = 0; j < v.Size(); j++) + out << v[j] + 1 << " "; + out << '\n'; + } + + // print the elements + out << NumOfElements << '\n'; + for (i = 0; i < NumOfElements; i++) + { + attr = elements[i]->GetAttribute(); + elements[i]->GetVertices(v); + + out << attr << " "; + if ((j = GetElementType(i)) == Element::TRIANGLE) + out << 3 << " "; + else + if (j == Element::QUADRILATERAL) + out << 4 << " "; + else + if (j == Element::SEGMENT) + out << 2 << " "; + for (j = 0; j < v.Size(); j++) + out << v[j] + 1 << " "; + out << '\n'; + } + + // print the vertices + out << NumOfVertices << '\n'; + for (i = 0; i < NumOfVertices; i++) + { + for (j = 0; j < Dim; j++) + out << vertices[i](j) << " "; + out << '\n'; + } + } +} + +void ParMesh::PrintAsOne(ostream &out) +{ + int i, j, k, p, nv_ne[2], &nv = nv_ne[0], &ne = nv_ne[1], vc; + const int *v; + MPI_Status status; + Array vert; + Array ints; + + if (MyRank == 0) + { + out << "MFEM mesh v1.0\n"; + + // optional + out << + "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n" + "# POINT = 0\n" + "# SEGMENT = 1\n" + "# TRIANGLE = 2\n" + "# SQUARE = 3\n" + "# TETRAHEDRON = 4\n" + "# CUBE = 5\n" + "#\n"; + + out << "\ndimension\n" << Dim; + } + + nv = NumOfElements; + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + if (MyRank == 0) + { + out << "\n\nelements\n" << ne << '\n'; + for (i = 0; i < NumOfElements; i++) + { + // processor number + 1 as attribute and geometry type + out << 1 << ' ' << elements[i]->GetGeometryType(); + // vertices + nv = elements[i]->GetNVertices(); + v = elements[i]->GetVertices(); + for (j = 0; j < nv; j++) + out << ' ' << v[j]; + out << '\n'; + } + vc = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(nv_ne, 2, MPI_INT, p, 444, MyComm, &status); + ints.SetSize(ne); + MPI_Recv(&ints[0], ne, MPI_INT, p, 445, MyComm, &status); + for (i = 0; i < ne; ) + { + // processor number + 1 as attribute and geometry type + out << p+1 << ' ' << ints[i]; + // vertices + k = Geometries.GetVertices(ints[i++])->GetNPoints(); + for (j = 0; j < k; j++) + out << ' ' << vc + ints[i++]; + out << '\n'; + } + vc += nv; + } + } + else + { + // for each element send its geometry type and its vertices + ne = 0; + for (i = 0; i < NumOfElements; i++) + ne += 1 + elements[i]->GetNVertices(); + nv = NumOfVertices; + MPI_Send(nv_ne, 2, MPI_INT, 0, 444, MyComm); + ints.SetSize(ne); + for (i = j = 0; i < NumOfElements; i++) + { + ints[j++] = elements[i]->GetGeometryType(); + nv = elements[i]->GetNVertices(); + v = elements[i]->GetVertices(); + for (k = 0; k < nv; k++) + ints[j++] = v[k]; + } + MPI_Send(&ints[0], ne, MPI_INT, 0, 445, MyComm); + } + + // boundary + shared boundary + Array &shared_boundary = + (Dim == 2) ? shared_edges : shared_faces; + nv = NumOfBdrElements + shared_boundary.Size(); + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + if (MyRank == 0) + { + out << "\nboundary\n" << ne << '\n'; + // actual boundary + for (i = 0; i < NumOfBdrElements; i++) + { + // processor number + 1 as bdr. attr. and bdr. geometry type + out << 1 << ' ' << boundary[i]->GetGeometryType(); + // vertices + nv = boundary[i]->GetNVertices(); + v = boundary[i]->GetVertices(); + for (j = 0; j < nv; j++) + out << ' ' << v[j]; + out << '\n'; + } + // shared boundary (interface) + for (i = 0; i < shared_boundary.Size(); i++) + { + // processor number + 1 as bdr. attr. and bdr. geometry type + out << 1 << ' ' << shared_boundary[i]->GetGeometryType(); + // vertices + nv = shared_boundary[i]->GetNVertices(); + v = shared_boundary[i]->GetVertices(); + for (j = 0; j < nv; j++) + out << ' ' << v[j]; + out << '\n'; + } + vc = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(nv_ne, 2, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(ne); + MPI_Recv(&ints[0], ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; ) + { + // processor number + 1 as bdr. attr. and bdr. geometry type + out << p+1 << ' ' << ints[i]; + k = Geometries.GetVertices(ints[i++])->GetNPoints(); + // vertices + for (j = 0; j < k; j++) + out << ' ' << vc + ints[i++]; + out << '\n'; + } + vc += nv; + } + } + else + { + // for each boundary and shared boundary element send its + // geometry type and its vertices + ne = 0; + for (i = 0; i < NumOfBdrElements; i++) + ne += 1 + boundary[i]->GetNVertices(); + for (i = 0; i < shared_boundary.Size(); i++) + ne += 1 + shared_boundary[i]->GetNVertices(); + nv = NumOfVertices; + MPI_Send(nv_ne, 2, MPI_INT, 0, 446, MyComm); + ints.SetSize(ne); + // boundary + for (i = j = 0; i < NumOfBdrElements; i++) + { + ints[j++] = boundary[i]->GetGeometryType(); + nv = boundary[i]->GetNVertices(); + v = boundary[i]->GetVertices(); + for (k = 0; k < nv; k++) + ints[j++] = v[k]; + } + // shared boundary + for (i = 0; i < shared_boundary.Size(); i++) + { + ints[j++] = shared_boundary[i]->GetGeometryType(); + nv = shared_boundary[i]->GetNVertices(); + v = shared_boundary[i]->GetVertices(); + for (k = 0; k < nv; k++) + ints[j++] = v[k]; + } + MPI_Send(&ints[0], ne, MPI_INT, 0, 447, MyComm); + } + + // vertices / nodes + MPI_Reduce(&NumOfVertices, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + if (MyRank == 0) + out << "\nvertices\n" << nv << '\n'; + if (Nodes == NULL) + { + if (MyRank == 0) + { + out << Dim << '\n'; + for (i = 0; i < NumOfVertices; i++) + { + out << vertices[i](0); + for (j = 1; j < Dim; j++) + out << ' ' << vertices[i](j); + out << '\n'; + } + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 448, MyComm, &status); + vert.SetSize(nv*Dim); + MPI_Recv(&vert[0], nv*Dim, MPI_DOUBLE, p, 449, MyComm, &status); + for (i = 0; i < nv; i++) + { + out << vert[i*Dim]; + for (j = 1; j < Dim; j++) + out << ' ' << vert[i*Dim+j]; + out << '\n'; + } + } + } + else + { + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 448, MyComm); + vert.SetSize(NumOfVertices*Dim); + for (i = 0; i < NumOfVertices; i++) + for (j = 0; j < Dim; j++) + vert[i*Dim+j] = vertices[i](j); + MPI_Send(&vert[0], NumOfVertices*Dim, MPI_DOUBLE, 0, 449, MyComm); + } + } + else + { + if (MyRank == 0) + out << "\nnodes\n"; + ParGridFunction *pnodes = dynamic_cast(Nodes); + if (pnodes) + { + pnodes->SaveAsOne(out); + } + else + { + ParFiniteElementSpace *pfes = + dynamic_cast(Nodes->FESpace()); + if (pfes) + { + // create a wrapper ParGridFunction + ParGridFunction ParNodes(pfes, Nodes); + ParNodes.SaveAsOne(out); + } + else + mfem_error("ParMesh::PrintAsOne : Nodes have no parallel info!"); + } + } +} + +void ParMesh::PrintAsOneXG(ostream &out) +{ + if (Dim == 3 && meshgen == 1) + { + int i, j, k, nv, ne, p; + const int *ind, *v; + MPI_Status status; + Array vert; + Array ints; + + if (MyRank == 0) + { + out << "NETGEN_Neutral_Format\n"; + // print the vertices + ne = NumOfVertices; + MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + out << nv << '\n'; + for (i = 0; i < NumOfVertices; i++) + { + for (j = 0; j < Dim; j++) + out << " " << vertices[i](j); + out << '\n'; + } + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + vert.SetSize(Dim*nv); + MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status); + for (i = 0; i < nv; i++) + { + for (j = 0; j < Dim; j++) + out << " " << vert[Dim*i+j]; + out << '\n'; + } + } + + // print the elements + nv = NumOfElements; + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + out << ne << '\n'; + for (i = 0; i < NumOfElements; i++) + { + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); + out << 1; + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + k = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(4*ne); + MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; i++) + { + out << p+1; + for (j = 0; j < 4; j++) + out << " " << k+ints[i*4+j]+1; + out << '\n'; + } + k += nv; + } + // print the boundary + shared faces information + nv = NumOfBdrElements + shared_faces.Size(); + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + out << ne << '\n'; + // boundary + for (i = 0; i < NumOfBdrElements; i++) + { + nv = boundary[i]->GetNVertices(); + ind = boundary[i]->GetVertices(); + out << 1; + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + // shared faces + for (i = 0; i < shared_faces.Size(); i++) + { + nv = shared_faces[i]->GetNVertices(); + ind = shared_faces[i]->GetVertices(); + out << 1; + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + k = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(3*ne); + MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; i++) + { + out << p+1; + for (j = 0; j < 3; j++) + out << " " << k+ints[i*3+j]+1; + out << '\n'; + } + k += nv; + } + } + else + { + ne = NumOfVertices; + MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + vert.SetSize(Dim*NumOfVertices); + for (i = 0; i < NumOfVertices; i++) + for (j = 0; j < Dim; j++) + vert[Dim*i+j] = vertices[i](j); + MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE, + 0, 445, MyComm); + // elements + ne = NumOfElements; + MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm); + ints.SetSize(NumOfElements*4); + for (i = 0; i < NumOfElements; i++) + { + v = elements[i]->GetVertices(); + for (j = 0; j < 4; j++) + ints[4*i+j] = v[j]; + } + MPI_Send(&ints[0], 4*NumOfElements, MPI_INT, 0, 447, MyComm); + // boundary + shared faces + nv = NumOfBdrElements + shared_faces.Size(); + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + ne = NumOfBdrElements + shared_faces.Size(); + MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm); + ints.SetSize(3*ne); + for (i = 0; i < NumOfBdrElements; i++) + { + v = boundary[i]->GetVertices(); + for (j = 0; j < 3; j++) + ints[3*i+j] = v[j]; + } + for ( ; i < ne; i++) + { + v = shared_faces[i-NumOfBdrElements]->GetVertices(); + for (j = 0; j < 3; j++) + ints[3*i+j] = v[j]; + } + MPI_Send(&ints[0], 3*ne, MPI_INT, 0, 447, MyComm); + } + } + + if (Dim == 3 && meshgen == 2) + { + int i, j, k, nv, ne, p; + const int *ind, *v; + MPI_Status status; + Array vert; + Array ints; + + int TG_nv, TG_ne, TG_nbe; + + if (MyRank == 0) + { + MPI_Reduce(&NumOfVertices, &TG_nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Reduce(&NumOfElements, &TG_ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + nv = NumOfBdrElements + shared_faces.Size(); + MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0, MyComm); + + out << "TrueGrid\n" + << "1 " << TG_nv << " " << TG_ne << " 0 0 0 0 0 0 0\n" + << "0 0 0 1 0 0 0 0 0 0 0\n" + << "0 0 " << TG_nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n" + << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; + + // print the vertices + nv = TG_nv; + for (i = 0; i < NumOfVertices; i++) + out << i+1 << " 0.0 " << vertices[i](0) << " " << vertices[i](1) + << " " << vertices[i](2) << " 0.0\n"; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + vert.SetSize(Dim*nv); + MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status); + for (i = 0; i < nv; i++) + out << i+1 << " 0.0 " << vert[Dim*i] << " " << vert[Dim*i+1] + << " " << vert[Dim*i+2] << " 0.0\n"; + } + + // print the elements + ne = TG_ne; + for (i = 0; i < NumOfElements; i++) + { + nv = elements[i]->GetNVertices(); + ind = elements[i]->GetVertices(); + out << i+1 << " " << 1; + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << '\n'; + } + k = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(8*ne); + MPI_Recv(&ints[0], 8*ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; i++) + { + out << i+1 << " " << p+1; + for (j = 0; j < 8; j++) + out << " " << k+ints[i*8+j]+1; + out << '\n'; + } + k += nv; + } + + // print the boundary + shared faces information + ne = TG_nbe; + // boundary + for (i = 0; i < NumOfBdrElements; i++) + { + nv = boundary[i]->GetNVertices(); + ind = boundary[i]->GetVertices(); + out << 1; + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << " 1.0 1.0 1.0 1.0\n"; + } + // shared faces + for (i = 0; i < shared_faces.Size(); i++) + { + nv = shared_faces[i]->GetNVertices(); + ind = shared_faces[i]->GetVertices(); + out << 1; + for (j = 0; j < nv; j++) + out << " " << ind[j]+1; + out << " 1.0 1.0 1.0 1.0\n"; + } + k = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(4*ne); + MPI_Recv(&ints[0], 4*ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; i++) + { + out << p+1; + for (j = 0; j < 4; j++) + out << " " << k+ints[i*4+j]+1; + out << " 1.0 1.0 1.0 1.0\n"; + } + k += nv; + } + } + else + { + MPI_Reduce(&NumOfVertices, &TG_nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Reduce(&NumOfElements, &TG_ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + nv = NumOfBdrElements + shared_faces.Size(); + MPI_Reduce(&nv, &TG_nbe, 1, MPI_INT, MPI_SUM, 0, MyComm); + + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + vert.SetSize(Dim*NumOfVertices); + for (i = 0; i < NumOfVertices; i++) + for (j = 0; j < Dim; j++) + vert[Dim*i+j] = vertices[i](j); + MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE, 0, 445, MyComm); + // elements + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm); + ints.SetSize(NumOfElements*8); + for (i = 0; i < NumOfElements; i++) + { + v = elements[i]->GetVertices(); + for (j = 0; j < 8; j++) + ints[8*i+j] = v[j]; + } + MPI_Send(&ints[0], 8*NumOfElements, MPI_INT, 0, 447, MyComm); + // boundary + shared faces + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + ne = NumOfBdrElements + shared_faces.Size(); + MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm); + ints.SetSize(4*ne); + for (i = 0; i < NumOfBdrElements; i++) + { + v = boundary[i]->GetVertices(); + for (j = 0; j < 4; j++) + ints[4*i+j] = v[j]; + } + for ( ; i < ne; i++) + { + v = shared_faces[i-NumOfBdrElements]->GetVertices(); + for (j = 0; j < 4; j++) + ints[4*i+j] = v[j]; + } + MPI_Send(&ints[0], 4*ne, MPI_INT, 0, 447, MyComm); + } + } + + if (Dim == 2) + { + int i, j, k, attr, nv, ne, p; + Array v; + MPI_Status status; + Array vert; + Array ints; + + + if (MyRank == 0) + { + out << "areamesh2\n\n"; + + // print the boundary + shared edges information + nv = NumOfBdrElements + shared_edges.Size(); + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + out << ne << '\n'; + // boundary + for (i = 0; i < NumOfBdrElements; i++) + { + attr = boundary[i]->GetAttribute(); + boundary[i]->GetVertices(v); + out << attr << " "; + for (j = 0; j < v.Size(); j++) + out << v[j] + 1 << " "; + out << '\n'; + } + // shared edges + for (i = 0; i < shared_edges.Size(); i++) + { + attr = shared_edges[i]->GetAttribute(); + shared_edges[i]->GetVertices(v); + out << attr << " "; + for (j = 0; j < v.Size(); j++) + out << v[j] + 1 << " "; + out << '\n'; + } + k = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(2*ne); + MPI_Recv(&ints[0], 2*ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; i++) + { + out << p+1; + for (j = 0; j < 2; j++) + out << " " << k+ints[i*2+j]+1; + out << '\n'; + } + k += nv; + } + + // print the elements + nv = NumOfElements; + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + out << ne << '\n'; + for (i = 0; i < NumOfElements; i++) + { + attr = elements[i]->GetAttribute(); + elements[i]->GetVertices(v); + out << 1 << " " << 3 << " "; + for (j = 0; j < v.Size(); j++) + out << v[j] + 1 << " "; + out << '\n'; + } + k = NumOfVertices; + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + MPI_Recv(&ne, 1, MPI_INT, p, 446, MyComm, &status); + ints.SetSize(3*ne); + MPI_Recv(&ints[0], 3*ne, MPI_INT, p, 447, MyComm, &status); + for (i = 0; i < ne; i++) + { + out << p+1 << " " << 3; + for (j = 0; j < 3; j++) + out << " " << k+ints[i*3+j]+1; + out << '\n'; + } + k += nv; + } + + // print the vertices + ne = NumOfVertices; + MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + out << nv << '\n'; + for (i = 0; i < NumOfVertices; i++) + { + for (j = 0; j < Dim; j++) + out << vertices[i](j) << " "; + out << '\n'; + } + for (p = 1; p < NRanks; p++) + { + MPI_Recv(&nv, 1, MPI_INT, p, 444, MyComm, &status); + vert.SetSize(Dim*nv); + MPI_Recv(&vert[0], Dim*nv, MPI_DOUBLE, p, 445, MyComm, &status); + for (i = 0; i < nv; i++) + { + for (j = 0; j < Dim; j++) + out << " " << vert[Dim*i+j]; + out << '\n'; + } + } + } + else + { + // boundary + shared faces + nv = NumOfBdrElements + shared_edges.Size(); + MPI_Reduce(&nv, &ne, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + ne = NumOfBdrElements + shared_edges.Size(); + MPI_Send(&ne, 1, MPI_INT, 0, 446, MyComm); + ints.SetSize(2*ne); + for (i = 0; i < NumOfBdrElements; i++) + { + boundary[i]->GetVertices(v); + for (j = 0; j < 2; j++) + ints[2*i+j] = v[j]; + } + for ( ; i < ne; i++) + { + shared_edges[i-NumOfBdrElements]->GetVertices(v); + for (j = 0; j < 2; j++) + ints[2*i+j] = v[j]; + } + MPI_Send(&ints[0], 2*ne, MPI_INT, 0, 447, MyComm); + // elements + ne = NumOfElements; + MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + MPI_Send(&NumOfElements, 1, MPI_INT, 0, 446, MyComm); + ints.SetSize(NumOfElements*3); + for (i = 0; i < NumOfElements; i++) + { + elements[i]->GetVertices(v); + for (j = 0; j < 3; j++) + ints[3*i+j] = v[j]; + } + MPI_Send(&ints[0], 3*NumOfElements, MPI_INT, 0, 447, MyComm); + // vertices + ne = NumOfVertices; + MPI_Reduce(&ne, &nv, 1, MPI_INT, MPI_SUM, 0, MyComm); + MPI_Send(&NumOfVertices, 1, MPI_INT, 0, 444, MyComm); + vert.SetSize(Dim*NumOfVertices); + for (i = 0; i < NumOfVertices; i++) + for (j = 0; j < Dim; j++) + vert[Dim*i+j] = vertices[i](j); + MPI_Send(&vert[0], Dim*NumOfVertices, MPI_DOUBLE, + 0, 445, MyComm); + } + } +} + +ParMesh::~ParMesh() +{ + int i; + + for (i = 0; i < shared_faces.Size(); i++) + FreeElement(shared_faces[i]); + for (i = 0; i < shared_edges.Size(); i++) + FreeElement(shared_edges[i]); + + // The Mesh destructor is called automatically +} + +#endif diff --git a/mesh/pmesh.hpp b/mesh/pmesh.hpp new file mode 100644 index 0000000000..a244459ee4 --- /dev/null +++ b/mesh/pmesh.hpp @@ -0,0 +1,101 @@ +// 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.googlecode.com. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License (as published by the Free +// Software Foundation) version 2.1 dated February 1999. + +#ifndef MFEM_PMESH +#define MFEM_PMESH + +/// Class for parallel meshes +class ParMesh : public Mesh +{ +private: + MPI_Comm MyComm; + int NRanks, MyRank; + + Array shared_edges; + Array shared_faces; + + /// Shared objects in each group. + Table group_svert; + Table group_sedge; + Table group_sface; + + /// Shared to local index mapping. + Array svert_lvert; + Array sedge_ledge; + Array sface_lface; + + /// Return a number(0-1) identifying how the given edge has been split + int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle); + /// Return a number(0-4) identifying how the given face has been split + int GetFaceSplittings(Element *face, const DSTable &v_to_v, int *middle); + +public: + ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL, + int part_method = 1); + + MPI_Comm GetComm() { return MyComm; } + int GetNRanks() { return NRanks; } + int GetMyRank() { return MyRank; } + + /** The shared vertices, faces and edges are split into groups, each group + determined by the set of participating processors, proc. They are + numbered locally in lproc. Assumptions: + - group 0 is the 'local' group + - groupmaster_lproc[0] = 0 + - lproc_proc[0] = MyRank */ + Table group_lproc; + Array groupmaster_lproc; + Array lproc_proc; + /// for each group gives the group number in the master + Array group_mgroup; + + int GetNGroups() { return group_lproc.Size(); } + + // next 6 methods do not work for the 'local' group 0 + int GroupNVertices(int group) { return group_svert.RowSize(group-1); } + int GroupNEdges(int group) { return group_sedge.RowSize(group-1); } + int GroupNFaces(int group) { return group_sface.RowSize(group-1); } + + int GroupVertex(int group, int i) + { return svert_lvert[group_svert.GetJ()[group_svert.GetI()[group-1]+i]]; } + void GroupEdge(int group, int i, int &edge, int &o); + void GroupFace(int group, int i, int &face, int &o); + + /// Refine the marked elements. + virtual void LocalRefinement(const Array &marked_el, int type = 3); + + /// Update the groups after tet refinement + void RefineGroups(const DSTable &v_to_v, int *middle); + + /// Refine quadrilateral mesh. + virtual void QuadUniformRefinement(); + + /// Refine a hexahedral mesh. + virtual void HexUniformRefinement(); + + /** Print the part of the mesh in the calling processor + adding the interface as boundary (for visualization purposes) */ + virtual void Print(ostream &out = cout) const; + + /** Write the mesh to the stream 'out' on Process 0 in a form + suitable for visualization: the mesh is written as a disjoint + mesh and the shared boundary is added to the actual boundary; + both the element and boundary attributes are set to the + precessor number. */ + void PrintAsOne(ostream &out = cout); + + /// Old mesh format (Netgen/Truegrid) version of 'PrintAsOne' + void PrintAsOneXG(ostream &out = cout); + + virtual ~ParMesh(); +}; + +#endif diff --git a/mesh/quadrilateral.hpp b/mesh/quadrilateral.hpp index 24480378ce..e2f35cef0a 100644 --- a/mesh/quadrilateral.hpp +++ b/mesh/quadrilateral.hpp @@ -21,13 +21,13 @@ protected: public: - Quadrilateral () : Element(Geometry::SQUARE) {} + Quadrilateral() : Element(Geometry::SQUARE) {} /// Constructs quadrilateral by specifying the indices and the attribute. - Quadrilateral ( const int *ind, int attr = 1 ); + Quadrilateral(const int *ind, int attr = 1); /// Constructs quadrilateral by specifying the indices and the attribute. - Quadrilateral( int ind1, int ind2, int ind3, int ind4, int attr = 1 ); + Quadrilateral(int ind1, int ind2, int ind3, int ind4, int attr = 1); /// Return element's type int GetType() const { return Element::QUADRILATERAL; } @@ -36,11 +36,11 @@ public: virtual void SetVertices(const int *ind); /// Returns the indices of the element's vertices. - virtual void GetVertices ( Array &v ) const; + virtual void GetVertices(Array &v) const; - virtual int * GetVertices () { return indices; }; + virtual int *GetVertices() { return indices; } - virtual int GetNVertices() const { return 4; }; + virtual int GetNVertices() const { return 4; } virtual int GetNEdges() const { return(4); } @@ -48,7 +48,7 @@ public: { return(edges[ei]); } virtual Element *Duplicate() const - { return new Quadrilateral (indices, attribute); }; + { return new Quadrilateral(indices, attribute); } virtual ~Quadrilateral() { } }; diff --git a/mesh/segment.hpp b/mesh/segment.hpp index ff7aef0e24..3e713f1768 100644 --- a/mesh/segment.hpp +++ b/mesh/segment.hpp @@ -23,10 +23,10 @@ public: Segment() : Element(Geometry::SEGMENT) {} /// Constructs triangle by specifying the indices and the attribute. - Segment( const int *ind, int attr = -1 ); + Segment(const int *ind, int attr = 1); /// Constructs triangle by specifying the indices and the attribute. - Segment( int ind1, int ind2, int attr = -1 ); + Segment(int ind1, int ind2, int attr = 1); /// Set the indices the element according to the input. virtual void SetVertices(const int *ind); @@ -35,18 +35,18 @@ public: virtual int GetType() const { return Element::SEGMENT; } /// Returns the indices of the element's vertices. - virtual void GetVertices( Array &v ) const; + virtual void GetVertices(Array &v) const; - virtual int * GetVertices () { return indices; }; + virtual int *GetVertices() { return indices; } - virtual int GetNVertices() const { return 2; }; + virtual int GetNVertices() const { return 2; } virtual int GetNEdges() const { return(0); } virtual const int *GetEdgeVertices(int ei) const { return(NULL); } virtual Element *Duplicate() const - { return new Segment (indices, attribute); }; + { return new Segment(indices, attribute); } virtual ~Segment() { } }; diff --git a/mesh/tetrahedron.cpp b/mesh/tetrahedron.cpp index 58f7e9bb46..f08e160fe1 100644 --- a/mesh/tetrahedron.cpp +++ b/mesh/tetrahedron.cpp @@ -22,6 +22,10 @@ void Tetrahedron::ParseRefinementFlag(int refinement_edges[2], int &type, { int i, f = refinement_flag; + if (f == 0) + mfem_error("Tetrahedron::ParseRefinementFlag :" + " tetrahedron is not marked"); + for (i = 0; i < 2; i++) { refinement_edges[i] = f & 7; @@ -45,7 +49,7 @@ void Tetrahedron::CreateRefinementFlag(int refinement_edges[2], int type, case Tetrahedron::TYPE_PU: if (e1 == 2 && e2 == 1) break; // if (e1 == 3 && e2 == 4) break; - mfem_error ("Error in Tetrahedron::CreateRefinementFlag(...) #1"); + mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #1"); break; case Tetrahedron::TYPE_A: if (e1 == 3 && e2 == 1) break; @@ -54,7 +58,7 @@ void Tetrahedron::CreateRefinementFlag(int refinement_edges[2], int type, // if (e2 == 5) // if (e1 >= 1 && e1 <= 5) break; // type is actually O or M // // ==> ok for generation = 0 - mfem_error ("Error in Tetrahedron::CreateRefinementFlag(...) #2"); + mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #2"); break; case Tetrahedron::TYPE_PF: if (flag > 0) // PF is ok only for generation > 0 @@ -62,12 +66,12 @@ void Tetrahedron::CreateRefinementFlag(int refinement_edges[2], int type, if (e1 == 2 && e2 == 1) break; // if (e1 == 3 && e2 == 4) break; } - mfem_error ("Error in Tetrahedron::CreateRefinementFlag(...) #3"); + mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #3"); break; case Tetrahedron::TYPE_O: if (flag == 0 && e1 == 5 && e2 == 5) break; - mfem_error ("Error in Tetrahedron::CreateRefinementFlag(...) #4"); + mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #4"); break; case Tetrahedron::TYPE_M: if (flag == 0) @@ -75,10 +79,10 @@ void Tetrahedron::CreateRefinementFlag(int refinement_edges[2], int type, if (e1 == 5 && e2 == 1) break; if (e1 == 2 && e2 == 5) break; } - mfem_error ("Error in Tetrahedron::CreateRefinementFlag(...) #5"); + mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #5"); break; default: - mfem_error ("Error in Tetrahedron::CreateRefinementFlag(...) #6"); + mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #6"); break; } #endif @@ -95,11 +99,10 @@ void Tetrahedron::CreateRefinementFlag(int refinement_edges[2], int type, refinement_flag = refinement_flag | refinement_edges[0]; } -Tetrahedron::Tetrahedron(int *ind, int attr) - : Element(Geometry::TETRAHEDRON) +Tetrahedron::Tetrahedron(int *ind, int attr) : Element(Geometry::TETRAHEDRON) { attribute = attr; - for (int i=0; i<4; i++) + for (int i = 0; i < 4; i++) indices[i] = ind[i]; refinement_flag = 0; } diff --git a/mesh/tetrahedron.hpp b/mesh/tetrahedron.hpp index 040e31ded6..42dd53b7b6 100644 --- a/mesh/tetrahedron.hpp +++ b/mesh/tetrahedron.hpp @@ -43,20 +43,20 @@ public: Tetrahedron(int ind1, int ind2, int ind3, int ind4, int attr = 1); void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag); - void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0); + void CreateRefinementFlag(int refinement_edges[2], int type, int flag = 0); - virtual int GetRefinementFlag() { return refinement_flag; }; + virtual int GetRefinementFlag() { return refinement_flag; } - void SetRefinementFlag (int rf) { refinement_flag = rf; }; + void SetRefinementFlag(int rf) { refinement_flag = rf; } /// Return 1 if the element needs refinement in order to get conforming mesh. - virtual int NeedRefinement ( DSTable &v_to_v, int *middle) const; + virtual int NeedRefinement(DSTable &v_to_v, int *middle) const; /// Set the vertices according to the given input. virtual void SetVertices(const int *ind); /// Mark the longest edge by assuming/changing the order of the vertices. - virtual void MarkEdge(DenseMatrix &pmat) {} + virtual void MarkEdge(DenseMatrix &pmat) { } /** Reorder the vertices so that the longest edge is from vertex 0 to vertex 1. If called it should be once from the mesh constructor, @@ -67,16 +67,15 @@ public: virtual int GetType() const { return Element::TETRAHEDRON; } /// Returns the indices of the element's vertices. - virtual void GetVertices( Array &v ) const; + virtual void GetVertices(Array &v) const; - virtual int *GetVertices () { return indices; } + virtual int *GetVertices() { return indices; } virtual int GetNVertices() const { return 4; } virtual int GetNEdges() const { return(6); } - virtual const int *GetEdgeVertices(int ei) const - { return(edges[ei]); } + virtual const int *GetEdgeVertices(int ei) const { return(edges[ei]); } virtual Element *Duplicate() const; diff --git a/mesh/triangle.cpp b/mesh/triangle.cpp index 13f54ad4b9..54916729e0 100644 --- a/mesh/triangle.cpp +++ b/mesh/triangle.cpp @@ -14,15 +14,15 @@ const int Triangle::edges[3][2] = {{0, 1}, {1, 2}, {2, 0}}; -Triangle::Triangle( const int *ind, int attr ) : Element(Geometry::TRIANGLE) +Triangle::Triangle(const int *ind, int attr) : Element(Geometry::TRIANGLE) { attribute = attr; - for (int i=0; i<3; i++) + for (int i = 0; i < 3; i++) indices[i] = ind[i]; } -Triangle::Triangle( int ind1, int ind2, int ind3, - int attr ) : Element(Geometry::TRIANGLE) +Triangle::Triangle(int ind1, int ind2, int ind3, int attr) + : Element(Geometry::TRIANGLE) { attribute = attr; indices[0] = ind1; @@ -30,19 +30,19 @@ Triangle::Triangle( int ind1, int ind2, int ind3, indices[2] = ind3; } -int Triangle::NeedRefinement ( DSTable &v_to_v, int *middle) const +int Triangle::NeedRefinement(DSTable &v_to_v, int *middle) const { int m; - if ((m = v_to_v(indices[0], indices[1]))!=-1 && middle[m]!=-1) return 1; - if ((m = v_to_v(indices[1], indices[2]))!=-1 && middle[m]!=-1) return 1; - if ((m = v_to_v(indices[2], indices[0]))!=-1 && middle[m]!=-1) return 1; + if ((m = v_to_v(indices[0], indices[1])) != -1 && middle[m] != -1) return 1; + if ((m = v_to_v(indices[1], indices[2])) != -1 && middle[m] != -1) return 1; + if ((m = v_to_v(indices[2], indices[0])) != -1 && middle[m] != -1) return 1; return 0; } void Triangle::SetVertices(const int *ind) { - for(int i=0; i<3; i++) + for (int i = 0; i < 3; i++) indices[i] = ind[i]; } @@ -65,7 +65,8 @@ void Triangle::MarkEdge(DenseMatrix &pmat) if (d[1] >= d[2]) shift = 1; else shift = 2; - switch (shift) { + switch (shift) + { case 0: break; case 1: @@ -87,14 +88,15 @@ void Triangle::MarkEdge(const DSTable &v_to_v, const int *length) { int l, L, j, ind[3], i; - L = length[ v_to_v(indices[0], indices[1] ) ]; j = 0; - if ( (l = length[ v_to_v(indices[1], indices[2] ) ]) > L ){ L = l; j = 1;} - if ( (l = length[ v_to_v(indices[2], indices[0] ) ]) > L ){ L = l; j = 2;} + L = length[ v_to_v(indices[0], indices[1]) ]; j = 0; + if ( (l = length[ v_to_v(indices[1], indices[2]) ]) > L ) { L = l; j = 1; } + if ( (l = length[ v_to_v(indices[2], indices[0]) ]) > L ) { L = l; j = 2; } - for(i=0; i<3; i++) + for (i = 0; i < 3; i++) ind[i] = indices[i]; - switch ( j ) { + switch (j) + { case 1: indices[0] = ind[1]; indices[1] = ind[2]; indices[2] = ind[0]; break; @@ -104,10 +106,10 @@ void Triangle::MarkEdge(const DSTable &v_to_v, const int *length) } } -void Triangle::GetVertices( Array &v ) const +void Triangle::GetVertices(Array &v) const { - v.SetSize( 3 ); - for (int i=0; i<3; i++) + v.SetSize(3); + for (int i = 0; i < 3; i++) v[i] = indices[i]; } diff --git a/mesh/triangle.hpp b/mesh/triangle.hpp index 74351ce297..87867fd79c 100644 --- a/mesh/triangle.hpp +++ b/mesh/triangle.hpp @@ -21,16 +21,16 @@ protected: public: - Triangle() : Element(Geometry::TRIANGLE) {} + Triangle() : Element(Geometry::TRIANGLE) { } /// Constructs triangle by specifying the indices and the attribute. - Triangle( const int *ind, int attr = 1 ); + Triangle(const int *ind, int attr = 1); /// Constructs triangle by specifying the indices and the attribute. - Triangle( int ind1, int ind2, int ind3, int attr = 1 ); + Triangle(int ind1, int ind2, int ind3, int attr = 1); /// Return 1 if the element needs refinement in order to get conforming mesh. - int NeedRefinement ( DSTable &v_to_v, int *middle) const; + int NeedRefinement(DSTable &v_to_v, int *middle) const; /// Set the vertices according to the given input. virtual void SetVertices(const int *ind); @@ -47,19 +47,18 @@ public: virtual int GetType() const { return Element::TRIANGLE; } /// Returns the indices of the element's vertices. - virtual void GetVertices( Array &v ) const; + virtual void GetVertices(Array &v) const; - virtual int *GetVertices () { return indices; }; + virtual int *GetVertices() { return indices; } - virtual int GetNVertices() const { return 3; }; + virtual int GetNVertices() const { return 3; } virtual int GetNEdges() const { return(3); } - virtual const int *GetEdgeVertices(int ei) const - { return(edges[ei]); } + virtual const int *GetEdgeVertices(int ei) const { return(edges[ei]); } virtual Element *Duplicate() const - { return new Triangle (indices, attribute); }; + { return new Triangle(indices, attribute); } virtual ~Triangle() { } }; diff --git a/mesh/vertex.hpp b/mesh/vertex.hpp index fc54f5bb0c..0343ca5e36 100644 --- a/mesh/vertex.hpp +++ b/mesh/vertex.hpp @@ -35,6 +35,9 @@ public: /// Returns the i'th coordinate of the vertex. inline const double & operator() (int i) const { return coord[i]; } + void SetCoords(const double *p) + { coord[0] = p[0]; coord[1] = p[1]; coord[2] = p[2]; } + ~Vertex() { } };