Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
432df01647 |
@@ -175,7 +175,6 @@ miniapps/meshing/mesh-optimizer
|
||||
miniapps/meshing/pmesh-optimizer
|
||||
miniapps/meshing/minimal-surface
|
||||
miniapps/meshing/pminimal-surface
|
||||
miniapps/meshing/polar-nc
|
||||
|
||||
miniapps/meshing/mobius-strip.mesh
|
||||
miniapps/meshing/klein-bottle.mesh
|
||||
@@ -188,7 +187,6 @@ miniapps/meshing/extruder.mesh
|
||||
miniapps/meshing/trimmer.mesh
|
||||
miniapps/meshing/optimized*
|
||||
miniapps/meshing/perturbed*
|
||||
miniapps/meshing/polar-nc.mesh
|
||||
|
||||
miniapps/performance/ex1
|
||||
miniapps/performance/ex1p
|
||||
@@ -235,7 +233,6 @@ miniapps/nurbs/mode_*
|
||||
miniapps/nurbs/Example1*
|
||||
|
||||
miniapps/gslib/field-diff
|
||||
miniapps/gslib/field-interp
|
||||
miniapps/gslib/findpts
|
||||
miniapps/gslib/pfindpts
|
||||
|
||||
@@ -262,10 +259,5 @@ tests/scripts/*.err
|
||||
tests/scripts/*.out
|
||||
tests/scripts/*.msg
|
||||
|
||||
# Other tests
|
||||
tests/convergence/rates
|
||||
tests/convergence/prates
|
||||
tests/par-mesh-format/ex1p
|
||||
|
||||
# VPATH builds
|
||||
build-*/*
|
||||
|
||||
+1
-17
@@ -71,8 +71,6 @@ stages:
|
||||
- build
|
||||
- test
|
||||
- deallocate
|
||||
- lassen_build
|
||||
- lassen_test
|
||||
- baseline_check
|
||||
- baseline_publish
|
||||
|
||||
@@ -81,11 +79,7 @@ stages:
|
||||
# TODO: updating tests and tpls is not necessary anymore since pipelines are
|
||||
# now using unique directories so repo are never shared with another pipeline.
|
||||
# This is not memory efficient (we keep a lot of data), hence this reminder.
|
||||
# Setup
|
||||
setup:
|
||||
tags:
|
||||
- shell
|
||||
- quartz
|
||||
.setup:
|
||||
stage: setup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
@@ -106,15 +100,6 @@ setup:
|
||||
before_script:
|
||||
- module load gcc/6.1.0
|
||||
|
||||
# On lassen
|
||||
.with_gcc_8_3_1:
|
||||
variables:
|
||||
TOOLCHAIN: gcc_8_3_1
|
||||
CXX: g++
|
||||
CC: gcc
|
||||
before_script:
|
||||
- module load gcc/8.3.1
|
||||
|
||||
.with_gcc_4_9_3:
|
||||
variables:
|
||||
TOOLCHAIN: gcc_4_9_3
|
||||
@@ -305,4 +290,3 @@ setup:
|
||||
# The list on jobs is defined in machine-specific files.
|
||||
include:
|
||||
- local: .gitlab/quartz.yml
|
||||
- local: .gitlab/lassen.yml
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# GitLab pipelines configurations for the Lassen machine at LLNL
|
||||
|
||||
.on_lassen:
|
||||
tags:
|
||||
- shell
|
||||
- lassen
|
||||
variables:
|
||||
PLAT: lassen
|
||||
|
||||
# Build MFEM
|
||||
build_mfem_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
needs: [setup]
|
||||
stage: lassen_build
|
||||
script:
|
||||
- mkdir -p ${BUILD_PATH}
|
||||
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
|
||||
- lalloc 1 -W 5 -q pdebug make -j cuda CUDA_ARCH=sm_70
|
||||
|
||||
build_mfem_debug_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
needs: [setup]
|
||||
stage: lassen_build
|
||||
script:
|
||||
- mkdir -p ${BUILD_PATH}
|
||||
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
|
||||
- lalloc 1 -W 5 -q pdebug make -j cuda MFEM_DEBUG="YES" CUDA_ARCH=sm_70
|
||||
|
||||
# Sanity check
|
||||
sanitycheck_mfem_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
stage: lassen_test
|
||||
needs: [build_mfem_ser_lassen]
|
||||
script:
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
|
||||
- lalloc 1 -W 15 -q pdebug make -j test
|
||||
|
||||
sanitycheck_mfem_debug_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
stage: lassen_test
|
||||
needs: [build_mfem_debug_ser_lassen]
|
||||
script:
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
|
||||
- lalloc 1 -W 30 -q pdebug make -j test
|
||||
@@ -22,6 +22,10 @@
|
||||
MAKE_PAR: 6
|
||||
BASELINE_PAR: 18
|
||||
|
||||
# Setup
|
||||
setup_quartz:
|
||||
extends: [.setup, .on_quartz]
|
||||
|
||||
# Allocate
|
||||
allocate_quartz:
|
||||
variables:
|
||||
|
||||
@@ -38,11 +38,6 @@ Meshing improvements
|
||||
- Added complete action of the TMOP Integrator to account for the spatial
|
||||
derivatives of discrete and analytic targets.
|
||||
|
||||
- Added support for initialization of (serial) non-conforming meshes. Hanging
|
||||
nodes can be marked with Mesh::AddVertexParents when building the mesh with
|
||||
the "init" constructor. The usage is demonstrated in a new meshing miniapp
|
||||
(polar-nc) which generates meshes that are non-conforming from the start.
|
||||
|
||||
Performance improvements
|
||||
------------------------
|
||||
- Added support for explicit vectorization in the high-performance templated
|
||||
@@ -69,10 +64,6 @@ Improved GPU capabilities
|
||||
|
||||
- Added support for BlockOperator on GPU. See the updated Example 5.
|
||||
|
||||
- Added partial assembly and GPU support for complex operators, including the
|
||||
classes ComplexOperator, [Par]ComplexGridFunction, [Par]ComplexLinearForm, and
|
||||
[Par]SesquilinearForm. See the updated Example 22.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Added support for matrix-free interpolation and restriction operators between
|
||||
@@ -101,14 +92,6 @@ Discretization improvements
|
||||
|
||||
- Added support face integrals on the boundaries of NURBS meshes.
|
||||
|
||||
- Added support for interpolation of functions in L2, H(div) and H(curl)
|
||||
spaces using GSLIB-FindPoints.
|
||||
|
||||
- Added support for computing asymptotic error estimates and convergence rates
|
||||
for the whole de Rham sequence based on the new class ConvergenceStudy and new
|
||||
member methods in GridFunction and ParGridFunction. See the rates.cpp file in
|
||||
the tests/convergence directory for sample usage.
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Added power method to iteratively estimate the largest eigenvalue and the
|
||||
@@ -134,12 +117,6 @@ Linear and nonlinear solvers
|
||||
|
||||
- Added support for the SLEPc eigensolver package.
|
||||
|
||||
- Added partially assembled convergent diagonal preconditioner for adaptively
|
||||
refined meshes (i.e. non-conforming finite element spaces), see Example 6/6p.
|
||||
|
||||
- Added an interface to the Intel MKL Parallel Direct Sparse Solver for
|
||||
Clusters. An example usage of the interface is shown in Example 11p.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
|
||||
@@ -176,9 +153,6 @@ New and updated examples and miniapps
|
||||
- Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem:
|
||||
the Dirichlet problem for the minimal surface equation.
|
||||
|
||||
- Added a new meshing miniapp, Polar NC, which demonstrates the construction of
|
||||
polar non-conforming meshes.
|
||||
|
||||
- Added partial assembly support to Example 4/4p and Example 5/5p, with diagonal
|
||||
preconditioning.
|
||||
|
||||
@@ -193,47 +167,30 @@ New and updated examples and miniapps
|
||||
mesh based on element attributes. Any newly exposed boundary elements are
|
||||
assigned attribute numbers related to the trimmed element attributes.
|
||||
|
||||
- Added a new miniapp (field-interp) that demonstrates transfer of grid function
|
||||
between different meshes using GSLIB-FindPoints.
|
||||
|
||||
- Added diagonal preconditioner in Example 6/6p for partial assembly with AMR.
|
||||
|
||||
- Added device support in Example 5/5p.
|
||||
|
||||
- Added partial assembly and device support to Example 22/22p, with diagonal
|
||||
preconditioning.
|
||||
|
||||
- Added the option to plot a function in Mesh Explorer.
|
||||
|
||||
Improved testing
|
||||
----------------
|
||||
- Upgraded the Catch unit test framework from version 1.6.1 to version 2.13.0.
|
||||
|
||||
- Added a GitLab pipeline that automates PR testing on supercomputing systems
|
||||
and Linux clusters at Lawrence Livermore National Lab (LLNL). This can be
|
||||
triggered only by LLNL developers, see .gitlab-ci.yml, the .gitlab directory
|
||||
and the updated CONTRIBUTING.md file.
|
||||
|
||||
- Added testing of the parallel mesh format in tests/par-mesh-format.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added support for ADIOS2 for parallel I/O with ParaView visualization. The
|
||||
classes adios2stream and ADIOS2DataCollection are introduced in mfem as the
|
||||
interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the
|
||||
entire spatial and temporal node data. Cell centered data is accessible by
|
||||
ADIOS2 data readers (e.g. Python), but currently not yet implement as of
|
||||
ParaView v5.8.1. In addition, ADIOS2 allows for setting a user-defined number
|
||||
of data substreams/subfiles at scale. See examples 5, 9, 12, 16.
|
||||
entire spatial and temporal data. In addition, ADIOS2 allows for setting a
|
||||
user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16.
|
||||
|
||||
- The integration order used in the ComputeLpError and ComputeElementLpError
|
||||
methods of class GridFunction has been increased.
|
||||
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
- Renamed "Backend::DEBUG" to "Backend::DEBUG_DEVICE" to avoid conflicts,
|
||||
as DEBUG is sometimes used as a macro.
|
||||
|
||||
|
||||
Version 4.1, released on March 10, 2020
|
||||
=======================================
|
||||
|
||||
+1
-7
@@ -346,12 +346,6 @@ if (MFEM_USE_ADIOS2)
|
||||
find_package(ADIOS2 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MKL_CPARDISO)
|
||||
if (MFEM_USE_MPI)
|
||||
find_package(MKL_CPARDISO REQUIRED MKL_SEQUENTIAL MKL_LP64 MKL_MPI_WRAPPER)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# MFEM_TIMER_TYPE
|
||||
if (NOT DEFINED MFEM_TIMER_TYPE)
|
||||
if (APPLE)
|
||||
@@ -378,7 +372,7 @@ endif()
|
||||
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
|
||||
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
|
||||
CUSPARSE MKL_CPARDISO)
|
||||
CUSPARSE)
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
set(TPL_INCLUDE_DIRS "")
|
||||
|
||||
@@ -486,13 +486,6 @@ MFEM_USE_CEED = YES/NO
|
||||
library for performant high-order operator evaluation developed by the Center
|
||||
for Efficient Exascale Discretizations in the Exascale Computing Project.
|
||||
|
||||
MFEM_USE_MKL_CPARDISO = YES/NO
|
||||
Enables the interface to the Intel MKL Parallel Direct Sparse Solver for
|
||||
Clusters. Make sure to set the correct values for MKL_MPI_WRAPPER and
|
||||
MKL_LIBRARY_SUBDIR as shown in defaults.mk. If you configure MFEM with
|
||||
MFEM_USE_LAPACK=YES, verify that the MKL LAPACK libraries are used. The
|
||||
OpenMP capabilities are disabled at link time.
|
||||
|
||||
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.
|
||||
@@ -670,7 +663,7 @@ The specific libraries and their options are:
|
||||
URL: https://github.com/CEED/libCEED
|
||||
https://ceed.exascaleproject.org/libceed
|
||||
Options: CEED_DIR, CEED_OPT, CEED_LIB.
|
||||
Versions: libCEED > 0.6, git-hash bdfed75.
|
||||
Versions: libCEED > 0.6, git-hash fe5822c.
|
||||
|
||||
- RAJA (optional), used when MFEM_USE_RAJA = YES.
|
||||
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
|
||||
|
||||
@@ -156,7 +156,4 @@
|
||||
// library.
|
||||
#cmakedefine MFEM_USE_SIMMETRIX
|
||||
|
||||
// Enable interface to the MKL CPardiso library.
|
||||
#cmakedefine MFEM_USE_MKL_CPARDISO
|
||||
|
||||
#endif // MFEM_CONFIG_HEADER
|
||||
|
||||
@@ -38,19 +38,7 @@ if(NOT ADIOS2_FOUND)
|
||||
endif()
|
||||
|
||||
find_path(ADIOS2_INCLUDE_DIR adios2.h ${ADIOS2_INCLUDE_OPTS})
|
||||
|
||||
# adios2 version 2.5.0
|
||||
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
|
||||
|
||||
# adios2 version 2.6.0 and onwards
|
||||
if(NOT ADIOS2_LIBRARY)
|
||||
find_library(ADIOS2_CXX11_MPI_LIBRARY NAMES adios2_cxx11_mpi ${ADIOS2_LIBRARY_OPTS})
|
||||
find_library(ADIOS2_CXX11_LIBRARY NAMES adios2_cxx11 ${ADIOS2_LIBRARY_OPTS})
|
||||
set(ADIOS2_LIBRARY ${ADIOS2_CXX11_MPI_LIBRARY} ${ADIOS2_CXX11_LIBRARY})
|
||||
if(MFEM_USE_MPI)
|
||||
add_definitions(-DADIOS2_USE_MPI)
|
||||
endif()
|
||||
endif()
|
||||
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ADIOS2
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Defines the following variables:
|
||||
# - MKL_CPARDISO_FOUND
|
||||
# - MKL_CPARDISO_LIBRARIES
|
||||
# - MKL_CPARDISO_INCLUDE_DIRS
|
||||
|
||||
if(NOT MKL_MPI_WRAPPER_LIB)
|
||||
message(FATAL_ERROR "MKL CPardiso enabled but no MKL MPI Wrapper lib specified")
|
||||
endif()
|
||||
|
||||
if(NOT MKL_LIBRARY_DIR)
|
||||
message(WARNING "Using default MKL library path. Double check the variable MKL_LIBRARY_DIR")
|
||||
set(MKL_LIBRARY_DIR "lib")
|
||||
endif()
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(MKL_CPARDISO MKL_CPARDISO
|
||||
MKL_CPARDISO_DIR "include" mkl_cluster_sparse_solver.h ${MKL_LIBRARY_DIR} mkl_core
|
||||
"Paths to headers required by MKL CPardiso." "Libraries required by MKL CPARDISO."
|
||||
ADD_COMPONENT MKL_LP64 "include" "" ${MKL_LIBRARY_DIR} mkl_intel_lp64
|
||||
ADD_COMPONENT MKL_SEQUENTIAL "include" "" ${MKL_LIBRARY_DIR} mkl_sequential
|
||||
ADD_COMPONENT MKL_MPI_WRAPPER "include" "" ${MKL_LIBRARY_DIR} ${MKL_MPI_WRAPPER_LIB}
|
||||
CHECK_BUILD MKL_CPARDISO_VERSION_OK TRUE
|
||||
"
|
||||
#include <mpi.h>
|
||||
#include <mkl.h>
|
||||
#include <mkl_cluster_sparse_solver.h>
|
||||
int main (void)
|
||||
{
|
||||
MKL_INT n = 5;
|
||||
MKL_INT ia[6] = { 1, 4, 6, 9, 12, 14};
|
||||
MKL_INT ja[13] = { 1, 2, 4, /* index of non-zeros in 1 row*/
|
||||
1, 2, /* index of non-zeros in 2 row*/
|
||||
3, 4, 5, /* index of non-zeros in 3 row*/
|
||||
1, 3, 4, /* index of non-zeros in 4 row*/
|
||||
2, 5 /* index of non-zeros in 5 row*/
|
||||
};
|
||||
double a[13] = {
|
||||
1.0, -1.0, /*0*/ -3.0, /*0*/
|
||||
-2.0, 5.0, /*0*/ /*0*/ /*0*/
|
||||
/*0*/ 4.0, 6.0, 4.0, /*0*/
|
||||
-4.0, /*0*/ 2.0, 7.0, /*0*/
|
||||
/*0*/ 8.0, /*0*/ /*0*/ -5.0
|
||||
};
|
||||
|
||||
MKL_INT mtype = 11; /* set matrix type to \"real unsymmetric matrix\" */
|
||||
MKL_INT nrhs = 1; /* Number of right hand sides. */
|
||||
double b[5], x[5], bs[5], res, res0; /* RHS and solution vectors. */
|
||||
|
||||
/* Internal solver memory pointer pt
|
||||
* 32-bit: int pt[64] or void *pt[64];
|
||||
* 64-bit: long int pt[64] or void *pt[64]; */
|
||||
void *pt[64] = { 0 };
|
||||
|
||||
/* Cluster Sparse Solver control parameters. */
|
||||
MKL_INT iparm[64] = { 0 };
|
||||
MKL_INT maxfct, mnum, phase, msglvl, error;
|
||||
|
||||
/* Auxiliary variables. */
|
||||
double ddum; /* Double dummy */
|
||||
MKL_INT idum; /* Integer dummy. */
|
||||
MKL_INT i, j;
|
||||
int mpi_stat = 0;
|
||||
int argc = 0;
|
||||
int comm, rank;
|
||||
char* uplo;
|
||||
char** argv;
|
||||
|
||||
mpi_stat = MPI_Init( &argc, &argv );
|
||||
mpi_stat = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
|
||||
comm = MPI_Comm_c2f( MPI_COMM_WORLD );
|
||||
|
||||
iparm[ 0] = 1; /* Solver default parameters overriden with provided by iparm */
|
||||
iparm[ 1] = 2; /* Use METIS for fill-in reordering */
|
||||
iparm[ 5] = 0; /* Write solution into x */
|
||||
iparm[ 7] = 2; /* Max number of iterative refinement steps */
|
||||
iparm[ 9] = 13; /* Perturb the pivot elements with 1E-13 */
|
||||
iparm[10] = 1; /* Use nonsymmetric permutation and scaling MPS */
|
||||
iparm[12] = 1; /* Switch on Maximum Weighted Matching algorithm (default for non-symmetric) */
|
||||
iparm[17] = -1; /* Output: Number of nonzeros in the factor LU */
|
||||
iparm[18] = -1; /* Output: Mflops for LU factorization */
|
||||
iparm[26] = 1; /* Check input data for correctness */
|
||||
iparm[39] = 0; /* Input: matrix/rhs/solution stored on master */
|
||||
maxfct = 1; /* Maximum number of numerical factorizations. */
|
||||
mnum = 1; /* Which factorization to use. */
|
||||
msglvl = 1; /* Print statistical information in file */
|
||||
error = 0; /* Initialize error flag */
|
||||
|
||||
phase = 11;
|
||||
cluster_sparse_solver ( pt, &maxfct, &mnum, &mtype, &phase,
|
||||
&n, a, ia, ja, &idum, &nrhs, iparm, &msglvl, &ddum, &ddum, &comm, &error );
|
||||
|
||||
mpi_stat = MPI_Finalize();
|
||||
return error;
|
||||
}
|
||||
")
|
||||
@@ -42,15 +42,9 @@
|
||||
#ifdef MFEM_USE_SUPERLU
|
||||
#error Building with SuperLU_DIST (MFEM_USE_SUPERLU=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
#error Building with MUMPS (MFEM_USE_MUMPS=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
#error Building with STRUMPACK (MFEM_USE_STRUMPACK=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
#error Building with MKL CPARDISO (MFEM_USE_MKL_CPARDISO=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_PETSC
|
||||
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
|
||||
@@ -94,10 +94,6 @@
|
||||
// Enable MFEM functionality based on the SuperLU library.
|
||||
// #define MFEM_USE_SUPERLU
|
||||
|
||||
// Enable MFEM functionality based on the MUMPS library.
|
||||
// #define MFEM_USE_MUMPS
|
||||
// #define MFEM_MUMPS_VERSION @MFEM_MUMPS_VERSION@
|
||||
|
||||
// Enable MFEM functionality based on the STRUMPACK library.
|
||||
// #define MFEM_USE_STRUMPACK
|
||||
|
||||
@@ -167,7 +163,4 @@
|
||||
// library.
|
||||
// #define MFEM_USE_SIMMETRIX
|
||||
|
||||
// Enable interface to the MKL CPardiso library.
|
||||
// #define MFEM_USE_MKL_CPARDISO
|
||||
|
||||
#endif // MFEM_CONFIG_HEADER
|
||||
|
||||
@@ -32,7 +32,6 @@ 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_MUMPS = @MFEM_USE_MUMPS@
|
||||
MFEM_USE_STRUMPACK = @MFEM_USE_STRUMPACK@
|
||||
MFEM_USE_GINKGO = @MFEM_USE_GINKGO@
|
||||
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
|
||||
@@ -53,7 +52,6 @@ MFEM_USE_CEED = @MFEM_USE_CEED@
|
||||
MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
|
||||
MFEM_USE_SIMD = @MFEM_USE_SIMD@
|
||||
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
|
||||
MFEM_USE_MKL_CPARDISO = @MFEM_USE_MKL_CPARDISO@
|
||||
|
||||
# Compiler, compile options, and link options
|
||||
MFEM_CXX = @MFEM_CXX@
|
||||
|
||||
@@ -52,7 +52,6 @@ option(MFEM_USE_CEED "Enable CEED" OFF)
|
||||
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
|
||||
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
|
||||
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
|
||||
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
|
||||
|
||||
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
|
||||
|
||||
@@ -181,10 +180,6 @@ set(HIOP_DIR "${MFEM_DIR}/../hiop/install" CACHE STRING
|
||||
set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
|
||||
"Packages that HiOp depends on.")
|
||||
|
||||
set(MKL_CPARDISO_DIR "" CACHE STRING "MKL installation path.")
|
||||
set(MKL_MPI_WRAPPER_LIB "mkl_blacs_mpich_lp64" CACHE STRING "MKL MPI wrapper library")
|
||||
set(MKL_LIBRARY_DIR "" CACHE STRING "Custom library subdirectory")
|
||||
|
||||
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
|
||||
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
|
||||
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
|
||||
|
||||
+2
-18
@@ -120,7 +120,6 @@ MFEM_USE_SUNDIALS = NO
|
||||
MFEM_USE_MESQUITE = NO
|
||||
MFEM_USE_SUITESPARSE = NO
|
||||
MFEM_USE_SUPERLU = NO
|
||||
MFEM_USE_MUMPS = NO
|
||||
MFEM_USE_STRUMPACK = NO
|
||||
MFEM_USE_GINKGO = NO
|
||||
MFEM_USE_GNUTLS = NO
|
||||
@@ -141,7 +140,6 @@ MFEM_USE_CEED = NO
|
||||
MFEM_USE_UMPIRE = NO
|
||||
MFEM_USE_SIMD = NO
|
||||
MFEM_USE_ADIOS2 = NO
|
||||
MFEM_USE_MKL_CPARDISO = NO
|
||||
|
||||
# Compile and link options for zlib.
|
||||
ZLIB_DIR =
|
||||
@@ -158,7 +156,7 @@ HYPRE_OPT = -I$(HYPRE_DIR)/include
|
||||
HYPRE_LIB = -L$(HYPRE_DIR)/lib -lHYPRE
|
||||
|
||||
# METIS library configuration
|
||||
ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK)$(MFEM_USE_MUMPS),NONONO)
|
||||
ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK),NONO)
|
||||
ifeq ($(MFEM_USE_METIS_5),NO)
|
||||
METIS_DIR = @MFEM_DIR@/../metis-4.0
|
||||
METIS_OPT =
|
||||
@@ -234,7 +232,7 @@ SCALAPACK_DIR = @MFEM_DIR@/../scalapack-2.0.2
|
||||
SCALAPACK_OPT = -I$(SCALAPACK_DIR)/SRC
|
||||
SCALAPACK_LIB = -L$(SCALAPACK_DIR)/lib -lscalapack $(LAPACK_LIB)
|
||||
|
||||
# MPI Fortran library, needed e.g. by STRUMPACK or MUMPS
|
||||
# MPI Fortran library, needed e.g. by STRUMPACK
|
||||
# MPICH:
|
||||
MPI_FORTRAN_LIB = -lmpifort
|
||||
# OpenMPI:
|
||||
@@ -242,11 +240,6 @@ MPI_FORTRAN_LIB = -lmpifort
|
||||
# Additional Fortan library:
|
||||
# MPI_FORTRAN_LIB += -lgfortran
|
||||
|
||||
# MUMPS library configuration
|
||||
MUMPS_DIR =
|
||||
MUMPS_OPT = -I$(MUMPS_DIR)/include
|
||||
MUMPS_LIB = -Wl,-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib -ldmumps -lmumps_common -lpord $(SCALAPACK_LIB) $(LAPACK_LIB) $(MPI_FORTRAN_LIB)
|
||||
|
||||
# STRUMPACK library configuration
|
||||
STRUMPACK_DIR = @MFEM_DIR@/../STRUMPACK-build
|
||||
STRUMPACK_OPT = -I$(STRUMPACK_DIR)/include $(SCOTCH_OPT)
|
||||
@@ -379,15 +372,6 @@ UMPIRE_DIR = @MFEM_DIR@/../umpire
|
||||
UMPIRE_OPT = -I$(UMPIRE_DIR)/include
|
||||
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
|
||||
|
||||
# MKL CPardiso library configuration
|
||||
MKL_CPARDISO_DIR ?=
|
||||
MKL_MPI_WRAPPER ?= mkl_blacs_mpich_lp64
|
||||
MKL_LIBRARY_SUBDIR ?= lib
|
||||
MKL_CPARDISO_OPT = -I$(MKL_CPARDISO_DIR)/include
|
||||
MKL_CPARDISO_LIB = -Wl,-rpath,$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\
|
||||
-L$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR) -l$(MKL_MPI_WRAPPER)\
|
||||
-lmkl_intel_lp64 -lmkl_sequential -lmkl_core
|
||||
|
||||
# If YES, enable some informational messages
|
||||
VERBOSE = NO
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "dmumps_c.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
// Macros to expand a macro as a string
|
||||
#define STR_EXPAND(s) #s
|
||||
#define STR(s) STR_EXPAND(s)
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef MUMPS_VERSION
|
||||
const char *ptr = STR(MUMPS_VERSION);
|
||||
std::string s(ptr);
|
||||
s.erase(std::remove(s.begin(), s.end(), '"'), s.end());
|
||||
s.erase(std::remove(s.begin(), s.end(), '.'), s.end());
|
||||
std::cout << s << "\n";
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
+2
-19
@@ -42,10 +42,6 @@ GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
|
||||
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
|
||||
SMX_PATH = $(PUMI_DIR)/include/gmi_sim.h
|
||||
SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
|
||||
MUMPS = $(MFEM_USE_MUMPS:NO=)
|
||||
GMV_CXX ?= $(MFEM_CXX)
|
||||
GMV = get_mumps_version
|
||||
GMV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(MUMPS_OPT))
|
||||
|
||||
$(GHV): $(SRC)$(GHV).cpp
|
||||
$(call mfem-info, Determining HYPRE version ...)
|
||||
@@ -54,13 +50,6 @@ $(GHV).out: $(GHV)
|
||||
./$(GHV) > $(GHV).out
|
||||
.INTERMEDIATE: $(GHV) $(GHV).out
|
||||
|
||||
$(GMV): $(SRC)$(GMV).cpp
|
||||
$(call mfem-info, Determining MUMPS version ...)
|
||||
$(GMV_CXX) ${GMV_FLAGS} $(SRC)$(GMV).cpp -o $(GMV)
|
||||
$(GMV).out: $(GMV)
|
||||
./$(GMV) > $(GMV).out
|
||||
.INTERMEDIATE: $(GMV) $(GMV).out
|
||||
|
||||
get-hypre-version: $(GHV).out
|
||||
$(eval MFEM_HYPRE_VERSION:=$(shell cat $(GHV).out))
|
||||
$(if $(MFEM_HYPRE_VERSION),$(eval export MFEM_HYPRE_VERSION)\
|
||||
@@ -73,16 +62,10 @@ check-smx:
|
||||
$(call mfem-info, MFEM_USE_SIMMETRIX = $(MFEM_USE_SIMMETRIX))
|
||||
$(eval export MFEM_USE_SIMMETRIX)
|
||||
|
||||
get-mumps-version: $(GMV).out
|
||||
$(eval MFEM_MUMPS_VERSION:=$(shell cat $(GMV).out))
|
||||
$(if $(MFEM_MUMPS_VERSION),$(eval export MFEM_MUMPS_VERSION)\
|
||||
$(info MUMPS version: $(MFEM_MUMPS_VERSION)),\
|
||||
$(error Unable to determine MUMPS version))
|
||||
|
||||
header: $(if $(MPI),get-hypre-version,) $(if $(SMX),check-smx,) $(if $(MUMPS),get-mumps-version,)
|
||||
header: $(if $(MPI),get-hypre-version,) $(if $(SMX),check-smx)
|
||||
$(call mfem-info, Writing $(CONFIG_HPP) ...)
|
||||
@set -- && \
|
||||
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION) $(SMX) $(if $(MUMPS),MFEM_MUMPS_VERSION); do \
|
||||
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION) $(SMX); do \
|
||||
eval var=\$$$$def && \
|
||||
if [ "NO" != "$${var}" ]; then \
|
||||
set -- "$$@" -e "s|// \(#define $${def} \)|\1|" && \
|
||||
|
||||
+7
-50
@@ -78,14 +78,6 @@ groups_parallel=(
|
||||
"miniapps/electromagnetics"
|
||||
"joule.cpp"'
|
||||
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
|
||||
'"convergence"
|
||||
"Convergence tests:"
|
||||
"tests/convergence"
|
||||
"diffusion.cpp"'
|
||||
'"par-mesh-format"
|
||||
"Parallel mesh tests:"
|
||||
"tests/par-mesh-format"
|
||||
"ex1p.cpp"'
|
||||
)
|
||||
# All groups serial + parallel runs mixed in the same group:
|
||||
groups_all=(
|
||||
@@ -115,14 +107,6 @@ groups_all=(
|
||||
"miniapps/electromagnetics"
|
||||
"joule.cpp"'
|
||||
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
|
||||
'"convergence"
|
||||
"Convergence tests:"
|
||||
"tests/convergence"
|
||||
"diffusion.cpp"'
|
||||
'"par-mesh-format"
|
||||
"Parallel mesh tests:"
|
||||
"tests/par-mesh-format"
|
||||
"ex1p.cpp"'
|
||||
)
|
||||
make_all="all"
|
||||
base_timeformat=$'real: %3Rs user: %3Us sys: %3Ss %%cpu: %P'
|
||||
@@ -396,15 +380,10 @@ function timed_run()
|
||||
# This function is used to execute the sample runs
|
||||
function go()
|
||||
{
|
||||
# Strip leading and trailing spaces from $1 and store the result in cmd_line
|
||||
shopt -s extglob
|
||||
local cmd_line="${1##+( )}"
|
||||
cmd_line="${cmd_line%%+( )}"
|
||||
shopt -u extglob
|
||||
eval local cmd=(${cmd_line})
|
||||
local cmd=("$@")
|
||||
local res=""
|
||||
echo $sep
|
||||
echo "<${group}>" "${cmd_line}"
|
||||
echo "<${group}>" "${cmd[@]}"
|
||||
echo $sep
|
||||
if [ "${timing}" == "yes" ]; then
|
||||
timed_run "${cmd[@]}"
|
||||
@@ -416,15 +395,15 @@ function go()
|
||||
else
|
||||
res="${red}FAILED${none}"
|
||||
fi
|
||||
printf "[${res}] <${group}> ${cmd_line}\n"
|
||||
printf "[${res}] <${group}> ${cmd[*]}\n"
|
||||
if [ "${timing}" == "yes" ]; then
|
||||
printf "Run time: %s\n" "${timer}"
|
||||
timer=(${timer})
|
||||
timer="${timer[1]}"
|
||||
printf -v line "[$res](%8s) ${cmd_line}" "$timer"
|
||||
printf -v line "[$res](%8s) ${cmd[*]}" "$timer"
|
||||
summary=("${summary[@]}" "$line")
|
||||
else
|
||||
summary=("${summary[@]}" "[${res}] ${cmd_line}")
|
||||
summary=("${summary[@]}" "[${res}] ${cmd[*]}")
|
||||
fi
|
||||
echo $sep
|
||||
}
|
||||
@@ -459,7 +438,7 @@ function go_group()
|
||||
fi
|
||||
for run in "${runs[@]}"; do
|
||||
if [ "${run}" == "" ]; then continue; fi
|
||||
eval go \"\${run_prefix} \${run} \${run_suffix}\" $output
|
||||
eval go \${run_prefix} \${run} \${run_suffix} $output
|
||||
done
|
||||
done
|
||||
${make} clean-exec
|
||||
@@ -525,7 +504,7 @@ function echo_run()
|
||||
{
|
||||
echo " $@"
|
||||
{ echo " $@"; echo "$sep";
|
||||
eval "$@"
|
||||
"$@"
|
||||
echo "$sep"; } >> "$echo_log" 2>&1
|
||||
}
|
||||
|
||||
@@ -545,28 +524,6 @@ function build_all()
|
||||
echo_run ${make} config ${mfem_config} || exit 1
|
||||
echo_run ${make} ${make_j} || exit 1
|
||||
echo_run ${make} ${make_all} ${make_j} || exit 1
|
||||
# Build groups in directories other than the directories built by 'make all':
|
||||
for group_params in "${groups[@]}"; do
|
||||
eval params=(${group_params})
|
||||
group_dir="${params[2]}"
|
||||
case "$group_dir" in
|
||||
(examples*|miniapps*)
|
||||
# Built by 'make all'
|
||||
;;
|
||||
(*)
|
||||
if [ "${mfem_dir}" != "${mfem_build_dir}" ]; then
|
||||
echo_run mkdir -p "${group_dir}" || exit 1
|
||||
echo_run cd "${group_dir}" || exit 1
|
||||
echo_run cp -af "${mfem_dir}/${group_dir}/makefile" . || exit 1
|
||||
else
|
||||
echo_run cd "${group_dir}" || exit 1
|
||||
fi
|
||||
echo_run ${make} clean || exit 1
|
||||
echo_run ${make} MFEM_DIR="${mfem_dir}" ${make_j} || exit 1
|
||||
echo_run cd "${mfem_build_dir}" || exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Function that runs all sample runs, given by the array variable "groups".
|
||||
|
||||
@@ -149,7 +149,6 @@ namespace mfem {
|
||||
* - <a class="el" href="toroid_8cpp_source.html">Toroid</a>: generate simple toroidal meshes
|
||||
* - <a class="el" href="twist_8cpp_source.html">Twist</a>: generate simple periodic meshes
|
||||
* - <a class="el" href="minimal-surface_8cpp_source.html">Minimal Surface</a>: compute minimal surfaces, <a class="el" href="minimal-surface_8cpp_source.html">serial</a> and <a class="el" href="pminimal-surface_8cpp_source.html">parallel</a> versions
|
||||
* - <a class="el" href="polar-nc_8cpp_source.html">Polar NC</a>: generate polar non-conforming meshes
|
||||
* - <a class="el" href="shaper_8cpp_source.html">Shaper</a>: resolve material interfaces by mesh refinement
|
||||
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
|
||||
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
|
||||
@@ -162,7 +161,6 @@ namespace mfem {
|
||||
* - <a class="el" href="lor-transfer_8cpp_source.html">LOR Transfer</a>: map functions between high-order and low-order refined spaces
|
||||
* - <a class="el" href="findpts_8cpp_source.html">Find Points</a>: evaluate grid function in physical space, <a class="el" href="findpts_8cpp_source.html">serial</a> and <a class="el" href="pfindpts_8cpp_source.html">parallel</a> versions
|
||||
* - <a class="el" href="field-diff_8cpp_source.html">Field Diff</a>: compare grid functions on different meshes
|
||||
* - <a class="el" href="field-interp_8cpp_source.html">Field Interp</a>: transfer a grid functions betwen meshes
|
||||
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
|
||||
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
|
||||
*
|
||||
|
||||
+28
-6
@@ -175,7 +175,8 @@ int main(int argc, char *argv[])
|
||||
// domain integrator.
|
||||
BilinearForm a(&fespace);
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
//a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
a.AddDomainIntegrator(new MassIntegrator(one));
|
||||
|
||||
// 10. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
@@ -184,19 +185,40 @@ int main(int argc, char *argv[])
|
||||
if (static_cond) { a.EnableStaticCondensation(); }
|
||||
a.Assemble();
|
||||
|
||||
OperatorPtr A;
|
||||
OperatorPtr A, As;
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
Array<int> empty_list;
|
||||
a.FormSystemMatrix(empty_list, As);
|
||||
//a.FormLinearSystem(empty_list, x, b, A, X, B);
|
||||
//a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
cout << "Size of linear system: " << A->Height() << endl;
|
||||
//cout << "Size of linear system: " << A->Height() << endl;
|
||||
|
||||
// 11. Solve the linear system A X = B.
|
||||
if (!pa)
|
||||
{
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
|
||||
GSSmoother M((SparseMatrix&)(*A));
|
||||
PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
|
||||
//GSSmoother M((SparseMatrix&)(*A));
|
||||
|
||||
//SparseMatrix &Asp = *As.As<SparseMatrix>();
|
||||
SparseMatrix &Asp = a.SpMat();
|
||||
|
||||
Asp.Finalize();
|
||||
Asp.SortColumnIndices();
|
||||
|
||||
Vector tmpx(B.Size());
|
||||
Vector tmpy(B.Size());
|
||||
tmpx = 1.0;
|
||||
tmpy = 0.0;
|
||||
|
||||
//As.As<SparseMatrix>()->Mult(tmpx, tmpy);
|
||||
Asp.Mult(tmpx, tmpy);
|
||||
|
||||
//IncompleteCholesky M(*As.As<SparseMatrix>());
|
||||
IncompleteCholesky M(Asp);
|
||||
//ILUcusparse M(*A.As<SparseMatrix>());
|
||||
PCG(*As, M, B, X, 1, 200, 1e-12, 0.0);
|
||||
#else
|
||||
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
UMFPackSolver umf_solver;
|
||||
|
||||
+2
-20
@@ -72,7 +72,6 @@ int main(int argc, char *argv[])
|
||||
int seed = 75;
|
||||
bool slu_solver = false;
|
||||
bool sp_solver = false;
|
||||
bool pardiso_solver = false;
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
@@ -96,14 +95,6 @@ int main(int argc, char *argv[])
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp",
|
||||
"--no-strumpack", "Use the STRUMPACK Solver.");
|
||||
#endif
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
args.AddOption(&pardiso_solver,
|
||||
"-pardiso",
|
||||
"--pardiso",
|
||||
"-no-pardiso",
|
||||
"--no-pardiso",
|
||||
"Use the MKL Cluster Pardiso Solver.");
|
||||
#endif
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -245,7 +236,7 @@ int main(int argc, char *argv[])
|
||||
// preconditioner for A to be used within the solver. Set the matrices
|
||||
// which define the generalized eigenproblem A x = lambda M x.
|
||||
Solver * precond = NULL;
|
||||
if (!slu_solver && !sp_solver && !pardiso_solver)
|
||||
if (!slu_solver && !sp_solver)
|
||||
{
|
||||
HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
|
||||
amg->SetPrintLevel(0);
|
||||
@@ -277,19 +268,10 @@ int main(int argc, char *argv[])
|
||||
strumpack->SetFromCommandLine();
|
||||
precond = strumpack;
|
||||
}
|
||||
#endif
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
if (pardiso_solver)
|
||||
{
|
||||
auto pardiso = new CPardisoSolver(A->GetComm());
|
||||
pardiso->SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
|
||||
pardiso->SetPrintLevel(1);
|
||||
pardiso->SetOperator(*A);
|
||||
precond = pardiso;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
HypreLOBPCG * lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
|
||||
lobpcg->SetNumModes(nev);
|
||||
lobpcg->SetRandomSeed(seed);
|
||||
|
||||
+20
-3
@@ -122,7 +122,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int ref_levels =
|
||||
(int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
for (int l = 0; l < ref_levels-1; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
{
|
||||
int par_ref_levels = 2;
|
||||
int par_ref_levels = 1;
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh.UniformRefinement();
|
||||
@@ -216,6 +216,13 @@ int main(int argc, char *argv[])
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
SparseMatrix Asp;
|
||||
A.As<HypreParMatrix>()->GetDiag(Asp);
|
||||
Vector diag;
|
||||
|
||||
StopWatch sw;
|
||||
sw.Start();
|
||||
|
||||
// 13. Solve the linear system A X = B.
|
||||
// * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// * With partial assembly, use Jacobi smoothing, for now.
|
||||
@@ -229,7 +236,14 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = new HypreBoomerAMG;
|
||||
//prec = new HypreBoomerAMG;
|
||||
Asp.Finalize();
|
||||
Asp.SortColumnIndices();
|
||||
|
||||
Asp.GetDiag(diag);
|
||||
prec = new OperatorJacobiSmoother(diag, ess_tdof_list);
|
||||
//prec = new IncompleteCholesky(Asp);
|
||||
//prec = new ILUcusparse(Asp);
|
||||
}
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-12);
|
||||
@@ -240,6 +254,9 @@ int main(int argc, char *argv[])
|
||||
cg.Mult(B, X);
|
||||
delete prec;
|
||||
|
||||
sw.Stop();
|
||||
cout << "Step 13 solve time " << sw.RealTime() << endl;
|
||||
|
||||
// 14. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
// MFEM Example 1 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex1p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
|
||||
//
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/inline-quad.mesh";
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool visualization = true;
|
||||
int sr = 1;
|
||||
int pr = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&sr, "-sr", "--serial_ref",
|
||||
"Number of serial refinements");
|
||||
args.AddOption(&pr, "-pr", "--parallel_ref",
|
||||
"Number of parallel refinements");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// 5. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 10,000 elements.
|
||||
{
|
||||
for (int l = 0; l < sr; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
{
|
||||
for (int l = 0; l < pr; l++)
|
||||
{
|
||||
pmesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec = new H1_FECollection(order, dim);
|
||||
ParFiniteElementSpace fespace(&pmesh, fec);
|
||||
HYPRE_Int size = fespace.GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (pmesh.bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (1,phi_i) where phi_i are the basis functions in fespace.
|
||||
ParLinearForm b(&fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b.Assemble();
|
||||
|
||||
// 10. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
ParGridFunction x(&fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator.
|
||||
ParBilinearForm a(&fespace);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
|
||||
if (static_cond) { a.EnableStaticCondensation(); }
|
||||
a.Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
// // 13. Solve the linear system A X = B.
|
||||
// // * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// // * With partial assembly, use Jacobi smoothing, for now.
|
||||
StopWatch chrono;
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
HypreBoomerAMG *prec = new HypreBoomerAMG;
|
||||
prec->SetPrintLevel(0);
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-13);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(0);
|
||||
if (prec) { cg.SetPreconditioner(*prec); }
|
||||
cg.SetOperator(A);
|
||||
cg.Mult(B, X);
|
||||
delete prec;
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "PCG-AMG time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
{
|
||||
MUMPSSolver MA;
|
||||
MA.SetMatrixSymType(0);
|
||||
MA.SetOperator(A);
|
||||
Vector Y(X.Size());
|
||||
MA.Mult(B,Y);
|
||||
Y-=X;
|
||||
cout << "Mumps Diff norm = " << Y.Norml2() << endl;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "mumps time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
|
||||
{
|
||||
CPardisoSolver pardiso(A.GetComm());
|
||||
// pardiso.SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
|
||||
pardiso.SetMatrixType(CPardisoSolver::MatType::REAL_UNSYMMETRIC);
|
||||
pardiso.SetPrintLevel(0);
|
||||
pardiso.SetOperator(A);
|
||||
Vector Y(X.Size());
|
||||
pardiso.Mult(B, Y);
|
||||
Y-=X;
|
||||
cout << "Pardiso Diff norm = " << Y.Norml2() << endl;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "pardiso time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
{
|
||||
SuperLURowLocMatrix SA(A);
|
||||
SuperLUSolver superlu(MPI_COMM_WORLD);
|
||||
superlu.SetPrintStatistics(false);
|
||||
superlu.SetSymmetricPattern(false);
|
||||
superlu.SetColumnPermutation(superlu::PARMETIS);
|
||||
superlu.SetOperator(SA);
|
||||
Vector Y(X.Size());
|
||||
superlu.Mult(B, Y);
|
||||
Y-=X;
|
||||
cout << "Superlu Diff norm = " << Y.Norml2() << endl;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "superlu time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << x << flush;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
delete fec;
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+21
-30
@@ -6,19 +6,17 @@
|
||||
// ex22 -m ../data/inline-tri.mesh -o 3
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 2
|
||||
// ex22 -m ../data/inline-tet.mesh -o 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa -d cuda
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa -d cuda
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0 -pa -d cuda
|
||||
// With partial assembly:
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0 -pa
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define and
|
||||
// solve simple complex-valued linear systems. It implements three
|
||||
@@ -84,7 +82,6 @@ int main(int argc, char *argv[])
|
||||
bool herm_conv = true;
|
||||
bool exact_sol = true;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -117,8 +114,6 @@ int main(int argc, char *argv[])
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -148,18 +143,13 @@ int main(int argc, char *argv[])
|
||||
ComplexOperator::Convention conv =
|
||||
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes
|
||||
// with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh to increase resolution. In this example we do
|
||||
// 3. Refine the mesh to increase resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement where the user specifies
|
||||
// the number of levels with the '-r' option.
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
@@ -167,7 +157,7 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use continuous
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange, Nedelec, or Raviart-Thomas finite elements of the specified
|
||||
// order.
|
||||
if (dim == 1 && prob != 0 )
|
||||
@@ -189,7 +179,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of finite element unknowns: " << fespace->GetTrueVSize()
|
||||
<< endl;
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined based on the type
|
||||
// of mesh and the problem type.
|
||||
Array<int> ess_tdof_list;
|
||||
@@ -201,12 +191,12 @@ int main(int argc, char *argv[])
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 7. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system.
|
||||
ComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
|
||||
// 8. Define the solution vector u as a complex finite element grid function
|
||||
// 7. Define the solution vector u as a complex finite element grid function
|
||||
// corresponding to fespace. Initialize u with initial guess of 1+0i or
|
||||
// the exact solution if it is known.
|
||||
ComplexGridFunction u(fespace);
|
||||
@@ -228,6 +218,7 @@ int main(int argc, char *argv[])
|
||||
VectorConstantCoefficient zeroVecCoef(zeroVec);
|
||||
VectorConstantCoefficient oneVecCoef(oneVec);
|
||||
|
||||
u = 0.0;
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
@@ -280,7 +271,7 @@ int main(int argc, char *argv[])
|
||||
<< "window_title 'Exact: Imaginary Part'" << flush;
|
||||
}
|
||||
|
||||
// 9. Set up the sesquilinear form a(.,.) on the finite element space
|
||||
// 8. Set up the sesquilinear form a(.,.) on the finite element space
|
||||
// corresponding to the damped harmonic oscillator operator of the
|
||||
// appropriate type:
|
||||
//
|
||||
@@ -323,7 +314,7 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 9a. Set up the bilinear form for the preconditioner corresponding to the
|
||||
// 8a. Set up the bilinear form for the preconditioner corresponding to the
|
||||
// appropriate operator
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
@@ -358,9 +349,9 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 10. Assemble the form and the corresponding linear system, applying any
|
||||
// necessary transformations such as: assembly, eliminating boundary
|
||||
// conditions, conforming constraints for non-conforming AMR, etc.
|
||||
// 9. Assemble the form and the corresponding linear system, applying any
|
||||
// necessary transformations such as: assembly, eliminating boundary
|
||||
// conditions, conforming constraints for non-conforming AMR, etc.
|
||||
a->Assemble();
|
||||
pcOp->Assemble();
|
||||
|
||||
@@ -371,7 +362,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
cout << "Size of linear system: " << A->Width() << endl << endl;
|
||||
|
||||
// 11. Define and apply a GMRES solver for AU=B with a block diagonal
|
||||
// 10. Define and apply a GMRES solver for AU=B with a block diagonal
|
||||
// preconditioner based on the appropriate sparse smoother.
|
||||
{
|
||||
Array<int> blockOffsets;
|
||||
@@ -428,7 +419,7 @@ int main(int argc, char *argv[])
|
||||
gmres.Mult(B, U);
|
||||
}
|
||||
|
||||
// 12. Recover the solution as a finite element grid function and compute the
|
||||
// 11. Recover the solution as a finite element grid function and compute the
|
||||
// errors if the exact solution is known.
|
||||
a->RecoverFEMSolution(U, b, u);
|
||||
|
||||
@@ -460,7 +451,7 @@ int main(int argc, char *argv[])
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
// 13. Save the refined mesh and the solution. This output can be viewed
|
||||
// 12. Save the refined mesh and the solution. This output can be viewed
|
||||
// later using GLVis: "glvis -m mesh -g sol".
|
||||
{
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
@@ -475,7 +466,7 @@ int main(int argc, char *argv[])
|
||||
u.imag().Save(sol_i_ofs);
|
||||
}
|
||||
|
||||
// 14. Send the solution by socket to a GLVis server.
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -534,7 +525,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Free the used memory.
|
||||
// 14. Free the used memory.
|
||||
delete a;
|
||||
delete u_exact;
|
||||
delete pcOp;
|
||||
|
||||
+23
-31
@@ -7,18 +7,16 @@
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3 -p 1
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3 -p 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/inline-tet.mesh -o 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa -d cuda
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa -d cuda
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0 -pa -d cuda
|
||||
// With partial assembly:
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0 -pa
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define and
|
||||
// solve simple complex-valued linear systems. It implements three
|
||||
@@ -48,6 +46,7 @@
|
||||
// We recommend viewing examples 1, 3 and 4 before viewing this
|
||||
// example.
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -91,7 +90,6 @@ int main(int argc, char *argv[])
|
||||
bool herm_conv = true;
|
||||
bool exact_sol = true;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -126,8 +124,6 @@ int main(int argc, char *argv[])
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -164,24 +160,19 @@ int main(int argc, char *argv[])
|
||||
ComplexOperator::Convention conv =
|
||||
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
|
||||
|
||||
// 3. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (myid == 0) { device.Print(); }
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 5. Refine the serial mesh on all processors to increase the resolution.
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution.
|
||||
for (int l = 0; l < ser_ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
@@ -191,7 +182,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange, Nedelec, or Raviart-Thomas finite elements of
|
||||
// the specified order.
|
||||
if (dim == 1 && prob != 0 )
|
||||
@@ -219,7 +210,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// based on the type of mesh and the problem type.
|
||||
Array<int> ess_tdof_list;
|
||||
@@ -231,14 +222,14 @@ int main(int argc, char *argv[])
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system.
|
||||
ParComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
|
||||
// 10. Define the solution vector u as a parallel complex finite element grid
|
||||
// function corresponding to fespace. Initialize u with initial guess of
|
||||
// 1+0i or the exact solution if it is known.
|
||||
// 9. Define the solution vector u as a parallel complex finite element grid
|
||||
// function corresponding to fespace. Initialize u with initial guess of
|
||||
// 1+0i or the exact solution if it is known.
|
||||
ParComplexGridFunction u(fespace);
|
||||
ParComplexGridFunction * u_exact = NULL;
|
||||
if (exact_sol) { u_exact = new ParComplexGridFunction(fespace); }
|
||||
@@ -258,6 +249,7 @@ int main(int argc, char *argv[])
|
||||
VectorConstantCoefficient zeroVecCoef(zeroVec);
|
||||
VectorConstantCoefficient oneVecCoef(oneVec);
|
||||
|
||||
u = 0.0;
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
@@ -312,7 +304,7 @@ int main(int argc, char *argv[])
|
||||
<< "window_title 'Exact: Imaginary Part'" << flush;
|
||||
}
|
||||
|
||||
// 11. Set up the parallel sesquilinear form a(.,.) on the finite element
|
||||
// 10. Set up the parallel sesquilinear form a(.,.) on the finite element
|
||||
// space corresponding to the damped harmonic oscillator operator of the
|
||||
// appropriate type:
|
||||
//
|
||||
@@ -355,7 +347,7 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 11a. Set up the parallel bilinear form for the preconditioner
|
||||
// 10a. Set up the parallel bilinear form for the preconditioner
|
||||
// corresponding to the appropriate operator
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
@@ -389,7 +381,7 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 12. Assemble the parallel bilinear form and the corresponding linear
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, etc.
|
||||
@@ -407,7 +399,7 @@ int main(int argc, char *argv[])
|
||||
<< 2 * fespace->GlobalTrueVSize() << endl << endl;
|
||||
}
|
||||
|
||||
// 13. Define and apply a parallel FGMRES solver for AU=B with a block
|
||||
// 12. Define and apply a parallel FGMRES solver for AU=B with a block
|
||||
// diagonal preconditioner based on the appropriate multigrid
|
||||
// preconditioner from hypre.
|
||||
{
|
||||
@@ -468,7 +460,7 @@ int main(int argc, char *argv[])
|
||||
fgmres.SetPrintLevel(1);
|
||||
fgmres.Mult(B, U);
|
||||
}
|
||||
// 14. Recover the parallel grid function corresponding to U. This is the
|
||||
// 13. Recover the parallel grid function corresponding to U. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(U, b, u);
|
||||
|
||||
@@ -503,7 +495,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can be
|
||||
// 14. Save the refined mesh and the solution in parallel. This output can be
|
||||
// viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
{
|
||||
ostringstream mesh_name, sol_r_name, sol_i_name;
|
||||
@@ -523,7 +515,7 @@ int main(int argc, char *argv[])
|
||||
u.imag().Save(sol_i_ofs);
|
||||
}
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -588,7 +580,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
// 16. Free the used memory.
|
||||
delete a;
|
||||
delete u_exact;
|
||||
delete pcOp;
|
||||
|
||||
+53
-47
@@ -82,24 +82,24 @@ public:
|
||||
};
|
||||
|
||||
// Class for returning the PML coefficients of the bilinear form
|
||||
class PMLDiagMatrixCoefficient : public VectorCoefficient
|
||||
class PMLMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
CartesianPML * pml = nullptr;
|
||||
void (*Function)(const Vector &, CartesianPML * , Vector &);
|
||||
void (*Function)(const Vector &, CartesianPML * , DenseMatrix &);
|
||||
public:
|
||||
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
Vector &),
|
||||
CartesianPML * pml_)
|
||||
: VectorCoefficient(dim), pml(pml_), Function(F)
|
||||
PMLMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
DenseMatrix &),
|
||||
CartesianPML * pml_)
|
||||
: MatrixCoefficient(dim), pml(pml_), Function(F)
|
||||
{}
|
||||
virtual void Eval(Vector &K, ElementTransformation &T,
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
double x[3];
|
||||
Vector transip(x, 3);
|
||||
T.Transform(ip, transip);
|
||||
K.SetSize(vdim);
|
||||
K.SetSize(height, width);
|
||||
(*Function)(transip, pml, K);
|
||||
}
|
||||
};
|
||||
@@ -116,13 +116,13 @@ void source(const Vector &x, Vector & f);
|
||||
|
||||
// Functions for computing the necessary coefficients after PML stretching.
|
||||
// J is the Jacobian matrix of the stretching function
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
Array2D<double> comp_domain_bdr;
|
||||
Array2D<double> domain_bdr;
|
||||
@@ -365,19 +365,19 @@ int main(int argc, char *argv[])
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_omeg),NULL);
|
||||
|
||||
int cdim = (dim == 2) ? 1 : dim;
|
||||
PMLDiagMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLDiagMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarVectorProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarVectorProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
VectorRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarMatrixProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarMatrixProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
MatrixRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLDiagMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarVectorProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarVectorProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
VectorRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarMatrixProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarMatrixProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
MatrixRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
|
||||
// Integrators inside the PML region
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_Re),
|
||||
@@ -419,13 +419,13 @@ int main(int argc, char *argv[])
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_muinv));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_absomeg));
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarVectorProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
VectorRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarMatrixProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
MatrixRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarVectorProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
VectorRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarMatrixProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
MatrixRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs));
|
||||
@@ -763,7 +763,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -774,13 +774,14 @@ void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).real();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).real();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -791,13 +792,14 @@ void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).imag();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).imag();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -808,13 +810,14 @@ void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(det / pow(dxs[i], 2));
|
||||
M(i, i) = abs(det / pow(dxs[i], 2));
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -828,18 +831,19 @@ void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
// in the 2D case the coefficient is scalar 1/det(J)
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).real();
|
||||
M = (1.0 / det).real();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).real();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).real();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -852,18 +856,19 @@ void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).imag();
|
||||
M = (1.0 / det).imag();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).imag();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).imag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -876,13 +881,14 @@ void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = abs(1.0 / det);
|
||||
M = abs(1.0 / det);
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(pow(dxs[i], 2) / det);
|
||||
M(i, i) = abs(pow(dxs[i], 2) / det);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+53
-47
@@ -82,24 +82,24 @@ public:
|
||||
};
|
||||
|
||||
// Class for returning the PML coefficients of the bilinear form
|
||||
class PMLDiagMatrixCoefficient : public VectorCoefficient
|
||||
class PMLMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
CartesianPML * pml = nullptr;
|
||||
void (*Function)(const Vector &, CartesianPML * , Vector &);
|
||||
void (*Function)(const Vector &, CartesianPML * , DenseMatrix &);
|
||||
public:
|
||||
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
Vector &),
|
||||
CartesianPML * pml_)
|
||||
: VectorCoefficient(dim), pml(pml_), Function(F)
|
||||
PMLMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
DenseMatrix &),
|
||||
CartesianPML * pml_)
|
||||
: MatrixCoefficient(dim), pml(pml_), Function(F)
|
||||
{}
|
||||
virtual void Eval(Vector &K, ElementTransformation &T,
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
double x[3];
|
||||
Vector transip(x, 3);
|
||||
T.Transform(ip, transip);
|
||||
K.SetSize(vdim);
|
||||
K.SetSize(height, width);
|
||||
(*Function)(transip, pml, K);
|
||||
}
|
||||
};
|
||||
@@ -116,13 +116,13 @@ void source(const Vector &x, Vector & f);
|
||||
|
||||
// Functions for computing the necessary coefficients after PML stretching.
|
||||
// J is the Jacobian matrix of the stretching function
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
Array2D<double> comp_domain_bdr;
|
||||
Array2D<double> domain_bdr;
|
||||
@@ -393,19 +393,19 @@ int main(int argc, char *argv[])
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_omeg),NULL);
|
||||
|
||||
int cdim = (dim == 2) ? 1 : dim;
|
||||
PMLDiagMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLDiagMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarVectorProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarVectorProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
VectorRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarMatrixProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarMatrixProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
MatrixRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLDiagMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarVectorProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarVectorProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
VectorRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarMatrixProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarMatrixProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
MatrixRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
|
||||
// Integrators inside the PML region
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_Re),
|
||||
@@ -453,13 +453,13 @@ int main(int argc, char *argv[])
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_muinv));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_absomeg));
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarVectorProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
VectorRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarMatrixProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
MatrixRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarVectorProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
VectorRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarMatrixProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
MatrixRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs));
|
||||
@@ -819,7 +819,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -830,13 +830,14 @@ void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).real();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).real();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -847,13 +848,14 @@ void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).imag();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).imag();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -864,13 +866,14 @@ void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(det / pow(dxs[i], 2));
|
||||
M(i, i) = abs(det / pow(dxs[i], 2));
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -884,18 +887,19 @@ void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
// in the 2D case the coefficient is scalar 1/det(J)
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).real();
|
||||
M = (1.0 / det).real();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).real();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).real();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -908,18 +912,19 @@ void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).imag();
|
||||
M = (1.0 / det).imag();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).imag();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).imag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -932,13 +937,14 @@ void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = abs(1.0 / det);
|
||||
M = abs(1.0 / det);
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(pow(dxs[i], 2) / det);
|
||||
M(i, i) = abs(pow(dxs[i], 2) / det);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-12
@@ -60,7 +60,6 @@ int main(int argc, char *argv[])
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
bool amg_elast = 0;
|
||||
bool reorder_space = false;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -76,8 +75,6 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&reorder_space, "-nodes", "--by-nodes", "-vdim", "--by-vdim",
|
||||
"Use byNODES ordering of vector space instead of byVDIM");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -159,14 +156,7 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
if (reorder_space)
|
||||
{
|
||||
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byNODES);
|
||||
}
|
||||
else
|
||||
{
|
||||
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM);
|
||||
}
|
||||
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM);
|
||||
}
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
@@ -259,7 +249,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
amg->SetSystemsOptions(dim, reorder_space);
|
||||
amg->SetSystemsOptions(dim);
|
||||
}
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(1e-8);
|
||||
|
||||
+3
-8
@@ -108,11 +108,7 @@ int main(int argc, char *argv[])
|
||||
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
|
||||
// problem yet, this will be done in the main loop.
|
||||
BilinearForm a(&fespace);
|
||||
if (pa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
a.SetDiagonalPolicy(Operator::DIAG_ONE);
|
||||
}
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
LinearForm b(&fespace);
|
||||
|
||||
ConstantCoefficient one(1.0);
|
||||
@@ -203,10 +199,9 @@ int main(int argc, char *argv[])
|
||||
umf_solver.Mult(B, X);
|
||||
#endif
|
||||
}
|
||||
else // Diagonal preconditioning in partial assembly mode.
|
||||
else // No preconditioning for now in partial assembly mode.
|
||||
{
|
||||
OperatorJacobiSmoother M(a, ess_tdof_list);
|
||||
PCG(*A, M, B, X, 3, 2000, 1e-12, 0.0);
|
||||
CG(*A, B, X, 3, 2000, 1e-12, 0.0);
|
||||
}
|
||||
|
||||
// 18. After solving the linear system, reconstruct the solution as a
|
||||
|
||||
+6
-19
@@ -129,11 +129,7 @@ int main(int argc, char *argv[])
|
||||
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
|
||||
// problem yet, this will be done in the main loop.
|
||||
ParBilinearForm a(&fespace);
|
||||
if (pa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
a.SetDiagonalPolicy(Operator::DIAG_ONE);
|
||||
}
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
ParLinearForm b(&fespace);
|
||||
|
||||
ConstantCoefficient one(1.0);
|
||||
@@ -224,26 +220,17 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 17. Solve the linear system A X = B.
|
||||
// * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// * With partial assembly, use a diagonal preconditioner.
|
||||
Solver *M = NULL;
|
||||
if (pa)
|
||||
{
|
||||
M = new OperatorJacobiSmoother(a, ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
HypreBoomerAMG *amg = new HypreBoomerAMG;
|
||||
amg->SetPrintLevel(0);
|
||||
M = amg;
|
||||
}
|
||||
// * With partial assembly, use no preconditioner, for now.
|
||||
HypreBoomerAMG *amg = NULL;
|
||||
if (!pa) { amg = new HypreBoomerAMG; amg->SetPrintLevel(0); }
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-6);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(3); // print the first and the last iterations only
|
||||
cg.SetPreconditioner(*M);
|
||||
if (amg) { cg.SetPreconditioner(*amg); }
|
||||
cg.SetOperator(*A);
|
||||
cg.Mult(B, X);
|
||||
delete M;
|
||||
delete amg;
|
||||
|
||||
// 18. Switch back to the host and extract the parallel grid function
|
||||
// corresponding to the finite element approximation X. This is the
|
||||
|
||||
@@ -119,11 +119,6 @@ ex11p-test-superlu: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu)
|
||||
test-par-YES: ex11p-test-superlu
|
||||
endif
|
||||
ifeq ($(MFEM_USE_MKL_CPARDISO),YES)
|
||||
ex11p-test-superlu: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--pardiso)
|
||||
test-par-YES: ex11p-test-pardiso
|
||||
endif
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ set(SRCS
|
||||
bilininteg_vecmass.cpp
|
||||
coefficient.cpp
|
||||
complex_fem.cpp
|
||||
convergence.cpp
|
||||
datacollection.cpp
|
||||
eltrans.cpp
|
||||
estimators.cpp
|
||||
@@ -66,7 +65,6 @@ set(HDRS
|
||||
bilininteg.hpp
|
||||
coefficient.hpp
|
||||
complex_fem.hpp
|
||||
convergence.hpp
|
||||
datacollection.hpp
|
||||
eltrans.hpp
|
||||
estimators.hpp
|
||||
|
||||
@@ -310,12 +310,13 @@ void EABilinearFormExtension::Assemble()
|
||||
|
||||
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
|
||||
ea_data.UseDevice(true);
|
||||
ea_data = 0.0;
|
||||
|
||||
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
|
||||
const int integratorCount = integrators.Size();
|
||||
for (int i = 0; i < integratorCount; ++i)
|
||||
{
|
||||
integrators[i]->AssembleEA(*a->FESpace(), ea_data, i);
|
||||
integrators[i]->AssembleEA(*a->FESpace(), ea_data);
|
||||
}
|
||||
|
||||
faceDofs = trialFes ->
|
||||
@@ -332,13 +333,14 @@ void EABilinearFormExtension::Assemble()
|
||||
nf_int = trialFes->GetNFbyType(FaceType::Interior);
|
||||
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
|
||||
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
|
||||
ea_data_int = 0.0;
|
||||
ea_data_ext = 0.0;
|
||||
}
|
||||
for (int i = 0; i < intFaceIntegratorCount; ++i)
|
||||
{
|
||||
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
|
||||
ea_data_int,
|
||||
ea_data_ext,
|
||||
i);
|
||||
ea_data_ext);
|
||||
}
|
||||
|
||||
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
|
||||
@@ -351,7 +353,7 @@ void EABilinearFormExtension::Assemble()
|
||||
}
|
||||
for (int i = 0; i < boundFaceIntegratorCount; ++i)
|
||||
{
|
||||
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr,i);
|
||||
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
|
||||
}
|
||||
|
||||
if (factorize_face_terms && int_face_restrict_lex)
|
||||
|
||||
+3
-14
@@ -52,8 +52,7 @@ void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &emat,
|
||||
const bool add)
|
||||
Vector &emat)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -62,8 +61,7 @@ void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
|
||||
&fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add)
|
||||
Vector &ea_data_ext)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -71,8 +69,7 @@ void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
|
||||
|
||||
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
|
||||
&fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add)
|
||||
Vector &ea_data_bdr)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -1525,7 +1522,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
double w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector D;
|
||||
DenseMatrix curlshape(nd,dimc), curlshape_dFt(nd,dimc), M;
|
||||
#else
|
||||
curlshape.SetSize(nd,dimc);
|
||||
@@ -1533,7 +1529,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
if (MQ) { M.SetSize(dimc); }
|
||||
if (DQ) { D.SetSize(dimc); }
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
@@ -1577,12 +1572,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
Mult(curlshape_dFt, M, curlshape);
|
||||
AddMultABt(curlshape, curlshape_dFt, elmat);
|
||||
}
|
||||
else if (DQ)
|
||||
{
|
||||
DQ->Eval(D, Trans, ip);
|
||||
D *= w;
|
||||
AddMultADAt(curlshape_dFt, D, elmat);
|
||||
}
|
||||
else if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
|
||||
+16
-34
@@ -86,10 +86,9 @@ public:
|
||||
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
||||
|
||||
/// Method defining element assembly.
|
||||
/** The result of the element assembly is added to the @a emat Vector if
|
||||
@a add is true. Otherwise, if @a add is false, we set @a emat. */
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add = true);
|
||||
/** The result of the element assembly is added and stored in the @a emat
|
||||
Vector. */
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
/** Used with BilinearFormIntegrators that have different spaces. */
|
||||
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
|
||||
// const FiniteElementSpace &test_fes,
|
||||
@@ -97,12 +96,10 @@ public:
|
||||
|
||||
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add = true);
|
||||
Vector &ea_data_ext);
|
||||
|
||||
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add = true);
|
||||
Vector &ea_data_bdr);
|
||||
|
||||
/// Given a particular Finite Element computes the element matrix elmat.
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
@@ -265,17 +262,14 @@ public:
|
||||
bfi->AddMultTransposePA(x, y);
|
||||
}
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add);
|
||||
Vector &ea_data_ext);
|
||||
|
||||
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add);
|
||||
Vector &ea_data_bdr);
|
||||
|
||||
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
|
||||
};
|
||||
@@ -1958,8 +1952,7 @@ public:
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AssembleDiagonalPA(Vector &diag);
|
||||
|
||||
@@ -2034,8 +2027,7 @@ public:
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AssembleDiagonalPA(Vector &diag);
|
||||
|
||||
@@ -2091,8 +2083,7 @@ public:
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace&);
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AddMultPA(const Vector&, Vector&) const;
|
||||
|
||||
@@ -2309,14 +2300,12 @@ class CurlCurlIntegrator: public BilinearFormIntegrator
|
||||
private:
|
||||
Vector vec, pointflux;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector D;
|
||||
DenseMatrix curlshape, curlshape_dFt, M;
|
||||
DenseMatrix vshape, projcurl;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *DQ;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
// PA extension
|
||||
@@ -2325,17 +2314,12 @@ protected:
|
||||
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
||||
const GeometricFactors *geom; ///< Not owned
|
||||
int dim, ne, nq, dofs1D, quad1D;
|
||||
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
|
||||
|
||||
public:
|
||||
CurlCurlIntegrator() { Q = NULL; DQ = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator() { Q = NULL; MQ = NULL; }
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), Q(&q) { DQ = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator(VectorCoefficient &dq, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), DQ(&dq) { Q = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator(MatrixCoefficient &mq, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), MQ(&mq) { Q = NULL; DQ = NULL; }
|
||||
CurlCurlIntegrator(Coefficient &q) : Q(&q) { MQ = NULL; }
|
||||
CurlCurlIntegrator(MatrixCoefficient &m) : MQ(&m) { Q = NULL; }
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element curl-curl matrix elmat */
|
||||
@@ -2669,12 +2653,10 @@ public:
|
||||
|
||||
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add);
|
||||
Vector &ea_data_ext);
|
||||
|
||||
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add);
|
||||
Vector &ea_data_bdr);
|
||||
|
||||
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
|
||||
FaceElementTransformations &T);
|
||||
|
||||
@@ -22,7 +22,6 @@ static void EAConvectionAssemble1D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -55,14 +54,7 @@ static void EAConvectionAssemble1D(const int NE,
|
||||
{
|
||||
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, j1, e) = val;
|
||||
}
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -74,7 +66,6 @@ static void EAConvectionAssemble2D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -130,14 +121,7 @@ static void EAConvectionAssemble2D(const int NE,
|
||||
* r_B[k1][j1]* r_B[k2][j2];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, j1, j2, e) = val;
|
||||
}
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +135,6 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -208,14 +191,7 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) = val;
|
||||
}
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,8 +202,7 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
}
|
||||
|
||||
void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data,
|
||||
const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
AssemblePA(fes);
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
@@ -237,47 +212,44 @@ void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
+55
-114
@@ -20,8 +20,7 @@ static void EADGTraceAssemble1DInt(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_int,
|
||||
Vector &eadata_ext,
|
||||
const bool add)
|
||||
Vector &eadata_ext)
|
||||
{
|
||||
auto D = Reshape(padata.Read(), 2, 2, NF);
|
||||
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
|
||||
@@ -33,41 +32,23 @@ static void EADGTraceAssemble1DInt(const int NF,
|
||||
val_ext10 = D(1, 0, f);
|
||||
val_ext01 = D(0, 1, f);
|
||||
val_int1 = D(1, 1, f);
|
||||
if (add)
|
||||
{
|
||||
A_int(0, f) += val_int0;
|
||||
A_int(1, f) += val_int1;
|
||||
A_ext(0, f) += val_ext01;
|
||||
A_ext(1, f) += val_ext10;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_int(0, f) = val_int0;
|
||||
A_int(1, f) = val_int1;
|
||||
A_ext(0, f) = val_ext01;
|
||||
A_ext(1, f) = val_ext10;
|
||||
}
|
||||
A_int(0, f) += val_int0;
|
||||
A_int(1, f) += val_int1;
|
||||
A_ext(0, f) += val_ext01;
|
||||
A_ext(1, f) += val_ext10;
|
||||
});
|
||||
}
|
||||
|
||||
static void EADGTraceAssemble1DBdr(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_bdr,
|
||||
const bool add)
|
||||
Vector &eadata_bdr)
|
||||
{
|
||||
auto D = Reshape(padata.Read(), 2, 2, NF);
|
||||
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
|
||||
MFEM_FORALL(f, NF,
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
A_bdr(f) += D(0, 0, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
A_bdr(f) = D(0, 0, f);
|
||||
}
|
||||
A_bdr(f) += D(0, 0, f);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,7 +58,6 @@ static void EADGTraceAssemble2DInt(const int NF,
|
||||
const Vector &padata,
|
||||
Vector &eadata_int,
|
||||
Vector &eadata_ext,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -108,20 +88,10 @@ static void EADGTraceAssemble2DInt(const int NF,
|
||||
val_ext10 += B(k1,i1) * B(k1,j1) * D(k1, 1, 0, f);
|
||||
val_int1 += B(k1,i1) * B(k1,j1) * D(k1, 1, 1, f);
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_int(i1, j1, 0, f) += val_int0;
|
||||
A_int(i1, j1, 1, f) += val_int1;
|
||||
A_ext(i1, j1, 0, f) += val_ext01;
|
||||
A_ext(i1, j1, 1, f) += val_ext10;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_int(i1, j1, 0, f) = val_int0;
|
||||
A_int(i1, j1, 1, f) = val_int1;
|
||||
A_ext(i1, j1, 0, f) = val_ext01;
|
||||
A_ext(i1, j1, 1, f) = val_ext10;
|
||||
}
|
||||
A_int(i1, j1, 0, f) += val_int0;
|
||||
A_int(i1, j1, 1, f) += val_int1;
|
||||
A_ext(i1, j1, 0, f) += val_ext01;
|
||||
A_ext(i1, j1, 1, f) += val_ext10;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -132,7 +102,6 @@ static void EADGTraceAssemble2DBdr(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_bdr,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -156,14 +125,7 @@ static void EADGTraceAssemble2DBdr(const int NF,
|
||||
{
|
||||
val_bdr += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_bdr(i1, j1, f) += val_bdr;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_bdr(i1, j1, f) = val_bdr;
|
||||
}
|
||||
A_bdr(i1, j1, f) += val_bdr;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -175,7 +137,6 @@ static void EADGTraceAssemble3DInt(const int NF,
|
||||
const Vector &padata,
|
||||
Vector &eadata_int,
|
||||
Vector &eadata_ext,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -246,20 +207,10 @@ static void EADGTraceAssemble3DInt(const int NF,
|
||||
* s_D[k1][k2][1][0];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_int(i1, i2, j1, j2, 0, f) += val_int0;
|
||||
A_int(i1, i2, j1, j2, 1, f) += val_int1;
|
||||
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
|
||||
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_int(i1, i2, j1, j2, 0, f) = val_int0;
|
||||
A_int(i1, i2, j1, j2, 1, f) = val_int1;
|
||||
A_ext(i1, i2, j1, j2, 0, f) = val_ext01;
|
||||
A_ext(i1, i2, j1, j2, 1, f) = val_ext10;
|
||||
}
|
||||
A_int(i1, i2, j1, j2, 0, f) += val_int0;
|
||||
A_int(i1, i2, j1, j2, 1, f) += val_int1;
|
||||
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
|
||||
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,7 +223,6 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_bdr,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -330,14 +280,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
* s_D[k1][k2][0][0];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_bdr(i1, i2, j1, j2, f) += val_bdr;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_bdr(i1, i2, j1, j2, f) = val_bdr;
|
||||
}
|
||||
A_bdr(i1, i2, j1, j2, f) += val_bdr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,8 +290,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
|
||||
void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add)
|
||||
Vector &ea_data_ext)
|
||||
{
|
||||
SetupPA(fes, FaceType::Interior);
|
||||
nf = fes.GetNFbyType(FaceType::Interior);
|
||||
@@ -356,7 +298,7 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
const Array<double> &B = maps->B;
|
||||
if (dim == 1)
|
||||
{
|
||||
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext,add);
|
||||
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
@@ -364,31 +306,31 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
case 0x22:
|
||||
return EADGTraceAssemble2DInt<2,2>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x33:
|
||||
return EADGTraceAssemble2DInt<3,3>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x44:
|
||||
return EADGTraceAssemble2DInt<4,4>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x55:
|
||||
return EADGTraceAssemble2DInt<5,5>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x66:
|
||||
return EADGTraceAssemble2DInt<6,6>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x77:
|
||||
return EADGTraceAssemble2DInt<7,7>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x88:
|
||||
return EADGTraceAssemble2DInt<8,8>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x99:
|
||||
return EADGTraceAssemble2DInt<9,9>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
default:
|
||||
return EADGTraceAssemble2DInt(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add,dofs1D,quad1D);
|
||||
ea_data_ext,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
@@ -397,36 +339,35 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
case 0x23:
|
||||
return EADGTraceAssemble3DInt<2,3>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x34:
|
||||
return EADGTraceAssemble3DInt<3,4>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x45:
|
||||
return EADGTraceAssemble3DInt<4,5>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x56:
|
||||
return EADGTraceAssemble3DInt<5,6>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x67:
|
||||
return EADGTraceAssemble3DInt<6,7>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x78:
|
||||
return EADGTraceAssemble3DInt<7,8>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x89:
|
||||
return EADGTraceAssemble3DInt<8,9>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
default:
|
||||
return EADGTraceAssemble3DInt(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add,dofs1D,quad1D);
|
||||
ea_data_ext,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add)
|
||||
Vector &ea_data_bdr)
|
||||
{
|
||||
SetupPA(fes, FaceType::Boundary);
|
||||
nf = fes.GetNFbyType(FaceType::Boundary);
|
||||
@@ -434,37 +375,37 @@ void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
const Array<double> &B = maps->B;
|
||||
if (dim == 1)
|
||||
{
|
||||
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr,add);
|
||||
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr);
|
||||
default:
|
||||
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,add,dofs1D,quad1D);
|
||||
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr);
|
||||
default:
|
||||
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,add,dofs1D,quad1D);
|
||||
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
@@ -22,7 +22,6 @@ static void EADiffusionAssemble1D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -54,14 +53,7 @@ static void EADiffusionAssemble1D(const int NE,
|
||||
{
|
||||
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, j1, e) = val;
|
||||
}
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -73,7 +65,6 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -129,14 +120,7 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
+ gbi * D11 * gbj;
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, j1, j2, e) = val;
|
||||
}
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +134,6 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -225,14 +208,7 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) = val;
|
||||
}
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,8 +219,7 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data,
|
||||
const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
AssemblePA(fes);
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
@@ -254,47 +229,44 @@ void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
@@ -1680,7 +1680,7 @@ static void PADiffusionApply(const int dim,
|
||||
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
const int ID = (D1D << 4) | Q1D;
|
||||
const int ID = (D1D << 4 ) | Q1D;
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
|
||||
+314
-1971
File diff suppressed because it is too large
Load Diff
+30
-58
@@ -21,7 +21,6 @@ static void EAMassAssemble1D(const int NE,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -53,14 +52,7 @@ static void EAMassAssemble1D(const int NE,
|
||||
{
|
||||
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
M(i1, j1, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
M(i1, j1, e) = val;
|
||||
}
|
||||
M(i1, j1, e) += val;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -71,7 +63,6 @@ static void EAMassAssemble2D(const int NE,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -123,14 +114,7 @@ static void EAMassAssemble2D(const int NE,
|
||||
* s_D[k1][k2];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
M(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
M(i1, i2, j1, j2, e) = val;
|
||||
}
|
||||
M(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +127,6 @@ static void EAMassAssemble3D(const int NE,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -206,14 +189,7 @@ static void EAMassAssemble3D(const int NE,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
M(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
M(i1, i2, i3, j1, j2, j3, e) = val;
|
||||
}
|
||||
M(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,8 +200,7 @@ static void EAMassAssemble3D(const int NE,
|
||||
}
|
||||
|
||||
void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data,
|
||||
const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
AssemblePA(fes);
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
@@ -234,47 +209,44 @@ void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data,add);
|
||||
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data,add);
|
||||
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data,add);
|
||||
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data,add);
|
||||
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data,add);
|
||||
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data,add);
|
||||
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data,add);
|
||||
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data,add);
|
||||
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data);
|
||||
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data);
|
||||
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data);
|
||||
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data);
|
||||
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data);
|
||||
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data);
|
||||
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data);
|
||||
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data);
|
||||
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data,add);
|
||||
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data,add);
|
||||
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data,add);
|
||||
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data,add);
|
||||
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data,add);
|
||||
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data,add);
|
||||
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data,add);
|
||||
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data,add);
|
||||
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data);
|
||||
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data);
|
||||
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data);
|
||||
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data);
|
||||
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data);
|
||||
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data);
|
||||
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data);
|
||||
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data);
|
||||
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data,add);
|
||||
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data,add);
|
||||
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data,add);
|
||||
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data,add);
|
||||
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data,add);
|
||||
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data,add);
|
||||
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data,add);
|
||||
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data);
|
||||
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data);
|
||||
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data);
|
||||
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data);
|
||||
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data);
|
||||
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data);
|
||||
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data);
|
||||
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
+56
-139
@@ -16,171 +16,88 @@ namespace mfem
|
||||
{
|
||||
|
||||
void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data, const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
if (add)
|
||||
Vector ea_data_tmp(ea_data.Size());
|
||||
ea_data_tmp = 0.0;
|
||||
bfi->AssembleEA(fes, ea_data_tmp);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
auto A = Reshape(ea_data_tmp.Write(), dofs, dofs, ne);
|
||||
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
MFEM_FORALL(e, ne,
|
||||
{
|
||||
Vector ea_data_tmp(ea_data.Size());
|
||||
bfi->AssembleEA(fes, ea_data_tmp, false);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
auto A = Reshape(ea_data_tmp.Read(), dofs, dofs, ne);
|
||||
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
MFEM_FORALL(e, ne,
|
||||
for (int i = 0; i < dofs; i++)
|
||||
{
|
||||
for (int i = 0; i < dofs; i++)
|
||||
for (int j = 0; j < dofs; j++)
|
||||
{
|
||||
for (int j = 0; j < dofs; j++)
|
||||
{
|
||||
const double a = A(i, j, e);
|
||||
AT(j, i, e) += a;
|
||||
}
|
||||
const double a = A(i, j, e);
|
||||
AT(j, i, e) += a;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bfi->AssembleEA(fes, ea_data, false);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
auto A = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
MFEM_FORALL(e, ne,
|
||||
{
|
||||
for (int i = 0; i < dofs; i++)
|
||||
{
|
||||
for (int j = i+1; j < dofs; j++)
|
||||
{
|
||||
const double aij = A(i, j, e);
|
||||
const double aji = A(j, i, e);
|
||||
A(j, i, e) = aij;
|
||||
A(i, j, e) = aji;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add)
|
||||
Vector &ea_data_ext)
|
||||
{
|
||||
const int nf = fes.GetNFbyType(FaceType::Interior);
|
||||
if (nf == 0) { return; }
|
||||
if (add)
|
||||
Vector ea_data_int_tmp(ea_data_int.Size());
|
||||
Vector ea_data_ext_tmp(ea_data_ext.Size());
|
||||
ea_data_int_tmp = 0.0;
|
||||
ea_data_ext_tmp = 0.0;
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
Vector ea_data_int_tmp(ea_data_int.Size());
|
||||
Vector ea_data_ext_tmp(ea_data_ext.Size());
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
const double a_int0 = A_int(i, j, 0, f);
|
||||
const double a_int1 = A_int(i, j, 1, f);
|
||||
const double a_ext0 = A_ext(i, j, 0, f);
|
||||
const double a_ext1 = A_ext(i, j, 1, f);
|
||||
AT_int(j, i, 0, f) += a_int0;
|
||||
AT_int(j, i, 1, f) += a_int1;
|
||||
AT_ext(j, i, 0, f) += a_ext1;
|
||||
AT_ext(j, i, 1, f) += a_ext0;
|
||||
}
|
||||
const double a_int0 = A_int(i, j, 0, f);
|
||||
const double a_int1 = A_int(i, j, 1, f);
|
||||
const double a_ext0 = A_ext(i, j, 0, f);
|
||||
const double a_ext1 = A_ext(i, j, 1, f);
|
||||
AT_int(j, i, 0, f) += a_int0;
|
||||
AT_int(j, i, 1, f) += a_int1;
|
||||
AT_ext(j, i, 0, f) += a_ext1;
|
||||
AT_ext(j, i, 1, f) += a_ext0;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int, ea_data_ext, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int j = i+1; j < faceDofs; j++)
|
||||
{
|
||||
const double aij_int0 = A_int(i, j, 0, f);
|
||||
const double aij_int1 = A_int(i, j, 1, f);
|
||||
const double aji_int0 = A_int(j, i, 0, f);
|
||||
const double aji_int1 = A_int(j, i, 1, f);
|
||||
A_int(j, i, 0, f) = aij_int0;
|
||||
A_int(j, i, 1, f) = aij_int1;
|
||||
A_int(i, j, 0, f) = aji_int0;
|
||||
A_int(i, j, 1, f) = aji_int1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
const double aij_ext0 = A_ext(i, j, 0, f);
|
||||
const double aji_ext1 = A_ext(j, i, 1, f);
|
||||
A_ext(j, i, 1, f) = aij_ext0;
|
||||
A_ext(i, j, 0, f) = aji_ext1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add)
|
||||
Vector &ea_data_bdr)
|
||||
{
|
||||
const int nf = fes.GetNFbyType(FaceType::Boundary);
|
||||
if (nf == 0) { return; }
|
||||
if (add)
|
||||
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
|
||||
ea_data_bdr_tmp = 0.0;
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
|
||||
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
|
||||
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
const double a_bdr = A_bdr(i, j, f);
|
||||
AT_bdr(j, i, f) += a_bdr;
|
||||
}
|
||||
const double a_bdr = A_bdr(i, j, f);
|
||||
AT_bdr(j, i, f) += a_bdr;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int j = i+1; j < faceDofs; j++)
|
||||
{
|
||||
const double aij_bdr = A_bdr(i, j, f);
|
||||
const double aji_bdr = A_bdr(j, i, f);
|
||||
A_bdr(j, i, f) = aij_bdr;
|
||||
A_bdr(i, j, f) = aji_bdr;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-114
@@ -20,7 +20,7 @@ void PAHcurlSetup2D(const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &w,
|
||||
const Vector &j,
|
||||
Vector &coeff,
|
||||
Vector &_coeff,
|
||||
Vector &op);
|
||||
|
||||
void PAHcurlSetup3D(const int Q1D,
|
||||
@@ -28,73 +28,50 @@ void PAHcurlSetup3D(const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &w,
|
||||
const Vector &j,
|
||||
Vector &coeff,
|
||||
Vector &_coeff,
|
||||
Vector &op);
|
||||
|
||||
void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &bo,
|
||||
const Array<double> &bc,
|
||||
const Vector &pa_data,
|
||||
Vector &diag);
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Vector &_op,
|
||||
Vector &_diag);
|
||||
|
||||
void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &bo,
|
||||
const Array<double> &bc,
|
||||
const Vector &pa_data,
|
||||
Vector &diag);
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
void SmemPAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &bo,
|
||||
const Array<double> &bc,
|
||||
const Vector &pa_data,
|
||||
Vector &diag);
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Vector &_op,
|
||||
Vector &_diag);
|
||||
|
||||
void PAHcurlMassApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &bo,
|
||||
const Array<double> &bc,
|
||||
const Array<double> &bot,
|
||||
const Array<double> &bct,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
Vector &y);
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
const Array<double> &_Bct,
|
||||
const Vector &_op,
|
||||
const Vector &_x,
|
||||
Vector &_y);
|
||||
|
||||
void PAHcurlMassApply3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &bo,
|
||||
const Array<double> &bc,
|
||||
const Array<double> &bot,
|
||||
const Array<double> &bct,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
Vector &y);
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
void SmemPAHcurlMassApply3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &bo,
|
||||
const Array<double> &bc,
|
||||
const Array<double> &bot,
|
||||
const Array<double> &bct,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
Vector &y);
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
const Array<double> &_Bct,
|
||||
const Vector &_op,
|
||||
const Vector &_x,
|
||||
Vector &_y);
|
||||
|
||||
void PAHdivSetup2D(const int Q1D,
|
||||
const int NE,
|
||||
@@ -113,24 +90,24 @@ void PAHdivSetup3D(const int Q1D,
|
||||
void PAHcurlH1Apply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &bc,
|
||||
const Array<double> &gc,
|
||||
const Array<double> &bot,
|
||||
const Array<double> &bct,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
Vector &y);
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Gc,
|
||||
const Array<double> &_Bot,
|
||||
const Array<double> &_Bct,
|
||||
const Vector &_op,
|
||||
const Vector &_x,
|
||||
Vector &_y);
|
||||
|
||||
void PAHcurlH1Apply3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &bc,
|
||||
const Array<double> &gc,
|
||||
const Array<double> &bot,
|
||||
const Array<double> &bct,
|
||||
const Vector &pa_data,
|
||||
const Vector &x,
|
||||
Vector &y);
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Gc,
|
||||
const Array<double> &_Bot,
|
||||
const Array<double> &_Bct,
|
||||
const Vector &_op,
|
||||
const Vector &_x,
|
||||
Vector &_y);
|
||||
|
||||
void PAHdivMassAssembleDiagonal2D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -904,30 +881,8 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
|
||||
{
|
||||
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
const int ID = (dofs1D << 4) | quad1D;
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23: return SmemPAHcurlMassAssembleDiagonal3D<2,3>(dofs1D, quad1D, ne,
|
||||
symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
case 0x34: return SmemPAHcurlMassAssembleDiagonal3D<3,4>(dofs1D, quad1D, ne,
|
||||
symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
case 0x45: return SmemPAHcurlMassAssembleDiagonal3D<4,5>(dofs1D, quad1D, ne,
|
||||
symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
case 0x56: return SmemPAHcurlMassAssembleDiagonal3D<5,6>(dofs1D, quad1D, ne,
|
||||
symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
default: return SmemPAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
}
|
||||
}
|
||||
else
|
||||
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
}
|
||||
else if (trial_fetype == mfem::FiniteElement::DIV &&
|
||||
test_fetype == trial_fetype)
|
||||
@@ -971,35 +926,8 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (trial_curl && test_curl)
|
||||
{
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
const int ID = (dofs1D << 4) | quad1D;
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23: return SmemPAHcurlMassApply3D<2,3>(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B,
|
||||
mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
case 0x34: return SmemPAHcurlMassApply3D<3,4>(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B,
|
||||
mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
case 0x45: return SmemPAHcurlMassApply3D<4,5>(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B,
|
||||
mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
case 0x56: return SmemPAHcurlMassApply3D<5,6>(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B,
|
||||
mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
default: return SmemPAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B,
|
||||
mapsC->B,
|
||||
mapsO->Bt, mapsC->Bt, pa_data, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
|
||||
mapsO->Bt, mapsC->Bt, pa_data, x, y);
|
||||
}
|
||||
else if (trial_div && test_div)
|
||||
{
|
||||
|
||||
+155
-322
@@ -10,7 +10,6 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "complex_fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -20,21 +19,16 @@ namespace mfem
|
||||
ComplexGridFunction::ComplexGridFunction(FiniteElementSpace *fes)
|
||||
: Vector(2*(fes->GetVSize()))
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
gfr = new GridFunction();
|
||||
gfr->MakeRef(fes, *this, 0);
|
||||
|
||||
gfi = new GridFunction();
|
||||
gfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
gfr = new GridFunction(fes, data);
|
||||
gfi = new GridFunction(fes, &data[fes->GetVSize()]);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::Update()
|
||||
{
|
||||
FiniteElementSpace *fes = gfr->FESpace();
|
||||
const int vsize = fes->GetVSize();
|
||||
FiniteElementSpace * fes = gfr->FESpace();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
|
||||
const Operator *T = fes->GetUpdateOperator();
|
||||
if (T)
|
||||
@@ -46,36 +40,30 @@ ComplexGridFunction::Update()
|
||||
|
||||
// Our data array now contains old data as well as being the wrong size so
|
||||
// reallocate it.
|
||||
UseDevice(true);
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Create temporary vectors which point to the new data array
|
||||
Vector gf_r; gf_r.MakeRef(*this, 0, vsize);
|
||||
Vector gf_i; gf_i.MakeRef(*this, vsize, vsize);
|
||||
Vector gf_r(data, vsize);
|
||||
Vector gf_i((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// Copy the updated GridFunctions into the new data array
|
||||
gf_r = *gfr;
|
||||
gf_i = *gfi;
|
||||
gf_r.SyncAliasMemory(*this);
|
||||
gf_i.SyncAliasMemory(*this);
|
||||
|
||||
// Replace the individual data arrays with pointers into the new data
|
||||
// array
|
||||
gfr->MakeRef(*this, 0, vsize);
|
||||
gfi->MakeRef(*this, vsize, vsize);
|
||||
gfr->NewDataAndSize(data, vsize);
|
||||
gfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The existing data will not be transferred to the new GridFunctions so
|
||||
// delete it and allocate a new array
|
||||
UseDevice(true);
|
||||
// delete it a allocate a new array
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Point the individual GridFunctions to the new data array
|
||||
gfr->MakeRef(*this, 0, vsize);
|
||||
gfi->MakeRef(*this, vsize, vsize);
|
||||
gfr->NewDataAndSize(data, vsize);
|
||||
gfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// These updates will only set the proper 'sequence' value within the
|
||||
// individual GridFunction objects because their sizes are already correct
|
||||
@@ -88,24 +76,16 @@ void
|
||||
ComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectCoefficient(real_coeff);
|
||||
gfi->ProjectCoefficient(imag_coeff);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectCoefficient(real_vcoeff);
|
||||
gfi->ProjectCoefficient(imag_vcoeff);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -113,12 +93,8 @@ ComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectBdrCoefficient(real_coeff, attr);
|
||||
gfi->ProjectBdrCoefficient(imag_coeff, attr);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -126,12 +102,8 @@ ComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
|
||||
gfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -141,28 +113,18 @@ ComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
|
||||
gfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *f,
|
||||
ComplexOperator::Convention convention)
|
||||
: Vector(2*(fes->GetVSize())),
|
||||
: Vector(2*(f->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
lfr = new LinearForm();
|
||||
lfr->MakeRef(fes, *this, 0);
|
||||
|
||||
lfi = new LinearForm();
|
||||
lfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
lfr = new LinearForm(f, data);
|
||||
lfi = new LinearForm(f, &data[f->GetVSize()]);
|
||||
}
|
||||
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
|
||||
@@ -171,14 +133,8 @@ ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
|
||||
: Vector(2*(fes->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
lfr = new LinearForm(fes, lf_r);
|
||||
lfi = new LinearForm(fes, lf_i);
|
||||
|
||||
lfr->MakeRef(fes, *this, 0);
|
||||
lfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
lfr = new LinearForm(fes, lf_r); lfr->SetData(data);
|
||||
lfi = new LinearForm(fes, lf_i); lfi->SetData(&data[fes->GetVSize()]);
|
||||
}
|
||||
|
||||
ComplexLinearForm::~ComplexLinearForm()
|
||||
@@ -233,43 +189,42 @@ void
|
||||
ComplexLinearForm::Update()
|
||||
{
|
||||
FiniteElementSpace *fes = lfr->FESpace();
|
||||
|
||||
this->Update(fes);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Update(FiniteElementSpace *fes)
|
||||
{
|
||||
UseDevice(true);
|
||||
SetSize(2 * fes->GetVSize());
|
||||
this->Vector::operator=(0.0);
|
||||
int vsize = fes->GetVSize();
|
||||
SetSize(2 * vsize);
|
||||
|
||||
lfr->MakeRef(fes, *this, 0);
|
||||
lfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
Vector vlfr(data, vsize);
|
||||
Vector vlfi((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
lfr->Update(fes, vlfr, 0);
|
||||
lfi->Update(fes, vlfi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Assemble()
|
||||
{
|
||||
lfr->SyncMemory(*this);
|
||||
lfi->SyncMemory(*this);
|
||||
lfr->Assemble();
|
||||
lfi->Assemble();
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { *lfi *= -1.0; }
|
||||
lfr->SyncAliasMemory(*this);
|
||||
lfi->SyncAliasMemory(*this);
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
{
|
||||
*lfi *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
complex<double>
|
||||
ComplexLinearForm::operator()(const ComplexGridFunction &gf) const
|
||||
{
|
||||
double s = (conv == ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
|
||||
lfr->SyncMemory(*this);
|
||||
lfi->SyncMemory(*this);
|
||||
double s = (conv == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
return complex<double>((*lfr)(gf.real()) - s * (*lfi)(gf.imag()),
|
||||
(*lfr)(gf.imag()) + s * (*lfi)(gf.real()));
|
||||
}
|
||||
|
||||
|
||||
bool SesquilinearForm::RealInteg()
|
||||
{
|
||||
int nint = blfr->GetFBFI()->Size() + blfr->GetDBFI()->Size() +
|
||||
@@ -386,45 +341,34 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &X, Vector &B,
|
||||
int ci)
|
||||
{
|
||||
FiniteElementSpace *fes = blfr->FESpace();
|
||||
const int vsize = fes->GetVSize();
|
||||
FiniteElementSpace * fes = blfr->FESpace();
|
||||
int vsize = fes->GetVSize();
|
||||
|
||||
// Allocate temporary vector
|
||||
Vector b_0;
|
||||
b_0.UseDevice(true);
|
||||
b_0.SetSize(vsize);
|
||||
b_0 = 0.0;
|
||||
// Allocate temporary vectors
|
||||
Vector b_0(vsize); b_0 = 0.0;
|
||||
|
||||
// Extract the real and imaginary parts of the input vectors
|
||||
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
|
||||
x.Read();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
|
||||
b.Read();
|
||||
Vector b_r; b_r.MakeRef(b, 0, vsize);
|
||||
Vector b_i; b_i.MakeRef(b, vsize, vsize);
|
||||
Vector b_r(b.GetData(), vsize);
|
||||
Vector b_i(&(b.GetData())[vsize], vsize);
|
||||
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
|
||||
|
||||
const int tvsize = fes->GetTrueVSize();
|
||||
int tvsize = fes->GetTrueVSize();
|
||||
OperatorHandle A_r, A_i;
|
||||
|
||||
X.UseDevice(true);
|
||||
X.SetSize(2 * tvsize);
|
||||
X = 0.0;
|
||||
|
||||
B.UseDevice(true);
|
||||
B.SetSize(2 * tvsize);
|
||||
B = 0.0;
|
||||
|
||||
Vector X_r; X_r.MakeRef(X, 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(X, tvsize, tvsize);
|
||||
Vector B_r; B_r.MakeRef(B, 0, tvsize);
|
||||
Vector B_i; B_i.MakeRef(B, tvsize, tvsize);
|
||||
|
||||
Vector X_0, B_0;
|
||||
Vector X_0(tvsize), B_0(tvsize);
|
||||
Vector X_r(X.GetData(),tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
|
||||
if (RealInteg())
|
||||
{
|
||||
@@ -474,18 +418,13 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
// conform with standard essential BC treatment
|
||||
if (A_i.Is<ConstrainedOperator>())
|
||||
{
|
||||
const int n = ess_tdof_list.Size();
|
||||
auto d_B_r = B_r.Write();
|
||||
auto d_B_i = B_i.Write();
|
||||
auto d_X_r = X_r.Read();
|
||||
auto d_X_i = X_i.Read();
|
||||
auto d_idx = ess_tdof_list.Read();
|
||||
MFEM_FORALL(i, n,
|
||||
int n = ess_tdof_list.Size();
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = d_idx[i];
|
||||
d_B_r[j] = d_X_r[j];
|
||||
d_B_i[j] = d_X_i[j];
|
||||
});
|
||||
int j = ess_tdof_list[k];
|
||||
B_r(j) = X_r(j);
|
||||
B_i(j) = X_i(j);
|
||||
}
|
||||
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
|
||||
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
|
||||
}
|
||||
@@ -497,16 +436,6 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
b_i *= -1.0;
|
||||
}
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
b_r.SyncAliasMemory(b);
|
||||
b_i.SyncAliasMemory(b);
|
||||
|
||||
X_r.SyncAliasMemory(X);
|
||||
X_i.SyncAliasMemory(X);
|
||||
B_r.SyncAliasMemory(B);
|
||||
B_i.SyncAliasMemory(B);
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
|
||||
@@ -599,32 +528,29 @@ void
|
||||
SesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
|
||||
Vector &x)
|
||||
{
|
||||
FiniteElementSpace *fes = blfr->FESpace();
|
||||
FiniteElementSpace * fes = blfr->FESpace();
|
||||
|
||||
const SparseMatrix *P = fes->GetConformingProlongation();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
int tvsize = X.Size() / 2;
|
||||
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
if (!P)
|
||||
{
|
||||
x = X;
|
||||
return;
|
||||
}
|
||||
|
||||
const int vsize = fes->GetVSize();
|
||||
const int tvsize = X.Size() / 2;
|
||||
|
||||
X.Read();
|
||||
Vector X_r; X_r.MakeRef(const_cast<Vector&>(X), 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(const_cast<Vector&>(X), tvsize, tvsize);
|
||||
|
||||
x.Write();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
|
||||
// Apply conforming prolongation
|
||||
P->Mult(X_r, x_r);
|
||||
P->Mult(X_i, x_i);
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
else
|
||||
{
|
||||
// Apply conforming prolongation
|
||||
P->Mult(X_r, x_r);
|
||||
P->Mult(X_i, x_i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -640,21 +566,16 @@ SesquilinearForm::Update(FiniteElementSpace *nfes)
|
||||
ParComplexGridFunction::ParComplexGridFunction(ParFiniteElementSpace *pfes)
|
||||
: Vector(2*(pfes->GetVSize()))
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
pgfr = new ParGridFunction();
|
||||
pgfr->MakeRef(pfes, *this, 0);
|
||||
|
||||
pgfi = new ParGridFunction();
|
||||
pgfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
pgfr = new ParGridFunction(pfes, data);
|
||||
pgfi = new ParGridFunction(pfes, (data) ? &data[pfes->GetVSize()]:data);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::Update()
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pgfr->ParFESpace();
|
||||
const int vsize = pfes->GetVSize();
|
||||
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
|
||||
|
||||
int vsize = pfes->GetVSize();
|
||||
|
||||
const Operator *T = pfes->GetUpdateOperator();
|
||||
if (T)
|
||||
@@ -666,34 +587,30 @@ ParComplexGridFunction::Update()
|
||||
|
||||
// Our data array now contains old data as well as being the wrong size so
|
||||
// reallocate it.
|
||||
UseDevice(true);
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Create temporary vectors which point to the new data array
|
||||
Vector gf_r; gf_r.MakeRef(*this, 0, vsize);
|
||||
Vector gf_i; gf_i.MakeRef(*this, vsize, vsize);
|
||||
Vector gf_r(data, vsize);
|
||||
Vector gf_i((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// Copy the updated GridFunctions into the new data array
|
||||
gf_r = *pgfr; gf_r.SyncAliasMemory(*this);
|
||||
gf_i = *pgfi; gf_i.SyncAliasMemory(*this);
|
||||
gf_r = *pgfr;
|
||||
gf_i = *pgfi;
|
||||
|
||||
// Replace the individual data arrays with pointers into the new data
|
||||
// array
|
||||
pgfr->MakeRef(*this, 0, vsize);
|
||||
pgfi->MakeRef(*this, vsize, vsize);
|
||||
pgfr->NewDataAndSize(data, vsize);
|
||||
pgfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The existing data will not be transferred to the new GridFunctions so
|
||||
// delete it and allocate a new array
|
||||
UseDevice(true);
|
||||
// delete it a allocate a new array
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Point the individual GridFunctions to the new data array
|
||||
pgfr->MakeRef(*this, 0, vsize);
|
||||
pgfi->MakeRef(*this, vsize, vsize);
|
||||
pgfr->NewDataAndSize(data, vsize);
|
||||
pgfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// These updates will only set the proper 'sequence' value within the
|
||||
// individual GridFunction objects because their sizes are already correct
|
||||
@@ -706,24 +623,16 @@ void
|
||||
ParComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectCoefficient(real_coeff);
|
||||
pgfi->ProjectCoefficient(imag_coeff);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectCoefficient(real_vcoeff);
|
||||
pgfi->ProjectCoefficient(imag_vcoeff);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -731,12 +640,8 @@ ParComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectBdrCoefficient(real_coeff, attr);
|
||||
pgfi->ProjectBdrCoefficient(imag_coeff, attr);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -746,12 +651,8 @@ ParComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
|
||||
pgfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -761,51 +662,36 @@ ParComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
|
||||
pgfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::Distribute(const Vector *tv)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pgfr->ParFESpace();
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
tv->Read();
|
||||
Vector tvr; tvr.MakeRef(const_cast<Vector&>(*tv), 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(const_cast<Vector&>(*tv), tvsize, tvsize);
|
||||
double * tvd = tv->GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->Distribute(tvr);
|
||||
pgfi->Distribute(tvi);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ParallelProject(Vector &tv) const
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pgfr->ParFESpace();
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
tv.Write();
|
||||
Vector tvr; tvr.MakeRef(tv, 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(tv, tvsize, tvsize);
|
||||
double * tvd = tv.GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ParallelProject(tvr);
|
||||
pgfi->ParallelProject(tvi);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
|
||||
tvr.SyncAliasMemory(tv);
|
||||
tvi.SyncAliasMemory(tv);
|
||||
}
|
||||
|
||||
|
||||
@@ -815,16 +701,10 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
|
||||
: Vector(2*(pfes->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
plfr = new ParLinearForm(pfes, data);
|
||||
plfi = new ParLinearForm(pfes, (data) ? &data[pfes->GetVSize()]:data);
|
||||
|
||||
plfr = new ParLinearForm();
|
||||
plfr->MakeRef(pfes, *this, 0);
|
||||
|
||||
plfi = new ParLinearForm();
|
||||
plfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
|
||||
HYPRE_Int *tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
HYPRE_Int * tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
|
||||
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
|
||||
tdof_offsets = new HYPRE_Int[n+1];
|
||||
@@ -844,16 +724,12 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
|
||||
: Vector(2*(pfes->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
plfr = new ParLinearForm(pfes, plf_r);
|
||||
plfr->SetData(data);
|
||||
plfi = new ParLinearForm(pfes, plf_i);
|
||||
plfi->SetData((data) ? &data[pfes->GetVSize()]:data);
|
||||
|
||||
plfr->MakeRef(pfes, *this, 0);
|
||||
plfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
|
||||
HYPRE_Int *tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
HYPRE_Int * tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
|
||||
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
|
||||
tdof_offsets = new HYPRE_Int[n+1];
|
||||
@@ -916,71 +792,58 @@ ParComplexLinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real,
|
||||
void
|
||||
ParComplexLinearForm::Update(ParFiniteElementSpace *pf)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = (pf != NULL) ? pf : plfr->ParFESpace();
|
||||
ParFiniteElementSpace *pfes = (pf!=NULL)?pf:plfr->ParFESpace();
|
||||
int vsize = pfes->GetVSize();
|
||||
SetSize(2 * vsize);
|
||||
|
||||
UseDevice(true);
|
||||
SetSize(2 * pfes->GetVSize());
|
||||
this->Vector::operator=(0.0);
|
||||
Vector vplfr(data, vsize);
|
||||
Vector vplfi((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
plfr->MakeRef(pfes, *this, 0);
|
||||
plfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
plfr->Update(pfes, vplfr, 0);
|
||||
plfi->Update(pfes, vplfi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::Assemble()
|
||||
{
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
plfr->Assemble();
|
||||
plfi->Assemble();
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { *plfi *= -1.0; }
|
||||
plfr->SyncAliasMemory(*this);
|
||||
plfi->SyncAliasMemory(*this);
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
{
|
||||
*plfi *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::ParallelAssemble(Vector &tv)
|
||||
{
|
||||
const int tvsize = plfr->ParFESpace()->GetTrueVSize();
|
||||
HYPRE_Int size = plfr->ParFESpace()->GetTrueVSize();
|
||||
|
||||
tv.Write();
|
||||
Vector tvr; tvr.MakeRef(tv, 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(tv, tvsize, tvsize);
|
||||
double * tvd = tv.GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
plfr->ParallelAssemble(tvr);
|
||||
plfi->ParallelAssemble(tvi);
|
||||
plfr->SyncAliasMemory(*this);
|
||||
plfi->SyncAliasMemory(*this);
|
||||
|
||||
tvr.SyncAliasMemory(tv);
|
||||
tvi.SyncAliasMemory(tv);
|
||||
}
|
||||
|
||||
HypreParVector *
|
||||
ParComplexLinearForm::ParallelAssemble()
|
||||
{
|
||||
const ParFiniteElementSpace *pfes = plfr->ParFESpace();
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
const ParFiniteElementSpace * pfes = plfr->ParFESpace();
|
||||
|
||||
HypreParVector *tv = new HypreParVector(pfes->GetComm(),
|
||||
2*(pfes->GlobalTrueVSize()),
|
||||
tdof_offsets);
|
||||
HypreParVector * tv = new HypreParVector(pfes->GetComm(),
|
||||
2*(pfes->GlobalTrueVSize()),
|
||||
tdof_offsets);
|
||||
|
||||
tv->Write();
|
||||
Vector tvr; tvr.MakeRef(*tv, 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(*tv, tvsize, tvsize);
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
double * tvd = tv->GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
plfr->ParallelAssemble(tvr);
|
||||
plfi->ParallelAssemble(tvi);
|
||||
plfr->SyncAliasMemory(*this);
|
||||
plfi->SyncAliasMemory(*this);
|
||||
|
||||
tvr.SyncAliasMemory(*tv);
|
||||
tvi.SyncAliasMemory(*tv);
|
||||
|
||||
return tv;
|
||||
}
|
||||
@@ -988,14 +851,13 @@ ParComplexLinearForm::ParallelAssemble()
|
||||
complex<double>
|
||||
ParComplexLinearForm::operator()(const ParComplexGridFunction &gf) const
|
||||
{
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
double s = (conv == ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
|
||||
double s = (conv == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
return complex<double>((*plfr)(gf.real()) - s * (*plfi)(gf.imag()),
|
||||
(*plfr)(gf.imag()) + s * (*plfi)(gf.real()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ParSesquilinearForm::RealInteg()
|
||||
{
|
||||
int nint = pblfr->GetFBFI()->Size() + pblfr->GetDBFI()->Size() +
|
||||
@@ -1102,6 +964,7 @@ ParSesquilinearForm::ParallelAssemble()
|
||||
return new ComplexHypreParMatrix(pblfr->ParallelAssemble(),
|
||||
pblfi->ParallelAssemble(),
|
||||
true, true, conv);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1111,45 +974,35 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &X, Vector &B,
|
||||
int ci)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pblfr->ParFESpace();
|
||||
const int vsize = pfes->GetVSize();
|
||||
ParFiniteElementSpace * pfes = pblfr->ParFESpace();
|
||||
int vsize = pfes->GetVSize();
|
||||
|
||||
// Allocate temporary vector
|
||||
Vector b_0;
|
||||
b_0.UseDevice(true);
|
||||
b_0.SetSize(vsize);
|
||||
b_0 = 0.0;
|
||||
// Allocate temporary vectors
|
||||
Vector b_0(vsize); b_0 = 0.0;
|
||||
|
||||
// Extract the real and imaginary parts of the input vectors
|
||||
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
|
||||
x.Read();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
|
||||
b.Read();
|
||||
Vector b_r; b_r.MakeRef(b, 0, vsize);
|
||||
Vector b_i; b_i.MakeRef(b, vsize, vsize);
|
||||
Vector b_r(b.GetData(), vsize);
|
||||
Vector b_i(&(b.GetData())[vsize], vsize);
|
||||
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
|
||||
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
int tvsize = pfes->GetTrueVSize();
|
||||
|
||||
OperatorHandle A_r, A_i;
|
||||
|
||||
X.UseDevice(true);
|
||||
X.SetSize(2 * tvsize);
|
||||
X = 0.0;
|
||||
|
||||
B.UseDevice(true);
|
||||
B.SetSize(2 * tvsize);
|
||||
B = 0.0;
|
||||
|
||||
Vector X_r; X_r.MakeRef(X, 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(X, tvsize, tvsize);
|
||||
Vector B_r; B_r.MakeRef(B, 0, tvsize);
|
||||
Vector B_i; B_i.MakeRef(B, tvsize, tvsize);
|
||||
|
||||
Vector X_0, B_0;
|
||||
Vector X_0(tvsize), B_0(tvsize);
|
||||
Vector X_r(X.GetData(),tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
|
||||
if (RealInteg())
|
||||
{
|
||||
@@ -1189,29 +1042,24 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
|
||||
if (RealInteg() && ImagInteg())
|
||||
{
|
||||
int n = ess_tdof_list.Size();
|
||||
// Modify RHS to conform with standard essential BC treatment
|
||||
const int n = ess_tdof_list.Size();
|
||||
auto d_B_r = B_r.Write();
|
||||
auto d_B_i = B_i.Write();
|
||||
auto d_X_r = X_r.Read();
|
||||
auto d_X_i = X_i.Read();
|
||||
auto d_idx = ess_tdof_list.Read();
|
||||
MFEM_FORALL(i, n,
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = d_idx[i];
|
||||
d_B_r[j] = d_X_r[j];
|
||||
d_B_i[j] = d_X_i[j];
|
||||
});
|
||||
int j=ess_tdof_list[k];
|
||||
B_r(j) = X_r(j);
|
||||
B_i(j) = X_i(j);
|
||||
}
|
||||
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
|
||||
// with standard essential BC treatment
|
||||
if (A_i.Type() == Operator::Hypre_ParCSR)
|
||||
if ( A_i.Type() == Operator::Hypre_ParCSR )
|
||||
{
|
||||
HypreParMatrix * Ah;
|
||||
A_i.Get(Ah);
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = ess_tdof_list[k];
|
||||
int j = ess_tdof_list[k];
|
||||
Aih->diag->data[Aih->diag->i[j]] = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -1228,16 +1076,6 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
b_i *= -1.0;
|
||||
}
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
b_r.SyncAliasMemory(b);
|
||||
b_i.SyncAliasMemory(b);
|
||||
|
||||
X_r.SyncAliasMemory(X);
|
||||
X_i.SyncAliasMemory(X);
|
||||
B_r.SyncAliasMemory(B);
|
||||
B_i.SyncAliasMemory(B);
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ( A_r.Type() == Operator::Hypre_ParCSR ||
|
||||
@@ -1337,27 +1175,22 @@ void
|
||||
ParSesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
|
||||
Vector &x)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pblfr->ParFESpace();
|
||||
ParFiniteElementSpace * pfes = pblfr->ParFESpace();
|
||||
|
||||
const Operator &P = *pfes->GetProlongationMatrix();
|
||||
|
||||
const int vsize = pfes->GetVSize();
|
||||
const int tvsize = X.Size() / 2;
|
||||
int vsize = pfes->GetVSize();
|
||||
int tvsize = X.Size() / 2;
|
||||
|
||||
X.Read();
|
||||
Vector X_r; X_r.MakeRef(const_cast<Vector&>(X), 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(const_cast<Vector&>(X), tvsize, tvsize);
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
x.Write();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
// Apply conforming prolongation
|
||||
P.Mult(X_r, x_r);
|
||||
P.Mult(X_i, x_i);
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+11
-44
@@ -38,8 +38,8 @@ protected:
|
||||
void Destroy() { delete gfr; delete gfi; }
|
||||
|
||||
public:
|
||||
/** @brief Construct a ComplexGridFunction associated with the
|
||||
FiniteElementSpace @a *f. */
|
||||
/* @brief Construct a ComplexGridFunction associated with the
|
||||
FiniteElementSpace @a *f. */
|
||||
ComplexGridFunction(FiniteElementSpace *f);
|
||||
|
||||
void Update();
|
||||
@@ -71,14 +71,6 @@ public:
|
||||
const GridFunction & real() const { return *gfr; }
|
||||
const GridFunction & imag() const { return *gfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary GridFunction @a gfr
|
||||
/// and @a gfi to match the ComplexGridFunction.
|
||||
void Sync() { gfr->SyncMemory(*this); gfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary GridFunction
|
||||
/// @a gfr and @a gfi to match the ComplexGridFunction.
|
||||
void SyncAlias() { gfr->SyncAliasMemory(*this); gfi->SyncAliasMemory(*this); }
|
||||
|
||||
/// Destroys the grid function.
|
||||
virtual ~ComplexGridFunction() { Destroy(); }
|
||||
|
||||
@@ -107,8 +99,8 @@ public:
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
/** @brief Create a ComplexLinearForm on the FiniteElementSpace @a fes, using
|
||||
the same integrators as the LinearForms @a lf_r (real) and @a lf_i (imag).
|
||||
/** @brief Create a ComplexLinearForm on the FiniteElementSpace @a f, using
|
||||
the same integrators as the LinearForms @a lfr (real) and @a lfi (imag) .
|
||||
|
||||
The pointer @a fes is not owned by the newly constructed object.
|
||||
|
||||
@@ -165,14 +157,6 @@ public:
|
||||
const LinearForm & real() const { return *lfr; }
|
||||
const LinearForm & imag() const { return *lfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary LinearForm @a lfr
|
||||
/// and @a lfi to match the ComplexLinearForm.
|
||||
void Sync() { lfr->SyncMemory(*this); lfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary LinearForm @a
|
||||
/// lfr and @a lfi to match the ComplexLinearForm.
|
||||
void SyncAlias() { lfr->SyncAliasMemory(*this); lfi->SyncAliasMemory(*this); }
|
||||
|
||||
void Update();
|
||||
void Update(FiniteElementSpace *f);
|
||||
|
||||
@@ -211,8 +195,8 @@ private:
|
||||
BilinearForm *blfr;
|
||||
BilinearForm *blfi;
|
||||
|
||||
/* These methods check if the real/imag parts of the sesquilinear form are
|
||||
not empty */
|
||||
/* These methods check if the real/imag parts of the sesqulinear form are not
|
||||
empty */
|
||||
bool RealInteg();
|
||||
bool ImagInteg();
|
||||
|
||||
@@ -220,7 +204,7 @@ public:
|
||||
SesquilinearForm(FiniteElementSpace *fes,
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
/** @brief Create a SesquilinearForm on the FiniteElementSpace @a fes, using
|
||||
/** @brief Create a SesquilinearForm on the FiniteElementSpace @a f, using
|
||||
the same integrators as the BilinearForms @a bfr and @a bfi .
|
||||
|
||||
The pointer @a fes is not owned by the newly constructed object.
|
||||
@@ -339,8 +323,8 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
/** @brief Construct a ParComplexGridFunction associated with the
|
||||
ParFiniteElementSpace @a *pf. */
|
||||
/* @brief Construct a ParComplexGridFunction associated with the
|
||||
ParFiniteElementSpace @a *f. */
|
||||
ParComplexGridFunction(ParFiniteElementSpace *pf);
|
||||
|
||||
void Update();
|
||||
@@ -381,15 +365,6 @@ public:
|
||||
const ParGridFunction & real() const { return *pgfr; }
|
||||
const ParGridFunction & imag() const { return *pgfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary ParGridFunction @a
|
||||
/// pgfr and @a pgfi to match the ParComplexGridFunction.
|
||||
void Sync() { pgfr->SyncMemory(*this); pgfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary
|
||||
/// ParGridFunction @a pgfr and @a pgfi to match the ParComplexGridFunction.
|
||||
void SyncAlias() { pgfr->SyncAliasMemory(*this); pgfi->SyncAliasMemory(*this); }
|
||||
|
||||
|
||||
virtual double ComputeL2Error(Coefficient &exsolr, Coefficient &exsoli,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
@@ -441,8 +416,8 @@ public:
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
/** @brief Create a ParComplexLinearForm on the ParFiniteElementSpace @a pf,
|
||||
using the same integrators as the LinearForms @a plf_r (real) and
|
||||
@a plf_i (imag).
|
||||
using the same integrators as the LinearForms @a plfr (real) and @a plfi
|
||||
(imag) .
|
||||
|
||||
The pointer @a fes is not owned by the newly constructed object.
|
||||
|
||||
@@ -500,14 +475,6 @@ public:
|
||||
const ParLinearForm & real() const { return *plfr; }
|
||||
const ParLinearForm & imag() const { return *plfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary ParLinearForm @a lfr
|
||||
/// and @a lfi to match the ParComplexLinearForm.
|
||||
void Sync() { plfr->SyncMemory(*this); plfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary ParLinearForm
|
||||
/// @a plfr and @a plfi to match the ParComplexLinearForm.
|
||||
void SyncAlias() { plfr->SyncAliasMemory(*this); plfi->SyncAliasMemory(*this); }
|
||||
|
||||
void Update(ParFiniteElementSpace *pf = NULL);
|
||||
|
||||
/// Assembles the linear form i.e. sums over all domain/bdr integrators.
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
#include "convergence.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void ConvergenceStudy::Reset()
|
||||
{
|
||||
counter=0;
|
||||
dcounter=0;
|
||||
fcounter=0;
|
||||
cont_type=-1;
|
||||
print_flag=1;
|
||||
L2Errors.SetSize(0);
|
||||
L2Rates.SetSize(0);
|
||||
DErrors.SetSize(0);
|
||||
DRates.SetSize(0);
|
||||
EnErrors.SetSize(0);
|
||||
EnRates.SetSize(0);
|
||||
DGFaceErrors.SetSize(0);
|
||||
DGFaceRates.SetSize(0);
|
||||
ndofs.SetSize(0);
|
||||
}
|
||||
|
||||
double ConvergenceStudy::GetNorm(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *vector_u)
|
||||
{
|
||||
bool norm_set = false;
|
||||
double norm=0.0;
|
||||
int order = gf->FESpace()->GetOrder(0);
|
||||
int order_quad = std::max(2, 2*order+1);
|
||||
const IntegrationRule *irs[Geometry::NumGeom];
|
||||
for (int i=0; i < Geometry::NumGeom; ++i)
|
||||
{
|
||||
irs[i] = &(IntRules.Get(i, order_quad));
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
|
||||
if (pgf)
|
||||
{
|
||||
ParMesh *pmesh = pgf->ParFESpace()->GetParMesh();
|
||||
if (scalar_u)
|
||||
{
|
||||
norm = ComputeGlobalLpNorm(2.0,*scalar_u,*pmesh,irs);
|
||||
}
|
||||
else if (vector_u)
|
||||
{
|
||||
norm = ComputeGlobalLpNorm(2.0,*vector_u,*pmesh,irs);
|
||||
}
|
||||
norm_set = true;
|
||||
}
|
||||
#endif
|
||||
if (!norm_set)
|
||||
{
|
||||
Mesh *mesh = gf->FESpace()->GetMesh();
|
||||
if (scalar_u)
|
||||
{
|
||||
norm = ComputeLpNorm(2.0,*scalar_u,*mesh,irs);
|
||||
}
|
||||
else if (vector_u)
|
||||
{
|
||||
norm = ComputeLpNorm(2.0,*vector_u,*mesh,irs);
|
||||
}
|
||||
}
|
||||
return norm;
|
||||
}
|
||||
|
||||
void ConvergenceStudy::AddL2Error(GridFunction *gf,
|
||||
Coefficient *scalar_u, VectorCoefficient *vector_u)
|
||||
{
|
||||
int tdofs=0;
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
|
||||
if (pgf)
|
||||
{
|
||||
MPI_Comm comm = pgf->ParFESpace()->GetComm();
|
||||
int rank;
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
print_flag = 0;
|
||||
if (rank==0) { print_flag = 1; }
|
||||
tdofs = pgf->ParFESpace()->GlobalTrueVSize();
|
||||
}
|
||||
#endif
|
||||
if (!tdofs) { tdofs = gf->FESpace()->GetTrueVSize(); }
|
||||
ndofs.Append(tdofs);
|
||||
double L2Err;
|
||||
if (scalar_u)
|
||||
{
|
||||
L2Err = gf->ComputeL2Error(*scalar_u);
|
||||
CoeffNorm = GetNorm(gf,scalar_u,nullptr);
|
||||
}
|
||||
else if (vector_u)
|
||||
{
|
||||
L2Err = gf->ComputeL2Error(*vector_u);
|
||||
CoeffNorm = GetNorm(gf,nullptr,vector_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Exact Solution Coefficient pointer is NULL");
|
||||
}
|
||||
L2Errors.Append(L2Err);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val = (counter) ? log(L2Errors[counter-1]/L2Err)/log(2.0) : 0.0;
|
||||
L2Rates.Append(val);
|
||||
counter++;
|
||||
}
|
||||
|
||||
void ConvergenceStudy::AddGf(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad,
|
||||
Coefficient *ell_coeff, double Nu)
|
||||
{
|
||||
cont_type = gf->FESpace()->FEColl()->GetContType();
|
||||
|
||||
MFEM_VERIFY((cont_type == mfem::FiniteElementCollection::CONTINUOUS) ||
|
||||
(cont_type == mfem::FiniteElementCollection::DISCONTINUOUS),
|
||||
"This constructor is intended for H1 or L2 Elements")
|
||||
|
||||
AddL2Error(gf,scalar_u, nullptr);
|
||||
|
||||
if (grad)
|
||||
{
|
||||
double GradErr = gf->ComputeGradError(grad);
|
||||
DErrors.Append(GradErr);
|
||||
double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1]+GradErr*GradErr);
|
||||
EnErrors.Append(err);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val = (dcounter) ? log(DErrors[dcounter-1]/GradErr)/log(2.0) : 0.0;
|
||||
double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
|
||||
DRates.Append(val);
|
||||
EnRates.Append(eval);
|
||||
CoeffDNorm = GetNorm(gf,nullptr,grad);
|
||||
dcounter++;
|
||||
MFEM_VERIFY(counter == dcounter,
|
||||
"Number of added solutions and derivatives do not match")
|
||||
}
|
||||
|
||||
if (cont_type == mfem::FiniteElementCollection::DISCONTINUOUS && ell_coeff)
|
||||
{
|
||||
double DGErr = gf->ComputeDGFaceJumpError(scalar_u,ell_coeff,Nu);
|
||||
DGFaceErrors.Append(DGErr);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val=(fcounter) ? log(DGFaceErrors[fcounter-1]/DGErr)/log(2.0):0.;
|
||||
DGFaceRates.Append(val);
|
||||
fcounter++;
|
||||
MFEM_VERIFY(fcounter == counter, "Number of added solutions mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
void ConvergenceStudy::AddGf(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
VectorCoefficient *curl, Coefficient *div)
|
||||
{
|
||||
cont_type = gf->FESpace()->FEColl()->GetContType();
|
||||
|
||||
AddL2Error(gf,nullptr,vector_u);
|
||||
double DErr = 0.0;
|
||||
bool derivative = false;
|
||||
if (curl)
|
||||
{
|
||||
DErr = gf->ComputeCurlError(curl);
|
||||
CoeffDNorm = GetNorm(gf,nullptr,curl);
|
||||
derivative = true;
|
||||
}
|
||||
else if (div)
|
||||
{
|
||||
DErr = gf->ComputeDivError(div);
|
||||
// update coefficient norm
|
||||
CoeffDNorm = GetNorm(gf,div,nullptr);
|
||||
derivative = true;
|
||||
}
|
||||
if (derivative)
|
||||
{
|
||||
double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1] + DErr*DErr);
|
||||
DErrors.Append(DErr);
|
||||
EnErrors.Append(err);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val = (dcounter) ? log(DErrors[dcounter-1]/DErr)/log(2.0) : 0.0;
|
||||
double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
|
||||
DRates.Append(val);
|
||||
EnRates.Append(eval);
|
||||
dcounter++;
|
||||
MFEM_VERIFY(counter == dcounter,
|
||||
"Number of added solutions and derivatives do not match")
|
||||
}
|
||||
}
|
||||
|
||||
void ConvergenceStudy::Print(bool relative, std::ostream &out)
|
||||
{
|
||||
if (print_flag)
|
||||
{
|
||||
std::string title = (relative) ? "Relative " : "Absolute ";
|
||||
out << "\n";
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::setw(21) << title << "L2 Error " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13) << "Error ";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
double d = (relative) ? CoeffNorm : 1.0;
|
||||
for (int i =0; i<counter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << L2Errors[i]/d << std::setw(13)
|
||||
<< std::fixed << L2Rates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
if (dcounter == counter)
|
||||
{
|
||||
std::string dname;
|
||||
switch (cont_type)
|
||||
{
|
||||
case 0: dname = "Grad"; break;
|
||||
case 1: dname = "Curl"; break;
|
||||
case 2: dname = "Div"; break;
|
||||
case 3: dname = "DG Grad"; break;
|
||||
default: break;
|
||||
}
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::setw(21) << title << dname << " Error " << "\n";
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::right<<std::setw(11)<< "DOFs "<< std::setw(13) << "Error";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
d = (relative) ? CoeffDNorm : 1.0;
|
||||
for (int i =0; i<dcounter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << DErrors[i]/d << std::setw(13)
|
||||
<< std::fixed << DRates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
switch (cont_type)
|
||||
{
|
||||
case 0: dname = "H1"; break;
|
||||
case 1: dname = "H(Curl)"; break;
|
||||
case 2: dname = "H(Div)"; break;
|
||||
case 3: dname = "DG H1"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (dcounter)
|
||||
{
|
||||
d = (relative) ?
|
||||
sqrt(CoeffNorm*CoeffNorm + CoeffDNorm*CoeffDNorm):1.0;
|
||||
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::setw(21) << title << dname << " Error " << "\n";
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
|
||||
out << "Error ";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
for (int i =0; i<dcounter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << EnErrors[i]/d << std::setw(13)
|
||||
<< std::fixed << EnRates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
if (cont_type == 3 && fcounter)
|
||||
{
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << " DG Face Jump Error " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
|
||||
out << "Error ";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
for (int i =0; i<fcounter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << DGFaceErrors[i] << std::setw(13)
|
||||
<< std::fixed << DGFaceRates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_CONVERGENCE
|
||||
#define MFEM_CONVERGENCE
|
||||
|
||||
#include "../linalg/linalg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "pgridfunc.hpp"
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** @brief Class to compute error and convergence rates.
|
||||
It supports H1, H(curl) (ND elements), H(div) (RT elements) and L2 (DG).
|
||||
|
||||
For "smooth enough" solutions the Galerkin error measured in the appropriate
|
||||
norm satisfies || u - u_h || ~ h^k
|
||||
|
||||
Here, k is called the asymptotic rate of convergence
|
||||
|
||||
For successive uniform h-refinements the rate can be estimated by
|
||||
k = log(||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
*/
|
||||
class ConvergenceStudy
|
||||
{
|
||||
private:
|
||||
// counters for solutions/derivatives
|
||||
int counter=0;
|
||||
int dcounter=0;
|
||||
int fcounter=0;
|
||||
|
||||
// space continuity type
|
||||
int cont_type=-1;
|
||||
|
||||
// printing flag for helpful for MPI calls
|
||||
int print_flag=1;
|
||||
|
||||
// exact solution and derivatives
|
||||
double CoeffNorm;
|
||||
double CoeffDNorm;
|
||||
|
||||
// Arrays to store error/rates
|
||||
Array<double> L2Errors, DGFaceErrors, DErrors, EnErrors;
|
||||
Array<double> L2Rates, DGFaceRates, DRates, EnRates;
|
||||
Array<int> ndofs;
|
||||
|
||||
void AddL2Error(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *vector_u);
|
||||
void AddGf(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad=nullptr,
|
||||
Coefficient *ell_coeff=nullptr, double Nu=1.0);
|
||||
void AddGf(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
VectorCoefficient *curl, Coefficient *div);
|
||||
// returns the L2-norm of scalar_u or vector_u
|
||||
double GetNorm(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *vector_u);
|
||||
|
||||
public:
|
||||
|
||||
/// Clear any internal data
|
||||
void Reset();
|
||||
|
||||
/// Add L2 GridFunction, the exact solution and possibly its gradient and/or
|
||||
/// DG face jumps parameters
|
||||
void AddL2GridFunction(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad=nullptr,
|
||||
Coefficient *ell_coeff=nullptr, double Nu=1.0)
|
||||
{
|
||||
AddGf(gf, scalar_u, grad, ell_coeff, Nu);
|
||||
}
|
||||
|
||||
/// Add H1 GridFunction, the exact solution and possibly its gradient
|
||||
void AddH1GridFunction(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad=nullptr)
|
||||
{
|
||||
AddGf(gf, scalar_u, grad);
|
||||
}
|
||||
|
||||
/// Add H(curl) GridFunction, the exact solution and possibly its curl
|
||||
void AddHcurlGridFunction(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
VectorCoefficient *curl=nullptr)
|
||||
{
|
||||
AddGf(gf, vector_u, curl, nullptr);
|
||||
}
|
||||
|
||||
/// Add H(div) GridFunction, the exact solution and possibly its div
|
||||
void AddHdivGridFunction(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
Coefficient *div=nullptr)
|
||||
{
|
||||
AddGf(gf,vector_u, nullptr, div);
|
||||
}
|
||||
|
||||
/// Get the L2 error at step n
|
||||
double GetL2Error(int n)
|
||||
{
|
||||
MFEM_VERIFY( n <= counter,"Step out of bounds")
|
||||
return L2Errors[n];
|
||||
}
|
||||
|
||||
/// Get all L2 errors
|
||||
void GetL2Errors(Array<double> & L2Errors_)
|
||||
{
|
||||
L2Errors_ = L2Errors;
|
||||
}
|
||||
|
||||
/// Get the Grad/Curl/Div error at step n
|
||||
double GetDError(int n)
|
||||
{
|
||||
MFEM_VERIFY(n <= dcounter,"Step out of bounds")
|
||||
return DErrors[n];
|
||||
}
|
||||
|
||||
/// Get all Grad/Curl/Div errors
|
||||
void GetDErrors(Array<double> & DErrors_)
|
||||
{
|
||||
DErrors_ = DErrors;
|
||||
}
|
||||
|
||||
/// Get the DGFaceJumps error at step n
|
||||
double GetDGFaceJumpsError(int n)
|
||||
{
|
||||
MFEM_VERIFY(n<= fcounter,"Step out of bounds")
|
||||
return DGFaceErrors[n];
|
||||
}
|
||||
|
||||
/// Get all DGFaceJumps errors
|
||||
void GetDGFaceJumpsErrors(Array<double> & DGFaceErrors_)
|
||||
{
|
||||
DGFaceErrors_ = DGFaceErrors;
|
||||
}
|
||||
|
||||
/// Print rates and errors
|
||||
void Print(bool relative = false, std::ostream &out = mfem::out);
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_CONVERGENCE
|
||||
@@ -563,8 +563,6 @@ void VisItDataCollection::LoadVisItRootFile(const std::string& root_name)
|
||||
|
||||
void VisItDataCollection::LoadMesh()
|
||||
{
|
||||
// GetMeshFileName() uses 'serial', so we need to set it in advance.
|
||||
serial = (format == SERIAL_FORMAT);
|
||||
std::string mesh_fname = GetMeshFileName();
|
||||
named_ifgzstream file(mesh_fname);
|
||||
// TODO: in parallel, check for errors on all processors
|
||||
|
||||
-36
@@ -139,12 +139,6 @@ void FiniteElement::Project (
|
||||
mfem_error ("FiniteElement::Project (...) (vector) is not overloaded !");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{
|
||||
mfem_error ("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{
|
||||
@@ -931,23 +925,6 @@ void VectorFiniteElement::Project_RT(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::Project_RT(
|
||||
const double *nk, const Array<int> &d2n,
|
||||
Vector &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
const int sdim = Trans.GetSpaceDim();
|
||||
const bool square_J = (dim == sdim);
|
||||
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
// dof_k = nk^t adj(J) xk
|
||||
Vector vk(vc.GetData()+k*sdim, sdim);
|
||||
dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim);
|
||||
if (!square_J) { dofs(k) /= Trans.Weight(); }
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::ProjectMatrixCoefficient_RT(
|
||||
const double *nk, const Array<int> &d2n,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
@@ -1124,19 +1101,6 @@ void VectorFiniteElement::Project_ND(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::Project_ND(
|
||||
const double *tk, const Array<int> &d2t,
|
||||
Vector &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
Vector vk(vc.GetData()+k*dim, dim);
|
||||
// dof_k = xk^t J tk
|
||||
dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::ProjectMatrixCoefficient_ND(
|
||||
const double *tk, const Array<int> &d2t,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
|
||||
+6
-48
@@ -504,21 +504,14 @@ public:
|
||||
/** @brief Given a coefficient and a transformation, compute its projection
|
||||
(approximation) in the local finite dimensional space in terms
|
||||
of the degrees of freedom. */
|
||||
virtual void Project(Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
virtual void Project (Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
/** @brief Given a vector coefficient and a transformation, compute its
|
||||
projection (approximation) in the local finite dimensional space
|
||||
in terms of the degrees of freedom. (VectorFiniteElements) */
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
/** @brief Given a vector of values at the finite element nodes and a
|
||||
transformation, compute its projection (approximation) in the local
|
||||
finite dimensional space in terms of the degrees of freedom. Valid for
|
||||
VectorFiniteElements. */
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
/** @brief Given a matrix coefficient and a transformation, compute an
|
||||
approximation ("projection") in the local finite dimensional space in
|
||||
@@ -804,12 +797,7 @@ protected:
|
||||
VectorCoefficient &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Projects the vector of values given at FE nodes to RT space
|
||||
void Project_RT(const double *nk, const Array<int> &d2n,
|
||||
Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Project the rows of the matrix coefficient in an RT space
|
||||
// project the rows of the matrix coefficient in an RT space
|
||||
void ProjectMatrixCoefficient_RT(
|
||||
const double *nk, const Array<int> &d2n,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
|
||||
@@ -837,12 +825,7 @@ protected:
|
||||
VectorCoefficient &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Projects the vector of values given at FE nodes to ND space
|
||||
void Project_ND(const double *tk, const Array<int> &d2t,
|
||||
Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Project the rows of the matrix coefficient in an ND space
|
||||
/// project the rows of the matrix coefficient in an ND space
|
||||
void ProjectMatrixCoefficient_ND(
|
||||
const double *tk, const Array<int> &d2t,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
|
||||
@@ -2706,9 +2689,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2767,9 +2747,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2821,9 +2798,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2881,9 +2855,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2943,10 +2914,6 @@ public:
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
@@ -3006,9 +2973,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
@@ -3060,9 +3024,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
@@ -3119,9 +3080,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "eltrans.hpp"
|
||||
#include "coefficient.hpp"
|
||||
#include "complex_fem.hpp"
|
||||
#include "convergence.hpp"
|
||||
#include "lininteg.hpp"
|
||||
#include "nonlininteg.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
|
||||
@@ -440,7 +440,6 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
|
||||
if (marker[i]) { num_marked++; }
|
||||
}
|
||||
list.SetSize(0);
|
||||
list.HostWrite();
|
||||
list.Reserve(num_marked);
|
||||
for (int i = 0; i < marker.Size(); i++)
|
||||
{
|
||||
@@ -452,9 +451,7 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
|
||||
void FiniteElementSpace::ListToMarker(const Array<int> &list, int marker_size,
|
||||
Array<int> &marker, int mark_val)
|
||||
{
|
||||
list.HostRead(); // make sure we can read the array on host
|
||||
marker.SetSize(marker_size);
|
||||
marker.HostWrite();
|
||||
marker = 0;
|
||||
for (int i = 0; i < list.Size(); i++)
|
||||
{
|
||||
|
||||
+126
-247
@@ -199,7 +199,8 @@ void GridFunction::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
if (f != fes) { Destroy(); }
|
||||
fes = f;
|
||||
v.UseDevice(true);
|
||||
this->Vector::MakeRef(v, v_offset, fes->GetVSize());
|
||||
NewMemoryAndSize(Memory<double>(v.GetMemory(), v_offset, fes->GetVSize()),
|
||||
fes->GetVSize(), true);
|
||||
sequence = fes->GetSequence();
|
||||
}
|
||||
|
||||
@@ -1833,19 +1834,6 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
|
||||
ImposeBounds(i, weights, minv, maxv);
|
||||
}
|
||||
|
||||
void GridFunction::RestrictConforming()
|
||||
{
|
||||
const SparseMatrix *R = fes->GetRestrictionMatrix();
|
||||
const Operator *P = fes->GetProlongationMatrix();
|
||||
|
||||
if (P && R)
|
||||
{
|
||||
Vector tmp(R->Height());
|
||||
R->Mult(*this, tmp);
|
||||
P->Mult(tmp, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::GetNodalValues(Vector &nval, int vdim) const
|
||||
{
|
||||
int i, j;
|
||||
@@ -2614,7 +2602,11 @@ double GridFunction::ComputeL2Error(
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
if (error < 0.0)
|
||||
{
|
||||
return -sqrt(-error);
|
||||
}
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeL2Error(
|
||||
@@ -2655,199 +2647,94 @@ double GridFunction::ComputeL2Error(
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double error = 0.0;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
Vector grad;
|
||||
int intorder;
|
||||
int dim = fes->GetMesh()->SpaceDimension();
|
||||
Vector vec(dim);
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
if (error < 0.0)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3; // <--------
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint(&ip);
|
||||
GetGradient(*Tr,grad);
|
||||
exgrad->Eval(vec,*Tr,ip);
|
||||
vec-=grad;
|
||||
error += ip.weight * Tr->Weight() * (vec * vec);
|
||||
}
|
||||
return -sqrt(-error);
|
||||
}
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[]) const
|
||||
double GridFunction::ComputeH1Error(
|
||||
Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coeff, double Nu, int norm_type) const
|
||||
{
|
||||
double error = 0.0;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
Vector curl;
|
||||
int intorder;
|
||||
int dim = fes->GetMesh()->SpaceDimension();
|
||||
int n = (dim == 3) ? dim : 1;
|
||||
Vector vec(n);
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3;
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint(&ip);
|
||||
GetCurl(*Tr,curl);
|
||||
excurl->Eval(vec,*Tr,ip);
|
||||
vec-=curl;
|
||||
error += ip.weight * Tr->Weight() * ( vec * vec );
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeDivError(
|
||||
Coefficient *exdiv, const IntegrationRule *irs[]) const
|
||||
{
|
||||
double error = 0.0, a;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
int intorder;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3;
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint (&ip);
|
||||
a = GetDivergence(*Tr) - exdiv->Eval(*Tr, ip);
|
||||
error += ip.weight * Tr->Weight() * a * a;
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff, double Nu,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
int fdof, dim, intorder, k;
|
||||
// assuming vdim is 1
|
||||
int i, fdof, dim, intorder, j, k;
|
||||
Mesh *mesh;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
FaceElementTransformations *face_elem_transf;
|
||||
Vector shape, el_dofs, err_val, ell_coeff_val;
|
||||
Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
|
||||
DenseMatrix dshape, dshapet, Jinv;
|
||||
Array<int> vdofs;
|
||||
IntegrationPoint eip;
|
||||
double error = 0.0;
|
||||
|
||||
mesh = fes->GetMesh();
|
||||
dim = mesh->Dimension();
|
||||
e_grad.SetSize(dim);
|
||||
a_grad.SetSize(dim);
|
||||
Jinv.SetSize(dim);
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); i++)
|
||||
{
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
|
||||
int i1 = face_elem_transf->Elem1No;
|
||||
int i2 = face_elem_transf->Elem2No;
|
||||
intorder = fes->GetFE(i1)->GetOrder();
|
||||
if (i2 >= 0)
|
||||
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
intorder = 2 * intorder; // <-------------
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
if (norm_type & 1)
|
||||
for (i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
ir = irs[face_elem_transf->GetGeometryType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
|
||||
}
|
||||
err_val.SetSize(ir->GetNPoints());
|
||||
ell_coeff_val.SetSize(ir->GetNPoints());
|
||||
// side 1
|
||||
transf = face_elem_transf->Elem1;
|
||||
fe = fes->GetFE(i1);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i1, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
|
||||
fe->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
|
||||
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
|
||||
}
|
||||
if (i2 >= 0)
|
||||
{
|
||||
// side 2
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
|
||||
transf = face_elem_transf->Elem2;
|
||||
fe = fes->GetFE(i2);
|
||||
fe = fes->GetFE(i);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i2, vdofs);
|
||||
transf = mesh->GetElementTransformation(i);
|
||||
el_dofs.SetSize(fdof);
|
||||
dshape.SetSize(fdof, dim);
|
||||
dshapet.SetSize(fdof, dim);
|
||||
intorder = 2 * fe->GetOrder(); // <----------
|
||||
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
fe->CalcDShape(ip, dshape);
|
||||
transf->SetIntPoint(&ip);
|
||||
exgrad->Eval(e_grad, *transf, ip);
|
||||
CalcInverse(transf->Jacobian(), Jinv);
|
||||
Mult(dshape, Jinv, dshapet);
|
||||
dshapet.MultTranspose(el_dofs, a_grad);
|
||||
e_grad -= a_grad;
|
||||
error += (ip.weight * transf->Weight() *
|
||||
ell_coeff->Eval(*transf, ip) *
|
||||
(e_grad * e_grad));
|
||||
}
|
||||
}
|
||||
|
||||
if (norm_type & 2)
|
||||
for (i = 0; i < mesh->GetNFaces(); i++)
|
||||
{
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
|
||||
int i1 = face_elem_transf->Elem1No;
|
||||
int i2 = face_elem_transf->Elem2No;
|
||||
intorder = fes->GetFE(i1)->GetOrder();
|
||||
if (i2 >= 0)
|
||||
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
intorder = 2 * intorder; // <-------------
|
||||
const IntegrationRule &ir =
|
||||
IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
|
||||
err_val.SetSize(ir.GetNPoints());
|
||||
ell_coeff_val.SetSize(ir.GetNPoints());
|
||||
// side 1
|
||||
transf = face_elem_transf->Elem1;
|
||||
fe = fes->GetFE(i1);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i1, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
@@ -2859,69 +2746,60 @@ double GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
|
||||
face_elem_transf->Loc1.Transform(ir.IntPoint(j), eip);
|
||||
fe->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
|
||||
ell_coeff_val(j) *= 0.5;
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
|
||||
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
|
||||
}
|
||||
if (i2 >= 0)
|
||||
{
|
||||
// side 2
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
|
||||
transf = face_elem_transf->Elem2;
|
||||
fe = fes->GetFE(i2);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i2, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc2.Transform(ir.IntPoint(j), eip);
|
||||
fe->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
|
||||
ell_coeff_val(j) *= 0.5;
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
}
|
||||
}
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
|
||||
transf = face_elem_transf;
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
error += (ip.weight * Nu * ell_coeff_val(j) *
|
||||
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
}
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
|
||||
transf = face_elem_transf;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
error += (ip.weight * Nu * ell_coeff_val(j) *
|
||||
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
|
||||
if (error < 0.0)
|
||||
{
|
||||
return -sqrt(-error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeH1Error(Coefficient *exsol,
|
||||
VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coef, double Nu,
|
||||
int norm_type) const
|
||||
{
|
||||
double error1 = 0.0;
|
||||
double error2 = 0.0;
|
||||
if (norm_type & 1) { error1 = GridFunction::ComputeGradError(exgrad); }
|
||||
if (norm_type & 2) { error2 = GridFunction::ComputeDGFaceJumpError(exsol,ell_coef,Nu); }
|
||||
|
||||
return sqrt(error1 * error1 + error2 * error2);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeH1Error(Coefficient *exsol,
|
||||
VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,irs);
|
||||
double GradError = ComputeGradError(exgrad,irs);
|
||||
return sqrt(L2error*L2error + GradError*GradError);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
|
||||
double DivError = ComputeDivError(exdiv,irs);
|
||||
return sqrt(L2error*L2error + DivError*DivError);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
|
||||
double CurlError = ComputeCurlError(excurl,irs);
|
||||
return sqrt(L2error*L2error + CurlError*CurlError);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeMaxError(
|
||||
@@ -2977,6 +2855,7 @@ double GridFunction::ComputeMaxError(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,11 +334,6 @@ public:
|
||||
void ImposeBounds(int i, const Vector &weights,
|
||||
double _min = 0.0, double _max = infinity());
|
||||
|
||||
/** On a non-conforming mesh, make sure the function lies in the conforming
|
||||
space by multiplying with R and then with P, the conforming restriction
|
||||
and prolongation matrices of the space, respectively. */
|
||||
void RestrictConforming();
|
||||
|
||||
/** @brief Project the @a src GridFunction to @a this GridFunction, both of
|
||||
which must be on the same mesh. */
|
||||
/** The current implementation assumes that all elements use the same
|
||||
@@ -427,7 +422,6 @@ public:
|
||||
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
Array<int> &bdr_attr);
|
||||
|
||||
|
||||
virtual double ComputeL2Error(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{ return ComputeLpError(2.0, exsol, NULL, irs); }
|
||||
@@ -439,50 +433,10 @@ public:
|
||||
const IntegrationRule *irs[] = NULL,
|
||||
Array<int> *elems = NULL) const;
|
||||
|
||||
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
|
||||
virtual double ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
|
||||
virtual double ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||div u_ex - div u_h||_L2 for RT elements
|
||||
virtual double ComputeDivError(Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements
|
||||
virtual double ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
double Nu,
|
||||
const IntegrationRule *irs[] = NULL)
|
||||
const;
|
||||
|
||||
/** This method is kept for backward compatibility.
|
||||
|
||||
Returns either the H1-seminorm, or the DG face jumps error, or both
|
||||
depending on norm_type = 1, 2, 3. Additional arguments for the DG face
|
||||
jumps norm: ell_coeff: mesh-depended coefficient (weight) Nu: scalar
|
||||
constant weight */
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coef, double Nu,
|
||||
int norm_type) const;
|
||||
|
||||
/// Returns the error measured in H1-norm for H1 elements or in "broken"
|
||||
/// H1-norm for L2 elements
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the error measured in H(div)-norm for RT elements
|
||||
virtual double ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the error measured in H(curl)-norm for ND elements
|
||||
virtual double ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
virtual double ComputeMaxError(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
|
||||
+86
-403
@@ -29,13 +29,10 @@ namespace mfem
|
||||
{
|
||||
|
||||
FindPointsGSLIB::FindPointsGSLIB()
|
||||
: mesh(NULL), meshsplit(NULL), ir_simplex(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC)
|
||||
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
|
||||
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
|
||||
{
|
||||
gsl_comm = new comm;
|
||||
cr = new crystal;
|
||||
#ifdef MFEM_USE_MPI
|
||||
int initialized;
|
||||
MPI_Initialized(&initialized);
|
||||
@@ -50,20 +47,15 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
FindPointsGSLIB::~FindPointsGSLIB()
|
||||
{
|
||||
delete gsl_comm;
|
||||
delete cr;
|
||||
delete ir_simplex;
|
||||
delete meshsplit;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm _comm)
|
||||
: mesh(NULL), meshsplit(NULL), ir_simplex(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC)
|
||||
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
|
||||
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
|
||||
{
|
||||
gsl_comm = new comm;
|
||||
cr = new crystal;
|
||||
comm_init(gsl_comm, _comm);
|
||||
}
|
||||
#endif
|
||||
@@ -78,7 +70,6 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
|
||||
// call FreeData if FindPointsGSLIB::Setup has been called already
|
||||
if (setupflag) { FreeData(); }
|
||||
|
||||
crystal_init(cr, gsl_comm);
|
||||
mesh = &m;
|
||||
dim = mesh->Dimension();
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
|
||||
@@ -122,16 +113,14 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
|
||||
setupflag = true;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
void FindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
Array<unsigned int> &codes,
|
||||
Array<unsigned int> &proc_ids,
|
||||
Array<unsigned int> &elem_ids,
|
||||
Vector &ref_pos, Vector &dist)
|
||||
{
|
||||
MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
|
||||
points_cnt = point_pos.Size() / dim;
|
||||
gsl_code.SetSize(points_cnt);
|
||||
gsl_proc.SetSize(points_cnt);
|
||||
gsl_elem.SetSize(points_cnt);
|
||||
gsl_ref.SetSize(points_cnt * dim);
|
||||
gsl_dist.SetSize(points_cnt);
|
||||
|
||||
const int points_cnt = point_pos.Size() / dim;
|
||||
if (dim == 2)
|
||||
{
|
||||
const double *xv_base[2];
|
||||
@@ -140,11 +129,11 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
unsigned xv_stride[2];
|
||||
xv_stride[0] = sizeof(double);
|
||||
xv_stride[1] = sizeof(double);
|
||||
findpts_2(gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
gsl_dist.GetData(), sizeof(double),
|
||||
findpts_2(codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
dist.GetData(), sizeof(double),
|
||||
xv_base, xv_stride, points_cnt, fdata2D);
|
||||
}
|
||||
else
|
||||
@@ -157,27 +146,25 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
xv_stride[0] = sizeof(double);
|
||||
xv_stride[1] = sizeof(double);
|
||||
xv_stride[2] = sizeof(double);
|
||||
findpts_3(gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
gsl_dist.GetData(), sizeof(double),
|
||||
findpts_3(codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
dist.GetData(), sizeof(double),
|
||||
xv_base, xv_stride, points_cnt, fdata3D);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the element number and reference position to 0 for points not found
|
||||
for (int i = 0; i < points_cnt; i++)
|
||||
{
|
||||
if (gsl_code[i] == 2)
|
||||
{
|
||||
gsl_elem[i] = 0;
|
||||
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
|
||||
}
|
||||
}
|
||||
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
{
|
||||
const int points_cnt = point_pos.Size() / dim;
|
||||
gsl_code.SetSize(points_cnt);
|
||||
gsl_proc.SetSize(points_cnt);
|
||||
gsl_elem.SetSize(points_cnt);
|
||||
gsl_ref.SetSize(points_cnt * dim);
|
||||
gsl_dist.SetSize(points_cnt);
|
||||
|
||||
// Map element number for simplices, and ref_pos from [-1,1] to [0,1] for
|
||||
// both simplices and quads.
|
||||
MapRefPosAndElemIndices();
|
||||
FindPoints(point_pos, gsl_code, gsl_proc, gsl_elem, gsl_ref, gsl_dist);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
|
||||
@@ -191,24 +178,72 @@ void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
|
||||
FindPoints(point_pos);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
|
||||
Array<unsigned int> &proc_ids,
|
||||
Array<unsigned int> &elem_ids,
|
||||
Vector &ref_pos, const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
|
||||
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
|
||||
GridFunction field_in_scalar(&ind_fes);
|
||||
Vector node_vals;
|
||||
|
||||
const int ncomp = field_in.FESpace()->GetVDim(),
|
||||
points_fld = field_in.Size() / ncomp,
|
||||
points_cnt = codes.Size();
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
const int dataptrin = i*points_fld,
|
||||
dataptrout = i*points_cnt;
|
||||
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
|
||||
GetNodeValues(field_in_scalar, node_vals);
|
||||
|
||||
if (dim==2)
|
||||
{
|
||||
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
|
||||
codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
|
||||
codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out)
|
||||
{
|
||||
FindPoints(point_pos);
|
||||
Interpolate(field_in, field_out);
|
||||
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out)
|
||||
{
|
||||
FindPoints(m, point_pos);
|
||||
Interpolate(field_in, field_out);
|
||||
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::FreeData()
|
||||
{
|
||||
if (!setupflag) { return; }
|
||||
crystal_free(cr);
|
||||
if (dim == 2)
|
||||
{
|
||||
findpts_free_2(fdata2D);
|
||||
@@ -217,13 +252,13 @@ void FindPointsGSLIB::FreeData()
|
||||
{
|
||||
findpts_free_3(fdata3D);
|
||||
}
|
||||
setupflag = false;
|
||||
gsl_code.DeleteAll();
|
||||
gsl_proc.DeleteAll();
|
||||
gsl_elem.DeleteAll();
|
||||
gsl_mesh.Destroy();
|
||||
gsl_ref.Destroy();
|
||||
gsl_dist.Destroy();
|
||||
setupflag = false;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::GetNodeValues(const GridFunction &gf_in,
|
||||
@@ -323,8 +358,9 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
|
||||
const Geometry::Type gt = fe->GetGeomType();
|
||||
const GridFunction *nodes = mesh->GetNodes();
|
||||
Mesh *meshsplit = NULL;
|
||||
const int NE = mesh->GetNE();
|
||||
int NEsplit = 0;
|
||||
int NEsplit = -1;
|
||||
|
||||
// Split the reference element into a reference submesh of quads or hexes.
|
||||
if (gt == Geometry::TRIANGLE)
|
||||
@@ -480,361 +516,8 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
|
||||
pt_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::MapRefPosAndElemIndices()
|
||||
{
|
||||
gsl_mfem_ref = gsl_ref;
|
||||
gsl_mfem_elem = gsl_elem;
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
|
||||
const Geometry::Type gt = fe->GetGeomType();
|
||||
int NEsplit = 0;
|
||||
|
||||
gsl_mfem_ref -= -1.; // map [-1, 1] to
|
||||
gsl_mfem_ref *= 0.5; // [0, 1]
|
||||
if (gt == Geometry::SQUARE || gt == Geometry::CUBE) { return; }
|
||||
|
||||
H1_FECollection feclin(1, dim);
|
||||
FiniteElementSpace nodal_fes_lin(meshsplit, &feclin, dim);
|
||||
GridFunction gf_lin(&nodal_fes_lin);
|
||||
|
||||
if (gt == Geometry::TRIANGLE)
|
||||
{
|
||||
const double quad_v[7][2] =
|
||||
{
|
||||
{0, 0}, {0.5, 0}, {1, 0}, {0, 0.5},
|
||||
{1./3., 1./3.}, {0.5, 0.5}, {0, 1}
|
||||
};
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
for (int j = 0; j < gf_lin.Size()/dim; j++)
|
||||
{
|
||||
gf_lin(j+k*gf_lin.Size()/dim) = quad_v[j][k];
|
||||
}
|
||||
}
|
||||
NEsplit = 3;
|
||||
}
|
||||
else if (gt == Geometry::TETRAHEDRON)
|
||||
{
|
||||
const double hex_v[15][3] =
|
||||
{
|
||||
{0, 0, 0.}, {1, 0., 0.}, {0., 1., 0.}, {0, 0., 1.},
|
||||
{0.5, 0., 0.}, {0.5, 0.5, 0.}, {0., 0.5, 0.},
|
||||
{0., 0., 0.5}, {0.5, 0., 0.5}, {0., 0.5, 0.5},
|
||||
{1./3., 0., 1./3.}, {1./3., 1./3., 1./3.}, {0, 1./3., 1./3.},
|
||||
{1./3., 1./3., 0}, {0.25, 0.25, 0.25}
|
||||
};
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
for (int j = 0; j < gf_lin.Size()/dim; j++)
|
||||
{
|
||||
gf_lin(j+k*gf_lin.Size()/dim) = hex_v[j][k];
|
||||
}
|
||||
}
|
||||
NEsplit = 4;
|
||||
}
|
||||
else if (gt == Geometry::PRISM)
|
||||
{
|
||||
const double hex_v[14][3] =
|
||||
{
|
||||
{0, 0, 0}, {0.5, 0, 0}, {1, 0, 0}, {0, 0.5, 0},
|
||||
{1./3., 1./3., 0}, {0.5, 0.5, 0}, {0, 1, 0},
|
||||
{0, 0, 1}, {0.5, 0, 1}, {1, 0, 1}, {0, 0.5, 1},
|
||||
{1./3., 1./3., 1}, {0.5, 0.5, 1}, {0, 1, 1}
|
||||
};
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
for (int j = 0; j < gf_lin.Size()/dim; j++)
|
||||
{
|
||||
gf_lin(j+k*gf_lin.Size()/dim) = hex_v[j][k];
|
||||
}
|
||||
}
|
||||
NEsplit = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Element type not currently supported.");
|
||||
}
|
||||
|
||||
// Simplices are split into quads/hexes for GSLIB. For MFEM, we need to find
|
||||
// the original element number and map the rst from micro to macro element.
|
||||
for (int i = 0; i < points_cnt; i++)
|
||||
{
|
||||
if (gsl_code[i] == 2) { continue; }
|
||||
int local_elem = gsl_elem[i]%NEsplit;
|
||||
gsl_mfem_elem[i] = (gsl_elem[i] - local_elem)/NEsplit; // macro element number
|
||||
|
||||
IntegrationPoint ip;
|
||||
Vector mfem_ref(gsl_mfem_ref.GetData()+i*dim, dim);
|
||||
ip.Set2(mfem_ref.GetData());
|
||||
if (dim == 3) { ip.z = mfem_ref(2); }
|
||||
gf_lin.GetVectorValue(local_elem, ip, mfem_ref); // map to rst of macro element
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
const int gf_order = field_in.FESpace()->GetFE(0)->GetOrder(),
|
||||
mesh_order = mesh->GetNodalFESpace()->GetFE(0)->GetOrder();
|
||||
|
||||
const FiniteElementCollection *fec_in = field_in.FESpace()->FEColl();
|
||||
const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
|
||||
const L2_FECollection *fec_l2 = dynamic_cast<const L2_FECollection *>(fec_in);
|
||||
|
||||
if (fec_h1 && gf_order == mesh_order &&
|
||||
fec_h1->GetBasisType() == BasisType::GaussLobatto)
|
||||
{
|
||||
InterpolateH1(field_in, field_out);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
InterpolateGeneral(field_in, field_out);
|
||||
if (!fec_l2 || avgtype == AvgType::NONE) { return; }
|
||||
}
|
||||
|
||||
// For points on element borders, project the L2 GridFunction to H1 and
|
||||
// re-interpolate.
|
||||
if (fec_l2)
|
||||
{
|
||||
Array<int> indl2;
|
||||
for (int i = 0; i < points_cnt; i++)
|
||||
{
|
||||
if (gsl_code[i] == 1) { indl2.Append(i); }
|
||||
}
|
||||
if (indl2.Size() == 0) { return; } // no points on element borders
|
||||
|
||||
Vector field_out_l2(field_out.Size());
|
||||
VectorGridFunctionCoefficient field_in_dg(&field_in);
|
||||
int gf_order_h1 = std::max(gf_order, 1); // H1 should be at least order 1
|
||||
H1_FECollection fec(gf_order_h1, dim);
|
||||
const int ncomp = field_in.FESpace()->GetVDim();
|
||||
FiniteElementSpace fes(mesh, &fec, ncomp);
|
||||
GridFunction field_in_h1(&fes);
|
||||
|
||||
if (avgtype == AvgType::ARITHMETIC)
|
||||
{
|
||||
field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::ARITHMETIC);
|
||||
}
|
||||
else if (avgtype == AvgType::HARMONIC)
|
||||
{
|
||||
field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::HARMONIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Invalid averaging type.");
|
||||
}
|
||||
|
||||
if (gf_order_h1 == mesh_order) // basis is GaussLobatto by default
|
||||
{
|
||||
InterpolateH1(field_in_h1, field_out_l2);
|
||||
}
|
||||
else
|
||||
{
|
||||
InterpolateGeneral(field_in_h1, field_out_l2);
|
||||
}
|
||||
|
||||
// Copy interpolated values for the points on element border
|
||||
for (int j = 0; j < ncomp; j++)
|
||||
{
|
||||
for (int i = 0; i < indl2.Size(); i++)
|
||||
{
|
||||
int idx = indl2[i] + j*points_cnt;
|
||||
field_out(idx) = field_out_l2(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::InterpolateH1(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
|
||||
GridFunction field_in_scalar(&ind_fes);
|
||||
Vector node_vals;
|
||||
|
||||
const int ncomp = field_in.FESpace()->GetVDim(),
|
||||
points_fld = field_in.Size() / ncomp,
|
||||
points_cnt = gsl_code.Size();
|
||||
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
field_out = default_interp_value;
|
||||
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
const int dataptrin = i*points_fld,
|
||||
dataptrout = i*points_cnt;
|
||||
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
|
||||
GetNodeValues(field_in_scalar, node_vals);
|
||||
|
||||
if (dim==2)
|
||||
{
|
||||
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
|
||||
gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
|
||||
gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
int ncomp = field_in.VectorDim(),
|
||||
nptorig = points_cnt,
|
||||
npt = points_cnt;
|
||||
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
field_out = default_interp_value;
|
||||
|
||||
if (gsl_comm->np == 1) // serial
|
||||
{
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
if (gsl_code[index] == 2) { continue; }
|
||||
IntegrationPoint ip;
|
||||
ip.Set2(gsl_mfem_ref.GetData()+index*dim);
|
||||
if (dim == 3) { ip.z = gsl_mfem_ref(index*dim + 2); }
|
||||
Vector localval(ncomp);
|
||||
field_in.GetVectorValue(gsl_mfem_elem[index], ip, localval);
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
field_out(index + i*npt) = localval(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // parallel
|
||||
{
|
||||
// Determine number of points to be sent
|
||||
int nptsend = 0;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
if (gsl_code[index] != 2) { nptsend +=1; }
|
||||
}
|
||||
|
||||
// Pack data to send via crystal router
|
||||
struct array *outpt = new array;
|
||||
struct out_pt { double r[3], ival; uint index, el, proc; };
|
||||
struct out_pt *pt;
|
||||
array_init(struct out_pt, outpt, nptsend);
|
||||
outpt->n=nptsend;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
if (gsl_code[index] == 2) { continue; }
|
||||
for (int d = 0; d < dim; ++d) { pt->r[d]= gsl_mfem_ref(index*dim + d); }
|
||||
pt->index = index;
|
||||
pt->proc = gsl_proc[index];
|
||||
pt->el = gsl_mfem_elem[index];
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data to target MPI ranks
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
|
||||
if (ncomp == 1)
|
||||
{
|
||||
// Interpolate the grid function
|
||||
npt = outpt->n;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
IntegrationPoint ip;
|
||||
ip.Set3(&pt->r[0]);
|
||||
pt->ival = field_in.GetValue(pt->el, ip, 1);
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data back to source MPI rank
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
npt = outpt->n;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
field_out(pt->index) = pt->ival;
|
||||
++pt;
|
||||
}
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
}
|
||||
else // ncomp > 1
|
||||
{
|
||||
// Interpolate data and store in a Vector
|
||||
npt = outpt->n;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
Vector vec_int_vals(npt*ncomp);
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
IntegrationPoint ip;
|
||||
ip.Set3(&pt->r[0]);
|
||||
Vector localval(vec_int_vals.GetData()+index*ncomp, ncomp);
|
||||
field_in.GetVectorValue(pt->el, ip, localval);
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Save index and proc data in a struct
|
||||
struct array *savpt = new array;
|
||||
struct sav_pt { uint index, proc; };
|
||||
struct sav_pt *spt;
|
||||
array_init(struct sav_pt, savpt, npt);
|
||||
savpt->n=npt;
|
||||
spt = (struct sav_pt *)savpt->ptr;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
spt->index = pt->index;
|
||||
spt->proc = pt->proc;
|
||||
++pt; ++spt;
|
||||
}
|
||||
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
|
||||
// Copy data from save struct to send struct and send component wise
|
||||
struct array *sendpt = new array;
|
||||
struct send_pt { double ival; uint index, proc; };
|
||||
struct send_pt *sdpt;
|
||||
for (int j = 0; j < ncomp; j++)
|
||||
{
|
||||
array_init(struct send_pt, sendpt, npt);
|
||||
sendpt->n=npt;
|
||||
spt = (struct sav_pt *)savpt->ptr;
|
||||
sdpt = (struct send_pt *)sendpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
sdpt->index = spt->index;
|
||||
sdpt->proc = spt->proc;
|
||||
sdpt->ival = vec_int_vals(j + index*ncomp);
|
||||
++sdpt; ++spt;
|
||||
}
|
||||
|
||||
sarray_transfer(struct send_pt, sendpt, proc, 1, cr);
|
||||
sdpt = (struct send_pt *)sendpt->ptr;
|
||||
for (int index = 0; index < nptorig; index++)
|
||||
{
|
||||
int idx = sdpt->index + j*nptorig;
|
||||
field_out(idx) = sdpt->ival;
|
||||
++sdpt;
|
||||
}
|
||||
array_free(sendpt);
|
||||
}
|
||||
array_free(savpt);
|
||||
delete sendpt;
|
||||
delete savpt;
|
||||
} // ncomp > 1
|
||||
} // parallel
|
||||
delete meshsplit;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+45
-93
@@ -20,66 +20,28 @@
|
||||
struct comm;
|
||||
struct findpts_data_2;
|
||||
struct findpts_data_3;
|
||||
struct array;
|
||||
struct crystal;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** \brief FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary
|
||||
* collection of points. There are three key functions in FindPointsGSLIB:
|
||||
*
|
||||
* 1. Setup - constructs the internal data structures of gslib.
|
||||
*
|
||||
* 2. FindPoints - for any given arbitrary set of points in physical space,
|
||||
* gslib finds the element number, MPI rank, and the reference space
|
||||
* coordinates inside the element that each point is located in. gslib also
|
||||
* returns a code that indicates whether the point was found inside an
|
||||
* element, on element border, or not found in the domain.
|
||||
*
|
||||
* 3. Interpolate - Interpolates any grid function at the points found using 2.
|
||||
*
|
||||
* FindPointsGSLIB provides interface to use these functions individually or
|
||||
* using a single call.
|
||||
*/
|
||||
class FindPointsGSLIB
|
||||
{
|
||||
public:
|
||||
enum AvgType {NONE, ARITHMETIC, HARMONIC}; // Average type for L2 functions
|
||||
|
||||
protected:
|
||||
Mesh *mesh, *meshsplit;
|
||||
IntegrationRule *ir_simplex; // IntegrationRule to split quads/hex -> simplex
|
||||
struct findpts_data_2 *fdata2D; // gslib's internal data
|
||||
struct findpts_data_3 *fdata3D; // gslib's internal data
|
||||
struct crystal *cr; // gslib's internal data
|
||||
struct comm *gsl_comm; // gslib's internal data
|
||||
int dim, points_cnt;
|
||||
Array<unsigned int> gsl_code, gsl_proc, gsl_elem, gsl_mfem_elem;
|
||||
Vector gsl_mesh, gsl_ref, gsl_dist, gsl_mfem_ref;
|
||||
bool setupflag; // flag to indicate whether gslib data has been setup
|
||||
double default_interp_value; // used for points that are not found in the mesh
|
||||
AvgType avgtype; // average type used for L2 functions
|
||||
Mesh *mesh;
|
||||
IntegrationRule *ir_simplex;
|
||||
struct findpts_data_2 *fdata2D;
|
||||
struct findpts_data_3 *fdata3D;
|
||||
int dim;
|
||||
Array<unsigned int> gsl_code, gsl_proc, gsl_elem;
|
||||
Vector gsl_mesh, gsl_ref, gsl_dist;
|
||||
bool setupflag;
|
||||
|
||||
struct comm *gsl_comm;
|
||||
|
||||
/// Get GridFunction from MFEM format to GSLIB format
|
||||
void GetNodeValues(const GridFunction &gf_in, Vector &node_vals);
|
||||
/// Get nodal coordinates from mesh to the format expected by GSLIB for quads
|
||||
/// and hexes
|
||||
void GetQuadHexNodalCoordinates();
|
||||
/// Convert simplices to quad/hexes and then get nodal coordinates for each
|
||||
/// split element into format expected by GSLIB
|
||||
void GetSimplexNodalCoordinates();
|
||||
|
||||
/// Use GSLIB for communication and interpolation
|
||||
void InterpolateH1(const GridFunction &field_in, Vector &field_out);
|
||||
/// Uses GSLIB Crystal Router for communication followed by MFEM's
|
||||
/// interpolation functions
|
||||
void InterpolateGeneral(const GridFunction &field_in, Vector &field_out);
|
||||
/// Map {r,s,t} coordinates from [-1,1] to [0,1] for MFEM. For simplices mesh
|
||||
/// find the original element number (that was split into micro quads/hexes
|
||||
/// by GetSimplexNodalCoordinates())
|
||||
void MapRefPosAndElemIndices();
|
||||
|
||||
public:
|
||||
FindPointsGSLIB();
|
||||
|
||||
@@ -102,37 +64,45 @@ public:
|
||||
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
|
||||
/** Searches positions given in physical space by @a point_pos. These positions
|
||||
must by ordered by nodes: (XXX...,YYY...,ZZZ).
|
||||
This function populates the following member variables:
|
||||
#gsl_code Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
#gsl_proc MPI proc ids where the points were found.
|
||||
#gsl_elem Element ids where the points were found.
|
||||
Defaults to 0 for points that were not found.
|
||||
#gsl_mfem_elem Element ids corresponding to MFEM-mesh where the points
|
||||
were found. #gsl_mfem_elem != #gsl_elem for simplices
|
||||
Defaults to 0 for points that were not found.
|
||||
#gsl_ref Reference coordinates of the found point.
|
||||
Ordered by vdim (XYZ,XYZ,XYZ...). Defaults to -1 for
|
||||
points that were not found. Note: the gslib reference
|
||||
frame is [-1,1].
|
||||
#gsl_mfem_ref Reference coordinates #gsl_ref mapped to [0,1].
|
||||
Defaults to 0 for points that were not found.
|
||||
#gsl_dist Distance between the sought and the found point
|
||||
in physical space. */
|
||||
/** Searches positions given in physical space by @a point_pos. All output
|
||||
Arrays and Vectors are expected to have the correct size.
|
||||
|
||||
@param[in] point_pos Positions to be found. Must by ordered by nodes
|
||||
(XXX...,YYY...,ZZZ).
|
||||
@param[out] codes Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
@param[out] proc_ids MPI proc ids where the points were found.
|
||||
@param[out] elem_ids Element ids where the points were found.
|
||||
@param[out] ref_pos Reference coordinates of the found point. Ordered
|
||||
by vdim (XYZ,XYZ,XYZ...).
|
||||
Note: the gslib reference frame is [-1,1].
|
||||
@param[out] dist Distance between the sought and the found point
|
||||
in physical space. */
|
||||
void FindPoints(const Vector &point_pos, Array<unsigned int> &codes,
|
||||
Array<unsigned int> &proc_ids, Array<unsigned int> &elem_ids,
|
||||
Vector &ref_pos, Vector &dist);
|
||||
void FindPoints(const Vector &point_pos);
|
||||
/// Setup FindPoints and search positions
|
||||
void FindPoints(Mesh &m, const Vector &point_pos, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12, const int npt_max = 256);
|
||||
|
||||
/** Interpolation of field values at prescribed reference space positions.
|
||||
|
||||
@param[in] codes Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
@param[in] proc_ids MPI proc ids where the points were found.
|
||||
@param[in] elem_ids Element ids where the points were found.
|
||||
@param[in] ref_pos Reference coordinates of the found point. Ordered
|
||||
by vdim (XYZ,XYZ,XYZ...).
|
||||
Note: the gslib reference frame is [-1,1].
|
||||
@param[in] field_in Function values that will be interpolated on the
|
||||
reference positions. Note: it is assumed that
|
||||
@a field_in is in H1 and in the same space as the
|
||||
mesh that was given to Setup().
|
||||
@param[out] field_out Interpolated values. For points that are not found
|
||||
the value is set to #default_interp_value. */
|
||||
@param[out] field_out Interpolated values. */
|
||||
void Interpolate(Array<unsigned int> &codes, Array<unsigned int> &proc_ids,
|
||||
Array<unsigned int> &elem_ids, Vector &ref_pos,
|
||||
const GridFunction &field_in, Vector &field_out);
|
||||
void Interpolate(const GridFunction &field_in, Vector &field_out);
|
||||
/** Search positions and interpolate */
|
||||
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
|
||||
@@ -141,45 +111,27 @@ public:
|
||||
void Interpolate(Mesh &m, const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out);
|
||||
|
||||
/// Average type to be used for L2 functions in-case a point is located at
|
||||
/// an element boundary where the function might be multi-valued.
|
||||
void SetL2AvgType(AvgType avgtype_) { avgtype = avgtype_; }
|
||||
|
||||
/// Set the default interpolation value for points that are not found in the
|
||||
/// mesh.
|
||||
void SetDefaultInterpolationValue(double interp_value_)
|
||||
{
|
||||
default_interp_value = interp_value_;
|
||||
}
|
||||
|
||||
/** Cleans up memory allocated internally by gslib.
|
||||
Note that in parallel, this must be called before MPI_Finalize(), as it
|
||||
calls MPI_Comm_free() for internal gslib communicators. */
|
||||
Note that in parallel, this must be called before MPI_Finalize(), as
|
||||
it calls MPI_Comm_free() for internal gslib communicators. */
|
||||
void FreeData();
|
||||
|
||||
/// Return code for each point searched by FindPoints: inside element (0), on
|
||||
/// element boundary (1), or not found (2).
|
||||
const Array<unsigned int> &GetCode() const { return gsl_code; }
|
||||
/// Return element number for each point found by FindPoints.
|
||||
const Array<unsigned int> &GetElem() const { return gsl_mfem_elem; }
|
||||
const Array<unsigned int> &GetElem() const { return gsl_elem; }
|
||||
/// Return MPI rank on which each point was found by FindPoints.
|
||||
const Array<unsigned int> &GetProc() const { return gsl_proc; }
|
||||
/// Return reference coordinates for each point found by FindPoints.
|
||||
const Vector &GetReferencePosition() const { return gsl_mfem_ref; }
|
||||
const Vector &GetReferencePosition() const { return gsl_ref; }
|
||||
/// Return distance Distance between the sought and the found point
|
||||
/// in physical space, for each point found by FindPoints.
|
||||
const Vector &GetDist() const { return gsl_dist; }
|
||||
|
||||
/// Return element number for each point found by FindPoints corresponding to
|
||||
/// GSLIB mesh. gsl_mfem_elem != gsl_elem for mesh with simplices.
|
||||
const Array<unsigned int> &GetGSLIBElem() const { return gsl_elem; }
|
||||
/// Return reference coordinates in [-1,1] (internal range in GSLIB) for each
|
||||
/// point found by FindPoints.
|
||||
const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_USE_GSLIB
|
||||
#endif //MFEM_USE_GSLIB
|
||||
|
||||
#endif // MFEM_GSLIB
|
||||
#endif //MFEM_GSLIB guard
|
||||
|
||||
+25
-149
@@ -35,9 +35,6 @@ extern Ceed ceed;
|
||||
|
||||
std::string ceed_path;
|
||||
|
||||
extern CeedBasisMap ceed_basis_map;
|
||||
extern CeedRestrMap ceed_restr_map;
|
||||
|
||||
}
|
||||
|
||||
void InitCeedCoeff(Coefficient* Q, CeedData* ptr)
|
||||
@@ -84,9 +81,10 @@ static CeedElemTopology GetCeedTopology(Geometry::Type geom)
|
||||
}
|
||||
}
|
||||
|
||||
static void InitCeedNonTensorBasis(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis)
|
||||
static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
@@ -99,73 +97,7 @@ static void InitCeedNonTensorBasis(const FiniteElementSpace &fes,
|
||||
Vector qweight(Q);
|
||||
Vector shape_i(P);
|
||||
DenseMatrix grad_i(P, dim);
|
||||
const Table &el_dof = fes.GetElementToDofTable();
|
||||
Array<int> tp_el_dof(el_dof.Size_of_connections());
|
||||
const TensorBasisElement * tfe =
|
||||
dynamic_cast<const TensorBasisElement *>(fe);
|
||||
if (tfe) // Lexicographic ordering using dof_map
|
||||
{
|
||||
const Array<int>& dof_map = tfe->GetDofMap();
|
||||
for (int i = 0; i < Q; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
qref(0,i) = ip.x;
|
||||
if (dim>1) { qref(1,i) = ip.y; }
|
||||
if (dim>2) { qref(2,i) = ip.z; }
|
||||
qweight(i) = ip.weight;
|
||||
fe->CalcShape(ip, shape_i);
|
||||
fe->CalcDShape(ip, grad_i);
|
||||
for (int j = 0; j < P; j++)
|
||||
{
|
||||
shape(j, i) = shape_i(dof_map[j]);
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
grad(j+i*P+d*Q*P) = grad_i(dof_map[j], d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Native ordering
|
||||
{
|
||||
for (int i = 0; i < Q; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
qref(0,i) = ip.x;
|
||||
if (dim>1) { qref(1,i) = ip.y; }
|
||||
if (dim>2) { qref(2,i) = ip.z; }
|
||||
qweight(i) = ip.weight;
|
||||
fe->CalcShape(ip, shape_i);
|
||||
fe->CalcDShape(ip, grad_i);
|
||||
for (int j = 0; j < P; j++)
|
||||
{
|
||||
shape(j, i) = shape_i(j);
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
grad(j+i*P+d*Q*P) = grad_i(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
|
||||
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
|
||||
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
|
||||
}
|
||||
|
||||
static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const int dim = mesh->Dimension();
|
||||
const int P = fe->GetDof();
|
||||
const int Q = ir.GetNPoints();
|
||||
DenseMatrix shape(P, Q);
|
||||
Vector grad(P*dim*Q);
|
||||
DenseMatrix qref(dim, Q);
|
||||
Vector qweight(Q);
|
||||
Vector shape_i(P);
|
||||
DenseMatrix grad_i(P, dim);
|
||||
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
|
||||
const Table &el_dof = fes.GetElementToDofTable();
|
||||
Array<int> tp_el_dof(el_dof.Size_of_connections());
|
||||
@@ -192,6 +124,7 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
const int el_offset = fe->GetDof() * i;
|
||||
@@ -229,6 +162,7 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int e = 0; e < mesh->GetNE(); e++)
|
||||
{
|
||||
for (int i = 0; i < P; i++)
|
||||
@@ -244,15 +178,19 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
}
|
||||
}
|
||||
}
|
||||
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
|
||||
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
|
||||
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
|
||||
CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(),
|
||||
compstride, (fes.GetVDim())*(fes.GetNDofs()),
|
||||
CEED_MEM_HOST, CEED_COPY_VALUES,
|
||||
tp_el_dof.GetData(), restr);
|
||||
}
|
||||
|
||||
static void InitCeedTensorBasis(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis)
|
||||
static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
@@ -260,6 +198,7 @@ static void InitCeedTensorBasis(const FiniteElementSpace &fes,
|
||||
const TensorBasisElement * tfe =
|
||||
dynamic_cast<const TensorBasisElement *>(fe);
|
||||
MFEM_VERIFY(tfe, "invalid FE");
|
||||
const Array<int>& dof_map = tfe->GetDofMap();
|
||||
const FiniteElement *fe1d =
|
||||
fes.FEColl()->FiniteElementForGeometry(Geometry::SEGMENT);
|
||||
DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
|
||||
@@ -288,28 +227,6 @@ static void InitCeedTensorBasis(const FiniteElementSpace &fes,
|
||||
ir.GetNPoints(), shape1d.GetData(),
|
||||
grad1d.GetData(), qref1d.GetData(),
|
||||
qweight1d.GetData(), basis);
|
||||
}
|
||||
|
||||
static void InitCeedTensorRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const TensorBasisElement * tfe =
|
||||
dynamic_cast<const TensorBasisElement *>(fe);
|
||||
MFEM_VERIFY(tfe, "invalid FE");
|
||||
const Array<int>& dof_map = tfe->GetDofMap();
|
||||
const FiniteElement *fe1d =
|
||||
fes.FEColl()->FiniteElementForGeometry(Geometry::SEGMENT);
|
||||
DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
|
||||
DenseMatrix grad1d(fe1d->GetDof(), ir.GetNPoints());
|
||||
Vector qref1d(ir.GetNPoints()), qweight1d(ir.GetNPoints());
|
||||
Vector shape_i(shape1d.Height());
|
||||
DenseMatrix grad_i(grad1d.Height(), 1);
|
||||
const H1_SegmentElement *h1_fe1d =
|
||||
dynamic_cast<const H1_SegmentElement *>(fe1d);
|
||||
MFEM_VERIFY(h1_fe1d, "invalid FE");
|
||||
|
||||
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
|
||||
const Table &el_dof = fes.GetElementToDofTable();
|
||||
@@ -341,52 +258,14 @@ void InitCeedBasisAndRestriction(const FiniteElementSpace &fes,
|
||||
Ceed ceed, CeedBasis *basis,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
// Check for FES -> basis, restriction in hash tables
|
||||
const Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const int P = fe->GetDof();
|
||||
const int Q = irm.GetNPoints();
|
||||
const int nelem = mesh->GetNE();
|
||||
const int ncomp = fes.GetVDim();
|
||||
CeedBasisKey basis_key(&fes, &irm, ncomp, P, Q);
|
||||
auto basis_itr = internal::ceed_basis_map.find(basis_key);
|
||||
CeedRestrKey restr_key(&fes, nelem, P, ncomp);
|
||||
auto restr_itr = internal::ceed_restr_map.find(restr_key);
|
||||
|
||||
// Init or retreive key values
|
||||
if (basis_itr == internal::ceed_basis_map.end())
|
||||
if (UsesTensorBasis(fes))
|
||||
{
|
||||
if (UsesTensorBasis(fes))
|
||||
{
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
|
||||
InitCeedTensorBasis(fes, ir, ceed, basis);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitCeedNonTensorBasis(fes, irm, ceed, basis);
|
||||
}
|
||||
internal::ceed_basis_map[basis_key] = *basis;
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
|
||||
InitCeedTensorBasisAndRestriction(fes, ir, ceed, basis, restr);
|
||||
}
|
||||
else
|
||||
{
|
||||
*basis = basis_itr->second;
|
||||
}
|
||||
if (restr_itr == internal::ceed_restr_map.end())
|
||||
{
|
||||
if (UsesTensorBasis(fes))
|
||||
{
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
|
||||
InitCeedTensorRestriction(fes, ir, ceed, restr);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitCeedNonTensorRestriction(fes, irm, ceed, restr);
|
||||
}
|
||||
internal::ceed_restr_map[restr_key] = *restr;
|
||||
}
|
||||
else
|
||||
{
|
||||
*restr = restr_itr->second;
|
||||
InitCeedNonTensorBasisAndRestriction(fes, irm, ceed, basis, restr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,8 +327,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedVectorCreate(ceed, nelem * nqpts * qdatasize, &ceedData.rho);
|
||||
|
||||
// Context data to be passed to the 'f_build_diff' Q-function.
|
||||
ceedData.build_ctx_data.dim = mesh->Dimension();
|
||||
ceedData.build_ctx_data.space_dim = mesh->SpaceDimension();
|
||||
ceedData.build_ctx.dim = mesh->Dimension();
|
||||
ceedData.build_ctx.space_dim = mesh->SpaceDimension();
|
||||
|
||||
std::string qf_file = GetCeedPath() + op.header;
|
||||
std::string qf;
|
||||
@@ -463,7 +342,7 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedQFunctionCreateInterior(ceed, 1, op.const_qf,
|
||||
qf.c_str(),
|
||||
&ceedData.build_qfunc);
|
||||
ceedData.build_ctx_data.coeff = ((CeedConstCoeff*)ceedData.coeff)->val;
|
||||
ceedData.build_ctx.coeff = ((CeedConstCoeff*)ceedData.coeff)->val;
|
||||
break;
|
||||
case CeedCoeff::Grid:
|
||||
qf = qf_file + op.grid_func;
|
||||
@@ -479,12 +358,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedQFunctionAddInput(ceedData.build_qfunc, "weights", 1, CEED_EVAL_WEIGHT);
|
||||
CeedQFunctionAddOutput(ceedData.build_qfunc, "qdata", qdatasize,
|
||||
CEED_EVAL_NONE);
|
||||
|
||||
CeedQFunctionContextCreate(ceed, &ceedData.build_ctx);
|
||||
CeedQFunctionContextSetData(ceedData.build_ctx, CEED_MEM_HOST, CEED_USE_POINTER,
|
||||
sizeof(ceedData.build_ctx_data),
|
||||
&ceedData.build_ctx_data);
|
||||
CeedQFunctionSetContext(ceedData.build_qfunc, ceedData.build_ctx);
|
||||
CeedQFunctionSetContext(ceedData.build_qfunc, &ceedData.build_ctx,
|
||||
sizeof(ceedData.build_ctx));
|
||||
|
||||
// Create the operator that builds the quadrature data for the operator.
|
||||
CeedOperatorCreate(ceed, ceedData.build_qfunc, NULL, NULL,
|
||||
@@ -524,7 +399,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedQFunctionAddInput(ceedData.apply_qfunc, "qdata", qdatasize,
|
||||
CEED_EVAL_NONE);
|
||||
CeedQFunctionAddOutput(ceedData.apply_qfunc, "v", dimV, op.test_op);
|
||||
CeedQFunctionSetContext(ceedData.apply_qfunc, ceedData.build_ctx);
|
||||
CeedQFunctionSetContext(ceedData.apply_qfunc, &ceedData.build_ctx,
|
||||
sizeof(ceedData.build_ctx));
|
||||
|
||||
// Create the diff operator.
|
||||
CeedOperatorCreate(ceed, ceedData.apply_qfunc, NULL, NULL, &ceedData.oper);
|
||||
|
||||
+8
-46
@@ -18,9 +18,6 @@
|
||||
#include "../../general/device.hpp"
|
||||
#include "../../linalg/vector.hpp"
|
||||
#include <ceed.h>
|
||||
#include <ceed-hash.h>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -30,47 +27,7 @@ class GridFunction;
|
||||
class IntegrationRule;
|
||||
class Coefficient;
|
||||
|
||||
// Hash table for CeedBasis
|
||||
using CeedBasisKey =
|
||||
std::tuple<const FiniteElementSpace*, const IntegrationRule*, int, int, int>;
|
||||
struct CeedBasisHash
|
||||
{
|
||||
std::size_t operator()(const CeedBasisKey& k) const
|
||||
{
|
||||
return CeedHashCombine(CeedHashCombine(CeedHashInt(
|
||||
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
|
||||
CeedHashInt(
|
||||
reinterpret_cast<CeedHash64_t>(std::get<1>(k)))),
|
||||
CeedHashCombine(CeedHashCombine(CeedHashInt(std::get<2>(k)),
|
||||
CeedHashInt(std::get<3>(k))),
|
||||
CeedHashInt(std::get<4>(k))));
|
||||
}
|
||||
};
|
||||
using CeedBasisMap =
|
||||
std::unordered_map<const CeedBasisKey, CeedBasis, CeedBasisHash>;
|
||||
|
||||
// Hash table for CeedElemRestriction
|
||||
using CeedRestrKey = std::tuple<const FiniteElementSpace*, int, int, int>;
|
||||
struct CeedRestrHash
|
||||
{
|
||||
std::size_t operator()(const CeedRestrKey& k) const
|
||||
{
|
||||
return CeedHashCombine(CeedHashCombine(CeedHashInt(
|
||||
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
|
||||
CeedHashInt(std::get<1>(k))),
|
||||
CeedHashCombine(CeedHashInt(std::get<2>(k)),
|
||||
CeedHashInt(std::get<3>(k))));
|
||||
}
|
||||
};
|
||||
using CeedRestrMap =
|
||||
std::unordered_map<const CeedRestrKey, CeedElemRestriction, CeedRestrHash>;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
extern Ceed ceed; // defined in device.cpp
|
||||
extern CeedBasisMap basis_map;
|
||||
extern CeedRestrMap restr_map;
|
||||
}
|
||||
namespace internal { extern Ceed ceed; } // defined in device.cpp
|
||||
|
||||
/// A structure used to pass additional data to f_build_diff and f_apply_diff
|
||||
struct BuildContext { CeedInt dim, space_dim; CeedScalar coeff; };
|
||||
@@ -99,8 +56,7 @@ struct CeedData
|
||||
CeedVector node_coords, rho;
|
||||
CeedCoeff coeff_type;
|
||||
void* coeff;
|
||||
CeedQFunctionContext build_ctx;
|
||||
BuildContext build_ctx_data;
|
||||
BuildContext build_ctx;
|
||||
|
||||
CeedVector u, v;
|
||||
|
||||
@@ -108,6 +64,10 @@ struct CeedData
|
||||
{
|
||||
CeedOperatorDestroy(&build_oper);
|
||||
CeedOperatorDestroy(&oper);
|
||||
CeedBasisDestroy(&basis);
|
||||
CeedBasisDestroy(&mesh_basis);
|
||||
CeedElemRestrictionDestroy(&restr);
|
||||
CeedElemRestrictionDestroy(&mesh_restr);
|
||||
CeedElemRestrictionDestroy(&restr_i);
|
||||
CeedElemRestrictionDestroy(&mesh_restr_i);
|
||||
CeedQFunctionDestroy(&apply_qfunc);
|
||||
@@ -117,6 +77,8 @@ struct CeedData
|
||||
if (coeff_type==CeedCoeff::Grid)
|
||||
{
|
||||
CeedGridCoeff* c = (CeedGridCoeff*)coeff;
|
||||
CeedBasisDestroy(&c->basis);
|
||||
CeedElemRestrictionDestroy(&c->restr);
|
||||
CeedVectorDestroy(&c->coeffVector);
|
||||
delete c;
|
||||
}
|
||||
|
||||
@@ -204,14 +204,6 @@ void LinearForm::Update(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
ResetDeltaLocations();
|
||||
}
|
||||
|
||||
void LinearForm::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
{
|
||||
MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
|
||||
fes = f;
|
||||
v.UseDevice(true);
|
||||
this->Vector::MakeRef(v, v_offset, fes->GetVSize());
|
||||
}
|
||||
|
||||
void LinearForm::AssembleDelta()
|
||||
{
|
||||
if (dlfi_delta.Size() == 0) { return; }
|
||||
|
||||
+1
-11
@@ -26,7 +26,7 @@ protected:
|
||||
/// FE space on which the LinearForm lives. Not owned.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
/** @brief Indicates the LinearFormIntegrator%s stored in #dlfi, #dlfi_delta,
|
||||
/** @brief Indicates the LinerFormIntegrator%s stored in #dlfi, #dlfi_delta,
|
||||
#blfi, and #flfi are owned by another LinearForm. */
|
||||
int extern_lfs;
|
||||
|
||||
@@ -175,16 +175,6 @@ public:
|
||||
@note This method does not perform assembly. */
|
||||
void Update(FiniteElementSpace *f, Vector &v, int v_offset);
|
||||
|
||||
/** @brief Make the LinearForm reference external data on a new
|
||||
FiniteElementSpace. */
|
||||
/** This method changes the FiniteElementSpace associated with the LinearForm
|
||||
@a *f and sets the data of the Vector @a v (plus the @a v_offset) as
|
||||
external data in the LinearForm.
|
||||
|
||||
@note This version of the method will also perform bounds checks when the
|
||||
build option MFEM_DEBUG is enabled. */
|
||||
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
|
||||
|
||||
/// Return the action of the LinearForm as a linear mapping.
|
||||
/** Linear forms are linear functionals which map GridFunctions to
|
||||
the real numbers. This method performs this mapping which in
|
||||
|
||||
+39
-6
@@ -457,8 +457,20 @@ void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
|
||||
|
||||
Tr.SetIntPoint (&ip);
|
||||
el.CalcPhysCurlShape(Tr, curlshape);
|
||||
QF->Eval(vec, Tr, ip);
|
||||
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided");
|
||||
QF->Eval(vec, Tr, ip);
|
||||
break;
|
||||
case 2:
|
||||
MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided");
|
||||
vec[0] = Q->Eval(Tr, ip);
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
vec *= ip.weight * Tr.Weight();
|
||||
curlshape.AddMult (vec, elvect);
|
||||
}
|
||||
@@ -468,17 +480,38 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
|
||||
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
||||
{
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
MFEM_ASSERT(vec_delta != NULL,
|
||||
"coefficient must be VectorDeltaCoefficient");
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
MFEM_ASSERT(vec_delta != NULL,
|
||||
"coefficient must be VectorDeltaCoefficient");
|
||||
break;
|
||||
case 2:
|
||||
MFEM_ASSERT(delta != NULL,
|
||||
"coefficient must be DeltaCoefficient");
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
int dof = fe.GetDof();
|
||||
int n=(spaceDim == 3)? spaceDim : 1;
|
||||
vec.SetSize(n);
|
||||
curlshape.SetSize(dof, n);
|
||||
elvect.SetSize(dof);
|
||||
fe.CalcPhysCurlShape(Trans, curlshape);
|
||||
|
||||
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
|
||||
curlshape.Mult(vec, elvect);
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
|
||||
curlshape.Mult(vec, elvect);
|
||||
break;
|
||||
case 2:
|
||||
curlshape.GetColumn(0,elvect);
|
||||
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
|
||||
|
||||
@@ -284,6 +284,7 @@ class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator
|
||||
{
|
||||
private:
|
||||
VectorCoefficient *QF=nullptr;
|
||||
Coefficient *Q=nullptr;
|
||||
DenseMatrix curlshape;
|
||||
Vector vec;
|
||||
|
||||
@@ -291,6 +292,8 @@ public:
|
||||
/// Constructs the domain integrator (Q, curl v)
|
||||
VectorFEDomainLFCurlIntegrator(VectorCoefficient &F)
|
||||
: DeltaLFIntegrator(F), QF(&F) { }
|
||||
VectorFEDomainLFCurlIntegrator(Coefficient &F)
|
||||
: DeltaLFIntegrator(F), Q(&F) { }
|
||||
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
|
||||
+2
-162
@@ -655,167 +655,6 @@ void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
#endif
|
||||
}
|
||||
|
||||
double ParGridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
double Nu,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
const_cast<ParGridFunction *>(this)->ExchangeFaceNbrData();
|
||||
|
||||
int fdof, dim, intorder, k;
|
||||
ElementTransformation *transf;
|
||||
Vector shape, el_dofs, err_val, ell_coeff_val;
|
||||
Array<int> vdofs;
|
||||
IntegrationPoint eip;
|
||||
double error = 0.0;
|
||||
|
||||
ParMesh *mesh = pfes->GetParMesh();
|
||||
dim = mesh->Dimension();
|
||||
|
||||
std::map<int,int> local_to_shared;
|
||||
for (int i = 0; i < mesh->GetNSharedFaces(); ++i)
|
||||
{
|
||||
int i_local = mesh->GetSharedFace(i);
|
||||
local_to_shared[i_local] = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); i++)
|
||||
{
|
||||
double shared_face_factor = 1.0;
|
||||
bool shared_face = false;
|
||||
int iel1, iel2, info1, info2;
|
||||
mesh->GetFaceElements(i, &iel1, &iel2);
|
||||
mesh->GetFaceInfos(i, &info1, &info2);
|
||||
|
||||
intorder = fes->GetFE(iel1)->GetOrder();
|
||||
|
||||
FaceElementTransformations *face_elem_transf;
|
||||
const FiniteElement *fe1, *fe2;
|
||||
if (info2 >= 0 && iel2 < 0)
|
||||
{
|
||||
int ishared = local_to_shared[i];
|
||||
face_elem_transf = mesh->GetSharedFaceTransformations(ishared);
|
||||
iel2 = face_elem_transf->Elem2No - mesh->GetNE();
|
||||
fe2 = pfes->GetFaceNbrFE(iel2);
|
||||
if ( (k = fe2->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
shared_face = true;
|
||||
shared_face_factor = 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i);
|
||||
|
||||
if (iel2 >= 0)
|
||||
{
|
||||
fe2 = pfes->GetFE(iel2);
|
||||
if ( (k = fe2->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fe2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
intorder = 2 * intorder; // <-------------
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[face_elem_transf->GetGeometryType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
|
||||
}
|
||||
err_val.SetSize(ir->GetNPoints());
|
||||
ell_coeff_val.SetSize(ir->GetNPoints());
|
||||
// side 1
|
||||
transf = face_elem_transf->Elem1;
|
||||
fe1 = fes->GetFE(iel1);
|
||||
fdof = fe1->GetDof();
|
||||
fes->GetElementVDofs(iel1, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
|
||||
fe1->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
|
||||
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
|
||||
}
|
||||
if (fe2 != NULL)
|
||||
{
|
||||
// side 2
|
||||
transf = face_elem_transf->Elem2;
|
||||
fdof = fe2->GetDof();
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
if (shared_face)
|
||||
{
|
||||
pfes->GetFaceNbrElementVDofs(iel2, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = face_nbr_data[vdofs[k]];
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - face_nbr_data[-1-vdofs[k]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pfes->GetElementVDofs(iel2, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1 - vdofs[k]);
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
|
||||
fe2->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
|
||||
ell_coeff_val(j) *= 0.5;
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
}
|
||||
}
|
||||
transf = face_elem_transf;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
error += shared_face_factor*(ip.weight * Nu * ell_coeff_val(j) *
|
||||
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
}
|
||||
|
||||
error = (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return GlobalLpNorm(2.0, error, pfes->GetComm());
|
||||
}
|
||||
|
||||
void ParGridFunction::Save(std::ostream &out) const
|
||||
{
|
||||
double *data_ = const_cast<double*>(HostRead());
|
||||
@@ -1021,6 +860,7 @@ double GlobalLpNorm(const double p, double loc_norm, MPI_Comm comm)
|
||||
return glob_norm;
|
||||
}
|
||||
|
||||
|
||||
void ParGridFunction::ComputeFlux(
|
||||
BilinearFormIntegrator &blfi,
|
||||
GridFunction &flux, bool wcoef, int subdomain)
|
||||
@@ -1161,6 +1001,6 @@ double L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator,
|
||||
return pow(glob_error, 1.0/norm_p);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
@@ -283,77 +283,6 @@ public:
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
|
||||
virtual double ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeGradError(exgrad,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
|
||||
virtual double ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeCurlError(excurl,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns ||div u_ex - div u_h||_L2 for RT elements
|
||||
virtual double ComputeDivError(Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeDivError(exdiv,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements
|
||||
virtual double ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
double Nu,
|
||||
const IntegrationRule *irs[]=NULL)
|
||||
const;
|
||||
|
||||
/// Returns either the H1-seminorm or the DG Face Jumps error or both
|
||||
/// depending on norm_type = 1, 2, 3
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coef, double Nu,
|
||||
int norm_type) const
|
||||
{
|
||||
return GlobalLpNorm(2.0,
|
||||
GridFunction::ComputeH1Error(exsol,exgrad,ell_coef,
|
||||
Nu, norm_type),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the error measured in H1-norm for H1 elements or in "broken"
|
||||
/// H1-norm for L2 elements
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeH1Error(exsol,exgrad,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the error measured H(div)-norm for RT elements
|
||||
virtual double ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeHDivError(exsol,exdiv,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the error measured H(curl)-norm for ND elements
|
||||
virtual double ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0,
|
||||
GridFunction::ComputeHCurlError(exsol,excurl,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
virtual double ComputeMaxError(Coefficient *exsol[],
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
|
||||
+1
-13
@@ -21,6 +21,7 @@ namespace mfem
|
||||
void ParLinearForm::Update(ParFiniteElementSpace *pf)
|
||||
{
|
||||
if (pf) { pfes = pf; }
|
||||
|
||||
LinearForm::Update(pfes);
|
||||
}
|
||||
|
||||
@@ -30,19 +31,6 @@ void ParLinearForm::Update(ParFiniteElementSpace *pf, Vector &v, int v_offset)
|
||||
LinearForm::Update(pf,v,v_offset);
|
||||
}
|
||||
|
||||
void ParLinearForm::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
{
|
||||
LinearForm::MakeRef(f, v, v_offset);
|
||||
pfes = dynamic_cast<ParFiniteElementSpace*>(f);
|
||||
MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
|
||||
}
|
||||
|
||||
void ParLinearForm::MakeRef(ParFiniteElementSpace *pf, Vector &v, int v_offset)
|
||||
{
|
||||
LinearForm::MakeRef(pf, v, v_offset);
|
||||
pfes = pf;
|
||||
}
|
||||
|
||||
void ParLinearForm::ParallelAssemble(Vector &tv)
|
||||
{
|
||||
const Operator* prolong = pfes->GetProlongationMatrix();
|
||||
|
||||
+4
-25
@@ -92,27 +92,6 @@ public:
|
||||
@note This method does not perform assembly. */
|
||||
void Update(ParFiniteElementSpace *pf, Vector &v, int v_offset);
|
||||
|
||||
|
||||
/** @brief Make the ParLinearForm reference external data on a new
|
||||
FiniteElementSpace. */
|
||||
/** This method changes the FiniteElementSpace associated with the
|
||||
ParLinearForm to @a *f and sets the data of the Vector @a v (plus the @a
|
||||
v_offset) as external data in the ParLinearForm.
|
||||
|
||||
@note This version of the method will also perform bounds checks when the
|
||||
build option MFEM_DEBUG is enabled. */
|
||||
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
|
||||
|
||||
/** @brief Make the ParLinearForm reference external data on a new
|
||||
ParFiniteElementSpace. */
|
||||
/** This method changes the ParFiniteElementSpace associated with the
|
||||
ParLinearForm to @a *pf and sets the data of the Vector @a v (plus the @a
|
||||
v_offset) as external data in the ParLinearForm.
|
||||
|
||||
@note This version of the method will also perform bounds checks when the
|
||||
build option MFEM_DEBUG is enabled. */
|
||||
void MakeRef(ParFiniteElementSpace *pf, Vector &v, int v_offset);
|
||||
|
||||
/// Assemble the vector on the true dofs, i.e. P^t v.
|
||||
void ParallelAssemble(Vector &tv);
|
||||
|
||||
@@ -120,10 +99,10 @@ public:
|
||||
HypreParVector *ParallelAssemble();
|
||||
|
||||
/// Return the action of the ParLinearForm as a linear mapping.
|
||||
/** Linear forms are linear functionals which map ParGridFunction%s to the
|
||||
real numbers. This method performs this mapping which in this case is
|
||||
equivalent as an inner product of the ParLinearForm and
|
||||
ParGridFunction. */
|
||||
/** Linear forms are linear functionals which map ParGridFunction%s to
|
||||
the real numbers. This method performs this mapping which in
|
||||
this case is equivalent as an inner product of the ParLinearForm
|
||||
and ParGridFunction. */
|
||||
double operator()(const ParGridFunction &gf) const
|
||||
{
|
||||
return InnerProduct(pfes->GetComm(), *this, gf);
|
||||
|
||||
+23
-1
@@ -298,12 +298,34 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
|
||||
field0_gf = init_field;
|
||||
|
||||
dim = f->GetFE(0)->GetDim();
|
||||
const int pts_cnt = init_nodes.Size() / dim;
|
||||
el_id_out.SetSize(pts_cnt);
|
||||
code_out.SetSize(pts_cnt);
|
||||
task_id_out.SetSize(pts_cnt);
|
||||
pos_r_out.SetSize(pts_cnt*dim);
|
||||
dist_p_out.SetSize(pts_cnt);
|
||||
}
|
||||
|
||||
void InterpolatorFP::ComputeAtNewPosition(const Vector &new_nodes,
|
||||
Vector &new_field)
|
||||
{
|
||||
finder->Interpolate(new_nodes, field0_gf, new_field);
|
||||
const int pts_cnt = new_nodes.Size() / dim;
|
||||
|
||||
// The sizes may change between calls due to AMR.
|
||||
if (el_id_out.Size() != pts_cnt)
|
||||
{
|
||||
el_id_out.SetSize(pts_cnt);
|
||||
code_out.SetSize(pts_cnt);
|
||||
task_id_out.SetSize(pts_cnt);
|
||||
pos_r_out.SetSize(pts_cnt*dim);
|
||||
dist_p_out(pts_cnt);
|
||||
}
|
||||
|
||||
// Interpolate FE function values on the found points.
|
||||
finder->FindPoints(new_nodes, code_out, task_id_out,
|
||||
el_id_out, pos_r_out, dist_p_out);
|
||||
finder->Interpolate(code_out, task_id_out, el_id_out,
|
||||
pos_r_out, field0_gf, new_field);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -49,6 +49,8 @@ private:
|
||||
Vector nodes0;
|
||||
GridFunction field0_gf;
|
||||
FindPointsGSLIB *finder;
|
||||
Array<uint> el_id_out, code_out, task_id_out;
|
||||
Vector pos_r_out, dist_p_out;
|
||||
int dim;
|
||||
public:
|
||||
InterpolatorFP() : finder(NULL) { }
|
||||
|
||||
@@ -235,8 +235,8 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
|
||||
}
|
||||
|
||||
// format info
|
||||
SafeDefineAttribute<std::string>(io, "format", "MFEM ADIOS2 BP v0.2" );
|
||||
SafeDefineAttribute<std::string>(io, "format/version", "0.2" );
|
||||
SafeDefineAttribute<std::string>(io, "format", "MFEM ADIOS2 BP v0.1" );
|
||||
SafeDefineAttribute<std::string>(io, "format/version", "0.1" );
|
||||
std::string mesh_type = "Unknown";
|
||||
std::vector<std::string> viz_tools;
|
||||
viz_tools.reserve(2); //for now
|
||||
@@ -298,7 +298,6 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
|
||||
element_nvertices = static_cast<size_t>(mesh.elements[0]->GetNVertices());
|
||||
}
|
||||
SafeDefineVariable<uint64_t>(io, "connectivity", {}, {}, {nelements, element_nvertices+1});
|
||||
SafeDefineVariable<int32_t>(io, "material", {}, {}, {nelements});
|
||||
|
||||
// vertices
|
||||
SafeDefineVariable<uint32_t>(io,"NumOfVertices", {adios2::LocalValueDim});
|
||||
@@ -349,15 +348,8 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
|
||||
io.InquireVariable<uint64_t>("connectivity");
|
||||
adios2::Variable<uint64_t>::Span span_connectivity = engine.Put<uint64_t>
|
||||
(var_connectivity);
|
||||
|
||||
adios2::Variable<int32_t> var_element_attribute =
|
||||
io.InquireVariable<int32_t>("material");
|
||||
adios2::Variable<int32_t>::Span span_element_attribute = engine.Put<int32_t>
|
||||
(var_element_attribute);
|
||||
|
||||
size_t span_vertices_offset = 0;
|
||||
size_t span_connectivity_offset = 0;
|
||||
size_t span_element_attribute_offset = 0;
|
||||
// use for setting absolute node id for each element
|
||||
size_t point_id = 0;
|
||||
DenseMatrix pmatrix;
|
||||
@@ -378,9 +370,6 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
|
||||
}
|
||||
span_vertices_offset += static_cast<size_t>(pmatrix.Width()*pmatrix.Height());
|
||||
|
||||
// element attribute
|
||||
const int element_attribute = mesh.GetAttribute(e);
|
||||
|
||||
// connectivity
|
||||
const int nv = Geometries.GetVertices(type)->GetNPoints();
|
||||
const Array<int> &element_vertices = refined_geometry->RefGeoms;
|
||||
@@ -390,10 +379,6 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
|
||||
span_connectivity[span_connectivity_offset] = static_cast<uint64_t>(nv);
|
||||
++span_connectivity_offset;
|
||||
|
||||
span_element_attribute[span_element_attribute_offset] = static_cast<int32_t>
|
||||
(element_attribute);
|
||||
++span_element_attribute_offset;
|
||||
|
||||
for (int k =0; k < nv; k++, v++ )
|
||||
{
|
||||
span_connectivity[span_connectivity_offset] = static_cast<uint64_t>
|
||||
@@ -434,17 +419,9 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
|
||||
adios2::Variable<uint64_t>::Span spanConnectivity =
|
||||
engine.Put<uint64_t>(varConnectivity);
|
||||
|
||||
adios2::Variable<int32_t> varElementAttribute =
|
||||
io.InquireVariable<int32_t>("material");
|
||||
// zero-copy access to adios2 buffer to put non-contiguous to contiguous memory
|
||||
adios2::Variable<int32_t>::Span spanElementAttribute =
|
||||
engine.Put<int32_t>(varElementAttribute);
|
||||
|
||||
size_t elementPosition = 0;
|
||||
for (int e = 0; e < mesh.GetNE(); ++e)
|
||||
{
|
||||
spanElementAttribute[e] = static_cast<int32_t>(mesh.GetAttribute(e));
|
||||
|
||||
const int nVertices = mesh.elements[e]->GetNVertices();
|
||||
spanConnectivity[elementPosition] = nVertices;
|
||||
for (int v = 0; v < nVertices; ++v)
|
||||
@@ -711,7 +688,7 @@ std::string adios2stream::VTKSchema() const noexcept
|
||||
{
|
||||
std::string vtkSchema = R"(
|
||||
<?xml version="1.0"?>
|
||||
<VTKFile type="UnstructuredGrid" version="0.2" byte_order="LittleEndian">
|
||||
<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">
|
||||
<UnstructuredGrid>
|
||||
<Piece NumberOfPoints="NumOfVertices" NumberOfCells="NumOfElements">
|
||||
<Points>
|
||||
@@ -719,9 +696,6 @@ std::string adios2stream::VTKSchema() const noexcept
|
||||
|
||||
vtkSchema += R"(
|
||||
</Points>
|
||||
<CellData>
|
||||
<DataArray Name="material" />
|
||||
</CellData>
|
||||
<Cells>
|
||||
<DataArray Name="connectivity" />
|
||||
<DataArray Name="types" />
|
||||
|
||||
+4
-18
@@ -12,10 +12,9 @@
|
||||
#include "forall.hpp"
|
||||
#include "occa.hpp"
|
||||
#ifdef MFEM_USE_CEED
|
||||
#include "../fem/libceed/ceed.hpp"
|
||||
#include <ceed.h>
|
||||
#endif
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
@@ -34,16 +33,13 @@ occa::device occaDevice;
|
||||
|
||||
#ifdef MFEM_USE_CEED
|
||||
Ceed ceed = NULL;
|
||||
|
||||
CeedBasisMap ceed_basis_map;
|
||||
CeedRestrMap ceed_restr_map;
|
||||
#endif
|
||||
|
||||
// Backends listed by priority, high to low:
|
||||
static const Backend::Id backend_list[Backend::NUM_BACKENDS] =
|
||||
{
|
||||
Backend::CEED_CUDA, Backend::OCCA_CUDA, Backend::RAJA_CUDA, Backend::CUDA,
|
||||
Backend::HIP, Backend::DEBUG_DEVICE,
|
||||
Backend::HIP, Backend::DEBUG,
|
||||
Backend::OCCA_OMP, Backend::RAJA_OMP, Backend::OMP,
|
||||
Backend::CEED_CPU, Backend::OCCA_CPU, Backend::RAJA_CPU, Backend::CPU
|
||||
};
|
||||
@@ -158,16 +154,6 @@ Device::~Device()
|
||||
{
|
||||
free(device_option);
|
||||
#ifdef MFEM_USE_CEED
|
||||
// Destroy FES -> CeedBasis, CeedElemRestriction hash table contents
|
||||
for (auto entry : internal::ceed_basis_map)
|
||||
{
|
||||
CeedBasisDestroy(&entry.second);
|
||||
}
|
||||
for (auto entry : internal::ceed_restr_map)
|
||||
{
|
||||
CeedElemRestrictionDestroy(&entry.second);
|
||||
}
|
||||
// Destroy Ceed context
|
||||
CeedDestroy(&internal::ceed);
|
||||
#endif
|
||||
mm.Destroy();
|
||||
@@ -280,7 +266,7 @@ void Device::Print(std::ostream &out)
|
||||
|
||||
void Device::UpdateMemoryTypeAndClass()
|
||||
{
|
||||
const bool debug = Device::Allows(Backend::DEBUG_DEVICE);
|
||||
const bool debug = Device::Allows(Backend::DEBUG);
|
||||
|
||||
const bool device = Device::Allows(Backend::DEVICE_MASK);
|
||||
|
||||
@@ -518,7 +504,7 @@ void Device::Setup(const int device)
|
||||
CeedDeviceSetup(device_option);
|
||||
}
|
||||
}
|
||||
if (Allows(Backend::DEBUG_DEVICE)) { ngpu = 1; }
|
||||
if (Allows(Backend::DEBUG)) { ngpu = 1; }
|
||||
}
|
||||
|
||||
} // mfem
|
||||
|
||||
+4
-6
@@ -64,9 +64,8 @@ struct Backend
|
||||
/** @brief [device] Debug backend: host memory is READ/WRITE protected
|
||||
while a device is in use. It allows to test the "device" code-path
|
||||
(using separate host/device memory pools and host <-> device
|
||||
transfers) without any GPU hardware. As 'DEBUG' is sometimes used
|
||||
as a macro, `_DEVICE` has been added to avoid conflicts. */
|
||||
DEBUG_DEVICE = 1 << 12
|
||||
transfers) without any GPU hardware. */
|
||||
DEBUG = 1 << 12
|
||||
};
|
||||
|
||||
/** @brief Additional useful constants. For example, the *_MASK constants can
|
||||
@@ -87,7 +86,7 @@ struct Backend
|
||||
/// Bitwise-OR of all CEED backends
|
||||
CEED_MASK = CEED_CPU | CEED_CUDA,
|
||||
/// Biwise-OR of all device backends
|
||||
DEVICE_MASK = CUDA_MASK | HIP_MASK | DEBUG_DEVICE,
|
||||
DEVICE_MASK = CUDA_MASK | HIP_MASK | DEBUG,
|
||||
|
||||
/// Biwise-OR of all RAJA backends
|
||||
RAJA_MASK = RAJA_CPU | RAJA_OMP | RAJA_CUDA,
|
||||
@@ -194,8 +193,7 @@ public:
|
||||
* The available backends are described by the Backend class.
|
||||
* The string name of a backend is the lowercase version of the
|
||||
Backend::Id enumeration constant with '_' replaced by '-', e.g. the
|
||||
string name of 'RAJA_CPU' is 'raja-cpu'. The string name of the debug
|
||||
backend (Backend::Id 'DEBUG_DEVICE') is exceptionally set to 'debug'.
|
||||
string name of 'RAJA_CPU' is 'raja-cpu'.
|
||||
* The 'cpu' backend is always enabled with lowest priority.
|
||||
* The current backend priority from highest to lowest is:
|
||||
'ceed-cuda', 'occa-cuda', 'raja-cuda', 'cuda', 'hip', 'debug',
|
||||
|
||||
+1
-1
@@ -343,7 +343,7 @@ inline void ForallWrap(const bool use_dev, const int N,
|
||||
{ return HipWrap3D(N, d_body, X, Y, Z); }
|
||||
#endif
|
||||
|
||||
if (Device::Allows(Backend::DEBUG_DEVICE)) { goto backend_cpu; }
|
||||
if (Device::Allows(Backend::DEBUG)) { goto backend_cpu; }
|
||||
|
||||
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
|
||||
// Handle all allowed OpenMP backends except Backend::OMP
|
||||
|
||||
+12
-18
@@ -136,10 +136,8 @@ struct Memory
|
||||
void *d_ptr;
|
||||
const size_t bytes;
|
||||
const MemoryType h_mt, d_mt;
|
||||
mutable bool h_rw, d_rw;
|
||||
Memory(void *p, size_t b, MemoryType h, MemoryType d):
|
||||
h_ptr(p), d_ptr(nullptr), bytes(b), h_mt(h), d_mt(d),
|
||||
h_rw(true), d_rw(true) { }
|
||||
h_ptr(p), d_ptr(nullptr), bytes(b), h_mt(h), d_mt(d) { }
|
||||
};
|
||||
|
||||
/// Alias class that holds the base memory region and the offset
|
||||
@@ -175,8 +173,8 @@ public:
|
||||
virtual ~HostMemorySpace() { }
|
||||
virtual void Alloc(void **ptr, size_t bytes) { *ptr = std::malloc(bytes); }
|
||||
virtual void Dealloc(void *ptr) { std::free(ptr); }
|
||||
virtual void Protect(const Memory&, size_t) { }
|
||||
virtual void Unprotect(const Memory&, size_t) { }
|
||||
virtual void Protect(const void*, size_t) { }
|
||||
virtual void Unprotect(const void*, size_t) { }
|
||||
virtual void AliasProtect(const void*, size_t) { }
|
||||
virtual void AliasUnprotect(const void*, size_t) { }
|
||||
};
|
||||
@@ -354,10 +352,8 @@ public:
|
||||
MmuHostMemorySpace(): HostMemorySpace() { MmuInit(); }
|
||||
void Alloc(void **ptr, size_t bytes) { MmuAlloc(ptr, bytes); }
|
||||
void Dealloc(void *ptr) { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
|
||||
void Protect(const Memory& mem, size_t bytes)
|
||||
{ if (mem.h_rw) { mem.h_rw = false; MmuProtect(mem.h_ptr, bytes); } }
|
||||
void Unprotect(const Memory &mem, size_t bytes)
|
||||
{ if (!mem.h_rw) { mem.h_rw = true; MmuAllow(mem.h_ptr, bytes); } }
|
||||
void Protect(const void *ptr, size_t bytes) { MmuProtect(ptr, bytes); }
|
||||
void Unprotect(const void *ptr, size_t bytes) { MmuAllow(ptr, bytes); }
|
||||
/// Aliases need to be restricted during protection
|
||||
void AliasProtect(const void *ptr, size_t bytes)
|
||||
{ MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
|
||||
@@ -446,10 +442,8 @@ public:
|
||||
MmuDeviceMemorySpace(): DeviceMemorySpace() { }
|
||||
void Alloc(Memory &m) { MmuAlloc(&m.d_ptr, m.bytes); }
|
||||
void Dealloc(Memory &m) { MmuDealloc(m.d_ptr, m.bytes); }
|
||||
void Protect(const Memory &m)
|
||||
{ if (m.d_rw) { m.d_rw = false; MmuProtect(m.d_ptr, m.bytes); } }
|
||||
void Unprotect(const Memory &m)
|
||||
{ if (!m.d_rw) { m.d_rw = true; MmuAllow(m.d_ptr, m.bytes); } }
|
||||
void Protect(const Memory &m) { MmuProtect(m.d_ptr, m.bytes); }
|
||||
void Unprotect(const Memory &m) { MmuAllow(m.d_ptr, m.bytes); }
|
||||
/// Aliases need to be restricted during protection
|
||||
void AliasProtect(const void *ptr, size_t bytes)
|
||||
{ MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
|
||||
@@ -975,8 +969,11 @@ void MemoryManager::Copy_(void *dst_h_ptr, const void *src_h_ptr,
|
||||
{
|
||||
if (dst_h_ptr != src_d_ptr && bytes != 0)
|
||||
{
|
||||
internal::Memory &dst_h_base = maps->memories.at(dst_h_ptr);
|
||||
internal::Memory &src_d_base = maps->memories.at(src_d_ptr);
|
||||
MemoryType dst_h_mt = dst_h_base.h_mt;
|
||||
MemoryType src_d_mt = src_d_base.d_mt;
|
||||
ctrl->Host(dst_h_mt)->Unprotect(dst_h_ptr, bytes);
|
||||
ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
|
||||
}
|
||||
}
|
||||
@@ -1177,14 +1174,13 @@ void *MemoryManager::GetDevicePtr(const void *h_ptr, size_t bytes,
|
||||
const MemoryType &d_mt = mem.d_mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
if (!mem.d_ptr) { ctrl->Device(d_mt)->Alloc(mem); }
|
||||
// Aliases might have done some protections
|
||||
ctrl->Device(d_mt)->Unprotect(mem);
|
||||
if (copy_data)
|
||||
{
|
||||
MFEM_ASSERT(bytes <= mem.bytes, "invalid copy size");
|
||||
ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes);
|
||||
}
|
||||
ctrl->Host(h_mt)->Protect(mem, bytes);
|
||||
ctrl->Host(h_mt)->Protect(h_ptr, bytes);
|
||||
return mem.d_ptr;
|
||||
}
|
||||
|
||||
@@ -1210,7 +1206,6 @@ void *MemoryManager::GetAliasDevicePtr(const void *alias_ptr, size_t bytes,
|
||||
void *alias_d_ptr = static_cast<char*>(mem.d_ptr) + offset;
|
||||
MFEM_ASSERT(alias_h_ptr == alias_ptr, "internal error");
|
||||
MFEM_ASSERT(bytes <= alias.bytes, "internal error");
|
||||
mem.d_rw = false;
|
||||
ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes);
|
||||
ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
|
||||
if (copy) { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
|
||||
@@ -1226,8 +1221,8 @@ void *MemoryManager::GetHostPtr(const void *ptr, size_t bytes, bool copy)
|
||||
const MemoryType &h_mt = mem.h_mt;
|
||||
const MemoryType &d_mt = mem.d_mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
ctrl->Host(h_mt)->Unprotect(mem.h_ptr, bytes);
|
||||
// Aliases might have done some protections
|
||||
ctrl->Host(h_mt)->Unprotect(mem, bytes);
|
||||
if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
|
||||
if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
|
||||
if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
|
||||
@@ -1245,7 +1240,6 @@ void *MemoryManager::GetAliasHostPtr(const void *ptr, size_t bytes,
|
||||
void *alias_h_ptr = static_cast<char*>(mem->h_ptr) + alias.offset;
|
||||
void *alias_d_ptr = static_cast<char*>(mem->d_ptr) + alias.offset;
|
||||
MFEM_ASSERT(alias_h_ptr == ptr, "internal error");
|
||||
mem->h_rw = false;
|
||||
ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
|
||||
if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
|
||||
if (copy_data && mem->d_ptr)
|
||||
|
||||
@@ -76,13 +76,6 @@ if (MFEM_USE_GINKGO)
|
||||
list(APPEND HDRS ginkgo.hpp)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MUMPS)
|
||||
list(APPEND SRCS mumps.cpp)
|
||||
# If this list (HDRS -> HEADERS) is used for install, we probably want the
|
||||
# header added all the time.
|
||||
list(APPEND HDRS mumps.hpp)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_SUNDIALS)
|
||||
list(APPEND SRCS sundials.cpp)
|
||||
list(APPEND HDRS sundials.hpp)
|
||||
@@ -105,11 +98,6 @@ if (MFEM_USE_HIOP)
|
||||
list(APPEND HDRS hiop.hpp)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MKL_CPARDISO)
|
||||
list(APPEND SRCS cpardiso.cpp)
|
||||
list(APPEND HDRS cpardiso.hpp)
|
||||
endif()
|
||||
|
||||
convert_filenames_to_full_paths(SRCS)
|
||||
convert_filenames_to_full_paths(HDRS)
|
||||
|
||||
|
||||
+22
-54
@@ -26,10 +26,10 @@ ComplexOperator::ComplexOperator(Operator * Op_Real, Operator * Op_Imag,
|
||||
, ownReal_(ownReal)
|
||||
, ownImag_(ownImag)
|
||||
, convention_(convention)
|
||||
, x_r_()
|
||||
, x_i_()
|
||||
, y_r_()
|
||||
, y_i_()
|
||||
, x_r_(NULL, width / 2)
|
||||
, x_i_(NULL, width / 2)
|
||||
, y_r_(NULL, height / 2)
|
||||
, y_i_(NULL, height / 2)
|
||||
, u_(NULL)
|
||||
, v_(NULL)
|
||||
{}
|
||||
@@ -68,26 +68,14 @@ const Operator & ComplexOperator::imag() const
|
||||
|
||||
void ComplexOperator::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
x.Read();
|
||||
y.UseDevice(true); y = 0.0;
|
||||
double * x_data = x.GetData();
|
||||
x_r_.SetData(x_data);
|
||||
x_i_.SetData(&x_data[width / 2]);
|
||||
|
||||
x_r_.MakeRef(const_cast<Vector&>(x), 0, width/2);
|
||||
x_i_.MakeRef(const_cast<Vector&>(x), width/2, width/2);
|
||||
|
||||
y_r_.MakeRef(y, 0, height/2);
|
||||
y_i_.MakeRef(y, height/2, height/2);
|
||||
y_r_.SetData(&y[0]);
|
||||
y_i_.SetData(&y[height / 2]);
|
||||
|
||||
this->Mult(x_r_, x_i_, y_r_, y_i_);
|
||||
|
||||
y_r_.SyncAliasMemory(y);
|
||||
y_i_.SyncAliasMemory(y);
|
||||
|
||||
// Destroy alias vectors to prevent dangling aliases when the base vectors
|
||||
// are deleted
|
||||
x_r_.Destroy();
|
||||
x_i_.Destroy();
|
||||
y_r_.Destroy();
|
||||
y_i_.Destroy();
|
||||
}
|
||||
|
||||
void ComplexOperator::Mult(const Vector &x_r, const Vector &x_i,
|
||||
@@ -103,47 +91,31 @@ void ComplexOperator::Mult(const Vector &x_r, const Vector &x_i,
|
||||
y_r = 0.0;
|
||||
y_i = 0.0;
|
||||
}
|
||||
|
||||
if (Op_Imag_)
|
||||
{
|
||||
if (!v_) { v_ = new Vector(); }
|
||||
v_->UseDevice(true);
|
||||
v_->SetSize(Op_Imag_->Height());
|
||||
|
||||
if (!v_) { v_ = new Vector(Op_Imag_->Height()); }
|
||||
Op_Imag_->Mult(x_i, *v_);
|
||||
y_r.Add(-1.0, *v_);
|
||||
y_r_ -= *v_;
|
||||
Op_Imag_->Mult(x_r, *v_);
|
||||
y_i.Add(1.0, *v_);
|
||||
y_i_ += *v_;
|
||||
}
|
||||
|
||||
if (convention_ == BLOCK_SYMMETRIC)
|
||||
{
|
||||
y_i *= -1.0;
|
||||
y_i_ *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ComplexOperator::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
x.Read();
|
||||
y.UseDevice(true); y = 0.0;
|
||||
double * x_data = x.GetData();
|
||||
y_r_.SetData(x_data);
|
||||
y_i_.SetData(&x_data[height / 2]);
|
||||
|
||||
x_r_.MakeRef(const_cast<Vector&>(x), 0, height/2);
|
||||
x_i_.MakeRef(const_cast<Vector&>(x), height/2, height/2);
|
||||
x_r_.SetData(&y[0]);
|
||||
x_i_.SetData(&y[width / 2]);
|
||||
|
||||
y_r_.MakeRef(y, 0, width/2);
|
||||
y_i_.MakeRef(y, width/2, width/2);
|
||||
|
||||
this->MultTranspose(x_r_, x_i_, y_r_, y_i_);
|
||||
|
||||
y_r_.SyncAliasMemory(y);
|
||||
y_i_.SyncAliasMemory(y);
|
||||
|
||||
// Destroy alias vectors to prevent dangling aliases when the base vectors
|
||||
// are deleted
|
||||
x_r_.Destroy();
|
||||
x_i_.Destroy();
|
||||
y_r_.Destroy();
|
||||
y_i_.Destroy();
|
||||
this->MultTranspose(y_r_, y_i_, x_r_, x_i_);
|
||||
}
|
||||
|
||||
void ComplexOperator::MultTranspose(const Vector &x_r, const Vector &x_i,
|
||||
@@ -164,17 +136,13 @@ void ComplexOperator::MultTranspose(const Vector &x_r, const Vector &x_i,
|
||||
y_r = 0.0;
|
||||
y_i = 0.0;
|
||||
}
|
||||
|
||||
if (Op_Imag_)
|
||||
{
|
||||
if (!u_) { u_ = new Vector(); }
|
||||
u_->UseDevice(true);
|
||||
u_->SetSize(Op_Imag_->Width());
|
||||
|
||||
if (!u_) { u_ = new Vector(Op_Imag_->Width()); }
|
||||
Op_Imag_->MultTranspose(x_i, *u_);
|
||||
y_r.Add(convention_ == BLOCK_SYMMETRIC ? -1.0 : 1.0, *u_);
|
||||
y_r_.Add(convention_ == BLOCK_SYMMETRIC ? -1.0 : 1.0, *u_);
|
||||
Op_Imag_->MultTranspose(x_r, *u_);
|
||||
y_i.Add(-1.0, *u_);
|
||||
y_i_ -= *u_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
/** @brief Real or imaginary part accessor methods
|
||||
|
||||
The following accessor methods should only be called if the requested
|
||||
part of the operator is known to exist. This can be checked with
|
||||
part of the opertor is known to exist. This can be checked with
|
||||
hasRealPart() or hasImagPart().
|
||||
*/
|
||||
virtual Operator & real();
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
/** Combine the blocks making up this complex operator into a single
|
||||
SparseMatrix. The resulting matrix can be passed to solvers which require
|
||||
access to the matrix entries themselves, such as sparse direct solvers,
|
||||
rather than simply the action of the operator. Note that this combined
|
||||
rather than simply the action of the opertor. Note that this combined
|
||||
operator requires roughly twice the memory of the block structured
|
||||
operator. */
|
||||
SparseMatrix * GetSystemMatrix() const;
|
||||
@@ -269,7 +269,7 @@ public:
|
||||
HypreParMatrix. The resulting matrix can be passed to solvers which
|
||||
require access to the matrix entries themselves, such as sparse direct
|
||||
solvers or Hypre preconditioners, rather than simply the action of the
|
||||
operator. Note that this combined operator requires roughly twice the
|
||||
opertor. Note that this combined operator requires roughly twice the
|
||||
memory of the block structured operator. */
|
||||
HypreParMatrix * GetSystemMatrix() const;
|
||||
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "cpardiso.hpp"
|
||||
#include "hypre.hpp"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
CPardisoSolver::CPardisoSolver(MPI_Comm comm) : comm_(comm)
|
||||
{
|
||||
// Solver default parameters overridden with provided by iparm
|
||||
iparm[0] = 1;
|
||||
// Use METIS for fill-in reordering
|
||||
iparm[1] = 2;
|
||||
// Write solution into x
|
||||
iparm[5] = 0;
|
||||
// Max number of iterative refinement steps
|
||||
iparm[7] = 2;
|
||||
// Perturb the pivot elements with 1E-13
|
||||
iparm[9] = 13;
|
||||
// Use non-symmetric permutation and scaling MPS
|
||||
iparm[10] = 1;
|
||||
// Switch on Maximum Weighted Matching algorithm (default for non-symmetric)
|
||||
iparm[12] = 1;
|
||||
// Output: Number of non-zeros in the factor LU
|
||||
iparm[17] = -1;
|
||||
// Output: Mflops for LU factorization
|
||||
iparm[18] = -1;
|
||||
// Check input data for correctness
|
||||
iparm[26] = 1;
|
||||
// 0-based indexing
|
||||
iparm[34] = 1;
|
||||
// All inputs are distributed between MPI processes
|
||||
iparm[39] = 2;
|
||||
// Maximum number of numerical factorizations
|
||||
maxfct = 1;
|
||||
// Which factorization to use
|
||||
mnum = 1;
|
||||
// Print statistical information in file
|
||||
msglvl = 0;
|
||||
// Initialize error flag
|
||||
error = 0;
|
||||
// Real unsymmetric matrix
|
||||
mtype = MatType::REAL_UNSYMMETRIC;
|
||||
// Number of right hand sides
|
||||
nrhs = 1;
|
||||
};
|
||||
|
||||
void CPardisoSolver::SetOperator(const Operator &op)
|
||||
{
|
||||
auto hypreParMat = dynamic_cast<const HypreParMatrix &>(op);
|
||||
|
||||
MFEM_ASSERT(hypreParMat, "Must pass HypreParMatrix as Operator");
|
||||
|
||||
auto parcsr_op = static_cast<hypre_ParCSRMatrix *>(
|
||||
const_cast<HypreParMatrix &>(hypreParMat));
|
||||
|
||||
hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
|
||||
#if MFEM_HYPRE_VERSION >= 21600
|
||||
hypre_CSRMatrixBigJtoJ(csr_op);
|
||||
#endif
|
||||
|
||||
m = parcsr_op->global_num_rows;
|
||||
first_row = parcsr_op->first_row_index;
|
||||
nnz_loc = csr_op->num_nonzeros;
|
||||
m_loc = csr_op->num_rows;
|
||||
|
||||
height = m_loc;
|
||||
width = m_loc;
|
||||
|
||||
double *csr_nzval = csr_op->data;
|
||||
int *csr_colind = csr_op->j;
|
||||
|
||||
delete[] csr_rowptr;
|
||||
delete[] reordered_csr_colind;
|
||||
delete[] reordered_csr_nzval;
|
||||
csr_rowptr = new int[m_loc + 1];
|
||||
reordered_csr_colind = new int[nnz_loc];
|
||||
reordered_csr_nzval = new double[nnz_loc];
|
||||
|
||||
for (int i = 0; i <= m_loc; i++)
|
||||
{
|
||||
csr_rowptr[i] = (csr_op->i)[i];
|
||||
}
|
||||
|
||||
// CPardiso expects the column indices to be sorted for each row
|
||||
std::vector<int> permutation_idx(nnz_loc);
|
||||
std::iota(permutation_idx.begin(), permutation_idx.end(), 0);
|
||||
for (int i = 0; i < m_loc; i++)
|
||||
{
|
||||
std::sort(permutation_idx.begin() + csr_rowptr[i],
|
||||
permutation_idx.begin() + csr_rowptr[i + 1],
|
||||
[csr_colind](int i1, int i2)
|
||||
{
|
||||
return csr_colind[i1] < csr_colind[i2];
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < nnz_loc; i++)
|
||||
{
|
||||
reordered_csr_colind[i] = csr_colind[permutation_idx[i]];
|
||||
reordered_csr_nzval[i] = csr_nzval[permutation_idx[i]];
|
||||
}
|
||||
|
||||
hypre_CSRMatrixDestroy(csr_op);
|
||||
|
||||
// The number of row in global matrix, rhs element and solution vector that
|
||||
// begins the input domain belonging to this MPI process
|
||||
iparm[40] = first_row;
|
||||
|
||||
// The number of row in global matrix, rhs element and solution vector that
|
||||
// ends the input domain belonging to this MPI process
|
||||
iparm[41] = first_row + m_loc - 1;
|
||||
|
||||
// Analyze inputs
|
||||
phase = 11;
|
||||
cluster_sparse_solver(pt,
|
||||
&maxfct,
|
||||
&mnum,
|
||||
&mtype,
|
||||
&phase,
|
||||
&m,
|
||||
reordered_csr_nzval,
|
||||
csr_rowptr,
|
||||
reordered_csr_colind,
|
||||
&idum,
|
||||
&nrhs,
|
||||
iparm,
|
||||
&msglvl,
|
||||
&ddum,
|
||||
&ddum,
|
||||
&comm_,
|
||||
&error);
|
||||
|
||||
MFEM_ASSERT(error == 0, "Pardiso analyze input error");
|
||||
|
||||
// Numerical factorization
|
||||
phase = 22;
|
||||
cluster_sparse_solver(pt,
|
||||
&maxfct,
|
||||
&mnum,
|
||||
&mtype,
|
||||
&phase,
|
||||
&m,
|
||||
reordered_csr_nzval,
|
||||
csr_rowptr,
|
||||
reordered_csr_colind,
|
||||
&idum,
|
||||
&nrhs,
|
||||
iparm,
|
||||
&msglvl,
|
||||
&ddum,
|
||||
&ddum,
|
||||
&comm_,
|
||||
&error);
|
||||
|
||||
MFEM_ASSERT(error == 0, "Pardiso factorization input error");
|
||||
}
|
||||
|
||||
void CPardisoSolver::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
// Solve
|
||||
phase = 33;
|
||||
cluster_sparse_solver(pt,
|
||||
&maxfct,
|
||||
&mnum,
|
||||
&mtype,
|
||||
&phase,
|
||||
&m,
|
||||
reordered_csr_nzval,
|
||||
csr_rowptr,
|
||||
reordered_csr_colind,
|
||||
&idum,
|
||||
&nrhs,
|
||||
iparm,
|
||||
&msglvl,
|
||||
b.GetData(),
|
||||
x.GetData(),
|
||||
&comm_,
|
||||
&error);
|
||||
|
||||
MFEM_ASSERT(error == 0, "Pardiso solve error");
|
||||
}
|
||||
|
||||
void CPardisoSolver::SetPrintLevel(int print_level)
|
||||
{
|
||||
msglvl = print_level;
|
||||
}
|
||||
|
||||
void CPardisoSolver::SetMatrixType(MatType mat_type)
|
||||
{
|
||||
mtype = mat_type;
|
||||
}
|
||||
|
||||
CPardisoSolver::~CPardisoSolver()
|
||||
{
|
||||
// Release all internal memory
|
||||
phase = -1;
|
||||
cluster_sparse_solver(pt,
|
||||
&maxfct,
|
||||
&mnum,
|
||||
&mtype,
|
||||
&phase,
|
||||
&m,
|
||||
reordered_csr_nzval,
|
||||
csr_rowptr,
|
||||
reordered_csr_colind,
|
||||
&idum,
|
||||
&nrhs,
|
||||
iparm,
|
||||
&msglvl,
|
||||
&ddum,
|
||||
&ddum,
|
||||
&comm_,
|
||||
&error);
|
||||
|
||||
MFEM_ASSERT(error == 0, "Pardiso free error");
|
||||
|
||||
delete[] csr_rowptr;
|
||||
delete[] reordered_csr_colind;
|
||||
delete[] reordered_csr_nzval;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_USE_MKL_CPARDISO
|
||||
#endif // MFEM_USE_MPI
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_CPARDISO
|
||||
#define MFEM_CPARDISO
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "operator.hpp"
|
||||
#include <mpi.h>
|
||||
#include "mkl_cluster_sparse_solver.h"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
/**
|
||||
* @brief MKL Parallel Direct Sparse Solver for Clusters
|
||||
*
|
||||
* Interface to the MPI enabled MKL version of Pardiso
|
||||
*/
|
||||
class CPardisoSolver : public Solver
|
||||
{
|
||||
public:
|
||||
enum MatType
|
||||
{
|
||||
REAL_STRUCTURE_SYMMETRIC = 1,
|
||||
REAL_UNSYMMETRIC = 11
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Construct a new CPardisoSolver object
|
||||
*
|
||||
* @param comm MPI Communicator
|
||||
*/
|
||||
CPardisoSolver(MPI_Comm comm);
|
||||
|
||||
/**
|
||||
* @brief Set the Operator object and perform factorization
|
||||
*
|
||||
* @a op needs to be of type HypreParMatrix. The contents are copied and
|
||||
* reordered in an internal CSR structure.
|
||||
*
|
||||
* @param op Operator to use in factorization and solve
|
||||
*/
|
||||
void SetOperator(const Operator &op) override;
|
||||
|
||||
/**
|
||||
* @brief Solve
|
||||
*
|
||||
* @param b RHS vector
|
||||
* @param x Solution vector
|
||||
*/
|
||||
void Mult(const Vector &b, Vector &x) const override;
|
||||
|
||||
/**
|
||||
* @brief Set the print level for Pardiso
|
||||
*
|
||||
* Prints statistics after the factorization and after each solve.
|
||||
*
|
||||
* @param print_lvl Print level
|
||||
*/
|
||||
void SetPrintLevel(int print_lvl);
|
||||
|
||||
/**
|
||||
* @brief Set the matrix type
|
||||
*
|
||||
* The matrix type supported is either real and symmetric or real and
|
||||
* non-symmetric.
|
||||
*
|
||||
* @param mat_type Matrix type
|
||||
*/
|
||||
void SetMatrixType(MatType mat_type);
|
||||
|
||||
~CPardisoSolver();
|
||||
|
||||
private:
|
||||
MPI_Comm comm_;
|
||||
|
||||
// Global number of rows
|
||||
int m;
|
||||
|
||||
// First row index of the global matrix on the local MPI rank
|
||||
int first_row;
|
||||
|
||||
// Local number of nonzero entries
|
||||
int nnz_loc;
|
||||
|
||||
// Local number of rows, obtained from a ParCSR matrix
|
||||
int m_loc;
|
||||
|
||||
// CSR data structure for the copy data of the local CSR matrix
|
||||
int *csr_rowptr = nullptr;
|
||||
double *reordered_csr_nzval = nullptr;
|
||||
int *reordered_csr_colind = nullptr;
|
||||
|
||||
// Internal solver memory pointer pt,
|
||||
// 32-bit: int pt[64]
|
||||
// 64-bit: long int pt[64] or void *pt[64] should be OK on both architectures
|
||||
mutable void *pt[64] = {0};
|
||||
|
||||
// Solver control parameters, detailed description can be found in the
|
||||
// constructor.
|
||||
mutable int iparm[64] = {0};
|
||||
mutable int maxfct, mnum, msglvl, phase, error;
|
||||
int mtype;
|
||||
int nrhs;
|
||||
|
||||
// Dummy variables
|
||||
mutable int idum;
|
||||
mutable double ddum;
|
||||
};
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
#endif // MFEM_USE_MKL_CPARDISO
|
||||
#endif // MFEM_USE_MPI
|
||||
+26
-26
@@ -373,7 +373,7 @@ void DenseMatrix::SymmetricScaling(const Vector & s)
|
||||
{
|
||||
if (height != width || s.Size() != height)
|
||||
{
|
||||
mfem_error("DenseMatrix::SymmetricScaling: dimension mismatch");
|
||||
mfem_error("DenseMatrix::SymmetricScaling");
|
||||
}
|
||||
|
||||
double * ss = new double[width];
|
||||
@@ -401,7 +401,7 @@ void DenseMatrix::InvSymmetricScaling(const Vector & s)
|
||||
{
|
||||
if (height != width || s.Size() != width)
|
||||
{
|
||||
mfem_error("DenseMatrix::InvSymmetricScaling: dimension mismatch");
|
||||
mfem_error("DenseMatrix::SymmetricScaling");
|
||||
}
|
||||
|
||||
double * ss = new double[width];
|
||||
@@ -528,7 +528,7 @@ double DenseMatrix::Weight() const
|
||||
double F = d[0] * d[3] + d[1] * d[4] + d[2] * d[5];
|
||||
return sqrt(E * G - F * F);
|
||||
}
|
||||
mfem_error("DenseMatrix::Weight(): mismatched or unsupported dimensions");
|
||||
mfem_error("DenseMatrix::Weight()");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ void DenseMatrix::Invert()
|
||||
#ifdef MFEM_DEBUG
|
||||
if (Height() <= 0 || Height() != Width())
|
||||
{
|
||||
mfem_error("DenseMatrix::Invert(): dimension mismatch");
|
||||
mfem_error("DenseMatrix::Invert()");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1083,7 +1083,7 @@ void DenseMatrix::Eigensystem(Vector &ev, DenseMatrix *evect)
|
||||
|
||||
MFEM_CONTRACT_VAR(ev);
|
||||
MFEM_CONTRACT_VAR(evect);
|
||||
mfem_error("DenseMatrix::Eigensystem: Compiled without LAPACK");
|
||||
mfem_error("DenseMatrix::Eigensystem");
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -1164,7 +1164,7 @@ void DenseMatrix::Eigensystem(DenseMatrix &b, Vector &ev,
|
||||
MFEM_CONTRACT_VAR(b);
|
||||
MFEM_CONTRACT_VAR(ev);
|
||||
MFEM_CONTRACT_VAR(evect);
|
||||
mfem_error("DenseMatrix::Eigensystem(generalized): Compiled without LAPACK");
|
||||
mfem_error("DenseMatrix::Eigensystem for generalized eigenvalues");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1204,7 +1204,7 @@ void DenseMatrix::SingularValues(Vector &sv) const
|
||||
#else
|
||||
MFEM_CONTRACT_VAR(sv);
|
||||
// compiling without lapack
|
||||
mfem_error("DenseMatrix::SingularValues: Compiled without LAPACK");
|
||||
mfem_error("DenseMatrix::SingularValues");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1441,7 +1441,7 @@ void DenseMatrix::GradToCurl(DenseMatrix &curl)
|
||||
if ((Width() != 2 || curl.Width() != 1 || 2*n != curl.Height()) &&
|
||||
(Width() != 3 || curl.Width() != 3 || 3*n != curl.Height()))
|
||||
{
|
||||
mfem_error("DenseMatrix::GradToCurl(...): dimension mismatch");
|
||||
mfem_error("DenseMatrix::GradToCurl(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1676,7 +1676,7 @@ void DenseMatrix::AddMatrix(DenseMatrix &A, int ro, int co)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (co+aw > Width() || ro+ah > h)
|
||||
{
|
||||
mfem_error("DenseMatrix::AddMatrix(...) 1 : dimension mismatch");
|
||||
mfem_error("DenseMatrix::AddMatrix(...) 1");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1706,7 +1706,7 @@ void DenseMatrix::AddMatrix(double a, const DenseMatrix &A, int ro, int co)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (co+aw > Width() || ro+ah > h)
|
||||
{
|
||||
mfem_error("DenseMatrix::AddMatrix(...) 2 : dimension mismatch");
|
||||
mfem_error("DenseMatrix::AddMatrix(...) 2");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1753,7 +1753,7 @@ void DenseMatrix::AdjustDofDirection(Array<int> &dofs)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (dofs.Size() != n || Width() != n)
|
||||
{
|
||||
mfem_error("DenseMatrix::AdjustDofDirection(...): dimension mismatch");
|
||||
mfem_error("DenseMatrix::AdjustDofDirection(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2093,11 +2093,11 @@ void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (a.Width() > a.Height() || a.Width() < 1 || a.Height() > 3)
|
||||
{
|
||||
mfem_error("CalcAdjugate(...): unsupported dimensions");
|
||||
mfem_error("CalcAdjugate(...)");
|
||||
}
|
||||
if (a.Width() != adja.Height() || a.Height() != adja.Width())
|
||||
{
|
||||
mfem_error("CalcAdjugate(...): dimension mismatch");
|
||||
mfem_error("CalcAdjugate(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2166,7 +2166,7 @@ void CalcAdjugateTranspose(const DenseMatrix &a, DenseMatrix &adjat)
|
||||
if (a.Height() != a.Width() || adjat.Height() != adjat.Width() ||
|
||||
a.Width() != adjat.Width() || a.Width() < 1 || a.Width() > 3)
|
||||
{
|
||||
mfem_error("CalcAdjugateTranspose(...): dimension mismatch");
|
||||
mfem_error("CalcAdjugateTranspose(...)");
|
||||
}
|
||||
#endif
|
||||
if (a.Width() == 1)
|
||||
@@ -2269,7 +2269,7 @@ void CalcInverseTranspose(const DenseMatrix &a, DenseMatrix &inva)
|
||||
if ( (a.Width() != a.Height()) || ( (a.Height()!= 1) && (a.Height()!= 2)
|
||||
&& (a.Height()!= 3) ) )
|
||||
{
|
||||
mfem_error("CalcInverseTranspose(...): dimension mismatch");
|
||||
mfem_error("CalcInverseTranspose(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2396,7 +2396,7 @@ void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
|
||||
if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
|
||||
A.Width() != B.Width())
|
||||
{
|
||||
mfem_error("MultABt(...): dimension mismatch");
|
||||
mfem_error("MultABt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2462,7 +2462,7 @@ void MultADBt(const DenseMatrix &A, const Vector &D,
|
||||
if (A.Height() != ADBt.Height() || B.Height() != ADBt.Width() ||
|
||||
A.Width() != B.Width() || A.Width() != D.Size())
|
||||
{
|
||||
mfem_error("MultADBt(...): dimension mismatch");
|
||||
mfem_error("MultADBt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2501,7 +2501,7 @@ void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
|
||||
if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
|
||||
A.Width() != B.Width())
|
||||
{
|
||||
mfem_error("AddMultABt(...): dimension mismatch");
|
||||
mfem_error("AddMultABt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2559,7 +2559,7 @@ void AddMultADBt(const DenseMatrix &A, const Vector &D,
|
||||
if (A.Height() != ADBt.Height() || B.Height() != ADBt.Width() ||
|
||||
A.Width() != B.Width() || A.Width() != D.Size())
|
||||
{
|
||||
mfem_error("AddMultADBt(...): dimension mismatch");
|
||||
mfem_error("AddMultADBt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2595,7 +2595,7 @@ void AddMult_a_ABt(double a, const DenseMatrix &A, const DenseMatrix &B,
|
||||
if (A.Height() != ABt.Height() || B.Height() != ABt.Width() ||
|
||||
A.Width() != B.Width())
|
||||
{
|
||||
mfem_error("AddMult_a_ABt(...): dimension mismatch");
|
||||
mfem_error("AddMult_a_ABt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2653,7 +2653,7 @@ void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
|
||||
if (A.Width() != AtB.Height() || B.Width() != AtB.Width() ||
|
||||
A.Height() != B.Height())
|
||||
{
|
||||
mfem_error("MultAtB(...): dimension mismatch");
|
||||
mfem_error("MultAtB(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2761,7 +2761,7 @@ void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (v.Size() != VWt.Height() || w.Size() != VWt.Width())
|
||||
{
|
||||
mfem_error("MultVWt(...): dimension mismatch");
|
||||
mfem_error("MultVWt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2782,7 +2782,7 @@ void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (VWt.Height() != m || VWt.Width() != n)
|
||||
{
|
||||
mfem_error("AddMultVWt(...): dimension mismatch");
|
||||
mfem_error("AddMultVWt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2803,7 +2803,7 @@ void AddMultVVt(const Vector &v, DenseMatrix &VVt)
|
||||
#ifdef MFEM_DEBUG
|
||||
if (VVt.Height() != n || VVt.Width() != n)
|
||||
{
|
||||
mfem_error("AddMultVVt(...): dimension mismatch");
|
||||
mfem_error("AddMultVVt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2828,7 +2828,7 @@ void AddMult_a_VWt(const double a, const Vector &v, const Vector &w,
|
||||
#ifdef MFEM_DEBUG
|
||||
if (VWt.Height() != m || VWt.Width() != n)
|
||||
{
|
||||
mfem_error("AddMult_a_VWt(...): dimension mismatch");
|
||||
mfem_error("AddMult_a_VWt(...)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3353,7 +3353,7 @@ void DenseMatrixEigensystem::Eval()
|
||||
#ifdef MFEM_DEBUG
|
||||
if (mat.Width() != n)
|
||||
{
|
||||
mfem_error("DenseMatrixEigensystem::Eval(): dimension mismatch");
|
||||
mfem_error("DenseMatrixEigensystem::Eval()");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+1
-22
@@ -3215,31 +3215,10 @@ void HypreBoomerAMG::SetOperator(const Operator &op)
|
||||
B = X = NULL;
|
||||
}
|
||||
|
||||
void HypreBoomerAMG::SetSystemsOptions(int dim, bool order_bynodes)
|
||||
void HypreBoomerAMG::SetSystemsOptions(int dim)
|
||||
{
|
||||
HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim);
|
||||
|
||||
// The default "system" ordering in hypre is Ordering::byVDIM. When we are
|
||||
// using Ordering::byNODES, we have to specify the ordering explicitly with
|
||||
// HYPRE_BoomerAMGSetDofFunc as in the following code.
|
||||
if (order_bynodes)
|
||||
{
|
||||
// hypre actually deletes the following pointer in HYPRE_BoomerAMGDestroy,
|
||||
// so we don't need to track it
|
||||
HYPRE_Int *mapping = mfem_hypre_CTAlloc(HYPRE_Int, height);
|
||||
int h_nnodes = height / dim; // nodes owned in linear algebra (not fem)
|
||||
MFEM_VERIFY(height % dim == 0, "Ordering does not work as claimed!");
|
||||
int k = 0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
for (int j = 0; j < h_nnodes; ++j)
|
||||
{
|
||||
mapping[k++] = i;
|
||||
}
|
||||
}
|
||||
HYPRE_BoomerAMGSetDofFunc(amg_precond, mapping);
|
||||
}
|
||||
|
||||
// More robust options with respect to convergence
|
||||
HYPRE_BoomerAMGSetAggNumLevels(amg_precond, 0);
|
||||
HYPRE_BoomerAMGSetStrongThreshold(amg_precond, 0.5);
|
||||
|
||||
+5
-4
@@ -992,15 +992,16 @@ public:
|
||||
|
||||
virtual void SetOperator(const Operator &op);
|
||||
|
||||
/** More robust options for systems, such as elasticity. */
|
||||
void SetSystemsOptions(int dim, bool order_bynodes=false);
|
||||
/** More robust options for systems, such as elasticity. Note that BoomerAMG
|
||||
assumes Ordering::byVDIM in the finite element space used to generate the
|
||||
matrix A. */
|
||||
void SetSystemsOptions(int dim);
|
||||
|
||||
/** A special elasticity version of BoomerAMG that takes advantage of
|
||||
geometric rigid body modes and could perform better on some problems, see
|
||||
"Improving algebraic multigrid interpolation operators for linear
|
||||
elasticity problems", Baker, Kolev, Yang, NLAA 2009, DOI:10.1002/nla.688.
|
||||
This solver assumes Ordering::byVDIM in the FiniteElementSpace used to
|
||||
construct A. */
|
||||
As with SetSystemsOptions(), this solver assumes Ordering::byVDIM. */
|
||||
void SetElasticityOptions(ParFiniteElementSpace *fespace);
|
||||
|
||||
void SetPrintLevel(int print_level)
|
||||
|
||||
@@ -45,10 +45,6 @@
|
||||
#include "hypre_parcsr.hpp"
|
||||
#include "hypre.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
#include "mumps.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_PETSC
|
||||
#include "petsc.hpp"
|
||||
#endif
|
||||
@@ -65,10 +61,6 @@
|
||||
#include "strumpack.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
#include "cpardiso.hpp"
|
||||
#endif
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,387 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "mumps.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
MUMPSSolver::~MUMPSSolver()
|
||||
{
|
||||
if (id)
|
||||
{
|
||||
id->job = -2;
|
||||
dmumps_c(id);
|
||||
delete[] J;
|
||||
delete[] I;
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
|
||||
void MUMPSSolver::SetParameters()
|
||||
{
|
||||
// output messages
|
||||
id->ICNTL(1) = -1;
|
||||
|
||||
// Diagnosting printing
|
||||
id->ICNTL(2) = -1;
|
||||
|
||||
// Global info on host
|
||||
id->ICNTL(3) = -1;
|
||||
|
||||
// Level of error printing
|
||||
id->ICNTL(4) = 0;
|
||||
|
||||
//input matrix format (assembled)
|
||||
id->ICNTL(5) = 0;
|
||||
|
||||
// Use A or A^T
|
||||
id->ICNTL(9) = 1;
|
||||
|
||||
// Iterative refinement (disabled)
|
||||
id->ICNTL(10) = 0;
|
||||
|
||||
// Error analysis-statistics (disabled)
|
||||
id->ICNTL(11) = 0;
|
||||
|
||||
// Use of ScaLAPACK (Parallel factorization on root)
|
||||
id->ICNTL(13) = 0;
|
||||
|
||||
// Percentage increase of estimated workspace (default = 20%)
|
||||
id->ICNTL(14) = 20;
|
||||
|
||||
// Number of OpenMP threads (default)
|
||||
id->ICNTL(16) = 0;
|
||||
|
||||
// Matrix input format (distributed)
|
||||
id->ICNTL(18) = 3;
|
||||
|
||||
// Schur complement (no Schur complement matrix returned)
|
||||
id->ICNTL(19) = 0;
|
||||
|
||||
#if MFEM_MUMPS_VERSION >= 530
|
||||
// Distributed RHS and Sol
|
||||
id->ICNTL(20) = 10;
|
||||
|
||||
id->ICNTL(21) = 1;
|
||||
#else
|
||||
// Centralized RHS and Sol
|
||||
id->ICNTL(20) = 0;
|
||||
|
||||
id->ICNTL(21) = 0;
|
||||
#endif
|
||||
// Out of core factorization and solve (disabled)
|
||||
id->ICNTL(22) = 0;
|
||||
|
||||
// Max size of working memory (default = based on estimates)
|
||||
id->ICNTL(23) = 0;
|
||||
}
|
||||
|
||||
void MUMPSSolver::SetOperator(const Operator &op)
|
||||
{
|
||||
// Verify that the operator is a HypreParMatrix
|
||||
auto APtr = dynamic_cast<const HypreParMatrix *>(&op);
|
||||
MFEM_VERIFY(APtr, "Not compatible matrix type");
|
||||
height = op.Height();
|
||||
width = op.Width();
|
||||
|
||||
comm = APtr->GetComm();
|
||||
MPI_Comm_size(comm, &numProcs);
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
|
||||
hypre_ParCSRMatrix *parcsr_op
|
||||
= (hypre_ParCSRMatrix *) const_cast<HypreParMatrix &>(*APtr);
|
||||
hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
|
||||
#if MFEM_HYPRE_VERSION >= 21600
|
||||
hypre_CSRMatrixBigJtoJ(csr_op);
|
||||
#endif
|
||||
|
||||
int *Iptr = csr_op->i;
|
||||
int *Jptr = csr_op->j;
|
||||
int n_loc = csr_op->num_rows;
|
||||
|
||||
row_start = parcsr_op->first_row_index;
|
||||
|
||||
int nnz;
|
||||
if (sym)
|
||||
{
|
||||
// count nnz;
|
||||
nnz = 0;
|
||||
int k = 0;
|
||||
for (int i = 0; i < n_loc; i++)
|
||||
{
|
||||
for (int j = Iptr[i]; j < Iptr[i + 1]; j++)
|
||||
{
|
||||
int ii = row_start + i + 1;
|
||||
int jj = Jptr[k] + 1;
|
||||
k++;
|
||||
if (ii>=jj) { nnz++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nnz = csr_op->num_nonzeros;
|
||||
}
|
||||
|
||||
I = new int[nnz];
|
||||
J = new int[nnz];
|
||||
|
||||
int k = 0;
|
||||
if (sym)
|
||||
{
|
||||
int l = 0;
|
||||
data = new double[nnz];
|
||||
for (int i = 0; i < n_loc; i++)
|
||||
{
|
||||
for (int j = Iptr[i]; j < Iptr[i + 1]; j++)
|
||||
{
|
||||
// Global I and J indices in 1-based index (for fortran)
|
||||
int ii = row_start + i + 1;
|
||||
int jj = Jptr[k] + 1;
|
||||
if (ii>=jj)
|
||||
{
|
||||
I[l] = ii;
|
||||
J[l] = jj;
|
||||
data[l++] = csr_op->data[k];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < n_loc; i++)
|
||||
{
|
||||
for (int j = Iptr[i]; j < Iptr[i + 1]; j++)
|
||||
{
|
||||
// Global I and J indices in 1-based index (for fortran)
|
||||
I[k] = row_start + i + 1;
|
||||
J[k] = Jptr[k] + 1;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
data = csr_op->data;
|
||||
}
|
||||
|
||||
// new MUMPS object
|
||||
id = new DMUMPS_STRUC_C;
|
||||
|
||||
// C to Fortran communicator
|
||||
id->comm_fortran = (MUMPS_INT) MPI_Comm_c2f(comm);
|
||||
|
||||
// Host is involved in computation
|
||||
id->par = 1;
|
||||
|
||||
// Unsymmetric matrix
|
||||
id->sym = sym;
|
||||
|
||||
// Mumps init
|
||||
id->job = -1;
|
||||
dmumps_c(id);
|
||||
|
||||
// Set MUMPS default parameters
|
||||
SetParameters();
|
||||
|
||||
// Global number of rows
|
||||
id->n = parcsr_op->global_num_rows;
|
||||
|
||||
// Number of non zeros on the processor
|
||||
id->nnz_loc = nnz;
|
||||
|
||||
// Distributed row array
|
||||
id->irn_loc = I;
|
||||
|
||||
// Distributed column array
|
||||
id->jcn_loc = J;
|
||||
|
||||
// Distributed data array
|
||||
id->a_loc = data;
|
||||
|
||||
// MUMPS Analysis
|
||||
id->job = 1;
|
||||
dmumps_c(id);
|
||||
|
||||
// MUMPS Factorization
|
||||
id->job = 2;
|
||||
dmumps_c(id);
|
||||
|
||||
// matrix can be destroyed now
|
||||
hypre_CSRMatrixDestroy(csr_op);
|
||||
if (!sym) { data = nullptr; }
|
||||
|
||||
#if MFEM_MUMPS_VERSION >= 530
|
||||
irhs_loc.SetSize(n_loc);
|
||||
for (int i = 0; i < n_loc; i++)
|
||||
{
|
||||
irhs_loc[i] = row_start + i + 1;
|
||||
}
|
||||
row_starts.SetSize(numProcs);
|
||||
MPI_Allgather(&row_start, 1, MPI_INT, row_starts, 1, MPI_INT, comm);
|
||||
sol_loc.SetSize(id->INFO(23));
|
||||
isol_loc.SetSize(id->INFO(23));
|
||||
#else
|
||||
if (myid == 0)
|
||||
{
|
||||
rhs_glob.SetSize(parcsr_op->global_num_rows);
|
||||
recv_counts.SetSize(numProcs);
|
||||
}
|
||||
MPI_Gather(&n_loc, 1, MPI_INT, recv_counts, 1, MPI_INT, 0, comm);
|
||||
if (myid == 0)
|
||||
{
|
||||
displs.SetSize(numProcs); displs[0] = 0;
|
||||
int s = 0;
|
||||
for (int k = 0; k < numProcs-1; k++)
|
||||
{
|
||||
s += recv_counts[k];
|
||||
displs[k+1] = s;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MUMPSSolver::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
#if MFEM_MUMPS_VERSION >= 530
|
||||
id->nloc_rhs = x.Size();
|
||||
id->lrhs_loc = x.Size();
|
||||
id->rhs_loc = x.GetData();
|
||||
id->irhs_loc = const_cast<int *>(irhs_loc.GetData());
|
||||
id->sol_loc = sol_loc.GetData();
|
||||
id->lsol_loc = id->INFO(23);
|
||||
id->isol_loc = const_cast<int *>(isol_loc.GetData());
|
||||
id->job = 3;
|
||||
dmumps_c(id);
|
||||
RedistributeSol(isol_loc, sol_loc, y);
|
||||
#else
|
||||
MPI_Gatherv(x.GetData(), x.Size(), MPI_DOUBLE,
|
||||
rhs_glob.GetData(), recv_counts,
|
||||
displs, MPI_DOUBLE, 0, comm);
|
||||
if (myid == 0)
|
||||
{
|
||||
id->rhs = rhs_glob.GetData();
|
||||
}
|
||||
id->job = 3;
|
||||
dmumps_c(id);
|
||||
MPI_Scatterv(rhs_glob.GetData(), recv_counts, displs,
|
||||
MPI_DOUBLE, y.GetData(), y.Size(),
|
||||
MPI_DOUBLE, 0, comm);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MUMPSSolver::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
id->ICNTL(9) = 0;
|
||||
Mult(x,y);
|
||||
}
|
||||
|
||||
#if MFEM_MUMPS_VERSION >= 530
|
||||
int MUMPSSolver::GetRowRank(int i, const Array<int> &row_starts_) const
|
||||
{
|
||||
if (row_starts_.Size() == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
auto up = std::upper_bound(row_starts_.begin(), row_starts_.end(), i);
|
||||
return std::distance(row_starts_.begin(), up) - 1;
|
||||
}
|
||||
|
||||
void MUMPSSolver::RedistributeSol(const Array<int> &row_map,
|
||||
const Vector &x,
|
||||
Vector &y) const
|
||||
{
|
||||
MFEM_VERIFY(row_map.Size() == x.Size(), "Inconcistent sizes");
|
||||
int size = x.Size();
|
||||
|
||||
// compute send_count
|
||||
Array<int> send_count(numProcs);
|
||||
send_count = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
int j = row_map[i] - 1; //fix to 0-based indexing
|
||||
int row_rank = GetRowRank(j, row_starts);
|
||||
send_count[row_rank]++; // both for val and global index
|
||||
}
|
||||
|
||||
// compute recv_count
|
||||
Array<int> recv_count(numProcs);
|
||||
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
|
||||
|
||||
// compute offsets
|
||||
Array<int> send_displ(numProcs);
|
||||
send_displ[0] = 0;
|
||||
Array<int> recv_displ(numProcs);
|
||||
recv_displ[0] = 0;
|
||||
for (int k = 0; k < numProcs - 1; k++)
|
||||
{
|
||||
send_displ[k + 1] = send_displ[k] + send_count[k];
|
||||
recv_displ[k + 1] = recv_displ[k] + recv_count[k];
|
||||
}
|
||||
int sbuff_size = send_count.Sum();
|
||||
int rbuff_size = recv_count.Sum();
|
||||
|
||||
Array<int> sendbuf_index(sbuff_size);
|
||||
sendbuf_index = 0;
|
||||
Array<double> sendbuf_value(sbuff_size);
|
||||
sendbuf_value = 0;
|
||||
Array<int> soffs(numProcs);
|
||||
soffs = 0;
|
||||
|
||||
// Fill in send buffers
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
int j = row_map[i] - 1; //fix to 0-based indexing
|
||||
int row_rank = GetRowRank(j, row_starts);
|
||||
int k = send_displ[row_rank] + soffs[row_rank];
|
||||
sendbuf_index[k] = j;
|
||||
sendbuf_value[k] = x(i);
|
||||
soffs[row_rank]++;
|
||||
}
|
||||
|
||||
// communicate
|
||||
Array<int> recvbuf_index(rbuff_size);
|
||||
Array<double> recvbuf_value(rbuff_size);
|
||||
MPI_Alltoallv(sendbuf_index,
|
||||
send_count,
|
||||
send_displ,
|
||||
MPI_INT,
|
||||
recvbuf_index,
|
||||
recv_count,
|
||||
recv_displ,
|
||||
MPI_INT,
|
||||
comm);
|
||||
MPI_Alltoallv(sendbuf_value,
|
||||
send_count,
|
||||
send_displ,
|
||||
MPI_DOUBLE,
|
||||
recvbuf_value,
|
||||
recv_count,
|
||||
recv_displ,
|
||||
MPI_DOUBLE,
|
||||
comm);
|
||||
|
||||
// Unpack recv buffer
|
||||
for (int i = 0; i < rbuff_size; i++)
|
||||
{
|
||||
int local_index = recvbuf_index[i] - row_start;
|
||||
y(local_index) = recvbuf_value[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
#endif // MFEM_USE_MUMPS
|
||||
@@ -1,104 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_MUMPS
|
||||
#define MFEM_MUMPS
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "operator.hpp"
|
||||
#include "hypre.hpp"
|
||||
|
||||
#include <mpi.h>
|
||||
#include "dmumps_c.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
class MUMPSSolver : public mfem::Solver
|
||||
{
|
||||
public:
|
||||
// Default Constructor.
|
||||
MUMPSSolver() {}
|
||||
|
||||
void SetMatrixSymType(int sym_) { sym = (sym_>2) ? 0 : sym_ ; }
|
||||
|
||||
// Factor and solve the linear system y = Op^{-1} x.
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
|
||||
// Set the operator.
|
||||
void SetOperator(const Operator &op);
|
||||
|
||||
// Default destructor.
|
||||
~MUMPSSolver();
|
||||
|
||||
private:
|
||||
|
||||
MPI_Comm comm;
|
||||
|
||||
int numProcs;
|
||||
|
||||
int myid;
|
||||
|
||||
int sym=0;
|
||||
|
||||
int row_start;
|
||||
|
||||
int *I;
|
||||
|
||||
int *J;
|
||||
|
||||
double * data;
|
||||
|
||||
// MUMPS workspace
|
||||
// macro s.t. indices match MUMPS documentation
|
||||
#define ICNTL(I) icntl[(I) -1]
|
||||
#define INFO(I) info[(I) -1]
|
||||
|
||||
DMUMPS_STRUC_C *id=nullptr;
|
||||
|
||||
void SetParameters();
|
||||
|
||||
#if MFEM_MUMPS_VERSION >= 530
|
||||
|
||||
Array<int> row_starts;
|
||||
|
||||
Array<int> irhs_loc;
|
||||
|
||||
Array<int> isol_loc;
|
||||
|
||||
Vector sol_loc;
|
||||
|
||||
int GetRowRank(int i, const Array<int> &row_starts_) const;
|
||||
|
||||
void RedistributeSol(const Array<int> &row_map,
|
||||
const Vector &x,
|
||||
Vector &y) const;
|
||||
#else
|
||||
Array<int> recv_counts;
|
||||
|
||||
Array<int> displs;
|
||||
|
||||
Vector rhs_glob;
|
||||
|
||||
#endif
|
||||
|
||||
}; // mfem::MUMPSSolver class
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
#endif // MFEM_USE_MUMPS
|
||||
#endif // MFEM_MUMPS
|
||||
@@ -2972,4 +2972,36 @@ KLUSolver::~KLUSolver()
|
||||
|
||||
#endif // MFEM_USE_SUITESPARSE
|
||||
|
||||
IncompleteCholesky::IncompleteCholesky(SparseMatrix &A_) : A(&A_)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->IncompleteCholeskySetup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void IncompleteCholesky::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->IncompleteCholeskyMult(b, x);
|
||||
#else
|
||||
x = b;
|
||||
#endif
|
||||
}
|
||||
|
||||
ILUcusparse::ILUcusparse(SparseMatrix &A_) : A(&A_)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->ILUSetup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILUcusparse::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->ILUMult(b, x);
|
||||
#else
|
||||
x = b;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -799,6 +799,28 @@ public:
|
||||
|
||||
#endif // MFEM_USE_SUITESPARSE
|
||||
|
||||
class IncompleteCholesky : public IterativeSolver
|
||||
{
|
||||
private:
|
||||
SparseMatrix *A;
|
||||
|
||||
public:
|
||||
IncompleteCholesky(SparseMatrix &A_);
|
||||
|
||||
virtual void Mult(const Vector &b, Vector &x) const;
|
||||
};
|
||||
|
||||
class ILUcusparse : public IterativeSolver
|
||||
{
|
||||
private:
|
||||
SparseMatrix *A;
|
||||
|
||||
public:
|
||||
ILUcusparse(SparseMatrix &A_);
|
||||
|
||||
virtual void Mult(const Vector &b, Vector &x) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MFEM_SOLVERS
|
||||
|
||||
@@ -3899,4 +3899,323 @@ void SparseMatrix::Swap(SparseMatrix &other)
|
||||
mfem::Swap(isSorted, other.isSorted);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
void SparseMatrix::IncompleteCholeskyMult(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
|
||||
{
|
||||
y = x;
|
||||
return;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(initCholesky, "Setup not done");
|
||||
|
||||
const double alpha = 1.0;
|
||||
|
||||
auto d_x = x.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
int64_t m = height;
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
|
||||
cusparseDnVecSetValues(vecY_descr, d_y);
|
||||
cusparseDnVecSetValues(vecZ_descr, d_z);
|
||||
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_Lt = CUSPARSE_OPERATION_TRANSPOSE;
|
||||
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_Lt = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
|
||||
// Solve L*z = x
|
||||
cusparseDcsrsv2_solve(handle, trans_L, m, nnz, &alpha, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_L,
|
||||
d_x, d_z, policy_L, pBuffer);
|
||||
|
||||
// Solve L'*y = z
|
||||
cusparseDcsrsv2_solve(handle, trans_Lt, m, nnz, &alpha, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_Lt,
|
||||
d_z, d_y, policy_Lt, pBuffer);
|
||||
}
|
||||
|
||||
void SparseMatrix::IncompleteCholeskySetup()
|
||||
{
|
||||
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!initILU && !initCholesky, "");
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
//MFEM_VERIFY(I[0] == 0, "cusparse thinks this is not zero based");
|
||||
|
||||
csric02Info_t info_M = 0;
|
||||
int bufferSize_M;
|
||||
int pBufferSize_L;
|
||||
int pBufferSize_Lt;
|
||||
int pBufferSize;
|
||||
int structural_zero;
|
||||
int numerical_zero;
|
||||
|
||||
const cusparseSolvePolicy_t policy_M = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_Lt = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_Lt = CUSPARSE_OPERATION_TRANSPOSE;
|
||||
|
||||
// step 1: create a descriptor which contains
|
||||
// - matrix M is base-0
|
||||
// - matrix L is base-0
|
||||
// - matrix L is lower triangular
|
||||
// - matrix L has non-unit diagonal
|
||||
cusparseCreateMatDescr(&descr_M);
|
||||
cusparseSetMatIndexBase(descr_M, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_M, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
|
||||
cusparseCreateMatDescr(&descr_L);
|
||||
cusparseSetMatIndexBase(descr_L, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_L, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
cusparseSetMatFillMode(descr_L, CUSPARSE_FILL_MODE_LOWER);
|
||||
cusparseSetMatDiagType(descr_L, CUSPARSE_DIAG_TYPE_NON_UNIT);
|
||||
|
||||
// step 2: create a empty info structure
|
||||
// we need one info for csric02 and two info's for csrsv2
|
||||
cusparseCreateCsric02Info(&info_M);
|
||||
cusparseCreateCsrsv2Info(&info_L);
|
||||
cusparseCreateCsrsv2Info(&info_Lt);
|
||||
|
||||
int64_t m = height;
|
||||
|
||||
// step 3: query how much memory used in csric02 and csrsv2, and allocate the buffer
|
||||
cusparseDcsric02_bufferSize(handle, m, nnz,
|
||||
descr_M, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, &bufferSize_M);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_L, m, nnz,
|
||||
descr_L, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_L, &pBufferSize_L);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_Lt, m, nnz,
|
||||
descr_L, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_Lt,&pBufferSize_Lt);
|
||||
|
||||
pBufferSize = max(bufferSize_M, max(pBufferSize_L, pBufferSize_Lt));
|
||||
|
||||
// pBuffer returned by cudaMalloc is automatically aligned to 128 bytes.
|
||||
cudaMalloc((void**)&pBuffer, pBufferSize);
|
||||
|
||||
// step 4: perform analysis of incomplete Cholesky on M
|
||||
// perform analysis of triangular solve on L
|
||||
// perform analysis of triangular solve on L'
|
||||
// The lower triangular part of M has the same sparsity pattern as L, so
|
||||
// we can do analysis of csric02 and csrsv2 simultaneously.
|
||||
|
||||
cusparseDcsric02_analysis(handle, m, nnz, descr_M,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_M,
|
||||
policy_M, pBuffer);
|
||||
status = cusparseXcsric02_zeroPivot(handle, info_M, &structural_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("A(%d,%d) is missing\n", structural_zero, structural_zero);
|
||||
}
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_L, m, nnz, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_L, policy_L, pBuffer);
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_Lt, m, nnz, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_Lt, policy_Lt, pBuffer);
|
||||
|
||||
// step 5: M = L * L'
|
||||
cusparseDcsric02(handle, m, nnz, descr_M,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, policy_M, pBuffer);
|
||||
status = cusparseXcsric02_zeroPivot(handle, info_M, &numerical_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("L(%d,%d) is zero\n", numerical_zero, numerical_zero);
|
||||
}
|
||||
|
||||
vecZ.SetSize(height);
|
||||
vecZ = 0.0;
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
cusparseCreateDnVec(&vecZ_descr, vecZ.Size(), d_z, CUDA_R_64F);
|
||||
|
||||
initCholesky = true;
|
||||
}
|
||||
|
||||
void SparseMatrix::ILUMult(const Vector &x, Vector &y) const
|
||||
{
|
||||
MFEM_VERIFY(initILU, "Setup not done");
|
||||
|
||||
const double alpha = 1.0;
|
||||
|
||||
auto d_x = x.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
int64_t m = height;
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
|
||||
cusparseDnVecSetValues(vecY_descr, d_y);
|
||||
cusparseDnVecSetValues(vecZ_descr, d_z);
|
||||
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_U = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_U = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
|
||||
// Solve L*z = x
|
||||
cusparseDcsrsv2_solve(handle, trans_L, m, nnz, &alpha, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_L,
|
||||
d_x, d_z, policy_L, pBuffer);
|
||||
|
||||
// Solve U*y = z
|
||||
cusparseDcsrsv2_solve(handle, trans_U, m, nnz, &alpha, descr_U,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_U,
|
||||
d_z, d_y, policy_U, pBuffer);
|
||||
|
||||
// TODO: destructor
|
||||
}
|
||||
|
||||
void SparseMatrix::ILUSetup()
|
||||
{
|
||||
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!initILU && !initCholesky, "");
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
csrilu02Info_t info_M = 0;
|
||||
int pBufferSize_M;
|
||||
int pBufferSize_L;
|
||||
int pBufferSize_U;
|
||||
int pBufferSize;
|
||||
int structural_zero;
|
||||
int numerical_zero;
|
||||
const cusparseSolvePolicy_t policy_M = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_U = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_U = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
|
||||
// step 1: create a descriptor which contains
|
||||
// - matrix M is base-0
|
||||
// - matrix L is base-0
|
||||
// - matrix L is lower triangular
|
||||
// - matrix L has unit diagonal
|
||||
// - matrix U is base-0
|
||||
// - matrix U is upper triangular
|
||||
// - matrix U has non-unit diagonal
|
||||
cusparseCreateMatDescr(&descr_M);
|
||||
cusparseSetMatIndexBase(descr_M, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_M, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
|
||||
cusparseCreateMatDescr(&descr_L);
|
||||
cusparseSetMatIndexBase(descr_L, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_L, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
cusparseSetMatFillMode(descr_L, CUSPARSE_FILL_MODE_LOWER);
|
||||
cusparseSetMatDiagType(descr_L, CUSPARSE_DIAG_TYPE_UNIT);
|
||||
|
||||
cusparseCreateMatDescr(&descr_U);
|
||||
cusparseSetMatIndexBase(descr_U, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_U, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
cusparseSetMatFillMode(descr_U, CUSPARSE_FILL_MODE_UPPER);
|
||||
cusparseSetMatDiagType(descr_U, CUSPARSE_DIAG_TYPE_NON_UNIT);
|
||||
|
||||
// step 2: create a empty info structure
|
||||
// we need one info for csrilu02 and two info's for csrsv2
|
||||
cusparseCreateCsrilu02Info(&info_M);
|
||||
cusparseCreateCsrsv2Info(&info_L);
|
||||
cusparseCreateCsrsv2Info(&info_U);
|
||||
|
||||
// step 3: query how much memory used in csrilu02 and csrsv2, and allocate the buffer
|
||||
int64_t m = height;
|
||||
|
||||
cusparseDcsrilu02_bufferSize(handle, m, nnz, descr_M,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, &pBufferSize_M);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_L, m, nnz, descr_L,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_L, &pBufferSize_L);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_U, m, nnz, descr_U,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_U, &pBufferSize_U);
|
||||
|
||||
pBufferSize = max(pBufferSize_M, max(pBufferSize_L, pBufferSize_U));
|
||||
|
||||
// pBuffer returned by cudaMalloc is automatically aligned to 128 bytes.
|
||||
cudaMalloc((void**)&pBuffer, pBufferSize);
|
||||
|
||||
// step 4: perform analysis of incomplete Cholesky on M
|
||||
// perform analysis of triangular solve on L
|
||||
// perform analysis of triangular solve on U
|
||||
// The lower(upper) triangular part of M has the same sparsity pattern as L(U),
|
||||
// we can do analysis of csrilu0 and csrsv2 simultaneously.
|
||||
|
||||
cusparseDcsrilu02_analysis(handle, m, nnz, descr_M,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_M,
|
||||
policy_M, pBuffer);
|
||||
status = cusparseXcsrilu02_zeroPivot(handle, info_M, &structural_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("A(%d,%d) is missing\n", structural_zero, structural_zero);
|
||||
}
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_L, m, nnz, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_L, policy_L, pBuffer);
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_U, m, nnz, descr_U,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_U, policy_U, pBuffer); // bug?
|
||||
|
||||
// step 5: M = L * U
|
||||
cusparseDcsrilu02(handle, m, nnz, descr_M,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, policy_M, pBuffer);
|
||||
status = cusparseXcsrilu02_zeroPivot(handle, info_M, &numerical_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("U(%d,%d) is zero\n", numerical_zero, numerical_zero);
|
||||
}
|
||||
|
||||
vecZ.SetSize(height);
|
||||
vecZ = 0.0;
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
cusparseCreateDnVec(&vecZ_descr, vecZ.Size(), d_z, CUDA_R_64F);
|
||||
|
||||
initILU = true;
|
||||
|
||||
// TODO: destructor
|
||||
}
|
||||
#endif // MFEM_USE_CUDA
|
||||
|
||||
}
|
||||
|
||||
@@ -103,6 +103,21 @@ protected:
|
||||
mutable cusparseSpMatDescr_t matA_descr;
|
||||
mutable cusparseDnVecDescr_t vecX_descr;
|
||||
mutable cusparseDnVecDescr_t vecY_descr;
|
||||
mutable cusparseDnVecDescr_t vecZ_descr;
|
||||
mutable Vector vecZ;
|
||||
|
||||
cusparseMatDescr_t descr_M = 0;
|
||||
cusparseMatDescr_t descr_L = 0;
|
||||
cusparseMatDescr_t descr_U = 0;
|
||||
|
||||
csrsv2Info_t info_L = 0;
|
||||
csrsv2Info_t info_Lt = 0;
|
||||
csrsv2Info_t info_U = 0;
|
||||
|
||||
void *pBuffer = 0;
|
||||
|
||||
bool initILU = false;
|
||||
bool initCholesky = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -610,6 +625,14 @@ public:
|
||||
|
||||
void Swap(SparseMatrix &other);
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
void IncompleteCholeskySetup();
|
||||
void IncompleteCholeskyMult(const Vector &x, Vector &y) const;
|
||||
|
||||
void ILUSetup();
|
||||
void ILUMult(const Vector &x, Vector &y) const;
|
||||
#endif
|
||||
|
||||
/// Destroys sparse matrix.
|
||||
virtual ~SparseMatrix()
|
||||
{
|
||||
|
||||
+2
-2
@@ -1071,7 +1071,7 @@ double Vector::operator*(const Vector &v) const
|
||||
return prod;
|
||||
}
|
||||
#endif
|
||||
if (Device::Allows(Backend::DEBUG_DEVICE))
|
||||
if (Device::Allows(Backend::DEBUG))
|
||||
{
|
||||
const int N = size;
|
||||
auto v_data = v.Read();
|
||||
@@ -1131,7 +1131,7 @@ double Vector::Min() const
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Device::Allows(Backend::DEBUG_DEVICE))
|
||||
if (Device::Allows(Backend::DEBUG))
|
||||
{
|
||||
const int N = size;
|
||||
auto m_data = Read();
|
||||
|
||||
@@ -204,11 +204,7 @@ CXXFLAGS ?= $(OPTIM_FLAGS)
|
||||
# MPI configuration
|
||||
ifneq ($(MFEM_USE_MPI),YES)
|
||||
MFEM_HOST_CXX = $(CXX)
|
||||
<<<<<<< HEAD
|
||||
PKGS_NEED_MPI = SUPERLU MUMPS STRUMPACK PETSC PUMI SLEPC
|
||||
=======
|
||||
PKGS_NEED_MPI = SUPERLU STRUMPACK PETSC PUMI SLEPC MKL_CPARDISO
|
||||
>>>>>>> mkl-pardiso
|
||||
PKGS_NEED_MPI = SUPERLU STRUMPACK PETSC PUMI SLEPC
|
||||
$(foreach mpidep,$(PKGS_NEED_MPI),$(if $(MFEM_USE_$(mpidep):NO=),\
|
||||
$(warning *** [MPI is OFF] setting MFEM_USE_$(mpidep) = NO)\
|
||||
$(eval override MFEM_USE_$(mpidep)=NO),))
|
||||
@@ -263,9 +259,9 @@ ifeq ($(MFEM_USE_LEGACY_OPENMP),YES)
|
||||
endif
|
||||
|
||||
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
|
||||
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\
|
||||
MFEM_REQ_LIB_DEPS = SUPERLU METIS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\
|
||||
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP GSLIB\
|
||||
OCCA CEED RAJA UMPIRE MKL_CPARDISO
|
||||
OCCA CEED RAJA UMPIRE
|
||||
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
|
||||
SLEPC_ERROR_MSG = $(if $(SLEPC_FOUND),,. SLEPC config not found: $(SLEPC_VARS))
|
||||
|
||||
@@ -325,11 +321,11 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
|
||||
MFEM_USE_ZLIB MFEM_USE_LIBUNWIND MFEM_USE_LAPACK MFEM_THREAD_SAFE\
|
||||
MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP MFEM_USE_MEMALLOC MFEM_TIMER_TYPE\
|
||||
MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE MFEM_USE_GINKGO\
|
||||
MFEM_USE_SUPERLU MFEM_USE_MUMPS MFEM_USE_STRUMPACK MFEM_USE_GNUTLS\
|
||||
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS\
|
||||
MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT\
|
||||
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
|
||||
MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD\
|
||||
MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_SOURCE_DIR MFEM_INSTALL_DIR
|
||||
MFEM_USE_ADIOS2 MFEM_SOURCE_DIR MFEM_INSTALL_DIR
|
||||
|
||||
# List of makefile variables that will be written to config.mk:
|
||||
MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\
|
||||
@@ -363,7 +359,7 @@ MFEM_INSTALL_DIR = $(abspath $(MFEM_PREFIX))
|
||||
# If we have 'config' target, export variables used by config/makefile
|
||||
ifneq (,$(filter config,$(MAKECMDGOALS)))
|
||||
export $(MFEM_DEFINES) MFEM_DEFINES $(MFEM_CONFIG_VARS) MFEM_CONFIG_VARS
|
||||
export VERBOSE HYPRE_OPT PUMI_DIR MUMPS_OPT
|
||||
export VERBOSE HYPRE_OPT PUMI_DIR
|
||||
endif
|
||||
|
||||
# If we have 'install' target, export variables used by config/makefile
|
||||
@@ -631,7 +627,6 @@ status info:
|
||||
$(info MFEM_USE_MESQUITE = $(MFEM_USE_MESQUITE))
|
||||
$(info MFEM_USE_SUITESPARSE = $(MFEM_USE_SUITESPARSE))
|
||||
$(info MFEM_USE_SUPERLU = $(MFEM_USE_SUPERLU))
|
||||
$(info MFEM_USE_MUMPS = $(MFEM_USE_MUMPS))
|
||||
$(info MFEM_USE_STRUMPACK = $(MFEM_USE_STRUMPACK))
|
||||
$(info MFEM_USE_GINKGO = $(MFEM_USE_GINKGO))
|
||||
$(info MFEM_USE_GNUTLS = $(MFEM_USE_GNUTLS))
|
||||
@@ -652,7 +647,6 @@ status info:
|
||||
$(info MFEM_USE_UMPIRE = $(MFEM_USE_UMPIRE))
|
||||
$(info MFEM_USE_SIMD = $(MFEM_USE_SIMD))
|
||||
$(info MFEM_USE_ADIOS2 = $(MFEM_USE_ADIOS2))
|
||||
$(info MFEM_USE_MKL_CPARDISO = $(MFEM_USE_MKL_CPARDISO))
|
||||
$(info MFEM_CXX = $(value MFEM_CXX))
|
||||
$(info MFEM_HOST_CXX = $(value MFEM_HOST_CXX))
|
||||
$(info MFEM_CPPFLAGS = $(value MFEM_CPPFLAGS))
|
||||
|
||||
+26
-154
@@ -1223,136 +1223,58 @@ void Mesh::InitMesh(int _Dim, int _spaceDim, int NVert, int NElem, int NBdrElem)
|
||||
boundary.SetSize(NBdrElem); // just allocate space for Element *
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void CheckEnlarge(Array<T> &array, int size)
|
||||
void Mesh::AddVertex(const double *x)
|
||||
{
|
||||
if (size >= array.Size()) { array.SetSize(size + 1); }
|
||||
}
|
||||
double *y = vertices[NumOfVertices]();
|
||||
|
||||
int Mesh::AddVertex(double x, double y, double z)
|
||||
{
|
||||
CheckEnlarge(vertices, NumOfVertices);
|
||||
double *v = vertices[NumOfVertices]();
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
v[2] = z;
|
||||
return NumOfVertices++;
|
||||
}
|
||||
|
||||
int Mesh::AddVertex(const double *coords)
|
||||
{
|
||||
CheckEnlarge(vertices, NumOfVertices);
|
||||
vertices[NumOfVertices].SetCoords(spaceDim, coords);
|
||||
return NumOfVertices++;
|
||||
}
|
||||
|
||||
void Mesh::AddVertexParents(int i, int p1, int p2)
|
||||
{
|
||||
tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
|
||||
|
||||
// if vertex coordinates are defined, make sure the hanging vertex has the
|
||||
// correct position
|
||||
if (i < vertices.Size())
|
||||
for (int i = 0; i < spaceDim; i++)
|
||||
{
|
||||
double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
vi[j] = (vp1[j] + vp2[j]) * 0.5;
|
||||
}
|
||||
y[i] = x[i];
|
||||
}
|
||||
NumOfVertices++;
|
||||
}
|
||||
|
||||
int Mesh::AddSegment(int v1, int v2, int attr)
|
||||
void Mesh::AddSegment(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Segment(v1, v2, attr);
|
||||
return NumOfElements++;
|
||||
elements[NumOfElements++] = new Segment(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddSegment(const int *vi, int attr)
|
||||
void Mesh::AddTri(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Segment(vi, attr);
|
||||
return NumOfElements++;
|
||||
elements[NumOfElements++] = new Triangle(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
|
||||
void Mesh::AddTriangle(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
|
||||
return NumOfElements++;
|
||||
elements[NumOfElements++] = new Triangle(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddTriangle(const int *vi, int attr)
|
||||
void Mesh::AddQuad(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Triangle(vi, attr);
|
||||
return NumOfElements++;
|
||||
elements[NumOfElements++] = new Quadrilateral(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
|
||||
void Mesh::AddTet(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddQuad(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Quadrilateral(vi, attr);
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
|
||||
{
|
||||
int vi[4] = {v1, v2, v3, v4};
|
||||
return AddTet(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddTet(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
Tetrahedron *tet;
|
||||
tet = TetMemory.Alloc();
|
||||
tet->SetVertices(vi);
|
||||
tet->SetAttribute(attr);
|
||||
elements[NumOfElements] = tet;
|
||||
elements[NumOfElements++] = tet;
|
||||
#else
|
||||
elements[NumOfElements] = new Tetrahedron(vi, attr);
|
||||
elements[NumOfElements++] = new Tetrahedron(vi, attr);
|
||||
#endif
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
|
||||
void Mesh::AddWedge(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
|
||||
return NumOfElements++;
|
||||
elements[NumOfElements++] = new Wedge(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddWedge(const int *vi, int attr)
|
||||
void Mesh::AddHex(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Wedge(vi, attr);
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
|
||||
int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] =
|
||||
new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddHex(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Hexahedron(vi, attr);
|
||||
return NumOfElements++;
|
||||
elements[NumOfElements++] = new Hexahedron(vi, attr);
|
||||
}
|
||||
|
||||
void Mesh::AddHexAsTets(const int *vi, int attr)
|
||||
@@ -1392,60 +1314,19 @@ void Mesh::AddHexAsWedges(const int *vi, int attr)
|
||||
}
|
||||
}
|
||||
|
||||
int Mesh::AddElement(Element *elem)
|
||||
void Mesh::AddBdrSegment(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = elem;
|
||||
return NumOfElements++;
|
||||
boundary[NumOfBdrElements++] = new Segment(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddBdrElement(Element *elem)
|
||||
void Mesh::AddBdrTriangle(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = elem;
|
||||
return NumOfBdrElements++;
|
||||
boundary[NumOfBdrElements++] = new Triangle(vi, attr);
|
||||
}
|
||||
|
||||
int Mesh::AddBdrSegment(int v1, int v2, int attr)
|
||||
void Mesh::AddBdrQuad(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
|
||||
return NumOfBdrElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddBdrSegment(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = new Segment(vi, attr);
|
||||
return NumOfBdrElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
|
||||
return NumOfBdrElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddBdrTriangle(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = new Triangle(vi, attr);
|
||||
return NumOfBdrElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
|
||||
return NumOfBdrElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddBdrQuad(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(boundary, NumOfBdrElements);
|
||||
boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
|
||||
return NumOfBdrElements++;
|
||||
boundary[NumOfBdrElements++] = new Quadrilateral(vi, attr);
|
||||
}
|
||||
|
||||
void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
|
||||
@@ -2538,15 +2419,6 @@ void Mesh::FinalizeTopology(bool generate_bdr)
|
||||
|
||||
// generate the arrays 'attributes' and 'bdr_attributes'
|
||||
SetAttributes();
|
||||
|
||||
// if the user defined any hanging nodes (see AddVertexParent),
|
||||
// initialize the NC mesh now
|
||||
if (tmp_vertex_parents.Size())
|
||||
{
|
||||
MFEM_VERIFY(ncmesh == NULL, "");
|
||||
EnsureNCMesh(true);
|
||||
tmp_vertex_parents.DeleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::Finalize(bool refine, bool fix_orientation)
|
||||
|
||||
+17
-40
@@ -206,9 +206,6 @@ public:
|
||||
Array<FaceGeometricFactors*>
|
||||
face_geom_factors; ///< Optional face geometric factors.
|
||||
|
||||
/// Used during initialization only.
|
||||
Array<Triple<int, int, int> > tmp_vertex_parents;
|
||||
|
||||
// Global parameter that can be used to control the removal of unused
|
||||
// vertices performed when reading a mesh in MFEM format. The default value
|
||||
// (true) is set in mesh_readers.cpp.
|
||||
@@ -502,7 +499,10 @@ public:
|
||||
@brief _Init_ constructor: begin the construction of a Mesh object. */
|
||||
Mesh(int _Dim, int NVert, int NElem, int NBdrElem = 0, int _spaceDim = -1)
|
||||
{
|
||||
if (_spaceDim == -1) { _spaceDim = _Dim; }
|
||||
if (_spaceDim == -1)
|
||||
{
|
||||
_spaceDim = _Dim;
|
||||
}
|
||||
InitMesh(_Dim, _spaceDim, NVert, NElem, NBdrElem);
|
||||
}
|
||||
|
||||
@@ -514,45 +514,22 @@ public:
|
||||
|
||||
Element *NewElement(int geom);
|
||||
|
||||
int AddVertex(double x, double y = 0.0, double z = 0.0);
|
||||
int AddVertex(const double *coords);
|
||||
/// Mark vertex @a i as non-conforming, with parent vertices @a p1 and @a p2.
|
||||
void AddVertexParents(int i, int p1, int p2);
|
||||
|
||||
int AddSegment(int v1, int v2, int attr = 1);
|
||||
int AddSegment(const int *vi, int attr = 1);
|
||||
|
||||
int AddTriangle(int v1, int v2, int v3, int attr = 1);
|
||||
int AddTriangle(const int *vi, int attr = 1);
|
||||
int AddTri(const int *vi, int attr = 1) { return AddTriangle(vi, attr); }
|
||||
|
||||
int AddQuad(int v1, int v2, int v3, int v4, int attr = 1);
|
||||
int AddQuad(const int *vi, int attr = 1);
|
||||
|
||||
int AddTet(int v1, int v2, int v3, int v4, int attr = 1);
|
||||
int AddTet(const int *vi, int attr = 1);
|
||||
|
||||
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr = 1);
|
||||
int AddWedge(const int *vi, int attr = 1);
|
||||
|
||||
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
|
||||
int attr = 1);
|
||||
int AddHex(const int *vi, int attr = 1);
|
||||
void AddVertex(const double *);
|
||||
void AddSegment(const int *vi, int attr = 1);
|
||||
void AddTri(const int *vi, int attr = 1);
|
||||
void AddTriangle(const int *vi, int attr = 1);
|
||||
void AddQuad(const int *vi, int attr = 1);
|
||||
void AddTet(const int *vi, int attr = 1);
|
||||
void AddWedge(const int *vi, int attr = 1);
|
||||
void AddHex(const int *vi, int attr = 1);
|
||||
void AddHexAsTets(const int *vi, int attr = 1);
|
||||
void AddHexAsWedges(const int *vi, int attr = 1);
|
||||
|
||||
/// The parameter @a elem should be allocated using the NewElement() method
|
||||
int AddElement(Element *elem);
|
||||
int AddBdrElement(Element *elem);
|
||||
|
||||
int AddBdrSegment(int v1, int v2, int attr = 1);
|
||||
int AddBdrSegment(const int *vi, int attr = 1);
|
||||
|
||||
int AddBdrTriangle(int v1, int v2, int v3, int attr = 1);
|
||||
int AddBdrTriangle(const int *vi, int attr = 1);
|
||||
|
||||
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr = 1);
|
||||
int AddBdrQuad(const int *vi, int attr = 1);
|
||||
void AddElement(Element *elem) { elements[NumOfElements++] = elem; }
|
||||
void AddBdrElement(Element *elem) { boundary[NumOfBdrElements++] = elem; }
|
||||
void AddBdrSegment(const int *vi, int attr = 1);
|
||||
void AddBdrTriangle(const int *vi, int attr = 1);
|
||||
void AddBdrQuad(const int *vi, int attr = 1);
|
||||
void AddBdrQuadAsTriangles(const int *vi, int attr = 1);
|
||||
|
||||
void GenerateBoundaryElements();
|
||||
|
||||
+1
-10
@@ -104,16 +104,7 @@ NCMesh::NCMesh(const Mesh *mesh, std::istream *vertex_parents)
|
||||
{
|
||||
LoadVertexParents(*vertex_parents);
|
||||
}
|
||||
// alternatively, the user might have initialized hanging nodes with
|
||||
// Mesh::AddVertexParents; copy the hierarchy now
|
||||
else if (mesh->tmp_vertex_parents.Size())
|
||||
{
|
||||
for (const auto &triple : mesh->tmp_vertex_parents)
|
||||
{
|
||||
nodes.Reparent(triple.one, triple.two, triple.three);
|
||||
}
|
||||
}
|
||||
else // otherwise we just assume a standard conforming coarse mesh
|
||||
else
|
||||
{
|
||||
top_vertex_pos.SetSize(3*mesh->GetNV());
|
||||
for (int i = 0; i < mesh->GetNV(); i++)
|
||||
|
||||
+4
-4
@@ -1066,9 +1066,9 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh)
|
||||
for (int j = mf.slaves_begin; j < mf.slaves_end; j++)
|
||||
{
|
||||
const Slave &sf = full_list.slaves[j];
|
||||
if (sf.element < 0) { continue; }
|
||||
if (sf.index < 0) { continue; }
|
||||
|
||||
MFEM_ASSERT(mf.element >= 0, "");
|
||||
MFEM_ASSERT(mf.element >= 0 && sf.element >= 0, "");
|
||||
Element* e[2] = { &elements[mf.element], &elements[sf.element] };
|
||||
|
||||
bool loc0 = (e[0]->rank == MyRank);
|
||||
@@ -1224,9 +1224,9 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh)
|
||||
for (int j = mf.slaves_begin; j < mf.slaves_end; j++)
|
||||
{
|
||||
const Slave &sf = full_list.slaves[j];
|
||||
if (sf.element < 0) { continue; }
|
||||
if (sf.index < 0) { continue; }
|
||||
|
||||
MFEM_ASSERT(mf.element >= 0, "");
|
||||
MFEM_ASSERT(sf.element >= 0 && mf.element >= 0, "");
|
||||
Element &sfe = elements[sf.element];
|
||||
Element &mfe = elements[mf.element];
|
||||
|
||||
|
||||
@@ -1,388 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// -------------------------------------------------------------
|
||||
// Field Interp Miniapp: Transfer a grid function between meshes
|
||||
// -------------------------------------------------------------
|
||||
//
|
||||
// This miniapp provides the capability to transfer a grid function (H1, L2,
|
||||
// H(div), and H(curl)) from one mesh onto another using GSLIB-FindPoints. Using
|
||||
// FindPoints, we identify the nodal positions of the target mesh with respect
|
||||
// to the source mesh and then interpolate the source grid function. The
|
||||
// interpolated values are then projected onto the desired finite element space
|
||||
// on the target mesh. Finally, the transferred solution is visualized using
|
||||
// GLVis. Note that the source grid function can be a user-defined vector
|
||||
// function or a grid function file that is compatible with the source mesh.
|
||||
//
|
||||
// Compile with: make field-interp
|
||||
//
|
||||
// Sample runs:
|
||||
// field-interp
|
||||
// field-interp -fts 3 -ft 0
|
||||
// field-interp -m1 triple-pt-1.mesh -s1 triple-pt-1.gf -m2 triple-pt-2.mesh -ft 1
|
||||
// field-interp -m2 ../meshing/amr-quad-q2.mesh -ft 0 -r 1
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
|
||||
using namespace mfem;
|
||||
using namespace std;
|
||||
|
||||
// Scalar function to project
|
||||
double scalar_func(const Vector &x)
|
||||
{
|
||||
const int dim = x.Size();
|
||||
double res = 0.0;
|
||||
for (int d = 0; d < dim; d++) { res += x(d) * x(d); }
|
||||
return res;
|
||||
}
|
||||
|
||||
void vector_func(const Vector &p, Vector &F)
|
||||
{
|
||||
F(0) = scalar_func(p);
|
||||
for (int i = 1; i < F.Size(); i++) { F(i) = (i+1)*pow(-1, i)*F(0); }
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// Set the method's default parameters.
|
||||
const char *src_mesh_file = "../meshing/square01.mesh";
|
||||
const char *tar_mesh_file = "../../data/inline-tri.mesh";
|
||||
const char *src_sltn_file = "must_be_provided_by_the_user.gf";
|
||||
int src_fieldtype = 0;
|
||||
int src_ncomp = 1;
|
||||
int ref_levels = 0;
|
||||
int fieldtype = -1;
|
||||
int order = 3;
|
||||
bool visualization = true;
|
||||
|
||||
// Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&src_mesh_file, "-m1", "--mesh1",
|
||||
"Mesh file for the starting solution.");
|
||||
args.AddOption(&tar_mesh_file, "-m2", "--mesh2",
|
||||
"Mesh file for interpolation.");
|
||||
args.AddOption(&src_sltn_file, "-s1", "--solution1",
|
||||
"(optional) GridFunction file compatible with src_mesh_file."
|
||||
"Set src_fieldtype to -1 if this option is used.");
|
||||
args.AddOption(&src_fieldtype, "-fts", "--field-type-src",
|
||||
"Source GridFunction type:"
|
||||
"0 - H1 (default), 1 - L2, 2 - H(div), 3 - H(curl).");
|
||||
args.AddOption(&src_ncomp, "-nc", "--ncomp",
|
||||
"Number of components for H1 or L2 GridFunctions.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of refinements of the interpolation mesh.");
|
||||
args.AddOption(&fieldtype, "-ft", "--field-type",
|
||||
"Target GridFunction type: -1 - source GridFunction type (default),"
|
||||
"0 - H1, 1 - L2, 2 - H(div), 3 - H(curl).");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order of the interpolated solution.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// Input meshes.
|
||||
Mesh mesh_1(src_mesh_file, 1, 1, false);
|
||||
Mesh mesh_2(tar_mesh_file, 1, 1, false);
|
||||
const int dim = mesh_1.Dimension();
|
||||
MFEM_ASSERT(dim == mesh_2.Dimension(), "Source and target meshes "
|
||||
"must be in the same dimension.");
|
||||
MFEM_VERIFY(dim > 1, "GSLIB requires a 2D or a 3D mesh" );
|
||||
|
||||
for (int lev = 0; lev < ref_levels; lev++)
|
||||
{
|
||||
mesh_2.UniformRefinement();
|
||||
}
|
||||
|
||||
if (mesh_1.GetNodes() == NULL) { mesh_1.SetCurvature(1); }
|
||||
if (mesh_2.GetNodes() == NULL) { mesh_2.SetCurvature(1); }
|
||||
const int mesh_poly_deg = mesh_2.GetNodes()->FESpace()->GetOrder(0);
|
||||
cout << "Source mesh curvature: "
|
||||
<< mesh_1.GetNodes()->OwnFEC()->Name() << endl
|
||||
<< "Target mesh curvature: "
|
||||
<< mesh_2.GetNodes()->OwnFEC()->Name() << endl;
|
||||
|
||||
int src_vdim = src_ncomp;
|
||||
FiniteElementCollection *src_fec = NULL;
|
||||
FiniteElementSpace *src_fes = NULL;
|
||||
GridFunction *func_source = NULL;
|
||||
if (src_fieldtype < 0) // use src_sltn_file
|
||||
{
|
||||
ifstream mat_stream_1(src_sltn_file);
|
||||
func_source = new GridFunction(&mesh_1, mat_stream_1);
|
||||
src_vdim = func_source->FESpace()->GetVDim();
|
||||
}
|
||||
else if (src_fieldtype == 0)
|
||||
{
|
||||
src_fec = new H1_FECollection(order, dim);
|
||||
}
|
||||
else if (src_fieldtype == 1)
|
||||
{
|
||||
src_fec = new L2_FECollection(order, dim);
|
||||
}
|
||||
else if (src_fieldtype == 2)
|
||||
{
|
||||
src_fec = new RT_FECollection(order, dim);
|
||||
src_ncomp = 1;
|
||||
src_vdim = dim;
|
||||
}
|
||||
else if (src_fieldtype == 3)
|
||||
{
|
||||
src_fec = new ND_FECollection(order, dim);
|
||||
src_ncomp = 1;
|
||||
src_vdim = dim;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Invalid FECollection type.");
|
||||
}
|
||||
|
||||
if (src_fieldtype > -1)
|
||||
{
|
||||
src_fes = new FiniteElementSpace(&mesh_1, src_fec, src_ncomp);
|
||||
func_source = new GridFunction(src_fes);
|
||||
// Project the grid function using VectorFunctionCoefficient.
|
||||
VectorFunctionCoefficient F(src_vdim, vector_func);
|
||||
func_source->ProjectCoefficient(F);
|
||||
}
|
||||
|
||||
// Display the starting mesh and the field.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sout1;
|
||||
sout1.open(vishost, visport);
|
||||
if (!sout1)
|
||||
{
|
||||
cout << "Unable to connect to GLVis server at "
|
||||
<< vishost << ':' << visport << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
sout1.precision(8);
|
||||
sout1 << "solution\n" << mesh_1 << *func_source
|
||||
<< "window_title 'Source mesh and solution'"
|
||||
<< "window_geometry 0 0 600 600";
|
||||
if (dim == 2) { sout1 << "keys RmjAc"; }
|
||||
if (dim == 3) { sout1 << "keys mA\n"; }
|
||||
sout1 << flush;
|
||||
}
|
||||
}
|
||||
|
||||
const Geometry::Type gt = mesh_2.GetNodalFESpace()->GetFE(0)->GetGeomType();
|
||||
MFEM_VERIFY(gt != Geometry::PRISM, "Wedge elements are not currently "
|
||||
"supported.");
|
||||
MFEM_VERIFY(mesh_2.GetNumGeometries(mesh_2.Dimension()) == 1, "Mixed meshes"
|
||||
"are not currently supported.");
|
||||
|
||||
// Ensure the source grid function can be transferred using GSLIB-FindPoints.
|
||||
const FiniteElementCollection *fec_in = func_source->FESpace()->FEColl();
|
||||
std::cout << "Source FE collection: " << fec_in->Name() << std::endl;
|
||||
|
||||
if (src_fieldtype < 0)
|
||||
{
|
||||
const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
|
||||
const L2_FECollection *fec_l2 = dynamic_cast<const L2_FECollection *>(fec_in);
|
||||
const RT_FECollection *fec_rt = dynamic_cast<const RT_FECollection *>(fec_in);
|
||||
const ND_FECollection *fec_nd = dynamic_cast<const ND_FECollection *>(fec_in);
|
||||
if (fec_h1) { src_fieldtype = 0; }
|
||||
else if (fec_l2) { src_fieldtype = 1; }
|
||||
else if (fec_rt) { src_fieldtype = 2; }
|
||||
else if (fec_nd) { src_fieldtype = 3; }
|
||||
else { MFEM_ABORT("GridFunction type not supported yet."); }
|
||||
}
|
||||
if (fieldtype < 0) { fieldtype = src_fieldtype; }
|
||||
|
||||
// Setup the FiniteElementSpace and GridFunction on the target mesh.
|
||||
FiniteElementCollection *tar_fec = NULL;
|
||||
FiniteElementSpace *tar_fes = NULL;
|
||||
|
||||
int tar_vdim = src_vdim;
|
||||
if (fieldtype == 0)
|
||||
{
|
||||
tar_fec = new H1_FECollection(order, dim);
|
||||
tar_vdim = (src_fieldtype > 1) ? dim : src_vdim;
|
||||
}
|
||||
else if (fieldtype == 1)
|
||||
{
|
||||
tar_fec = new L2_FECollection(order, dim);
|
||||
tar_vdim = (src_fieldtype > 1) ? dim : src_vdim;
|
||||
}
|
||||
else if (fieldtype == 2)
|
||||
{
|
||||
tar_fec = new RT_FECollection(order, dim);
|
||||
tar_vdim = 1;
|
||||
MFEM_VERIFY(src_fieldtype > 1, "Cannot interpolate a scalar "
|
||||
"grid function to a vector");
|
||||
|
||||
}
|
||||
else if (fieldtype == 3)
|
||||
{
|
||||
tar_fec = new ND_FECollection(order, dim);
|
||||
tar_vdim = 1;
|
||||
MFEM_VERIFY(src_fieldtype > 1, "Cannot interpolate a scalar "
|
||||
"grid function to a vector");
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("GridFunction type not supported.");
|
||||
}
|
||||
std::cout << "Target FE collection: " << tar_fec->Name() << std::endl;
|
||||
tar_fes = new FiniteElementSpace(&mesh_2, tar_fec, tar_vdim);
|
||||
GridFunction func_target(tar_fes);
|
||||
|
||||
const int NE = mesh_2.GetNE(),
|
||||
nsp = tar_fes->GetFE(0)->GetNodes().GetNPoints(),
|
||||
tar_ncomp = func_target.VectorDim();
|
||||
|
||||
// Generate list of points where the grid function will be evaluated.
|
||||
Vector vxyz;
|
||||
if (fieldtype == 0 && order == mesh_poly_deg)
|
||||
{
|
||||
vxyz = *mesh_2.GetNodes();
|
||||
}
|
||||
else
|
||||
{
|
||||
vxyz.SetSize(nsp*NE*dim);
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
const FiniteElement *fe = tar_fes->GetFE(i);
|
||||
const IntegrationRule ir = fe->GetNodes();
|
||||
ElementTransformation *et = tar_fes->GetElementTransformation(i);
|
||||
|
||||
DenseMatrix pos;
|
||||
et->Transform(ir, pos);
|
||||
Vector rowx(vxyz.GetData() + i*nsp, nsp),
|
||||
rowy(vxyz.GetData() + i*nsp + NE*nsp, nsp),
|
||||
rowz;
|
||||
if (dim == 3)
|
||||
{
|
||||
rowz.SetDataAndSize(vxyz.GetData() + i*nsp + 2*NE*nsp, nsp);
|
||||
}
|
||||
pos.GetRow(0, rowx);
|
||||
pos.GetRow(1, rowy);
|
||||
if (dim == 3) { pos.GetRow(2, rowz); }
|
||||
}
|
||||
}
|
||||
const int nodes_cnt = vxyz.Size() / dim;
|
||||
|
||||
// Evaluate source grid function.
|
||||
Vector interp_vals(nodes_cnt*tar_ncomp);
|
||||
FindPointsGSLIB finder;
|
||||
finder.Setup(mesh_1);
|
||||
finder.Interpolate(vxyz, *func_source, interp_vals);
|
||||
|
||||
// Project the interpolated values to the target FiniteElementSpace.
|
||||
if (fieldtype <= 1) // H1 or L2
|
||||
{
|
||||
if ((fieldtype == 0 && order == mesh_poly_deg) || fieldtype == 1)
|
||||
{
|
||||
func_target = interp_vals;
|
||||
}
|
||||
else // H1 - but mesh order != GridFunction order
|
||||
{
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
Vector elem_dof_vals(nsp*tar_ncomp);
|
||||
|
||||
for (int i = 0; i < mesh_2.GetNE(); i++)
|
||||
{
|
||||
tar_fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
for (int d = 0; d < tar_ncomp; d++)
|
||||
{
|
||||
// Arrange values byNodes
|
||||
elem_dof_vals(j+d*nsp) = interp_vals(d*nsp*NE + i*nsp + j);
|
||||
}
|
||||
}
|
||||
func_target.SetSubVector(vdofs, elem_dof_vals);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // H(div) or H(curl)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
Vector elem_dof_vals(nsp*tar_ncomp);
|
||||
|
||||
for (int i = 0; i < mesh_2.GetNE(); i++)
|
||||
{
|
||||
tar_fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
for (int d = 0; d < tar_ncomp; d++)
|
||||
{
|
||||
// Arrange values byVDim
|
||||
elem_dof_vals(j*tar_ncomp+d) = interp_vals(d*nsp*NE + i*nsp + j);
|
||||
}
|
||||
}
|
||||
tar_fes->GetFE(i)->ProjectFromNodes(elem_dof_vals,
|
||||
*tar_fes->GetElementTransformation(i),
|
||||
vals);
|
||||
func_target.SetSubVector(vdofs, vals);
|
||||
}
|
||||
}
|
||||
|
||||
// Visualize the transferred solution.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sout1;
|
||||
sout1.open(vishost, visport);
|
||||
if (!sout1)
|
||||
{
|
||||
cout << "Unable to connect to GLVis server at "
|
||||
<< vishost << ':' << visport << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
sout1.precision(8);
|
||||
sout1 << "solution\n" << mesh_2 << func_target
|
||||
<< "window_title 'Target mesh and solution'"
|
||||
<< "window_geometry 600 0 600 600";
|
||||
if (dim == 2) { sout1 << "keys RmjAc"; }
|
||||
if (dim == 3) { sout1 << "keys mA\n"; }
|
||||
sout1 << flush;
|
||||
}
|
||||
}
|
||||
|
||||
// Output the target mesh with the interpolated solution.
|
||||
ostringstream rho_name;
|
||||
rho_name << "interpolated.gf";
|
||||
ofstream rho_ofs(rho_name.str().c_str());
|
||||
rho_ofs.precision(8);
|
||||
func_target.Save(rho_ofs);
|
||||
rho_ofs.close();
|
||||
|
||||
// Free the internal gslib data.
|
||||
finder.FreeData();
|
||||
|
||||
// Delete remaining memory.
|
||||
delete func_source;
|
||||
delete src_fes;
|
||||
delete src_fec;
|
||||
delete tar_fes;
|
||||
delete tar_fec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
+30
-85
@@ -27,6 +27,7 @@
|
||||
// Compile with: make findpts
|
||||
//
|
||||
// Sample runs:
|
||||
// findpts -m ../../data/rt-2d-q3.mesh -o 3
|
||||
// findpts -m ../../data/rt-2d-p4-tri.mesh -o 4
|
||||
// findpts -m ../../data/inline-tri.mesh -o 3
|
||||
// findpts -m ../../data/inline-quad.mesh -o 3
|
||||
@@ -34,7 +35,6 @@
|
||||
// findpts -m ../../data/inline-hex.mesh -o 3
|
||||
// findpts -m ../../data/inline-wedge.mesh -o 3
|
||||
// findpts -m ../../data/amr-quad.mesh -o 2
|
||||
// findpts -m ../../data/rt-2d-q3.mesh -o 3 -mo 4 -ft 2
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
@@ -50,37 +50,22 @@ double field_func(const Vector &x)
|
||||
return res;
|
||||
}
|
||||
|
||||
void F_exact(const Vector &p, Vector &F)
|
||||
{
|
||||
F(0) = field_func(p);
|
||||
for (int i = 1; i < F.Size(); i++) { F(i) = (i+1)*F(0); }
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// Set the method's default parameters.
|
||||
const char *mesh_file = "../../data/rt-2d-q3.mesh";
|
||||
int order = 3;
|
||||
int mesh_poly_deg = 3;
|
||||
int rs_levels = 0;
|
||||
bool visualization = true;
|
||||
int fieldtype = 0;
|
||||
int ncomp = 1;
|
||||
|
||||
// Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&mesh_poly_deg, "-mo", "--mesh-order",
|
||||
args.AddOption(&mesh_poly_deg, "-o", "--mesh-order",
|
||||
"Polynomial degree of mesh finite element space.");
|
||||
args.AddOption(&rs_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&fieldtype, "-ft", "--field-type",
|
||||
"Field type: 0 - H1, 1 - L2, 2 - H(div), 3 - H(curl).");
|
||||
args.AddOption(&ncomp, "-nc", "--ncomp",
|
||||
"Number of components for H1 or L2 GridFunctions");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
@@ -114,48 +99,16 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Curve the mesh based on the chosen polynomial degree.
|
||||
H1_FECollection fecm(mesh_poly_deg, dim);
|
||||
FiniteElementSpace fespace(&mesh, &fecm, dim);
|
||||
H1_FECollection fec(mesh_poly_deg, dim);
|
||||
FiniteElementSpace fespace(&mesh, &fec, dim);
|
||||
mesh.SetNodalFESpace(&fespace);
|
||||
cout << "Mesh curvature of the curved mesh: " << fecm.Name() << endl;
|
||||
cout << "Mesh curvature of the curved mesh: " << fec.Name() << endl;
|
||||
|
||||
MFEM_VERIFY(ncomp > 0, "Invalid number of components.");
|
||||
int vec_dim = ncomp;
|
||||
FiniteElementCollection *fec = NULL;
|
||||
if (fieldtype == 0)
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
cout << "H1-GridFunction\n";
|
||||
}
|
||||
else if (fieldtype == 1)
|
||||
{
|
||||
fec = new L2_FECollection(order, dim);
|
||||
cout << "L2-GridFunction\n";
|
||||
}
|
||||
else if (fieldtype == 2)
|
||||
{
|
||||
fec = new RT_FECollection(order, dim);
|
||||
ncomp = 1;
|
||||
vec_dim = dim;
|
||||
cout << "H(div)-GridFunction\n";
|
||||
}
|
||||
else if (fieldtype == 3)
|
||||
{
|
||||
fec = new ND_FECollection(order, dim);
|
||||
ncomp = 1;
|
||||
vec_dim = dim;
|
||||
cout << "H(curl)-GridFunction\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Invalid field type.");
|
||||
}
|
||||
FiniteElementSpace sc_fes(&mesh, fec, ncomp);
|
||||
// Define a scalar function on the mesh.
|
||||
FiniteElementSpace sc_fes(&mesh, &fec, 1);
|
||||
GridFunction field_vals(&sc_fes);
|
||||
|
||||
// Project the GridFunction using VectorFunctionCoefficient.
|
||||
VectorFunctionCoefficient F(vec_dim, F_exact);
|
||||
field_vals.ProjectCoefficient(F);
|
||||
FunctionCoefficient fc(field_func);
|
||||
field_vals.ProjectCoefficient(fc);
|
||||
|
||||
// Display the mesh and the field through glvis.
|
||||
if (visualization)
|
||||
@@ -182,8 +135,8 @@ int main (int argc, char *argv[])
|
||||
// Generate equidistant points in physical coordinates over the whole mesh.
|
||||
// Note that some points might be outside, if the mesh is not a box. Note
|
||||
// also that all tasks search the same points (not mandatory).
|
||||
const int pts_cnt_1D = 25;
|
||||
int pts_cnt = pow(pts_cnt_1D, dim);
|
||||
const int pts_cnt_1D = 5;
|
||||
const int pts_cnt = pow(pts_cnt_1D, dim);
|
||||
Vector vxyz(pts_cnt * dim);
|
||||
if (dim == 2)
|
||||
{
|
||||
@@ -192,8 +145,8 @@ int main (int argc, char *argv[])
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
vxyz(i) = 100*pos_min(0) + ip.x * (pos_max(0)-pos_min(0));
|
||||
vxyz(pts_cnt + i) = 100*pos_min(1) + ip.y * (pos_max(1)-pos_min(1));
|
||||
vxyz(i) = pos_min(0) + ip.x * (pos_max(0)-pos_min(0));
|
||||
vxyz(pts_cnt + i) = pos_min(1) + ip.y * (pos_max(1)-pos_min(1));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -210,35 +163,32 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Find and Interpolate FE function values on the desired points.
|
||||
Vector interp_vals(pts_cnt*vec_dim);
|
||||
Vector interp_vals(pts_cnt);
|
||||
// FindPoints using GSLIB and interpolate
|
||||
FindPointsGSLIB finder;
|
||||
finder.Setup(mesh);
|
||||
finder.SetL2AvgType(FindPointsGSLIB::NONE);
|
||||
finder.Interpolate(vxyz, field_vals, interp_vals);
|
||||
Array<unsigned int> code_out = finder.GetCode();
|
||||
finder.Interpolate(mesh, vxyz, field_vals, interp_vals);
|
||||
Array<unsigned int> code_out = finder.GetCode();
|
||||
Vector dist_p_out = finder.GetDist();
|
||||
|
||||
// Free the internal gslib data.
|
||||
finder.FreeData();
|
||||
|
||||
int face_pts = 0, not_found = 0, found = 0;
|
||||
double max_err = 0.0, max_dist = 0.0;
|
||||
Vector pos(dim);
|
||||
int npt = 0;
|
||||
for (int j = 0; j < vec_dim; j++)
|
||||
for (int i = 0; i < pts_cnt; i++)
|
||||
{
|
||||
for (int i = 0; i < pts_cnt; i++)
|
||||
if (code_out[i] < 2)
|
||||
{
|
||||
if (code_out[i] < 2)
|
||||
{
|
||||
if (j == 0) { found++; }
|
||||
for (int d = 0; d < dim; d++) { pos(d) = vxyz(d * pts_cnt + i); }
|
||||
Vector exact_val(vec_dim);
|
||||
F_exact(pos, exact_val);
|
||||
max_err = std::max(max_err, fabs(exact_val(j) - interp_vals[npt]));
|
||||
max_dist = std::max(max_dist, dist_p_out(i));
|
||||
if (code_out[i] == 1 && j == 0) { face_pts++; }
|
||||
}
|
||||
else { if (j == 0) { not_found++; } }
|
||||
npt++;
|
||||
found++;
|
||||
for (int d = 0; d < dim; d++) { pos(d) = vxyz(d * pts_cnt + i); }
|
||||
const double exact_val = field_func(pos);
|
||||
|
||||
max_err = std::max(max_err, fabs(exact_val - interp_vals[i]));
|
||||
max_dist = std::max(max_dist, dist_p_out(i));
|
||||
if (code_out[i] == 1) { face_pts++; }
|
||||
}
|
||||
else { not_found++; }
|
||||
}
|
||||
|
||||
cout << setprecision(16)
|
||||
@@ -249,10 +199,5 @@ int main (int argc, char *argv[])
|
||||
<< "\nPoints not found: " << not_found
|
||||
<< "\nPoints on faces: " << face_pts << endl;
|
||||
|
||||
// Free the internal gslib data.
|
||||
finder.FreeData();
|
||||
|
||||
delete fec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
ifeq ($(MFEM_USE_GSLIB),YES)
|
||||
SEQ_MINIAPPS = findpts field-diff field-interp
|
||||
SEQ_MINIAPPS = findpts field-diff
|
||||
PAR_MINIAPPS = pfindpts
|
||||
else
|
||||
SEQ_MINIAPPS =
|
||||
|
||||
+29
-86
@@ -27,6 +27,7 @@
|
||||
// Compile with: make pfindpts
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 2 pfindpts -m ../../data/rt-2d-q3.mesh -o 3
|
||||
// mpirun -np 2 pfindpts -m ../../data/rt-2d-p4-tri.mesh -o 4
|
||||
// mpirun -np 2 pfindpts -m ../../data/inline-tri.mesh -o 3
|
||||
// mpirun -np 2 pfindpts -m ../../data/inline-quad.mesh -o 3
|
||||
@@ -34,7 +35,6 @@
|
||||
// mpirun -np 2 pfindpts -m ../../data/inline-hex.mesh -o 3
|
||||
// mpirun -np 2 pfindpts -m ../../data/inline-wedge.mesh -o 3
|
||||
// mpirun -np 2 pfindpts -m ../../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 2 pfindpts -m ../../data/rt-2d-q3.mesh -o 3 -mo 4 -ft 2
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
@@ -51,12 +51,6 @@ double field_func(const Vector &x)
|
||||
return res;
|
||||
}
|
||||
|
||||
void F_exact(const Vector &p, Vector &F)
|
||||
{
|
||||
F(0) = field_func(p);
|
||||
for (int i = 1; i < F.Size(); i++) { F(i) = (i+1)*F(0); }
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// Initialize MPI.
|
||||
@@ -67,30 +61,21 @@ int main (int argc, char *argv[])
|
||||
|
||||
// Set the method's default parameters.
|
||||
const char *mesh_file = "../../data/rt-2d-q3.mesh";
|
||||
int order = 3;
|
||||
int mesh_poly_deg = 3;
|
||||
int rs_levels = 0;
|
||||
int rp_levels = 0;
|
||||
bool visualization = true;
|
||||
int fieldtype = 0;
|
||||
int ncomp = 1;
|
||||
|
||||
// Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&mesh_poly_deg, "-mo", "--mesh-order",
|
||||
args.AddOption(&mesh_poly_deg, "-o", "--mesh-order",
|
||||
"Polynomial degree of mesh finite element space.");
|
||||
args.AddOption(&rs_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&rp_levels, "-rp", "--refine-parallel",
|
||||
"Number of times to refine the mesh uniformly in parallel.");
|
||||
args.AddOption(&fieldtype, "-ft", "--field-type",
|
||||
"Field type: 0 - H1, 1 - L2, 2 - H(div), 3 - H(curl).");
|
||||
args.AddOption(&ncomp, "-nc", "--ncomp",
|
||||
"Number of components for H1 or L2 GridFunctions");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
@@ -135,51 +120,19 @@ int main (int argc, char *argv[])
|
||||
for (int lev = 0; lev < rp_levels; lev++) { pmesh.UniformRefinement(); }
|
||||
|
||||
// Curve the mesh based on the chosen polynomial degree.
|
||||
H1_FECollection fecm(mesh_poly_deg, dim);
|
||||
ParFiniteElementSpace pfespace(&pmesh, &fecm, dim);
|
||||
H1_FECollection fec(mesh_poly_deg, dim);
|
||||
ParFiniteElementSpace pfespace(&pmesh, &fec, dim);
|
||||
pmesh.SetNodalFESpace(&pfespace);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Mesh curvature of the curved mesh: " << fecm.Name() << endl;
|
||||
cout << "Mesh curvature of the curved mesh: " << fec.Name() << endl;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(ncomp > 0, "Invalid number of components.");
|
||||
int vec_dim = ncomp;
|
||||
FiniteElementCollection *fec = NULL;
|
||||
if (fieldtype == 0)
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
if (myid == 0) { cout << "H1-GridFunction\n"; }
|
||||
}
|
||||
else if (fieldtype == 1)
|
||||
{
|
||||
fec = new L2_FECollection(order, dim);
|
||||
if (myid == 0) { cout << "L2-GridFunction\n"; }
|
||||
}
|
||||
else if (fieldtype == 2)
|
||||
{
|
||||
fec = new RT_FECollection(order, dim);
|
||||
ncomp = 1;
|
||||
vec_dim = dim;
|
||||
if (myid == 0) { cout << "H(div)-GridFunction\n"; }
|
||||
}
|
||||
else if (fieldtype == 3)
|
||||
{
|
||||
fec = new ND_FECollection(order, dim);
|
||||
ncomp = 1;
|
||||
vec_dim = dim;
|
||||
if (myid == 0) { cout << "H(curl)-GridFunction\n"; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (myid == 0) { MFEM_ABORT("Invalid FECollection type."); }
|
||||
}
|
||||
ParFiniteElementSpace sc_fes(&pmesh, fec, ncomp);
|
||||
ParGridFunction field_vals(&sc_fes);
|
||||
|
||||
// Project the GridFunction using VectorFunctionCoefficient.
|
||||
VectorFunctionCoefficient F(vec_dim, F_exact);
|
||||
field_vals.ProjectCoefficient(F);
|
||||
// Define a scalar function on the mesh.
|
||||
ParFiniteElementSpace sc_fes(&pmesh, &fec, 1);
|
||||
GridFunction field_vals(&sc_fes);
|
||||
FunctionCoefficient fc(field_func);
|
||||
field_vals.ProjectCoefficient(fc);
|
||||
|
||||
// Display the mesh and the field through glvis.
|
||||
if (visualization)
|
||||
@@ -210,7 +163,7 @@ int main (int argc, char *argv[])
|
||||
// Generate equidistant points in physical coordinates over the whole mesh.
|
||||
// Note that some points might be outside, if the mesh is not a box. Note
|
||||
// also that all tasks search the same points (not mandatory).
|
||||
const int pts_cnt_1D = 10;
|
||||
const int pts_cnt_1D = 5;
|
||||
const int pts_cnt = pow(pts_cnt_1D, dim);
|
||||
Vector vxyz(pts_cnt * dim);
|
||||
if (dim == 2)
|
||||
@@ -238,10 +191,10 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Find and Interpolate FE function values on the desired points.
|
||||
Vector interp_vals(pts_cnt*vec_dim);
|
||||
Vector interp_vals(pts_cnt);
|
||||
// FindPoints using GSLIB and interpolate
|
||||
FindPointsGSLIB finder(MPI_COMM_WORLD);
|
||||
finder.Setup(pmesh);
|
||||
finder.Interpolate(vxyz, field_vals, interp_vals);
|
||||
finder.Interpolate(pmesh, vxyz, field_vals, interp_vals);
|
||||
Array<unsigned int> code_out = finder.GetCode();
|
||||
Array<unsigned int> task_id_out = finder.GetProc();
|
||||
Vector dist_p_out = finder.GetDist();
|
||||
@@ -249,35 +202,28 @@ int main (int argc, char *argv[])
|
||||
int face_pts = 0, not_found = 0, found_loc = 0, found_away = 0;
|
||||
double max_err = 0.0, max_dist = 0.0;
|
||||
Vector pos(dim);
|
||||
int npt = 0;
|
||||
for (int j = 0; j < vec_dim; j++)
|
||||
for (int i = 0; i < pts_cnt; i++)
|
||||
{
|
||||
for (int i = 0; i < pts_cnt; i++)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
(task_id_out[i] == (unsigned)myid) ? found_loc++ : found_away++;
|
||||
}
|
||||
(task_id_out[i] == (unsigned)myid) ? found_loc++ : found_away++;
|
||||
|
||||
if (code_out[i] < 2)
|
||||
{
|
||||
for (int d = 0; d < dim; d++) { pos(d) = vxyz(d * pts_cnt + i); }
|
||||
Vector exact_val(vec_dim);
|
||||
F_exact(pos, exact_val);
|
||||
max_err = std::max(max_err, fabs(exact_val(j) - interp_vals(npt)));
|
||||
max_dist = std::max(max_dist, dist_p_out(i));
|
||||
if (code_out[i] == 1 && j == 0) { face_pts++; }
|
||||
}
|
||||
else { if (j == 0) { not_found++; } }
|
||||
npt++;
|
||||
if (code_out[i] < 2)
|
||||
{
|
||||
for (int d = 0; d < dim; d++) { pos(d) = vxyz(d * pts_cnt + i); }
|
||||
const double exact_val = field_func(pos);
|
||||
|
||||
max_err = std::max(max_err, fabs(exact_val - interp_vals[i]));
|
||||
max_dist = std::max(max_dist, dist_p_out(i));
|
||||
if (code_out[i] == 1) { face_pts++; }
|
||||
}
|
||||
else { not_found++; }
|
||||
}
|
||||
|
||||
// Print the results for task 0 since all tasks have the same set of points.
|
||||
// We print only the task 0 result (other tasks should be identical except
|
||||
// the number of points found locally).
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << setprecision(16)
|
||||
<< "Searched unique points: " << pts_cnt
|
||||
cout << setprecision(16) << "--- Task " << myid << ": "
|
||||
<< "\nSearched points: " << pts_cnt
|
||||
<< "\nFound on local mesh: " << found_loc
|
||||
<< "\nFound on other tasks: " << found_away
|
||||
<< "\nMax interp error: " << max_err
|
||||
@@ -288,9 +234,6 @@ int main (int argc, char *argv[])
|
||||
|
||||
// Free the internal gslib data.
|
||||
finder.FreeData();
|
||||
|
||||
delete fec;
|
||||
|
||||
MPI_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,10 +50,6 @@ add_mfem_miniapp(twist
|
||||
MAIN twist.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(polar-nc
|
||||
MAIN polar-nc.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
# Add serial tests.
|
||||
add_test(NAME mesh-optimizer
|
||||
COMMAND mesh-optimizer -no-vis -m ${CMAKE_CURRENT_SOURCE_DIR}/icf.mesh)
|
||||
|
||||
@@ -25,8 +25,9 @@ include $(DEFAULTS_MK)
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_MINIAPPS = mobius-strip klein-bottle toroid trimmer twist mesh-explorer\
|
||||
shaper extruder mesh-optimizer minimal-surface polar-nc
|
||||
SEQ_MINIAPPS = mobius-strip klein-bottle toroid trimmer twist \
|
||||
mesh-explorer shaper extruder mesh-optimizer \
|
||||
minimal-surface
|
||||
PAR_MINIAPPS = pmesh-optimizer pminimal-surface
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
@@ -106,7 +107,7 @@ clean: clean-build clean-exec
|
||||
clean-build:
|
||||
rm -f *.o *~ mobius-strip klein-bottle toroid twist
|
||||
rm -f mesh-explorer shaper extruder trimmer
|
||||
rm -f mesh-optimizer pmesh-optimizer polar-nc
|
||||
rm -f mesh-optimizer pmesh-optimizer
|
||||
rm -f minimal-surface pminimal-surface
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
@@ -114,4 +115,4 @@ clean-exec:
|
||||
@rm -f mobius-strip.mesh klein-bottle.mesh mesh-explorer.mesh
|
||||
@rm -f toroid-*.mesh twist-*.mesh trimmer.mesh
|
||||
@rm -f partitioning.txt shaper.mesh extruder.mesh
|
||||
@rm -f optimized* perturbed* polar-nc.mesh
|
||||
@rm -f optimized* perturbed*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user