Compare commits

..
Author SHA1 Message Date
Veselin Dobrev 33ccd307bd Include "mpi-ext.h" only if using OpenMPI. 2018-08-23 17:50:39 -07:00
Veselin Dobrev 958e0f27c4 Add an option in mfem::occa::Engine to force the use of CUDA
pointers in MPI calls, regardless of the result of the
CUDA-aware MPI check.
2018-08-23 17:21:24 -07:00
Veselin Dobrev 07d043ec77 Add a message in the ctor of OccaConformingProlongation that shows
if MPI is CUDA aware or not - this is done only when using the CUDA
OCCA mode.
2018-08-21 12:16:00 -07:00
Veselin Dobrev a61e836c4a Fix a bug in the 3D mass and diffusion GPU kernels: add barriers. 2018-08-21 05:20:31 -07:00
Veselin Dobrev aa58b549ab Include "mpi-ext.h" only when MPI_USE_MPI is defined. 2018-08-20 02:30:42 -07:00
Veselin Dobrev 87b9412e80 In class OccaConformingProlongation, check for CUDA-aware MPI. 2018-08-20 02:02:07 -07:00
Veselin Dobrev 36a9a3ac92 A few enhancements in ex1d and ex1pd - can be removed later,
before merging into master.
2018-08-18 09:40:00 -07:00
Veselin Dobrev 5bd5e169a3 Fix a bug in the class OccaConformingProlongation - need to wait for
the first copy kernel to finish before MPI communication is started.

Other small tweaks.
2018-08-15 15:47:28 -07:00
Johann Dahm a2ad9af08f Add VectorMassIntegrator 2018-08-13 10:37:58 -07:00
Veselin Dobrev c967429b2d A couple of small tweaks. 2018-08-06 17:48:13 -07:00
Johann Dahm c33e2edb72 Changes for ex16d in CUDA mode 2018-08-06 12:59:44 -07:00
Johann Dahm 7057bde885 Merge branch 'engines-dev' of github.com:mfem/mfem into engines-dev 2018-08-06 10:50:03 -07:00
Veselin Dobrev fa1f7666c4 In the OCCA backend, add support for parallel prolongation on
conforming meshes without transferring the whole vector to host
memory.

Add support for parallel AMR meshes with engines.

In class mfem::FiniteElementSpace, the conforming prolongation,
cP, and conforming restriction, cR, are no longer lazy-constructed.

In class ParFiniteElementSpace, rename the parallel versions of
the methods Construct and Destroy to ParConstruct and ParDestroy,
respectively.

In class ParFiniteElementSpace, use the field pncmesh in all
places instead of pmesh->pncmesh.

A number of small tweaks in the OCCA backend.
2018-08-06 02:25:32 -07:00
Veselin Dobrev 066c37520a Cleanup some of the code in the OCCA backend:
* Remove the method mfem::occa::Engine::GetOklDefines().
 * Switch the argument of mfem::occa::Array::OccaFill() from 'const T *'
   to 'const T'.
 * Remove unused constructors from mfem::occa::OccaSparseMatrix and make
   some of its members protected.
 * Replace 'restrict' with '@restrict' in .okl files.
 * When the prolongation is identity, initialize the occa prolongation
   and restriction operators to NULL.
2018-08-04 20:17:12 -07:00
Veselin Dobrev 61cd1aa8cd Add two new methods to the PFiniteElementSpace interface:
GetInterpolationOperator() and GetGradientOperator(), both of which map
GridFunction-size vectors (L-vectors) to QuadratureFunction-size vectors
(Q-vectors).

These new methods are not yet implemented in the OCCA backend.
2018-08-03 19:51:14 -07:00
Veselin Dobrev f87dbdc2ad Make QuadratureFunction::OwnsSpace() a const method 2018-08-03 19:49:20 -07:00
Veselin Dobrev 6c0777c0e1 Merge branch 'master' into engines-dev
Resolved conflicts:
   config/config.hpp.in
   config/config.mk.in
   config/defaults.mk
   fem/bilinearform.cpp
   makefile
2018-08-03 19:45:51 -07:00
Johann Dahm 3051b7ed11 Merge branch 'engines-dev' of github.com:mfem/mfem into engines-dev 2018-08-02 10:51:08 -07:00
Johann Dahm e77ee6a3a3 Update to latest OCCA commit and make ex16d work in GPU mode 2018-08-02 10:50:02 -07:00
Veselin Dobrev d0c90c8505 Some tweaks and cleanup in the OCCA backend.
Adjust the return types of the methods GetVLayout, GetTrueVLayout, and
Get_PFESpace in class FiniteElementSpace.

Add missing return statements in the methods mfem::Engine::As.
2018-08-01 21:52:37 -07:00
Veselin Dobrev 8ee2e444be Re-enable the engine in ex1d.
Small tweak in backends/occa/utils.okl.
2018-07-30 22:59:25 -07:00
Veselin Dobrev 7336d8ea84 Update the occa spec strings in ex1pd and ex16d. 2018-07-30 21:23:38 -07:00
Veselin Dobrev cf053cdc59 Move some methods in mfem::Engine from .hpp to .cpp.
Update the occa spec strings in ex1d to use the latest syntax.
2018-07-30 21:18:30 -07:00
Johann Dahm e845d83cce Example 16 working with OCCA engine
The coefficient is computed on the host and pushed to the device on
every SetParameters call.
2018-07-29 23:21:44 -07:00
Johann Dahm 9764593415 Make restrict compatible with current OKL format 2018-07-22 17:49:03 -07:00
Johann Dahm 5beb85d4ce Move DontDelete() to e_layout in backend FiniteElementSpace 2018-07-05 15:03:11 -07:00
Johann Dahm 7f1d0689ef Make mfem::Vertex trivially copyable 2018-07-02 22:40:38 -07:00
Johann Dahm bdc8e0c16a Move GetFESpace to mfem::PFiniteElementSpace 2018-07-02 22:38:22 -07:00
Johann Dahm 3a6ef2cd85 Delete underlying OccaBilinearForm but keep ref to e_layouts 2018-07-02 22:33:47 -07:00
Veselin Dobrev d49258aaaa Update okl files for OCCA v1.0.0. 2018-06-14 16:48:43 -07:00
Veselin Dobrev abfa3bc631 Make DevExtension::Pull() a const method -- this makes it possible
to call Pull() for the input mfem::Vector inside Operator::Mult()
implementation.

Simplify the implementation of mfem::occa::ProlongationOperator
which still needs OCCA operator(s) for the MPI case.
2018-06-13 20:11:06 -07:00
Veselin Dobrev 4f11a7194d Run 'make style'.
A few small tweaks in ex1d and ex1pd.
2018-06-12 18:10:38 -07:00
Johann Dahm bfaf7a8da9 Fix ex1d and correct tolerance on CG solver in parallel 2018-06-07 11:45:58 -07:00
Johann Dahm 65e1de0f2b OCCA backend works in parallel on ex1pd 2018-06-04 10:37:38 -07:00
Johann Dahm 8980df563e Toward parallel engines support
* Add engine in parfespace and parbilinearform
* Add parallel ex1 with engines
2018-05-22 10:05:15 -07:00
Veselin Dobrev b79c9fc31c When updating libmfem.a remove the old archive first.
This prevents an issue when updating the archive in cases when we
have object files with the same name from different directories.
2018-05-15 20:09:37 -07:00
Veselin Dobrev 65e1fe7365 Add new files forgotten in the last commit 2018-05-15 18:37:37 -07:00
Veselin Dobrev 60834fc386 Add a custom "mfem-occa://" file-opener
With this file-opener there is no need for the makefile okl-hacks.

The path specification "mfem-occa://a/b.ext" will be resolved by
searching for the file 'a/b.ext' in a list of directories, currently
defined from the list (only existing directories are added to the list):

 * All directories specified by the environment variable
   MFEM_OCCA_OKL_PATH - list of directories separated by ':'.
 * The MFEM source directory + "/backends/occa".
 * The MFEM install prefix + "/lib/mfem/occa".

The order of the above list also defines the directory search order.
2018-05-15 18:22:34 -07:00
Veselin Dobrev 7a1b66b203 Update some doxygen documentation and comments 2018-05-15 18:04:12 -07:00
Johann Dahm 7d0d3bb6e1 Fix typo in simplex gpuHighOrder file 2018-05-11 14:17:07 -07:00
Veselin Dobrev 788bcea676 Adding an acknowledgment:
The first MFEM backend (backends/occa) is based on the OCCA
library with code taken from the previous work in the branch
occa-dev, developed by David Medina (@dmed256) and others.
2018-05-09 19:06:41 -07:00
Veselin Dobrev 2c3ce1b4db Initial commit of new draft MFEM extensions to support GPUs and
other accelerators.
2018-05-09 17:11:38 -07:00
372 changed files with 22720 additions and 62608 deletions
+8 -9
View File
@@ -26,25 +26,24 @@ install:
- cd ..
# Install hypre
- ps: Start-FileDownload 'https://github.com/hypre-space/hypre/archive/V2-10-0b.tar.gz'
- 7z x V2-10-0b.tar.gz -so | 7z x -si -ttar > nul
- cd hypre-2-10-0b
- cmake -H. -Bbuild -DHYPRE_USING_FEI=OFF -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
- ps: Start-FileDownload 'https://computation.llnl.gov/project/linear_solvers/download/hypre-2.10.0b.tar.gz'
- 7z x hypre-2.10.0b.tar.gz -so | 7z x -si -ttar > nul
- cd hypre-2.10.0b
- cmake -Hsrc -Bbuild -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
# - cmake -Hsrc -Bbuild -DCMAKE_BUILD_TYPE=Release -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
- cmake --build build
- cmake --build build --target install
- cd ..
# MFEM
before_build:
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2-10-0b\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2-10-0b\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2.10.0b\src\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2.10.0b\src\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2.10.0b\src\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2.10.0b\src\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
build_script:
- cmake --build build_parallel
- cmake --build build_serial
- cmake --build build_serial --target exec
after_build:
# - cmake --build build_parallel --target check
- cmake --build build_serial --target RUN_TESTS
- cmake --build build_serial --target check
-21
View File
@@ -45,8 +45,6 @@ examples/ex[1-9]
examples/ex[1-9]p
examples/ex1[04-9]
examples/ex1[0-9]p
examples/ex2[0-9]
examples/ex2[0-9]p
examples/refined.mesh
examples/displaced.mesh
@@ -78,13 +76,6 @@ examples/vortex-?-init.*
examples/vortex-?-final.*
examples/deformation.*
examples/pressure.*
examples/ex20.dat
examples/ex20p_?????.dat
examples/gnuplot_ex20.inp
examples/gnuplot_ex20p.inp
examples/ex21*.mesh
examples/ex21*.sol
examples/ex21p_*.*
examples/sundials/ex9
examples/sundials/ex1[06]
@@ -142,20 +133,16 @@ miniapps/electromagnetics/Joule_*
miniapps/meshing/mobius-strip
miniapps/meshing/klein-bottle
miniapps/meshing/toroid
miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
miniapps/meshing/mesh-optimizer
miniapps/meshing/pmesh-optimizer
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
miniapps/meshing/toroid-*.mesh
miniapps/meshing/mesh-explorer.mesh
miniapps/meshing/partitioning.txt
miniapps/meshing/shaper.mesh
miniapps/meshing/extruder.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
@@ -169,7 +156,6 @@ miniapps/performance/sol.*
miniapps/tools/display-basis
miniapps/tools/load-dc
miniapps/tools/convert-dc
miniapps/tools/lor-transfer
miniapps/nurbs/ex1
miniapps/nurbs/ex1p
@@ -179,10 +165,3 @@ miniapps/nurbs/mesh.*
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
# Unit test binary and outputs
tests/unit/output_meshes
tests/unit/unit_tests
# VPATH builds
build-*/*
-1
View File
@@ -205,7 +205,6 @@ install:
else
echo "Reusing cached hypre-2.10.0b/";
fi;
ln -s hypre-2.10.0b hypre;
else
echo "Serial build, not using hypre";
fi
+1 -227
View File
@@ -8,237 +8,11 @@
http://mfem.org
Version 4.0.1 (development)
Version 3.4.1 (development)
===========================
Improved GPU support
--------------------
- Added initial support for AMD GPUs based on HIP: a C++ runtime API and kernel
language that can run on both AMD and NVIDIA hardware. With this change, the
list of backends is: "occa-cuda", "raja-cuda", "cuda", "hip", "occa-omp",
"raja-omp", "omp", "occa-cpu", "raja-cpu", and "cpu".
- Improved RAJA backend and multi-GPU MPI communications.
Discretization improvements
---------------------------
- Added support for non-conforming prism AMR, including coarsening and parallel
load balancing. Anisotropic prism refinement is only available in the serial
version at the moment.
Meshing improvements
--------------------
- The TMOP mesh optimization algorithms were extended to support r-adaptivity.
Target matrices can now be constructed either via a given analytical function
(e.g. spatial dependence of size, aspect ratio, etc., for each element) or via
a (Par)GridFunction specified on the original mesh.
- The TMOP mesh optimization algorithms have been improved to support AMR meshes.
- Added support for creating refined versions of periodic meshes, making use of
the new L2ElementRestriction class. This class also allows for computing
geometric factors on periodic meshes using partial assembly.
- Improved element numbering after uniform mesh refinement.
New and updated examples and miniapps
-------------------------------------
- The mesh-optimizer and pmesh-optimizer miniapps have been updated to
demonstrate the new r-adaptivity capabilities of TMOP.
- The (p)mesh-optimizer miniapp has been updated to demonstrate mesh
optimization for an AMR mesh.
Miscellaneous
-------------
- Upgraded the SUNDIALS interface to utilize SUNDIALS version 5.0. This
necessitated a complete rework of the interface and requires changes at
the application level. Example usage of this new interface can be found
in the examples/sundials directory.
Version 4.0, released on May 24, 2019
=====================================
Unlike previous MFEM releases, this version requires a C++11 compiler.
GPU support
-----------
- Added initial support for hardware devices, such as GPUs, and programming
models, such as CUDA, OCCA, RAJA and OpenMP.
- The GPU/device support is based on MFEM's new backends and kernels working
seamlessly with a new lightweight device/host memory manager. The kernels can
be implemented either in OCCA, or as a simple wrapper around for-loops, which
can then be dispatched to RAJA and native backends. See the files forall.hpp
and mem_manager.hpp in the general/ directory for more details.
- Several of the MFEM example codes (ex1, ex1p, ex6, and ex6p) can now take
advantage of GPU acceleration with the backend selectable at runtime. Many of
the linear algebra and finite element operations (e.g. partially assembled
bilinear forms) have been extended to take advantage of kernel acceleration by
simply replacing loops with the MFEM_FORALL() macro.
- In addition to native CUDA kernels, the library currently supports OCCA, RAJA
and OpenMP kernels, which could be mixed and matched in different parts of the
same application. We plan on adding support for more programming models and
devices in the future, without the need for significant modifications in user
code. The list of current backends is: "occa-cuda", "raja-cuda", "cuda",
"occa-omp", "raja-omp", "omp", "occa-cpu", "raja-cpu", and "cpu".
- GPU-related limitations:
* Hypre preconditioners are not yet available in GPU mode, and in particular
hypre must be built in CPU mode.
* Only constant coefficients are currently supported on GPUs.
* Optimized element assembly, and matrix-free bilinear forms are not
implemented yet. Element batching is currently ignored.
* In device mode, full assembly is performed on the host (but the matvec
action is performed on the device).
* Partial assembly kernels are not implemented yet for simplices.
Discretization improvements
---------------------------
- Partial assembled finite element operators are now available in the core
library, based on the new classes PABilinearFormExtension, ElementRestriction,
DofToQuad and GeometricFactors (associated with the classes BilinearForm,
FiniteElementSpace, FiniteElement and Mesh, respectively). The kernels for
partial assembled Setup/Assembly and Action/Mult are implemented in the
BilinearFormIntegrator methods AssemblePA and AddMultPA.
- Added support for a general "low-order refined"-to-"high-order" transfer of
GridFunction data from a "low-order refined" (LOR) space defined on a refined
mesh to a "high-order" (HO) finite element space defined on a coarse mesh. See
the new classes InterpolationGridTransfer and L2ProjectionGridTransfer and the
new LOR Transfer miniapp: miniapps/tools/lor-transfer.cpp.
- Added element flux, and flux energy computation in class ElasticityIntegrator,
allowing for the use of Zienkiewicz-Zhu type error estimators with the
integrator. For an illustration of this addition, see the new Example 21.
- Added support for derefinement of vector (RT + ND) spaces.
- Added a variety of coefficients which are sums or products of existing
coefficients as well as grid function coefficients which return the
divergence, gradient, or curl of their GridFunctions.
Support for wedge elements and meshes with mixed element types
--------------------------------------------------------------
- Added support for wedge-shaped mesh elements of arbitrary order (with Geometry
type PRISM) which have two triangular faces and three quadrilateral faces.
Several examples of such meshes can be found in the data/ directory.
- Added support for mixed meshes containing triangles and quadrilaterals in 2D
or tetrahedra, wedges, and hexahedra in 3D. This includes support for uniform
refinement of such meshes. Several examples of such meshes can be found in the
data/ directory.
- Added H1 and L2 finite elements of arbitrary order for Wedge elements.
- Added support for reading and writing linear and quadratic meshes containing
wedge elements in VTK mesh format. Several examples of such meshes can be
found in the data/ directory.
Other meshing improvements
--------------------------
- Improved the uniform refinement of tetrahedral meshes (also part of the
uniform refinement of mixed 3D meshes). The previous refinement algorithm is
still available as an option in Mesh::UniformRefinement. Both can be used in
the updated Mesh Explorer miniapp.
- The local tetrahedral mesh refinement algorithm in serial and in parallel now
follows precisely the paper:
D. Arnold, A. Mukherjee, and L. Pouly, "Locally Adapted Tetrahedral Meshes
Using Bisection", SIAM J. Sci. Comput. 22 (2000), 431448.
This guarantees that the shape regularity of the elements will be preserved
under refinement.
- The TMOP mesh optimization algorithms were extended to support user-defined
space-dependent limiting terms. Improved the TMOP objective functions by more
accurate normalization of the different terms.
- Added support for parallel communication groups on non-conforming meshes.
- Improved parallel partitioning of non-conforming meshes. If the coarse mesh
elements are ordered as a sequence of face-neighbors, the parallel partitions
are now guaranteed to be continuous. To that end, inline quadrilateral and
hexahedral meshes are now by default ordered along a space-filling curve.
- A boundary in a NURBS mesh can now be connected with another boundary. Such a
periodic NURBS mesh is a simple way to impose periodic boundary conditions.
- Added support for reading linear and quadratic 2D quadrilateral and triangular
Cubit meshes.
New and updated examples and miniapps
-------------------------------------
- Added a new meshing miniapp, Toroid, which can produce a variety of torus
shaped meshes by twisting a stack of wedges or hexahedra.
- Added a new meshing miniapp, Extruder, that demonstrates the capability to
produce 3D meshes by extruding 2D meshes.
- Added a simple miniapp, LOR Transfer, for visualizing the actions of the
transfer operators between a high-order and a low-order refined spaces.
- Added a new example, Example 20/20p, that solves a system of 1D ODEs derived
from a Hamiltonian. The example demonstrates the use of the variable order,
symplectic integration algorithm implemented in class SIAVSolver.
- Added a new example, Example 21/21p, that illustrates the use of AMR to solve
a linear elasticity problem. This is an extension of Example 2/2p.
New and improved solvers and preconditioners
--------------------------------------------
- Added support for parallel ILU preconditioning via hypre's Euclid solver.
- Added support for STRUMPACK v3 with a small API change in the class
STRUMPACKSolver, see "API changes" below.
Miscellaneous
-------------
- Added unit tests based on the Catch++ library in the test/ directory.
- Renamed the option MFEM_USE_OPENMP to MFEM_USE_LEGACY_OPENMP. This legacy
option is deprecated and planned for removal in a future release. The original
option name, MFEM_USE_OPENMP, is now used to enable the new OpenMP backends in
the new kernels.
- In SparseMatrix added the option to perform MultTranspose() by matvec with
computed and stored transpose matrix. This is required for deterministic
results when using devices such as CUDA and OpenMP.
- Altered the way FGMRES counts its iterations so that it matches GMRES.
- Various other simplifications, extensions, and bugfixes in the code.
- Construct abstract parallel rectangular truedof-to-truedof operators via
Operator::FormDiscreteOperator().
API changes
-----------
- In multiple places, use Geometry::Type instead of int, where appropriate.
- In multiple places, use Element::Type instead of int, where appropriate.
- The Mesh methods GetElementBaseGeometry and GetBdrElementBaseGeometry no
longer have a default value for their parameter, they only work with an
explicitly given index.
- In class Mesh, added methods useful for queries regarding the types of
elements present in the mesh: HasGeometry, GetNumGeometries, GetGeometries,
and class Mesh::GeometryList.
- The struct CoarseFineTransformations (returned by the Mesh method
GetRefinementTransforms) now stores the embedding matrices separately for each
Geometry::Type.
- In class ParMesh, replaced the method GroupNFaces with two new methods:
GroupNTriangles and GroupNQuadrilaterals. Also, replaced GroupFace with two
methods: GroupTriangle and GroupQuadrilateral.
- In class ParMesh, made the two RefineGroups methods protected.
- Removed the virtual method Element::GetRefinementFlag, it is only used by the
derived class Tetrahedron.
- Added new methods: Array::CopyTo, Tetrahedron::Init.
- In class STRUMPACKSolver, the method SetMC64Job() was replaced by the new
methods: DisableMatching(), EnableMatching(), and EnableParallelMatching().
Version 3.4, released on May 29, 2018
=====================================
+18 -82
View File
@@ -13,11 +13,6 @@ cmake_minimum_required(VERSION 2.8.11)
set(USER_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/config/user.cmake" CACHE PATH
"Path to optional user configuration file.")
# Require C++11 and disable compiler-specific extensions
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Load user settings before the defaults - this way the defaults will not
# overwrite the user set options. If the user has not set all options, we still
# have the defaults.
@@ -50,7 +45,7 @@ project(mfem NONE)
# Current version of MFEM, see also `makefile`.
# mfem_VERSION = (string)
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
set(${PROJECT_NAME}_VERSION 4.0.1)
set(${PROJECT_NAME}_VERSION 3.4.1)
# Prohibit in-source build
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
@@ -86,13 +81,6 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/config/XSDKDefaults.cmake")
# Enable languages.
enable_language(CXX)
if (MFEM_USE_CUDA)
# MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support)
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
enable_language(CUDA)
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
endif()
if (XSDK_ENABLE_C)
enable_language(C)
endif()
@@ -182,11 +170,12 @@ if (MFEM_USE_LAPACK)
endif()
# OpenMP
if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
if (NOT MFEM_THREAD_SAFE AND MFEM_USE_LEGACY_OPENMP)
message(FATAL_ERROR " *** MFEM_USE_LEGACY_OPENMP requires MFEM_THREAD_SAFE=ON.")
if (MFEM_USE_OPENMP)
if (MFEM_THREAD_SAFE)
find_package(OpenMP REQUIRED)
else()
message(FATAL_ERROR " *** MFEM_USE_OPENMP requires MFEM_THREAD_SAFE=ON.")
endif()
find_package(OpenMP REQUIRED)
endif()
# SuiteSparse (before SUNDIALS which may depend on KLU)
@@ -254,7 +243,7 @@ endif()
# Axom/Sidre
if (MFEM_USE_SIDRE)
find_package(Axom REQUIRED Axom)
find_package(Axom REQUIRED Sidre SLIC axom_utils)
endif()
# PUMI
@@ -273,31 +262,6 @@ if (MFEM_USE_PUMI)
endif()
endif()
# CUDA
if (MFEM_USE_CUDA)
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
set(CMAKE_CUDA_FLAGS "-arch=${CUDA_ARCH} --expt-extended-lambda"
CACHE STRING "CUDA flags set for MFEM" FORCE)
if (MFEM_USE_MPI)
set(CUDA_CCBIN_COMPILER ${MPI_CXX_COMPILER})
else()
set(CUDA_CCBIN_COMPILER ${CMAKE_CXX_COMPILER})
endif()
string(APPEND CMAKE_CUDA_FLAGS " -ccbin ${CUDA_CCBIN_COMPILER}")
endif()
# OCCA
if (MFEM_USE_OCCA)
find_package(OCCA REQUIRED)
endif()
# RAJA
if (MFEM_USE_RAJA)
find_package(RAJA REQUIRED)
endif()
# MFEM_TIMER_TYPE
if (NOT DEFINED MFEM_TIMER_TYPE)
if (APPLE)
@@ -323,7 +287,7 @@ endif()
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT GECKO GNUTLS NETCDF MPFR PUMI
POSIXCLOCKS MFEMBacktrace ZLIB OCCA RAJA)
POSIXCLOCKS MFEMBacktrace ZLIB)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
@@ -348,6 +312,9 @@ message(STATUS "MFEM build type: CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
message(STATUS "MFEM version: v${MFEM_VERSION_STRING}")
message(STATUS "MFEM git string: ${MFEM_GIT_STRING}")
# Windows specific
set(_USE_MATH_DEFINES ${WIN32})
#-------------------------------------------------------------------------------
# Define and configure the MFEM library
#-------------------------------------------------------------------------------
@@ -359,13 +326,6 @@ set(MFEM_SOURCE_DIRS general linalg mesh fem)
foreach(DIR IN LISTS MFEM_SOURCE_DIRS)
add_subdirectory(${DIR})
endforeach()
if (MFEM_USE_CUDA)
foreach(file IN LISTS SOURCES)
set_property(SOURCE ${file} PROPERTY LANGUAGE CUDA)
endforeach()
endif()
add_subdirectory(config)
set(MASTER_HEADERS
${PROJECT_SOURCE_DIR}/mfem.hpp
@@ -376,11 +336,6 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON CACHE BOOL "")
set(CMAKE_INSTALL_RPATH "${_lib_path}" CACHE PATH "")
set(CMAKE_INSTALL_NAME_DIR "${_lib_path}" CACHE PATH "")
set(MFEM_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
"The MFEM source directory" FORCE)
set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH
"The MFEM install directory" FORCE)
# Declaring the library
add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS})
# message(STATUS "TPL_LIBRARIES = ${TPL_LIBRARIES}")
@@ -395,11 +350,11 @@ endif()
set_target_properties(mfem PROPERTIES VERSION "${mfem_VERSION}")
set_target_properties(mfem PROPERTIES SOVERSION "${mfem_VERSION}")
# If building out-of-source, define MFEM_CONFIG_FILE to point to the config file
# inside the build directory.
# If building out-of-source, define MFEM_BUILD_DIR to point to the build
# directory.
if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
target_compile_definitions(mfem PRIVATE
"MFEM_CONFIG_FILE=\"${PROJECT_BINARY_DIR}/config/_config.hpp\"")
"MFEM_BUILD_DIR=${PROJECT_BINARY_DIR}")
endif()
# Generate configuration file in the build directory: config/_config.hpp.
@@ -415,7 +370,7 @@ if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
"Writing substitute header --> \"${Header}\"")
file(WRITE "${PROJECT_BINARY_DIR}/${Header}"
"// Auto-generated file.
#define MFEM_CONFIG_FILE \"${PROJECT_BINARY_DIR}/config/_config.hpp\"
#define MFEM_BUILD_DIR ${PROJECT_BINARY_DIR}
#include \"${PROJECT_SOURCE_DIR}/${Header}\"
")
# This version will be installed in the top include directory:
@@ -433,9 +388,6 @@ endif()
# Enable testing if required
if (MFEM_ENABLE_TESTING)
enable_testing()
set(MFEM_ALL_TESTS_TARGET_NAME tests)
add_mfem_target(${MFEM_ALL_TESTS_TARGET_NAME} OFF)
add_subdirectory(tests EXCLUDE_FROM_ALL)
endif()
# Define a target that all examples and miniapps will depend on.
@@ -455,9 +407,7 @@ add_subdirectory(miniapps EXCLUDE_FROM_ALL)
# Target to build all executables, i.e. everything.
add_custom_target(exec)
add_dependencies(exec
${MFEM_ALL_EXAMPLES_TARGET_NAME}
${MFEM_ALL_MINIAPPS_TARGET_NAME}
${MFEM_ALL_TESTS_TARGET_NAME})
${MFEM_ALL_EXAMPLES_TARGET_NAME} ${MFEM_ALL_MINIAPPS_TARGET_NAME})
# Here, we want to "add_dependencies(test exec)". However, dependencies for
# 'test' (and other built-in targets) can not be added with add_dependencies():
# - https://gitlab.kitware.com/cmake/cmake/issues/8438
@@ -478,12 +428,12 @@ endif()
# Add 'check' target - quick test
if (NOT MFEM_USE_MPI)
add_custom_target(check
${CMAKE_CTEST_COMMAND} -R \"^ex1_ser\" -C ${CMAKE_CFG_INTDIR}
${CMAKE_CTEST_COMMAND} -R '^ex1_ser' -C ${CMAKE_CFG_INTDIR}
USES_TERMINAL)
add_dependencies(check ex1)
else()
add_custom_target(check
${CMAKE_CTEST_COMMAND} -R \"^ex1p\" -C ${CMAKE_CFG_INTDIR}
${CMAKE_CTEST_COMMAND} -R '^ex1p' -C ${CMAKE_CFG_INTDIR}
USES_TERMINAL)
add_dependencies(check ex1p)
endif()
@@ -528,13 +478,6 @@ install(DIRECTORY ${MFEM_SOURCE_DIRS}
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem
FILES_MATCHING PATTERN "*.hpp")
# Install the okl files
if (MFEM_USE_OCCA)
install(DIRECTORY ${MFEM_SOURCE_DIRS}
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem
FILES_MATCHING PATTERN "*.okl")
endif()
# Install ${HEADERS}
# ---
# foreach (HDR ${HEADERS})
@@ -600,10 +543,3 @@ install(FILES
# Install the export set for use with the install-tree
install(EXPORT ${PROJECT_NAME_UC}Targets
DESTINATION ${INSTALL_CMAKE_DIR})
#-------------------------------------------------------------------------------
# Create 'config.mk' from 'config.mk.in' for the build and install locations and
# define install rules for 'config.mk' and 'test.mk'
#-------------------------------------------------------------------------------
mfem_export_mk_files()
+11 -28
View File
@@ -90,18 +90,13 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
├── general
├── linalg
├── mesh
── miniapps
├── common
├── electromagnetics
├── meshing
├── nurbs
├── performance
└── tools
└── tests
├── unit
│ ├── ...
└── ...
── miniapps
├── common
├── electromagnetics
├── meshing
├── nurbs
├── performance
└── tools
```
- The main directories are `fem/`, `mesh/` and `linalg/` containing the C++
@@ -142,16 +137,6 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
+ [`HypreParMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParMatrix.html) and [`HypreParVector`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParVector.html)
+ [`HypreSolver`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreSolver.html) and other [hypre classes](http://mfem.github.io/doxygen/html/hypre_8hpp.html)
- GPU and multi-core CPU support is based on device kernels supporting different
backends (CUDA, OCCA, RAJA, OpenMP, etc.) and an internal lightweight
device/host memory manager.
- The main device-relevant classes and sources are:
+ [`Device`](http://mfem.github.io/doxygen/html/device_8hpp.html)
+ [`MemoryManager`](http://mfem.github.io/doxygen/html/mem_manager_8hpp.html)
+ the [`MFEM_FORALL`](http://mfem.github.io/doxygen/html/forall_8hpp.html) macro
+ the [`cuda.hpp`](http://mfem.github.io/doxygen/html/cuda_8hpp.html) and [`occa.hpp`](http://mfem.github.io/doxygen/html/occa_8hpp.html) files
- The `general/` directory contains C++ classes that serve as utilities for
communication, error handling, arrays, (Boolean) tables, timing, etc.
@@ -166,9 +151,6 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
in the simple example codes and more fully-featured mini applications in the
`examples/` and `miniapps/` directories.
- The `tests/` directory contains a unit test suite and will later contain more
tests that run example codes.
- See also the [code overview](http://mfem.org/code-overview/) section on the
MFEM website.
@@ -334,9 +316,9 @@ Before a PR can be merged, it should satisfy the following:
- [ ] Is this a new feature users need to be aware of? New or updated example or miniapp?
- [ ] Does it make sense to create a new section in the `CHANGELOG` to group with other related features?
- [ ] Update `INSTALL`:
- [ ] Had a new optional library been added? (*Make sure the external library is licensed under LGPL, not GPL!*)
- [ ] Has a new optional library been added? (*Make sure the external library is licensed under LGPL, not GPL!*)
- [ ] Does `make` or `cmake` have a new target?
- [ ] Did the requirements or the installation process change? *(rare)*
- [ ] Did the requirements or the installation process change? *(rare)*.
- [ ] Update `.gitignore`:
- [ ] Check if `make distclean; git status` shows any files that are generated from the source but we don't want to track in the repository.
- [ ] Add new patterns (just for the new files above) and re-run the above test.
@@ -376,10 +358,10 @@ Before a PR can be merged, it should satisfy the following:
- [ ] If this is a major new feature, consider mentioning in the short summary inside `README` *(rare)*.
- [ ] List major new classes in `doc/CodeDocumentation.dox` *(rare)*.
- [ ] Update this checklist, if the new pull request affects it.
- [ ] Run the unit tests and make sure they all pass `make unittest`.
- [ ] (LLNL only) Clone the `tests` repository and run the following tests, see `mfem/tests/README.md`:
- [ ] `compilers`
- [ ] `memcheck`
- [ ] `unit-test`
- [ ] `documentation`
- [ ] (LLNL only) After merging:
- [ ] Regenerate `README.html` files from companion documentation pull requests.
@@ -490,6 +472,7 @@ MFEM uses a `master`/`next`-branch workflow as described below:
- `mfem:gh-next` -- Bleeding-edge development version, may be broken, use at
your own risk.
## Automated Testing
MFEM has several levels of automated testing running on GitHub, as well as on
+24 -135
View File
@@ -13,41 +13,14 @@ of MFEM is a (modern) C++ compiler, such as g++. The parallel version of MFEM
requires an MPI C++ compiler, as well as the following external libraries:
- hypre (a library of high-performance preconditioners)
https://github.com/hypre-space/hypre
http://www.llnl.gov/CASC/hypre
- METIS (a family of multilevel partitioning algorithms)
http://glaros.dtc.umn.edu/gkhome/metis/metis/overview
The hypre dependency can be downloaded as a tarball from GitHub or from the
project webpage https://www.llnl.gov/casc/hypre. For example, the 2.16.0 release
of hypre is available at
https://github.com/hypre-space/hypre/archive/v2.16.0.tar.gz
The METIS dependency can be disabled but that is not generally recommended, see
the option MFEM_USE_METIS.
MFEM also includes support for devices such as GPUs, and programming models such
as CUDA, HIP, OCCA, OpenMP and RAJA.
- Starting with version 4.0, MFEM requires a C++11 compiler
- CUDA support requires an NVIDIA GPU and an installation of the CUDA Toolkit
https://developer.nvidia.com/cuda-toolkit
- HIP support requires an AMD GPU and an installation of the ROCm software stack
https://rocm.github.io/ROCmInstall.html#installing-from-amd-rocm-repositories
- OCCA support requires the OCCA library
https://libocca.org
- OpenMP support requires a compiler implementing the OpenMP API
https://www.openmp.org
- RAJA support requires installation of the RAJA performance portability layer
with (optionally) support for CUDA and OpenMP
https://github.com/LLNL/RAJA
The library supports two build systems: one based on GNU make, and a second one
based on CMake. Both build systems are described below. Some hints for building
without GNU make or CMake can be found at the end of this file.
@@ -57,7 +30,7 @@ following package managers:
- Spack, https://github.com/spack/spack
- OpenHPC, http://openhpc.community
- Homebrew/Science, https://github.com/Homebrew/homebrew-science (deprecated)
- Homebrew/Science, https://github.com/Homebrew/homebrew-science
We also recommend downloading and building the MFEM-based GLVis visualization
tool which can be used to visualize the meshes and solution in MFEM's examples
@@ -69,19 +42,11 @@ Serial build:
make serial -j 4
Parallel build:
(download hypre and METIS 4 from above URLs)
(download hypre 2.10.0b and METIS 4 from above URLs)
(build METIS 4 in ../metis-4.0 relative to mfem/)
(build hypre in ../hypre relative to mfem/)
(build hypre 2.10.0b in ../hypre-2.10.0b relative to mfem/)
make parallel -j 4
CUDA build:
make cuda -j 4
(build for a specific compute capability: 'make cuda -j 4 CUDA_ARCH=sm_30')
HIP build:
make hip -j 4
(build for a specific AMD GPU chip: 'make hip -j 4 HIP_ARCH=gfx900')
Example codes (serial/parallel, depending on the build):
cd examples
make -j 4
@@ -92,6 +57,7 @@ Build everything (library, examples and miniapps) with current configuration:
Quick-check the build by running Example 1/1p (optional):
make check
Quick start with CMake
======================
Serial build:
@@ -100,19 +66,13 @@ Serial build:
make -j 4 (assuming "UNIX Makefiles" generator)
Parallel build:
(download hypre and METIS 4 from above URLs)
(download hypre 2.10.0b and METIS 4 from above URLs)
(build METIS 4 in ../metis-4.0 relative to mfem/)
(build hypre in ../hypre relative to mfem/)
(build hypre 2.10.0b in ../hypre-2.10.0b relative to mfem/)
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
cmake <mfem-source-dir> -DMFEM_USE_MPI=YES
make -j 4
CUDA build:
(this build requires CMake 3.8 or newer)
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
cmake <mfem-source-dir> -DMFEM_USE_CUDA=YES
make -j 4
Example codes (serial/parallel, depending on the build):
make examples -j 4
@@ -168,18 +128,10 @@ Note that re-configuration is only needed to change the currently configured
options. Several shortcut targets combining (re-)configuration and compilation
are also defined:
make serial -> Builds serial optimized version of the library
make parallel -> Builds parallel optimized version of the library
make debug -> Builds serial debug version of the library
make pdebug -> Builds parallel debug version of the library
make cuda -> Builds serial cuda optimized version of the library
make pcuda -> Builds parallel cuda optimized version of the library
make cudebug -> Builds serial cuda debug version of the library
make pcudebug -> Builds parallel cuda debug version of the library
make hip -> Builds serial hip optimized version of the library
make phip -> Builds parallel hip optimized version of the library
make hipdebug -> Builds serial hip debug version of the library
make phipdebug -> Builds parallel hip debug version of the library
make serial -> Builds serial optimized version of the library
make parallel -> Builds parallel optimized version of the library
make debug -> Builds serial debug version of the library
make pdebug -> Builds parallel debug version of the library
Note that any of the above shortcuts accept configuration options, either at the
command line or through a user configuration file.
@@ -241,9 +193,8 @@ Configuration options (GNU make)
See the configuration file config/defaults.mk for the default settings.
Compilers:
CXX - C++ compiler, serial build
MPICXX - MPI C++ compiler, parallel build
CUDA_CXX - The CUDA compiler, 'nvcc'
CXX - C++ compiler, serial build
MPICXX - MPI C++ compiler, parallel build
Compiler options:
OPTIM_FLAGS - Options for optimized build
@@ -279,7 +230,7 @@ MFEM_DEBUG = YES/NO
and consistency checks that may simplify bug-hunting.
MFEM_USE_EXCEPTIONS = YES/NO
Enable the use of exceptions. In particular, modifies the default behavior
Enable the use of exceptions. In particular, modifies the default bahavior
when errors are encountered: throw an exception, instead of aborting.
MFEM_USE_LIBUNWIND = YES/NO
@@ -299,12 +250,8 @@ MFEM_THREAD_SAFE = YES/NO
Use thread-safe implementation for some classes/methods. This comes at the
cost of extra memory allocation and de-allocation.
MFEM_USE_LEGACY_OPENMP = YES/NO
Enable (basic) experimental OpenMP support. Requires MFEM_THREAD_SAFE.
This option is deprecated.
MFEM_USE_OPENMP = YES/NO
Enable the OpenMP backend.
Enable (basic) experimental OpenMP support. Requires MFEM_THREAD_SAFE.
MFEM_USE_MEMALLOC = YES/NO
Internal MFEM option: enable batch allocation for some small objects.
@@ -383,11 +330,11 @@ MFEM_USE_MPFR = YES/NO
see below.
MFEM_USE_SIDRE = YES/NO
Sidre is a component of LLNL's axom project, https://github.com/LLNL/axom,
that provides an HDF5-based file format for visualization or restart
capability following the Conduit (https://github.com/LLNL/conduit) mesh
blueprint specification. When enabled, this option requires installation of
HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
Sidre is a component of LLNL's axom project, http://goo.gl/cZyJdn, that
provides an HDF5-based file format for visualization or restart capability
following the Conduit (https://github.com/LLNL/conduit) mesh blueprint
specification. When enabled, this option requires installation of HDF5 (see
also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
MFEM_USE_CONDUIT = YES/NO
Enables support for converting MFEM Mesh and Grid Function objects to and
@@ -415,33 +362,6 @@ MFEM_USE_PUMI = YES/NO
models and effectively supports automated adaptive analysis. PUMI enables
support for parallel unstructured mesh modifications in MFEM.
MFEM_USE_CUDA = YES/NO
Enables support for CUDA devices in MFEM. CUDA is a parallel computing
platform and programming model for general computing on graphical processing
units (GPUs). The variable CUDA_ARCH is used to specify the CUDA compute
capability used during compilation (by default, CUDA_ARCH=sm_60). When
enabled, this option uses the CUDA_* build options, see below.
MFEM_USE_HIP = YES/NO
Enables support for AMD devices in MFEM. HIP is a heterogeneous-compute
interface for portability developed by AMD that can target both AMD and
NVIDIA GPUs. The variable HIP_ARCH is used to specify the AMD GPU processor
used during compilation (by default, HIP_ARCH=gfx900). When enabled, this
option uses the HIP_* build options, see below.
MFEM_USE_RAJA = YES/NO
Enable support for the RAJA performance portability layer in MFEM. RAJA
provides a portable abstraction for loops, supporting different programming
model backends. When using RAJA built with CUDA support, CUDA support must be
also enabled in MFEM, i.e. MFEM_USE_CUDA=YES must be set.
MFEM_USE_OCCA = YES/NO
Enables support for the OCCA library in MFEM. OCCA is an open-source library
which aims to make it easy to program different types of devices (e.g. CPU,
GPU, FPGA) by providing an unified API for interacting with JIT-compiled
backends. In order to use the OCCA CUDA backend, CUDA support must be enabled
in MFEM as well, i.e. MFEM_USE_CUDA=YES must be set.
MFEM_BUILD_TAG = (any value)
An optional tag to characterize the build. Exported to config/config.mk.
Can be used to identify the MFEM build from other makefiles.
@@ -463,7 +383,7 @@ directory and use the string @MFEM_DIR@, e.g. HYPRE_OPT = -I@MFEM_DIR@/../hypre.
The specific libraries and their options are:
- HYPRE, required for the parallel build, i.e. when MFEM_USE_MPI = YES.
URL: https://github.com/hypre-space/hypre and https://www.llnl.gov/casc/hypre
URL: http://www.llnl.gov/CASC/hypre
Options: HYPRE_OPT, HYPRE_LIB.
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
@@ -477,8 +397,7 @@ The specific libraries and their options are:
http://math-atlas.sourceforge.net (ATLAS)
Options: LAPACK_OPT (currently not used/needed), LAPACK_LIB.
- OpenMP (optional), usually part of compiler, used when either MFEM_USE_OPENMP
or MFEM_USE_LEGACY_OPENMP is set to YES.
- OpenMP (optional), usually part of compiler, used when MFEM_USE_OPENMP = YES.
Options: OPENMP_OPT, OPENMP_LIB.
- High-resolution POSIX clocks: when using MFEM_TIMER_TYPE = 2, it may be
@@ -488,7 +407,6 @@ The specific libraries and their options are:
- SUNDIALS (optional), used when MFEM_USE_SUNDIALS = YES.
Beginning with MFEM v3.3, SUNDIALS v2.7.0 is supported.
Beginning with MFEM v3.3.2, SUNDIALS v3.0.0 is also supported.
Beginning with MFEM v4.1, only SUNDIALS v5.0.0+ is supported.
If MFEM_USE_MPI is enabled, we expect that SUNDIALS is built with support for
both MPI and hypre.
URL: http://computation.llnl.gov/projects/sundials/sundials-software
@@ -511,8 +429,7 @@ The specific libraries and their options are:
- STRUMPACK (optional), used when MFEM_USE_STRUMPACK = YES. Note that STRUMPACK
requires the PT-Scotch and Scalapack libraries as well as ParMETIS, which
includes METIS 5 in its distribution. Starting with STRUMPACK v2.2.0, ParMETIS
and PT-Scotch are optional dependencies.
includes METIS 5 in its distribution.
The support for STRUMPACK was added in MFEM v3.3.2 and it requires STRUMPACK
2.0.0 or later.
URL: http://portal.nersc.gov/project/sparse/strumpack
@@ -543,8 +460,7 @@ The specific libraries and their options are:
Options: PETSC_OPT, PETSC_LIB.
- Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES.
Starting with MFEM v4.1, Axom version 0.3.1 or later is required.
URL: https://github.com/LLNL/axom
URL: http://goo.gl/cZyJdn (axom, to be released)
https://github.com/LLNL/conduit (Conduit)
https://support.hdfgroup.org/HDF5 (HDF5)
Options: SIDRE_OPT, SIDRE_LIB.
@@ -559,23 +475,6 @@ The specific libraries and their options are:
URL: https://scorec.rpi.edu/pumi
Options: PUMI_OPT, PUMI_LIB.
- CUDA, used when MFEM_USE_CUDA = YES.
URL: https://developer.nvidia.com/cuda-toolkit
Options: CUDA_CXX, CUDA_ARCH, CUDA_OPT, CUDA_LIB.
- HIP, used when MFEM_USE_HIP = YES.
URL: https://rocm.github.io/ROCmInstall.html
Options: HIP_CXX, HIP_ARCH, HIP_OPT, HIP_LIB.
- OCCA, used when MFEM_USE_OCCA = YES.
URL: https://libocca.org
Options: OCCA_DIR, OCCA_OPT, OCCA_LIB.
- RAJA, used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
URL: https://github.com/LLNL/RAJA
Options: RAJA_DIR, RAJA_OPT, RAJA_LIB.
- MPFR (optional), used when MFEM_USE_MPFR = YES.
URL: http://mpfr.org, it depends on the GMP library: https://gmplib.org
Options: MPFR_OPT, MPFR_LIB.
@@ -680,8 +579,6 @@ Configuration variables (CMake)
===============================
See the configuration file config/defaults.cmake for the default settings.
Note: the option MFEM_USE_CUDA requires CMake version 3.8 or newer!
Non-standard CMake variables for compilers:
CXX - If set, overwrite the auto-detected C++ compiler, serial build
MPICXX - If set, overwrite the auto-detected MPI C++ compiler, parallel build
@@ -699,7 +596,6 @@ MFEM_USE_METIS - Set to ${MFEM_USE_MPI}, can be overwritten.
MFEM_USE_LIBUNWIND
MFEM_USE_LAPACK
MFEM_THREAD_SAFE
MFEM_USE_LEGACY_OPENMP
MFEM_USE_OPENMP
MFEM_USE_MEMALLOC
MFEM_TIMER_TYPE - Set automatically, can be overwritten.
@@ -712,10 +608,6 @@ MFEM_USE_NETCDF
MFEM_USE_MPFR
MFEM_USE_GZSTREAM
MFEM_USE_PUMI
MFEM_USE_CUDA
MFEM_USE_OCCA
MFEM_USE_RAJA
MFEM_USE_SIDRE
The following options are CMake specific:
@@ -762,9 +654,6 @@ The CMake build system adds auto-detection for the following packages/libraries:
- LIBUNWIND
- POSIXCLOCKS
- PUMI
- OCCA
- RAJA
- AXOM - Used when MFEM_USE_SIDRE is enabled
The following built-in CMake packages are also used:
+11 -11
View File
@@ -1,5 +1,5 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@@ -10,7 +10,7 @@
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
@@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
@@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@@ -455,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
@@ -485,8 +485,7 @@ convey the exclusion of warranty; and each file should have at least the
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
@@ -495,10 +494,11 @@ school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+16 -17
View File
@@ -8,9 +8,9 @@
http://mfem.org
MFEM is a modular parallel C++ library for finite element methods. Its goal is
to enable high-performance scalable finite element discretization research and
application development on a wide variety of platforms, ranging from laptops to
supercomputers.
to enable the research and development of scalable finite element discretization
and solver algorithms through general finite element abstractions, accurate and
flexible visualization, and tight integration with the hypre library.
* For building instructions, see the file INSTALL, or type "make help".
@@ -39,24 +39,23 @@ conforming and non-conforming (AMR) adaptive refinement. Arbitrary element
transformations, allowing for high-order mesh elements with curved boundaries,
are also supported.
When used as a "finite element to linear algebra translator", MFEM can take a
problem described in terms of finite element-type objects, and produce the
corresponding linear algebra vectors and fully or partially assembled operators,
e.g. in the form of global sparse matrices or matrix-free operators. The library
includes simple smoothers and Krylov solvers, such as PCG, MINRES and GMRES, as
well as support for sequential sparse direct solvers from the SuiteSparse
MFEM is commonly used as a "finite element to linear algebra translator", since
it can take a problem described in terms of finite element-type objects, and
produce the corresponding linear algebra vectors and sparse matrices. In order
to facilitate this, MFEM uses compressed sparse row (CSR) sparse matrix storage
and includes simple smoothers and Krylov solvers, such as PCG, MINRES and GMRES,
as well as support for sequential sparse direct solvers from the SuiteSparse
library. Nonlinear solvers (the Newton method), eigensolvers (LOBPCG), and
several explicit and implicit Runge-Kutta time integrators are also available.
MFEM supports MPI-based parallelism throughout the library, and can readily be
used as a scalable unstructured finite element problem generator. As of version
4.0, MFEM offers initial support for GPU acceleration, and programming models,
such as CUDA, OCCA, RAJA and OpenMP. MFEM-based applications require minimal
changes to switch from a serial to a high-performing MPI-parallel version of the
code, where they can take advantage of the integrated linear solvers from the
hypre library. Comprehensive support for other external packages, e.g. PETSc
and SUNDIALS is also included, giving access to many additional linear and
nonlinear solvers, preconditioners, time integrators, etc.
used as a scalable unstructured finite element problem generator. MFEM-based
applications require minimal changes to transition from a serial to a
high-performing parallel version of the code, where they can take advantage of
the integrated scalable linear solvers from the hypre library. Comprehensive
support for other external packages, e.g. PETSc and SUNDIALS is also included,
giving access to many additional linear and nonlinear solvers, preconditioners,
time integrators, etc.
For examples of using MFEM, see the examples/ and miniapps/ directories, as well
as the OpenGL visualization tool GLVis which is available at http://glvis.org.
@@ -9,5 +9,19 @@
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
#ifndef MFEM_BACKENDS_ALL_HPP
#define MFEM_BACKENDS_ALL_HPP
#include "../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "base/backend.hpp"
#ifdef MFEM_USE_OCCA
#include "occa/backend.hpp"
#endif
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_ALL_HPP
+213
View File
@@ -0,0 +1,213 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_ARRAY_HPP
#define MFEM_BACKENDS_BASE_ARRAY_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "layout.hpp"
#include "utils.hpp"
namespace mfem
{
/// Extension to the template class Array<T>
class PArray : public RefCounted
{
protected:
/// Layout with shared ownership (smart pointer)
DLayout layout;
/**
@name Virtual interface
*/
///@{
/** @brief Create and return a new array (in @a *clone) of the same dynamic
type as this array using the same layout and ItemSize().
Set @a *clone to NULL if allocation fails.
If @a copy_data is true, the contents of this array is copied to the new
array; otherwise, the new array remains uninitialized.
If @a buffer is not NULL, return the array data of the newly created
object (in @a *buffer) , if it is stored as a contiguous array on the
host; otherwise, set @a *buffer to NULL. */
virtual PArray *DoClone(bool copy_data, void **buffer,
std::size_t item_size) const = 0;
/// Resize the array, reallocating its data if necessary.
/** If @a buffer is not NULL, return the array data (in @a *buffer), if it
is stored as a contiguous array on the host; otherwise, set @a *buffer to
NULL. Returns 0 on success and non-zero otherwise, e.g. if memory
allocation fails.
If the @a new_layout is not supported, a non-zero error code will be
returned.
The @a new_layout has to be valid, i.e. new_layout != NULL and
new_layout->HasEngine() == true.
@note If reallocation is performed, the previous content of the array is
NOT copied to the new location. */
virtual int DoResize(PLayout &new_layout, void **buffer,
std::size_t item_size) = 0;
/** @brief Get access to the contents of the array in host memory, as a
contiguous array. */
/** If the array data is stored as a contiguous array in host memory, return
a pointer to it. Otherwise, copy the data to @a buffer (if @a buffer is
not NULL) and return @a buffer.
@note If not NULL, @a buffer is assumed to be of size greater than or
equal to Size(). */
virtual void *DoPullData(void *buffer, std::size_t item_size) = 0;
/** @brief Set all entries of the array to the (single) value pointed to by
@a value_ptr. */
virtual void DoFill(const void *value_ptr, std::size_t item_size) = 0;
/** @brief Set all Size() entries of the array from the given contiguous
array, @a src_buffer, on the host. */
virtual void DoPushData(const void *src_buffer, std::size_t item_size) = 0;
/// Copy the data from @a src to @a *this.
/** Both arrays must have the same dynamic type, layout, and item_size. */
virtual void DoAssign(const PArray &src, std::size_t item_size) = 0;
///@}
// End: Virtual interface
public:
/** @brief The @a layout parameter will be reference counted and therefore it
should be dynamically allocated. */
/** The @a layout must be valid in the sense that layout != NULL and
layout->HasEngine() == true. */
PArray(PLayout &p_layout)
: layout(&p_layout)
{
MFEM_ASSERT(layout && layout->HasEngine(), "invalid layout");
}
virtual ~PArray() { }
/// Get the current size of the array.
std::size_t Size() const { return layout->Size(); }
/// Get the current layout of the array.
PLayout &GetLayout() const { return *layout; }
/// TODO
/// Note: we cannot use static_cast for class PArray.
template <typename derived_t>
derived_t &As() { return dynamic_cast<derived_t&>(*this); }
/// TODO
/// Note: we cannot use static_cast for class PArray.
template <typename derived_t>
const derived_t &As() const { return dynamic_cast<const derived_t&>(*this); }
// TODO: Error handling ... handle errors at the Engine level, at the class
// level, or at the method level?
// TODO: Asynchronous execution interface ...
/**
@name Public virtual interface
*/
///@{
/** @brief Create and return a new array (in @a *clone) of the same dynamic
type as this array using the same layout and ItemSize().
Set @a *clone to NULL if allocation fails.
If @a copy_data is true, the contents of this array is copied to the new
array; otherwise, the new array remains uninitialized.
If @a buffer is not NULL, return the array data of the newly created
object (in @a *buffer) , if it is stored as a contiguous array on the
host; otherwise, set @a *buffer to NULL. */
template <typename T>
DArray Clone(bool copy_data, T **buffer) const
{ return DArray(DoClone(copy_data, (void**)buffer, sizeof(T))); }
/// Resize the array, reallocating its data if necessary.
/** If @a buffer is not NULL, return the array data (in @a *buffer), if it
is stored as a contiguous array on the host; otherwise, set @a *buffer to
NULL. Returns 0 on success and non-zero otherwise, e.g. if memory
allocation fails.
If the @a new_layout is not supported, a non-zero error code will be
returned.
The @a new_layout has to be valid, i.e. new_layout != NULL and
new_layout->HasEngine() == true.
@note If reallocation is performed, the previous content of the array is
NOT copied to the new location. */
template <typename T>
int Resize(PLayout &new_layout, T **buffer)
{ return DoResize(new_layout, (void**)buffer, sizeof(T)); }
/// Shortcut for Resize(*layout, buffer).
/** This method is useful for updating the array after its layout is changed
externally. */
template <typename T>
int Update(T **buffer)
{ return DoResize(*layout, (void**)buffer, sizeof(T)); }
/// Shortcut for layout->Resize(new_size) followed by Update()
template <typename T>
int Resize(std::size_t new_size, T **buffer)
{ layout->Resize(new_size); return Update(buffer); }
/** @brief Get access to the contents of the array in host memory, as a
contiguous array. */
/** If the array data is stored as a contiguous array in host memory, return
a pointer to it. Otherwise, copy the data to @a buffer (if @a buffer is
not NULL) and return @a buffer.
@note If not NULL, @a buffer is assumed to be of size greater than or
equal to Size(). */
template <typename T>
T *PullData(T *buffer)
{ return Size() ? (T*)DoPullData((void*)buffer, sizeof(T)) : NULL; }
/** @brief Set all entries of the array to the (single) value pointed to by
@a value_ptr. */
template <typename T>
void Fill(const T &value) { if (Size()) { DoFill(&value, sizeof(T)); } }
/** @brief Set all Size() entries of the array from the given contiguous
array, @a src_buffer, on the host. */
template <typename T>
void PushData(const T *src_buffer)
{ if (Size()) { DoPushData(src_buffer, sizeof(T)); } }
/// Copy the data from @a src to @a *this.
/** Both arrays must have the same dynamic type, layout, and entry type. */
template <typename T>
void Assign(const PArray &src) { if (Size()) { DoAssign(src, sizeof(T)); } }
///@}
// End: Virtual interface
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_ARRAY_HPP
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_BACKEND_HPP
#define MFEM_BACKENDS_BASE_BACKEND_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "memory_resource.hpp"
#include "engine.hpp"
#include "array.hpp"
#include "vector.hpp"
#include "fespace.hpp"
#include "bilinearform.hpp"
#include <string>
#ifdef MFEM_USE_MPI
#include <mpi.h>
#endif
namespace mfem
{
/// TODO
class Backend
{
public:
/// TODO
virtual ~Backend() { }
/// TODO
virtual bool Supports(const std::string &engine_spec) const = 0;
/// TODO
virtual Engine *Create(const std::string &engine_spec) = 0;
#ifdef MFEM_USE_MPI
/// TODO
virtual Engine *Create(MPI_Comm comm, const std::string &engine_spec) = 0;
#endif
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_BACKEND_HPP
+72
View File
@@ -0,0 +1,72 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_BILINEARFORM_HPP
#define MFEM_BACKENDS_BASE_BILINEARFORM_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "engine.hpp"
namespace mfem
{
class Vector;
class OperatorHandle;
class BilinearForm;
/// TODO: doxygen
class PBilinearForm : public RefCounted
{
protected:
/// Engine with shared ownership
SharedPtr<const Engine> engine;
/// Not owned.
BilinearForm *bform;
public:
/// TODO: doxygen
PBilinearForm(const Engine &e, BilinearForm &bf)
: engine(&e), bform(&bf) { }
/// Virtual destructor
virtual ~PBilinearForm() { }
/// Get the associated Engine
const Engine &GetEngine() const { return *engine; }
/// Assemble the PBilinearForm.
/** This method is called from the method BilinearForm::Assemble() of the
associated BilinearForm #bform.
@returns True, if the host assembly should be skipped. */
virtual bool Assemble() = 0;
/// TODO: doxygen
virtual void FormSystemMatrix(const Array<int> &ess_tdof_list,
OperatorHandle &A) = 0;
/// TODO: doxygen
virtual void FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior) = 0;
/// TODO: doxygen
virtual void RecoverFEMSolution(const Vector &X, const Vector &b,
Vector &x) = 0;
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_BILINEARFORM_HPP
+49
View File
@@ -0,0 +1,49 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "engine.hpp"
#include "fespace.hpp"
#include "bilinearform.hpp"
namespace mfem
{
Engine::Engine(Backend *b, int n_mem, int n_workers)
: backend(b),
#ifdef MFEM_USE_MPI
comm(MPI_COMM_NULL),
#endif
num_mem_res(n_mem),
num_workers(n_workers),
memory_resources(new MemoryResource*[num_mem_res]()),
workers_weights(new double[num_workers]()),
workers_mem_res(new int[num_workers]())
{
// Note: all arrays are value-initialized with zeros.
}
Engine::~Engine()
{
delete [] workers_mem_res;
delete [] workers_weights;
for (int i = 0; i < num_mem_res; i++)
{
delete memory_resources[i];
}
delete [] memory_resources;
}
} // namespace mfem
#endif // MFEM_USE_BACKENDS
+190
View File
@@ -0,0 +1,190 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_ENGINE_HPP
#define MFEM_BACKENDS_BASE_ENGINE_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "../../general/scalars.hpp"
#include "memory_resource.hpp"
#include "smart_pointers.hpp"
#include "utils.hpp"
#ifdef MFEM_USE_MPI
#include <mpi.h>
#endif
namespace mfem
{
// Forward declarations.
class Backend;
template <typename T> class Array;
class Operator;
class FiniteElementSpace;
class LinearForm;
class BilinearForm;
class MixedBilinearForm;
class NonlinearForm;
/// In parallel, each MPI rank will usually create a single engine.
class Engine : public RefCounted
{
protected:
Backend *backend; ///< Backend that created the engine. Not owned.
#ifdef MFEM_USE_MPI
MPI_Comm comm; ///< Associated MPI communicator (may be MPI_COMM_NULL).
#endif
/// Number of memory resources used by the Engine.
int num_mem_res;
/// Number of workers used by the Engine.
int num_workers;
/// Memory resources used by the engine - array of pointers.
/** Both the array and the entries are owned. */
MemoryResource **memory_resources;
/// Relative computational speed of the workers. Owned.
double *workers_weights;
/// For each worker, which memory resource it uses.
int *workers_mem_res;
public:
/// TODO: doxygen
Engine(Backend *b, int n_mem, int n_workers);
/// TODO: doxygen
virtual ~Engine();
/**
@name Machine resources interface
*/
///@{
#ifdef MFEM_USE_MPI
/// Get the associated MPI_Comm
MPI_Comm GetComm() const { return comm; }
#endif
/// TODO
int GetNumMemRes() const { return num_mem_res; }
/// TODO
MemoryResource &GetMemRes(int idx) const { return *memory_resources[idx]; }
/// TODO
int GetNumWorkers() const { return num_workers; }
/// TODO
const double *GetWorkersWeights() const { return workers_weights; }
/// TODO
const int *GetWorkersMemRes() const { return workers_mem_res; }
///@}
// End: Machine resources interface
/// TODO
template <typename derived_t>
derived_t &As() { return *util::As<derived_t>(this); }
/// TODO
template <typename derived_t>
const derived_t &As() const { return *util::As<const derived_t>(this); }
// TODO: Error handling ... handle errors at the Engine level, at the class
// level, or at the method level?
/**
@name Virtual interface: finite element data structures and algorithms
*/
///@{
// TODO: Asynchronous execution in this class ...
/// Allocate and return a new layout for the given @a size.
/** The layout decomposition (in the case of multiple workers) is determined
automatically by the Engine using a deterministic algorithm: calls to
this method with the same @a size will produce the same result, as long
as the Engine remains unmodified between the calls.
The returned object is allocated with operator new and must be
deallocated by the caller.
TODO: Returns NULL if memory allocation fails?
*/
virtual DLayout MakeLayout(std::size_t size) const = 0;
/// Allocate and return a new layout for the given worker decomposition.
/** The returned object is allocated with operator new and must be
deallocated by the caller.
TODO: Returns NULL if memory allocation fails?
The @a offsets should satisfy: offsets.Size() == number of workers + 1,
offsets[0] == 0, and offsets[i] <= offsets[i+1], for i: 0 <= i < number
of workers. */
virtual DLayout MakeLayout(const Array<std::size_t> &offsets) const = 0;
// Note: There may be other ways to construct layouts in the future, e.g.
// block-vector layouts, or multi-vector layouts.
/// TODO
virtual DArray MakeArray(PLayout &layout, std::size_t item_size) const = 0;
/// Allocate and return a new vector using the given @a layout.
/** The returned object is a smart pointer that will automatically deallocate
the vector.
TODO: Produce an error if memory allocation fails?
Only layouts returned by this Engine are guaranteed to be supported.
Using a type that is not supported will produce an error. */
virtual DVector MakeVector(PLayout &layout,
int type_id = ScalarId<double>::value) const = 0;
/// TODO: doxygen
virtual DFiniteElementSpace MakeFESpace(FiniteElementSpace &fes) const = 0;
/// TODO: doxygen
virtual DBilinearForm MakeBilinearForm(BilinearForm &bf) const = 0;
// Question: How do we construct coefficients?
/// FIXME - What will the actual parameters be?
virtual void AssembleLinearForm(LinearForm &l_form) const = 0;
/// FIXME - What will the actual parameters be?
virtual Operator *MakeOperator(const MixedBilinearForm &mbl_form) const = 0;
/// FIXME - What will the actual parameters be?
virtual Operator *MakeOperator(const NonlinearForm &nl_form) const = 0;
///@}
// End: Virtual interface
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_ENGINE_HPP
+98
View File
@@ -0,0 +1,98 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_FE_SPACE_HPP
#define MFEM_BACKENDS_BASE_FE_SPACE_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "engine.hpp"
#include "utils.hpp"
namespace mfem
{
class FiniteElementSpace;
class QuadratureSpace;
/// TODO: doxygen
class PFiniteElementSpace : public RefCounted
{
protected:
/// Engine with shared ownership
SharedPtr<const Engine> engine;
/// Not owned.
mfem::FiniteElementSpace *fes;
public:
/// TODO: doxygen
PFiniteElementSpace(const Engine &e, mfem::FiniteElementSpace &fespace)
: engine(&e), fes(&fespace) { }
/// Virtual destructor
virtual ~PFiniteElementSpace() { }
/// Get the associated engine
const Engine &GetEngine() const { return *engine; }
/// Return the associated mfem::FiniteElementSpace
mfem::FiniteElementSpace *GetFESpace() const { return fes; }
/// TODO
template <typename derived_t>
derived_t &As() { return *util::As<derived_t>(this); }
/// TODO
template <typename derived_t>
const derived_t &As() const { return *util::As<const derived_t>(this); }
/**
@name Virtual interface: finite element space functionality
*/
///@{
/// TODO
/** Return the operator mapping T-vectors to L-vectors. If a NULL pointer is
returned then the mapping is the idenity. */
virtual const mfem::Operator *GetProlongationOperator() const = 0;
/// TODO
/** Return the operator mapping L-vectors to T-vectors that extracts the
subset of all true dofs, i.e. no assembly is performed. If a NULL pointer
is returned then the mapping is the idenity. */
virtual const mfem::Operator *GetRestrictionOperator() const = 0;
/// TODO
/** Return the operator mapping L-vectors to Q-vectors that evaluates the
values of a GridFunction as a QuadratureFunction on the given
QuadratureSpace. If the returned pointer is NULL, then the mapping is the
identity. */
virtual const mfem::Operator *GetInterpolationOperator(
const mfem::QuadratureSpace &qspace) const = 0;
/// TODO
/** Return the operator mapping L-vectors to Q-vectors that evaluates the
_reference element_ gradients of a GridFunction as a QuadratureFunction
on the given QuadratureSpace. */
virtual const mfem::Operator *GetGradientOperator(
const mfem::QuadratureSpace &qspace) const = 0;
///@}
// End: Virtual interface
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_FE_SPACE_HPP
+110
View File
@@ -0,0 +1,110 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_LAYOUT_HPP
#define MFEM_BACKENDS_BASE_LAYOUT_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "smart_pointers.hpp"
#include "engine.hpp"
namespace mfem
{
/// Polymorphic layout (array/vector layout descriptor)
class PLayout : public RefCounted
{
protected:
/// Engine with shared ownership
SharedPtr<const Engine> engine;
std::size_t size;
template <typename DObject>
struct Maker
{
template <typename entry_t>
static DObject MakeNew(PLayout &layout);
};
public:
explicit PLayout(std::size_t s = 0) : engine(NULL), size(s) { }
explicit PLayout(const Engine &e, std::size_t s = 0)
: engine(&e), size(s) { }
virtual ~PLayout() { }
/**
@name Virtual interface
*/
///@{
/// Resize the layout
virtual void Resize(std::size_t new_size) { size = new_size; }
/// Resize the layout based on the given worker offsets
virtual void Resize(const Array<std::size_t> &offsets)
{ MFEM_ABORT("method not supported"); }
///@}
// End: Virtual interface
/// Layouts without engine cannot create DArray, DVector, etc.
bool HasEngine() const { return engine != NULL; }
/// TODO: doxygen
const Engine &GetEngine() const { return *engine; }
/// TODO: doxygen
std::size_t Size() const { return size; }
/// TODO
/** Useful in backends for down-casting to a backend-specific layout type.
When MFEM_DEBUG=YES, performs a type check using dynamic_cast. */
template <typename derived_t>
derived_t &As() { return *util::As<derived_t>(this); }
/// TODO
/** Useful in backends for down-casting to a backend-specific layout type.
When MFEM_DEBUG=YES, performs a type check using dynamic_cast. */
template <typename derived_t>
const derived_t &As() const { return *util::As<const derived_t>(this); }
/// TODO: doxygen
template <typename DObject, typename entry_t>
DObject Make()
{
MFEM_ASSERT(HasEngine(), "this method requires an Engine");
return Maker<DObject>::template MakeNew<entry_t>(*this);
}
};
template <> struct PLayout::Maker<DArray>
{
template <typename entry_t> static DArray MakeNew(PLayout &layout)
{ return layout.GetEngine().MakeArray(layout, sizeof(entry_t)); }
};
template <> struct PLayout::Maker<DVector>
{
template <typename entry_t> static DVector MakeNew(PLayout &layout)
{ return layout.GetEngine().MakeVector(layout, ScalarId<entry_t>::value); }
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_LAYOUT_HPP
+59
View File
@@ -0,0 +1,59 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "memory_resource.hpp"
#include "../../general/error.hpp"
#include <cstdlib>
#include <cstring>
#include <cerrno>
namespace mfem
{
void *NewDeleteMemoryResource::DoAllocate(std::size_t bytes,
std::size_t alignment)
{
void *p = ::operator new[](bytes);
MFEM_VERIFY(!alignment || (std::size_t)(p) % alignment == 0,
"invalid alignment");
return p;
}
void NewDeleteMemoryResource::DoDeallocate(void *p, std::size_t bytes,
std::size_t alignment)
{
::operator delete[](p);
}
void *AlignedMemoryResource::DoAllocate(std::size_t bytes,
std::size_t alignment)
{
void *p;
if (!alignment) { alignment = sizeof(long double); }
MFEM_VERIFY(posix_memalign(&p, alignment, bytes) == 0,
"error in posix_memalign(): " << strerror(errno));
return p;
}
void AlignedMemoryResource::DoDeallocate(void *p, std::size_t bytes,
std::size_t alignment)
{
free(p);
}
} // namespace mfem
#endif // MFEM_USE_BACKENDS
+70
View File
@@ -0,0 +1,70 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_MEMORY_RESOURCE_HPP
#define MFEM_BACKENDS_BASE_MEMORY_RESOURCE_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include <cstddef>
namespace mfem
{
/// Polymorphic memory resource. Similar to C++17's std::pmr::memory_resource.
class MemoryResource
{
protected:
virtual void *DoAllocate(std::size_t bytes, std::size_t alignment) = 0;
virtual void DoDeallocate(void* p, std::size_t bytes,
std::size_t alignment) = 0;
public:
// Implicitly defined default & copy constructors
/// Virtual destructor.
virtual ~MemoryResource() { }
/// If alignment == 0, use default alignment.
void *Allocate(std::size_t bytes, std::size_t alignment = 0)
{ return DoAllocate(bytes, alignment); }
/// If alignment == 0, use default alignment.
void Deallocate(void *p, std::size_t bytes, std::size_t alignment = 0)
{ DoDeallocate(p, bytes, alignment); }
};
/** @brief Dynamic host memory resource using operator new[](std::size_t) for
allocation and operator delete[](void*) for deallocation. */
class NewDeleteMemoryResource : public MemoryResource
{
protected:
virtual void *DoAllocate(std::size_t bytes, std::size_t alignment);
virtual void DoDeallocate(void *p, std::size_t bytes, std::size_t alignment);
};
/** @brief Dynamic host memory resource using posix_memalign() for aligned
allocation and free() for deallocation. */
class AlignedMemoryResource : public MemoryResource
{
protected:
virtual void *DoAllocate(std::size_t bytes, std::size_t alignment);
virtual void DoDeallocate(void *p, std::size_t bytes, std::size_t alignment);
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_MEMORY_RESOURCE_HPP
+234
View File
@@ -0,0 +1,234 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_SMART_POINTERS_HPP
#define MFEM_BACKENDS_BASE_SMART_POINTERS_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "utils.hpp"
#include "../../general/error.hpp"
#include <cstddef>
// #define MFEM_TRACE_SHARED_PTR
#ifdef MFEM_TRACE_SHARED_PTR
#include "../../general/globals.hpp"
#endif
namespace mfem
{
/// Base class for classes with simple reference counting.
/** Reference counting is performed by the class SharedPtr. */
class RefCounted
{
private:
mutable unsigned ref_count;
/// Only class SharedPtr can access ref_count.
template <typename T> friend class SharedPtr;
public:
RefCounted() : ref_count(0) { }
/** @brief Prevent SharedPtr objects from deleting this object by
incrementing the reference counter by one. */
void DontDelete() const { ++ref_count; }
};
/** @brief Smart pointer class that manages objects of type T derived from class
RefCounted. */
/** This class is generally meant to work with dynamically allocated object,
specifically objects allocated with operator new(). It will invoke operator
delete() to destroy the managed object when its reference counter reaches
zero. This behavior can be overriden by calling RefCounted::DontDelete() to
ensure that an object will not be deleted by a SharedPtr that holds a
pointer to it.
@note This class is NOT thread-safe and does not support circular ownership.
*/
template <typename T>
class SharedPtr
{
public:
typedef T stored_type;
private:
T *ptr;
void Init(T *new_ptr)
{
ptr = new_ptr;
if (ptr) { ++ptr->RefCounted::ref_count; }
#ifdef MFEM_TRACE_SHARED_PTR
#elif 0
mfem::out << " [" << _MFEM_FUNC_NAME << "]: ptr = " << ptr;
if (ptr)
{
mfem::out << ", new ref_count = " << ptr->RefCounted::ref_count;
}
mfem::out << '\n';
#endif
}
void Destroy()
{
MFEM_ASSERT(!ptr || ptr->RefCounted::ref_count >= 1, "invalid use");
if (ptr && --ptr->RefCounted::ref_count == 0) { delete ptr; }
#ifdef MFEM_TRACE_SHARED_PTR
#elif 0
mfem::out << " [" << _MFEM_FUNC_NAME << "]: ptr = " << ptr;
if (ptr)
{
mfem::out << ", new ref_count = " << ptr->RefCounted::ref_count;
}
mfem::out << '\n';
#endif
}
public:
SharedPtr() : ptr(NULL)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]: ptr = " << ptr << '\n';
#endif
}
SharedPtr(const SharedPtr &other)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Init(other.ptr);
}
template <typename U>
SharedPtr(const SharedPtr<U> &other)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Init(other.Get());
}
explicit SharedPtr(T *p)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Init(p);
}
~SharedPtr()
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Destroy();
}
SharedPtr &operator=(const SharedPtr &other)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Reset(other.ptr); return *this;
}
template <typename U>
SharedPtr &operator=(const SharedPtr<U> &other)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Reset(other.Get()); return *this;
}
T &operator*() const { return *ptr; }
T *operator->() const { return ptr; }
operator bool() const { return ptr; }
bool operator!() const { return !ptr; }
template <typename U>
bool operator==(const SharedPtr<U> &other) const
{ return ptr == other.Get(); }
template <typename U>
bool operator!=(const SharedPtr<U> &other) const
{ return ptr != other.Get(); }
// Comparison to any type convertible to void *, e.g. the type of NULL.
template <typename U>
bool operator==(const U &p) const { return ptr == (void*) p; }
template <typename U>
bool operator!=(const U &p) const { return ptr != (void*) p; }
T *Get() const { return ptr; }
/// TODO
template <typename derived_t>
derived_t *As() const { return util::As<derived_t>(ptr); }
unsigned UseCount() const { return ptr ? ptr->RefCounted::ref_count : 0; }
void Reset()
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
Destroy();
ptr = NULL;
}
/// The type U* needs to be implicitly convertible to T*
template <typename U>
void Reset(U *new_ptr)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
if (ptr != new_ptr) { Destroy(); Init(new_ptr); }
}
void Swap(SharedPtr &other)
{
#ifdef MFEM_TRACE_SHARED_PTR
mfem::out << '[' << _MFEM_FUNC_NAME << "]\n";
#endif
std::swap(ptr, other.ptr);
}
};
template <class T>
inline void Swap(SharedPtr<T> &a, SharedPtr<T> &b) { a.Swap(b); }
class PLayout;
typedef SharedPtr<PLayout> DLayout;
class PArray;
typedef SharedPtr<PArray> DArray;
class PVector;
typedef SharedPtr<PVector> DVector;
class PFiniteElementSpace;
typedef SharedPtr<PFiniteElementSpace> DFiniteElementSpace;
class PBilinearForm;
typedef SharedPtr<PBilinearForm> DBilinearForm;
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_SMART_POINTERS_HPP
+52
View File
@@ -0,0 +1,52 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_UTILS_HPP
#define MFEM_BACKENDS_BASE_UTILS_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "../../general/error.hpp"
namespace mfem
{
namespace util
{
//
// Inline methods
//
/// TODO: doxygen
template <typename derived_t, typename base_t>
inline derived_t *As(base_t *base_obj)
{
MFEM_ASSERT(dynamic_cast<derived_t*>(base_obj) != NULL,
"invalid object type");
return static_cast<derived_t*>(base_obj);
}
/// TODO: doxygen
template <typename derived_t, typename base_t>
inline derived_t *Is(base_t *base_obj)
{
return dynamic_cast<derived_t*>(base_obj);
}
} // namespace mfem::util
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_UTILS_HPP
+153
View File
@@ -0,0 +1,153 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_BASE_VECTOR_HPP
#define MFEM_BACKENDS_BASE_VECTOR_HPP
#include "../../config/config.hpp"
#ifdef MFEM_USE_BACKENDS
#include "../../general/scalars.hpp"
#include "array.hpp"
namespace mfem
{
/// Polymorphic vector - array of scalars.
class PVector : virtual public PArray
{
protected:
/**
@name Virtual interface
*/
///@{
/** @brief Create and return a new vector of the same dynamic type as this
vector using the same layout with entries specified by @a buffer_type_id
which should be a constant defined by the `value` field in a
specialization of the template class mfem::ScalarId.
Returns NULL if allocation fails.
If @a copy_data is true, the contents of this vector is copied to the new
vector; otherwise, the new vector remains uninitialized.
If @a buffer is not NULL, return the vector data of the newly created
object (in @a *buffer), if it is stored as a contiguous array on the
host; otherwise, set @a *buffer to NULL. */
virtual PVector *DoVectorClone(bool copy_data, void **buffer,
int buffer_type_id) const = 0;
/** @brief Compute and return the dot product of @a *this and @a x. In the
case of an MPI-parallel vector, the result must be the MPI-global dot
product. */
/** Both vectors must have the same dynamic type and layout. */
virtual void DoDotProduct(const PVector &x, void *result,
int result_type_id) const = 0;
// TODO: add reduction operations: min, max, sum
/// Perform the operation @a *this = @a a @a x + @a b @a y.
/** Rules:
- the dynamic type of both @a x and @a y is the same as that of @a *this
- if @a a == 0, neither @a x nor its data are accessed
- if @a b == 0, neither @a y nor its data are accessed
- @a x's data is never the same as @a y's data, unless @a a == 0, or
@a b == 0
- @a x's data or @a y's data may be the same as the data of @a *this
- all accessed vectors, @a x, @a y, and @a *this have the same layout. */
virtual void DoAxpby(const void *a, const PVector &x,
const void *b, const PVector &y,
int ab_type_id) = 0;
///@}
// End: Virtual interface
public:
/** @brief Create a PVector. */
/** The @a layout must be valid in the sense that layout != NULL and
layout->HasEngine() == true. */
PVector(PLayout &p_layout)
: PArray(p_layout) { }
template <typename derived_t>
derived_t &As() { return *util::As<derived_t>(this); }
template <typename derived_t>
const derived_t &As() const { return *util::As<const derived_t>(this); }
// TODO: Error handling ... handle errors at the Engine level, at the class
// level, or at the method level?
// TODO: Asynchronous execution interface ...
// TODO: Multi-vector interface ...
/**
@name Public virtual interface
*/
///@{
/** @brief Create and return a new vector of the same dynamic type as this
vector using the same layout with entries of type @a scalar_t.
If @a copy_data is true, the contents of this vector is copied to the new
vector; otherwise, the new vector remains uninitialized.
If @a buffer is not NULL, return the vector data of the newly created
object (in @a *buffer) , if it is stored as a contiguous array on the
host; otherwise, set @a *buffer to NULL. */
template <typename scalar_t>
DVector Clone(bool copy_data, scalar_t **buffer) const
{
return DVector(DoVectorClone(copy_data, (void**)buffer,
ScalarId<scalar_t>::value));
}
/** @brief Compute and return the dot product of @a *this and @a x. In the
case of an MPI-parallel vector, the result must be the MPI-global dot
product. */
/** Both vectors must have the same dynamic type and layout. */
template <typename scalar_t>
scalar_t DotProduct(const PVector &x) const
{
scalar_t result;
DoDotProduct(x, &result, ScalarId<scalar_t>::value);
return result;
}
// TODO: add reduction operations: min, max, sum
/// Perform the operation @a *this = @a a @a x + @a b @a y.
/** Rules:
- the dynamic type of both @a x and @a y is the same as that of @a *this
- if @a a == 0, neither @a x nor its data are accessed
- if @a b == 0, neither @a y nor its data are accessed
- @a x's data is never the same as @a y's data, unless @a a == 0, or
@a b == 0
- @a x's data or @a y's data may be the same as the data of @a *this
- all accessed vectors, @a x, @a y, and @a *this have the same layout. */
template <typename scalar_t>
void Axpby(const scalar_t &a, const PVector &x,
const scalar_t &b, const PVector &y)
{ if (Size()) { DoAxpby(&a, x, &b, y, ScalarId<scalar_t>::value); } }
///@}
// End: Virtual interface
};
} // namespace mfem
#endif // MFEM_USE_BACKENDS
#endif // MFEM_BACKENDS_BASE_VECTOR_HPP
+66
View File
@@ -0,0 +1,66 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
/*
---[ Defines Known At Compile-Time ]------------
ELEMENT_BATCH : How many elements are in each
. computation batch
NUM_DOFS_1D : Dofs in the 1D segments
NUM_DOFS_2D : Dofs in the 2D faces
NUM_DOFS_3D : Dofs in the 3D domain
NUM_QUAD_1D : Dofs in the 1D segments
NUM_QUAD_2D : Dofs in the 2D faces
NUM_QUAD_3D : Dofs in the 3D domain
NUM_MAX_1D : max(NUM_QUAD_1D, NUM_DOFS_1D)
NUM_QUAD_DOFS_1D: NUM_QUAD_1D * NUM_DOFS_1D
COEFF_ARGS : Code that passes required arguments to the kernel
COEFF : Code that computes the coefficient
================================================
[MISSING]
- Add support to auto-pick @dim and use @idxOrder on stack arrays
| double a[2][2];
| a[0][1]; <-- regular index
| a(0,1); <-- uses @idxOrder a[0][1] or a[1][0]
- Add support for @idxOrder to change indexing order after allocation
| double a[2][2] @idxOrder(0,1);
| a(0,1) -> a[1][0]
| @set(a, idxOrder(1,0));
| a(0,1) -> a[0][1]
- Add support to iterate over loop depending on mode
| for(i; @inner) {
| for(0 < j < N) {} <-- ++j or j += block?
| }
*/
#include "mfem-occa://defines.okl"
#if USING_TENSOR_OPS
# ifdef OCCA_USING_GPU
# if USING_LOW_ORDER
# include "mfem-occa://diffusion/tensor/gpuHighOrder.okl"
# else
# include "mfem-occa://diffusion/tensor/gpuHighOrder.okl"
# endif
# else
# include "mfem-occa://diffusion/tensor/cpu.okl"
# endif
#else
# ifdef OCCA_USING_GPU
# if USING_LOW_ORDER
# include "mfem-occa://diffusion/simplex/gpuHighOrder.okl"
# else
# include "mfem-occa://diffusion/simplex/gpuHighOrder.okl"
# endif
# else
# include "mfem-occa://diffusion/simplex/cpu.okl"
# endif
#endif
+66
View File
@@ -0,0 +1,66 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
/*
---[ Defines Known At Compile-Time ]------------
ELEMENT_BATCH : How many elements are in each
. computation batch
NUM_DOFS_1D : Dofs in the 1D segments
NUM_DOFS_2D : Dofs in the 2D faces
NUM_DOFS_3D : Dofs in the 3D domain
NUM_QUAD_1D : Dofs in the 1D segments
NUM_QUAD_2D : Dofs in the 2D faces
NUM_QUAD_3D : Dofs in the 3D domain
NUM_MAX_1D : max(NUM_QUAD_1D, NUM_DOFS_1D)
NUM_QUAD_DOFS_1D: NUM_QUAD_1D * NUM_DOFS_1D
COEFF_ARGS : Code that passes required arguments to the kernel
COEFF : Code that computes the coefficient
================================================
[MISSING]
- Add support to auto-pick @dim and use @idxOrder on stack arrays
| double a[2][2];
| a[0][1]; <-- regular index
| a(0,1); <-- uses @idxOrder a[0][1] or a[1][0]
- Add support for @idxOrder to change indexing order after allocation
| double a[2][2] @idxOrder(0,1);
| a(0,1) -> a[1][0]
| @set(a, idxOrder(1,0));
| a(0,1) -> a[0][1]
- Add support to iterate over loop depending on mode
| for(i; @inner) {
| for(0 < j < N) {} <-- ++j or j += block?
| }
*/
#include "mfem-occa://defines.okl"
#if USING_TENSOR_OPS
# ifdef OCCA_USING_GPU
# if USING_LOW_ORDER
# include "mfem-occa://mass/tensor/gpuHighOrder.okl"
# else
# include "mfem-occa://mass/tensor/gpuHighOrder.okl"
# endif
# else
# include "mfem-occa://mass/tensor/cpu.okl"
# endif
#else
# ifdef OCCA_USING_GPU
# if USING_LOW_ORDER
# include "mfem-occa://mass/simplex/gpuHighOrder.okl"
# else
# include "mfem-occa://mass/simplex/gpuHighOrder.okl"
# endif
# else
# include "mfem-occa://mass/simplex/cpu.okl"
# endif
#endif
+38
View File
@@ -0,0 +1,38 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
/*
---[ Defines Known At Compile-Time ]------------
ELEMENT_BATCH : How many elements are in each
. computation batch
NUM_DOFS_1D : Dofs in the 1D segments
NUM_DOFS_2D : Dofs in the 2D faces
NUM_DOFS_3D : Dofs in the 3D domain
NUM_QUAD_1D : Dofs in the 1D segments
NUM_QUAD_2D : Dofs in the 2D faces
NUM_QUAD_3D : Dofs in the 3D domain
NUM_MAX_1D : max(NUM_QUAD_1D, NUM_DOFS_1D)
NUM_QUAD_DOFS_1D: NUM_QUAD_1D * NUM_DOFS_1D
CONST_COEFF : If the coefficient is constant, pass it
. as a define
================================================
[MISSING]
See kernels/DiffusionIntegrator.okl
*/
#include "mfem-occa://defines.okl"
#if USING_TENSOR_OPS
# ifndef OCCA_USING_GPU
# include "mfem-occa://vmass/tensor/cpu.okl"
# endif
#endif
+121
View File
@@ -0,0 +1,121 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "array.hpp"
namespace mfem
{
namespace occa
{
PArray *Array::DoClone(bool copy_data, void **buffer,
std::size_t item_size) const
{
Array *new_array = new Array(OccaLayout(), item_size);
if (copy_data)
{
new_array->slice.copyFrom(slice);
}
if (buffer)
{
*buffer = new_array->GetBuffer();
}
return new_array;
}
int Array::DoResize(PLayout &new_layout, void **buffer,
std::size_t item_size)
{
MFEM_ASSERT(dynamic_cast<Layout *>(&new_layout) != NULL,
"new_layout is not an OCCA Layout");
Layout *lt = static_cast<Layout *>(&new_layout);
int err = OccaResize(lt, item_size);
if (!err && buffer)
{
*buffer = GetBuffer();
}
return err;
}
void *Array::DoPullData(void *buffer, std::size_t item_size)
{
// called only when Size() != 0
if (!slice.getDevice().hasSeparateMemorySpace())
{
return slice.ptr();
}
if (buffer)
{
slice.copyTo(buffer);
}
return buffer;
}
void Array::DoFill(const void *value_ptr, std::size_t item_size)
{
// called only when Size() != 0
switch (item_size)
{
case sizeof(int8_t):
OccaFill(*(const int8_t *)value_ptr);
break;
case sizeof(int16_t):
OccaFill(*(const int16_t *)value_ptr);
break;
case sizeof(int32_t):
OccaFill(*(const int32_t *)value_ptr);
break;
// case sizeof(int64_t):
// OccaFill(*(const int64_t *)value_ptr);
// break;
case sizeof(double):
OccaFill(*(const double *)value_ptr);
break;
// case sizeof(::occa::double2):
// OccaFill(*(const ::occa::double2 *)value_ptr);
// break;
default:
MFEM_ABORT("item_size = " << item_size << " is not supported");
}
}
void Array::DoPushData(const void *src_buffer, std::size_t item_size)
{
// called only when Size() != 0
if (slice.getDevice().hasSeparateMemorySpace() || slice.ptr() != src_buffer)
{
slice.copyFrom(src_buffer);
}
}
void Array::DoAssign(const PArray &src, std::size_t item_size)
{
// called only when Size() != 0
// Note: static_cast can not be used here since PArray is a virtual base
// class.
const Array *source = dynamic_cast<const Array *>(&src);
MFEM_ASSERT(source != NULL, "invalid source Array type");
OccaAssign(*source);
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+175
View File
@@ -0,0 +1,175 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_ARRAY_HPP
#define MFEM_BACKENDS_OCCA_ARRAY_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include <occa.hpp>
#include "layout.hpp"
#include "../base/array.hpp"
namespace mfem
{
namespace occa
{
class Array : public virtual PArray
{
protected:
//
// Inherited fields
//
// DLayout layout;
// Always true: Size()*item_size == slice.size() <= data.size()
mutable ::occa::memory data, slice;
//
// Virtual interface
//
virtual PArray *DoClone(bool copy_data, void **buffer,
std::size_t item_size) const;
virtual int DoResize(PLayout &new_layout, void **buffer,
std::size_t item_size);
virtual void *DoPullData(void *buffer, std::size_t item_size);
virtual void DoFill(const void *value_ptr, std::size_t item_size);
virtual void DoPushData(const void *src_buffer, std::size_t item_size);
virtual void DoAssign(const PArray &src, std::size_t item_size);
//
// Auxiliary methods
//
inline void *GetBuffer() const;
public:
Array(const Engine &e)
: PArray(*(new Layout(e, 0))),
data(e.Alloc(0)),
slice(data)
{ }
Array(Layout &lt, std::size_t item_size)
: PArray(lt),
data(lt.OccaEngine().Alloc(lt.Size()*item_size)),
slice(data)
{ }
virtual ~Array() { }
inline void MakeRef(Array &master);
Layout &OccaLayout() const { return layout->As<Layout>(); }
const Engine &OccaEngine() const { return OccaLayout().OccaEngine(); }
::occa::memory &OccaMem() { return slice; }
const ::occa::memory &OccaMem() const { return slice; }
inline int OccaResize(Layout *lt, std::size_t item_size);
inline int OccaResize(std::size_t new_size, std::size_t item_size);
template <typename T>
inline void OccaFill(const T val);
inline void OccaAssign(const Array &src);
inline void OccaPush(const void *src);
};
//
// Inline methods
//
inline void *Array::GetBuffer() const
{
if (!slice.getDevice().hasSeparateMemorySpace())
{
return slice.ptr();
}
return NULL;
}
inline int Array::OccaResize(Layout *lt, std::size_t item_size)
{
layout.Reset(lt); // Reset() checks if the pointer is the same
const std::size_t new_bytes = lt->Size()*item_size;
if (data.size() < new_bytes ||
data.getDevice() != lt->OccaEngine().GetDevice())
{
data = lt->OccaEngine().Alloc(new_bytes);
slice = data;
// If memory allocation fails - an exception is thrown.
}
else if (slice.size() != new_bytes)
{
slice = data.slice(0, new_bytes);
}
return 0;
}
inline void Array::MakeRef(Array &master)
{
layout = master.layout;
data = master.data;
slice = master.slice;
}
inline int Array::OccaResize(std::size_t new_size, std::size_t item_size)
{
Layout &ol = OccaLayout();
ol.OccaResize(new_size);
return OccaResize(&ol, item_size);
}
template <typename T>
inline void Array::OccaFill(const T val)
{
::occa::linalg::operator_eq<T>(slice, val);
}
inline void Array::OccaAssign(const Array &src)
{
if (slice != src.slice && slice.size() != 0)
{
MFEM_ASSERT(slice.size() == src.slice.size(), "");
slice.copyFrom(src.slice);
}
}
inline void Array::OccaPush(const void *src)
{
if (slice.size() != 0)
{
slice.copyFrom(src);
}
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_ARRAY_HPP
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "backend.hpp"
#include "engine.hpp"
namespace mfem
{
namespace occa
{
bool Backend::Supports(const std::string &engine_spec) const
{
// TODO: check if 'engine_spec' is valid OCCA string.
return true;
}
mfem::Engine *Create(const std::string &engine_spec)
{
return new Engine(engine_spec);
}
#ifdef MFEM_USE_MPI
mfem::Engine *Create(MPI_Comm comm, const std::string &engine_spec)
{
return new Engine(comm, engine_spec);
}
#endif
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+49
View File
@@ -0,0 +1,49 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_BACKEND_HPP
#define MFEM_BACKENDS_OCCA_BACKEND_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
// Only the Backend and Engine classes should be exposed through "backend.hpp"
#include "../base/backend.hpp"
#include "engine.hpp"
#include <occa.hpp>
namespace mfem
{
namespace occa
{
class Backend : public mfem::Backend
{
public:
virtual ~Backend();
virtual bool Supports(const std::string &engine_spec) const;
virtual mfem::Engine *Create(const std::string &engine_spec);
#ifdef MFEM_USE_MPI
virtual mfem::Engine *Create(MPI_Comm comm, const std::string &engine_spec);
#endif
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_BACKEND_HPP
+538
View File
@@ -0,0 +1,538 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "backend.hpp"
#include "bilininteg.hpp"
#include "../../fem/bilinearform.hpp"
namespace mfem
{
namespace occa
{
OccaBilinearForm::OccaBilinearForm(FiniteElementSpace *ofespace_) :
Operator(ofespace_->OccaVLayout()),
localX(ofespace_->OccaEVLayout()),
localY(ofespace_->OccaEVLayout())
{
Init(ofespace_->OccaEngine(), ofespace_, ofespace_);
}
OccaBilinearForm::OccaBilinearForm(FiniteElementSpace *otrialFESpace_,
FiniteElementSpace *otestFESpace_) :
Operator(otrialFESpace_->OccaVLayout(),
otestFESpace_->OccaVLayout()),
localX(otrialFESpace_->OccaEVLayout()),
localY(otestFESpace_->OccaEVLayout())
{
Init(otrialFESpace_->OccaEngine(), otrialFESpace_, otestFESpace_);
}
void OccaBilinearForm::Init(const Engine &e,
FiniteElementSpace *otrialFESpace_,
FiniteElementSpace *otestFESpace_)
{
engine.Reset(&e);
otrialFESpace = otrialFESpace_;
trialFESpace = otrialFESpace_->GetFESpace();
otestFESpace = otestFESpace_;
testFESpace = otestFESpace_->GetFESpace();
mesh = trialFESpace->GetMesh();
const int elements = GetNE();
const int trialVDim = trialFESpace->GetVDim();
const int trialLocalDofs = otrialFESpace->GetLocalDofs();
const int testLocalDofs = otestFESpace->GetLocalDofs();
// First-touch policy when running with OpenMP
if (GetDevice().mode() == "OpenMP")
{
const std::string &okl_path = OccaEngine().GetOklPath();
::occa::kernel initLocalKernel =
GetDevice().buildKernel(okl_path + "utils.okl",
"InitLocalVector");
const std::size_t sd = sizeof(double);
const uint64_t trialEntries = sd * (elements * trialLocalDofs);
const uint64_t testEntries = sd * (elements * testLocalDofs);
for (int v = 0; v < trialVDim; ++v)
{
const uint64_t trialOffset = v * trialEntries;
const uint64_t testOffset = v * testEntries;
initLocalKernel(elements, trialLocalDofs,
localX.OccaMem().slice(trialOffset, trialEntries));
initLocalKernel(elements, testLocalDofs,
localY.OccaMem().slice(testOffset, testEntries));
}
}
}
int OccaBilinearForm::BaseGeom() const
{
return mesh->GetElementBaseGeometry();
}
int OccaBilinearForm::GetDim() const
{
return mesh->Dimension();
}
int64_t OccaBilinearForm::GetNE() const
{
return mesh->GetNE();
}
Mesh& OccaBilinearForm::GetMesh() const
{
return *mesh;
}
FiniteElementSpace& OccaBilinearForm::GetTrialOccaFESpace() const
{
return *otrialFESpace;
}
FiniteElementSpace& OccaBilinearForm::GetTestOccaFESpace() const
{
return *otestFESpace;
}
mfem::FiniteElementSpace& OccaBilinearForm::GetTrialFESpace() const
{
return *trialFESpace;
}
mfem::FiniteElementSpace& OccaBilinearForm::GetTestFESpace() const
{
return *testFESpace;
}
int64_t OccaBilinearForm::GetTrialNDofs() const
{
return trialFESpace->GetNDofs();
}
int64_t OccaBilinearForm::GetTestNDofs() const
{
return testFESpace->GetNDofs();
}
int64_t OccaBilinearForm::GetTrialVDim() const
{
return trialFESpace->GetVDim();
}
int64_t OccaBilinearForm::GetTestVDim() const
{
return testFESpace->GetVDim();
}
const FiniteElement& OccaBilinearForm::GetTrialFE(const int i) const
{
return *(trialFESpace->GetFE(i));
}
const FiniteElement& OccaBilinearForm::GetTestFE(const int i) const
{
return *(testFESpace->GetFE(i));
}
// Adds new Domain Integrator.
void OccaBilinearForm::AddDomainIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props)
{
AddIntegrator(integrator, props, DomainIntegrator);
}
// Adds new Boundary Integrator.
void OccaBilinearForm::AddBoundaryIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props)
{
AddIntegrator(integrator, props, BoundaryIntegrator);
}
// Adds new interior Face Integrator.
void OccaBilinearForm::AddInteriorFaceIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props)
{
AddIntegrator(integrator, props, InteriorFaceIntegrator);
}
// Adds new boundary Face Integrator.
void OccaBilinearForm::AddBoundaryFaceIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props)
{
AddIntegrator(integrator, props, BoundaryFaceIntegrator);
}
// Adds Integrator based on OccaIntegratorType
void OccaBilinearForm::AddIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props,
const OccaIntegratorType itype)
{
if (integrator == NULL)
{
std::stringstream error_ss;
error_ss << "OccaBilinearForm::";
switch (itype)
{
case DomainIntegrator : error_ss << "AddDomainIntegrator"; break;
case BoundaryIntegrator : error_ss << "AddBoundaryIntegrator"; break;
case InteriorFaceIntegrator: error_ss << "AddInteriorFaceIntegrator"; break;
case BoundaryFaceIntegrator: error_ss << "AddBoundaryFaceIntegrator"; break;
}
error_ss << " (...):\n"
<< " Integrator is NULL";
const std::string error = error_ss.str();
mfem_error(error.c_str());
}
integrator->SetupIntegrator(*this, baseKernelProps + props, itype);
integrators.push_back(integrator);
}
const mfem::Operator* OccaBilinearForm::GetTrialProlongation() const
{
return otrialFESpace->GetProlongationOperator();
}
const mfem::Operator* OccaBilinearForm::GetTestProlongation() const
{
return otestFESpace->GetProlongationOperator();
}
const mfem::Operator* OccaBilinearForm::GetTrialRestriction() const
{
return otrialFESpace->GetRestrictionOperator();
}
const mfem::Operator* OccaBilinearForm::GetTestRestriction() const
{
return otestFESpace->GetRestrictionOperator();
}
void OccaBilinearForm::Assemble()
{
// [MISSING] Find geometric information that is needed by intergrators
// to share between integrators.
const int integratorCount = (int) integrators.size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->Assemble();
}
}
void OccaBilinearForm::FormLinearSystem(const mfem::Array<int> &constraintList,
mfem::Vector &x, mfem::Vector &b,
mfem::Operator *&Aout,
mfem::Vector &X, mfem::Vector &B,
int copy_interior)
{
FormOperator(constraintList, Aout);
InitRHS(constraintList, x, b, Aout, X, B, copy_interior);
}
void OccaBilinearForm::FormOperator(const mfem::Array<int> &constraintList,
mfem::Operator *&Aout)
{
const mfem::Operator *trialP = GetTrialProlongation();
const mfem::Operator *testP = GetTestProlongation();
mfem::Operator *rap = this;
if (trialP)
{
rap = new RAPOperator(*testP, *this, *trialP);
}
Aout = new OccaConstrainedOperator(rap, constraintList,
rap != this);
}
void OccaBilinearForm::InitRHS(const mfem::Array<int> &constraintList,
mfem::Vector &x, mfem::Vector &b,
mfem::Operator *A,
mfem::Vector &X, mfem::Vector &B,
int copy_interior)
{
// FIXME: move these kernels to the Backend?
static ::occa::kernelBuilder get_subvector_builder =
::occa::linalg::customLinearMethod(
"vector_get_subvector",
"const int dof_i = v2[i];"
"v0[i] = dof_i >= 0 ? v1[dof_i] : -v1[-dof_i - 1];",
"defines: {"
" VTYPE0: 'double',"
" VTYPE1: 'double',"
" VTYPE2: 'int',"
" TILESIZE: 128,"
"}");
static ::occa::kernelBuilder set_subvector_builder =
::occa::linalg::customLinearMethod(
"vector_set_subvector",
"const int dof_i = v2[i];"
"if (dof_i >= 0) { v0[dof_i] = v1[i]; }"
"else { v0[-dof_i - 1] = -v1[i]; }",
"defines: {"
" VTYPE0: 'double',"
" VTYPE1: 'double',"
" VTYPE2: 'int',"
" TILESIZE: 128,"
"}");
const mfem::Operator *P = GetTrialProlongation();
const mfem::Operator *R = GetTrialRestriction();
if (P)
{
// Variational restriction with P
B.Resize(P->InLayout());
P->MultTranspose(b, B);
X.Resize(R->OutLayout());
R->Mult(x, X);
}
else
{
// rap, X and B point to the same data as this, x and b
X.MakeRef(x);
B.MakeRef(b);
}
if (!copy_interior && constraintList.Size() > 0)
{
::occa::kernel get_subvector_kernel =
get_subvector_builder.build(GetDevice());
::occa::kernel set_subvector_kernel =
set_subvector_builder.build(GetDevice());
const Array &constrList = constraintList.Get_PArray()->As<Array>();
Vector subvec(constrList.OccaLayout());
get_subvector_kernel(constraintList.Size(),
subvec.OccaMem(),
X.Get_PVector()->As<Vector>().OccaMem(),
constrList.OccaMem());
X.Fill(0.0);
set_subvector_kernel(constraintList.Size(),
X.Get_PVector()->As<Vector>().OccaMem(),
subvec.OccaMem(),
constrList.OccaMem());
}
// FIXME: add case for HypreParMatrix here
OccaConstrainedOperator *cA = dynamic_cast<OccaConstrainedOperator*>(A);
if (cA)
{
cA->EliminateRHS(X.Get_PVector()->As<Vector>(),
B.Get_PVector()->As<Vector>());
}
else
{
mfem_error("OccaBilinearForm::InitRHS expects an OccaConstrainedOperator");
}
}
// Matrix vector multiplication.
void OccaBilinearForm::Mult_(const Vector &x, Vector &y) const
{
otrialFESpace->GlobalToLocal(x, localX);
localY.OccaFill<double>(0.0);
const int integratorCount = (int) integrators.size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->MultAdd(localX, localY);
}
otestFESpace->LocalToGlobal(localY, y);
}
// Matrix transpose vector multiplication.
void OccaBilinearForm::MultTranspose_(const Vector &x, Vector &y) const
{
otestFESpace->GlobalToLocal(x, localX);
localY.OccaFill<double>(0.0);
const int integratorCount = (int) integrators.size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->MultTransposeAdd(localX, localY);
}
otrialFESpace->LocalToGlobal(localY, y);
}
void OccaBilinearForm::OccaRecoverFEMSolution(const mfem::Vector &X,
const mfem::Vector &b,
mfem::Vector &x)
{
const mfem::Operator *P = this->GetTrialProlongation();
if (P)
{
// Apply conforming prolongation
x.Resize(P->OutLayout());
P->Mult(X, x);
}
// Otherwise X and x point to the same data
}
// Frees memory bilinear form.
OccaBilinearForm::~OccaBilinearForm()
{
// Make sure all integrators free their data
IntegratorVector::iterator it = integrators.begin();
while (it != integrators.end())
{
delete *it;
++it;
}
}
void BilinearForm::InitOccaBilinearForm()
{
// Init 'obform' using 'bform'
MFEM_ASSERT(bform != NULL, "");
MFEM_ASSERT(obform == NULL, "");
FiniteElementSpace &ofes =
bform->FESpace()->Get_PFESpace()->As<FiniteElementSpace>();
obform = new OccaBilinearForm(&ofes);
// Transfer domain integrators
mfem::Array<mfem::BilinearFormIntegrator*> &dbfi = *bform->GetDBFI();
for (int i = 0; i < dbfi.Size(); i++)
{
std::string integ_name(dbfi[i]->Name());
Coefficient *scal_coeff = dbfi[i]->GetScalarCoefficient();
ConstantCoefficient *const_coeff =
dynamic_cast<ConstantCoefficient*>(scal_coeff);
GridFunctionCoefficient *gridfunc_coeff =
dynamic_cast<GridFunctionCoefficient*>(scal_coeff);
// TODO: other types of coefficients ...
OccaCoefficient *ocoeff = NULL;
if (const_coeff)
{
ocoeff = new OccaCoefficient(obform->OccaEngine(),
const_coeff->constant);
}
else if (gridfunc_coeff)
{
ocoeff = new OccaCoefficient(obform->OccaEngine(),
*gridfunc_coeff->GetGridFunction(), true);
}
else if (!scal_coeff)
{
ocoeff = new OccaCoefficient(obform->OccaEngine(), 1.0);
}
else
{
MFEM_ABORT("Coefficient type not supported");
}
OccaIntegrator *ointeg = NULL;
if (integ_name == "(undefined)")
{
MFEM_ABORT("BilinearFormIntegrator does not define Name()");
}
else if (integ_name == "mass")
{
ointeg = new OccaMassIntegrator(*ocoeff);
}
else if (integ_name == "diffusion")
{
ointeg = new OccaDiffusionIntegrator(*ocoeff);
}
else
{
MFEM_ABORT("BilinearFormIntegrator [Name() = " << integ_name
<< "] is not supported");
}
// NOTE: The integrators copy ocoeff, so it can be deleted here so there
// is no memory leak.
delete ocoeff;
const mfem::IntegrationRule *ir = dbfi[i]->GetIntRule();
if (ir) { ointeg->SetIntegrationRule(*ir); }
obform->AddDomainIntegrator(ointeg);
}
// TODO: other types of integrators ...
}
bool BilinearForm::Assemble()
{
if (obform == NULL) { InitOccaBilinearForm(); }
obform->Assemble();
return true; // --> host assembly is not needed
}
void BilinearForm::FormSystemMatrix(const mfem::Array<int> &ess_tdof_list,
mfem::OperatorHandle &A)
{
if (A.Type() == mfem::Operator::ANY_TYPE)
{
mfem::Operator *Aout = NULL;
obform->FormOperator(ess_tdof_list, Aout);
A.Reset(Aout);
}
else
{
MFEM_ABORT("Operator::Type is not supported, type = " << A.Type());
}
}
void BilinearForm::FormLinearSystem(const mfem::Array<int> &ess_tdof_list,
mfem::Vector &x, mfem::Vector &b,
mfem::OperatorHandle &A,
mfem::Vector &X, mfem::Vector &B,
int copy_interior)
{
FormSystemMatrix(ess_tdof_list, A);
obform->InitRHS(ess_tdof_list, x, b, A.Ptr(), X, B, copy_interior);
}
void BilinearForm::RecoverFEMSolution(const mfem::Vector &X,
const mfem::Vector &b,
mfem::Vector &x)
{
obform->OccaRecoverFEMSolution(X, b, x);
}
BilinearForm::~BilinearForm()
{
delete obform;
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+213
View File
@@ -0,0 +1,213 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_BILINEAR_FORM_HPP
#define MFEM_BACKENDS_OCCA_BILINEAR_FORM_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "fespace.hpp"
namespace mfem
{
namespace occa
{
enum OccaIntegratorType
{
DomainIntegrator = 0,
BoundaryIntegrator = 1,
InteriorFaceIntegrator = 2,
BoundaryFaceIntegrator = 3
};
class OccaIntegrator;
/** Class for bilinear form - "Matrix" with associated FE space and
BLFIntegrators. */
class OccaBilinearForm : public Operator
{
friend class OccaIntegrator;
protected:
typedef std::vector<OccaIntegrator*> IntegratorVector;
SharedPtr<const Engine> engine;
// State information
mutable mfem::Mesh *mesh;
mutable FiniteElementSpace *otrialFESpace;
mutable mfem::FiniteElementSpace *trialFESpace;
mutable FiniteElementSpace *otestFESpace;
mutable mfem::FiniteElementSpace *testFESpace;
IntegratorVector integrators;
// Device data
::occa::properties baseKernelProps;
// The input and output vectors are mapped to local nodes for efficient
// operations. In other words, they are E-vectors.
// The size is: (number of elements) * (nodes in element) * (vector dim)
mutable Vector localX, localY;
public:
OccaBilinearForm(FiniteElementSpace *ofespace_);
OccaBilinearForm(FiniteElementSpace *otrialFESpace_,
FiniteElementSpace *otestFESpace_);
void Init(const Engine &e,
FiniteElementSpace *otrialFESpace_,
FiniteElementSpace *otestFESpace_);
const Engine &OccaEngine() const { return *engine; }
::occa::device GetDevice(int idx = 0) const
{ return engine->GetDevice(idx); }
// Useful mesh Information
int BaseGeom() const;
int GetDim() const;
int64_t GetNE() const;
mfem::Mesh& GetMesh() const;
FiniteElementSpace& GetTrialOccaFESpace() const;
FiniteElementSpace& GetTestOccaFESpace() const;
mfem::FiniteElementSpace& GetTrialFESpace() const;
mfem::FiniteElementSpace& GetTestFESpace() const;
// Useful FE information
int64_t GetTrialNDofs() const;
int64_t GetTestNDofs() const;
int64_t GetTrialVDim() const;
int64_t GetTestVDim() const;
const mfem::FiniteElement& GetTrialFE(const int i) const;
const mfem::FiniteElement& GetTestFE(const int i) const;
// Adds new Domain Integrator.
void AddDomainIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props =
::occa::properties());
// Adds new Boundary Integrator.
void AddBoundaryIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props =
::occa::properties());
// Adds new interior Face Integrator.
void AddInteriorFaceIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props =
::occa::properties());
// Adds new boundary Face Integrator.
void AddBoundaryFaceIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props =
::occa::properties());
// Adds Integrator based on OccaIntegratorType
void AddIntegrator(OccaIntegrator *integrator,
const ::occa::properties &props,
const OccaIntegratorType itype);
virtual const mfem::Operator *GetTrialProlongation() const;
virtual const mfem::Operator *GetTestProlongation() const;
virtual const mfem::Operator *GetTrialRestriction() const;
virtual const mfem::Operator *GetTestRestriction() const;
// Assembles the form i.e. sums over all domain/bdr integrators.
virtual void Assemble();
void FormLinearSystem(const mfem::Array<int> &constraintList,
mfem::Vector &x, mfem::Vector &b,
mfem::Operator *&Aout,
mfem::Vector &X, mfem::Vector &B,
int copy_interior = 0);
void FormOperator(const mfem::Array<int> &constraintList,
mfem::Operator *&Aout);
void InitRHS(const mfem::Array<int> &constraintList,
mfem::Vector &x, mfem::Vector &b,
mfem::Operator *Aout,
mfem::Vector &X, mfem::Vector &B,
int copy_interior = 0);
// overrides
virtual void Mult_(const Vector &x, Vector &y) const;
virtual void MultTranspose_(const Vector &x, Vector &y) const;
void OccaRecoverFEMSolution(const mfem::Vector &X, const mfem::Vector &b,
mfem::Vector &x);
// Destroys bilinear form.
~OccaBilinearForm();
};
/// TODO: doxygen
class BilinearForm : public mfem::PBilinearForm
{
protected:
//
// Inherited fields
//
// SharedPtr<const mfem::Engine> engine;
// mfem::BilinearForm *bform;
OccaBilinearForm *obform;
// Called from Assemble() if obform is NULL to initialize obform.
void InitOccaBilinearForm();
public:
/// TODO: doxygen
BilinearForm(const Engine &e, mfem::BilinearForm &bf)
: mfem::PBilinearForm(e, bf), obform(NULL) { }
/// Virtual destructor
virtual ~BilinearForm();
/// Assemble the PBilinearForm.
/** This method is called from the method mfem::BilinearForm::Assemble() of
the associated mfem::BilinearForm, #bform.
@returns True, if the host assembly should NOT be performed. */
virtual bool Assemble();
virtual void FormSystemMatrix(const mfem::Array<int> &ess_tdof_list,
mfem::OperatorHandle &A);
virtual void FormLinearSystem(const mfem::Array<int> &ess_tdof_list,
mfem::Vector &x, mfem::Vector &b,
mfem::OperatorHandle &A,
mfem::Vector &X, mfem::Vector &B,
int copy_interior);
virtual void RecoverFEMSolution(const mfem::Vector &X, const mfem::Vector &b,
mfem::Vector &x);
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_BILINEAR_FORM_HPP
+954
View File
@@ -0,0 +1,954 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "bilininteg.hpp"
#include "../../fem/fem.hpp"
namespace mfem
{
namespace occa
{
std::map<std::string, OccaDofQuadMaps> OccaDofQuadMaps::AllDofQuadMaps;
OccaGeometry OccaGeometry::Get(::occa::device device,
FiniteElementSpace &ofespace,
const mfem::IntegrationRule &ir,
const int flags)
{
OccaGeometry geom;
mfem::Mesh &mesh = *(ofespace.GetMesh());
if (!mesh.GetNodes())
{
mesh.SetCurvature(1, false, -1, mfem::Ordering::byVDIM);
}
mfem::GridFunction &nodes = *(mesh.GetNodes());
const mfem::FiniteElementSpace &fespace = *(nodes.FESpace());
const mfem::FiniteElement &fe = *(fespace.GetFE(0));
const int dims = fe.GetDim();
const int elements = fespace.GetNE();
const int numDofs = fe.GetDof();
const int numQuad = ir.GetNPoints();
MFEM_ASSERT(dims == mesh.SpaceDimension(), "");
geom.meshNodes.allocate(device,
dims, numDofs, elements);
const mfem::Table &e2dTable = fespace.GetElementToDofTable();
const int *elementMap = e2dTable.GetJ();
nodes.Pull();
for (int e = 0; e < elements; ++e)
{
for (int dof = 0; dof < numDofs; ++dof)
{
const int gid = elementMap[dof + numDofs*e];
for (int dim = 0; dim < dims; ++dim)
{
geom.meshNodes(dim, dof, e) = nodes[fespace.DofToVDof(gid,dim)];
}
}
}
geom.meshNodes.keepInDevice();
if (flags & Jacobian)
{
geom.J.allocate(device,
dims, dims, numQuad, elements);
}
else
{
geom.J.allocate(device, 1);
}
if (flags & JacobianInv)
{
geom.invJ.allocate(device,
dims, dims, numQuad, elements);
}
else
{
geom.invJ.allocate(device, 1);
}
if (flags & JacobianDet)
{
geom.detJ.allocate(device,
numQuad, elements);
}
else
{
geom.detJ.allocate(device, 1);
}
geom.J.stopManaging();
geom.invJ.stopManaging();
geom.detJ.stopManaging();
OccaDofQuadMaps &maps = OccaDofQuadMaps::GetSimplexMaps(device, fe, ir);
::occa::properties props;
props["defines/NUM_DOFS"] = numDofs;
props["defines/NUM_QUAD"] = numQuad;
props["defines/STORE_JACOBIAN"] = (flags & Jacobian);
props["defines/STORE_JACOBIAN_INV"] = (flags & JacobianInv);
props["defines/STORE_JACOBIAN_DET"] = (flags & JacobianDet);
const std::string &okl_path = ofespace.OccaEngine().GetOklPath();
::occa::kernel init = device.buildKernel(okl_path + "geometry.okl",
stringWithDim("InitGeometryInfo",
fe.GetDim()),
props);
init(elements,
maps.dofToQuadD,
geom.meshNodes,
geom.J, geom.invJ, geom.detJ);
return geom;
}
OccaDofQuadMaps::OccaDofQuadMaps() :
hash() {}
OccaDofQuadMaps::OccaDofQuadMaps(const OccaDofQuadMaps &maps)
{
*this = maps;
}
OccaDofQuadMaps& OccaDofQuadMaps::operator = (const OccaDofQuadMaps &maps)
{
hash = maps.hash;
dofToQuad = maps.dofToQuad;
dofToQuadD = maps.dofToQuadD;
quadToDof = maps.quadToDof;
quadToDofD = maps.quadToDofD;
quadWeights = maps.quadWeights;
return *this;
}
OccaDofQuadMaps& OccaDofQuadMaps::Get(::occa::device device,
const FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
const bool transpose)
{
return Get(device,
*fespace.GetFE(0),
*fespace.GetFE(0),
ir,
transpose);
}
OccaDofQuadMaps& OccaDofQuadMaps::Get(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose)
{
return Get(device, fe, fe, ir, transpose);
}
OccaDofQuadMaps& OccaDofQuadMaps::Get(::occa::device device,
const FiniteElementSpace &trialFESpace,
const FiniteElementSpace &testFESpace,
const mfem::IntegrationRule &ir,
const bool transpose)
{
return Get(device,
*trialFESpace.GetFE(0),
*testFESpace.GetFE(0),
ir,
transpose);
}
OccaDofQuadMaps& OccaDofQuadMaps::Get(::occa::device device,
const mfem::FiniteElement &trialFE,
const mfem::FiniteElement &testFE,
const mfem::IntegrationRule &ir,
const bool transpose)
{
return (dynamic_cast<const mfem::TensorBasisElement*>(&trialFE)
? GetTensorMaps(device, trialFE, testFE, ir, transpose)
: GetSimplexMaps(device, trialFE, testFE, ir, transpose));
}
OccaDofQuadMaps& OccaDofQuadMaps::GetTensorMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose)
{
return GetTensorMaps(device,
fe, fe,
ir, transpose);
}
OccaDofQuadMaps& OccaDofQuadMaps::GetTensorMaps(::occa::device device,
const mfem::FiniteElement &trialFE,
const mfem::FiniteElement &testFE,
const mfem::IntegrationRule &ir,
const bool transpose)
{
const mfem::TensorBasisElement &trialTFE =
dynamic_cast<const mfem::TensorBasisElement&>(trialFE);
const mfem::TensorBasisElement &testTFE =
dynamic_cast<const mfem::TensorBasisElement&>(testFE);
std::stringstream ss;
ss << ::occa::hash(device)
<< "Tensor"
<< "O1:" << trialFE.GetOrder()
<< "O2:" << testFE.GetOrder()
<< "BT1:" << trialTFE.GetBasisType()
<< "BT2:" << testTFE.GetBasisType()
<< "Q:" << ir.GetNPoints();
std::string hash = ss.str();
// If we've already made the dof-quad maps, reuse them
OccaDofQuadMaps &maps = AllDofQuadMaps[hash];
if (!maps.hash.size())
{
// Create the dof-quad maps
maps.hash = hash;
OccaDofQuadMaps trialMaps = GetD2QTensorMaps(device, trialFE, ir);
OccaDofQuadMaps testMaps = GetD2QTensorMaps(device, testFE , ir, true);
maps.dofToQuad = trialMaps.dofToQuad;
maps.dofToQuadD = trialMaps.dofToQuadD;
maps.quadToDof = testMaps.dofToQuad;
maps.quadToDofD = testMaps.dofToQuadD;
maps.quadWeights = testMaps.quadWeights;
}
return maps;
}
OccaDofQuadMaps OccaDofQuadMaps::GetD2QTensorMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose)
{
const mfem::TensorBasisElement &tfe =
dynamic_cast<const mfem::TensorBasisElement&>(fe);
const mfem::Poly_1D::Basis &basis = tfe.GetBasis1D();
const int order = fe.GetOrder();
// [MISSING] Get 1D dofs
const int dofs = order + 1;
const int dims = fe.GetDim();
// Create the dof -> quadrature point map
const mfem::IntegrationRule &ir1D =
mfem::IntRules.Get(mfem::Geometry::SEGMENT, ir.GetOrder());
const int quadPoints = ir1D.GetNPoints();
const int quadPoints2D = quadPoints*quadPoints;
const int quadPoints3D = quadPoints2D*quadPoints;
const int quadPointsND = ((dims == 1) ? quadPoints :
((dims == 2) ? quadPoints2D : quadPoints3D));
OccaDofQuadMaps maps;
// Initialize the dof -> quad mapping
maps.dofToQuad.allocate(device,
quadPoints, dofs);
maps.dofToQuadD.allocate(device,
quadPoints, dofs);
double *quadWeights1DData = NULL;
if (transpose)
{
maps.dofToQuad.reindex(1,0);
maps.dofToQuadD.reindex(1,0);
// Initialize quad weights only for transpose
maps.quadWeights.allocate(device,
quadPointsND);
quadWeights1DData = new double[quadPoints];
}
mfem::Vector d2q(dofs);
mfem::Vector d2qD(dofs);
for (int q = 0; q < quadPoints; ++q)
{
const mfem::IntegrationPoint &ip = ir1D.IntPoint(q);
basis.Eval(ip.x, d2q, d2qD);
if (transpose)
{
quadWeights1DData[q] = ip.weight;
}
for (int d = 0; d < dofs; ++d)
{
maps.dofToQuad(q, d) = d2q[d];
maps.dofToQuadD(q, d) = d2qD[d];
}
}
maps.dofToQuad.keepInDevice();
maps.dofToQuadD.keepInDevice();
if (transpose)
{
for (int q = 0; q < quadPointsND; ++q)
{
const int qx = q % quadPoints;
const int qz = q / quadPoints2D;
const int qy = (q - qz*quadPoints2D) / quadPoints;
double w = quadWeights1DData[qx];
if (dims > 1)
{
w *= quadWeights1DData[qy];
}
if (dims > 2)
{
w *= quadWeights1DData[qz];
}
maps.quadWeights[q] = w;
}
maps.quadWeights.keepInDevice();
delete [] quadWeights1DData;
}
return maps;
}
OccaDofQuadMaps& OccaDofQuadMaps::GetSimplexMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose)
{
return GetSimplexMaps(device,
fe, fe,
ir, transpose);
}
OccaDofQuadMaps& OccaDofQuadMaps::GetSimplexMaps(::occa::device device,
const mfem::FiniteElement &trialFE,
const mfem::FiniteElement &testFE,
const mfem::IntegrationRule &ir,
const bool transpose)
{
std::stringstream ss;
ss << ::occa::hash(device)
<< "Simplex"
<< "O1:" << trialFE.GetOrder()
<< "O2:" << testFE.GetOrder()
<< "Q:" << ir.GetNPoints();
std::string hash = ss.str();
// If we've already made the dof-quad maps, reuse them
OccaDofQuadMaps &maps = AllDofQuadMaps[hash];
if (!maps.hash.size())
{
// Create the dof-quad maps
maps.hash = hash;
OccaDofQuadMaps trialMaps = GetD2QSimplexMaps(device, trialFE, ir);
OccaDofQuadMaps testMaps = GetD2QSimplexMaps(device, testFE , ir, true);
maps.dofToQuad = trialMaps.dofToQuad;
maps.dofToQuadD = trialMaps.dofToQuadD;
maps.quadToDof = testMaps.dofToQuad;
maps.quadToDofD = testMaps.dofToQuadD;
maps.quadWeights = testMaps.quadWeights;
}
return maps;
}
OccaDofQuadMaps OccaDofQuadMaps::GetD2QSimplexMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose)
{
const int dims = fe.GetDim();
const int numDofs = fe.GetDof();
const int numQuad = ir.GetNPoints();
OccaDofQuadMaps maps;
// Initialize the dof -> quad mapping
maps.dofToQuad.allocate(device,
numQuad, numDofs);
maps.dofToQuadD.allocate(device,
dims, numQuad, numDofs);
if (transpose)
{
maps.dofToQuad.reindex(1,0);
maps.dofToQuadD.reindex(1,0);
// Initialize quad weights only for transpose
maps.quadWeights.allocate(device,
numQuad);
}
mfem::Vector d2q(numDofs);
mfem::DenseMatrix d2qD(numDofs, dims);
for (int q = 0; q < numQuad; ++q)
{
const mfem::IntegrationPoint &ip = ir.IntPoint(q);
if (transpose)
{
maps.quadWeights[q] = ip.weight;
}
fe.CalcShape(ip, d2q);
fe.CalcDShape(ip, d2qD);
for (int d = 0; d < numDofs; ++d)
{
const double w = d2q[d];
maps.dofToQuad(q, d) = w;
for (int dim = 0; dim < dims; ++dim)
{
const double wD = d2qD(d, dim);
maps.dofToQuadD(dim, q, d) = wD;
}
}
}
maps.dofToQuad.keepInDevice();
maps.dofToQuadD.keepInDevice();
if (transpose)
{
maps.quadWeights.keepInDevice();
}
return maps;
}
//---[ Integrator Defines ]-----------
std::string stringWithDim(const std::string &s, const int dim)
{
std::string ret = s;
ret += ('0' + (char) dim);
ret += 'D';
return ret;
}
int closestWarpBatchTo(const int value)
{
return ((value + 31) / 32) * 32;
}
int closestMultipleWarpBatch(const int multiple, const int maxSize)
{
if (multiple > maxSize)
{
return maxSize;
}
int batch = (32 / multiple);
int minDiff = 32 - (multiple * batch);
for (int i = 64; i <= maxSize; i += 32)
{
const int newDiff = i - (multiple * (i / multiple));
if (newDiff < minDiff)
{
batch = (i / multiple);
minDiff = newDiff;
}
}
return batch;
}
void SetProperties(FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
::occa::properties &props)
{
SetProperties(fespace, fespace, ir, props);
}
void SetProperties(FiniteElementSpace &trialFESpace,
FiniteElementSpace &testFESpace,
const mfem::IntegrationRule &ir,
::occa::properties &props)
{
props["defines/TRIAL_VDIM"] = trialFESpace.GetVDim();
props["defines/TEST_VDIM"] = testFESpace.GetVDim();
props["defines/NUM_DIM"] = trialFESpace.GetDim();
if (trialFESpace.hasTensorBasis())
{
SetTensorProperties(trialFESpace, testFESpace, ir, props);
}
else
{
SetSimplexProperties(trialFESpace, testFESpace, ir, props);
}
}
void SetTensorProperties(FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
::occa::properties &props)
{
SetTensorProperties(fespace, fespace, ir, props);
}
void SetTensorProperties(FiniteElementSpace &trialFESpace,
FiniteElementSpace &testFESpace,
const mfem::IntegrationRule &ir,
::occa::properties &props)
{
const mfem::FiniteElement &trialFE = *(trialFESpace.GetFE(0));
const mfem::FiniteElement &testFE = *(testFESpace.GetFE(0));
const mfem::IntegrationRule &ir1D =
mfem::IntRules.Get(mfem::Geometry::SEGMENT, ir.GetOrder());
const int trialDofs = trialFE.GetDof();
const int testDofs = testFE.GetDof();
const int numQuad = ir.GetNPoints();
const int trialDofs1D = trialFE.GetOrder() + 1;
const int testDofs1D = testFE.GetOrder() + 1;
const int quad1D = ir1D.GetNPoints();
int trialDofsND = trialDofs1D;
int testDofsND = testDofs1D;
int quadND = quad1D;
const bool trialByVDIM = (trialFESpace.GetOrdering() == mfem::Ordering::byVDIM);
const bool testByVDIM = (testFESpace.GetOrdering() == mfem::Ordering::byVDIM);
props["defines/ORDERING_BY_NODES"] = 0;
props["defines/ORDERING_BY_VDIM"] = 1;
props["defines/VDIM_ORDERING"] = (int) trialByVDIM;
props["defines/TRIAL_ORDERING"] = (int) trialByVDIM;
props["defines/TEST_ORDERING"] = (int) testByVDIM;
props["defines/USING_TENSOR_OPS"] = 1;
props["defines/NUM_DOFS"] = trialDofs;
props["defines/NUM_QUAD"] = numQuad;
props["defines/TRIAL_DOFS"] = trialDofs;
props["defines/TEST_DOFS"] = testDofs;
for (int d = 1; d <= 3; ++d)
{
if (d > 1)
{
trialDofsND *= trialDofs1D;
testDofsND *= testDofs1D;
quadND *= quad1D;
}
props["defines"][stringWithDim("NUM_DOFS_", d)] = trialDofsND;
props["defines"][stringWithDim("NUM_QUAD_", d)] = quadND;
props["defines"][stringWithDim("TRIAL_DOFS_", d)] = trialDofsND;
props["defines"][stringWithDim("TEST_DOFS_" , d)] = testDofsND;
}
// 1D Defines
const int m1InnerBatch = 32 * ((quad1D + 31) / 32);
props["defines/A1_ELEMENT_BATCH"] = closestMultipleWarpBatch(quad1D, 512);
props["defines/M1_OUTER_ELEMENT_BATCH"] = closestMultipleWarpBatch(m1InnerBatch,
512);
props["defines/M1_INNER_ELEMENT_BATCH"] = m1InnerBatch;
// 2D Defines
props["defines/A2_ELEMENT_BATCH"] = 1;
props["defines/A2_QUAD_BATCH"] = 1;
props["defines/M2_ELEMENT_BATCH"] = 32;
// 3D Defines
const int a3QuadBatch = closestMultipleWarpBatch(quadND, 512);
props["defines/A3_ELEMENT_BATCH"] = closestMultipleWarpBatch(a3QuadBatch, 512);
props["defines/A3_QUAD_BATCH"] = a3QuadBatch;
}
void SetSimplexProperties(FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
::occa::properties &props)
{
SetSimplexProperties(fespace, fespace, ir, props);
}
void SetSimplexProperties(FiniteElementSpace &trialFESpace,
FiniteElementSpace &testFESpace,
const mfem::IntegrationRule &ir,
::occa::properties &props)
{
const mfem::FiniteElement &trialFE = *(trialFESpace.GetFE(0));
const mfem::FiniteElement &testFE = *(testFESpace.GetFE(0));
const int trialDofs = trialFE.GetDof();
const int testDofs = testFE.GetDof();
const int numQuad = ir.GetNPoints();
const int maxDQ = std::max(std::max(trialDofs, testDofs), numQuad);
const bool trialByVDIM = (trialFESpace.GetOrdering() == mfem::Ordering::byVDIM);
const bool testByVDIM = (testFESpace.GetOrdering() == mfem::Ordering::byVDIM);
props["defines/ORDERING_BY_NODES"] = 0;
props["defines/ORDERING_BY_VDIM"] = 1;
props["defines/VDIM_ORDERING"] = (int) trialByVDIM;
props["defines/TRIAL_ORDERING"] = (int) trialByVDIM;
props["defines/TEST_ORDERING"] = (int) testByVDIM;
props["defines/USING_TENSOR_OPS"] = 0;
props["defines/NUM_DOFS"] = trialDofs;
props["defines/NUM_QUAD"] = numQuad;
props["defines/TRIAL_DOFS"] = trialDofs;
props["defines/TEST_DOFS"] = testDofs;
// 2D Defines
const int quadBatch = closestWarpBatchTo(numQuad);
props["defines/A2_ELEMENT_BATCH"] = closestMultipleWarpBatch(quadBatch, 2048);
props["defines/A2_QUAD_BATCH"] = quadBatch;
props["defines/M2_INNER_BATCH"] = closestWarpBatchTo(maxDQ);
// 3D Defines
props["defines/A3_ELEMENT_BATCH"] = closestMultipleWarpBatch(quadBatch, 2048);
props["defines/A3_QUAD_BATCH"] = quadBatch;
props["defines/M3_INNER_BATCH"] = closestWarpBatchTo(maxDQ);
}
//---[ Base Integrator ]--------------
OccaIntegrator::OccaIntegrator(const Engine &e)
: engine(&e),
bform(),
mesh(),
otrialFESpace(),
otestFESpace(),
trialFESpace(),
testFESpace(),
itype(DomainIntegrator),
ir(NULL),
hasTensorBasis(false) { }
OccaIntegrator::~OccaIntegrator() {}
void OccaIntegrator::SetupMaps()
{
maps = OccaDofQuadMaps::Get(GetDevice(),
*otrialFESpace,
*otestFESpace,
*ir);
mapsTranspose = OccaDofQuadMaps::Get(GetDevice(),
*otestFESpace,
*otrialFESpace,
*ir);
}
FiniteElementSpace& OccaIntegrator::GetTrialOccaFESpace() const
{
return *otrialFESpace;
}
FiniteElementSpace& OccaIntegrator::GetTestOccaFESpace() const
{
return *otestFESpace;
}
mfem::FiniteElementSpace& OccaIntegrator::GetTrialFESpace() const
{
return *trialFESpace;
}
mfem::FiniteElementSpace& OccaIntegrator::GetTestFESpace() const
{
return *testFESpace;
}
void OccaIntegrator::SetIntegrationRule(const mfem::IntegrationRule &ir_)
{
ir = &ir_;
}
const mfem::IntegrationRule& OccaIntegrator::GetIntegrationRule() const
{
return *ir;
}
OccaDofQuadMaps& OccaIntegrator::GetDofQuadMaps()
{
return maps;
}
void OccaIntegrator::SetupIntegrator(OccaBilinearForm &bform_,
const ::occa::properties &props_,
const OccaIntegratorType itype_)
{
MFEM_ASSERT(engine == &bform_.OccaEngine(), "");
bform = &bform_;
mesh = &(bform_.GetMesh());
otrialFESpace = &(bform_.GetTrialOccaFESpace());
otestFESpace = &(bform_.GetTestOccaFESpace());
trialFESpace = &(bform_.GetTrialFESpace());
testFESpace = &(bform_.GetTestFESpace());
hasTensorBasis = otrialFESpace->hasTensorBasis();
props = props_;
itype = itype_;
if (ir == NULL)
{
SetupIntegrationRule();
}
SetupMaps();
SetProperties(*otrialFESpace,
*otestFESpace,
*ir,
props);
Setup();
}
OccaGeometry OccaIntegrator::GetGeometry(const int flags)
{
return OccaGeometry::Get(GetDevice(), *otrialFESpace, *ir, flags);
}
::occa::kernel OccaIntegrator::GetAssembleKernel(const ::occa::properties
&props)
{
const mfem::FiniteElement &fe = *(trialFESpace->GetFE(0));
return GetKernel(stringWithDim("Assemble", fe.GetDim()),
props);
}
::occa::kernel OccaIntegrator::GetMultAddKernel(const ::occa::properties &props)
{
const mfem::FiniteElement &fe = *(trialFESpace->GetFE(0));
return GetKernel(stringWithDim("MultAdd", fe.GetDim()),
props);
}
::occa::kernel OccaIntegrator::GetKernel(const std::string &kernelName,
const ::occa::properties &props)
{
const std::string filename = GetName() + ".okl";
const std::string &okl_path = OccaEngine().GetOklPath();
return GetDevice().buildKernel(okl_path + filename,
kernelName,
props);
}
//====================================
//---[ Diffusion Integrator ]---------
OccaDiffusionIntegrator::OccaDiffusionIntegrator(const OccaCoefficient &coeff_)
:
OccaIntegrator(coeff_.OccaEngine()),
coeff(coeff_),
assembledOperator(*(new Layout(coeff_.OccaEngine(), 0)))
{
coeff.SetName("COEFF");
}
OccaDiffusionIntegrator::~OccaDiffusionIntegrator() {}
std::string OccaDiffusionIntegrator::GetName()
{
return "DiffusionIntegrator";
}
void OccaDiffusionIntegrator::SetupIntegrationRule()
{
const FiniteElement &trialFE = *(trialFESpace->GetFE(0));
const FiniteElement &testFE = *(testFESpace->GetFE(0));
ir = &mfem::DiffusionIntegrator::GetRule(trialFE, testFE);
}
void OccaDiffusionIntegrator::Setup()
{
::occa::properties kernelProps = props;
coeff.Setup(*this, kernelProps);
// Setup assemble and mult kernels
assembleKernel = GetAssembleKernel(kernelProps);
multKernel = GetMultAddKernel(kernelProps);
}
void OccaDiffusionIntegrator::Assemble()
{
const mfem::FiniteElement &fe = *(trialFESpace->GetFE(0));
const int dims = fe.GetDim();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int elements = trialFESpace->GetNE();
const int quadraturePoints = ir->GetNPoints();
OccaGeometry geom = GetGeometry(OccaGeometry::Jacobian);
assembledOperator.OccaResize(symmDims * quadraturePoints * elements,
sizeof(double));
assembleKernel((int) mesh->GetNE(),
maps.quadWeights,
geom.J,
coeff,
assembledOperator.OccaMem());
}
void OccaDiffusionIntegrator::MultAdd(Vector &x, Vector &y)
{
// Note: x and y are E-vectors
multKernel((int) mesh->GetNE(),
maps.dofToQuad,
maps.dofToQuadD,
maps.quadToDof,
maps.quadToDofD,
assembledOperator.OccaMem(),
x.OccaMem(), y.OccaMem());
}
//====================================
//---[ Mass Integrator ]--------------
OccaMassIntegrator::OccaMassIntegrator(const OccaCoefficient &coeff_) :
OccaIntegrator(coeff_.OccaEngine()),
coeff(coeff_),
assembledOperator(*(new Layout(coeff_.OccaEngine(), 0)))
{
coeff.SetName("COEFF");
}
OccaMassIntegrator::~OccaMassIntegrator() {}
std::string OccaMassIntegrator::GetName()
{
return "MassIntegrator";
}
void OccaMassIntegrator::SetupIntegrationRule()
{
const mfem::FiniteElement &trialFE = *(trialFESpace->GetFE(0));
const mfem::FiniteElement &testFE = *(testFESpace->GetFE(0));
mfem::ElementTransformation &T = *trialFESpace->GetElementTransformation(0);
ir = &mfem::MassIntegrator::GetRule(trialFE, testFE, T);
}
void OccaMassIntegrator::Setup()
{
::occa::properties kernelProps = props;
coeff.Setup(*this, kernelProps);
// Setup assemble and mult kernels
assembleKernel = GetAssembleKernel(kernelProps);
multKernel = GetMultAddKernel(kernelProps);
}
void OccaMassIntegrator::Assemble()
{
if (assembledOperator.Size())
{
return;
}
const int elements = trialFESpace->GetNE();
const int quadraturePoints = ir->GetNPoints();
OccaGeometry geom = GetGeometry(OccaGeometry::Jacobian);
assembledOperator.Resize<double>(quadraturePoints * elements, NULL);
assembleKernel((int) mesh->GetNE(),
maps.quadWeights,
geom.J,
coeff,
assembledOperator.OccaMem());
}
void OccaMassIntegrator::SetOperator(Vector &v)
{
assembledOperator = v;
}
void OccaMassIntegrator::MultAdd(Vector &x, Vector &y)
{
multKernel((int) mesh->GetNE(),
maps.dofToQuad,
maps.dofToQuadD,
maps.quadToDof,
maps.quadToDofD,
assembledOperator.OccaMem(),
x.OccaMem(), y.OccaMem());
}
//====================================
//---[ Vector Mass Integrator ]--------------
OccaVectorMassIntegrator::OccaVectorMassIntegrator(const OccaCoefficient &
coeff_)
:
OccaIntegrator(coeff_.OccaEngine()),
coeff(coeff_),
assembledOperator(*(new Layout(coeff_.OccaEngine(), 0)))
{
coeff.SetName("COEFF");
}
OccaVectorMassIntegrator::~OccaVectorMassIntegrator() {}
std::string OccaVectorMassIntegrator::GetName()
{
return "VectorMassIntegrator";
}
void OccaVectorMassIntegrator::SetupIntegrationRule()
{
const mfem::FiniteElement &trialFE = *(trialFESpace->GetFE(0));
const mfem::FiniteElement &testFE = *(testFESpace->GetFE(0));
mfem::ElementTransformation &T = *trialFESpace->GetElementTransformation(0);
ir = &mfem::MassIntegrator::GetRule(trialFE, testFE, T);
}
void OccaVectorMassIntegrator::Setup()
{
::occa::properties kernelProps = props;
coeff.Setup(*this, kernelProps);
// Setup assemble and mult kernels
assembleKernel = GetAssembleKernel(kernelProps);
multKernel = GetMultAddKernel(kernelProps);
}
void OccaVectorMassIntegrator::Assemble()
{
const int elements = trialFESpace->GetNE();
const int quadraturePoints = ir->GetNPoints();
OccaGeometry geom = GetGeometry(OccaGeometry::Jacobian);
assembledOperator.Resize<double>(quadraturePoints * elements, NULL);
assembleKernel((int) mesh->GetNE(),
maps.quadWeights,
geom.J,
coeff,
assembledOperator.OccaMem());
}
void OccaVectorMassIntegrator::MultAdd(Vector &x, Vector &y)
{
multKernel((int) mesh->GetNE(),
maps.dofToQuad,
maps.dofToQuadD,
maps.quadToDof,
maps.quadToDofD,
assembledOperator.OccaMem(),
x.OccaMem(), y.OccaMem());
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+323
View File
@@ -0,0 +1,323 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_BILIN_INTEG_HPP
#define MFEM_BACKENDS_OCCA_BILIN_INTEG_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "fespace.hpp"
#include "bilinearform.hpp"
#include "coefficient.hpp"
namespace mfem
{
namespace occa
{
class OccaGeometry
{
public:
::occa::array<double> meshNodes;
::occa::array<double> J, invJ, detJ;
// byVDIM -> [x y z x y z x y z]
// byNodes -> [x x x y y y z z z]
static const int Jacobian = (1 << 0);
static const int JacobianInv = (1 << 1);
static const int JacobianDet = (1 << 2);
static OccaGeometry Get(::occa::device device,
FiniteElementSpace &ofespace,
const IntegrationRule &ir,
const int flags = (Jacobian |
JacobianInv |
JacobianDet));
};
class OccaDofQuadMaps
{
private:
// Reuse dof-quad maps
static std::map<std::string, OccaDofQuadMaps> AllDofQuadMaps;
std::string hash;
public:
// Local stiffness matrices (B and B^T operators)
::occa::array<double, ::occa::dynamic> dofToQuad, dofToQuadD; // B
::occa::array<double, ::occa::dynamic> quadToDof, quadToDofD; // B^T
::occa::array<double> quadWeights;
OccaDofQuadMaps();
OccaDofQuadMaps(const OccaDofQuadMaps &maps);
OccaDofQuadMaps& operator = (const OccaDofQuadMaps &maps);
// [[x y] [x y] [x y]]
// [[x y z] [x y z] [x y z]]
// mfem::GridFunction* mfem::Mesh::GetNodes() { return Nodes; }
// mfem::FiniteElementSpace *Nodes->FESpace()
// 25
// 1D [x x x x x x]
// 2D [x y x y x y]
// GetVdim()
// 3D ordering == byVDIM -> [x y z x y z x y z x y z x y z x y z]
// ordering == byNODES -> [x x x x x x y y y y y y z z z z z z]
static OccaDofQuadMaps& Get(::occa::device device,
const FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& Get(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& Get(::occa::device device,
const FiniteElementSpace &trialFESpace,
const FiniteElementSpace &testFESpace,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& Get(::occa::device device,
const mfem::FiniteElement &trialFE,
const mfem::FiniteElement &testFE,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& GetTensorMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& GetTensorMaps(::occa::device device,
const mfem::FiniteElement &trialFE,
const mfem::FiniteElement &testFE,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps GetD2QTensorMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& GetSimplexMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps& GetSimplexMaps(::occa::device device,
const mfem::FiniteElement &trialFE,
const mfem::FiniteElement &testFE,
const mfem::IntegrationRule &ir,
const bool transpose = false);
static OccaDofQuadMaps GetD2QSimplexMaps(::occa::device device,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
const bool transpose = false);
};
//---[ Define Methods ]---------------
std::string stringWithDim(const std::string &s, const int dim);
int closestWarpBatch(const int multiple, const int maxSize);
void SetProperties(FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
::occa::properties &props);
void SetProperties(FiniteElementSpace &trialFESpace,
FiniteElementSpace &testFESpace,
const mfem::IntegrationRule &ir,
::occa::properties &props);
void SetTensorProperties(FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir,
::occa::properties &props);
void SetTensorProperties(FiniteElementSpace &trialFESpace,
FiniteElementSpace &testFESpace,
const IntegrationRule &ir,
::occa::properties &props);
void SetSimplexProperties(FiniteElementSpace &fespace,
const IntegrationRule &ir,
::occa::properties &props);
void SetSimplexProperties(FiniteElementSpace &trialFESpace,
FiniteElementSpace &testFESpace,
const IntegrationRule &ir,
::occa::properties &props);
//---[ Base Integrator ]--------------
class OccaIntegrator
{
protected:
SharedPtr<const Engine> engine;
OccaBilinearForm *bform;
mfem::Mesh *mesh;
FiniteElementSpace *otrialFESpace;
FiniteElementSpace *otestFESpace;
mfem::FiniteElementSpace *trialFESpace;
mfem::FiniteElementSpace *testFESpace;
::occa::properties props;
OccaIntegratorType itype;
const IntegrationRule *ir;
bool hasTensorBasis;
OccaDofQuadMaps maps;
OccaDofQuadMaps mapsTranspose;
public:
OccaIntegrator(const Engine &e);
virtual ~OccaIntegrator();
const Engine &OccaEngine() const { return *engine; }
::occa::device GetDevice(int idx = 0) const
{ return engine->GetDevice(idx); }
virtual std::string GetName() = 0;
FiniteElementSpace& GetTrialOccaFESpace() const;
FiniteElementSpace& GetTestOccaFESpace() const;
mfem::FiniteElementSpace& GetTrialFESpace() const;
mfem::FiniteElementSpace& GetTestFESpace() const;
void SetIntegrationRule(const mfem::IntegrationRule &ir_);
const mfem::IntegrationRule& GetIntegrationRule() const;
OccaDofQuadMaps& GetDofQuadMaps();
void SetupMaps();
virtual void SetupIntegrationRule() = 0;
virtual void SetupIntegrator(OccaBilinearForm &bform_,
const ::occa::properties &props_,
const OccaIntegratorType itype_);
virtual void Setup() = 0;
virtual void Assemble() = 0;
/// This method works on E-vectors!
virtual void MultAdd(Vector &x, Vector &y) = 0;
virtual void MultTransposeAdd(Vector &x, Vector &y)
{
mfem_error("OccaIntegrator::MultTransposeAdd() is not overloaded!");
}
OccaGeometry GetGeometry(const int flags = (OccaGeometry::Jacobian |
OccaGeometry::JacobianInv |
OccaGeometry::JacobianDet));
::occa::kernel GetAssembleKernel(const ::occa::properties &props);
::occa::kernel GetMultAddKernel(const ::occa::properties &props);
::occa::kernel GetKernel(const std::string &kernelName,
const ::occa::properties &props);
};
//====================================
//---[ Diffusion Integrator ]---------
class OccaDiffusionIntegrator : public OccaIntegrator
{
private:
OccaCoefficient coeff;
::occa::kernel assembleKernel, multKernel;
Vector assembledOperator;
public:
OccaDiffusionIntegrator(const OccaCoefficient &coeff_);
virtual ~OccaDiffusionIntegrator();
virtual std::string GetName();
virtual void SetupIntegrationRule();
virtual void Setup();
virtual void Assemble();
virtual void MultAdd(Vector &x, Vector &y);
};
//====================================
//---[ Mass Integrator ]--------------
class OccaMassIntegrator : public OccaIntegrator
{
private:
OccaCoefficient coeff;
::occa::kernel assembleKernel, multKernel;
Vector assembledOperator;
public:
OccaMassIntegrator(const OccaCoefficient &coeff_);
virtual ~OccaMassIntegrator();
virtual std::string GetName();
virtual void SetupIntegrationRule();
virtual void Setup();
virtual void Assemble();
void SetOperator(Vector &v);
virtual void MultAdd(Vector &x, Vector &y);
};
//====================================
//---[ Vector Mass Integrator ]--------------
class OccaVectorMassIntegrator : public OccaIntegrator
{
private:
OccaCoefficient coeff;
::occa::kernel assembleKernel, multKernel;
Vector assembledOperator;
public:
OccaVectorMassIntegrator(const OccaCoefficient &coeff_);
virtual ~OccaVectorMassIntegrator();
virtual std::string GetName();
virtual void SetupIntegrationRule();
virtual void Setup();
virtual void Assemble();
virtual void MultAdd(Vector &x, Vector &y);
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_BILIN_INTEG_HPP
+357
View File
@@ -0,0 +1,357 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "coefficient.hpp"
#include "bilininteg.hpp"
namespace mfem
{
namespace occa
{
//---[ Parameter ]------------
OccaParameter::~OccaParameter() {}
void OccaParameter::Setup(OccaIntegrator &integ,
::occa::properties &props) {}
::occa::kernelArg OccaParameter::KernelArgs()
{
return ::occa::kernelArg();
}
//====================================
//---[ Include Parameter ]------------
OccaIncludeParameter::OccaIncludeParameter(const std::string &filename_) :
filename(filename_) {}
OccaParameter* OccaIncludeParameter::Clone()
{
return new OccaIncludeParameter(filename);
}
void OccaIncludeParameter::Setup(OccaIntegrator &integ,
::occa::properties &props)
{
props["headers"].asArray() += "#include " + filename;
}
//====================================
//---[ Source Parameter ]------------
OccaSourceParameter::OccaSourceParameter(const std::string &source_) :
source(source_) {}
OccaParameter* OccaSourceParameter::Clone()
{
return new OccaSourceParameter(source);
}
void OccaSourceParameter::Setup(OccaIntegrator &integ,
::occa::properties &props)
{
props["headers"].asArray() += source;
}
//====================================
//---[ Vector Parameter ]-------
OccaVectorParameter::OccaVectorParameter(const std::string &name_,
Vector &v_,
const bool useRestrict_) :
name(name_),
v(v_),
useRestrict(useRestrict_),
attr("") {}
OccaVectorParameter::OccaVectorParameter(const std::string &name_,
Vector &v_,
const std::string &attr_,
const bool useRestrict_) :
name(name_),
v(v_),
useRestrict(useRestrict_),
attr(attr_) {}
OccaParameter* OccaVectorParameter::Clone()
{
return new OccaVectorParameter(name, v, attr, useRestrict);
}
void OccaVectorParameter::Setup(OccaIntegrator &integ,
::occa::properties &props)
{
std::string &args = (props["defines/COEFF_ARGS"]
.asString()
.string());
args += "const double *";
if (useRestrict)
{
args += " restrict ";
}
args += name;
if (attr.size())
{
args += ' ';
args += attr;
}
args += ",\n";
}
::occa::kernelArg OccaVectorParameter::KernelArgs()
{
return ::occa::kernelArg(v.OccaMem());
}
//====================================
//---[ GridFunction Parameter ]-------
OccaGridFunctionParameter::OccaGridFunctionParameter(const std::string &name_,
const Engine &e,
mfem::GridFunction &gf_,
const bool useRestrict_)
: name(name_),
gf(gf_),
gfQuad(e),
useRestrict(useRestrict_) {}
OccaParameter* OccaGridFunctionParameter::Clone()
{
OccaGridFunctionParameter *param =
new OccaGridFunctionParameter(name, gfQuad.OccaEngine(), gf, useRestrict);
param->gfQuad.MakeRef(gfQuad);
return param;
}
void OccaGridFunctionParameter::Setup(OccaIntegrator &integ,
::occa::properties &props)
{
std::string &args = (props["defines/COEFF_ARGS"]
.asString()
.string());
if (useRestrict)
{
args += "@restrict ";
}
args += "const double *";
args += name;
args += " @dim(NUM_QUAD, numElements),\n";
FiniteElementSpace &f = gf.FESpace()->Get_PFESpace()->As<FiniteElementSpace>();
ToQuad(integ.GetIntegrationRule(), f, gf.Get_PVector()->As<Vector>(), gfQuad);
}
::occa::kernelArg OccaGridFunctionParameter::KernelArgs()
{
return gfQuad.OccaMem();
}
//====================================
//---[ Coefficient ]------------------
OccaCoefficient::OccaCoefficient(const Engine &e, const double value) :
engine(&e),
integ(NULL),
name("COEFF")
{
coeffValue = value;
}
OccaCoefficient::OccaCoefficient(const Engine &e, mfem::GridFunction &gf,
const bool useRestrict) :
engine(&e),
integ(NULL),
name("COEFF")
{
coeffValue = "(u(q, e))";
AddGridFunction("u", gf, useRestrict);
}
OccaCoefficient::OccaCoefficient(const Engine &e, const std::string &source) :
engine(&e),
integ(NULL),
name("COEFF")
{
coeffValue = source;
}
OccaCoefficient::OccaCoefficient(const Engine &e, const char *source) :
engine(&e),
integ(NULL),
name("COEFF")
{
coeffValue = source;
}
OccaCoefficient::OccaCoefficient(const OccaCoefficient &coeff) :
engine(coeff.engine),
integ(NULL),
name(coeff.name),
coeffValue(coeff.coeffValue)
{
const int paramCount = (int) coeff.params.size();
for (int i = 0; i < paramCount; ++i)
{
params.push_back(coeff.params[i]->Clone());
}
}
OccaCoefficient::~OccaCoefficient()
{
const int paramCount = (int) params.size();
for (int i = 0; i < paramCount; ++i)
{
delete params[i];
}
}
OccaCoefficient& OccaCoefficient::SetName(const std::string &name_)
{
name = name_;
return *this;
}
void OccaCoefficient::Setup(OccaIntegrator &integ_,
::occa::properties &props_)
{
integ = &integ_;
const int paramCount = (int) params.size();
props_["defines"][name + "_ARGS"] = "";
for (int i = 0; i < paramCount; ++i)
{
params[i]->Setup(integ_, props_);
}
props_["defines"][name] = coeffValue;
props = props_;
}
OccaCoefficient& OccaCoefficient::Add(OccaParameter *param)
{
params.push_back(param);
return *this;
}
OccaCoefficient& OccaCoefficient::IncludeHeader(const std::string &filename)
{
return Add(new OccaIncludeParameter(filename));
}
OccaCoefficient& OccaCoefficient::IncludeSource(const std::string &source)
{
return Add(new OccaSourceParameter(source));
}
OccaCoefficient& OccaCoefficient::AddVector(const std::string &name_,
Vector &v,
const bool useRestrict)
{
return Add(new OccaVectorParameter(name_, v, useRestrict));
}
OccaCoefficient& OccaCoefficient::AddVector(const std::string &name_,
Vector &v,
const std::string &attr,
const bool useRestrict)
{
return Add(new OccaVectorParameter(name_, v, attr, useRestrict));
}
OccaCoefficient& OccaCoefficient::AddGridFunction(const std::string &name_,
mfem::GridFunction &gf,
const bool useRestrict)
{
MFEM_ASSERT(engine->CheckVector(gf.Get_PVector()) &&
engine->CheckFESpace(gf.FESpace()->Get_PFESpace()),
"invalid device GridFunction");
return Add(new OccaGridFunctionParameter(name_, *engine, gf, useRestrict));
}
bool OccaCoefficient::IsConstant()
{
return coeffValue.isNumber();
}
double OccaCoefficient::GetConstantValue()
{
if (!IsConstant())
{
mfem_error("OccaCoefficient is not constant");
}
return coeffValue.number();
}
Vector OccaCoefficient::Eval()
{
if (integ == NULL)
{
mfem_error("OccaCoefficient requires a Setup() call before Eval()");
}
mfem::FiniteElementSpace &fespace = integ->GetTrialFESpace();
const mfem::IntegrationRule &ir = integ->GetIntegrationRule();
const int elements = fespace.GetNE();
const int numQuad = ir.GetNPoints();
Vector quadCoeff(*(new Layout(OccaEngine(), numQuad * elements)));
Eval(quadCoeff);
return quadCoeff;
}
void OccaCoefficient::Eval(Vector &quadCoeff)
{
const std::string &okl_path = OccaEngine().GetOklPath();
static ::occa::kernelBuilder builder =
::occa::kernelBuilder::fromFile(okl_path + "coefficient.okl",
"CoefficientEval");
if (integ == NULL)
{
mfem_error("OccaCoefficient requires a Setup() call before Eval()");
}
const int elements = integ->GetTrialFESpace().GetNE();
::occa::properties kernelProps = props;
if (name != "COEFF")
{
kernelProps["defines/COEFF"] = name;
kernelProps["defines/COEFF_ARGS"] = name + "_ARGS";
}
::occa::kernel evalKernel = builder.build(GetDevice(), kernelProps);
evalKernel(elements, *this, quadCoeff.OccaMem());
}
OccaCoefficient::operator ::occa::kernelArg ()
{
::occa::kernelArg kArg;
const int paramCount = (int) params.size();
for (int i = 0; i < paramCount; ++i)
{
kArg.add(params[i]->KernelArgs());
}
return kArg;
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+287
View File
@@ -0,0 +1,287 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_COEFFICIENT_HPP
#define MFEM_BACKENDS_OCCA_COEFFICIENT_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "vector.hpp"
#include "gridfunc.hpp"
namespace mfem
{
namespace occa
{
class OccaIntegrator;
class OccaParameter
{
public:
virtual ~OccaParameter();
virtual OccaParameter* Clone() = 0;
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props);
virtual ::occa::kernelArg KernelArgs();
};
//---[ Include Parameter ]------------
class OccaIncludeParameter : public OccaParameter
{
private:
std::string filename;
public:
OccaIncludeParameter(const std::string &filename_);
virtual OccaParameter* Clone();
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props);
};
//====================================
//---[ Source Parameter ]------------
class OccaSourceParameter : public OccaParameter
{
private:
std::string source;
public:
OccaSourceParameter(const std::string &filename_);
virtual OccaParameter* Clone();
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props);
};
//====================================
//---[ Define Parameter ]------------
template <class TM>
class OccaDefineParameter : public OccaParameter
{
private:
const std::string name;
TM value;
public:
OccaDefineParameter(const std::string &name_,
const TM &value_) :
name(name_),
value(value_) {}
virtual OccaParameter* Clone()
{
return new OccaDefineParameter(name, value);
}
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props)
{
props["defines"][name] = value;
}
};
//====================================
//---[ Variable Parameter ]-----------
template <class TM>
class OccaVariableParameter : public OccaParameter
{
private:
const std::string name;
const TM &value;
public:
OccaVariableParameter(const std::string &name_,
const TM &value_) :
name(name_),
value(value_) {}
virtual OccaParameter* Clone()
{
return new OccaVariableParameter(name, value);
}
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props)
{
std::string &args = (props["defines/COEFF_ARGS"]
.asString()
.string());
// const TM name,\n"
args += "const ";
args += ::occa::primitiveinfo<TM>::name;
args += ' ';
args += name;
args += ",\n";
}
virtual ::occa::kernelArg KernelArgs()
{
return ::occa::kernelArg(value);
}
};
//====================================
//---[ Vector Parameter ]-------
class OccaVectorParameter : public OccaParameter
{
private:
const std::string name;
Vector v;
bool useRestrict;
std::string attr;
public:
OccaVectorParameter(const std::string &name_,
Vector &v_,
const bool useRestrict_ = false);
OccaVectorParameter(const std::string &name_,
Vector &v_,
const std::string &attr_,
const bool useRestrict_ = false);
virtual OccaParameter* Clone();
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props);
virtual ::occa::kernelArg KernelArgs();
};
//====================================
//---[ GridFunction Parameter ]-------
class OccaGridFunctionParameter : public OccaParameter
{
private:
const std::string name;
mfem::GridFunction &gf;
Vector gfQuad;
bool useRestrict;
public:
OccaGridFunctionParameter(const std::string &name_,
const Engine &e,
mfem::GridFunction &gf_,
const bool useRestrict_ = false);
virtual OccaParameter* Clone();
virtual void Setup(OccaIntegrator &integ,
::occa::properties &props);
virtual ::occa::kernelArg KernelArgs();
};
//====================================
//---[ Coefficient ]------------------
// [MISSING]
// Needs to know about the integrator's
// - fespace
// - ir
// Step where parameters that need the ir get called for setup
// For example, GridFunction (d, e) -> (q, e)
class OccaCoefficient
{
private:
SharedPtr<const Engine> engine;
OccaIntegrator *integ;
std::string name;
::occa::json coeffValue;
::occa::properties props;
std::vector<OccaParameter*> params;
public:
OccaCoefficient(const Engine &e, const double value = 1.0);
OccaCoefficient(const Engine &e, mfem::GridFunction &gf,
const bool useRestrict = false);
OccaCoefficient(const Engine &e, const std::string &source);
OccaCoefficient(const Engine &e, const char *source);
~OccaCoefficient();
OccaCoefficient(const OccaCoefficient &coeff);
const Engine &OccaEngine() const { return *engine; }
::occa::device GetDevice(int idx = 0) const
{ return engine->GetDevice(idx); }
OccaCoefficient& SetName(const std::string &name_);
void Setup(OccaIntegrator &integ_,
::occa::properties &props_);
OccaCoefficient& Add(OccaParameter *param);
OccaCoefficient& IncludeHeader(const std::string &filename);
OccaCoefficient& IncludeSource(const std::string &source);
template <class TM>
OccaCoefficient& AddDefine(const std::string &name_, const TM &value)
{
return Add(new OccaDefineParameter<TM>(name_, value));
}
template <class TM>
OccaCoefficient& AddVariable(const std::string &name_, const TM &value)
{
return Add(new OccaVariableParameter<TM>(name_, value));
}
OccaCoefficient& AddVector(const std::string &name_,
Vector &v,
const bool useRestrict = false);
OccaCoefficient& AddVector(const std::string &name_,
Vector &v,
const std::string &attr,
const bool useRestrict = false);
OccaCoefficient& AddGridFunction(const std::string &name_,
mfem::GridFunction &gf,
const bool useRestrict = false);
bool IsConstant();
double GetConstantValue();
Vector Eval();
void Eval(Vector &quadCoeff);
operator ::occa::kernelArg ();
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_COEFFICIENT_HPP
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_OCCA_DEFINES
#define MFEM_OCCA_DEFINES
#ifndef USING_TENSOR_OPS
# define USING_TENSOR_OPS 0
#endif
#ifdef OCCA_USING_GPU
# define GPU_ORDER_2(I0, I1) @dimOrder(I0, I1)
# define GPU_ORDER_3(I0, I1, I2) @dimOrder(I0, I1, I2)
# define GPU_ORDER_4(I0, I1, I2, I3) @dimOrder(I0, I1, I2, I3)
#else
# define GPU_ORDER_2(I0, I1) @dimOrder(0, 1)
# define GPU_ORDER_3(I0, I1, I2) @dimOrder(0, 1, 2)
# define GPU_ORDER_4(I0, I1, I2, I3) @dimOrder(0, 1, 2, 3)
#endif
#ifndef COEFF
# define COEFF 1.0
# define COEFF_ARGS
#endif
#if USING_TENSOR_OPS
# include "mfem-occa://defines/tensor.okl"
#else
# include "mfem-occa://defines/simplex.okl"
#endif
#endif
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#define USING_LOW_ORDER 1
#define USING_HI_ORDER 0
typedef double* DofToQuad_t @dim(NUM_QUAD, NUM_DOFS);
typedef double* DofToQuadD2D_t @dim(2, NUM_QUAD, NUM_DOFS);
typedef double* DofToQuadD3D_t @dim(3, NUM_QUAD, NUM_DOFS);
typedef double* QuadToDof_t @dim(NUM_DOFS, NUM_QUAD);
typedef double* QuadToDofD2D_t @dim(2, NUM_DOFS, NUM_QUAD);
typedef double* QuadToDofD3D_t @dim(3, NUM_DOFS, NUM_QUAD);
typedef double* Jacobian2D_t @dim(2, 2, NUM_QUAD, numElements);
typedef double* Jacobian3D_t @dim(3, 3, NUM_QUAD, numElements);
typedef double* SymmOperator2D_t @dim(3, NUM_QUAD, numElements);
typedef double* SymmOperator3D_t @dim(6, NUM_QUAD, numElements);
typedef double* DLocal_t @dim(NUM_DOFS, numElements);
typedef double* QLocal_t @dim(NUM_QUAD, numElements);
#if VDIM_ORDERING == ORDERING_BY_VDIM
typedef double* DVLocal_t @dim(NUM_VDIM, NUM_DOFS, numElements);
typedef double* QVLocal_t @dim(NUM_VDIM, NUM_QUAD, numElements);
#else
typedef double* DVLocal_t @dim(NUM_VDIM, NUM_DOFS, numElements) @dimOrder(2,0,1);
typedef double* QVLocal_t @dim(NUM_VDIM, NUM_QUAD, numElements) @dimOrder(2,0,1);
#endif
typedef int* DLocalMap_t @dim(NUM_DOFS, numElements);
+85
View File
@@ -0,0 +1,85 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#if NUM_QUAD_1D < NUM_DOFS_1D
# define NUM_MAX_1D NUM_DOFS_1D
#else
# define NUM_MAX_1D NUM_QUAD_1D
#endif
#define NUM_MAX_2D (NUM_MAX_1D * NUM_MAX_1D)
#define NUM_QUAD_DOFS_1D (NUM_QUAD_1D * NUM_DOFS_1D)
#define QUAD_2D_ID(X, Y) (X + ((Y) * NUM_QUAD_1D))
#define DOFS_2D_ID(X, Y) (X + ((Y) * NUM_DOFS_1D))
#define QUAD_3D_ID(X, Y, Z) (X + ((Y) * NUM_QUAD_1D) + ((Z) * NUM_QUAD_2D))
#define DOFS_3D_ID(X, Y, Z) (X + ((Y) * NUM_DOFS_1D) + ((Z) * NUM_DOFS_2D))
#if NUM_MAX_1D < 8
# define USING_LOW_ORDER 1
# define USING_HI_ORDER 0
#else
# define USING_LOW_ORDER 0
# define USING_HI_ORDER 1
#endif
#define M1_ELEMENT_BATCHES (M1_OUTER_ELEMENT_BATCH * M1_INNER_ELEMENT_BATCH)
typedef double* DofToQuad_t @dim(NUM_QUAD_1D, NUM_DOFS_1D);
typedef double* QuadToDof_t @dim(NUM_DOFS_1D, NUM_QUAD_1D);
typedef double* Jacobian_t @dim(NUM_DIM, NUM_DIM, numElements);
typedef double* Jacobian1D_t @dim(NUM_QUAD_1D, numElements);
typedef double* Jacobian2D_t @dim(2, 2, NUM_QUAD_2D, numElements);
typedef double* Jacobian3D_t @dim(3, 3, NUM_QUAD_3D, numElements);
typedef double* SymmOperator1D_t @dim(NUM_QUAD_1D, numElements);
typedef double* SymmOperator2D_t @dim(3, NUM_QUAD_2D, numElements);
typedef double* SymmOperator3D_t @dim(6, NUM_QUAD_3D, numElements);
typedef double* DLocal_t @dim(NUM_DOFS, numElements);
typedef double* DLocal1D_t @dim(NUM_DOFS_1D, numElements);
typedef double* DLocal2D_t @dim(NUM_DOFS_1D, NUM_DOFS_1D, numElements);
typedef double* DLocal3D_t @dim(NUM_DOFS_1D, NUM_DOFS_1D, NUM_DOFS_1D, numElements);
typedef double* QLocal_t @dim(NUM_QUAD, numElements);
typedef double* QLocal1D_t @dim(NUM_QUAD_1D, numElements);
typedef double* QLocal2D_t @dim(NUM_QUAD_1D, NUM_QUAD_1D, numElements);
typedef double* QLocal3D_t @dim(NUM_QUAD_1D, NUM_QUAD_1D, NUM_QUAD_1D, numElements);
#if VDIM_ORDERING == ORDERING_BY_VDIM
typedef double* DVLocal_t @dim(NUM_VDIM, NUM_DOFS, numElements);
typedef double* DVLocal1D_t @dim(NUM_VDIM, NUM_DOFS_1D, numElements);
typedef double* DVLocal2D_t @dim(NUM_VDIM, NUM_DOFS_1D, NUM_DOFS_1D, numElements);
typedef double* DVLocal3D_t @dim(NUM_VDIM, NUM_DOFS_1D, NUM_DOFS_1D, NUM_DOFS_1D, numElements);
typedef double* QVLocal_t @dim(NUM_VDIM, NUM_QUAD, numElements);
typedef double* QVLocal1D_t @dim(NUM_VDIM, NUM_QUAD_1D, numElements);
typedef double* QVLocal2D_t @dim(NUM_VDIM, NUM_QUAD_1D, NUM_QUAD_1D, numElements);
typedef double* QVLocal3D_t @dim(NUM_VDIM, NUM_QUAD_1D, NUM_QUAD_1D, NUM_QUAD_1D, numElements);
#else
typedef double* DVLocal_t @dim(NUM_VDIM, NUM_DOFS, numElements) @dimOrder(2,0,1);
typedef double* DVLocal1D_t @dim(NUM_VDIM, NUM_DOFS_1D, numElements) @dimOrder(2,0,1);
typedef double* DVLocal2D_t @dim(NUM_VDIM, NUM_DOFS_1D, NUM_DOFS_1D, numElements) @dimOrder(3,0,1,2);
typedef double* DVLocal3D_t @dim(NUM_VDIM, NUM_DOFS_1D, NUM_DOFS_1D, NUM_DOFS_1D, numElements) @dimOrder(4,0,1,2,3);
typedef double* QVLocal_t @dim(NUM_VDIM, NUM_QUAD, numElements) @dimOrder(2,0,1);
typedef double* QVLocal1D_t @dim(NUM_VDIM, NUM_QUAD_1D, numElements) @dimOrder(2,0,1);
typedef double* QVLocal2D_t @dim(NUM_VDIM, NUM_QUAD_1D, NUM_QUAD_1D, numElements) @dimOrder(3,0,1,2);
typedef double* QVLocal3D_t @dim(NUM_VDIM, NUM_QUAD_1D, NUM_QUAD_1D, NUM_QUAD_1D, numElements) @dimOrder(4,0,1,2,3);
#endif
typedef int* DLocalMap_t @dim(NUM_DOFS, numElements);
typedef int* DLocalMap1D_t @dim(NUM_DOFS_1D, numElements);
typedef int* DLocalMap2D_t @dim(NUM_DOFS_1D, NUM_DOFS_1D, numElements);
typedef int* DLocalMap3D_t @dim(NUM_DOFS_1D, NUM_DOFS_1D, NUM_DOFS_1D, numElements);
+168
View File
@@ -0,0 +1,168 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double *quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict SymmOperator2D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
const double c_detJ = quadWeights[q] * COEFF / ((J11 * J22) - (J21 * J12));
oper(0, q, e) = c_detJ * (J12*J12 + J22*J22); // (1,1)
oper(1, q, e) = -c_detJ * (J12*J11 + J22*J21); // (1,2) + (2,1)
oper(2, q, e) = c_detJ * (J11*J11 + J21*J21); // (2,2)
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_sol[NUM_DOFS];
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] = 0;
}
for (int q = 0; q < NUM_QUAD; ++q) {
double gradX = 0, gradY = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double s = solIn(d, e);
gradX += s * quadToDofD(0, d, q);
gradY += s * quadToDofD(1, d, q);
}
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O22 = oper(2, q, e);
const double gradX2 = (O11 * gradX) + (O12 * gradY);
const double gradY2 = (O12 * gradX) + (O22 * gradY);
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] += ((gradX2 * quadToDofD(0, d, q)) +
(gradY2 * quadToDofD(1, d, q)));
}
}
for (int d = 0; d < NUM_DOFS; ++d) {
solOut(d, e) += r_sol[d];
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict SymmOperator3D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
const double c_detJ = quadWeights[q] * COEFF / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J23 * J31) - (J21 * J33);
const double A13 = (J21 * J32) - (J22 * J31);
const double A21 = (J13 * J32) - (J12 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J12 * J31) - (J11 * J32);
const double A31 = (J12 * J23) - (J13 * J22);
const double A32 = (J13 * J21) - (J11 * J23);
const double A33 = (J11 * J22) - (J12 * J21);
// adj(J)^Tadj(J)
oper(0, q, e) = c_detJ * (A11*A11 + A21*A21 + A31*A31); // (1,1)
oper(1, q, e) = c_detJ * (A11*A12 + A21*A22 + A31*A32); // (1,2) + (2,1)
oper(2, q, e) = c_detJ * (A11*A13 + A21*A23 + A31*A33); // (1,3) + (3,1)
oper(3, q, e) = c_detJ * (A12*A12 + A22*A22 + A32*A32); // (2,2)
oper(4, q, e) = c_detJ * (A12*A13 + A22*A23 + A32*A33); // (2,3) + (3,2)
oper(5, q, e) = c_detJ * (A13*A13 + A23*A23 + A33*A33); // (3,3)
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_sol[NUM_DOFS];
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] = 0;
}
for (int q = 0; q < NUM_QUAD; ++q) {
double gradX = 0, gradY = 0, gradZ = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double s = solIn(d, e);
gradX += s * quadToDofD(0, d, q);
gradY += s * quadToDofD(1, d, q);
gradZ += s * quadToDofD(2, d, q);
}
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O13 = oper(2, q, e);
const double O22 = oper(3, q, e);
const double O23 = oper(4, q, e);
const double O33 = oper(5, q, e);
const double gradX2 = (O11 * gradX) + (O12 * gradY) + (O13 * gradZ);
const double gradY2 = (O12 * gradX) + (O22 * gradY) + (O23 * gradZ);
const double gradZ2 = (O13 * gradX) + (O23 * gradY) + (O33 * gradZ);
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] += ((gradX2 * quadToDofD(0, d, q)) +
(gradY2 * quadToDofD(1, d, q)) +
(gradZ2 * quadToDofD(2, d, q)));
}
}
for (int d = 0; d < NUM_DOFS; ++d) {
solOut(d, e) += r_sol[d];
}
}
}
}
//======================================
@@ -0,0 +1,182 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
const double *quadWeights,
const Jacobian2D_t J,
COEFF_ARGS
SymmOperator2D_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A2_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A2_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A2_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += A2_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
const double c_detJ = quadWeights[q] * COEFF / ((J11 * J22) - (J21 * J12));
oper(0, q, e) = c_detJ * (J12*J12 + J22*J22); // (1,1)
oper(1, q, e) = -c_detJ * (J12*J11 + J22*J21); // (1,2) + (2,1)
oper(2, q, e) = c_detJ * (J11*J11 + J21*J21); // (2,2)
}
}
}
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gradX[NUM_QUAD];
@shared double s_gradY[NUM_QUAD];
for (int qOff = 0; qOff < M2_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M2_INNER_BATCH) {
double gradX = 0, gradY = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double s = solIn(d, e);
gradX += s * quadToDofD(0, d, q);
gradY += s * quadToDofD(1, d, q);
}
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O22 = oper(2, q, e);
s_gradX[q] = (O11 * gradX) + (O12 * gradY);
s_gradY[q] = (O12 * gradX) + (O22 * gradY);
}
}
for (int dOff = 0; dOff < M2_INNER_BATCH; ++dOff) {
for (int d = dOff; d < NUM_DOFS; d += M2_INNER_BATCH) {
double r_sol = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
// FIXME: s_gradX and s_gradY are @shared used outside of @inner
r_sol += ((s_gradX[q] * quadToDofD(0, d, q)) +
(s_gradY[q] * quadToDofD(1, d, q)));
}
solOut(d, e) += r_sol;
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
const double *quadWeights,
const Jacobian3D_t J,
COEFF_ARGS
SymmOperator3D_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A3_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A3_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A3_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += A3_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
const double c_detJ = quadWeights[q] * COEFF / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J23 * J31) - (J21 * J33);
const double A13 = (J21 * J32) - (J22 * J31);
const double A21 = (J13 * J32) - (J12 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J12 * J31) - (J11 * J32);
const double A31 = (J12 * J23) - (J13 * J22);
const double A32 = (J13 * J21) - (J11 * J23);
const double A33 = (J11 * J22) - (J12 * J21);
// adj(J)^Tadj(J)
oper(0, q, e) = c_detJ * (A11*A11 + A21*A21 + A31*A31); // (1,1)
oper(1, q, e) = c_detJ * (A11*A12 + A21*A22 + A31*A32); // (1,2) + (2,1)
oper(2, q, e) = c_detJ * (A11*A13 + A21*A23 + A31*A33); // (1,3) + (3,1)
oper(3, q, e) = c_detJ * (A12*A12 + A22*A22 + A32*A32); // (2,2)
oper(4, q, e) = c_detJ * (A12*A13 + A22*A23 + A32*A33); // (2,3) + (3,2)
oper(5, q, e) = c_detJ * (A13*A13 + A23*A23 + A33*A33); // (3,3)
}
}
}
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gradX[NUM_QUAD];
@shared double s_gradY[NUM_QUAD];
@shared double s_gradZ[NUM_QUAD];
for (int qOff = 0; qOff < M3_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M3_INNER_BATCH) {
double gradX = 0, gradY = 0, gradZ = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double s = solIn(d, e);
gradX += s * quadToDofD(0, d, q);
gradY += s * quadToDofD(1, d, q);
gradZ += s * quadToDofD(2, d, q);
}
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O13 = oper(2, q, e);
const double O22 = oper(3, q, e);
const double O23 = oper(4, q, e);
const double O33 = oper(5, q, e);
s_gradX[q] = (O11 * gradX) + (O12 * gradY) + (O13 * gradZ);
s_gradY[q] = (O12 * gradX) + (O22 * gradY) + (O23 * gradZ);
s_gradZ[q] = (O13 * gradX) + (O23 * gradY) + (O33 * gradZ);
}
}
for (int dOff = 0; dOff < M3_INNER_BATCH; ++dOff) {
for (int d = dOff; d < NUM_DOFS; d += M3_INNER_BATCH) {
double r_sol = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_sol += ((s_gradX[q] * quadToDofD(0, d, q)) +
(s_gradY[q] * quadToDofD(1, d, q)) +
(s_gradZ[q] * quadToDofD(2, d, q)));
}
solOut(d, e) += r_sol;
}
}
}
}
//======================================
+370
View File
@@ -0,0 +1,370 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian1D_t J,
COEFF_ARGS
@restrict SymmOperator1D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF / J(q, e);
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double grad[NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qx] += s * dofToQuadD(qx, dx);
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qx] *= oper(qx, e);
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double gradX = grad[qx];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, e) += gradX * quadToDofD(dx, qx);
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict SymmOperator2D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_2D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
const double c_detJ = quadWeights[q] * COEFF / ((J11 * J22) - (J21 * J12));
oper(0, q, e) = c_detJ * (J21*J21 + J22*J22); // (1,1)
oper(1, q, e) = -c_detJ * (J21*J11 + J22*J12); // (1,2), (2,1)
oper(2, q, e) = c_detJ * (J11*J11 + J12*J12); // (2,2)
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double grad[NUM_QUAD_1D][NUM_QUAD_1D][2];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qy][qx][0] = 0;
grad[qy][qx][1] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double gradX[NUM_QUAD_1D][2];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
gradX[qx][0] = 0;
gradX[qx][1] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, dy, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
gradX[qx][0] += s * dofToQuad(qx, dx);
gradX[qx][1] += s * dofToQuadD(qx, dx);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
const double wDy = dofToQuadD(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qy][qx][0] += gradX[qx][1] * wy;
grad[qy][qx][1] += gradX[qx][0] * wDy;
}
}
}
// Calculate Dxy, xDy in plane
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const int q = QUAD_2D_ID(qx, qy);
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O22 = oper(2, q, e);
const double gradX = grad[qy][qx][0];
const double gradY = grad[qy][qx][1];
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double gradX[NUM_DOFS_1D][2];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
gradX[dx][0] = 0;
gradX[dx][1] = 0;
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double gX = grad[qy][qx][0];
const double gY = grad[qy][qx][1];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double wx = quadToDof(dx, qx);
const double wDx = quadToDofD(dx, qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = quadToDof(dy, qy);
const double wDy = quadToDofD(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, dy, e) += ((gradX[dx][0] * wy) +
(gradX[dx][1] * wDy));
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict SymmOperator3D_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_3D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
const double c_detJ = quadWeights[q] * COEFF / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J23 * J31) - (J21 * J33);
const double A13 = (J21 * J32) - (J22 * J31);
const double A21 = (J13 * J32) - (J12 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J12 * J31) - (J11 * J32);
const double A31 = (J12 * J23) - (J13 * J22);
const double A32 = (J13 * J21) - (J11 * J23);
const double A33 = (J11 * J22) - (J12 * J21);
// adj(J)^Tadj(J)
oper(0, q, e) = c_detJ * (A11*A11 + A21*A21 + A31*A31); // (1,1)
oper(1, q, e) = c_detJ * (A11*A12 + A21*A22 + A31*A32); // (1,2), (2,1)
oper(2, q, e) = c_detJ * (A11*A13 + A21*A23 + A31*A33); // (1,3), (3,1)
oper(3, q, e) = c_detJ * (A12*A12 + A22*A22 + A32*A32); // (2,2)
oper(4, q, e) = c_detJ * (A12*A13 + A22*A23 + A32*A33); // (2,3), (3,2)
oper(5, q, e) = c_detJ * (A13*A13 + A23*A23 + A33*A33); // (3,3)
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double grad[NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D][4];
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qz][qy][qx][0] = 0;
grad[qz][qy][qx][1] = 0;
grad[qz][qy][qx][2] = 0;
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
double gradXY[NUM_QUAD_1D][NUM_QUAD_1D][4];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
gradXY[qy][qx][0] = 0;
gradXY[qy][qx][1] = 0;
gradXY[qy][qx][2] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double gradX[NUM_QUAD_1D][2];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
gradX[qx][0] = 0;
gradX[qx][1] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, dy, dz, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
gradX[qx][0] += s * dofToQuad(qx, dx);
gradX[qx][1] += s * dofToQuadD(qx, dx);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
const double wDy = dofToQuadD(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double wx = gradX[qx][0];
const double wDx = gradX[qx][1];
gradXY[qy][qx][0] += wDx * wy;
gradXY[qy][qx][1] += wx * wDy;
gradXY[qy][qx][2] += wx * wy;
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
const double wz = dofToQuad(qz, dz);
const double wDz = dofToQuadD(qz, dz);
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
}
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const int q = QUAD_3D_ID(qx, qy, qz);
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O13 = oper(2, q, e);
const double O22 = oper(3, q, e);
const double O23 = oper(4, q, e);
const double O33 = oper(5, q, e);
const double gradX = grad[qz][qy][qx][0];
const double gradY = grad[qz][qy][qx][1];
const double gradZ = grad[qz][qy][qx][2];
grad[qz][qy][qx][0] = (O11 * gradX) + (O12 * gradY) + (O13 * gradZ);
grad[qz][qy][qx][1] = (O12 * gradX) + (O22 * gradY) + (O23 * gradZ);
grad[qz][qy][qx][2] = (O13 * gradX) + (O23 * gradY) + (O33 * gradZ);
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
double gradXY[NUM_DOFS_1D][NUM_DOFS_1D][4];
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
gradXY[dy][dx][0] = 0;
gradXY[dy][dx][1] = 0;
gradXY[dy][dx][2] = 0;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double gradX[NUM_DOFS_1D][4];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
gradX[dx][0] = 0;
gradX[dx][1] = 0;
gradX[dx][2] = 0;
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double gX = grad[qz][qy][qx][0];
const double gY = grad[qz][qy][qx][1];
const double gZ = grad[qz][qy][qx][2];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double wx = quadToDof(dx, qx);
const double wDx = quadToDofD(dx, qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
gradX[dx][2] += gZ * wx;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = quadToDof(dy, qy);
const double wDy = quadToDofD(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
gradXY[dy][dx][0] += gradX[dx][0] * wy;
gradXY[dy][dx][1] += gradX[dx][1] * wDy;
gradXY[dy][dx][2] += gradX[dx][2] * wy;
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = quadToDof(dz, qz);
const double wDz = quadToDofD(dz, qz);
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, dy, dz, e) += ((gradXY[dy][dx][0] * wz) +
(gradXY[dy][dx][1] * wz) +
(gradXY[dy][dx][2] * wDz));
}
}
}
}
}
}
}
//======================================
@@ -0,0 +1,435 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
const double *quadWeights,
const Jacobian1D_t J,
COEFF_ARGS
SymmOperator1D_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A1_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A1_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF / J(q, e);
}
}
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M1_ELEMENT_BATCHES; @outer) {
@shared double s_dofToQuadD[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDofD[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@exclusive double grad[NUM_QUAD_1D];
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
for (int i = el; i < NUM_QUAD_DOFS_1D; i += M1_INNER_ELEMENT_BATCH) {
s_dofToQuadD[i] = dofToQuadD[i];
s_quadToDofD[i] = quadToDofD[i];
}
}
for (int b = 0; b < M1_OUTER_ELEMENT_BATCH; ++b) {
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
const int e = eOff + b*M1_INNER_ELEMENT_BATCH + el;
if (e < numElements) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qx] += s * s_dofToQuadD(qx, dx);
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
grad[qx] *= oper(qx, e);
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
double s = 0;
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
s += grad[qx] * s_quadToDofD(dx, qx);
}
solOut(dx, e) += s;
}
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
const double *quadWeights,
const Jacobian2D_t J,
COEFF_ARGS
SymmOperator2D_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A2_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A2_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A2_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD_2D; q += A2_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
const double c_detJ = quadWeights[q] * COEFF / ((J11 * J22) - (J21 * J12));
oper(0, q, e) = c_detJ * (J21*J21 + J22*J22); // (1,1)
oper(1, q, e) = -c_detJ * (J21*J11 + J22*J12); // (1,2), (2,1)
oper(2, q, e) = c_detJ * (J11*J11 + J12*J12); // (2,2)
}
}
}
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M2_ELEMENT_BATCH; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_dofToQuadD[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@shared double s_quadToDofD[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
// Store xy planes in shared memory
@shared double s_xy[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@shared double s_xDy[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@shared double s_grad[2 * NUM_QUAD_2D] @dim(2, NUM_QUAD_1D, NUM_QUAD_1D);
@exclusive double r_x[NUM_MAX_1D];
@exclusive double r_y[NUM_QUAD_1D];
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
for (int id = x; id < NUM_QUAD_DOFS_1D; id += NUM_MAX_1D) {
s_dofToQuad[id] = dofToQuad[id];
s_dofToQuadD[id] = dofToQuadD[id];
s_quadToDof[id] = quadToDof[id];
s_quadToDofD[id] = quadToDofD[id];
}
}
for (int e = eOff; e < (eOff + M2_ELEMENT_BATCH); ++e) {
if (e < numElements) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
s_xy(dx, qy) = 0;
s_xDy(dx, qy) = 0;
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
r_x[dy] = solIn(dx, dy, e);
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double xy = 0;
double xDy = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
xy += r_x[dy] * s_dofToQuad(qy, dy);
xDy += r_x[dy] * s_dofToQuadD(qy, dy);
}
s_xy(dx, qy) = xy;
s_xDy(dx, qy) = xDy;
}
}
}
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
if (qy < NUM_QUAD_1D) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
double gradX = 0, gradY = 0;
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
gradX += s_xy(dx, qy) * s_dofToQuadD(qx, dx);
gradY += s_xDy(dx, qy) * s_dofToQuad(qx, dx);
}
const int q = QUAD_2D_ID(qx, qy);
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O22 = oper(2, q, e);
s_grad(0, qx, qy) = (O11 * gradX) + (O12 * gradY);
s_grad(1, qx, qy) = (O12 * gradX) + (O22 * gradY);
}
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx; @inner) {
if (qx < NUM_QUAD_1D) {
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
s_xy(dy, qx) = 0;
s_xDy(dy, qx) = 0;
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
r_x[qy] = s_grad(0, qx, qy);
r_y[qy] = s_grad(1, qx, qy);
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double xy = 0;
double xDy = 0;
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
xy += r_x[qy] * s_quadToDof(dy, qy);
xDy += r_y[qy] * s_quadToDofD(dy, qy);
}
s_xy(dy, qx) = xy;
s_xDy(dy, qx) = xDy;
}
}
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double s = 0;
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
s += ((s_xy(dy, qx) * s_quadToDofD(dx, qx)) +
(s_xDy(dy, qx) * s_quadToDof(dx, qx)));
}
solOut(dx, dy, e) += s;
}
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
const double *quadWeights,
const Jacobian3D_t J,
COEFF_ARGS
SymmOperator3D_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A3_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A3_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A3_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD_3D; q += A3_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
const double c_detJ = quadWeights[q] * COEFF / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J23 * J31) - (J21 * J33);
const double A13 = (J21 * J32) - (J22 * J31);
const double A21 = (J13 * J32) - (J12 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J12 * J31) - (J11 * J32);
const double A31 = (J12 * J23) - (J13 * J22);
const double A32 = (J13 * J21) - (J11 * J23);
const double A33 = (J11 * J22) - (J12 * J21);
// adj(J)^Tadj(J)
oper(0, q, e) = c_detJ * (A11*A11 + A21*A21 + A31*A31); // (1,1)
oper(1, q, e) = c_detJ * (A11*A12 + A21*A22 + A31*A32); // (1,2), (2,1)
oper(2, q, e) = c_detJ * (A11*A13 + A21*A23 + A31*A33); // (1,3), (3,1)
oper(3, q, e) = c_detJ * (A12*A12 + A22*A22 + A32*A32); // (2,2)
oper(4, q, e) = c_detJ * (A12*A13 + A22*A23 + A32*A33); // (2,3), (3,2)
oper(5, q, e) = c_detJ * (A13*A13 + A23*A23 + A33*A33); // (3,3)
}
}
}
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const SymmOperator3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_dofToQuadD[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@shared double s_quadToDofD[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
// Store xy planes in shared memory
@shared double s_z[NUM_MAX_2D] @dim(NUM_MAX_1D, NUM_MAX_1D);
@shared double s_Dz[NUM_MAX_2D] @dim(NUM_MAX_1D, NUM_MAX_1D);
@shared double s_xyDz[NUM_QUAD_2D] @dim(NUM_QUAD_1D, NUM_QUAD_1D);
// Store z axis as registers
@exclusive double r_qz[NUM_QUAD_1D];
@exclusive double r_qDz[NUM_QUAD_1D];
@exclusive double r_dDxyz[NUM_DOFS_1D];
@exclusive double r_dxDyz[NUM_DOFS_1D];
@exclusive double r_dxyDz[NUM_DOFS_1D];
for (int y = 0; y < NUM_MAX_1D; ++y; @inner) {
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
const int id = (y * NUM_MAX_1D) + x;
// Fetch Q <--> D maps
if (id < NUM_QUAD_DOFS_1D) {
s_dofToQuad[id] = dofToQuad[id];
s_dofToQuadD[id] = dofToQuadD[id];
s_quadToDof[id] = quadToDof[id];
s_quadToDofD[id] = quadToDofD[id];
}
// Initialize our Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_qz[qz] = 0;
r_qDz[qz] = 0;
}
// Initialize our solution updates in the Z axis
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
r_dDxyz[dz] = 0;
r_dxDyz[dz] = 0;
r_dxyDz[dz] = 0;
}
}
}
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double s = solIn(dx, dy, dz, e);
// Calculate D -> Q in the Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_qz[qz] += s * s_dofToQuad(qz, dz);
r_qDz[qz] += s * s_dofToQuadD(qz, dz);
}
}
}
}
}
// For each xy plane
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
// Fill xy plane at given z position
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
s_z(dx, dy) = r_qz[qz];
s_Dz(dx, dy) = r_qDz[qz];
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
double Dxyz = 0;
double xDyz = 0;
double xyDz = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = s_dofToQuad(qy, dy);
const double wDy = s_dofToQuadD(qy, dy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double wx = s_dofToQuad(qx, dx);
const double wDx = s_dofToQuadD(qx, dx);
const double z = s_z(dx, dy);
const double Dz = s_Dz(dx, dy);
Dxyz += wDx * wy * z;
xDyz += wx * wDy * z;
xyDz += wx * wy * Dz;
}
}
const int q = QUAD_3D_ID(qx, qy, qz);
const double O11 = oper(0, q, e);
const double O12 = oper(1, q, e);
const double O13 = oper(2, q, e);
const double O22 = oper(3, q, e);
const double O23 = oper(4, q, e);
const double O33 = oper(5, q, e);
const double qDxyz = (O11 * Dxyz) + (O12 * xDyz) + (O13 * xyDz);
const double qxDyz = (O12 * Dxyz) + (O22 * xDyz) + (O23 * xyDz);
const double qxyDz = (O13 * Dxyz) + (O23 * xDyz) + (O33 * xyDz);
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = s_quadToDof(dz, qz);
const double wDz = s_quadToDofD(dz, qz);
r_dDxyz[dz] += wz * qDxyz;
r_dxDyz[dz] += wz * qxDyz;
r_dxyDz[dz] += wDz * qxyDz;
}
}
}
}
@barrier("s_z_s_Dz_sync_1");
}
// Iterate over xy planes to compute solution
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
// Place xy plane in shared memory
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
s_z(qx, qy) = r_dDxyz[dz];
s_Dz(qx, qy) = r_dxDyz[dz];
s_xyDz(qx, qy) = r_dxyDz[dz];
}
}
}
// Finalize solution in xy plane
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
double solZ = 0;
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = s_quadToDof(dy, qy);
const double wDy = s_quadToDofD(dy, qy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double wx = s_quadToDof(dx, qx);
const double wDx = s_quadToDofD(dx, qx);
const double Dxyz = s_z(qx, qy);
const double xDyz = s_Dz(qx, qy);
const double xyDz = s_xyDz(qx, qy);
solZ += ((wDx * wy * Dxyz) +
(wx * wDy * xDyz) +
(wx * wy * xyDz));
}
}
solOut(dx, dy, dz, e) += solZ;
}
}
}
@barrier("s_z_s_Dz_s_xyDz_sync_1");
}
}
}
//======================================
+167
View File
@@ -0,0 +1,167 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "backend.hpp"
#include "url_handler.hpp"
#include "bilinearform.hpp"
#include "../../general/array.hpp"
namespace mfem
{
namespace occa
{
bool Engine::fileOpenerRegistered = false;
void Engine::Init(const std::string &engine_spec)
{
//
// Initialize inherited fields
//
memory_resources[0] = NULL;
workers_weights[0]= 1.0;
workers_mem_res[0] = 0;
//
// Initialize the OCCA engine
//
::occa::properties props(engine_spec);
device = new ::occa::device[1];
device[0].setup(props);
okl_path = "mfem-occa://";
if (!fileOpenerRegistered)
{
// The directories from "MFEM_OCCA_OKL_PATH", if any, have the highest
// priority.
FileOpener *fo = new FileOpener("mfem-occa://", "MFEM_OCCA_OKL_PATH");
// Next in priority is the source path, if it exists.
std::string mfem_src_prefix = mfem::GetSourcePath();
fo->AddDir(mfem_src_prefix + "/backends/occa");
// And last in priority is the install path, if it exists.
std::string mfem_install_prefix = mfem::GetInstallPath();
fo->AddDir(mfem_install_prefix + "/lib/mfem/occa");
::occa::io::fileOpener::add(fo);
fileOpenerRegistered = true;
}
// std::cout << "OCCA device properties:\n" << device[0].properties();
force_cuda_aware_mpi = false;
}
Engine::Engine(const std::string &engine_spec)
: mfem::Engine(NULL, 1, 1)
{
Init(engine_spec);
}
#ifdef MFEM_USE_MPI
Engine::Engine(MPI_Comm _comm, const std::string &engine_spec)
: mfem::Engine(NULL, 1, 1)
{
comm = _comm;
Init(engine_spec);
}
#endif
bool Engine::CheckEngine(const mfem::Engine *engine) const
{
return (engine != NULL && util::Is<const Engine>(engine) != NULL &&
*util::As<const Engine>(engine) == *this);
}
bool Engine::CheckLayout(const PLayout *layout) const
{
return (layout != NULL && util::Is<const Layout>(layout) != NULL &&
layout->As<Layout>().OccaEngine() == *this);
}
bool Engine::CheckArray(const PArray *array) const
{
return (array != NULL && util::Is<const Array>(array) != NULL &&
array->As<Array>().OccaEngine() == *this);
}
bool Engine::CheckVector(const PVector *vector) const
{
return (vector != NULL && util::Is<const Vector>(vector) != NULL &&
vector->As<Vector>().OccaEngine() == *this);
}
bool Engine::CheckFESpace(const PFiniteElementSpace *fes) const
{
return (fes != NULL && util::Is<const FiniteElementSpace>(fes) != NULL &&
fes->As<FiniteElementSpace>().OccaEngine() == *this);
}
DLayout Engine::MakeLayout(std::size_t size) const
{
return DLayout(new Layout(*this, size));
}
DLayout Engine::MakeLayout(const mfem::Array<std::size_t> &offsets) const
{
MFEM_ASSERT(offsets.Size() == 2,
"multiple workers are not supported yet");
return DLayout(new Layout(*this, offsets.Last()));
}
DArray Engine::MakeArray(PLayout &layout, std::size_t item_size) const
{
return DArray(new Array(layout.As<Layout>(), item_size));
}
DVector Engine::MakeVector(PLayout &layout, int type_id) const
{
MFEM_ASSERT(type_id == ScalarId<double>::value, "type_id " << type_id
<< " is not supported");
return DVector(new Vector(layout.As<Layout>()));
}
DFiniteElementSpace Engine::MakeFESpace(mfem::FiniteElementSpace &fespace) const
{
return DFiniteElementSpace(new FiniteElementSpace(*this, fespace));
}
DBilinearForm Engine::MakeBilinearForm(mfem::BilinearForm &bf) const
{
return DBilinearForm(new BilinearForm(*this, bf));
}
void Engine::AssembleLinearForm(LinearForm &l_form) const
{
/// FIXME - What will the actual parameters be?
MFEM_ABORT("FIXME");
}
mfem::Operator *Engine::MakeOperator(const MixedBilinearForm &mbl_form) const
{
/// FIXME - What will the actual parameters be?
MFEM_ABORT("FIXME");
return NULL;
}
mfem::Operator *Engine::MakeOperator(const NonlinearForm &nl_form) const
{
/// FIXME - What will the actual parameters be?
MFEM_ABORT("FIXME");
return NULL;
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+144
View File
@@ -0,0 +1,144 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_ENGINE_HPP
#define MFEM_BACKENDS_OCCA_ENGINE_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "../base/backend.hpp"
#include <occa.hpp>
namespace mfem
{
namespace occa
{
class Engine : public mfem::Engine
{
protected:
//
// Inherited fields
//
// mfem::Backend *backend;
#ifdef MFEM_USE_MPI
// MPI_Comm comm;
#endif
// int num_mem_res;
// int num_workers;
// MemoryResource **memory_resources;
// double *workers_weights;
// int *workers_mem_res;
static bool fileOpenerRegistered;
/// An array of OCCA devices. Currently only a single device is supported.
::occa::device *device;
std::string okl_path;
bool force_cuda_aware_mpi;
void Init(const std::string &engine_spec);
public:
/// TODO: doxygen
Engine(const std::string &engine_spec);
#ifdef MFEM_USE_MPI
/// TODO: doxygen
Engine(MPI_Comm comm, const std::string &engine_spec);
#endif
/// TODO: doxygen
virtual ~Engine() { delete [] device; }
/**
@name OCCA specific interface, used by other objects in the OCCA backend
*/
///@{
/// Get the associated OCCA device.
::occa::device GetDevice(int idx = 0) const { return device[idx]; }
/// TODO: doxygen
const std::string &GetOklPath() const { return okl_path; }
/// OCCA device memory allocation.
::occa::memory Alloc(std::size_t bytes) const
{ return GetDevice().malloc(bytes); }
/// Two mfem::occa::Engine%s are equal if they use the same OCCA device.
bool operator==(const Engine &other) const
{ return GetDevice() == other.GetDevice(); }
/// TODO: doxygen
bool CheckEngine(const mfem::Engine *e) const;
/// TODO: doxygen
bool CheckLayout(const PLayout *layout) const;
/// TODO: doxygen
bool CheckArray(const PArray *array) const;
/// TODO: doxygen
bool CheckVector(const PVector *vector) const;
/// TODO: doxygen
bool CheckFESpace(const PFiniteElementSpace *fes) const;
#ifdef MFEM_USE_MPI
void SetForceCudaAwareMPI(bool force = true)
{ force_cuda_aware_mpi = force; }
bool GetForceCudaAwareMPI() const { return force_cuda_aware_mpi; }
#endif
///@}
// End: OCCA specific interface
/**
@name Virtual interface: finite element data structures and algorithms
*/
///@{
virtual DLayout MakeLayout(std::size_t size) const;
virtual DLayout MakeLayout(const mfem::Array<std::size_t> &offsets) const;
virtual DArray MakeArray(PLayout &layout, std::size_t item_size) const;
virtual DVector MakeVector(PLayout &layout,
int type_id = ScalarId<double>::value) const;
virtual DFiniteElementSpace MakeFESpace(mfem::FiniteElementSpace &
fespace) const;
virtual DBilinearForm MakeBilinearForm(mfem::BilinearForm &bf) const;
/// FIXME - What will the actual parameters be?
virtual void AssembleLinearForm(LinearForm &l_form) const;
/// FIXME - What will the actual parameters be?
virtual mfem::Operator *MakeOperator(const MixedBilinearForm &mbl_form) const;
/// FIXME - What will the actual parameters be?
virtual mfem::Operator *MakeOperator(const NonlinearForm &nl_form) const;
///@}
// End: Virtual interface
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_ENGINE_HPP
+532
View File
@@ -0,0 +1,532 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "backend.hpp"
#include "fespace.hpp"
#include "interpolation.hpp"
#ifdef MFEM_USE_MPI
#ifdef OMPI_RELEASE_VERSION
#include <mpi-ext.h> // Check for cuda support
#endif
#endif
namespace mfem
{
namespace occa
{
FiniteElementSpace::FiniteElementSpace(const Engine &e,
mfem::FiniteElementSpace &fespace)
: PFiniteElementSpace(e, fespace),
e_layout(new Layout(e, 0)) // resized in SetupLocalGlobalMaps()
{
vdim = fespace.GetVDim();
ordering = fespace.GetOrdering();
SetupLocalGlobalMaps();
SetupOperators(); // calls virtual methods of 'fes'
SetupKernels();
}
FiniteElementSpace::~FiniteElementSpace()
{
delete restrictionOp;
delete prolongationOp;
}
void FiniteElementSpace::SetupLocalGlobalMaps()
{
const int elements = fes->GetNE();
if (elements == 0) { return; }
// Assuming of finite elements are the same.
const mfem::FiniteElement &fe = *fes->GetFE(0);
const mfem::TensorBasisElement *el =
dynamic_cast<const mfem::TensorBasisElement*>(&fe);
const mfem::Table &e2dTable = fes->GetElementToDofTable();
const int *elementMap = e2dTable.GetJ();
globalDofs = fes->GetNDofs();
localDofs = fe.GetDof();
e_layout->OccaResize(e2dTable.Size_of_connections());
int *elementDofMap = new int[localDofs];
if (el)
{
::memcpy(elementDofMap,
el->GetDofMap().GetData(),
localDofs * sizeof(int));
}
else
{
for (int i = 0; i < localDofs; ++i)
{
elementDofMap[i] = i;
}
}
// Allocate device offsets and indices
globalToLocalOffsets.allocate(GetDevice(),
globalDofs + 1);
globalToLocalIndices.allocate(GetDevice(),
localDofs, elements);
localToGlobalMap.allocate(GetDevice(),
localDofs, elements);
int *offsets = globalToLocalOffsets.ptr();
int *indices = globalToLocalIndices.ptr();
int *l2gMap = localToGlobalMap.ptr();
// We'll be keeping a count of how many local nodes point
// to its global dof
for (int i = 0; i <= globalDofs; ++i)
{
offsets[i] = 0;
}
for (int e = 0; e < elements; ++e)
{
MFEM_ASSERT(e2dTable.RowSize(e) == localDofs, "");
for (int d = 0; d < localDofs; ++d)
{
const int gid = elementMap[localDofs*e + d];
++offsets[gid + 1];
}
}
// Aggregate to find offsets for each global dof
for (int i = 1; i <= globalDofs; ++i)
{
offsets[i] += offsets[i - 1];
}
// For each global dof, fill in all local nodes that point
// to it
for (int e = 0; e < elements; ++e)
{
for (int d = 0; d < localDofs; ++d)
{
const int gid = elementMap[localDofs*e + elementDofMap[d]];
const int lid = localDofs*e + d;
indices[offsets[gid]++] = lid;
l2gMap[lid] = gid;
}
}
// We shifted the offsets vector by 1 by using it
// as a counter. Now we shift it back.
for (int i = globalDofs; i > 0; --i)
{
offsets[i] = offsets[i - 1];
}
offsets[0] = 0;
delete [] elementDofMap;
globalToLocalOffsets.keepInDevice();
globalToLocalIndices.keepInDevice();
localToGlobalMap.keepInDevice();
}
void FiniteElementSpace::SetupOperators() const
{
// Construct 'restrictionOp' and 'prolongationOp'.
prolongationOp = restrictionOp = NULL;
const mfem::SparseMatrix *R = fes->GetRestrictionMatrix();
const mfem::Operator *P = fes->GetProlongationMatrix();
if (!P) { return; }
Layout &v_layout = OccaVLayout();
Layout &t_layout = OccaTrueVLayout();
// Assuming R has one entry per row equal to 1.
MFEM_ASSERT(R->Finalized(), "");
const int tdofs = R->Height();
MFEM_ASSERT(tdofs == (int)t_layout.Size(), "");
MFEM_ASSERT(tdofs == R->GetI()[tdofs], "");
::occa::array<int> ltdof_ldof(GetDevice(), tdofs, R->GetJ());
ltdof_ldof.keepInDevice();
restrictionOp = new RestrictionOperator(v_layout, t_layout, ltdof_ldof);
const mfem::SparseMatrix *pmat = dynamic_cast<const mfem::SparseMatrix*>(P);
if (pmat)
{
const mfem::SparseMatrix *pmatT = Transpose(*pmat);
OccaSparseMatrix *occaP =
CreateMappedSparseMatrix(t_layout, v_layout, *pmat);
OccaSparseMatrix *occaPT =
CreateMappedSparseMatrix(v_layout, t_layout, *pmatT);
prolongationOp = new ProlongationOperator(*occaP, *occaPT);
delete occaPT;
delete occaP;
}
#ifdef MFEM_USE_MPI
else if (fes->Conforming() && dynamic_cast<ParFiniteElementSpace*>(fes))
{
ParFiniteElementSpace *pfes = static_cast<ParFiniteElementSpace*>(fes);
prolongationOp = new OccaConformingProlongation(*this, *pfes,
ltdof_ldof.memory());
}
#endif
else
{
prolongationOp = new ProlongationOperator(t_layout, v_layout, P);
}
}
void FiniteElementSpace::SetupKernels()
{
::occa::properties props("defines: {"
" TILESIZE: 256,"
"}");
props["defines/NUM_VDIM"] = vdim;
props["defines/ORDERING_BY_NODES"] = 0;
props["defines/ORDERING_BY_VDIM"] = 1;
props["defines/VDIM_ORDERING"] = (int) (ordering == Ordering::byVDIM);
::occa::device device = GetDevice();
const std::string &okl_path = OccaEngine().GetOklPath();
globalToLocalKernel = device.buildKernel(okl_path + "fespace.okl",
"GlobalToLocal",
props);
localToGlobalKernel = device.buildKernel(okl_path + "fespace.okl",
"LocalToGlobal",
props);
}
#ifdef MFEM_USE_MPI
OccaConformingProlongation::OccaConformingProlongation(
const FiniteElementSpace &ofes, const mfem::ParFiniteElementSpace &pfes,
::occa::memory ltdof_ldof_)
: Operator(ofes.OccaTrueVLayout(), ofes.OccaVLayout()),
shr_ltdof(ofes.OccaEngine()),
ext_ldof(ofes.OccaEngine()),
shr_buf(shr_ltdof.OccaLayout(), sizeof(double)),
ext_buf(ext_ldof.OccaLayout(), sizeof(double)),
shr_buf_offsets(NULL), ext_buf_offsets(NULL),
ltdof_ldof(ltdof_ldof_),
gc(pfes.GroupComm())
{
MFEM_ASSERT(pfes.Conforming(), "internal error");
const Engine &engine = ofes.OccaEngine();
const std::string &okl_path = engine.GetOklPath();
::occa::device device = engine.GetDevice();
{
Table nbr_ltdof;
gc.GetNeighborLTDofTable(nbr_ltdof);
shr_ltdof.OccaResize(nbr_ltdof.Size_of_connections(), sizeof(int));
shr_ltdof.OccaPush(nbr_ltdof.GetJ());
shr_buf.OccaResize(&shr_ltdof.OccaLayout(), sizeof(double));
shr_buf_offsets = nbr_ltdof.GetI();
{
mfem::Array<int> shr_ltdof(nbr_ltdof.GetJ(),
nbr_ltdof.Size_of_connections());
mfem::Array<int> unique_ltdof(shr_ltdof);
unique_ltdof.Sort();
unique_ltdof.Unique();
// Note: the next loop modifies the J array of nbr_ltdof
for (int i = 0; i < shr_ltdof.Size(); i++)
{
shr_ltdof[i] = unique_ltdof.FindSorted(shr_ltdof[i]);
MFEM_ASSERT(shr_ltdof[i] != -1, "internal error");
}
Table unique_shr;
Transpose(shr_ltdof, unique_shr, unique_ltdof.Size());
unq_ltdof = device.malloc(unique_ltdof.Size()*sizeof(int),
unique_ltdof.GetData());
unq_shr_i = device.malloc((unique_shr.Size()+1)*sizeof(int),
unique_shr.GetI());
unq_shr_j = device.malloc(unique_shr.Size_of_connections()*sizeof(int),
unique_shr.GetJ());
}
delete [] nbr_ltdof.GetJ();
nbr_ltdof.LoseData();
}
{
Table nbr_ldof;
gc.GetNeighborLDofTable(nbr_ldof);
ext_ldof.OccaResize(nbr_ldof.Size_of_connections(), sizeof(int));
ext_ldof.OccaPush(nbr_ldof.GetJ());
ext_buf.OccaResize(&ext_ldof.OccaLayout(), sizeof(double));
ext_buf_offsets = nbr_ldof.GetI();
delete [] nbr_ldof.GetJ();
nbr_ldof.LoseData();
}
host_shr_buf = NULL;
host_ext_buf = NULL;
// If the device has a separate memory space (e.g. CUDA device) and the MPI
// library does not support buffers in that separate memory space, we
// allocate separate host buffers to use for MPI communication.
if (device.hasSeparateMemorySpace())
{
bool need_host_buf = true;
if (device.mode() == "CUDA")
{
#ifdef MPIX_CUDA_AWARE_SUPPORT
need_host_buf = !MPIX_Query_cuda_support();
#endif
if (engine.GetForceCudaAwareMPI()) { need_host_buf = false; }
if (gc.GetGroupTopology().MyRank() == 0)
{
mfem::out << "\nOccaConformingProlongation: CUDA-aware MPI: "
<< (need_host_buf ? "NO" : "YES") << "\n\n";
}
}
if (need_host_buf)
{
host_shr_buf = new char[shr_buf.OccaMem().size()];
host_ext_buf = new char[ext_buf.OccaMem().size()];
}
}
ExtractSubVector = device.buildKernel(okl_path + "mappings.okl",
"ExtractSubVector",
"defines: { TILESIZE: 256 }");
SetSubVector = device.buildKernel(okl_path + "mappings.okl",
"SetSubVector",
"defines: { TILESIZE: 256 }");
AddSubVector = device.buildKernel(okl_path + "mappings.okl",
"AddSubVector",
"defines: { TILESIZE: 256 }");
const GroupTopology &gtopo = gc.GetGroupTopology();
int req_counter = 0;
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
{
const int send_offset = shr_buf_offsets[nbr];
const int send_size = shr_buf_offsets[nbr+1] - send_offset;
if (send_size > 0) { req_counter++; }
const int recv_offset = ext_buf_offsets[nbr];
const int recv_size = ext_buf_offsets[nbr+1] - recv_offset;
if (recv_size > 0) { req_counter++; }
}
requests = new MPI_Request[req_counter];
}
OccaConformingProlongation::~OccaConformingProlongation()
{
delete [] requests;
delete [] host_ext_buf;
delete [] host_shr_buf;
delete [] ext_buf_offsets;
delete [] shr_buf_offsets;
}
void OccaConformingProlongation::BcastBeginCopy(const ::occa::memory &src,
std::size_t item_size) const
{
// shr_buf[i] = src[shr_ltdof[i]]
MFEM_ASSERT(item_size == sizeof(double), "");
if (shr_ltdof.Size() == 0) { return; }
ExtractSubVector((int)shr_ltdof.Size(), shr_ltdof.OccaMem(), src,
shr_buf.OccaMem());
// If the above kernel is executed asynchronously, wait for it to complete:
shr_buf.OccaMem().getDevice().finish();
if (host_shr_buf)
{
shr_buf.OccaMem().copyTo(host_shr_buf);
}
}
void OccaConformingProlongation::BcastLocalCopy(const ::occa::memory &src,
::occa::memory &dst,
std::size_t item_size) const
{
// dst[ltdof_ldof[i]] = src[i]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ltdof_ldof.size<int>() == 0) { return; }
SetSubVector((int)ltdof_ldof.size<int>(), ltdof_ldof, src, dst);
}
void OccaConformingProlongation::BcastEndCopy(::occa::memory &dst,
std::size_t item_size) const
{
// dst[ext_ldof[i]] = ext_buf[i]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ext_ldof.Size() == 0) { return; }
if (host_ext_buf)
{
ext_buf.OccaMem().copyFrom(host_ext_buf);
}
SetSubVector((int)ext_ldof.Size(), ext_ldof.OccaMem(),
ext_buf.OccaMem(), dst);
}
void OccaConformingProlongation::ReduceBeginCopy(const ::occa::memory &src,
std::size_t item_size) const
{
// ext_buf[i] = src[ext_ldof[i]]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ext_ldof.Size() == 0) { return; }
ExtractSubVector((int)ext_ldof.Size(), ext_ldof.OccaMem(), src,
ext_buf.OccaMem());
// If the above kernel is executed asynchronously, wait for it to complete:
ext_buf.OccaMem().getDevice().finish();
if (host_ext_buf)
{
ext_buf.OccaMem().copyTo(host_ext_buf);
}
}
void OccaConformingProlongation::ReduceLocalCopy(const ::occa::memory &src,
::occa::memory &dst,
std::size_t item_size) const
{
// dst[i] = src[ltdof_ldof[i]]
MFEM_ASSERT(item_size == sizeof(double), "");
if (ltdof_ldof.size<int>() == 0) { return; }
ExtractSubVector((int)ltdof_ldof.size<int>(), ltdof_ldof, src, dst);
}
void OccaConformingProlongation::ReduceEndAssemble(::occa::memory &dst,
std::size_t item_size) const
{
// dst[shr_ltdof[i]] += shr_buf[i]
MFEM_ASSERT(item_size == sizeof(double), "");
if (unq_ltdof.size<int>() == 0) { return; }
if (host_shr_buf)
{
shr_buf.OccaMem().copyFrom(host_shr_buf);
}
AddSubVector((int)unq_ltdof.size<int>(), unq_ltdof, unq_shr_i, unq_shr_j,
shr_buf.OccaMem(), dst);
}
void OccaConformingProlongation::Mult_(const Vector &x, Vector &y) const
{
const GroupTopology &gtopo = gc.GetGroupTopology();
BcastBeginCopy(x.OccaMem(), sizeof(double)); // copy to 'shr_buf'
int req_counter = 0;
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
{
const int send_offset = shr_buf_offsets[nbr];
const int send_size = shr_buf_offsets[nbr+1] - send_offset;
if (send_size > 0)
{
void *send_buf;
if (host_shr_buf)
{
send_buf = host_shr_buf + send_offset*sizeof(double);
}
else
{
send_buf = (shr_buf.OccaMem() + send_offset*sizeof(double)).ptr();
}
MPI_Isend(send_buf, send_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41822, gtopo.GetComm(), &requests[req_counter++]);
}
const int recv_offset = ext_buf_offsets[nbr];
const int recv_size = ext_buf_offsets[nbr+1] - recv_offset;
if (recv_size > 0)
{
void *recv_buf;
if (host_ext_buf)
{
recv_buf = host_ext_buf + recv_offset*sizeof(double);
}
else
{
recv_buf = (ext_buf.OccaMem() + recv_offset*sizeof(double)).ptr();
}
MPI_Irecv(recv_buf, recv_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41822, gtopo.GetComm(), &requests[req_counter++]);
}
}
BcastLocalCopy(x.OccaMem(), y.OccaMem(), sizeof(double));
MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE);
BcastEndCopy(y.OccaMem(), sizeof(double)); // copy from 'ext_buf'
}
void OccaConformingProlongation::MultTranspose_(const Vector &x,
Vector &y) const
{
const GroupTopology &gtopo = gc.GetGroupTopology();
ReduceBeginCopy(x.OccaMem(), sizeof(double)); // copy to 'ext_buf'
int req_counter = 0;
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
{
const int send_offset = ext_buf_offsets[nbr];
const int send_size = ext_buf_offsets[nbr+1] - send_offset;
if (send_size > 0)
{
void *send_buf;
if (host_ext_buf)
{
send_buf = host_ext_buf + send_offset*sizeof(double);
}
else
{
send_buf = (ext_buf.OccaMem() + send_offset*sizeof(double)).ptr();
}
MPI_Isend(send_buf, send_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41823, gtopo.GetComm(), &requests[req_counter++]);
}
const int recv_offset = shr_buf_offsets[nbr];
const int recv_size = shr_buf_offsets[nbr+1] - recv_offset;
if (recv_size > 0)
{
void *recv_buf;
if (host_shr_buf)
{
recv_buf = host_shr_buf + recv_offset*sizeof(double);
}
else
{
recv_buf = (shr_buf.OccaMem() + recv_offset*sizeof(double)).ptr();
}
MPI_Irecv(recv_buf, recv_size, MPI_DOUBLE, gtopo.GetNeighborRank(nbr),
41823, gtopo.GetComm(), &requests[req_counter++]);
}
}
ReduceLocalCopy(x.OccaMem(), y.OccaMem(), sizeof(double));
MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE);
ReduceEndAssemble(y.OccaMem(), sizeof(double)); // assemble from 'shr_buf'
}
#endif // MFEM_USE_MPI
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+210
View File
@@ -0,0 +1,210 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_FE_SPACE_HPP
#define MFEM_BACKENDS_OCCA_FE_SPACE_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "engine.hpp"
#include "operator.hpp"
#include "../../fem/fem.hpp"
namespace mfem
{
namespace occa
{
/// TODO: doxygen
class FiniteElementSpace : public mfem::PFiniteElementSpace
{
protected:
//
// Inherited fields
//
// SharedPtr<const mfem::Engine> engine;
// mfem::FiniteElementSpace *fes;
SharedPtr<Layout> e_layout;
::occa::array<int> globalToLocalOffsets;
::occa::array<int> globalToLocalIndices;
::occa::array<int> localToGlobalMap;
::occa::kernel globalToLocalKernel, localToGlobalKernel;
mfem::Ordering::Type ordering;
int globalDofs, localDofs;
int vdim;
mutable Operator *prolongationOp, *restrictionOp;
void SetupLocalGlobalMaps();
void SetupOperators() const; // calls virtual methods of 'fes' !!!
void SetupKernels();
public:
/// TODO: doxygen
FiniteElementSpace(const Engine &e, mfem::FiniteElementSpace &fespace);
/// Virtual destructor
virtual ~FiniteElementSpace();
/// TODO: doxygen
const Engine &OccaEngine() const { return engine->As<Engine>(); }
/// TODO: doxygen
::occa::device GetDevice(int idx = 0) const
{ return OccaEngine().GetDevice(idx); }
mfem::Mesh* GetMesh() const { return fes->GetMesh(); }
Layout &OccaVLayout() const
{ return *fes->GetVLayout().As<Layout>(); }
Layout &OccaTrueVLayout() const
{ return *fes->GetTrueVLayout().As<Layout>(); }
Layout &OccaEVLayout() { return *e_layout; }
bool hasTensorBasis() const
{ return dynamic_cast<const mfem::TensorBasisElement*>(fes->GetFE(0)); }
mfem::Ordering::Type GetOrdering() const { return ordering; }
int GetGlobalDofs() const { return globalDofs; }
int GetLocalDofs() const { return localDofs; }
int GetDim() const { return fes->GetMesh()->Dimension(); }
int GetVDim() const { return vdim; }
int GetVSize() const { return globalDofs * vdim; }
int GetTrueVSize() const { return fes->GetTrueVSize(); }
int GetGlobalVSize() const { return globalDofs*vdim; /* FIXME: MPI */ }
int GetGlobalTrueVSize() const { return fes->GetTrueVSize(); }
int GetNE() const { return fes->GetNE(); }
const mfem::FiniteElementCollection *FEColl() const
{ return fes->FEColl(); }
const mfem::FiniteElement *GetFE(const int idx) const
{ return fes->GetFE(idx); }
virtual const mfem::Operator *GetProlongationOperator() const
{ return prolongationOp; }
virtual const mfem::Operator *GetRestrictionOperator() const
{ return restrictionOp; }
virtual const mfem::Operator *GetInterpolationOperator(
const mfem::QuadratureSpace &qspace) const
{ return NULL; /* FIXME */ }
virtual const mfem::Operator *GetGradientOperator(
const mfem::QuadratureSpace &qspace) const
{ return NULL; /* FIXME */ }
const ::occa::array<int> GetLocalToGlobalMap() const
{ return localToGlobalMap; }
/// L-vector to E-vector
void GlobalToLocal(const Vector &globalVec, Vector &localVec) const
{
globalToLocalKernel(globalDofs,
localDofs * fes->GetNE(),
globalToLocalOffsets,
globalToLocalIndices,
globalVec.OccaMem(), localVec.OccaMem());
}
/// E-vector to L-vector, transpose of GlobalToLocal
void LocalToGlobal(const Vector &localVec, Vector &globalVec) const
{
localToGlobalKernel(globalDofs,
localDofs * fes->GetNE(),
globalToLocalOffsets,
globalToLocalIndices,
localVec.OccaMem(), globalVec.OccaMem());
}
};
#ifdef MFEM_USE_MPI
/// OCCA version of mfem::ConformingProlongationOperator
class OccaConformingProlongation : public Operator
{
protected:
// size(shr_buf)=size(shr_ltdof)
// size(ext_buf)=size(ext_ldof)
Array shr_ltdof, ext_ldof;
mutable Array shr_buf, ext_buf;
mutable char *host_shr_buf, *host_ext_buf;
// Offsets into {shr,ext}_buf; size is num. neighbors, i.e.
// gc.GetGroupTopology().GetNumNeighbors():
int *shr_buf_offsets, *ext_buf_offsets;
::occa::memory ltdof_ldof; // shared with the restriction operator
::occa::memory unq_ltdof; // enumeration of the unique ltdofs in shr_ltdof
::occa::memory unq_shr_i, unq_shr_j;
::occa::kernel ExtractSubVector, SetSubVector, AddSubVector;
MPI_Request *requests;
const GroupCommunicator &gc;
// Kernel: copy ltdofs from 'src' to 'shr_buf' - prepare for send.
// shr_buf[i] = src[shr_ltdof[i]]
void BcastBeginCopy(const ::occa::memory &src, std::size_t item_size) const;
// Kernel: copy ltdofs from 'src' to ldofs in 'dst'.
// dst[ltdof_ldof[i]] = src[i]
void BcastLocalCopy(const ::occa::memory &src, ::occa::memory &dst,
std::size_t item_size) const;
// Kernel: copy ext. dofs from 'ext_buf' to 'dst' - after recv.
// dst[ext_ldof[i]] = ext_buf[i]
void BcastEndCopy(::occa::memory &dst, std::size_t item_size) const;
// Kernel: copy ext. dofs from 'src' to 'ext_buf' - prepare for send.
// ext_buf[i] = src[ext_ldof[i]]
void ReduceBeginCopy(const ::occa::memory &src, std::size_t item_size) const;
// Kernel: copy owned ldofs from 'src' to ltdofs in 'dst'.
// dst[i] = src[ltdof_ldof[i]]
void ReduceLocalCopy(const ::occa::memory &src, ::occa::memory &dst,
std::size_t item_size) const;
// Kernel: assemble dofs from 'shr_buf' into to 'dst' - after recv.
// dst[shr_ltdof[i]] += shr_buf[i]
void ReduceEndAssemble(::occa::memory &dst, std::size_t item_size) const;
public:
OccaConformingProlongation(const FiniteElementSpace &ofes,
const mfem::ParFiniteElementSpace &pfes,
::occa::memory ltdof_ldof_);
virtual ~OccaConformingProlongation();
// overrides
virtual void Mult_(const Vector &x, Vector &y) const;
virtual void MultTranspose_(const Vector &x, Vector &y) const;
};
#endif // MFEM_USE_MPI
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_FE_SPACE_HPP
+67
View File
@@ -0,0 +1,67 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
/*
---[ Defines Known At Compile-Time ]------------
TILESIZE : Tilesize for iterating over entries
================================================
*/
#if VDIM_ORDERING == ORDERING_BY_VDIM
typedef double *Global_t @dim(NUM_VDIM, globalEntries);
typedef double *Local_t @dim(NUM_VDIM, localEntries);
#else
typedef double *Global_t @dim(NUM_VDIM, globalEntries) @dimOrder(1, 0);
typedef double *Local_t @dim(NUM_VDIM, localEntries) @dimOrder(1, 0);
#endif
@kernel void GlobalToLocal(const int globalEntries,
const int localEntries,
@restrict const int * offsets,
@restrict const int * indices,
@restrict const Global_t globalX,
@restrict Local_t localX) {
for (int i = 0; i < globalEntries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < globalEntries) {
const int offset = offsets[i];
const int nextOffset = offsets[i + 1];
for (int v = 0; v < NUM_VDIM; ++v) {
const double dofValue = globalX(v, i);
for (int j = offset; j < nextOffset; ++j) {
localX(v, indices[j]) = dofValue;
}
}
}
}
}
@kernel void LocalToGlobal(const int globalEntries,
const int localEntries,
@restrict const int * offsets,
@restrict const int * indices,
@restrict const Local_t localX,
@restrict Global_t globalX) {
for (int i = 0; i < globalEntries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < globalEntries) {
const int offset = offsets[i];
const int nextOffset = offsets[i + 1];
for (int v = 0; v < NUM_VDIM; ++v) {
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j) {
dofValue += localX(v, indices[j]);
}
globalX(v, i) = dofValue;
}
}
}
}
+181
View File
@@ -0,0 +1,181 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef STORE_JACOBIAN
# define STORE_JACOBIAN 1
#endif
#ifndef STORE_JACOBIAN_INV
# define STORE_JACOBIAN_INV 1
#endif
#ifndef STORE_JACOBIAN_DET
# define STORE_JACOBIAN_DET 1
#endif
typedef double* Local1D_t @dim(1, NUM_DOFS, numElements);
typedef double* Local2D_t @dim(2, NUM_DOFS, numElements);
typedef double* Local3D_t @dim(3, NUM_DOFS, numElements);
typedef double* QLocal_t @dim(NUM_QUAD, numElements);
typedef double* DofToQuadD1D_t @dim(NUM_QUAD, NUM_DOFS);
typedef double* DofToQuadD2D_t @dim(2, NUM_QUAD, NUM_DOFS);
typedef double* DofToQuadD3D_t @dim(3, NUM_QUAD, NUM_DOFS);
typedef double* Jacobian1D_t @dim(NUM_QUAD, numElements);
typedef double* Jacobian2D_t @dim(2, 2, NUM_QUAD, numElements);
typedef double* Jacobian3D_t @dim(3, 3, NUM_QUAD, numElements);
@kernel void InitGeometryInfo1D(const int numElements,
@restrict const DofToQuadD1D_t dofToQuadD,
@restrict const Local1D_t nodes,
@restrict Jacobian1D_t J,
@restrict Jacobian1D_t invJ,
@restrict QLocal_t detJ) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_nodes[NUM_DOFS];
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
for (int d = q; d < NUM_DOFS; d += NUM_QUAD) {
s_nodes[d] = nodes(0, d, e);
}
}
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
double J11 = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double wx = dofToQuadD(q, d);
J11 += wx * s_nodes[d];
}
#if STORE_JACOBIAN
J(q, e) = J11;
#endif
#if STORE_JACOBIAN_INV
invJ(q, e) = 1.0 / J11;
#endif
#if STORE_JACOBIAN_DET
detJ(q, e) = J11;
#endif
}
}
}
@kernel void InitGeometryInfo2D(const int numElements,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const Local2D_t nodes,
@restrict Jacobian2D_t J,
@restrict Jacobian2D_t invJ,
@restrict QLocal_t detJ) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_nodes[2 * NUM_DOFS] @dim(2, NUM_DOFS);
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
for (int d = q; d < NUM_DOFS; d += NUM_QUAD) {
s_nodes(0, d) = nodes(0, d, e);
s_nodes(1, d) = nodes(1, d, e);
}
}
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
double J11 = 0, J12 = 0;
double J21 = 0, J22 = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double wx = dofToQuadD(0, q, d);
const double wy = dofToQuadD(1, q, d);
const double x = s_nodes(0, d);
const double y = s_nodes(1, d);
J11 += (wx * x); J12 += (wx * y);
J21 += (wy * x); J22 += (wy * y);
}
#if STORE_JACOBIAN_INV || STORE_JACOBIAN_DET
const double r_detJ = (J11 * J22) - (J12 * J21);
#endif
#if STORE_JACOBIAN
J(0, 0, q, e) = J11; J(1, 0, q, e) = J12;
J(0, 1, q, e) = J21; J(1, 1, q, e) = J22;
#endif
#if STORE_JACOBIAN_INV
const double r_idetJ = 1.0 / r_detJ;
invJ(0, 0, q, e) = J22 * r_idetJ;
invJ(1, 0, q, e) = -J12 * r_idetJ;
invJ(0, 1, q, e) = -J21 * r_idetJ;
invJ(1, 1, q, e) = J11 * r_idetJ;
#endif
#if STORE_JACOBIAN_DET
detJ(q, e) = r_detJ;
#endif
}
}
}
@kernel void InitGeometryInfo3D(const int numElements,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const Local3D_t nodes,
@restrict Jacobian3D_t J,
@restrict Jacobian3D_t invJ,
@restrict QLocal_t detJ) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_nodes[3 * NUM_DOFS] @dim(3, NUM_DOFS);
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
for (int d = q; d < NUM_DOFS; d += NUM_QUAD) {
s_nodes(0, d) = nodes(0, d, e);
s_nodes(1, d) = nodes(1, d, e);
s_nodes(2, d) = nodes(2, d, e);
}
}
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
double J11 = 0, J12 = 0, J13 = 0;
double J21 = 0, J22 = 0, J23 = 0;
double J31 = 0, J32 = 0, J33 = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
const double wx = dofToQuadD(0, q, d);
const double wy = dofToQuadD(1, q, d);
const double wz = dofToQuadD(2, q, d);
const double x = s_nodes(0, d);
const double y = s_nodes(1, d);
const double z = s_nodes(2, d);
J11 += (wx * x); J12 += (wx * y); J13 += (wx * z);
J21 += (wy * x); J22 += (wy * y); J23 += (wy * z);
J31 += (wz * x); J32 += (wz * y); J33 += (wz * z);
}
#if STORE_JACOBIAN_INV || STORE_JACOBIAN_DET
const double r_detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
#endif
#if STORE_JACOBIAN
J(0, 0, q, e) = J11; J(1, 0, q, e) = J12; J(2, 0, q, e) = J13;
J(0, 1, q, e) = J21; J(1, 1, q, e) = J22; J(2, 1, q, e) = J23;
J(0, 2, q, e) = J31; J(1, 2, q, e) = J32; J(2, 2, q, e) = J33;
#endif
#if STORE_JACOBIAN_INV
const double r_idetJ = 1.0 / r_detJ;
invJ(0, 0, q, e) = r_idetJ * ((J22 * J33) - (J23 * J32));
invJ(1, 0, q, e) = r_idetJ * ((J32 * J13) - (J33 * J12));
invJ(2, 0, q, e) = r_idetJ * ((J12 * J23) - (J13 * J22));
invJ(0, 1, q, e) = r_idetJ * ((J23 * J31) - (J21 * J33));
invJ(1, 1, q, e) = r_idetJ * ((J33 * J11) - (J31 * J13));
invJ(2, 1, q, e) = r_idetJ * ((J13 * J21) - (J11 * J23));
invJ(0, 2, q, e) = r_idetJ * ((J21 * J32) - (J22 * J31));
invJ(1, 2, q, e) = r_idetJ * ((J31 * J12) - (J32 * J11));
invJ(2, 2, q, e) = r_idetJ * ((J11 * J22) - (J12 * J21));
#endif
#if STORE_JACOBIAN_DET
detJ(q, e) = r_detJ;
#endif
}
}
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "gridfunc.hpp"
#include "bilininteg.hpp"
#include "../../fem/gridfunc.hpp"
namespace mfem
{
namespace occa
{
std::map<std::string, ::occa::kernel> gridFunctionKernels;
::occa::kernel GetGridFunctionKernel(::occa::device device,
FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir)
{
const int numQuad = ir.GetNPoints();
const FiniteElement &fe = *(fespace.GetFE(0));
const int dim = fe.GetDim();
const int vdim = fespace.GetVDim();
std::stringstream ss;
ss << ::occa::hash(device)
<< "FEColl : " << fespace.FEColl()->Name()
<< "Quad: " << numQuad
<< "Dim: " << dim
<< "VDim: " << vdim;
std::string hash = ss.str();
// Kernel defines
::occa::properties props;
props["defines/NUM_VDIM"] = vdim;
SetProperties(fespace, ir, props);
::occa::kernel kernel = gridFunctionKernels[hash];
if (!kernel.isInitialized())
{
const std::string &okl_path = fespace.OccaEngine().GetOklPath();
kernel = device.buildKernel(okl_path + "gridfunc.okl",
stringWithDim("GridFuncToQuad", dim),
props);
}
return kernel;
}
void ToQuad(const IntegrationRule &ir, FiniteElementSpace &fespace, Vector &gf,
Vector &quadValues)
{
const Engine &engine = fespace.OccaEngine();
::occa::device device = engine.GetDevice();
OccaDofQuadMaps &maps = OccaDofQuadMaps::Get(device, fespace, ir);
const int elements = fespace.GetNE();
const int numQuad = ir.GetNPoints();
quadValues.OccaResize(numQuad * elements, sizeof(double));
::occa::kernel g2qKernel = GetGridFunctionKernel(device, fespace, ir);
g2qKernel(elements,
maps.dofToQuad,
fespace.GetLocalToGlobalMap(),
gf.OccaMem(),
quadValues.OccaMem());
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_GRID_FUNC_HPP
#define MFEM_BACKENDS_OCCA_GRID_FUNC_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "vector.hpp"
#include "fespace.hpp"
namespace mfem
{
class IntegrationRule;
namespace occa
{
// TODO: make this object part of the backend or the engine.
extern std::map<std::string, ::occa::kernel> gridFunctionKernels;
// TODO: make this a method of the backend or the engine.
::occa::kernel GetGridFunctionKernel(::occa::device device,
FiniteElementSpace &fespace,
const mfem::IntegrationRule &ir);
// ToQuad version without the deprecated class.
//
// FIXME: This is the action of a global B matrix, mapping L-vector to Q-vector,
// so it should be made into an operator that can be constructed by the
// FE space class. A batched version, where only a subset of the elements
// are processed should be defined as well.
//
// The abstract operator construction method in the FE space class is:
// PFiniteElementSpace::GetInterpolationOperator(...)
void ToQuad(const IntegrationRule &ir, FiniteElementSpace &ofespace, Vector &gf,
Vector &quadValues);
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_GRID_FUNC_HPP
+26
View File
@@ -0,0 +1,26 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
#ifdef USING_TENSOR_OPS
# ifdef OCCA_USING_CPU
# include "mfem-occa://gridfunc/tensor/cpu.okl"
# else
# include "mfem-occa://gridfunc/tensor/gpuHighOrder.okl"
# endif
#else
# ifdef OCCA_USING_CPU
# include "mfem-occa://gridfunc/simplex/cpu.okl"
# else
# include "mfem-occa://gridfunc/simplex/gpuHighOrder.okl"
# endif
#endif
+63
View File
@@ -0,0 +1,63 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
for (int d = 0; d < NUM_DOFS; ++d) {
const int gid = l2gMap(d, e);
for (int v = 0; v < NUM_VDIM; ++v) {
const double r_gf = gf[v + gid*NUM_VDIM];
double r_out = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_out += r_gf * dofToQuad(d, q);
}
out(v, d, e) = r_out;
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
for (int d = 0; d < NUM_DOFS; ++d) {
const int gid = l2gMap(d, e);
for (int v = 0; v < NUM_VDIM; ++v) {
const double r_gf = gf[v + gid*NUM_VDIM];
double r_out = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_out += r_gf * dofToQuad(d, q);
}
out(v, d, e) = r_out;
}
}
}
}
}
//======================================
@@ -0,0 +1,79 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gf[NUM_VDIM][NUM_DOFS];
for (int dOff = 0; dOff < M2_INNER_BATCH; ++dOff; @inner) {
for (int d = dOff; d < NUM_DOFS; d += M2_INNER_BATCH) {
const int gid = l2gMap(d, e);
for (int v = 0; v < NUM_VDIM; ++v) {
s_gf[v][d] = gf[v + gid*NUM_VDIM]];
}
}
}
for (int qOff = 0; qOff < M2_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M2_INNER_BATCH) {
for (int v = 0; v < NUM_VDIM; ++v) {
double r_out = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
r_out += s_gf[v][d] * dofToQuad(d, q);
}
out(v, q, e) = r_out;
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap_t l2gMap,
@restrict const double * gf,
@restrict QVLocal_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_gf[NUM_VDIM][NUM_DOFS];
for (int dOff = 0; dOff < M3_INNER_BATCH; ++dOff; @inner) {
for (int d = dOff; d < NUM_DOFS; d += M3_INNER_BATCH) {
const int gid = l2gMap(d, e);
for (int v = 0; v < NUM_VDIM; ++v) {
s_gf[v][d] = gf[v + gid*NUM_VDIM]];
}
}
}
for (int qOff = 0; qOff < M3_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M3_INNER_BATCH) {
for (int v = 0; v < NUM_VDIM; ++v) {
double r_out = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
r_out += s_gf[v][d] * dofToQuad(d, q);
}
out(v, q, e) = r_out;
}
}
}
}
}
//======================================
+188
View File
@@ -0,0 +1,188 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void GridFuncToQuad1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap1D_t l2gMap,
@restrict const double * gf,
@restrict QVLocal1D_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_out[NUM_VDIM][NUM_QUAD_1D];
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_out[v][qx] = 0;
}
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const int gid = l2gMap(dx, e);
for (int v = 0; v < NUM_VDIM; ++v) {
const double r_gf = gf[v + gid*NUM_VDIM];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_out[v][qx] += r_gf * dofToQuad(qx, dx);
}
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int v = 0; v < NUM_VDIM; ++v) {
out(v, qx, e) = r_out[v][qx];
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap2D_t l2gMap,
@restrict const double * gf,
@restrict QVLocal2D_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double out_xy[NUM_VDIM][NUM_QUAD_1D][NUM_QUAD_1D];
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_xy[v][qy][qx] = 0;
}
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double out_x[NUM_VDIM][NUM_QUAD_1D];
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
out_x[v][qy] = 0;
}
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const int gid = l2gMap(dx, dy, e);
for (int v = 0; v < NUM_VDIM; ++v) {
const double r_gf = gf[v + gid*NUM_VDIM];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
out_x[v][qy] += r_gf * dofToQuad(qy, dx);
}
}
}
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double d2q = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_xy[v][qy][qx] += d2q * out_x[v][qx];
}
}
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int v = 0; v < NUM_VDIM; ++v) {
out(v, qx, qy, e) = out_xy[v][qy][qx];
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap3D_t l2gMap,
@restrict const double * gf,
@restrict QVLocal3D_t out) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double out_xyz[NUM_VDIM][NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D];
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_xyz[v][qz][qy][qx] = 0;
}
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
double out_xy[NUM_VDIM][NUM_QUAD_1D][NUM_QUAD_1D];
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_xy[v][qy][qx] = 0;
}
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double out_x[NUM_VDIM][NUM_QUAD_1D];
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_x[v][qx] = 0;
}
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const int gid = l2gMap(dx, dy, dz, e);
for (int v = 0; v < NUM_VDIM; ++v) {
const double r_gf = gf[v + gid*NUM_VDIM];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_x[v][qx] += r_gf * dofToQuad(qx, dx);
}
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_xy[v][qy][qx] += wy * out_x[v][qx];
}
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
const double wz = dofToQuad(qz, dz);
for (int v = 0; v < NUM_VDIM; ++v) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out_xyz[v][qz][qy][qx] += wz * out_xy[v][qy][qx];
}
}
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int v = 0; v < NUM_VDIM; ++v) {
out(v, qx, qy, qz, e) = out_xyz[v][qz][qy][qx];
}
}
}
}
}
}
}
//======================================
@@ -0,0 +1,183 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void GridFuncToQuad1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap1D_t l2gMap,
@restrict const double * gf,
@restrict QLocal1D_t out) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M1_ELEMENT_BATCHES; @outer) {
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@exclusive double r_out[NUM_QUAD_1D];
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
for (int i = el; i < NUM_QUAD_DOFS_1D; i += M1_INNER_ELEMENT_BATCH) {
s_dofToQuad[i] = dofToQuad[i];
}
}
for (int b = 0; b < M1_OUTER_ELEMENT_BATCH; ++b) {
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
const int e = eOff + b*M1_INNER_ELEMENT_BATCH + el;
if (e < numElements) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_out[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double r_gf = gf[l2gMap(dx, e)];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_out[qx] += r_gf * s_dofToQuad(qx, dx);
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
out(qx, e) = r_out[qx];
}
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void GridFuncToQuad2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap2D_t l2gMap,
@restrict const double * gf,
@restrict QLocal2D_t out) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M2_ELEMENT_BATCH; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
// Store xy planes in shared memory
@shared double s_xy[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
for (int id = x; id < NUM_QUAD_DOFS_1D; id += NUM_MAX_1D) {
s_dofToQuad[id] = dofToQuad[id];
}
}
for (int e = eOff; e < (eOff + M2_ELEMENT_BATCH); ++e) {
if (e < numElements) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
double r_x[NUM_DOFS_1D];
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
r_x[dy] = gf[l2gMap(dx, dy, e)];
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double xy = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
xy += r_x[dy] * s_dofToQuad(qy, dy);
}
s_xy(dx, qy) = xy;
}
}
}
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
if (qy < NUM_QUAD_1D) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
double val = 0;
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
val += s_xy(dx, qy) * s_dofToQuad(qx, dx);
}
out(qx, qy, e) = val;
}
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void GridFuncToQuad3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DLocalMap3D_t l2gMap,
@restrict const double * gf,
@restrict QLocal3D_t out) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
// Store xy planes in shared memory
@shared double s_z[NUM_MAX_2D] @dim(NUM_MAX_1D, NUM_MAX_1D);
// Store z axis as registers
@exclusive double r_qz[NUM_QUAD_1D];
for (int y = 0; y < NUM_MAX_1D; ++y; @inner) {
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
const int id = (y * NUM_MAX_1D) + x;
// Fetch Q <--> D maps
if (id < NUM_QUAD_DOFS_1D) {
s_dofToQuad[id] = dofToQuad[id];
}
// Initialize our Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_qz[qz] = 0;
}
}
}
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double val = gf[l2gMap(dx, dy, dz, e)];
// Calculate D -> Q in the Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_qz[qz] += val * s_dofToQuad(qz, dz);
}
}
}
}
}
// For each xy plane
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
// Fill xy plane at given z position
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
s_z(dx, dy) = r_qz[qz];
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
double val = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = s_dofToQuad(qy, dy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double wx = s_dofToQuad(qx, dx);
val += wx * wy * s_z(dx, dy);
}
}
out(qx, qy, qz, e) = val;
}
}
}
}
}
}
//======================================
+119
View File
@@ -0,0 +1,119 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "interpolation.hpp"
namespace mfem
{
namespace occa
{
RestrictionOperator::RestrictionOperator(Layout &in_layout, Layout &out_layout,
::occa::array<int> indices)
: Operator(in_layout, out_layout)
{
trueIndices = indices;
::occa::device device = in_layout.OccaEngine().GetDevice();
const std::string &okl_path = in_layout.OccaEngine().GetOklPath();
multOp = device.buildKernel(okl_path + "mappings.okl",
"ExtractSubVector",
"defines: { TILESIZE: 256 }");
multTransposeOp = device.buildKernel(okl_path + "mappings.okl",
"SetSubVector",
"defines: { TILESIZE: 256 }");
}
void RestrictionOperator::Mult_(const Vector &x, Vector &y) const
{
// y[i] = x[trueIndices[i]]
multOp(height, trueIndices, x.OccaMem(), y.OccaMem());
}
void RestrictionOperator::MultTranspose_(const Vector &x, Vector &y) const
{
y.OccaFill<double>(0.0);
// y[trueIndices[i]] = x[i]
multTransposeOp(height, trueIndices, x.OccaMem(), y.OccaMem());
}
ProlongationOperator::ProlongationOperator(OccaSparseMatrix &multOp_,
OccaSparseMatrix &multTransposeOp_)
: Operator(multOp_),
pmat(NULL),
multOp(multOp_),
multTransposeOp(multTransposeOp_)
{ }
ProlongationOperator::ProlongationOperator(Layout &in_layout,
Layout &out_layout,
const mfem::Operator *pmat_)
: Operator(in_layout, out_layout),
pmat(pmat_),
multOp(*this),
multTransposeOp(*this)
{ }
void ProlongationOperator::Mult_(const Vector &x, Vector &y) const
{
MFEM_VERIFY(pmat == NULL, "");
multOp.Mult_(x, y);
}
void ProlongationOperator::MultTranspose_(const Vector &x, Vector &y) const
{
MFEM_VERIFY(pmat == NULL, "");
multTransposeOp.Mult_(x, y);
}
void ProlongationOperator::Mult(const mfem::Vector &x, mfem::Vector &y) const
{
if (pmat)
{
// FIXME: create an OCCA version of 'pmat'
x.Pull();
y.Pull(false);
pmat->Mult(x, y);
y.Push();
}
else
{
multOp.Mult(x, y);
}
}
void ProlongationOperator::MultTranspose(const mfem::Vector &x,
mfem::Vector &y) const
{
if (pmat)
{
// FIXME: create an OCCA version of 'pmat'
x.Pull();
y.Pull(false);
pmat->MultTranspose(x, y);
y.Push();
}
else
{
multTransposeOp.Mult(x, y);
}
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_INTERPOLATION_HPP
#define MFEM_BACKENDS_OCCA_INTERPOLATION_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include <occa.hpp>
#include "vector.hpp"
#include "engine.hpp"
#include "sparsemat.hpp"
#include "../../fem/fem.hpp"
namespace mfem
{
namespace occa
{
class RestrictionOperator : public Operator
{
protected:
::occa::array<int> trueIndices; // ldof = trueIndices[ltdof]
::occa::kernel multOp, multTransposeOp;
public:
RestrictionOperator(Layout &in_layout, Layout &out_layout,
::occa::array<int> indices);
// overrides
virtual void Mult_(const Vector &x, Vector &y) const;
virtual void MultTranspose_(const Vector &x, Vector &y) const;
};
class ProlongationOperator : public Operator
{
protected:
const mfem::Operator *pmat;
OccaSparseMatrix multOp, multTransposeOp;
public:
ProlongationOperator(OccaSparseMatrix &multOp_,
OccaSparseMatrix &multTransposeOp_);
ProlongationOperator(Layout &in_layout, Layout &out_layout,
const mfem::Operator *pmat_);
// overrides
virtual void Mult_(const Vector &x, Vector &y) const;
virtual void MultTranspose_(const Vector &x, Vector &y) const;
// overrides
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const;
virtual void MultTranspose(const mfem::Vector &x, mfem::Vector &y) const;
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_INTERPOLATION_HPP
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "layout.hpp"
#include "../../general/array.hpp"
namespace mfem
{
namespace occa
{
void Layout::Resize(std::size_t new_size)
{
size = new_size;
}
void Layout::Resize(const Array<std::size_t> &offsets)
{
MFEM_ASSERT(offsets.Size() == 2,
"multiple workers are not supported yet");
size = offsets.Last();
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+67
View File
@@ -0,0 +1,67 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_LAYOUT_HPP
#define MFEM_BACKENDS_OCCA_LAYOUT_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "../base/layout.hpp"
#include "engine.hpp"
namespace mfem
{
namespace occa
{
class Layout : public PLayout
{
protected:
//
// Inherited fields
//
// SharedPtr<const mfem::Engine> engine;
// std::size_t size;
public:
Layout(const Engine &e, std::size_t s = 0) : PLayout(e, s) { }
const Engine &OccaEngine() const
{ return *static_cast<const Engine *>(engine.Get()); }
void OccaResize(std::size_t new_size) { size = new_size; }
virtual ~Layout() { }
/**
@name Virtual interface
*/
///@{
/// Resize the layout
virtual void Resize(std::size_t new_size);
/// Resize the layout based on the given worker offsets
virtual void Resize(const Array<std::size_t> &offsets);
///@}
// End: Virtual interface
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_LAYOUT_HPP
+76
View File
@@ -0,0 +1,76 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
/*
---[ Defines Known At Compile-Time ]------------
TILESIZE : Tilesize for iterating over entries
================================================
*/
@kernel void ExtractSubVector(const int entries,
@restrict const int *indices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
out[i] = in[indices[i]]; // indices can be repeated
}
}
}
@kernel void SetSubVector(const int entries,
@restrict const int *indices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
out[indices[i]] = in[i]; // indices CANNOT be repeated
}
}
}
@kernel void AddSubVector(const int num_unique_dst_indices,
@restrict const int *unique_dst_indices,
@restrict const int *unique_to_src_offsets,
@restrict const int *unique_to_src_indices,
@restrict const double *src,
@restrict double *dst) {
for (int i = 0; i < num_unique_dst_indices; ++i;
@tile(TILESIZE, @outer, @inner)) {
if (i < num_unique_dst_indices) {
const int dst_idx = unique_dst_indices[i];
double sum = dst[dst_idx];
const int end = unique_to_src_offsets[i+1];
for (int j = unique_to_src_offsets[i]; j != end; ++j) {
sum += src[unique_to_src_indices[j]];
}
dst[dst_idx] = sum;
}
}
}
@kernel void MapSubVector(const int entries,
@restrict const int *indices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
const int fromIdx = indices[2*i + 0]; // fromIdx indices can be repeated
const int toIdx = indices[2*i + 1]; // toIdx indices CANNOT be repeated
out[toIdx] = in[fromIdx];
}
}
}
+122
View File
@@ -0,0 +1,122 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_sol[NUM_DOFS];
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] = 0;
}
for (int q = 0; q < NUM_QUAD; ++q) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * quadToDof(d, q);
}
s *= oper(q, e);
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] += (s * quadToDof(d, q));
}
}
for (int d = 0; d < NUM_DOFS; ++d) {
solOut(d, e) += r_sol[d];
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double r_sol[NUM_DOFS];
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] = 0;
}
for (int q = 0; q < NUM_QUAD; ++q) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * quadToDof(d, q);
}
s *= oper(q, e);
for (int d = 0; d < NUM_DOFS; ++d) {
r_sol[d] += (s * quadToDof(d, q));
}
}
for (int d = 0; d < NUM_DOFS; ++d) {
solOut(d, e) += r_sol[d];
}
}
}
}
//======================================
+129
View File
@@ -0,0 +1,129 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A2_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A2_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A2_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += A2_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
}
}
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD2D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD2D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_sol[NUM_QUAD];
for (int qOff = 0; qOff < M2_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M2_INNER_BATCH) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * dofToQuad(d, q);
}
s_sol[q] = s * oper(q, e);
}
}
for (int dOff = 0; dOff < M2_INNER_BATCH; ++dOff) {
for (int d = dOff; d < NUM_DOFS; d += M2_INNER_BATCH) {
double r_sol = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_sol += (s_sol[q] * quadToDof(d, q));
}
solOut(d, e) += r_sol;
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A3_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A3_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A3_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += A3_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuadD3D_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDofD3D_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DLocal_t solIn,
@restrict DLocal_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
@shared double s_sol[NUM_QUAD];
for (int qOff = 0; qOff < M3_INNER_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD; q += M3_INNER_BATCH) {
double s = 0;
for (int d = 0; d < NUM_DOFS; ++d) {
s += solIn(d, e) * dofToQuad(d, q);
}
s_sol[q] = s * oper(q, e);
}
}
for (int dOff = 0; dOff < M3_INNER_BATCH; ++dOff) {
for (int d = dOff; d < NUM_DOFS; d += M3_INNER_BATCH) {
double r_sol = 0;
for (int q = 0; q < NUM_QUAD; ++q) {
r_sol += (s_sol[q] * quadToDof(d, q));
}
solOut(d, e) += r_sol;
}
}
}
}
//======================================
+281
View File
@@ -0,0 +1,281 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian1D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
const double detJ = J(q, e);
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_x[NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] = 0;
}
// sol_x{qx} = dofToQuad{qx,dx} * sol{dx}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] += s * dofToQuad(qx, dx);
}
}
// sol_x{q} *= oper{q}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] *= oper(qx, e);
}
// sol{dx} = quadToDof{dx,qx} * sol_x{qx}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, e) += sol_x[qx] * quadToDof(dx, qx);
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_2D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
const double detJ = ((J11 * J22) - (J21 * J12));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_xy[NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
sol_x[qy] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, dy, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] += dofToQuad(qx, dx) * s;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double d2q = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] += d2q * sol_x[qx];
}
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] *= oper(qx, qy, e);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[NUM_DOFS_1D];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] = 0;
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double s = sol_xy[qy][qx];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] += quadToDof(dx, qx) * s;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double q2d = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, dy, e) += q2d * sol_x[dx];
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_3D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_xyz[NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[qz][qy][qx] = 0;
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
double sol_xy[NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, dy, dz, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[qx] += dofToQuad(qx, dx) * s;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[qy][qx] += wy * sol_x[qx];
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
const double wz = dofToQuad(qz, dz);
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[qz][qy][qx] += wz * sol_xy[qy][qx];
}
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[qz][qy][qx] *= oper(qx, qy, qz, e);
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
double sol_xy[NUM_DOFS_1D][NUM_DOFS_1D];
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[dy][dx] = 0;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[NUM_DOFS_1D];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] = 0;
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double s = sol_xyz[qz][qy][qx];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[dx] += quadToDof(dx, qx) * s;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[dy][dx] += wy * sol_x[dx];
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = quadToDof(dz, qz);
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(dx, dy, dz, e) += wz * sol_xy[dy][dx];
}
}
}
}
}
}
}
//======================================
+341
View File
@@ -0,0 +1,341 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
const double *quadWeights,
const Jacobian1D_t J,
COEFF_ARGS
QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A1_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A1_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF * J(q, e);
}
}
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal1D_t oper,
@restrict const DLocal1D_t solIn,
@restrict DLocal1D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M1_ELEMENT_BATCHES; @outer) {
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@exclusive double r_sol[NUM_QUAD_1D];
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
for (int i = el; i < NUM_QUAD_DOFS_1D; i += M1_INNER_ELEMENT_BATCH) {
s_dofToQuad[i] = dofToQuad[i];
s_quadToDof[i] = quadToDof[i];
}
}
for (int b = 0; b < M1_OUTER_ELEMENT_BATCH; ++b) {
for (int el = 0; el < M1_INNER_ELEMENT_BATCH; ++el; @inner) {
const int e = eOff + b*M1_INNER_ELEMENT_BATCH + el;
if (e < numElements) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_sol[qx] = 0;
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double s = solIn(dx, e);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_sol[qx] += s * s_dofToQuad(qx, dx);
}
}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
r_sol[qx] *= oper(qx, e);
}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
double s = 0;
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
s += r_sol[qx] * s_quadToDof(dx, qx);
}
solOut(dx, e) += s;
}
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
const double *quadWeights,
const Jacobian2D_t J,
COEFF_ARGS
QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A2_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A2_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A2_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD_2D; q += A2_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
}
}
}
}
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal2D_t oper,
@restrict const DLocal2D_t solIn,
@restrict DLocal2D_t solOut) {
// Iterate over elements
for (int eOff = 0; eOff < numElements; eOff += M2_ELEMENT_BATCH; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
// Store xy planes in @shared memory
@shared double s_xy[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
@shared double s_xy2[NUM_QUAD_2D] @dim(NUM_QUAD_1D, NUM_QUAD_1D);
@exclusive double r_x[NUM_MAX_1D];
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
for (int id = x; id < NUM_QUAD_DOFS_1D; id += NUM_MAX_1D) {
s_dofToQuad[id] = dofToQuad[id];
s_quadToDof[id] = quadToDof[id];
}
}
for (int e = eOff; e < (eOff + M2_ELEMENT_BATCH); ++e) {
if (e < numElements) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
s_xy(dx, qy) = 0;
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
r_x[dy] = solIn(dx, dy, e);
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double xy = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
xy += r_x[dy] * s_dofToQuad(qy, dy);
}
s_xy(dx, qy) = xy;
}
}
}
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
if (qy < NUM_QUAD_1D) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
double s = 0;
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
s += s_xy(dx, qy) * s_dofToQuad(qx, dx);
}
s_xy2(qx, qy) = s * oper(qx, qy, e);
}
}
}
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if (qx < NUM_QUAD_1D) {
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
s_xy(dy, qx) = 0;
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
r_x[qy] = s_xy2(qx, qy);
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double s = 0;
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
s += r_x[qy] * s_quadToDof(dy, qy);
}
s_xy(dy, qx) = s;
}
}
}
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if (dx < NUM_DOFS_1D) {
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double s = 0;
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
s += (s_xy(dy, qx) * s_quadToDof(dx, qx));
}
solOut(dx, dy, e) += s;
}
}
}
}
}
}
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
const double *quadWeights,
const Jacobian3D_t J,
COEFF_ARGS
QLocal_t oper) {
for (int eOff = 0; eOff < numElements; eOff += A3_ELEMENT_BATCH; @outer) {
for (int e = eOff; e < (eOff + A3_ELEMENT_BATCH); ++e; @inner) {
if (e < numElements) {
for (int qOff = 0; qOff < A3_QUAD_BATCH; ++qOff; @inner) {
for (int q = qOff; q < NUM_QUAD_3D; q += A3_QUAD_BATCH) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal3D_t oper,
@restrict const DLocal3D_t solIn,
@restrict DLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
// Store dof <--> quad mappings
@shared double s_dofToQuad[NUM_QUAD_DOFS_1D] @dim(NUM_QUAD_1D, NUM_DOFS_1D);
@shared double s_quadToDof[NUM_QUAD_DOFS_1D] @dim(NUM_DOFS_1D, NUM_QUAD_1D);
// Store xy planes in @shared memory
@shared double s_xy[NUM_MAX_2D] @dim(NUM_MAX_1D, NUM_MAX_1D);
// Store z axis as registers
@exclusive double r_z[NUM_QUAD_1D];
@exclusive double r_z2[NUM_DOFS_1D];
for (int y = 0; y < NUM_MAX_1D; ++y; @inner) {
for (int x = 0; x < NUM_MAX_1D; ++x; @inner) {
const int id = (y * NUM_MAX_1D) + x;
// Fetch Q <--> D maps
if (id < NUM_QUAD_DOFS_1D) {
s_dofToQuad[id] = dofToQuad[id];
s_quadToDof[id] = quadToDof[id];
}
// Initialize our Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_z[qz] = 0;
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
r_z2[dz] = 0;
}
}
}
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double s = solIn(dx, dy, dz, e);
// Calculate D -> Q in the Z axis
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
r_z[qz] += s * s_dofToQuad(qz, dz);
}
}
}
}
}
// For each xy plane
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
// Fill xy plane at given z position
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
s_xy(dx, dy) = r_z[qz];
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
double s = 0;
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = s_dofToQuad(qy, dy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
const double wx = s_dofToQuad(qx, dx);
s += wx * wy * s_xy(dx, dy);
}
}
s *= oper(qx, qy, qz, e);
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = s_quadToDof(dz, qz);
r_z2[dz] += wz * s;
}
}
}
}
@barrier("s_xy_sync_1");
}
// Iterate over xy planes to compute solution
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
// Place xy plane in @shared memory
for (int qy = 0; qy < NUM_MAX_1D; ++qy; @inner) {
for (int qx = 0; qx < NUM_MAX_1D; ++qx; @inner) {
if ((qx < NUM_QUAD_1D) && (qy < NUM_QUAD_1D)) {
s_xy(qx, qy) = r_z2[dz];
}
}
}
// Finalize solution in xy plane
for (int dy = 0; dy < NUM_MAX_1D; ++dy; @inner) {
for (int dx = 0; dx < NUM_MAX_1D; ++dx; @inner) {
if ((dx < NUM_DOFS_1D) && (dy < NUM_DOFS_1D)) {
double solZ = 0;
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = s_quadToDof(dy, qy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const double wx = s_quadToDof(dx, qx);
solZ += wx * wy * s_xy(qx, qy);
}
}
solOut(dx, dy, dz, e) += solZ;
}
}
}
@barrier("s_xy_sync_2");
}
}
}
//======================================
+142
View File
@@ -0,0 +1,142 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "operator.hpp"
namespace mfem
{
namespace occa
{
// FIXME: move this object to the Backend?
::occa::kernelBuilder OccaConstrainedOperator::mapDofBuilder =
::occa::linalg::customLinearMethod(
"vector_map_dofs",
"const int idx = v2[i];"
"v0[idx] = v1[idx];",
"defines: {"
" VTYPE0: 'double',"
" VTYPE1: 'double',"
" VTYPE2: 'int',"
" TILESIZE: 128,"
"}");
// FIXME: move this object to the Backend?
::occa::kernelBuilder OccaConstrainedOperator::clearDofBuilder =
::occa::linalg::customLinearMethod(
"vector_clear_dofs",
"v0[v1[i]] = 0.0;",
"defines: {"
" VTYPE0: 'double',"
" VTYPE1: 'int',"
" TILESIZE: 128,"
"}");
OccaConstrainedOperator::OccaConstrainedOperator(
mfem::Operator *A_,
const mfem::Array<int> &constraintList_,
bool own_A_)
: Operator(A_->InLayout()->As<Layout>()),
z(OutLayout_()),
w(OutLayout_()),
mfem_z((z.DontDelete(), z)),
mfem_w((w.DontDelete(), w))
{
Setup(OutLayout_().OccaEngine().GetDevice(), A_, constraintList_, own_A_);
}
void OccaConstrainedOperator::Setup(::occa::device device_,
mfem::Operator *A_,
const mfem::Array<int> &constraintList_,
bool own_A_)
{
device = device_;
A = A_;
own_A = own_A_;
constraintIndices = constraintList_.Size();
if (constraintList_.Size() > 0)
{
constraintList = constraintList_.Get_PArray()->As<Array>().OccaMem();
}
else
{
// constraintList is not used
}
}
void OccaConstrainedOperator::EliminateRHS(const Vector &x, Vector &b) const
{
::occa::kernel mapDofs = mapDofBuilder.build(device);
w.OccaFill(0.0);
if (constraintIndices)
{
mapDofs(constraintIndices, w.OccaMem(), x.OccaMem(), constraintList);
}
A->Mult(mfem_w, mfem_z);
b.Axpby<double>(1.0, b, -1.0, z);
if (constraintIndices)
{
mapDofs(constraintIndices, b.OccaMem(), x.OccaMem(), constraintList);
}
}
void OccaConstrainedOperator::Mult_(const Vector &x, Vector &y) const
{
mfem::Vector mfem_y(y);
if (constraintIndices == 0)
{
A->Mult(x.Wrap(), mfem_y);
return;
}
::occa::kernel mapDofs = mapDofBuilder.build(device);
::occa::kernel clearDofs = clearDofBuilder.build(device);
// z.OccaAssign(x); // z = x
// Is Axpy faster than DtoD copy on Volta?
z.Axpby(1.0, x, 0.0, x);
clearDofs(constraintIndices, z.OccaMem(), constraintList);
A->Mult(mfem_z, mfem_y);
mapDofs(constraintIndices, y.OccaMem(), x.OccaMem(), constraintList);
}
OccaConstrainedOperator::~OccaConstrainedOperator()
{
if (own_A)
{
delete A;
}
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+127
View File
@@ -0,0 +1,127 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_OPERATOR_HPP
#define MFEM_BACKENDS_OCCA_OPERATOR_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "vector.hpp"
#include "../../linalg/operator.hpp"
namespace mfem
{
namespace occa
{
class Operator : public mfem::Operator
{
public:
/// Creare an operator with the same dimensions as @a orig.
Operator(const Operator &orig)
: mfem::Operator(orig) { }
Operator(Layout &layout)
: mfem::Operator(layout) { }
Operator(Layout &in_layout, Layout &out_layout)
: mfem::Operator(in_layout, out_layout) { }
Layout &InLayout_() const { return in_layout->As<Layout>(); }
Layout &OutLayout_() const { return out_layout->As<Layout>(); }
virtual void Mult_(const Vector &x, Vector &y) const = 0;
virtual void MultTranspose_(const Vector &x, Vector &y) const
{ MFEM_ABORT("method is not supported"); }
// override
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const
{
Mult_(x.Get_PVector()->As<Vector>(),
y.Get_PVector()->As<Vector>());
}
// override
virtual void MultTranspose(const mfem::Vector &x, mfem::Vector &y) const
{
MultTranspose_(x.Get_PVector()->As<Vector>(),
y.Get_PVector()->As<Vector>());
}
};
class OccaConstrainedOperator : public Operator
{
protected:
::occa::device device;
mfem::Operator *A; //< The unconstrained Operator.
bool own_A; //< Ownership flag for A.
::occa::memory constraintList; //< List of constrained indices/dofs.
int constraintIndices;
mutable Vector z, w; //< Auxiliary vectors.
mutable mfem::Vector mfem_z, mfem_w; // Wrap z, w
static ::occa::kernelBuilder mapDofBuilder, clearDofBuilder;
public:
/** @brief Constructor from a general Operator and a list of essential
indices/dofs.
Specify the unconstrained operator @a *A and a @a list of indices to
constrain, i.e. each entry @a list[i] represents an essential-dof. If the
ownership flag @a own_A is true, the operator @a *A will be destroyed
when this object is destroyed. */
OccaConstrainedOperator(mfem::Operator *A_,
const mfem::Array<int> &constraintList_,
bool own_A_ = false);
void Setup(::occa::device device_,
mfem::Operator *A_,
const mfem::Array<int> &constraintList_,
bool own_A_ = false);
/** @brief Eliminate "essential boundary condition" values specified in @a x
from the given right-hand side @a b.
Performs the following steps:
z = A((0,x_b)); b_i -= z_i; b_b = x_b;
where the "_b" subscripts denote the essential (boundary) indices/dofs of
the vectors, and "_i" -- the rest of the entries. */
void EliminateRHS(const Vector &x, Vector &b) const;
/** @brief Constrained operator action.
Performs the following steps:
z = A((x_i,0)); y_i = z_i; y_b = x_b;
where the "_b" subscripts denote the essential (boundary) indices/dofs of
the vectors, and "_i" -- the rest of the entries. */
virtual void Mult_(const Vector &x, Vector &y) const;
// Destructor: destroys the unconstrained Operator @a A if @a own_A is true.
virtual ~OccaConstrainedOperator();
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_OPERATOR_HPP
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
/*
---[ Defines Known At Compile-Time ]------------
TILESIZE : Tilesize for iterating over dofs
================================================
*/
@kernel void Mult(const int entries,
@restrict const int *offsets,
@restrict const int *indices,
@restrict const double *weights,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
const int offset = offsets[i];
const int nextOffset = offsets[i + 1];
double value = 0;
for (int j = offset; j < nextOffset; ++j) {
value += weights[j] * in[indices[j]];
}
out[i] = value;
}
}
}
@kernel void MappedMult(const int entries,
@restrict const int *offsets,
@restrict const int *indices,
@restrict const double *weights,
@restrict const int *outIndices,
@restrict const double *in,
@restrict double *out) {
for (int i = 0; i < entries; ++i; @tile(TILESIZE, @outer, @inner)) {
if (i < entries) {
const int offset = offsets[i];
const int nextOffset = offsets[i + 1];
double value = 0;
for (int j = offset; j < nextOffset; ++j) {
value += weights[j] * in[indices[j]];
}
out[outIndices[i]] = value;
}
}
}
+221
View File
@@ -0,0 +1,221 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "sparsemat.hpp"
namespace mfem
{
namespace occa
{
OccaSparseMatrix::OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props)
: Operator(in_layout, out_layout)
{
Setup(in_layout.OccaEngine().GetDevice(), m, props);
}
OccaSparseMatrix::OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props)
: Operator(in_layout, out_layout),
offsets(offsets_),
indices(indices_),
weights(weights_),
reorderIndices(reorderIndices_),
mappedIndices(mappedIndices_)
{
SetupKernel(in_layout.OccaEngine().GetDevice(), props);
}
void OccaSparseMatrix::Setup(::occa::device device, const mfem::SparseMatrix &m,
const ::occa::properties &props)
{
Setup(device, m, ::occa::array<int>(), ::occa::array<int>(), props);
}
void OccaSparseMatrix::Setup(::occa::device device, const SparseMatrix &m,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props)
{
MFEM_ASSERT(m.Finalized(), "");
MFEM_ASSERT(m.Height() == height, "");
MFEM_ASSERT(m.Width() == width, "");
const int nnz = m.GetI()[height];
offsets.allocate(device,
height + 1, m.GetI());
indices.allocate(device,
nnz, m.GetJ());
weights.allocate(device,
nnz, m.GetData());
offsets.keepInDevice();
indices.keepInDevice();
weights.keepInDevice();
reorderIndices = reorderIndices_;
mappedIndices = mappedIndices_;
SetupKernel(device, props);
}
void OccaSparseMatrix::SetupKernel(::occa::device device,
const ::occa::properties &props)
{
const bool hasOutIndices = mappedIndices.isInitialized();
const ::occa::properties defaultProps("defines: {"
" TILESIZE: 256,"
"}");
const std::string &okl_path = InLayout_().OccaEngine().GetOklPath();
mapKernel = device.buildKernel(okl_path + "mappings.okl",
"MapSubVector",
defaultProps + props);
multKernel = device.buildKernel(okl_path + "sparse.okl",
hasOutIndices ? "MappedMult" : "Mult",
defaultProps + props);
}
void OccaSparseMatrix::Mult_(const Vector &x, Vector &y) const
{
if (reorderIndices.isInitialized() ||
mappedIndices.isInitialized())
{
if (reorderIndices.isInitialized())
{
mapKernel((int) (reorderIndices.size() / 2),
reorderIndices,
x.OccaMem(), y.OccaMem());
}
if (mappedIndices.isInitialized())
{
multKernel((int) (mappedIndices.size()),
offsets, indices, weights,
mappedIndices,
x.OccaMem(), y.OccaMem());
}
}
else
{
multKernel((int) height,
offsets, indices, weights,
x.OccaMem(), y.OccaMem());
}
}
OccaSparseMatrix* CreateMappedSparseMatrix(Layout &in_layout,
Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props)
{
const int mHeight = m.Height();
// const int mWidth = m.Width();
// Count indices that are only reordered (true dofs)
const int *I = m.GetI();
const int *J = m.GetJ();
const double *D = m.GetData();
int trueCount = 0;
for (int i = 0; i < mHeight; ++i)
{
trueCount += ((I[i + 1] - I[i]) == 1);
}
const int dupCount = (mHeight - trueCount);
// Create the reordering map for entries that aren't modified (true dofs)
::occa::device device(in_layout.OccaEngine().GetDevice());
::occa::array<int> reorderIndices(device,
2 * trueCount);
::occa::array<int> mappedIndices, offsets, indices;
::occa::array<double> weights;
if (dupCount)
{
mappedIndices.allocate(device,
dupCount);
}
int trueIdx = 0, dupIdx = 0;
for (int i = 0; i < mHeight; ++i)
{
const int i1 = I[i];
if ((I[i + 1] - i1) == 1)
{
reorderIndices[trueIdx++] = J[i1];
reorderIndices[trueIdx++] = i;
}
else
{
mappedIndices[dupIdx++] = i;
}
}
reorderIndices.keepInDevice();
if (dupCount)
{
mappedIndices.keepInDevice();
// Extract sparse matrix without reordered identity
const int dupNnz = I[mHeight] - trueCount;
offsets.allocate(device,
dupCount + 1);
indices.allocate(device,
dupNnz);
weights.allocate(device,
dupNnz);
int nnz = 0;
offsets[0] = 0;
for (int i = 0; i < dupCount; ++i)
{
const int idx = mappedIndices[i];
const int offStart = I[idx];
const int offEnd = I[idx + 1];
offsets[i + 1] = offsets[i] + (offEnd - offStart);
for (int j = offStart; j < offEnd; ++j)
{
indices[nnz] = J[j];
weights[nnz] = D[j];
++nnz;
}
}
offsets.keepInDevice();
indices.keepInDevice();
weights.keepInDevice();
}
return new OccaSparseMatrix(in_layout, out_layout,
offsets, indices, weights,
reorderIndices, mappedIndices,
props);
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+89
View File
@@ -0,0 +1,89 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_SPARSE_MAT_HPP
#define MFEM_BACKENDS_OCCA_SPARSE_MAT_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include <occa.hpp>
#include "vector.hpp"
#include "engine.hpp"
#include "operator.hpp"
#include "../../linalg/sparsemat.hpp"
namespace mfem
{
namespace occa
{
/// TODO: doxygen
class OccaSparseMatrix : public Operator
{
protected:
::occa::array<int> offsets, indices;
::occa::array<double> weights;
::occa::array<int> reorderIndices, mappedIndices;
::occa::kernel mapKernel, multKernel;
void Setup(::occa::device device, const mfem::SparseMatrix &m,
const ::occa::properties &props);
void Setup(::occa::device device, const mfem::SparseMatrix &m,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props);
void SetupKernel(::occa::device device,
const ::occa::properties &props);
public:
/// Construct an empty OccaSparseMatrix.
OccaSparseMatrix(const Operator &orig)
: Operator(orig) { }
// Implicitly defined copy constructor.
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props = ::occa::properties());
OccaSparseMatrix(Layout &in_layout, Layout &out_layout,
::occa::array<int> offsets_,
::occa::array<int> indices_,
::occa::array<double> weights_,
::occa::array<int> reorderIndices_,
::occa::array<int> mappedIndices_,
const ::occa::properties &props = ::occa::properties());
const ::occa::array<int> &GetReorderIndices() const
{ return reorderIndices; }
// override
virtual void Mult_(const Vector &x, Vector &y) const;
};
/// TODO: doxygen
OccaSparseMatrix* CreateMappedSparseMatrix(
Layout &in_layout, Layout &out_layout,
const mfem::SparseMatrix &m,
const ::occa::properties &props = ::occa::properties());
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_SPARSE_MAT_HPP
+81
View File
@@ -0,0 +1,81 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "url_handler.hpp"
#include "../../general/error.hpp"
#include <cstdlib>
#include <sys/stat.h>
namespace mfem
{
namespace occa
{
FileOpener::FileOpener(const std::string &prefix,
const std::string &env_variable)
: pfx(prefix)
{
const char *env_path = getenv(env_variable.c_str());
if (!env_path) { return; }
std::string path(env_path);
for (std::size_t start = 0, end; start < path.size(); start = end + 1)
{
end = path.find(':', start);
if (end == std::string::npos)
{
AddDir(path.substr(start, end));
break;
}
AddDir(path.substr(start, end - start));
}
}
bool FileOpener::AddDir(const std::string &dir)
{
if (dir.size() == 0 || dir[0] != '/') { return false; }
struct stat dir_stat;
if (stat(dir.c_str(), &dir_stat)) { return false; }
if (!S_ISDIR(dir_stat.st_mode)) { return false; }
paths.push_back(dir + (*dir.rbegin() == '/' ? "" : "/"));
return true;
}
bool FileOpener::handles(const std::string &filename)
{
return filename.size() >= pfx.size() &&
filename.compare(0, pfx.size(), pfx) == 0;
}
std::string FileOpener::expand(const std::string &filename)
{
std::string sfx(filename.substr(pfx.size()));
for (std::size_t i = 0; i < paths.size(); i++)
{
std::string file = paths[i] + sfx;
struct stat file_stat;
if (stat(file.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode))
{
return file;
}
}
MFEM_ABORT("invalid url: " << filename);
return sfx;
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_URL_HANDLER_HPP
#define MFEM_BACKENDS_OCCA_URL_HANDLER_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include <occa.hpp>
namespace mfem
{
namespace occa
{
class FileOpener : public ::occa::io::fileOpener
{
protected:
std::string pfx; // prefix, e.g. "mfem://"
std::vector<std::string> paths; // paths to search for prefix replacement
public:
FileOpener(const std::string &prefix, const std::string &env_variable);
bool AddDir(const std::string &dir);
virtual bool handles(const std::string &filename);
virtual std::string expand(const std::string &filename);
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_URL_HANDLER_HPP
@@ -9,20 +9,14 @@
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem.hpp"
using namespace mfem;
typedef double* Local_t @dim(numDofs, numElements);
#include "catch.hpp"
#include "general/text.hpp"
TEST_CASE("String Manipulation", "[General]")
{
SECTION("String Conversion")
{
SECTION("Integer")
{
REQUIRE(to_int(to_string(12)) == 12);
REQUIRE(to_int(to_string(-1234)) == -1234);
}
}
@kernel void InitLocalVector(const int numElements,
const int numDofs,
@restrict Local_t sol) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int d = 0; d < numDofs; ++d; @inner) {
sol(d, e) = 0;
}
}
}
+196
View File
@@ -0,0 +1,196 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include "vector.hpp"
#include "../../linalg/vector.hpp"
namespace mfem
{
namespace occa
{
PVector *Vector::DoVectorClone(bool copy_data, void **buffer,
int buffer_type_id) const
{
MFEM_ASSERT(buffer_type_id == ScalarId<double>::value, "");
Vector *new_vector = new Vector(OccaLayout());
if (copy_data)
{
new_vector->slice.copyFrom(slice);
}
if (buffer)
{
*buffer = new_vector->GetBuffer();
}
return new_vector;
}
void Vector::DoDotProduct(const PVector &x, void *result,
int result_type_id) const
{
// Can be called when Size() == 0, e.g. when an MPI-parallel vector has a
// local size of 0.
MFEM_ASSERT(result_type_id == ScalarId<double>::value, "");
double *res = (double *)result;
const Vector &xp = x.As<Vector>();
MFEM_ASSERT(this->Size() == xp.Size(), "");
*res = ::occa::linalg::dot<double, double, double>(this->slice, xp.slice);
#ifdef MFEM_USE_MPI
double local_dot = *res;
if (IsParallel())
{
MPI_Allreduce(&local_dot, res, 1, MPI_DOUBLE, MPI_SUM,
OccaEngine().GetComm());
}
#endif
}
void Vector::DoAxpby(const void *a, const PVector &x,
const void *b, const PVector &y,
int ab_type_id)
{
//
// TODO: move all kernel builders to class mfem::occa::Backend
//
static ::occa::kernelBuilder axpby1_builder =
::occa::linalg::customLinearMethod(
"mfem_occa_axpby1",
"v0[i] = c0 * v1[i];",
"defines: {"
" CTYPE0: 'double',"
" VTYPE0: 'double',"
" VTYPE1: 'double',"
" TILESIZE: '128',"
"}");
static ::occa::kernelBuilder axpby2_builder =
::occa::linalg::customLinearMethod(
"mfem_occa_axpby2",
"v0[i] = c0 * v0[i] + c1 * v1[i];",
"defines: {"
" CTYPE0: 'double',"
" CTYPE1: 'double',"
" VTYPE0: 'double',"
" VTYPE1: 'double',"
" TILESIZE: '128',"
"}");
static ::occa::kernelBuilder axpby3_builder =
::occa::linalg::customLinearMethod(
"mfem_occa_axpby3",
"v0[i] = c0 * v1[i] + c1 * v2[i];",
"defines: {"
" CTYPE0: 'double',"
" CTYPE1: 'double',"
" VTYPE0: 'double',"
" VTYPE1: 'double',"
" VTYPE2: 'double',"
" TILESIZE: '128',"
"}");
// called only when Size() != 0
MFEM_ASSERT(ab_type_id == ScalarId<double>::value, "");
const double da = *static_cast<const double *>(a);
const double db = *static_cast<const double *>(b);
MFEM_ASSERT(da == 0.0 || dynamic_cast<const Vector *>(&x) != NULL,
"invalid Vector x");
MFEM_ASSERT(db == 0.0 || dynamic_cast<const Vector *>(&y) != NULL,
"invalid Vector y");
const Vector *xp = static_cast<const Vector *>(&x);
const Vector *yp = static_cast<const Vector *>(&y);
MFEM_ASSERT(da == 0.0 || this->Size() == xp->Size(), "");
MFEM_ASSERT(db == 0.0 || this->Size() == yp->Size(), "");
if (da == 0.0)
{
if (db == 0.0)
{
OccaFill(da);
}
else
{
if (this->slice == yp->slice)
{
// *this *= db
::occa::linalg::operator_mult_eq(slice, db);
}
else
{
// *this = db * y
::occa::kernel kernel = axpby1_builder.build(slice.getDevice());
kernel((int)Size(), db, slice, yp->slice);
}
}
}
else
{
if (db == 0.0)
{
if (this->slice == xp->slice)
{
// *this *= da
::occa::linalg::operator_mult_eq(slice, da);
}
else
{
// *this = da * x
::occa::kernel kernel = axpby1_builder.build(slice.getDevice());
kernel((int)Size(), da, slice, xp->slice);
}
}
else
{
MFEM_ASSERT(xp->slice != yp->slice, "invalid input");
if (this->slice == xp->slice)
{
// *this = da * (*this) + db * y
::occa::kernel kernel = axpby2_builder.build(slice.getDevice());
kernel((int)Size(), da, db, slice, yp->slice);
}
else if (this->slice == yp->slice)
{
// *this = da * x + db * (*this)
::occa::kernel kernel = axpby2_builder.build(slice.getDevice());
kernel((int)Size(), db, da, slice, xp->slice);
}
else
{
// *this = da * x + db * y
::occa::kernel kernel = axpby3_builder.build(slice.getDevice());
kernel((int)Size(), da, db, slice, xp->slice, yp->slice);
}
}
}
}
mfem::Vector Vector::Wrap()
{
return mfem::Vector(*this);
}
const mfem::Vector Vector::Wrap() const
{
return mfem::Vector(*const_cast<Vector*>(this));
}
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_BACKENDS_OCCA_VECTOR_HPP
#define MFEM_BACKENDS_OCCA_VECTOR_HPP
#include "../../config/config.hpp"
#if defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#include <occa.hpp>
#include "../base/vector.hpp"
#include "array.hpp"
namespace mfem
{
namespace occa
{
// FIXME: Once XL fixes this code quirk we can remove this #ifdef switch
#ifdef __ibmxl__
class Vector : public Array, public PVector
#else
class Vector : virtual public Array, public PVector
#endif
{
protected:
//
// Inherited fields
//
// DLayout layout;
/**
@name Virtual interface
*/
///@{
virtual PVector *DoVectorClone(bool copy_data, void **buffer,
int buffer_type_id) const;
virtual void DoDotProduct(const PVector &x, void *result,
int result_type_id) const;
virtual void DoAxpby(const void *a, const PVector &x,
const void *b, const PVector &y,
int ab_type_id);
///@}
// End: Virtual interface
public:
Vector(const Engine &e)
: PArray(*(new Layout(e, 0))), Array(e), PVector(*layout)
{ }
Vector(Layout &lt)
: PArray(lt), Array(lt, sizeof(double)), PVector(lt)
{ }
mfem::Vector Wrap();
const mfem::Vector Wrap() const;
#if defined(MFEM_USE_MPI)
bool IsParallel() const { return (OccaEngine().GetComm() != MPI_COMM_NULL); }
#endif
};
} // namespace mfem::occa
} // namespace mfem
#endif // defined(MFEM_USE_BACKENDS) && defined(MFEM_USE_OCCA)
#endif // MFEM_BACKENDS_OCCA_VECTOR_HPP
+321
View File
@@ -0,0 +1,321 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "mfem-occa://defines.okl"
//---[ 1D ]-----------------------------
@kernel void Assemble1D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian1D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_1D; ++q; @inner) {
oper(q, e) = quadWeights[q] * COEFF * J(q, e);
}
}
}
@kernel void MultAdd1D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DVLocal1D_t solIn,
@restrict DVLocal1D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_x[1][NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] = 0;
}
// sol_x{qx} = dofToQuad{qx,dx} * sol{dx}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] += dofToQuad(qx, dx) * solIn(0, dx, e);
}
}
// sol_x{q} *= oper{q}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] *= oper(qx, e);
}
// sol{dx} = quadToDof{dx,qx} * sol_x{qx}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(0, dx, e) += sol_x[0][qx] * quadToDof(dx, qx);
}
}
}
}
}
//======================================
//---[ 2D ]-----------------------------
@kernel void Assemble2D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian2D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_2D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
oper(q, e) = quadWeights[q] * COEFF * ((J11 * J22) - (J21 * J12));
}
} // e
}
@kernel void MultAdd2D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DVLocal2D_t solIn,
@restrict DVLocal2D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy=0; dummy<1; ++dummy; @inner) {
double sol_xy[2][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qx][qy] = 0;
sol_xy[1][qx][qy] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[2][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
sol_x[0][qy] = 0;
sol_x[1][qy] = 0;
}
// sol_x{vd, dx, qy} = dofToQuad{qy, dy} * sol{vd, dx, dy}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
sol_x[0][qy] += dofToQuad(qy, dx) * solIn(0, dx, dy, e);
sol_x[1][qy] += dofToQuad(qy, dx) * solIn(1, dx, dy, e);
}
}
// sol_xy{qx, qy} = dofToQuad{qx, dx} * sol_x{dx, qy}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double d2q = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qx][qy] += d2q * sol_x[0][qx];
sol_xy[1][qx][qy] += d2q * sol_x[1][qx];
}
}
} // dy
// sol_xy{qx, qy} = sol_xy{q} *= oper{q, e}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const int q = QUAD_2D_ID(qx, qy);
sol_xy[0][qx][qy] *= oper(q, e);
sol_xy[1][qx][qy] *= oper(q, e);
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[2][NUM_DOFS_1D];
for (int dx = 0; dx < NUM_QUAD_1D; ++dx) {
sol_x[0][dx] = 0;
sol_x[1][dx] = 0;
}
// sol_x{qx, dy} = quadToDof{dy, qy} * sol_xy{qx, qy}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[0][dx] += quadToDof(dx, qx) * sol_xy[0][qx][qy];
sol_x[1][dx] += quadToDof(dx, qx) * sol_xy[1][qx][qy];
}
}
// sol{dx, dy, e} = quadToDof{dx, qx} * sol_x{qx, dy}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double q2d = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(0, dx, dy, e) += q2d * sol_x[0][dx];
solOut(1, dx, dy, e) += q2d * sol_x[1][dx];
}
}
}
} // dummy
} // e
}
//======================================
//---[ 3D ]-----------------------------
@kernel void Assemble3D(const int numElements,
@restrict const double * quadWeights,
@restrict const Jacobian3D_t J,
COEFF_ARGS
@restrict QLocal_t oper) {
for (int e = 0; e < numElements; ++e; @outer) {
for (int q = 0; q < NUM_QUAD_3D; ++q; @inner) {
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
oper(q, e) = quadWeights[q] * COEFF * detJ;
}
}
}
@kernel void MultAdd3D(const int numElements,
@restrict const DofToQuad_t dofToQuad,
@restrict const DofToQuad_t dofToQuadD,
@restrict const QuadToDof_t quadToDof,
@restrict const QuadToDof_t quadToDofD,
@restrict const QLocal_t oper,
@restrict const DVLocal3D_t solIn,
@restrict DVLocal3D_t solOut) {
// Iterate over elements
for (int e = 0; e < numElements; ++e; @outer) {
for (int dummy = 0; dummy < 1; ++dummy; @inner) {
double sol_xyz[3][NUM_QUAD_1D][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[0][qz][qy][qx] = 0;
sol_xyz[1][qz][qy][qx] = 0;
sol_xyz[2][qz][qy][qx] = 0;
}
}
}
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
double sol_xy[3][NUM_QUAD_1D][NUM_QUAD_1D];
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qy][qx] = 0;
sol_xy[1][qy][qx] = 0;
sol_xy[2][qy][qx] = 0;
}
}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
double sol_x[3][NUM_QUAD_1D];
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] = 0;
sol_x[1][qx] = 0;
sol_x[2][qx] = 0;
}
// sol_x{qx} = dofToQuad{qx, dx} * sol{dx, dy, dz, e}
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_x[0][qx] += dofToQuad(qx, dx) * solIn(0, dx, dy, dz, e);
sol_x[1][qx] += dofToQuad(qx, dx) * solIn(1, dx, dy, dz, e);
sol_x[2][qx] += dofToQuad(qx, dx) * solIn(2, dx, dy, dz, e);
}
}
// sol_xy{qx, qy} = dofToQuad{qy, dy} * sol_x{dx}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
const double wy = dofToQuad(qy, dy);
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xy[0][qy][qx] += wy * sol_x[0][qx];
sol_xy[1][qy][qx] += wy * sol_x[1][qx];
sol_xy[2][qy][qx] += wy * sol_x[2][qx];
}
}
} // dy
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
const double wz = dofToQuad(qz, dz);
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
sol_xyz[0][qz][qy][qx] += wz * sol_xy[0][qy][qx];
sol_xyz[1][qz][qy][qx] += wz * sol_xy[1][qy][qx];
sol_xyz[2][qz][qy][qx] += wz * sol_xy[2][qy][qx];
}
}
}
} // dz
// sol_xyz{qz, qy, qx} *= oper{q, e}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
const int q = QUAD_3D_ID(qx, qy, qz);
sol_xyz[0][qz][qy][qx] *= oper(q, e);
sol_xyz[1][qz][qy][qx] *= oper(q, e);
sol_xyz[2][qz][qy][qx] *= oper(q, e);
}
}
}
for (int qz = 0; qz < NUM_QUAD_1D; ++qz) {
double sol_xy[3][NUM_DOFS_1D][NUM_DOFS_1D];
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[0][dy][dx] = 0;
sol_xy[1][dy][dx] = 0;
sol_xy[2][dy][dx] = 0;
}
}
for (int qy = 0; qy < NUM_QUAD_1D; ++qy) {
double sol_x[3][NUM_DOFS_1D];
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[0][dx] = 0;
sol_x[1][dx] = 0;
sol_x[2][dx] = 0;
}
// sol_x{dx} = quadToDof{dx, qx} * sol_xyz{qz, qy, qx}
for (int qx = 0; qx < NUM_QUAD_1D; ++qx) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_x[0][dx] += quadToDof(dx, qx) * sol_xyz[0][qz][qy][qx];
sol_x[1][dx] += quadToDof(dx, qx) * sol_xyz[1][qz][qy][qx];
sol_x[2][dx] += quadToDof(dx, qx) * sol_xyz[2][qz][qy][qx];
}
}
// sol_xy{dy, dx} = quadToDof{dy, qy} * sol_x{dx}
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
const double wy = quadToDof(dy, qy);
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
sol_xy[0][dy][dx] += wy * sol_x[0][dx];
sol_xy[1][dy][dx] += wy * sol_x[1][dx];
sol_xy[2][dy][dx] += wy * sol_x[2][dx];
}
}
} // qy
for (int dz = 0; dz < NUM_DOFS_1D; ++dz) {
const double wz = quadToDof(dz, qz);
for (int dy = 0; dy < NUM_DOFS_1D; ++dy) {
for (int dx = 0; dx < NUM_DOFS_1D; ++dx) {
solOut(0, dx, dy, dz, e) += wz * sol_xy[0][dy][dx];
solOut(1, dx, dy, dz, e) += wz * sol_xy[1][dy][dx];
solOut(2, dx, dy, dz, e) += wz * sol_xy[2][dy][dx];
}
}
}
} // qz
} // dummy
} // e
}
//======================================
+4 -95
View File
@@ -74,7 +74,7 @@
IF (NOT COMMAND PRINT_VAR)
FUNCTION(PRINT_VAR VAR_NAME)
MESSAGE(STATUS "${VAR_NAME} = '${${VAR_NAME}}'")
MESSAGE("-- " "${VAR_NAME} = '${${VAR_NAME}}'")
ENDFUNCTION()
ENDIF()
@@ -166,108 +166,17 @@ IF (USE_XSDK_DEFAULTS)
ENDIF()
XSDK_HANDLE_LANG_DEFAULTS(Fortran FC "FFLAGS;FCFLAGS")
ENDIF()
# Set XSDK defaults for other CMake variables
IF ("${BUILD_SHARED_LIBS}" STREQUAL "")
MESSAGE("-- " "XSDK: Setting default BUILD_SHARED_LIBS=TRUE")
SET(BUILD_SHARED_LIBS TRUE CACHE BOOL "Set by default in XSDK mode")
ENDIF()
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
MESSAGE("-- " "XSDK: Setting default CMAKE_BUILD_TYPE=DEBUG")
SET(CMAKE_BUILD_TYPE DEBUG CACHE STRING "Set by default in XSDK mode")
ENDIF()
ENDIF()
##################################################################################
#
# MFEM-specific additions: set TPL MFEM_USE_* defaults
#
##################################################################################
IF (DEFINED TPL_ENABLE_MPI)
SET(MFEM_USE_MPI ${TPL_ENABLE_MPI} CACHE BOOL "Enable MPI parallel build" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_METIS)
SET(MFEM_USE_METIS ${TPL_ENABLE_METIS} CACHE BOOL "Enable METIS usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_GZSTREAM)
SET(MFEM_USE_GZSTREAM ${TPL_ENABLE_GZSTREAM} CACHE BOOL "Enable gzstream for compressed data streams." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_LIBUNWIND)
SET(MFEM_USE_LIBUNWIND ${TPL_ENABLE_LIBUNWIND} CACHE BOOL "Enable backtrace for errors." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_LAPACK)
SET(MFEM_USE_LAPACK ${TPL_ENABLE_LAPACK} CACHE BOOL "Enable LAPACK usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_SUNDIALS)
SET(MFEM_USE_SUNDIALS ${TPL_ENABLE_SUNDIALS} CACHE BOOL "Enable SUNDIALS usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_MESQUITE)
SET(MFEM_USE_MESQUITE ${TPL_ENABLE_MESQUITE} CACHE BOOL "Enable MESQUITE usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_SUITESPARSE)
SET(MFEM_USE_SUITESPARSE ${TPL_ENABLE_SUITESPARSE} CACHE BOOL "Enable SuiteSparse usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_SUPERLU)
SET(MFEM_USE_SUPERLU ${TPL_ENABLE_SUPERLU} CACHE BOOL "Enable SuperLU_DIST usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_STRUMPACK)
SET(MFEM_USE_STRUMPACK ${TPL_ENABLE_STRUMPACK} CACHE BOOL "Enable STRUMPACK usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_GECKO)
SET(MFEM_USE_GECKO ${TPL_ENABLE_GECKO} CACHE BOOL "Enable GECKO usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_GNUTLS)
SET(MFEM_USE_GNUTLS ${TPL_ENABLE_GNUTLS} CACHE BOOL "Enable GNUTLS usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_NETCDF)
SET(MFEM_USE_NETCDF ${TPL_ENABLE_NETCDF} CACHE BOOL "Enable NETCDF usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_PETSC)
SET(MFEM_USE_PETSC ${TPL_ENABLE_PETSC} CACHE BOOL "Enable PETSc support." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_MPFR)
SET(MFEM_USE_MPFR ${TPL_ENABLE_MPFR} CACHE BOOL "Enable MPFR usage." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_SIDRE)
SET(MFEM_USE_SIDRE ${TPL_ENABLE_SIDRE} CACHE BOOL "Enable Axom/Sidre usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_CONDUIT)
SET(MFEM_USE_CONDUIT ${TPL_ENABLE_CONDUIT} CACHE BOOL "Enable Conduit usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_PUMI)
SET(MFEM_USE_PUMI ${TPL_ENABLE_PUMI} CACHE BOOL "Enable PUMI" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_CUDA)
SET(MFEM_USE_CUDA ${TPL_ENABLE_CUDA} CACHE BOOL "Enable CUDA" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_OCCA)
SET(MFEM_USE_OCCA ${TPL_ENABLE_OCCA} CACHE BOOL "Enable OCCA" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_RAJA)
SET(MFEM_USE_RAJA ${TPL_ENABLE_RAJA} CACHE BOOL "Enable RAJA" FORCE)
ENDIF()
-4
View File
@@ -25,7 +25,6 @@ set(MFEM_USE_LIBUNWIND @MFEM_USE_LIBUNWIND@)
set(MFEM_USE_LAPACK @MFEM_USE_LAPACK@)
set(MFEM_THREAD_SAFE @MFEM_THREAD_SAFE@)
set(MFEM_USE_OPENMP @MFEM_USE_OPENMP@)
set(MFEM_USE_LEGACY_OPENMP @MFEM_USE_LEGACY_OPENMP@)
set(MFEM_USE_MEMALLOC @MFEM_USE_MEMALLOC@)
set(MFEM_TIMER_TYPE @MFEM_TIMER_TYPE@)
set(MFEM_USE_SUNDIALS @MFEM_USE_SUNDIALS@)
@@ -41,9 +40,6 @@ set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
set(MFEM_USE_PUMI @MFEM_USE_PUMI@)
set(MFEM_USE_CUDA @MFEM_USE_CUDA@)
set(MFEM_USE_OCCA @MFEM_USE_OCCA@)
set(MFEM_USE_RAJA @MFEM_USE_RAJA@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
+5 -20
View File
@@ -30,12 +30,6 @@
#define MFEM_VERSION_MINOR (((MFEM_VERSION)/100)%100)
#define MFEM_VERSION_PATCH ((MFEM_VERSION)%100)
// MFEM source directory.
#define MFEM_SOURCE_DIR "@MFEM_SOURCE_DIR@"
// MFEM install directory.
#define MFEM_INSTALL_DIR "@MFEM_INSTALL_DIR@"
// Description of the git commit used to build MFEM.
#cmakedefine MFEM_GIT_STRING "@MFEM_GIT_STRING@"
@@ -68,12 +62,9 @@
// allocation and de-allocation.
#cmakedefine MFEM_THREAD_SAFE
// Enable the OpenMP backend.
// Enable experimental OpenMP support. Requires MFEM_THREAD_SAFE.
#cmakedefine MFEM_USE_OPENMP
// [Deprecated] Enable experimental OpenMP support. Requires MFEM_THREAD_SAFE.
#cmakedefine MFEM_USE_LEGACY_OPENMP
// Enable MFEM functionality based on the Mesquite library.
#cmakedefine MFEM_USE_MESQUITE
@@ -110,16 +101,6 @@
// Enable MFEM functionality based on the PUMI library
#cmakedefine MFEM_USE_PUMI
// Build the GPU/CUDA-enabled version of the MFEM library.
// Requires a CUDA compiler (nvcc).
#cmakedefine MFEM_USE_CUDA
// Enable MFEM functionality based on the RAJA library
#cmakedefine MFEM_USE_RAJA
// Enable MFEM functionality based on the OCCA library
#cmakedefine MFEM_USE_OCCA
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
@@ -128,6 +109,10 @@
// Enable MFEM functionality based on the SUNDIALS libraries.
#cmakedefine MFEM_USE_SUNDIALS
// Windows specific options
// Macro needed to get defines like M_PI from <cmath>. (Visual Studio C++ only?)
#cmakedefine _USE_MATH_DEFINES
// Version of HYPRE used for building MFEM.
#cmakedefine MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
+3 -1
View File
@@ -18,4 +18,6 @@ include(MfemCmakeUtilities)
# Note: components are enabled based on the find_package() parameters.
mfem_find_package(Axom AXOM AXOM_DIR "include" "" "lib" ""
"Paths to headers required by Axom." "Libraries required by Axom."
ADD_COMPONENT Axom "include" axom/config.hpp "lib" axom)
ADD_COMPONENT Sidre "include" sidre/sidre.hpp "lib" sidre
ADD_COMPONENT SLIC "include" slic/slic.hpp "lib" slic
ADD_COMPONENT axom_utils "include" axom_utils/Utilities.hpp "lib" axom_utils)
-19
View File
@@ -1,19 +0,0 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
# Defines the following variables:
# - OCCA_FOUND
# - OCCA_LIBRARIES
# - OCCA_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(OCCA OCCA OCCA_DIR "include" "occa.hpp" "lib" "occa"
"Paths to headers required by OCCA." "Libraries required by OCCA.")
-30
View File
@@ -1,30 +0,0 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
# Defines the following variables:
# - RAJA_FOUND
# - RAJA_LIBRARIES
# - RAJA_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(RAJA RAJA RAJA_DIR "include" "RAJA/RAJA.hpp" "lib" "RAJA"
"Paths to headers required by RAJA." "Libraries required by RAJA.")
if (NOT RAJA_CONFIG_CMAKE)
set(RAJA_CONFIG_CMAKE "${RAJA_DIR}/share/raja/cmake/raja-config.cmake")
endif()
if (EXISTS "${RAJA_CONFIG_CMAKE}")
include("${RAJA_CONFIG_CMAKE}")
if (ENABLE_CUDA AND NOT MFEM_USE_CUDA)
message(FATAL_ERROR
"RAJA is built with CUDA: MFEM_USE_CUDA=YES is required")
endif()
endif()
@@ -229,17 +229,6 @@ endfunction(mfem_find_component)
function(mfem_find_package Name Prefix DirVar IncSuffixes Header LibSuffixes
Lib IncDoc LibDoc)
# If we have the TPL_ versions of _INCLUDE_DIRS and _LIBRARIES then set the
# standard ${Prefix} versions
if (TPL_${Prefix}_INCLUDE_DIRS)
set(${Prefix}_INCLUDE_DIRS ${TPL_${Prefix}_INCLUDE_DIRS} CACHE STRING
"TPL_${Prefix}_INCLUDE_DIRS was found." FORCE)
endif()
if (TPL_${Prefix}_LIBRARIES)
set(${Prefix}_LIBRARIES ${TPL_${Prefix}_LIBRARIES} CACHE STRING
"TPL_${Prefix}_LIBRARIES was found." FORCE)
endif()
# Quick return
if (${Prefix}_FOUND)
return()
@@ -696,163 +685,3 @@ function(mfem_find_library Name Prefix Lib LibDoc CheckVar CheckSrc)
endif()
endfunction(mfem_find_library)
#
# Function that creates 'config.mk' from 'config.mk.in' for the both the
# build- and the install-locations and define install rules for 'config.mk'
# and 'test.mk'.
#
function(mfem_export_mk_files)
# Define a few auxiliary variables (not written to 'config.mk')
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
# CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG -> '-Wl,-rpath,'
set(shared_link_flag ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
if (NOT shared_link_flag)
set(shared_link_flag "-Wl,-rpath,")
endif()
# Convert Boolean vars to YES/NO without writting the values to cache
set(CONFIG_MK_BOOL_VARS MFEM_USE_MPI MFEM_USE_METIS MFEM_USE_METIS_5
MFEM_DEBUG MFEM_USE_EXCEPTIONS MFEM_USE_GZSTREAM MFEM_USE_LIBUNWIND
MFEM_USE_LAPACK MFEM_THREAD_SAFE MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GECKO MFEM_USE_GNUTLS
MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
else()
set(${var} NO)
endif()
endforeach()
# TODO: Add support for MFEM_USE_CUDA=YES
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
set(MFEM_CPPFLAGS "")
string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
MFEM_CXXFLAGS)
set(MFEM_TPLFLAGS "")
foreach(dir ${MFEM_TPL_INCLUDE_DIRS})
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} -I${dir}")
endforeach()
# TODO: MFEM_TPLFLAGS: add other TPL flags, in addition to the -I flags.
set(MFEM_INCFLAGS "-I\$(MFEM_INC_DIR) \$(MFEM_TPLFLAGS)")
set(MFEM_PICFLAG "")
if (BUILD_SHARED_LIBS)
set(MFEM_PICFLAG "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
endif()
set(MFEM_FLAGS "\$(MFEM_CPPFLAGS) \$(MFEM_CXXFLAGS) \$(MFEM_INCFLAGS)")
# TPL link flags: set below
set(MFEM_EXT_LIBS "")
if (BUILD_SHARED_LIBS)
set(MFEM_LIBS "${shared_link_flag}\$(MFEM_LIB_DIR) -L\$(MFEM_LIB_DIR)")
set(MFEM_LIBS "${MFEM_LIBS} -lmfem \$(MFEM_EXT_LIBS)")
if (APPLE)
set(SO_VER ".${mfem_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}")
else()
set(SO_VER "${CMAKE_SHARED_LIBRARY_SUFFIX}.${mfem_VERSION}")
endif()
set(MFEM_LIB_FILE "\$(MFEM_LIB_DIR)/libmfem${SO_VER}")
set(MFEM_SHARED YES)
set(MFEM_STATIC NO)
else()
set(MFEM_LIBS "-L\$(MFEM_LIB_DIR) -lmfem \$(MFEM_EXT_LIBS)")
set(MFEM_LIB_FILE "\$(MFEM_LIB_DIR)/libmfem.a")
set(MFEM_SHARED NO)
set(MFEM_STATIC YES)
endif()
set(MFEM_BUILD_TAG "${CMAKE_SYSTEM}")
set(MFEM_PREFIX "${CMAKE_INSTALL_PREFIX}")
# For the next 4 variable, these are the values for the build-tree version of
# 'config.mk'
set(MFEM_INC_DIR "${PROJECT_BINARY_DIR}")
set(MFEM_LIB_DIR "${PROJECT_BINARY_DIR}")
set(MFEM_TEST_MK "${PROJECT_SOURCE_DIR}/config/test.mk")
set(MFEM_CONFIG_EXTRA "MFEM_BUILD_DIR ?= ${PROJECT_BINARY_DIR}")
set(MFEM_MPIEXEC ${MPIEXEC})
if (NOT MFEM_MPIEXEC)
set(MFEM_MPIEXEC "mpirun")
endif()
set(MFEM_MPIEXEC_NP ${MPIEXEC_NUMPROC_FLAG})
if (NOT MFEM_MPIEXEC_NP)
set(MFEM_MPIEXEC_NP "-np")
endif()
# MFEM_MPI_NP is already set
# Define the variable 'MFEM_EXT_LIBS': handle PUMI libs
if ("${MFEM_USE_PUMI}" STREQUAL "YES")
message(STATUS "simmodsuite_dir = '${SIMMODSUITE_DIR}'")
get_target_property(liblist ${PUMI_LIBRARIES} INTERFACE_LINK_LIBRARIES)
set(pumi_dep_libs "${liblist}")
foreach(pumilib ${liblist})
get_target_property(libdeps ${pumilib} INTERFACE_LINK_LIBRARIES)
if (NOT "${libdeps}" MATCHES "libdeps-NOTFOUND")
list(APPEND pumi_dep_libs ${libdeps})
endif()
endforeach()
list(REMOVE_DUPLICATES pumi_dep_libs)
foreach(pumilib ${pumi_dep_libs})
unset(lib CACHE)
string(REGEX REPLACE "^SCOREC::" "" libname ${pumilib})
string(FIND "${pumilib}" ".a" staticlib)
string(FIND "${pumilib}" ".so" sharedlib)
find_library(lib ${libname} PATHS ${PUMI_DIR}/lib NO_DEFUALT_PATH)
if (NOT "${sharedlib}" MATCHES "-1" OR
NOT "${staticlib}" MATCHES "-1" )
set(MFEM_EXT_LIBS "${pumilib} ${MFEM_EXT_LIBS}")
elseif (NOT "${lib}" MATCHES "lib-NOTFOUND")
set(MFEM_EXT_LIBS "${lib} ${MFEM_EXT_LIBS}")
elseif ("${lib}" MATCHES "lib-NOTFOUND" AND
NOT "${libname}" MATCHES "can" AND
NOT "${libname}" MATCHES "pthread")
message(FATAL_ERROR "SCOREC lib ${libname} not found")
endif()
endforeach()
endif()
# Define the variable 'MFEM_EXT_LIBS': handle other (not PUMI) libs
foreach(lib ${TPL_LIBRARIES})
get_filename_component(suffix ${lib} EXT)
# handle interfaces (e.g., SCOREC::apf)
if ("${lib}" MATCHES "SCOREC::.*")
elseif (NOT "${lib}" MATCHES "SCOREC::.*" AND "${lib}" MATCHES ".*::.*")
message(FATAL_ERROR "***** interface lib found ... exiting *****")
# handle static and shared libs
elseif ("${suffix}" STREQUAL "${CMAKE_SHARED_LIBRARY_SUFFIX}")
get_filename_component(dir ${lib} DIRECTORY)
get_filename_component(fullLibName ${lib} NAME_WE)
string(REGEX REPLACE "^lib" "" libname ${fullLibName})
set(MFEM_EXT_LIBS
"${MFEM_EXT_LIBS} ${shared_link_flag}${dir} -L${dir} -l${libname}")
else()
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${lib}")
endif()
endforeach()
# Create the build-tree version of 'config.mk'
configure_file(
"${PROJECT_SOURCE_DIR}/config/config.mk.in"
"${PROJECT_BINARY_DIR}/config/config.mk")
# Copy 'test.mk' from the source-tree to the build-tree
configure_file(
"${PROJECT_SOURCE_DIR}/config/test.mk"
"${PROJECT_BINARY_DIR}/config/test.mk" COPYONLY)
# Update variables for the install-tree version of 'config.mk'
set(MFEM_INC_DIR "${CMAKE_INSTALL_PREFIX}/include")
set(MFEM_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
set(MFEM_TEST_MK "${CMAKE_INSTALL_PREFIX}/share/mfem/test.mk")
set(MFEM_CONFIG_EXTRA "")
# Create the install-tree version of 'config.mk'
configure_file(
"${PROJECT_SOURCE_DIR}/config/config.mk.in"
"${PROJECT_BINARY_DIR}/config/config-install.mk")
# Install rules for 'config.mk' and 'test.mk'
install(FILES ${PROJECT_SOURCE_DIR}/config/test.mk
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mfem/)
install(FILES ${PROJECT_BINARY_DIR}/config/config-install.mk
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mfem/ RENAME config.mk)
endfunction()
+13 -19
View File
@@ -10,31 +10,19 @@
// Software Foundation) version 2.1 dated February 1999.
// Support out-of-source builds: if MFEM_CONFIG_FILE is defined, include it.
// Support out-of-source builds: if MFEM_BUILD_DIR is defined, load the config
// file MFEM_BUILD_DIR/config/_config.hpp.
//
// Otherwise, use the local file: _config.hpp.
#ifndef MFEM_CONFIG_HPP
#define MFEM_CONFIG_HPP
#ifdef MFEM_CONFIG_FILE
#include MFEM_CONFIG_FILE
#ifdef MFEM_BUILD_DIR
#define MFEM_QUOTE(a) #a
#define MFEM_MAKE_PATH(x,y) MFEM_QUOTE(x/y)
#include MFEM_MAKE_PATH(MFEM_BUILD_DIR,config/_config.hpp)
#else
#include "_config.hpp"
#endif
// Common configuration macros
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) || defined(__clang__)
#define MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
#endif
// Windows specific options
#ifdef _WIN32
// Macro needed to get defines like M_PI from <cmath>. (Visual Studio C++ only?)
#define _USE_MATH_DEFINES
#endif
// Check dependencies:
// Options that require MPI
@@ -53,4 +41,10 @@
#endif
#endif // MFEM_USE_MPI not defined
#endif // MFEM_CONFIG_HPP
// Macro that returns its first arg when MFEM_USE_BACKENDS is defined, and its
// second arg if it is not defined.
#ifdef MFEM_USE_BACKENDS
#define MFEM_IF_BACKENDS(x,y) x
#else
#define MFEM_IF_BACKENDS(x,y) y
#endif
+13 -18
View File
@@ -30,15 +30,15 @@
#define MFEM_VERSION_MINOR (((MFEM_VERSION)/100)%100)
#define MFEM_VERSION_PATCH ((MFEM_VERSION)%100)
// Description of the git commit used to build MFEM.
// #define MFEM_GIT_STRING "@MFEM_GIT_STRING@"
// The absolute path of the MFEM source prefix
// #define MFEM_SOURCE_DIR "@MFEM_SOURCE_DIR@"
// The absolute path of the MFEM installation prefix
// #define MFEM_INSTALL_DIR "@MFEM_INSTALL_DIR@"
// Description of the git commit used to build MFEM.
// #define MFEM_GIT_STRING "@MFEM_GIT_STRING@"
// Build the parallel MFEM library.
// Requires an MPI compiler, and the libraries HYPRE and METIS.
// #define MFEM_USE_MPI
@@ -68,12 +68,9 @@
// allocation and de-allocation.
// #define MFEM_THREAD_SAFE
// Enable the OpenMP backend.
// Enable experimental OpenMP support. Requires MFEM_THREAD_SAFE.
// #define MFEM_USE_OPENMP
// [Deprecated] Enable experimental OpenMP support. Requires MFEM_THREAD_SAFE.
// #define MFEM_USE_LEGACY_OPENMP
// Internal MFEM option: enable group/batch allocation for some small objects.
// #define MFEM_USE_MEMALLOC
@@ -121,20 +118,18 @@
// Enable MFEM functionality based on the PUMI library
// #define MFEM_USE_PUMI
// Build the NVIDIA GPU/CUDA-enabled version of the MFEM library.
// Requires a CUDA compiler (nvcc).
// #define MFEM_USE_CUDA
// Enable the use of MFEM backends.
// #define MFEM_USE_BACKENDS
// Build the AMD GPU/HIP-enabled version of the MFEM library.
// Requires a HIP compiler (hipcc).
// #define MFEM_USE_HIP
// Enable functionality based on the RAJA library.
// #define MFEM_USE_RAJA
// Enable functionality based on the OCCA library.
// Enable the OCCA backend.
// #define MFEM_USE_OCCA
// Windows specific options
#ifdef _WIN32
// Macro needed to get defines like M_PI from <cmath>. (Visual Studio C++ only?)
#define _USE_MATH_DEFINES
#endif
// Version of HYPRE used for building MFEM.
// #define MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
+32 -38
View File
@@ -10,41 +10,38 @@
# Software Foundation) version 2.1 dated February 1999.
# Variables corresponding to defines in config.hpp (YES, NO, or value)
MFEM_VERSION = @MFEM_VERSION@
MFEM_VERSION_STRING = @MFEM_VERSION_STRING@
MFEM_SOURCE_DIR = @MFEM_SOURCE_DIR@
MFEM_INSTALL_DIR = @MFEM_INSTALL_DIR@
MFEM_GIT_STRING = @MFEM_GIT_STRING@
MFEM_USE_MPI = @MFEM_USE_MPI@
MFEM_USE_METIS = @MFEM_USE_METIS@
MFEM_USE_METIS_5 = @MFEM_USE_METIS_5@
MFEM_DEBUG = @MFEM_DEBUG@
MFEM_USE_EXCEPTIONS = @MFEM_USE_EXCEPTIONS@
MFEM_USE_GZSTREAM = @MFEM_USE_GZSTREAM@
MFEM_USE_LIBUNWIND = @MFEM_USE_LIBUNWIND@
MFEM_USE_LAPACK = @MFEM_USE_LAPACK@
MFEM_THREAD_SAFE = @MFEM_THREAD_SAFE@
MFEM_USE_LEGACY_OPENMP = @MFEM_USE_LEGACY_OPENMP@
MFEM_USE_OPENMP = @MFEM_USE_OPENMP@
MFEM_USE_MEMALLOC = @MFEM_USE_MEMALLOC@
MFEM_TIMER_TYPE = @MFEM_TIMER_TYPE@
MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
MFEM_USE_STRUMPACK = @MFEM_USE_STRUMPACK@
MFEM_USE_GECKO = @MFEM_USE_GECKO@
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
MFEM_USE_PUMI = @MFEM_USE_PUMI@
MFEM_USE_CUDA = @MFEM_USE_CUDA@
MFEM_USE_HIP = @MFEM_USE_HIP@
MFEM_USE_RAJA = @MFEM_USE_RAJA@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
MFEM_VERSION = @MFEM_VERSION@
MFEM_VERSION_STRING = @MFEM_VERSION_STRING@
MFEM_GIT_STRING = @MFEM_GIT_STRING@
MFEM_SOURCE_DIR = @MFEM_SOURCE_DIR@
MFEM_INSTALL_DIR = @MFEM_INSTALL_DIR@
MFEM_USE_MPI = @MFEM_USE_MPI@
MFEM_USE_METIS = @MFEM_USE_METIS@
MFEM_USE_METIS_5 = @MFEM_USE_METIS_5@
MFEM_DEBUG = @MFEM_DEBUG@
MFEM_USE_EXCEPTIONS = @MFEM_USE_EXCEPTIONS@
MFEM_USE_GZSTREAM = @MFEM_USE_GZSTREAM@
MFEM_USE_LIBUNWIND = @MFEM_USE_LIBUNWIND@
MFEM_USE_LAPACK = @MFEM_USE_LAPACK@
MFEM_THREAD_SAFE = @MFEM_THREAD_SAFE@
MFEM_USE_OPENMP = @MFEM_USE_OPENMP@
MFEM_USE_MEMALLOC = @MFEM_USE_MEMALLOC@
MFEM_TIMER_TYPE = @MFEM_TIMER_TYPE@
MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
MFEM_USE_STRUMPACK = @MFEM_USE_STRUMPACK@
MFEM_USE_GECKO = @MFEM_USE_GECKO@
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
MFEM_USE_PUMI = @MFEM_USE_PUMI@
MFEM_USE_BACKENDS = @MFEM_USE_BACKENDS@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
@@ -72,8 +69,5 @@ MFEM_MPIEXEC = @MFEM_MPIEXEC@
MFEM_MPIEXEC_NP = @MFEM_MPIEXEC_NP@
MFEM_MPI_NP = @MFEM_MPI_NP@
# The NVCC compiler cannot link with -x=cu
MFEM_LINK_FLAGS := $(filter-out -x=cu, $(MFEM_FLAGS))
# Optional extra configuration
@MFEM_CONFIG_EXTRA@
+5 -19
View File
@@ -26,8 +26,7 @@ option(MFEM_USE_GZSTREAM "Enable gzstream for compressed data streams." OFF)
option(MFEM_USE_LIBUNWIND "Enable backtrace for errors." OFF)
option(MFEM_USE_LAPACK "Enable LAPACK usage" OFF)
option(MFEM_THREAD_SAFE "Enable thread safety" OFF)
option(MFEM_USE_OPENMP "Enable the OpenMP backend" OFF)
option(MFEM_USE_LEGACY_OPENMP "Enable legacy OpenMP usage" OFF)
option(MFEM_USE_OPENMP "Enable OpenMP usage" OFF)
option(MFEM_USE_MEMALLOC "Enable the internal MEMALLOC option." ON)
option(MFEM_USE_SUNDIALS "Enable SUNDIALS usage" OFF)
option(MFEM_USE_MESQUITE "Enable MESQUITE usage" OFF)
@@ -42,11 +41,6 @@ option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
option(MFEM_USE_PUMI "Enable PUMI" OFF)
option(MFEM_USE_CUDA "Enable CUDA" OFF)
option(MFEM_USE_OCCA "Enable OCCA" OFF)
option(MFEM_USE_RAJA "Enable RAJA" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
# Allow a user to disable testing, examples, and/or miniapps at CONFIGURE TIME
# if they don't want/need them (e.g. if MFEM is "just a dependency" and all they
@@ -62,16 +56,13 @@ option(MFEM_ENABLE_MINIAPPS "Build all of the miniapps" OFF)
# set(CXX g++)
# set(MPICXX mpicxx)
# Set the target CUDA architecture
set(CUDA_ARCH "sm_60" CACHE STRING "Target CUDA architecture.")
set(MFEM_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# The *_DIR paths below will be the first place searched for the corresponding
# headers and library. If these fail, then standard cmake search is performed.
# Note: if the variables are already in the cache, they are not overwritten.
set(HYPRE_DIR "${MFEM_DIR}/../hypre/src/hypre" CACHE PATH
set(HYPRE_DIR "${MFEM_DIR}/../hypre-2.10.0b/src/hypre" CACHE PATH
"Path to the hypre library.")
# If hypre was compiled to depend on BLAS and LAPACK:
# set(HYPRE_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
@@ -81,7 +72,7 @@ set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library."
set(LIBUNWIND_DIR "" CACHE PATH "Path to Libunwind.")
set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-5.0.0/instdir" CACHE PATH
set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-3.0.0" CACHE PATH
"Path to the SUNDIALS library.")
# The following may be necessary, if SUNDIALS was built with KLU:
# set(SUNDIALS_REQUIRED_PACKAGES "SuiteSparse/KLU/AMD/BTF/COLAMD/config"
@@ -109,7 +100,6 @@ set(SuperLUDist_REQUIRED_PACKAGES "MPI" "BLAS" "ParMETIS" CACHE STRING
set(STRUMPACK_DIR "${MFEM_DIR}/../STRUMPACK-build" CACHE PATH
"Path to the STRUMPACK library.")
# STRUMPACK may also depend on "OpenMP", depending on how it was compiled.
# Starting with v2.2.0 of STRUMPACK, ParMETIS and Scotch are optional.
set(STRUMPACK_REQUIRED_PACKAGES "MPI" "MPI_Fortran" "ParMETIS" "METIS"
"ScaLAPACK" "Scotch/ptscotch/ptscotcherr/scotch/scotcherr" CACHE STRING
"Additional packages required by STRUMPACK.")
@@ -117,8 +107,7 @@ set(STRUMPACK_REQUIRED_PACKAGES "MPI" "MPI_Fortran" "ParMETIS" "METIS"
# set(STRUMPACK_REQUIRED_LIBRARIES "gfortran" "mpi_mpifh" CACHE STRING
# "Additional libraries required by STRUMPACK.")
# The Scotch library, required by STRUMPACK <= v2.1.0, optional in STRUMPACK >=
# v2.2.0.
# The Scotch library, required by STRUMPACK
set(Scotch_DIR "${MFEM_DIR}/../scotch_6.0.4" CACHE PATH
"Path to the Scotch and PT-Scotch libraries.")
set(Scotch_REQUIRED_PACKAGES "Threads" CACHE STRING
@@ -154,15 +143,12 @@ set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH
set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH "Path to the Axom library.")
# May need to add "Boost" as requirement.
set(Axom_REQUIRED_PACKAGES "Conduit/relay/blueprint" CACHE STRING
set(Axom_REQUIRED_PACKAGES "Conduit/relay" CACHE STRING
"Additional packages required by Axom.")
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
"Directory where PUMI is installed")
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(BLAS_INCLUDE_DIRS "" CACHE STRING "Path to BLAS headers.")
set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
+46 -89
View File
@@ -21,13 +21,8 @@ NOTMAC := $(subst Darwin,,$(shell uname -s))
CXX = g++
MPICXX = mpicxx
BASE_FLAGS = -std=c++11
OPTIM_FLAGS = -O3 $(BASE_FLAGS)
DEBUG_FLAGS = -g $(XCOMPILER)-Wall $(BASE_FLAGS)
# Prefixes for passing flags to the compiler and linker when using CXX or MPICXX
CXX_XCOMPILER =
CXX_XLINKER = -Wl,
OPTIM_FLAGS = -O3
DEBUG_FLAGS = -g -Wall
# Destination location of make install
# PREFIX = $(HOME)/mfem
@@ -38,49 +33,33 @@ INSTALL = /usr/bin/install
STATIC = YES
SHARED = NO
# CUDA configuration options
CUDA_CXX = nvcc
CUDA_ARCH = sm_60
CUDA_FLAGS = -x=cu --expt-extended-lambda -arch=$(CUDA_ARCH)
# Prefixes for passing flags to the host compiler and linker when using CUDA_CXX
CUDA_XCOMPILER = -Xcompiler=
CUDA_XLINKER = -Xlinker=
# HIP configuration options
HIP_CXX = hipcc
# The HIP_ARCH option specifies the AMD GPU processor, similar to CUDA_ARCH. For
# example: gfx600 (tahiti), gfx700 (kaveri), gfx701 (hawaii), gfx801 (carrizo),
# gfx900, gfx1010, etc.
HIP_ARCH = gfx900
HIP_FLAGS = --amdgpu-target=$(HIP_ARCH)
ifneq ($(NOTMAC),)
AR = ar
ARFLAGS = cruv
RANLIB = ranlib
PICFLAG = $(XCOMPILER)-fPIC
PICFLAG = -fPIC
SO_EXT = so
SO_VER = so.$(MFEM_VERSION_STRING)
BUILD_SOFLAGS = -shared $(XLINKER)-soname,libmfem.$(SO_VER)
BUILD_RPATH = $(XLINKER)-rpath,$(BUILD_REAL_DIR)
BUILD_SOFLAGS = -shared -Wl,-soname,libmfem.$(SO_VER)
BUILD_RPATH = -Wl,-rpath,$(BUILD_REAL_DIR)
INSTALL_SOFLAGS = $(BUILD_SOFLAGS)
INSTALL_RPATH = $(XLINKER)-rpath,@MFEM_LIB_DIR@
INSTALL_RPATH = -Wl,-rpath,@MFEM_LIB_DIR@
else
# Silence "has no symbols" warnings on Mac OS X
AR = ar
ARFLAGS = Scruv
RANLIB = ranlib -no_warning_for_no_symbols
PICFLAG = $(XCOMPILER)-fPIC
PICFLAG = -fPIC
SO_EXT = dylib
SO_VER = $(MFEM_VERSION_STRING).dylib
MAKE_SOFLAGS = $(XLINKER)-dylib,-install_name,$(1)/libmfem.$(SO_VER),\
MAKE_SOFLAGS = -Wl,-dylib,-install_name,$(1)/libmfem.$(SO_VER),\
-compatibility_version,$(MFEM_VERSION_STRING),\
-current_version,$(MFEM_VERSION_STRING),\
-undefined,dynamic_lookup
BUILD_SOFLAGS = $(subst $1 ,,$(call MAKE_SOFLAGS,$(BUILD_REAL_DIR)))
BUILD_RPATH = $(XLINKER)-undefined,dynamic_lookup
BUILD_RPATH = -Wl,-undefined,dynamic_lookup
INSTALL_SOFLAGS = $(subst $1 ,,$(call MAKE_SOFLAGS,$(MFEM_LIB_DIR)))
INSTALL_RPATH = $(XLINKER)-undefined,dynamic_lookup
INSTALL_RPATH = -Wl,-undefined,dynamic_lookup
endif
# Set CXXFLAGS to overwrite the default selection of DEBUG_FLAGS/OPTIM_FLAGS
@@ -103,36 +82,34 @@ MFEM_MPI_NP = 4
# config.hpp. The values below are the defaults for generating the actual values
# in config.mk and config.hpp.
MFEM_USE_MPI = NO
MFEM_USE_METIS = $(MFEM_USE_MPI)
MFEM_USE_METIS_5 = NO
MFEM_DEBUG = NO
MFEM_USE_EXCEPTIONS = NO
MFEM_USE_GZSTREAM = NO
MFEM_USE_LIBUNWIND = NO
MFEM_USE_LAPACK = NO
MFEM_THREAD_SAFE = NO
MFEM_USE_OPENMP = NO
MFEM_USE_LEGACY_OPENMP = NO
MFEM_USE_MEMALLOC = YES
MFEM_TIMER_TYPE = $(if $(NOTMAC),2,4)
MFEM_USE_SUNDIALS = NO
MFEM_USE_MESQUITE = NO
MFEM_USE_SUITESPARSE = NO
MFEM_USE_SUPERLU = NO
MFEM_USE_STRUMPACK = NO
MFEM_USE_GECKO = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
MFEM_USE_PUMI = NO
MFEM_USE_CUDA = NO
MFEM_USE_HIP = NO
MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_MPI = NO
# FIXME: add MFEM_USE_BACKENDS, MFEM_USE_OCCA to the CMake build system
MFEM_USE_BACKENDS = YES
MFEM_USE_OCCA = YES
MFEM_USE_METIS = $(MFEM_USE_MPI)
MFEM_USE_METIS_5 = NO
MFEM_DEBUG = NO
MFEM_USE_EXCEPTIONS = NO
MFEM_USE_GZSTREAM = NO
MFEM_USE_LIBUNWIND = NO
MFEM_USE_LAPACK = NO
MFEM_THREAD_SAFE = NO
MFEM_USE_OPENMP = NO
MFEM_USE_MEMALLOC = YES
MFEM_TIMER_TYPE = $(if $(NOTMAC),2,4)
MFEM_USE_SUNDIALS = NO
MFEM_USE_MESQUITE = NO
MFEM_USE_SUITESPARSE = NO
MFEM_USE_SUPERLU = NO
MFEM_USE_STRUMPACK = NO
MFEM_USE_GECKO = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
MFEM_USE_PUMI = NO
# Compile and link options for zlib.
ZLIB_DIR =
@@ -144,7 +121,7 @@ LIBUNWIND_OPT = -g
LIBUNWIND_LIB = $(if $(NOTMAC),-lunwind -ldl,)
# HYPRE library configuration (needed to build the parallel version)
HYPRE_DIR = @MFEM_DIR@/../hypre/src/hypre
HYPRE_DIR = @MFEM_DIR@/../hypre-2.10.0b/src/hypre
HYPRE_OPT = -I$(HYPRE_DIR)/include
HYPRE_LIB = -L$(HYPRE_DIR)/lib -lHYPRE
@@ -162,8 +139,6 @@ ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK),NONO)
else
# ParMETIS: currently needed by SuperLU or STRUMPACK. We assume that METIS 5
# (included with ParMETIS) is installed in the same location.
# Starting with STRUMPACK v2.2.0, ParMETIS is an optional dependency while
# METIS is still required.
METIS_DIR = @MFEM_DIR@/../parmetis-4.0.3
METIS_OPT = -I$(METIS_DIR)/include
METIS_LIB = -L$(METIS_DIR)/lib -lparmetis -lmetis
@@ -175,16 +150,16 @@ LAPACK_OPT =
LAPACK_LIB = $(if $(NOTMAC),-llapack -lblas,-framework Accelerate)
# OpenMP configuration
OPENMP_OPT = $(XCOMPILER)-fopenmp
OPENMP_OPT = -fopenmp
OPENMP_LIB =
# Used when MFEM_TIMER_TYPE = 2
POSIX_CLOCKS_LIB = -lrt
# SUNDIALS library configuration
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
SUNDIALS_DIR = @MFEM_DIR@/../sundials-3.0.0
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
SUNDIALS_LIB = -Wl,-rpath,$(SUNDIALS_DIR)/lib64 -L$(SUNDIALS_DIR)/lib64\
SUNDIALS_LIB = -Wl,-rpath,$(SUNDIALS_DIR)/lib -L$(SUNDIALS_DIR)/lib\
-lsundials_arkode -lsundials_cvode -lsundials_nvecserial -lsundials_kinsol
ifeq ($(MFEM_USE_MPI),YES)
@@ -209,10 +184,9 @@ SUITESPARSE_LIB = -Wl,-rpath,$(SUITESPARSE_DIR)/lib -L$(SUITESPARSE_DIR)/lib\
# SuperLU library configuration
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_5.1.0
SUPERLU_OPT = -I$(SUPERLU_DIR)/SRC
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib -lsuperlu_dist_5.1.0
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/SRC -L$(SUPERLU_DIR)/SRC -lsuperlu_dist
# SCOTCH library configuration (required by STRUMPACK <= v2.1.0, optional in
# STRUMPACK >= v2.2.0)
# SCOTCH library configuration (required by STRUMPACK)
SCOTCH_DIR = @MFEM_DIR@/../scotch_6.0.4
SCOTCH_OPT = -I$(SCOTCH_DIR)/include
SCOTCH_LIB = -L$(SCOTCH_DIR)/lib -lptscotch -lptscotcherr -lscotch -lscotcherr\
@@ -299,7 +273,7 @@ SIDRE_LIB = \
-Wl,-rpath,$(SIDRE_DIR)/lib -L$(SIDRE_DIR)/lib \
-Wl,-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \
-Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \
-laxom -lconduit -lconduit_relay -lconduit_blueprint -lhdf5 $(ZLIB_LIB) -ldl
-lsidre -lslic -laxom_utils -lconduit -lconduit_relay -lhdf5 $(ZLIB_LIB) -ldl
# PUMI
# Note that PUMI_DIR is needed -- it is used to check for gmi_sim.h
@@ -308,26 +282,9 @@ PUMI_OPT = -I$(PUMI_DIR)/include
PUMI_LIB = -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf -lpcu -lgmi -lparma\
-llion -lmth -lapf_zoltan -lspr
# CUDA library configuration (currently not needed)
CUDA_OPT =
CUDA_LIB =
# HIP library configuration (currently not needed)
HIP_OPT =
HIP_LIB =
# OCCA library configuration
OCCA_DIR = @MFEM_DIR@/../occa
OCCA_OPT = -I$(OCCA_DIR)/include
OCCA_LIB = $(XLINKER)-rpath,$(OCCA_DIR)/lib -L$(OCCA_DIR)/lib -locca
# RAJA library configuration
RAJA_DIR = @MFEM_DIR@/../raja
RAJA_OPT = -I$(RAJA_DIR)/include
ifdef CUB_DIR
RAJA_OPT += -I$(CUB_DIR)
endif
RAJA_LIB = $(XLINKER)-rpath,$(RAJA_DIR)/lib -L$(RAJA_DIR)/lib -lRAJA
OCCA_LIB = -Wl,-rpath,$(OCCA_DIR)/lib -L$(OCCA_DIR)/lib -locca
# If YES, enable some informational messages
VERBOSE = NO
+1 -2
View File
@@ -36,7 +36,6 @@ CONFIG_MK = config.mk
all: header config-mk
MPI = $(MFEM_USE_MPI:NO=)
GHV_CXX ?= $(MFEM_CXX)
GHV = get_hypre_version
GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
@@ -45,7 +44,7 @@ SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
$(GHV): $(SRC)$(GHV).cpp
$(call mfem-info, Determining HYPRE version ...)
$(GHV_CXX) ${GHV_FLAGS} $(SRC)$(GHV).cpp -o $(GHV)
$(MFEM_CXX) ${GHV_FLAGS} $(SRC)$(GHV).cpp -o $(GHV)
$(GHV).out: $(GHV)
./$(GHV) > $(GHV).out
.INTERMEDIATE: $(GHV) $(GHV).out
+8 -35
View File
@@ -18,8 +18,6 @@ run_prefix=""
run_vg="valgrind --leak-check=full --show-reachable=yes --track-origins=yes"
run_suffix="-no-vis"
skip_gen_meshes="yes"
# filter-out device runs ("no") or non-device runs ("yes"):
device_runs="no"
cur_dir="${PWD}"
mfem_dir="$(cd "$(dirname "$0")"/.. && pwd)"
mfem_build_dir=""
@@ -32,7 +30,7 @@ groups_serial=(
'"examples"
"Examples:"
"examples"
"ex{,1,2}[0-9].cpp"'
"ex{,1}[0-9].cpp"'
# "ex1.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -46,15 +44,14 @@ groups_serial=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
mesh-optimizer.cpp"'
"mobius-strip.cpp klein-bottle.cpp mesh-optimizer.cpp"'
)
# Parallel groups
groups_parallel=(
'"examples"
"Examples:"
"examples"
"ex{,1,2}[0-9]p.cpp"'
"ex{,1}[0-9]p.cpp"'
# "ex1p.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -84,7 +81,7 @@ groups_all=(
'"examples"
"Examples:"
"examples"
"ex\"{,1,2}[0-9]\"{,p}.cpp"'
"ex\"{,1}[0-9]\"{,p}.cpp"'
'"sundials"
"SUNDIALS examples:"
"examples/sundials"
@@ -100,8 +97,7 @@ groups_all=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
{,p}mesh-optimizer.cpp"'
"mobius-strip.cpp klein-bottle.cpp {,p}mesh-optimizer.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
@@ -150,11 +146,6 @@ function extract_sample_runs()
if [ "$skip_gen_meshes" == "yes" ]; then
runs=`printf "%s" "$runs" | grep -v ".* -m .*\.gen"`
fi
if [ "$device_runs" == "yes" ]; then
runs=`printf "%s" "$runs" | grep ".* -d .*"`
else
runs=`printf "%s" "$runs" | grep -v ".* -d .*"`
fi
IFS=$'\n'
runs=(${runs})
IFS="${old_IFS}"
@@ -176,15 +167,9 @@ function help_message()
-g <dir> <pattern>
Specify explicitly a group (dir + file pattern) to run; This
option can be used multiple times to define multiple groups
-dev configure only sample runs using devices.
To test with a parallel build, the parallel (-p|-par) option
should be set first on the command line.
-v Enable valgrind
-o <dir> [${output_dir:-"<empty>: output goes to stdout"}]
If not empty, save output to files inside <dir>
-d <dir> [${mfem_build_dir}]
If <dir> is different from <mfem_dir> then use an
out-of-source build in <dir>
-j <np> [${make_j}] Specify the number of jobs to use for building
-c|-color Always use colors for the status messages: OK, FAILED, etc
-b|-built Do NOT rebuild the library and the executables
@@ -211,8 +196,8 @@ function help_message()
Their values can also set using the respective uppercase environment
variable
mfem_build_dir [${mfem_build_dir}]
Same as '-d': set this variable to something different from <mfem_dir>
to use an out-of-source build
Set this variable to something different from <mfem_dir> to use an
out-of-source build
For other valid variables, see the script source.
@@ -263,7 +248,7 @@ case "$1" in
-h|-help)
opt_help="yes"
;;
-p|-par)
-p|-parallel)
mfem_config="MFEM_USE_MPI=YES MFEM_DEBUG=NO"
;;
-g)
@@ -274,10 +259,6 @@ case "$1" in
groups=("${groups[@]}" "${test_group}")
shift 2
;;
-dev)
device_runs="yes"
mfem_config+=" MFEM_USE_CUDA=YES MFEM_USE_OCCA=YES MFEM_USE_RAJA=YES MFEM_USE_OPENMP=YES"
;;
-v)
valgrind="yes"
;;
@@ -285,10 +266,6 @@ case "$1" in
shift
output_dir="$1"
;;
-d)
shift
mfem_build_dir="$1"
;;
-j)
shift
make_j="-j $1"
@@ -308,10 +285,6 @@ case "$1" in
-n)
run_prefix="echo"
;;
-*)
echo "unknown option: '$1'"
exit 1
;;
*=*)
eval $1
;;
+3 -2
View File
@@ -43,14 +43,15 @@
#define MFEM_ALIGN_SIZE(size,type) \
MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type))
#ifdef MFEM_COUNT_FLOPS
namespace mfem
{
namespace internal
{
extern long long flop_count;
long long flop_count;
}
}
#ifdef MFEM_COUNT_FLOPS
#define MFEM_FLOPS_RESET() (mfem::internal::flop_count = 0)
#define MFEM_FLOPS_ADD(cnt) (mfem::internal::flop_count += (cnt))
#define MFEM_FLOPS_GET() (mfem::internal::flop_count)
+2 -3
View File
@@ -38,7 +38,7 @@ export TIME='%es %MkB %x'; \
set -- $$($(1) $(SHELL) -c "$(2)" 2>&1); while [ "$$#" -gt 3 ]; do shift; done
endef
define TIMECMD.NOTGNU
set -- $$($(1) -l $(SHELL) -c "{ $(2); } > /dev/null 2>&1" 2>&1; echo $$?); \
set -- $$($(1) -l $(SHELL) -c "$(2)" 2>&1; echo $$?); \
set -- "$$1"s "$$(($$7/1024))"kB "$${60}"
endef
define TIMECMD.BASH
@@ -60,8 +60,7 @@ endif
# Test runs of the examples/miniapps with parameters - check exit code
mfem-test = \
printf " $(3) [$(2) $(1) ... ]: "; \
$(call $(TIMEFUN),$(TIMECMD),$(2) ./$(1) $(if $(5),,-no-vis )$(4) \
> $(1).stderr 2>&1); \
$(call $(TIMEFUN),$(TIMECMD),$(2) ./$(1) -no-vis $(4) > $(1).stderr 2>&1); \
if [ "$$3" = 0 ]; \
then $(PRINT_OK); else $(PRINT_FAILED); cat $(1).stderr; fi; \
rm -f $(1).stderr; exit $$3
-87
View File
@@ -1,87 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
8
1 6 0 9 18 1 10 19
1 6 1 10 19 2 11 20
1 6 2 11 20 3 12 21
1 6 3 12 21 4 13 22
2 6 4 13 22 5 14 23
2 6 5 14 23 6 15 24
2 6 6 15 24 7 16 25
2 6 7 16 25 8 17 26
boundary
26
1 2 0 18 9
2 2 8 17 26
3 3 0 9 10 1
3 3 1 10 11 2
3 3 2 11 12 3
3 3 3 12 13 4
3 3 4 13 14 5
3 3 5 14 15 6
3 3 6 15 16 7
3 3 7 16 17 8
3 3 18 0 1 19
3 3 19 1 2 20
3 3 20 2 3 21
3 3 21 3 4 22
3 3 22 4 5 23
3 3 23 5 6 24
3 3 24 6 7 25
3 3 25 7 8 26
3 3 9 18 19 10
3 3 10 19 20 11
3 3 11 20 21 12
3 3 12 21 22 13
3 3 13 22 23 14
3 3 14 23 24 15
3 3 15 24 25 16
3 3 16 25 26 17
vertices
27
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.5 1
1 0.5 1
2 0.5 1
3 0.5 1
4 0.5 1
5 0.5 1
6 0.5 1
7 0.5 1
8 0.5 1
-61
View File
@@ -1,61 +0,0 @@
# vtk DataFile Version 3.0
Generated by MFEM
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 27 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.5 1
1 0.5 1
2 0.5 1
3 0.5 1
4 0.5 1
5 0.5 1
6 0.5 1
7 0.5 1
8 0.5 1
CELLS 8 56
6 0 9 18 1 10 19
6 1 10 19 2 11 20
6 2 11 20 3 12 21
6 3 12 21 4 13 22
6 4 13 22 5 14 23
6 5 14 23 6 15 24
6 6 15 24 7 16 25
6 7 16 25 8 17 26
CELL_TYPES 8
13
13
13
13
13
13
13
13
CELL_DATA 8
SCALARS material int
LOOKUP_TABLE default
1
1
1
1
2
2
2
2
-192
View File
@@ -1,192 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
14
1 4 13 15 21 25
1 4 15 13 21 12
1 4 21 13 25 22
1 4 15 21 25 24
1 4 13 15 25 16
1 5 0 1 4 3 9 10 13 12
1 5 8 9 12 11 17 18 21 20
1 5 2 3 6 5 11 12 15 14
1 6 3 4 6 12 13 15
1 6 4 7 6 13 16 15
1 6 12 13 21 9 10 18
1 6 13 22 21 10 19 18
1 6 11 14 20 12 15 21
1 6 15 21 24 14 20 23
boundary
30
1 3 5 6 3 2
2 2 6 4 3
2 2 4 6 7
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 2 10 18 9
7 2 18 10 19
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 2 25 13 16
11 2 13 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 2 15 25 16
16 2 25 15 24
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 2 20 14 11
20 2 14 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 2 25 21 22
23 2 21 25 24
24 3 20 21 24 23
vertices
26
nodes
FiniteElementSpace
FiniteElementCollection: H1_3D_P2
VDim: 3
Ordering: 1
0.028213666146621 -1.0129124616273 -1.0197422793601
0.99151103207842 -0.97408353323117 -1.0219424221199
-0.98628834960982 -0.048291393648833 -1.0334530425724
-0.045286384224892 -0.028259630873799 -0.95961592583917
1.0351351283956 0.016103611653671 -1.0465984194074
-0.97963495329022 0.975340601895 -0.95050375238061
-0.016565482225269 0.98394050155766 -1.0119900547434
0.98232264800655 1.0061312792241 -0.97468885016611
-1.0111163694877 -1.0328216757625 -0.033904406474903
-0.031359497737139 -0.95907832225785 -0.02936147605069
1.0216721775476 -0.95571139678359 -0.041445003869012
-0.96617995956913 0.013420177670196 -0.047073400672525
0.03735491973348 0.024136644229293 -0.035419858060777
0.99844568660483 -0.023344853520393 0.043047091318294
-1.0075354852248 0.95110015915707 0.040374961402267
-0.018023004801944 0.98735854397528 0.035048884851858
0.96496833880778 0.98624407089765 0.029059857856424
-0.95618249163963 -0.95913625303656 0.99699592567049
0.010523111699149 -1.0380611987319 1.0054330066312
1.0131589291349 -0.99133288586241 1.0510169859154
-0.9992929702159 -0.016950021823868 1.0209834648762
-0.030905270343646 -0.024878516234457 0.96677784407511
1.0369556044533 0.036727200814101 0.97476146325791
-1.0268666699025 0.99100244478387 0.95557046163574
0.032850918109418 0.9761234538078 0.99340013005027
0.96517252528448 1.018590816239 0.96241486393546
0.52641251369336 0.53453492783232 -0.046831832639522
0.54842095679127 0.012466884090474 0.52264325135947
1.0546647359835 0.51503200008771 0.47661895657821
0.008193729444779 0.46320342579585 0.51330736048101
0.48446121998846 1.0366433051979 0.46910527980021
0.50338134740858 0.53372671722279 1.0016026703109
-0.0026805294677615 0.54834160562605 -0.022633473388851
0.4992129677441 -0.027650739811361 -0.025983834639192
-0.010308592952788 0.043478553090245 0.54404251929373
0.52373361142037 0.017260625417003 1.0190168930687
0.95156254112601 0.024917951411289 0.48927665714905
1.0114961385777 0.53988309084877 0.98077339629239
0.01429600397056 1.0255897320394 0.44945099394948
-0.0037663174125072 0.46114195337251 0.98693741812483
0.53955416269275 0.95254191223583 0.99345054396648
1.0344137934711 0.51549308419917 0.0019079259000746
0.4635900873147 1.0074141174823 -0.025796540646941
1.0393698821347 0.99823230649269 0.53561992818844
0.54910938213579 -1.0186136680655 -1.0399189315271
0.98251790353097 -0.52159510049969 -1.0488538759761
0.51290647936985 0.019199261348695 -1.0180139709264
0.039190890220925 -0.51870735888369 -1.0145805133507
0.54531239252537 -1.0346180800814 -0.026071808021516
1.0111227696296 -0.45961035727523 0.028725982550532
-0.0024106570985168 -0.51591348233633 0.042102640075609
0.019072471559048 -1.0489699664991 -0.53822694290429
1.0197706996463 -1.0138504981995 -0.48532295548357
0.97708769380115 0.012869927892461 -0.49512141938321
-0.0056951441802084 -0.018287890031934 -0.46456751856022
-0.48628377295099 -0.97137148869224 -0.040609835088253
-0.52949825478718 0.022831952339038 0.036623532185331
-0.9682938832324 -0.51529484749772 0.039498377451673
-0.45076946932822 -0.98247022288851 1.0229644412175
-0.036635886738077 -0.53934830226935 0.97308384231292
-0.47986206617206 -0.041745604947209 0.98161771683954
-0.95103283049539 -0.5087813614402 1.0116585971788
-0.95395673410967 -0.95082942959853 0.50977751370519
0.030673310998827 -0.97366141136736 0.47265974627808
-1.0076441270299 0.025157339498401 0.51940553779714
-0.45112570035271 0.030354945734143 -1.0244264173787
-0.034796683816239 0.47213521944359 -1.0233666383661
-0.52309081116691 1.0127369282767 -1.030445962213
-1.0052867605351 0.54541603662074 -0.99267176855355
-0.53441363093443 1.0101050069556 0.034852372528985
-1.0361742412671 0.51952713127248 -0.0075041593052447
-1.0224051106721 0.037305149668828 -0.51234883274883
-0.0468317149207 0.99936735257506 -0.53290488454513
-1.0323944162577 1.0470460939221 -0.49629869163036
0.50827771586097 0.51091354087276 -0.96143114171132
0.97860428203942 0.53881222049291 -1.0227558970328
0.54899092558423 1.0449853148062 -1.0290394971016
0.98149990118493 1.0265442789565 -0.45402792714566
0.47938502309767 -0.95321110021154 0.46438798044786
0.98893120098231 -1.0252040218394 0.52866776747387
0.46061993861414 -0.973998097143 0.95264651015888
0.98858339184873 -0.49578777734639 0.97955980177082
-0.95322811676761 0.49312524158842 0.46350421594559
-0.9670648949319 0.52720408663568 1.0147400701319
-0.95970724064157 0.9966338243727 0.47198853459547
-0.55076990539437 0.95548113087191 1.0002298586837
0.48237521727569 -0.51972299404442 -0.98436066769063
0.45025863721967 -1.0030842470471 -0.53693975312635
0.95356930759735 -0.4606471833773 -0.49721032292582
0.48610299886204 0.033102156873792 -0.45204877182841
0.016292646434158 -0.4694908623118 -0.53292224425822
0.47584088565782 -0.54223454683088 -0.036028525792062
-0.53143287785351 -0.4923779387027 0.0039846746250987
-0.52957315347157 -1.0359902368858 0.51208876920864
-0.024055424472317 -0.49951890320517 0.48579422575422
-0.45644746879116 -0.012607240816578 0.51010388839059
-0.98394734906033 -0.50309513998218 0.47998268660158
-0.53098605261184 -0.48258609846234 0.97544367099181
-0.51822144156322 0.45223189569078 -1.0385291075334
-0.45871022404172 -0.042734754644334 -0.54302125046961
0.041843411838636 0.46222349074669 -0.5097909247037
-0.45607118047774 1.0116704457439 -0.45481789885089
-1.0244252419565 0.4849586374592 -0.50017994958907
-0.52441235366277 0.50157218999229 0.023797604069114
0.46467856940869 0.54693057615002 -0.46251054922067
0.98669286111723 0.51824862516758 -0.45168929326637
0.54790127868275 0.98589193659248 -0.51421705686245
0.54233705943277 -0.4508773840935 0.45025142266283
1.0203662623874 -0.5304726794563 0.52365051237419
0.48446453821555 -0.47976663671026 1.043945324572
-0.48793381256969 0.50247088679532 0.48323828733422
-0.52670996575095 0.50194146344506 1.0026980744777
-0.47523256142428 0.97748358070477 0.48234451559035
0.45616661459208 -0.50770850274712 -0.4568053398747
-0.52734654471278 -0.51337681044824 0.47594708297402
-0.45737625267357 0.47732204026543 -0.54846904515289
-168
View File
@@ -1,168 +0,0 @@
# vtk DataFile Version 3.0
Generated by MFEM
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 116 double
0.028213666146621 -1.0129124616273 -1.0197422793601
0.99151103207842 -0.97408353323117 -1.0219424221199
-0.98628834960982 -0.048291393648833 -1.0334530425724
-0.045286384224892 -0.028259630873799 -0.95961592583917
1.0351351283956 0.016103611653671 -1.0465984194074
-0.97963495329022 0.975340601895 -0.95050375238061
-0.016565482225269 0.98394050155766 -1.0119900547434
0.98232264800655 1.0061312792241 -0.97468885016611
-1.0111163694877 -1.0328216757625 -0.033904406474903
-0.031359497737139 -0.95907832225785 -0.02936147605069
1.0216721775476 -0.95571139678359 -0.041445003869012
-0.96617995956913 0.013420177670196 -0.047073400672525
0.03735491973348 0.024136644229293 -0.035419858060777
0.99844568660483 -0.023344853520393 0.043047091318294
-1.0075354852248 0.95110015915707 0.040374961402267
-0.018023004801944 0.98735854397528 0.035048884851858
0.96496833880778 0.98624407089765 0.029059857856424
-0.95618249163963 -0.95913625303656 0.99699592567049
0.010523111699149 -1.0380611987319 1.0054330066312
1.0131589291349 -0.99133288586241 1.0510169859154
-0.9992929702159 -0.016950021823868 1.0209834648762
-0.030905270343646 -0.024878516234457 0.96677784407511
1.0369556044533 0.036727200814101 0.97476146325791
-1.0268666699025 0.99100244478387 0.95557046163574
0.032850918109418 0.9761234538078 0.99340013005027
0.96517252528448 1.018590816239 0.96241486393546
0.50338134740858 0.53372671722279 1.0016026703109
0.54842095679127 0.012466884090474 0.52264325135947
0.008193729444779 0.46320342579585 0.51330736048101
1.0546647359835 0.51503200008771 0.47661895657821
0.48446121998846 1.0366433051979 0.46910527980021
0.52641251369336 0.53453492783232 -0.046831832639522
-0.0026805294677615 0.54834160562605 -0.022633473388851
0.4992129677441 -0.027650739811361 -0.025983834639192
-0.010308592952788 0.043478553090245 0.54404251929373
1.0114961385777 0.53988309084877 0.98077339629239
0.52373361142037 0.017260625417003 1.0190168930687
0.95156254112601 0.024917951411289 0.48927665714905
-0.0037663174125072 0.46114195337251 0.98693741812483
0.53955416269275 0.95254191223583 0.99345054396648
0.01429600397056 1.0255897320394 0.44945099394948
1.0344137934711 0.51549308419917 0.0019079259000746
0.4635900873147 1.0074141174823 -0.025796540646941
1.0393698821347 0.99823230649269 0.53561992818844
0.54910938213579 -1.0186136680655 -1.0399189315271
0.98251790353097 -0.52159510049969 -1.0488538759761
0.51290647936985 0.019199261348695 -1.0180139709264
0.039190890220925 -0.51870735888369 -1.0145805133507
0.54531239252537 -1.0346180800814 -0.026071808021516
1.0111227696296 -0.45961035727523 0.028725982550532
-0.0024106570985168 -0.51591348233633 0.042102640075609
0.019072471559048 -1.0489699664991 -0.53822694290429
1.0197706996463 -1.0138504981995 -0.48532295548357
0.97708769380115 0.012869927892461 -0.49512141938321
-0.0056951441802084 -0.018287890031934 -0.46456751856022
-0.48628377295099 -0.97137148869224 -0.040609835088253
-0.52949825478718 0.022831952339038 0.036623532185331
-0.9682938832324 -0.51529484749772 0.039498377451673
-0.45076946932822 -0.98247022288851 1.0229644412175
-0.036635886738077 -0.53934830226935 0.97308384231292
-0.47986206617206 -0.041745604947209 0.98161771683954
-0.95103283049539 -0.5087813614402 1.0116585971788
-0.95395673410967 -0.95082942959853 0.50977751370519
0.030673310998827 -0.97366141136736 0.47265974627808
-1.0076441270299 0.025157339498401 0.51940553779714
-0.45112570035271 0.030354945734143 -1.0244264173787
-0.034796683816239 0.47213521944359 -1.0233666383661
-0.52309081116691 1.0127369282767 -1.030445962213
-1.0052867605351 0.54541603662074 -0.99267176855355
-0.53441363093443 1.0101050069556 0.034852372528985
-1.0361742412671 0.51952713127248 -0.0075041593052447
-1.0224051106721 0.037305149668828 -0.51234883274883
-0.0468317149207 0.99936735257506 -0.53290488454513
-1.0323944162577 1.0470460939221 -0.49629869163036
0.50827771586097 0.51091354087276 -0.96143114171132
0.97860428203942 0.53881222049291 -1.0227558970328
0.54899092558423 1.0449853148062 -1.0290394971016
0.98149990118493 1.0265442789565 -0.45402792714566
0.47938502309767 -0.95321110021154 0.46438798044786
0.98893120098231 -1.0252040218394 0.52866776747387
0.46061993861414 -0.973998097143 0.95264651015888
0.98858339184873 -0.49578777734639 0.97955980177082
-0.95322811676761 0.49312524158842 0.46350421594559
-0.9670648949319 0.52720408663568 1.0147400701319
-0.95970724064157 0.9966338243727 0.47198853459547
-0.55076990539437 0.95548113087191 1.0002298586837
0.48237521727569 -0.51972299404442 -0.98436066769063
0.45025863721967 -1.0030842470471 -0.53693975312635
0.95356930759735 -0.4606471833773 -0.49721032292582
0.48610299886204 0.033102156873792 -0.45204877182841
0.016292646434158 -0.4694908623118 -0.53292224425822
0.47584088565782 -0.54223454683088 -0.036028525792062
-0.53143287785351 -0.4923779387027 0.0039846746250987
-0.52957315347157 -1.0359902368858 0.51208876920864
-0.024055424472317 -0.49951890320517 0.48579422575422
-0.45644746879116 -0.012607240816578 0.51010388839059
-0.98394734906033 -0.50309513998218 0.47998268660158
-0.53098605261184 -0.48258609846234 0.97544367099181
-0.51822144156322 0.45223189569078 -1.0385291075334
-0.45871022404172 -0.042734754644334 -0.54302125046961
0.041843411838636 0.46222349074669 -0.5097909247037
-0.45607118047774 1.0116704457439 -0.45481789885089
-1.0244252419565 0.4849586374592 -0.50017994958907
-0.52441235366277 0.50157218999229 0.023797604069114
0.46467856940869 0.54693057615002 -0.46251054922067
0.98669286111723 0.51824862516758 -0.45168929326637
0.54790127868275 0.98589193659248 -0.51421705686245
0.54233705943277 -0.4508773840935 0.45025142266283
1.0203662623874 -0.5304726794563 0.52365051237419
0.48446453821555 -0.47976663671026 1.043945324572
-0.48793381256969 0.50247088679532 0.48323828733422
-0.52670996575095 0.50194146344506 1.0026980744777
-0.47523256142428 0.97748358070477 0.48234451559035
0.45616661459208 -0.50770850274712 -0.4568053398747
-0.52734654471278 -0.51337681044824 0.47594708297402
-0.45737625267357 0.47732204026543 -0.54846904515289
CELLS 14 253
10 21 25 13 15 26 29 27 28 30 31
10 15 13 21 12 31 27 28 32 33 34
10 25 21 13 22 26 27 29 35 36 37
10 21 25 15 24 26 30 28 38 39 40
10 13 15 25 16 31 30 29 41 42 43
27 0 1 4 3 9 10 13 12 44 45 46 47 48 49 33 50 51 52 53 54 90 88 87 89 86 91 113
27 8 9 12 11 17 18 21 20 55 50 56 57 58 59 60 61 62 63 34 64 96 94 93 95 92 97 114
27 2 3 6 5 11 12 15 14 65 66 67 68 56 32 69 70 71 54 72 73 102 100 99 101 98 103 115
18 3 6 4 12 15 13 66 74 46 32 31 33 54 72 53 100 104 89
18 4 6 7 13 15 16 74 76 75 31 42 41 53 72 77 104 106 105
18 12 21 13 9 18 10 34 27 33 63 78 48 50 59 49 94 107 91
18 13 21 22 10 18 19 27 36 37 78 80 79 49 59 81 107 109 108
18 11 20 14 12 21 15 64 82 70 34 28 32 56 60 69 95 110 103
18 15 24 21 14 23 20 40 38 28 84 83 82 69 85 60 112 111 110
CELL_TYPES 14
24
24
24
24
24
29
29
29
32
32
32
32
32
32
CELL_DATA 14
SCALARS material int
LOOKUP_TABLE default
1
1
1
1
1
1
1
1
1
1
1
1
1
1
-96
View File
@@ -1,96 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
14
1 4 13 15 21 25
1 4 12 13 15 21
1 4 13 21 22 25
1 4 15 24 21 25
1 4 13 15 25 16
1 5 0 1 4 3 9 10 13 12
1 5 8 9 12 11 17 18 21 20
1 5 2 3 6 5 11 12 15 14
1 6 3 4 6 12 13 15
1 6 4 7 6 13 16 15
1 6 12 13 21 9 10 18
1 6 13 22 21 10 19 18
1 6 11 14 20 12 15 21
1 6 15 21 24 14 20 23
boundary
30
1 3 5 6 3 2
2 2 3 6 4
2 2 4 6 7
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 2 9 10 18
7 2 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 2 13 16 25
11 2 13 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 2 16 15 25
16 2 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 2 11 20 14
20 2 14 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 2 21 22 25
23 2 21 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
+3 -3
View File
@@ -19,10 +19,10 @@ elements
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 11 12 15 14 20 21 24 23
1 5 12 13 16 15 21 22 25 24
1 5 9 10 13 12 18 19 22 21
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
-9
View File
@@ -1,9 +0,0 @@
MFEM INLINE mesh v1.0
type = wedge
nx = 4
ny = 4
nz = 4
sx = 1.0
sy = 1.0
sz = 1.0
-182
View File
@@ -1,182 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
30
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 2 1 26 11
1 2 26 1 12
1 3 26 12 3 13
1 2 2 26 13
1 2 26 2 14
1 2 2 27 14
1 2 27 2 15
1 3 27 15 5 16
1 2 4 27 16
1 2 27 4 17
1 2 4 28 17
1 2 28 4 18
1 3 28 18 7 19
1 2 6 28 19
1 2 28 6 20
1 2 6 29 20
1 2 29 6 21
1 3 29 21 9 22
1 2 8 29 22
1 2 29 8 23
1 2 8 30 23
1 2 30 8 24
1 3 30 24 10 25
1 2 1 30 25
1 2 30 1 11
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
nodes
FiniteElementSpace
FiniteElementCollection: H1_2D_P2
VDim: 2
Ordering: 1
0.01350768617383 -0.0075500592639684
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.4935497789318 -0.012882964767041
1.15451 0.475529
0.809019 0.951057
0.17136163619581 0.48175756223348
-0.0954915 1.24495
-0.654508 1.06331
-0.41734925397369 0.28726550311701
-1.21352 0.293893
-1.21352 -0.293892
-0.39460365124056 -0.30156877530663
-0.654508 -1.06331
-0.0954915 -1.24495
0.14399901886801 -0.48762042397771
0.809019 -0.951057
1.15451 -0.475529
0.6498356311584 0.48434918539882
-0.24288407581812 0.75594729997554
-0.8152592767797 0.0028387384025541
-0.22754482186326 -0.77540708661379
0.672255499984 -0.48174474211839
0.22829595615988 0.0021164169942289
0.60101450815825 0.21860266792331
0.41883194868682 0.47605389684094
0.07343165966527 0.21396989328966
-0.02571592547416 0.63942139993498
-0.32229829912758 0.53827901417123
-0.17873676879185 0.14412581843398
-0.6182337454462 0.14256917811499
-0.59596471744054 -0.16569961862581
-0.19439899436461 -0.12390276596268
-0.33986575323528 -0.53331120777067
-0.064647379830725 -0.60235938684263
0.091924539036435 -0.25440885597942
0.40469418107844 -0.47549896605132
0.59442400974309 -0.23815570080881
0.83567929699787 0.25605757828544
0.73491944894413 -0.013500778246483
1.077255 0.2377645
0.88696375569985 0.49133008726061
1.231765 0.713293
1.0590195 0.951057
0.72725653289275 0.73104100472096
0.50225974659165 0.6904536152084
0.559018 0.951057
0.23657516510421 0.69857072686934
0.011561493903121 0.87524541641085
0.10676275 1.0980035
-0.17127243181091 0.99863326833074
-0.29774575 1.391895
-0.577254 1.301075
-0.45323351407757 0.93490604288187
-0.55200861955087 0.66792304985565
-0.7317625 0.8255475
-0.58327877079184 0.4240660861124
-0.81465656906104 0.28713104760848
-1.0112685 0.440839
-0.99771272279525 0.1592736885552
-1.415775 0.1469465
-1.415775 -0.146946
-1.0166887889241 -0.16866723370018
-0.80412516287867 -0.29582734656
-1.0112685 -0.4408385
-0.6073309356422 -0.45826153759998
-0.55501395481483 -0.68914767547246
-0.7317625 -0.8255475
-0.45240617124569 -0.93833106759189
-0.577254 -1.301075
-0.29774575 -1.391895
-0.1923419715726 -1.0285844005569
0.031614306262131 -0.83601077226744
0.10676275 -1.0980035
0.22112358843745 -0.69009711121629
0.50046759811715 -0.72837571286759
0.559018 -0.951057
0.71074483315985 -0.70826931724532
1.0590195 -0.951057
1.231765 -0.713293
0.89135027612826 -0.46226040977064
0.84948897506491 -0.23986695857234
1.077255 -0.2377645
0.31586449185434 0.2462788698702
-0.13788918217579 0.40149150514309
-0.40416548945856 0.0027692745957735
-0.14861804521337 -0.3698676302047
0.33007376541085 -0.24598293851351
0.99473757603443 0.69214841080247
-0.38122249894249 1.1629329119286
-1.208195003484 -0.0026998371675556
-0.35890854853443 -1.1361244276705
0.9901912195942 -0.73640851058427
-201
View File
@@ -1,201 +0,0 @@
# vtk DataFile Version 3.0
Generated by MFEM
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 101 double
0.01350768617383 -0.0075500592639684 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.4935497789318 -0.012882964767041 0
1.15451 0.475529 0
0.809019 0.951057 0
0.17136163619581 0.48175756223348 0
-0.0954915 1.24495 0
-0.654508 1.06331 0
-0.41734925397369 0.28726550311701 0
-1.21352 0.293893 0
-1.21352 -0.293892 0
-0.39460365124056 -0.30156877530663 0
-0.654508 -1.06331 0
-0.0954915 -1.24495 0
0.14399901886801 -0.48762042397771 0
0.809019 -0.951057 0
1.15451 -0.475529 0
0.6498356311584 0.48434918539882 0
-0.24288407581812 0.75594729997554 0
-0.8152592767797 0.0028387384025541 0
-0.22754482186326 -0.77540708661379 0
0.672255499984 -0.48174474211839 0
0.22829595615988 0.0021164169942289 0
0.60101450815825 0.21860266792331 0
0.41883194868682 0.47605389684094 0
0.07343165966527 0.21396989328966 0
-0.02571592547416 0.63942139993498 0
-0.32229829912758 0.53827901417123 0
-0.17873676879185 0.14412581843398 0
-0.6182337454462 0.14256917811499 0
-0.59596471744054 -0.16569961862581 0
-0.19439899436461 -0.12390276596268 0
-0.33986575323528 -0.53331120777067 0
-0.064647379830725 -0.60235938684263 0
0.091924539036435 -0.25440885597942 0
0.40469418107844 -0.47549896605132 0
0.59442400974309 -0.23815570080881 0
0.83567929699787 0.25605757828544 0
0.73491944894413 -0.013500778246483 0
1.077255 0.2377645 0
0.88696375569985 0.49133008726061 0
1.231765 0.713293 0
1.0590195 0.951057 0
0.72725653289275 0.73104100472096 0
0.50225974659165 0.6904536152084 0
0.559018 0.951057 0
0.23657516510421 0.69857072686934 0
0.011561493903121 0.87524541641085 0
0.10676275 1.0980035 0
-0.17127243181091 0.99863326833074 0
-0.29774575 1.391895 0
-0.577254 1.301075 0
-0.45323351407757 0.93490604288187 0
-0.55200861955087 0.66792304985565 0
-0.7317625 0.8255475 0
-0.58327877079184 0.4240660861124 0
-0.81465656906104 0.28713104760848 0
-1.0112685 0.440839 0
-0.99771272279525 0.1592736885552 0
-1.415775 0.1469465 0
-1.415775 -0.146946 0
-1.0166887889241 -0.16866723370018 0
-0.80412516287867 -0.29582734656 0
-1.0112685 -0.4408385 0
-0.6073309356422 -0.45826153759998 0
-0.55501395481483 -0.68914767547246 0
-0.7317625 -0.8255475 0
-0.45240617124569 -0.93833106759189 0
-0.577254 -1.301075 0
-0.29774575 -1.391895 0
-0.1923419715726 -1.0285844005569 0
0.031614306262131 -0.83601077226744 0
0.10676275 -1.0980035 0
0.22112358843745 -0.69009711121629 0
0.50046759811715 -0.72837571286759 0
0.559018 -0.951057 0
0.71074483315985 -0.70826931724532 0
1.0590195 -0.951057 0
1.231765 -0.713293 0
0.89135027612826 -0.46226040977064 0
0.84948897506491 -0.23986695857234 0
1.077255 -0.2377645 0
0.31586449185434 0.2462788698702 0
-0.13788918217579 0.40149150514309 0
-0.40416548945856 0.0027692745957735 0
-0.14861804521337 -0.3698676302047 0
0.33007376541085 -0.24598293851351 0
0.99473757603443 0.69214841080247 0
-0.38122249894249 1.1629329119286 0
-1.208195003484 -0.0026998371675556 0
-0.35890854853443 -1.1361244276705 0
0.9901912195942 -0.73640851058427 0
CELLS 30 240
9 0 11 26 14 31 32 33 34 91
9 0 14 27 17 34 35 36 37 92
9 0 17 28 20 37 38 39 40 93
9 0 20 29 23 40 41 42 43 94
9 0 23 30 11 43 44 45 31 95
6 1 26 11 46 32 47
6 26 1 12 46 48 49
9 26 12 3 13 49 50 51 52 96
6 2 26 13 53 52 54
6 26 2 14 53 55 33
6 2 27 14 56 35 55
6 27 2 15 56 57 58
9 27 15 5 16 58 59 60 61 97
6 4 27 16 62 61 63
6 27 4 17 62 64 36
6 4 28 17 65 38 64
6 28 4 18 65 66 67
9 28 18 7 19 67 68 69 70 98
6 6 28 19 71 70 72
6 28 6 20 71 73 39
6 6 29 20 74 41 73
6 29 6 21 74 75 76
9 29 21 9 22 76 77 78 79 99
6 8 29 22 80 79 81
6 29 8 23 80 82 42
6 8 30 23 83 44 82
6 30 8 24 83 84 85
9 30 24 10 25 85 86 87 88 100
6 1 30 25 89 88 90
6 30 1 11 89 47 45
CELL_TYPES 30
28
28
28
28
28
22
22
28
22
22
22
22
28
22
22
22
22
28
22
22
22
22
28
22
22
22
22
28
22
22
CELL_DATA 30
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

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