Compare commits

..
2 Commits
165 changed files with 5455 additions and 8890 deletions
+61
View File
@@ -0,0 +1,61 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
# Number of days of inactivity before an Issue or Pull Request with the stale
# label is closed. Set to false to disable. If disabled, issues still need to
# be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale.
# Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set
# to `[]` to disable
exemptLabels:
- bug
- WIP
- ready-for-review
- in-review
- in-next
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
:warning: This issue or PR has been automatically marked as stale because it has not
had any activity in the last month. *If no activity occurs in the next week, it will
be automatically closed.* Thank you for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed
-31
View File
@@ -1,31 +0,0 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
# For more information, see: https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
actions: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: ':warning: This issue has been automatically marked as stale because it has not had any activity in the last month. *If no activity occurs in the next week, it will be automatically closed.* Thank you for your contributions.'
stale-pr-message: ':warning: This PR has been automatically marked as stale because it has not had any activity in the last month. *If no activity occurs in the next week, it will be automatically closed.* Thank you for your contributions.'
days-before-stale: 30
days-before-close: 7
stale-issue-label: 'stale'
stale-pr-label: 'stale'
operations-per-run: 500
exempt-issue-labels: "bug,WIP,ready-for-review,in-review,in-next"
exempt-pr-labels: "bug,WIP,ready-for-review,in-review,in-next"
-1
View File
@@ -8,7 +8,6 @@
# Object and library files
*.o
*.o.tmp
/libmfem.*
/miniapps/common/libmfem-common.*
-37
View File
@@ -10,8 +10,6 @@
Version 4.7.1 (development)
===========================
- Refactored ALGOIM cut integration rules. The interface is unified with
the interface for moment based cut integration rules.
Discretization improvements
---------------------------
@@ -20,8 +18,6 @@ Discretization improvements
- Added support for boundary constraints to the hybridization class.
- Added support for external boundary submeshes with nonconformal mesh adaptation.
Meshing improvements
--------------------
- The ExodusII reader now handles pyramid and wedge element types. Mixed meshes
@@ -54,15 +50,8 @@ GPU computing
or by explicitly calling `KernelReporter::Enable`. Users can then add
specializations for these kernels to achieve higher performance.
- Element assembly kernels have been added for low-order refined to
high-order transfer operators. New kernels can be offloaded as device
kernels. Example usage may be found in lor-transfer.cpp under miniapps/tools.
Miscellaneous
-------------
- Added support for SUNDIALS v7. See the section "API changes" for some small
changes related to this new version.
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
`TimeDependentOperator::Mult` only when the associated ODE operator is
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
@@ -75,27 +64,10 @@ Miscellaneous
- Added support for custom interpolation procedure in FindPointsGSLIB.
- `FiniteElementSpace` has new methods to directly set prolongation and
restriction operators to arbitrary sparse matrices.
- There are new convenience constructors for NURBS patches and knot vectors.
API changes
-----------
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
- API change: support for SUNDIALS v7:
* the SUNDIALS types `realtype` and `booleantype` are no longer defined by v7
and therefore MFEM now uses the new type names `sunrealtype` and
`sunbooleantype`, respectively, which MFEM defines when using SUNDIALS < v6
where these types were not defined.
* The SUNDIALS macro `SUNLS_SUCCESS` and some other `*_SUCCESS` macros were
removed and replaced by `SUN_SUCCESS` in v7, so to avoid tedious checks for
SUNDIALS versions, MFEM now defines and uses the constant `SUN_SUCCESS` when
using SUNDIALS < v7.
* The constants `SUN_PREC_*`, introduced by SUNDIALS v6 are now introduced by
MFEM when using SUNDIALS < v6 to avoid tedious version checks.
Version 4.7, released on May 7, 2024
====================================
@@ -182,15 +154,6 @@ New and updated examples and miniapps
- Added two new example codes: 38 and 39/39p described above. Substantially
updated Example 18/18p.
- Added ODE solvers selection routines. This creates a uniformity across examples,
miniapps and other executables in regard to ODE(time-integrator) selection.
- Added new mechanism for retrieving and setting state vectors in ODE solvers.
This is relevant for AB/AM and gen-alpha solvers.
- Added ODEsolver/ODEsolver2 unit tests to verify order of convergence and
read/write functionality.
Miscellaneous
-------------
- Updated the Doxygen documentation style, which now requires Doxygen version
+1 -4
View File
@@ -340,10 +340,7 @@ if (MFEM_USE_SUNDIALS)
if (MFEM_USE_HIP)
list(APPEND SUNDIALS_COMPONENTS NVector_Hip)
endif()
# The Core component was added in SUNDIALS v7, so we treat it as optional in
# order to support older versions.
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS}
OPTIONAL_COMPONENTS Core)
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
endif()
# SuperLU_DIST can only be enabled in parallel
+3 -7
View File
@@ -502,14 +502,10 @@ MFEM_USE_CODIPACK = YES/NO
MFEM_USE_ALGOIM = YES/NO
Enable the usage of Algoim - a collection of high-order accurate numerical
methods and C++ algorithms for working with implicitly-defined geometry and
level set methods, see https://algoim.github.io. MFEM provides interface to
Algoim v1. To check out the specific Algoim state use:
https://github.com/algoim/algoim
level set methods. The Algoim library requires the Blitz++ library. The MFEM
provides interface to Algoim v1. Thus, to check out the specific state use:
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a
The Algoim library requires the Blitz++ library. To use the latest state of
Blitz++ that has been tested with MFEM, use:
https://github.com/blitzpp/blitz
git checkout f24a250a43dff88c31ad92916da828b7ea9a98b7
https://algoim.github.io
MFEM_USE_ADFORWARD = YES/NO
Enable forward mode for AD packages. This option is valid
+1 -2
View File
@@ -31,5 +31,4 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
ADD_COMPONENT CVODE "include" cvode/cvode.h "lib" sundials_cvode
ADD_COMPONENT CVODES "include" cvodes/cvodes.h "lib" sundials_cvodes
ADD_COMPONENT ARKODE "include" arkode/arkode.h "lib" sundials_arkode
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol
ADD_COMPONENT Core "include" sundials/sundials_core.h "lib" sundials_core)
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol)
+1 -10
View File
@@ -289,13 +289,6 @@ endif
ifeq ($(MFEM_USE_HIP),YES)
SUNDIALS_LIB += -lsundials_nvechip
endif
SUNDIALS_CORE_PAT = $(subst\
@MFEM_DIR@,$(MFEM_DIR),$(SUNDIALS_DIR))/lib*/libsundials_core.*
ifeq ($(MFEM_USE_SUNDIALS),YES)
ifneq ($(wildcard $(SUNDIALS_CORE_PAT)),)
SUNDIALS_LIB += -lsundials_core
endif
endif
# If SUNDIALS was built with KLU:
# MFEM_USE_SUITESPARSE = YES
@@ -540,10 +533,8 @@ ifdef GOTCHA_DIR
endif
# BLITZ library configuration
# BLITZ_DIR must be the custom installation folder (-DCMAKE_INSTALL_PREFIX).
BLITZ_DIR = @MFEM_DIR@/../blitz/install
BLITZ_DIR = @MFEM_DIR@/../blitz
BLITZ_OPT = -I$(BLITZ_DIR)/include
# On intel machines, use /lib64 instead of /lib.
BLITZ_LIB = $(XLINKER)-rpath,$(BLITZ_DIR)/lib -L$(BLITZ_DIR)/lib -lblitz
# ALGOIM library configuration
+37 -11
View File
@@ -3,14 +3,14 @@
// Compile with: make ex10
//
// Sample runs:
// ex10 -m ../data/beam-quad.mesh -s 23 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-tri.mesh -s 23 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-hex.mesh -s 22 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-tet.mesh -s 22 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-wedge.mesh -s 22 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-quad.mesh -s 4 -r 2 -o 2 -dt 0.03 -vs 20
// ex10 -m ../data/beam-hex.mesh -s 4 -r 1 -o 2 -dt 0.05 -vs 20
// ex10 -m ../data/beam-quad-amr.mesh -s 23 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-quad.mesh -s 3 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-tri.mesh -s 3 -r 2 -o 2 -dt 3
// ex10 -m ../data/beam-hex.mesh -s 2 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-tet.mesh -s 2 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-wedge.mesh -s 2 -r 1 -o 2 -dt 3
// ex10 -m ../data/beam-quad.mesh -s 14 -r 2 -o 2 -dt 0.03 -vs 20
// ex10 -m ../data/beam-hex.mesh -s 14 -r 1 -o 2 -dt 0.05 -vs 20
// ex10 -m ../data/beam-quad-amr.mesh -s 3 -r 2 -o 2 -dt 3
//
// Description: This examples solves a time dependent nonlinear elasticity
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
@@ -160,7 +160,7 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/beam-quad.mesh";
int ref_levels = 2;
int order = 2;
int ode_solver_type = 23;
int ode_solver_type = 3;
real_t t_final = 300.0;
real_t dt = 3.0;
real_t visc = 1e-2;
@@ -177,7 +177,11 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::Types.c_str());
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
" 11 - Forward Euler, 12 - RK2,\n\t"
" 13 - RK3 SSP, 14 - RK4."
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -209,7 +213,28 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several implicit
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
// explicit Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
ODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit L-stable methods
case 1: ode_solver = new BackwardEulerSolver; break;
case 2: ode_solver = new SDIRK23Solver(2); break;
case 3: ode_solver = new SDIRK33Solver; break;
// Explicit methods
case 11: ode_solver = new ForwardEulerSolver; break;
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return 3;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
@@ -346,6 +371,7 @@ int main(int argc, char *argv[])
}
// 10. Free the used memory.
delete ode_solver;
delete mesh;
return 0;
+40 -11
View File
@@ -3,14 +3,14 @@
// Compile with: make ex10p
//
// Sample runs:
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 23 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 23 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 22 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 22 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 22 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 4 -rs 2 -dt 0.03 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 4 -rs 1 -dt 0.05 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 23 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 3 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 3 -rs 2 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 2 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 2 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 2 -rs 1 -dt 3
// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 14 -rs 2 -dt 0.03 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 14 -rs 1 -dt 0.05 -vs 20
// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 3 -rs 2 -dt 3
//
// Description: This examples solves a time dependent nonlinear elasticity
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
int ser_ref_levels = 2;
int par_ref_levels = 0;
int order = 2;
int ode_solver_type = 23;
int ode_solver_type = 3;
real_t t_final = 300.0;
real_t dt = 3.0;
real_t visc = 1e-2;
@@ -192,7 +192,11 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::Types.c_str());
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
" 11 - Forward Euler, 12 - RK2,\n\t"
" 13 - RK3 SSP, 14 - RK4."
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -234,7 +238,31 @@ int main(int argc, char *argv[])
// 4. Define the ODE solver used for time integration. Several implicit
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
// explicit Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
ODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit L-stable methods
case 1: ode_solver = new BackwardEulerSolver; break;
case 2: ode_solver = new SDIRK23Solver(2); break;
case 3: ode_solver = new SDIRK33Solver; break;
// Explicit methods
case 11: ode_solver = new ForwardEulerSolver; break;
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
if (myid == 0)
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
}
delete mesh;
return 3;
}
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
@@ -405,6 +433,7 @@ int main(int argc, char *argv[])
}
// 12. Free the used memory.
delete ode_solver;
delete pmesh;
return 0;
+30 -9
View File
@@ -5,10 +5,10 @@
// Sample runs: ex16
// ex16 -m ../data/inline-tri.mesh
// ex16 -m ../data/disc-nurbs.mesh -tf 2
// ex16 -s 21 -a 0.0 -k 1.0
// ex16 -s 22 -a 1.0 -k 0.0
// ex16 -s 23 -a 0.5 -k 0.5 -o 4
// ex16 -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// ex16 -s 1 -a 0.0 -k 1.0
// ex16 -s 2 -a 1.0 -k 0.0
// ex16 -s 3 -a 0.5 -k 0.5 -o 4
// ex16 -s 14 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// ex16 -m ../data/fichera-q2.mesh
// ex16 -m ../data/fichera-mixed.mesh
// ex16 -m ../data/escher.mesh
@@ -95,13 +95,11 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int ref_levels = 2;
int order = 2;
int ode_solver_type = 23; // SDIRK33Solver
int ode_solver_type = 3;
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
@@ -117,7 +115,8 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::Types.c_str());
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
"\t 11 - Forward Euler, 12 - RK2, 13 - RK3 SSP, 14 - RK4.");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -150,7 +149,28 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several implicit
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
// explicit Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
ODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit L-stable methods
case 1: ode_solver = new BackwardEulerSolver; break;
case 2: ode_solver = new SDIRK23Solver(2); break;
case 3: ode_solver = new SDIRK33Solver; break;
// Explicit methods
case 11: ode_solver = new ForwardEulerSolver; break;
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return 3;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
@@ -267,6 +287,7 @@ int main(int argc, char *argv[])
}
// 10. Free the used memory.
delete ode_solver;
delete mesh;
return 0;
+30 -9
View File
@@ -5,10 +5,10 @@
// Sample runs: mpirun -np 4 ex16p
// mpirun -np 4 ex16p -m ../data/inline-tri.mesh
// mpirun -np 4 ex16p -m ../data/disc-nurbs.mesh -tf 2
// mpirun -np 4 ex16p -s 21 -a 0.0 -k 1.0
// mpirun -np 4 ex16p -s 22 -a 1.0 -k 0.0
// mpirun -np 8 ex16p -s 23 -a 0.5 -k 0.5 -o 4
// mpirun -np 4 ex16p -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// mpirun -np 4 ex16p -s 1 -a 0.0 -k 1.0
// mpirun -np 4 ex16p -s 2 -a 1.0 -k 0.0
// mpirun -np 8 ex16p -s 3 -a 0.5 -k 0.5 -o 4
// mpirun -np 4 ex16p -s 14 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// mpirun -np 16 ex16p -m ../data/fichera-q2.mesh
// mpirun -np 16 ex16p -m ../data/fichera-mixed.mesh
// mpirun -np 16 ex16p -m ../data/escher-p2.mesh
@@ -104,13 +104,11 @@ int main(int argc, char *argv[])
int ser_ref_levels = 2;
int par_ref_levels = 1;
int order = 2;
int ode_solver_type = 23; // SDIRK33Solver
int ode_solver_type = 3;
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
@@ -129,7 +127,8 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::Types.c_str());
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
"\t 11 - Forward Euler, 12 - RK2, 13 - RK3 SSP, 14 - RK4.");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -170,7 +169,28 @@ int main(int argc, char *argv[])
// 4. Define the ODE solver used for time integration. Several implicit
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
// explicit Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
ODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit L-stable methods
case 1: ode_solver = new BackwardEulerSolver; break;
case 2: ode_solver = new SDIRK23Solver(2); break;
case 3: ode_solver = new SDIRK33Solver; break;
// Explicit methods
case 11: ode_solver = new ForwardEulerSolver; break;
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 13: ode_solver = new RK3SSPSolver; break;
case 14: ode_solver = new RK4Solver; break;
case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return 3;
}
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
@@ -356,6 +376,7 @@ int main(int argc, char *argv[])
}
// 12. Free the used memory.
delete ode_solver;
delete pmesh;
return 0;
+17 -2
View File
@@ -90,7 +90,8 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::ExplicitTypes.c_str());
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step. Positive number skips CFL timestep calculation.");
@@ -124,7 +125,18 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
// 4. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
@@ -292,5 +304,8 @@ int main(int argc, char *argv[])
const real_t error = sol.ComputeLpError(2, u0);
cout << "Solution error: " << error << endl;
// Free the used memory.
delete ode_solver;
return 0;
}
+17 -2
View File
@@ -99,7 +99,8 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::ExplicitTypes.c_str());
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step. Positive number skips CFL timestep calculation.");
@@ -147,7 +148,18 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
// 4. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
@@ -348,5 +360,8 @@ int main(int argc, char *argv[])
cout << "Solution error: " << error << endl;
}
// Free the used memory.
delete ode_solver;
return 0;
}
+29 -2
View File
@@ -201,7 +201,9 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
SecondOrderODESolver::Types.c_str());
"ODE solver: [0--10] - GeneralizedAlpha(0.1 * s),\n\t"
"\t 11 - Average Acceleration, 12 - Linear Acceleration\n"
"\t 13 - CentralDifference, 14 - FoxGoodwin");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -236,7 +238,32 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several second order
// time integrators are available.
SecondOrderODESolver *ode_solver= SecondOrderODESolver::Select(ode_solver_type);
SecondOrderODESolver *ode_solver;
switch (ode_solver_type)
{
// Implicit methods
case 0: ode_solver = new GeneralizedAlpha2Solver(0.0); break;
case 1: ode_solver = new GeneralizedAlpha2Solver(0.1); break;
case 2: ode_solver = new GeneralizedAlpha2Solver(0.2); break;
case 3: ode_solver = new GeneralizedAlpha2Solver(0.3); break;
case 4: ode_solver = new GeneralizedAlpha2Solver(0.4); break;
case 5: ode_solver = new GeneralizedAlpha2Solver(0.5); break;
case 6: ode_solver = new GeneralizedAlpha2Solver(0.6); break;
case 7: ode_solver = new GeneralizedAlpha2Solver(0.7); break;
case 8: ode_solver = new GeneralizedAlpha2Solver(0.8); break;
case 9: ode_solver = new GeneralizedAlpha2Solver(0.9); break;
case 10: ode_solver = new GeneralizedAlpha2Solver(1.0); break;
case 11: ode_solver = new AverageAccelerationSolver(); break;
case 12: ode_solver = new LinearAccelerationSolver(); break;
case 13: ode_solver = new CentralDifferenceSolver(); break;
case 14: ode_solver = new FoxGoodwinSolver(); break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
delete mesh;
return 3;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
+84 -118
View File
@@ -3,18 +3,18 @@
// Compile with: make ex38
//
// Sample runs:
// (since all sample runs require LAPACK or ALGOIM, the * symbol is used to
// exclude them from the automatically generated internal MFEM tests).
// (since all sample runs require LAPACK, the * symbol is used to exclude them
// from the automatically generated internal MFEM tests).
// * ex38
// * ex38 -i volumetric1d
// * ex38 -i surface2d
// * ex38 -i surface2d -o 4 -r 5 -m 1
// * ex38 -i surface2d -o 4 -r 5
// * ex38 -i volumetric2d
// * ex38 -i volumetric2d -o 4 -r 5 -m 1
// * ex38 -i volumetric2d -o 4 -r 5
// * ex38 -i surface3d
// * ex38 -i surface3d -o 3 -r 4 -m 1
// * ex38 -i surface3d -o 4 -r 5
// * ex38 -i volumetric3d
// * ex38 -i volumetric3d -o 3 -r 4 -m 1
// * ex38 -i volumetric3d -o 4 -r 5
//
// Description: This example code demonstrates the use of MFEM to integrate
// functions over implicit interfaces and subdomains bounded by
@@ -71,7 +71,7 @@ real_t integrand(const Vector& X)
switch (itype)
{
case IntegrationType::Volumetric1D:
return pow(X(0), 2.);
return 1.;
case IntegrationType::Surface2D:
return 3. * pow(X(0), 2.) - pow(X(1), 2.);
case IntegrationType::Volumetric2D:
@@ -91,7 +91,7 @@ real_t Surface()
switch (itype)
{
case IntegrationType::Volumetric1D:
return .3025;
return 1.;
case IntegrationType::Surface2D:
return 2. * M_PI;
case IntegrationType::Volumetric2D:
@@ -111,7 +111,7 @@ real_t Volume()
switch (itype)
{
case IntegrationType::Volumetric1D:
return pow(.55, 3.) / 3.;
return .55;
case IntegrationType::Surface2D:
return NAN;
case IntegrationType::Volumetric2D:
@@ -125,6 +125,7 @@ real_t Volume()
}
}
#ifdef MFEM_USE_LAPACK
/**
@brief Class for surface IntegrationRule
@@ -134,14 +135,11 @@ real_t Volume()
class SIntegrationRule : public IntegrationRule
{
protected:
/// method 0 is moments-based, 1 is Algoim.
int method, ir_order, ls_order;
Coefficient &level_set;
/// Space Dimension of the IntegrationRule
/// @brief Space Dimension of the IntegrationRule
int dim;
/// Column-wise matrix of the quadtrature weights
/// @brief Column-wise matrix of the quadtrature weights
DenseMatrix Weights;
/// Column-wise matrix of the transformation weights of the normal
/// @brief Column-wise matrix of the transformation weights of the normal
DenseMatrix SurfaceWeights;
public:
@@ -155,21 +153,15 @@ public:
@param [in] lsOrder Polynomial degree for approx of level-set function
@param [in] mesh Pointer to the mesh that is used
*/
SIntegrationRule(int method_, int Order,
Coefficient& LvlSet, int lsOrder, Mesh* mesh)
: method(method_), ir_order(Order), ls_order(lsOrder),
level_set(LvlSet), dim(mesh->Dimension())
SIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
{
// Nothing gets pre-computed for Algoim.
if (method == 1) { return; }
#ifdef MFEM_USE_LAPACK
MomentFittingIntRules mf_ir(ir_order, level_set, ls_order);
dim = mesh->Dimension();
IsoparametricTransformation Tr;
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
mesh->GetElementTransformation(0, &Tr);
IntegrationRule ir;
mf_ir.GetSurfaceIntegrationRule(Tr, ir);
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
if (dim >1)
{
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
@@ -180,7 +172,7 @@ public:
}
SurfaceWeights.SetSize(ir.GetNPoints(), mesh->GetNE());
Vector w;
mf_ir.GetSurfaceWeights(Tr, ir, w);
MFIRs.GetSurfaceWeights(Tr, ir, w);
SurfaceWeights.SetCol(0, w);
SetSize(ir.GetNPoints());
@@ -206,8 +198,8 @@ public:
for (int elem = 1; elem < mesh->GetNE(); elem++)
{
mesh->GetElementTransformation(elem, &Tr);
mf_ir.GetSurfaceIntegrationRule(Tr, ir);
mf_ir.GetSurfaceWeights(Tr, ir, w);
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
MFIRs.GetSurfaceWeights(Tr, ir, w);
SurfaceWeights.SetCol(elem, w);
for (int ip = 0; ip < GetNPoints(); ip++)
@@ -223,48 +215,48 @@ public:
}
}
}
#else
MFEM_ABORT("Moment-fitting requires MFEM to be built with LAPACK!");
#endif
}
/**
@brief Set the weights for the given element and multiply them with the
transformation of the interface
*/
void SetElementAndSurfaceWeight(ElementTransformation &Tr)
void SetElementinclSurfaceWeight(int Element)
{
if (method == 1)
{
#ifdef MFEM_USE_ALGOIM
AlgoimIntegrationRules a_ir(ir_order, level_set, ls_order);
a_ir.GetSurfaceIntegrationRule(Tr, *this);
Vector w;
a_ir.GetSurfaceWeights(Tr, *this, w);
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntPoint(ip).weight *= w(ip);
}
return;
#else
MFEM_ABORT("MFEM is not built with Algoim support!");
#endif
}
if (dim == 1)
{
IntPoint(0).x = Weights(0, Tr.ElementNo);
IntPoint(0).weight = Weights(1, Tr.ElementNo);
IntegrationPoint &intp = IntPoint(0);
intp.x = Weights(0, Element);
intp.weight = Weights(1, Element);
cout << intp.x << " " << Element << endl;
}
else
{
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntPoint(ip).weight = Weights(ip, Tr.ElementNo) *
SurfaceWeights(ip, Tr.ElementNo);
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element) * SurfaceWeights(ip, Element);
}
}
}
/// @brief Set the weights for the given element
void SetElement(int Element)
{
if (dim == 1)
{
IntegrationPoint &intp = IntPoint(0);
intp.x = Weights(0, Element);
intp.weight = Weights(1, Element);
}
else
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element);
}
}
/// @brief Destructor of SIntegrationRule
~SIntegrationRule() {}
};
/**
@@ -276,12 +268,9 @@ public:
class CIntegrationRule : public IntegrationRule
{
protected:
/// method 0 is moments-based, 1 is Algoim.
int method, ir_order, ls_order;
Coefficient &level_set;
/// Space Dimension of the IntegrationRule
/// @brief Space Dimension of the IntegrationRule
int dim;
/// Column-wise matrix of the quadtrature positions and weights.
/// @brief Column-wise matrix of the quadtrature weights
DenseMatrix Weights;
public:
@@ -295,21 +284,15 @@ public:
@param [in] lsOrder Polynomial degree for approx of level-set function
@param [in] mesh Pointer to the mesh that is used
*/
CIntegrationRule(int method_, int Order,
Coefficient &LvlSet, int lsOrder, Mesh *mesh)
: method(method_), ir_order(Order), ls_order(lsOrder),
level_set(LvlSet), dim(mesh->Dimension())
CIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
{
// Nothing gets pre-computed for Algoim.
if (method == 1) { return; }
#ifdef MFEM_USE_LAPACK
MomentFittingIntRules mf_ir(ir_order, level_set, ls_order);
dim = mesh->Dimension();
IsoparametricTransformation Tr;
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
mesh->GetElementTransformation(0, &Tr);
IntegrationRule ir;
mf_ir.GetVolumeIntegrationRule(Tr, ir);
MFIRs.GetVolumeIntegrationRule(Tr, ir);
if (dim > 1)
{
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
@@ -341,9 +324,9 @@ public:
for (int elem = 1; elem < mesh->GetNE(); elem++)
{
mesh->GetElementTransformation(elem, &Tr);
mf_ir.GetVolumeIntegrationRule(Tr, ir);
MFIRs.GetVolumeIntegrationRule(Tr, ir);
for (int ip = 0; ip < ir.GetNPoints(); ip++)
for (int ip = 0; ip < GetNPoints(); ip++)
{
if (dim > 1)
{
@@ -356,39 +339,29 @@ public:
}
}
}
#else
MFEM_ABORT("Moment-fitting requires MFEM to be built with LAPACK!");
#endif
}
/// @brief Set the weights for the given element
void SetElement(ElementTransformation &Tr)
void SetElement(int Element)
{
if (method == 1)
{
#ifdef MFEM_USE_ALGOIM
AlgoimIntegrationRules a_ir(ir_order, level_set, ls_order);
a_ir.GetVolumeIntegrationRule(Tr, *this);
return;
#else
MFEM_ABORT("MFEM is not built with Algoim support!");
#endif
}
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
if (dim == 1)
if (dim == 1)
for (int ip = 0; ip < GetNPoints(); ip++)
{
intp.x = Weights(2 * ip, Tr.ElementNo);
intp.weight = Weights(2 * ip + 1, Tr.ElementNo);
IntegrationPoint &intp = IntPoint(ip);
intp.x = Weights(2 * ip, Element);
intp.weight = Weights(2 * ip + 1, Element);
}
else
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element);
}
else { intp.weight = Weights(ip, Tr.ElementNo); }
}
}
/// @brief Destructor of CIntegrationRule
~CIntegrationRule() {}
};
/**
@brief Class for surface linearform integrator
@@ -445,7 +418,7 @@ public:
elvect = 0.;
// Update the surface integration rule for the current element
SIntRule->SetElementAndSurfaceWeight(Tr);
SIntRule->SetElementinclSurfaceWeight(Tr.ElementNo);
for (int ip = 0; ip < SIntRule->GetNPoints(); ip++)
{
@@ -455,8 +428,6 @@ public:
add(elvect, SIntRule->IntPoint(ip).weight * val, shape, elvect);
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
};
/**
@@ -515,7 +486,7 @@ public:
elvect = 0.;
// Update the subdomain integration rule
CIntRule->SetElement(Tr);
CIntRule->SetElement(Tr.ElementNo);
for (int ip = 0; ip < CIntRule->GetNPoints(); ip++)
{
@@ -526,17 +497,18 @@ public:
add(elvect, CIntRule->IntPoint(ip).weight * val, shape, elvect);
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
};
#endif // MFEM_USE_LAPACK
int main(int argc, char *argv[])
{
#if defined(MFEM_USE_LAPACK) || defined(MFEM_USE_ALGOIM)
#ifndef MFEM_USE_LAPACK
cout << "MFEM must be built with LAPACK for this example." << endl;
return MFEM_SKIP_RETURN_VALUE;
#else
// 1. Parse he command-line options.
int ref_levels = 3;
int order = 2;
int method = 0;
const char *inttype = "surface2d";
bool visualization = true;
itype = IntegrationType::Surface2D;
@@ -544,8 +516,6 @@ int main(int argc, char *argv[])
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order", "Order of quadrature rule");
args.AddOption(&ref_levels, "-r", "--refine", "Number of meh refinements");
args.AddOption(&method, "-m", "--method",
"Cut integration method: 0 for moments-based, 1 for Algoim.");
args.AddOption(&inttype, "-i", "--integrationtype",
"IntegrationType to demonstrate");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -580,7 +550,7 @@ int main(int argc, char *argv[])
}
// 2. Construct and refine the mesh.
Mesh *mesh = nullptr;
Mesh *mesh;
if (itype == IntegrationType::Volumetric1D)
{
mesh = new Mesh("../data/inline-segment.mesh");
@@ -628,14 +598,13 @@ int main(int argc, char *argv[])
// 5. Define the necessary Integration rules on element 0.
IsoparametricTransformation Tr;
mesh->GetElementTransformation(0, &Tr);
SIntegrationRule* sir = new SIntegrationRule(method, order,
levelset, 2, mesh);
SIntegrationRule* sir = new SIntegrationRule(order, levelset, 2, mesh);
CIntegrationRule* cir = NULL;
if (itype == IntegrationType::Volumetric1D
|| itype == IntegrationType::Volumetric2D
|| itype == IntegrationType::Volumetric3D)
{
cir = new CIntegrationRule(method, order, levelset, 2, mesh);
cir = new CIntegrationRule(order, levelset, 2, mesh);
}
// 6. Define and assemble the linear forms on the finite element space.
@@ -678,11 +647,11 @@ int main(int argc, char *argv[])
cout << "Number of div free basis functions: " << nbasis << endl;
cout << "Number of quadrature points: " << ir.GetNPoints() << endl;
}
cout << scientific << setprecision(10);
cout << scientific << setprecision(2);
cout << "============================================" << endl;
cout << "Computed value of surface integral: " << surface.Sum() << endl;
cout << "True value of surface integral: " << Surface() << endl;
cout << "Absolute Error (Surface): ";
cout << "Absolute Error (Surface): ";
cout << abs(surface.Sum() - Surface()) << endl;
cout << "Relative Error (Surface): ";
cout << abs(surface.Sum() - Surface()) / Surface() << endl;
@@ -693,7 +662,7 @@ int main(int argc, char *argv[])
cout << "--------------------------------------------" << endl;
cout << "Computed value of volume integral: " << volume.Sum() << endl;
cout << "True value of volume integral: " << Volume() << endl;
cout << "Absolute Error (Volume): ";
cout << "Absolute Error (Volume): ";
cout << abs(volume.Sum() - Volume()) << endl;
cout << "Relative Error (Volume): ";
cout << abs(volume.Sum() - Volume()) / Volume() << endl;
@@ -722,8 +691,5 @@ int main(int argc, char *argv[])
delete fespace;
delete mesh;
return EXIT_SUCCESS;
#else
cout << "MFEM must be built with LAPACK or ALGOIM for this example." << endl;
return MFEM_SKIP_RETURN_VALUE;
#endif // MFEM_USE_LAPACK
#endif //MFEM_USE_LAPACK
}
+30 -3
View File
@@ -9,7 +9,7 @@
// ex9 -m ../data/periodic-square.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/periodic-hexagon.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.002 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.02 -s 23 -tf 9
// ex9 -m ../data/amr-quad.mesh -p 1 -r 2 -dt 0.02 -s 13 -tf 9
// ex9 -m ../data/star-q3.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/star-mixed.mesh -p 1 -r 2 -dt 0.005 -tf 9
// ex9 -m ../data/disc-nurbs.mesh -p 1 -r 3 -dt 0.005 -tf 9
@@ -182,7 +182,12 @@ int main(int argc, char *argv[])
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::Types.c_str());
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
" 11 - Backward Euler,\n\t"
" 12 - SDIRK23 (L-stable), 13 - SDIRK33,\n\t"
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -219,7 +224,28 @@ int main(int argc, char *argv[])
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
// Explicit methods
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
// Implicit (L-stable) methods
case 11: ode_solver = new BackwardEulerSolver; break;
case 12: ode_solver = new SDIRK23Solver(2); break;
case 13: ode_solver = new SDIRK33Solver; break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
@@ -414,6 +440,7 @@ int main(int argc, char *argv[])
}
// 10. Free the used memory.
delete ode_solver;
delete pd;
delete dc;
+33 -3
View File
@@ -9,7 +9,7 @@
// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 1 -dt 0.005 -tf 9
// mpirun -np 4 ex9p -m ../data/periodic-hexagon.mesh -p 1 -dt 0.005 -tf 9
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.002 -tf 9
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 23 -tf 9
// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 13 -tf 9
// mpirun -np 4 ex9p -m ../data/star-q3.mesh -p 1 -rp 1 -dt 0.004 -tf 9
// mpirun -np 4 ex9p -m ../data/star-mixed.mesh -p 1 -rp 1 -dt 0.004 -tf 9
// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 1 -rp 1 -dt 0.005 -tf 9
@@ -285,7 +285,12 @@ int main(int argc, char *argv[])
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
ODESolver::Types.c_str());
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
" 11 - Backward Euler,\n\t"
" 12 - SDIRK23 (L-stable), 13 - SDIRK33,\n\t"
" 22 - Implicit Midpoint Method,\n\t"
" 23 - SDIRK23 (A-stable), 24 - SDIRK34");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -333,7 +338,31 @@ int main(int argc, char *argv[])
// 4. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
// Explicit methods
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
// Implicit (L-stable) methods
case 11: ode_solver = new BackwardEulerSolver; break;
case 12: ode_solver = new SDIRK23Solver(2); break;
case 13: ode_solver = new SDIRK33Solver; break;
// Implicit A-stable methods (not L-stable)
case 22: ode_solver = new ImplicitMidpointSolver; break;
case 23: ode_solver = new SDIRK23Solver; break;
case 24: ode_solver = new SDIRK34Solver; break;
default:
if (Mpi::Root())
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
}
delete mesh;
return 3;
}
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
@@ -613,6 +642,7 @@ int main(int argc, char *argv[])
delete m;
delete fes;
delete pmesh;
delete ode_solver;
delete pd;
#ifdef MFEM_USE_ADIOS2
if (adios2)
-4
View File
@@ -486,11 +486,7 @@ int main(int argc, char *argv[])
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
arkode->Init(*oper);
arkode->SetSStolerances(reltol, abstol);
#if MFEM_SUNDIALS_VERSION < 70100
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#else
ARKodeSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#endif
arkode->SetMaxStep(dt);
if (ode_solver_type == 15)
{
-4
View File
@@ -541,11 +541,7 @@ int main(int argc, char *argv[])
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
arkode->Init(*oper);
arkode->SetSStolerances(reltol, abstol);
#if MFEM_SUNDIALS_VERSION < 70100
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#else
ARKodeSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
#endif
arkode->SetMaxStep(dt);
if (ode_solver_type == 15)
{
+6 -6
View File
@@ -447,7 +447,7 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa), z(height)
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace), z(height)
{
// specify a relative tolerance for all solves with MFEM integrators
const real_t rel_tol = 1e-8;
@@ -522,7 +522,7 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
@@ -544,7 +544,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
}
if (T_solver.GetConverged())
{
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
else
{
@@ -555,7 +555,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
int ConductionOperator::SUNMassSetup()
{
// Do nothing b/c mass solver was setup in constructor.
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
@@ -565,7 +565,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
M_solver.Mult(b, x);
if (M_solver.GetConverged())
{
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
else
{
@@ -577,6 +577,6 @@ int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
+6 -6
View File
@@ -499,7 +499,7 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa),
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace),
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
{
// specify a relative tolerance for all solves with MFEM integrators
@@ -576,7 +576,7 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
@@ -598,7 +598,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
}
if (T_solver.GetConverged())
{
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
else
{
@@ -609,7 +609,7 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
int ConductionOperator::SUNMassSetup()
{
// Do nothing b/c mass solver was setup in constructor.
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
@@ -619,7 +619,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
M_solver.Mult(b, x);
if (M_solver.GetConverged())
{
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
else
{
@@ -631,5 +631,5 @@ int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
return SUN_SUCCESS;
return SUNLS_SUCCESS;
}
-39
View File
@@ -855,34 +855,6 @@ const IntegrationRule &GradientIntegrator::GetRule(const FiniteElement
}
DiffusionIntegrator::DiffusionIntegrator(const IntegrationRule *ir)
: BilinearFormIntegrator(ir),
Q(nullptr), VQ(nullptr), MQ(nullptr), maps(nullptr), geom(nullptr)
{
static Kernels kernels;
}
DiffusionIntegrator::DiffusionIntegrator(Coefficient &q,
const IntegrationRule *ir)
: DiffusionIntegrator(ir)
{
Q = &q;
}
DiffusionIntegrator::DiffusionIntegrator(VectorCoefficient &q,
const IntegrationRule *ir)
: DiffusionIntegrator(ir)
{
VQ = &q;
}
DiffusionIntegrator::DiffusionIntegrator(MatrixCoefficient &q,
const IntegrationRule *ir)
: DiffusionIntegrator(ir)
{
MQ = &q;
}
void DiffusionIntegrator::AssembleElementMatrix
( const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
@@ -1338,17 +1310,6 @@ const IntegrationRule &DiffusionIntegrator::GetRule(
return IntRules.Get(trial_fe.GetGeomType(), order);
}
MassIntegrator::MassIntegrator(const IntegrationRule *ir)
: BilinearFormIntegrator(ir), Q(nullptr), maps(nullptr), geom(nullptr)
{
static Kernels kernels;
}
MassIntegrator::MassIntegrator(Coefficient &q, const IntegrationRule *ir)
: MassIntegrator(ir)
{
Q = &q;
}
void MassIntegrator::AssembleElementMatrix
( const FiniteElement &el, ElementTransformation &Trans,
+25 -44
View File
@@ -2156,7 +2156,7 @@ public:
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
struct Kernels { Kernels(); };
static struct Kernels { Kernels(); } kernels;
protected:
Coefficient *Q;
@@ -2234,16 +2234,26 @@ private:
public:
/// Construct a diffusion integrator with coefficient Q = 1
DiffusionIntegrator(const IntegrationRule *ir = nullptr);
DiffusionIntegrator(const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(NULL), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL) { }
/// Construct a diffusion integrator with a scalar coefficient q
DiffusionIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr);
DiffusionIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(&q), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL) { }
/// Construct a diffusion integrator with a vector coefficient q
DiffusionIntegrator(VectorCoefficient &q, const IntegrationRule *ir = nullptr);
DiffusionIntegrator(VectorCoefficient &q,
const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(NULL), VQ(&q), MQ(NULL), maps(NULL), geom(NULL) { }
/// Construct a diffusion integrator with a matrix coefficient q
DiffusionIntegrator(MatrixCoefficient &q, const IntegrationRule *ir = nullptr);
DiffusionIntegrator(MatrixCoefficient &q,
const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(NULL), VQ(NULL), MQ(&q), maps(NULL), geom(NULL) { }
/** Given a particular Finite Element computes the element stiffness matrix
elmat. */
@@ -2346,13 +2356,15 @@ public:
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
struct Kernels { Kernels(); };
static struct Kernels { Kernels(); } kernels;
public:
MassIntegrator(const IntegrationRule *ir = nullptr);
MassIntegrator(const IntegrationRule *ir = NULL)
: BilinearFormIntegrator(ir), Q(NULL), maps(NULL), geom(NULL) { }
/// Construct a mass integrator with coefficient q
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL);
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL)
: BilinearFormIntegrator(ir), Q(&q), maps(NULL), geom(NULL) { }
/** Given a particular Finite Element computes the element mass matrix
elmat. */
@@ -3710,37 +3722,14 @@ private:
the range space. Otherwise, a dof projection matrix is constructed. */
class IdentityInterpolator : public DiscreteInterpolator
{
protected:
const int vdim;
public:
/** @brief Construct an identity interpolator.
@param[in] vdim_ Vector dimension (number of components) in the domain
and range FE spaces.
*/
IdentityInterpolator(int vdim_ = 1) : vdim(vdim_) { }
IdentityInterpolator(): dofquad_fe(NULL) { }
void AssembleElementMatrix2(const FiniteElement &dom_fe,
const FiniteElement &ran_fe,
ElementTransformation &Trans,
DenseMatrix &elmat) override
{
if (vdim == 1)
{
ran_fe.Project(dom_fe, Trans, elmat);
return;
}
DenseMatrix elmat_block;
ran_fe.Project(dom_fe, Trans, elmat_block);
elmat.SetSize(vdim*elmat_block.Height(), vdim*elmat_block.Width());
elmat = 0_r;
for (int i = 0; i < vdim; i++)
{
elmat.SetSubMatrix(i*elmat_block.Height(), i*elmat_block.Width(),
elmat_block);
}
}
{ ran_fe.Project(dom_fe, Trans, elmat); }
using BilinearFormIntegrator::AssemblePA;
void AssemblePA(const FiniteElementSpace &trial_fes,
@@ -3749,9 +3738,11 @@ public:
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultTransposePA(const Vector &x, Vector &y) const override;
virtual ~IdentityInterpolator() { delete dofquad_fe; }
private:
/// 1D finite element that generates and owns the 1D DofToQuad maps below
std::unique_ptr<FiniteElement> dofquad_fe;
FiniteElement *dofquad_fe;
const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns
const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns
@@ -3761,16 +3752,6 @@ private:
};
/** @brief Class identical to IdentityInterpolator with the exception that it
requires the vector dimension (number of components) to be specified during
construction. */
class VectorIdentityInterpolator : public IdentityInterpolator
{
public:
VectorIdentityInterpolator(int vdim_) : IdentityInterpolator(vdim_) { }
};
/** Class for constructing the (local) discrete curl matrix which can be used
as an integrator in a DiscreteLinearOperator object to assemble the global
discrete curl matrix. */
-18
View File
@@ -798,12 +798,6 @@ public:
/// Sets coefficient in the vector.
void Set(int i, Coefficient *c, bool own=true);
/// Set ownership of the i'th coefficient
void SetOwnership(int i, bool own) { ownCoeff[i] = own; }
/// Get ownership of the i'th coefficient
bool GetOwnership(int i) const { return ownCoeff[i]; }
/// Evaluates i'th component of the vector of coefficients and returns the
/// value.
real_t Eval(int i, ElementTransformation &T, const IntegrationPoint &ip)
@@ -1326,12 +1320,6 @@ public:
can be overridden with the @a own parameter. */
void Set(int i, int j, Coefficient * c, bool own=true);
/// Set ownership of the coefficient at (i,j) in the matrix
void SetOwnership(int i, int j, bool own) { ownCoeff[i*width+j] = own; }
/// Get ownership of the coefficient at (i,j) in the matrix
bool GetOwnership(int i, int j) const { return ownCoeff[i*width+j]; }
using MatrixCoefficient::Eval;
/// Evaluate coefficient located at (i,j) in the matrix using integration
@@ -1372,12 +1360,6 @@ public:
can be overridden with the @a own parameter. */
void Set(int i, VectorCoefficient * c, bool own=true);
/// Set ownership of the i'th coefficient
void SetOwnership(int i, bool own) { ownCoeff[i] = own; }
/// Get ownership of the i'th coefficient
bool GetOwnership(int i) const { return ownCoeff[i]; }
using MatrixCoefficient::Eval;
/// Evaluate coefficient located at the i-th row of the matrix using integration
+1 -1
View File
@@ -1245,7 +1245,7 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
hypre_ParCSRMatrix *Aih = *Ah;
Ah->HypreReadWrite();
const int *d_ess_tdof_list =
ess_tdof_list.GetMemory().Read(GetHypreForallMemoryClass(), n);
ess_tdof_list.GetMemory().Read(GetHypreMemoryClass(), n);
HYPRE_Int *d_diag_i = Aih->diag->i;
real_t *d_diag_data = Aih->diag->data;
mfem::hypre_forall(n, [=] MFEM_HOST_DEVICE (int k)
+2 -1
View File
@@ -997,7 +997,8 @@ std::string
ConduitDataCollection::MeshFilePattern(const std::string &relay_protocol)
{
std::ostringstream oss;
oss << name
oss << prefix_path
<< name
<< "_"
<< to_padded_string(cycle, pad_digits_cycle)
<< "/domain_%0"
+2 -2
View File
@@ -41,8 +41,8 @@ void FillFaceMap(const int n_face_dofs_per_component,
const std::vector<int> &n_dofs_per_dim,
Array<int> &face_map)
{
const int n_components = static_cast<int>(offsets.size());
const int face_dim = static_cast<int>(strides.size()) / n_components;
const int n_components = offsets.size();
const int face_dim = strides.size() / n_components;
for (int comp = 0; comp < n_components; ++comp)
{
const int offset = offsets[comp];
-37
View File
@@ -146,43 +146,6 @@ void FiniteElementSpace::CopyProlongationAndRestriction(
delete perm_mat_tr;
}
void FiniteElementSpace::SetProlongation(const SparseMatrix& p)
{
#ifdef MFEM_USE_MPI
MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
"Attempting to set serial prolongation operator for "
"parallel finite element space.");
#endif
if (!cP)
{
cP = std::unique_ptr<SparseMatrix>(new SparseMatrix(p));
}
else
{
*cP = p;
}
cP_is_set = true;
}
void FiniteElementSpace::SetRestriction(const SparseMatrix& r)
{
#ifdef MFEM_USE_MPI
MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
"Attempting to set serial restriction operator for "
"parallel finite element space.");
#endif
if (!cR)
{
cR = std::unique_ptr<SparseMatrix>(new SparseMatrix(r));
}
else
{
*cR = r;
}
}
void FiniteElementSpace::SetElementOrder(int i, int p)
{
MFEM_VERIFY(mesh_sequence == mesh->GetSequence(),
-8
View File
@@ -587,14 +587,6 @@ public:
bool Conforming() const { return mesh->Conforming() && cP == NULL; }
bool Nonconforming() const { return mesh->Nonconforming() || cP != NULL; }
/** Set the prolongation operator of the space to an arbitrary sparse matrix,
creating a copy of the argument. */
void SetProlongation(const SparseMatrix& p);
/** Set the restriction operator of the space to an arbitrary sparse matrix,
creating a copy of the argument. */
void SetRestriction(const SparseMatrix& r);
/// Sets the order of the i'th finite element.
/** By default, all elements are assumed to be of fec->GetOrder(). Once
SetElementOrder is called, the space becomes a variable order space. */
+6 -8
View File
@@ -37,7 +37,7 @@ FindPointsGSLIB::FindPointsGSLIB()
: mesh(NULL),
fec_map_lin(NULL),
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
{
mesh_split.SetSize(4);
@@ -55,7 +55,7 @@ FindPointsGSLIB::FindPointsGSLIB()
gsl_comm = new gslib::comm;
cr = new gslib::crystal;
#ifdef MFEM_USE_MPI
int initialized = 0;
int initialized;
MPI_Initialized(&initialized);
if (!initialized) { MPI_Init(NULL, NULL); }
MPI_Comm comm = MPI_COMM_WORLD;
@@ -85,7 +85,7 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
: mesh(NULL),
fec_map_lin(NULL),
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
{
mesh_split.SetSize(4);
@@ -307,7 +307,6 @@ void FindPointsGSLIB::FreeData()
}
if (fec_map_lin) { delete fec_map_lin; fec_map_lin = NULL; }
setupflag = false;
points_cnt = -1;
}
void FindPointsGSLIB::SetupSplitMeshes()
@@ -898,8 +897,7 @@ void FindPointsGSLIB::Interpolate(const GridFunction &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,
field_in.FESpace()->GetOrdering());
FiniteElementSpace fes(mesh, &fec, ncomp);
GridFunction field_in_h1(&fes);
if (avgtype == AvgType::ARITHMETIC)
@@ -929,7 +927,7 @@ void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
{
for (int i = 0; i < indl2.Size(); i++)
{
int idx = field_in_h1.FESpace()->GetOrdering() == Ordering::byNODES?
int idx = field_in.FESpace()->GetOrdering() == Ordering::byNODES ?
indl2[i] + j*points_cnt:
indl2[i]*ncomp + j;
field_out(idx) = field_out_l2(idx);
@@ -1174,7 +1172,7 @@ void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
Array<unsigned int> &recv_elem, Vector &recv_ref,
Array<unsigned int> &recv_code)
{
MFEM_VERIFY(points_cnt >= 0,
MFEM_VERIFY(points_cnt,
"Invalid size. Please make sure to call FindPoints method "
"before calling this function.");
@@ -16,6 +16,7 @@ namespace mfem
// PA Diffusion Integrator
DiffusionIntegrator::Kernels DiffusionIntegrator::kernels;
DiffusionIntegrator::Kernels::Kernels()
{
// 2D
+5 -5
View File
@@ -1039,7 +1039,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
for (int zquad = 0; zquad<2; ++zquad)
{
// Reduced quadrature in z
const int nwz = static_cast<int>(rid(zquad,2,patch)[jdz].size());
const int nwz = rid(zquad,2,patch)[jdz].size();
for (int irz=0; irz < nwz; ++irz)
{
const int qz = rid(zquad,2,patch)[jdz][irz] + minD[2][jdz];
@@ -1062,7 +1062,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
for (int yquad = 0; yquad<2; ++yquad)
{
// Reduced quadrature in y
const int nwy = static_cast<int>(rid(yquad,1,patch)[jdy].size());
const int nwy = rid(yquad,1,patch)[jdy].size();
for (int iry=0; iry < nwy; ++iry)
{
const int qy = rid(yquad,1,patch)[jdy][iry] + minD[1][jdy];
@@ -1082,7 +1082,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
// Reduced quadrature in x
for (int xquad=0; xquad<2; ++xquad)
{
const int nwx = static_cast<int>(rid(xquad,0,patch)[jdx].size());
const int nwx = rid(xquad,0,patch)[jdx].size();
for (int irx=0; irx < nwx; ++irx)
{
const int qx = rid(xquad,0,patch)[jdx][irx] + minD[0][jdx];
@@ -1117,7 +1117,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
}
// 00 terms
const int nw = static_cast<int>(rid(0,0,patch)[jdx].size());
const int nw = rid(0,0,patch)[jdx].size();
for (int irx=0; irx < nw; ++irx)
{
const int qx = rid(0,0,patch)[jdx][irx] + minD[0][jdx];
@@ -1140,7 +1140,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
}
// 11 terms
const int nw11 = static_cast<int>(rid(1,0,patch)[jdx].size());
const int nw11 = rid(1,0,patch)[jdx].size();
for (int irx=0; irx < nw11; ++irx)
{
+1 -3
View File
@@ -1819,12 +1819,10 @@ void IdentityInterpolator::AssemblePA(const FiniteElementSpace &trial_fes,
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
MFEM_VERIFY(vdim == 1, "vdim != 1 with PA is not supported yet!");
ne = trial_fes.GetNE();
const int order = trial_el->GetOrder();
dofquad_fe.reset(new H1_SegmentElement(order));
dofquad_fe = new H1_SegmentElement(order);
mfem::QuadratureFunctions1D qf1d;
mfem::IntegrationRule closed_ir;
closed_ir.SetSize(order + 1);
+1
View File
@@ -14,6 +14,7 @@
namespace mfem
{
MassIntegrator::Kernels MassIntegrator::kernels;
MassIntegrator::Kernels::Kernels()
{
// 2D
+1 -1
View File
@@ -1908,7 +1908,7 @@ IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
}
}
npd[d] = static_cast<int>(el[d].size() / 2);
npd[d] = el[d].size() / 2;
np *= npd[d];
}
+12 -230
View File
@@ -31,172 +31,6 @@ void CutIntegrationRules::SetLevelSetProjectionOrder(int order)
lsOrder = order;
}
#ifdef MFEM_USE_ALGOIM
void AlgoimIntegrationRules::GetSurfaceIntegrationRule(ElementTransformation
&Tr,
IntegrationRule &result)
{
GenerateLSVector(Tr,LvlSet);
const int dim=pe->GetDim();
int np1d=CutIntegrationRules::Order/2+1;
if (dim==2)
{
LevelSet2D ls(pe,lsvec);
auto q = Algoim::quadGen<2>(ls,Algoim::BoundingBox<real_t,2>(0.0,1.0),
2, -1, np1d);
result.SetSize(q.nodes.size());
result.SetOrder(CutIntegrationRules::Order);
for (size_t i=0; i<q.nodes.size(); i++)
{
IntegrationPoint& ip=result.IntPoint(i);
ip.Set2w(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].w);
}
}
else
{
LevelSet3D ls(pe,lsvec);
auto q = Algoim::quadGen<3>(ls,Algoim::BoundingBox<real_t,3>(0.0,1.0),
3, -1, np1d);
result.SetSize(q.nodes.size());
result.SetOrder(CutIntegrationRules::Order);
for (size_t i=0; i<q.nodes.size(); i++)
{
IntegrationPoint& ip=result.IntPoint(i);
ip.Set(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].x(2),q.nodes[i].w);
}
}
}
void AlgoimIntegrationRules::GetVolumeIntegrationRule(ElementTransformation &Tr,
IntegrationRule &result,
const IntegrationRule *sir)
{
GenerateLSVector(Tr,LvlSet);
const int dim=pe->GetDim();
int np1d=CutIntegrationRules::Order/2+1;
if (dim==2)
{
LevelSet2D ls(pe,lsvec);
auto q = Algoim::quadGen<2>(ls,Algoim::BoundingBox<real_t,2>(0.0,1.0),
-1, -1, np1d);
result.SetSize(q.nodes.size());
result.SetOrder(CutIntegrationRules::Order);
for (size_t i=0; i<q.nodes.size(); i++)
{
IntegrationPoint& ip=result.IntPoint(i);
ip.Set2w(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].w);
}
}
else
{
LevelSet3D ls(pe,lsvec);
auto q = Algoim::quadGen<3>(ls,Algoim::BoundingBox<real_t,3>(0.0,1.0),
-1, -1, np1d);
result.SetSize(q.nodes.size());
result.SetOrder(CutIntegrationRules::Order);
for (size_t i=0; i<q.nodes.size(); i++)
{
IntegrationPoint& ip=result.IntPoint(i);
ip.Set(q.nodes[i].x(0),q.nodes[i].x(1),q.nodes[i].x(2),q.nodes[i].w);
}
}
}
void AlgoimIntegrationRules::GetSurfaceWeights(ElementTransformation &Tr,
const IntegrationRule &sir,
Vector &weights)
{
GenerateLSVector(Tr,LvlSet);
DenseMatrix bmat; // gradients of the shape functions in isoparametric space
DenseMatrix pmat; // gradients of the shape functions in physical space
Vector inormal; // normal to the level set in isoparametric space
Vector tnormal; // normal to the level set in physical space
bmat.SetSize(pe->GetDof(),pe->GetDim());
pmat.SetSize(pe->GetDof(),pe->GetDim());
inormal.SetSize(pe->GetDim());
tnormal.SetSize(pe->GetDim());
weights.SetSize(sir.GetNPoints());
for (int j = 0; j < sir.GetNPoints(); j++)
{
const IntegrationPoint &ip = sir.IntPoint(j);
Tr.SetIntPoint(&ip);
pe->CalcDShape(ip,bmat);
Mult(bmat, Tr.InverseJacobian(), pmat);
// compute the normal to the LS in isoparametric space
bmat.MultTranspose(lsvec,inormal);
// compute the normal to the LS in physical space
pmat.MultTranspose(lsvec,tnormal);
weights[j]= tnormal.Norml2() / inormal.Norml2();
}
}
void AlgoimIntegrationRules::GenerateLSVector(ElementTransformation &Tr,
Coefficient* lvlset)
{
//check if the coefficient is already projected
if (currentElementNo==Tr.ElementNo)
{
if (currentLvlSet==lvlset)
{
if (currentGeometry==Tr.GetGeometryType())
{
return;
}
}
}
currentElementNo=Tr.ElementNo;
if (currentGeometry!=Tr.GetGeometryType())
{
delete le;
delete pe;
currentGeometry=Tr.GetGeometryType();
if (Tr.GetGeometryType()==Geometry::Type::SQUARE)
{
pe=new H1Pos_QuadrilateralElement(lsOrder);
le=new H1_QuadrilateralElement(lsOrder);
}
else if (Tr.GetGeometryType()==Geometry::Type::CUBE)
{
pe=new H1Pos_HexahedronElement(lsOrder);
le=new H1_HexahedronElement(lsOrder);
}
else
{
MFEM_ABORT("Currently MFEM + Algoim supports only quads and hexes.");
}
T.SetSize(pe->GetDof());
pe->Project(*le,Tr,T);
//The transformation matrix depends only on the geometry for change of basis
}
currentLvlSet=lvlset;
const IntegrationRule &ir=le->GetNodes();
lsvec.SetSize(ir.GetNPoints());
lsfun.SetSize(ir.GetNPoints());
for (int i=0; i<ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
lsfun(i)=lvlset->Eval(Tr,ip);
}
T.Mult(lsfun,lsvec);
}
#endif
#ifdef MFEM_USE_LAPACK
void MomentFittingIntRules::InitSurface(int order, Coefficient& levelset,
@@ -341,7 +175,6 @@ void MomentFittingIntRules::ComputeFaceWeights(ElementTransformation& Tr)
local_mesh.GetElementTransformation(0, &faceTrafo);
// The 3D face integrals are computed as 2D volumetric integrals.
// The 2D face integrals are computed as 1D volumetric integrals.
MomentFittingIntRules FaceRules(Order, *LvlSet, lsOrder);
IntegrationRule FaceRule;
FaceRules.GetVolumeIntegrationRule(faceTrafo, FaceRule);
@@ -421,56 +254,8 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
}
}
double bisect(ElementTransformation &Tr, Coefficient *LvlSet)
{
IntegrationPoint intp;
IntegrationPoint ip0;
ip0.x = 0.;
IntegrationPoint ip1;
ip1.x = 1.;
Tr.SetIntPoint(&ip0);
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip1) < 0.)
{
IntegrationPoint ip2;
ip2.x = .5;
while (LvlSet->Eval(Tr, ip2) > 1e-12
|| LvlSet->Eval(Tr, ip2) < -1e-12)
{
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip2) < 0.)
{
ip1.x = ip2.x;
}
else
{
ip0.x = ip2.x;
}
ip2.x = (ip1.x + ip0.x) / 2.;
}
intp.x = ip2.x;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= 1e-12)
{
intp.x = 1.;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= 1e-12)
{
intp.x = 0.;
intp.weight = 1. / Tr.Weight();
}
else
{
intp.x = .5;
intp.weight = 0.;
}
return intp.x;
}
void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr)
void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
const IntegrationRule* sir)
{
IntegrationRules irs(0, Quadrature1D::GaussLegendre);
IntegrationRule ir2 = irs.Get(Geometry::SEGMENT, ir.GetOrder());
@@ -486,7 +271,7 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr)
real_t length;
if (LvlSet->Eval(Tr, ip0) > 0.)
{
length = bisect(Tr, LvlSet);
length = sir->IntPoint(0).x;
for (int ip = 0; ip < ir.GetNPoints(); ip++)
{
IntegrationPoint &intp = ir.IntPoint(ip);
@@ -496,11 +281,11 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr)
}
else
{
length = 1. - bisect(Tr, LvlSet);
length = 1. - sir->IntPoint(0).x;
for (int ip = 0; ip < ir.GetNPoints(); ip++)
{
IntegrationPoint &intp = ir.IntPoint(ip);
intp.x = bisect(Tr, LvlSet) + ir2.IntPoint(ip).x * length;
intp.x = sir->IntPoint(ip).x + ir2.IntPoint(ip).x * length;
intp.weight = ir2.IntPoint(ip).weight * length;
}
}
@@ -1706,29 +1491,26 @@ void MomentFittingIntRules::GetVolumeIntegrationRule(ElementTransformation& Tr,
}
IntegrationRule SIR;
if (Tr.GetDimension() == 1)
{
Clear();
InitVolume(Order, *LvlSet, lsOrder, Tr);
}
else if (sir == NULL)
if (sir == NULL)
{
Order++;
GetSurfaceIntegrationRule(Tr, SIR);
Order--;
}
else if (sir->GetOrder() - 1 != ir.GetOrder())
else if ((sir->GetOrder() - 1) != ir.GetOrder())
{
Order++;
GetSurfaceIntegrationRule(Tr, SIR);
Order--;
}
else { SIR = *sir; }
else
{
SIR = *sir;
}
if (Tr.GetDimension() == 1)
{
ComputeVolumeWeights1D(Tr);
ComputeVolumeWeights1D(Tr, &SIR);
}
else if (Tr.GetDimension() == 2)
{
+3 -354
View File
@@ -18,16 +18,6 @@
#include "eltrans.hpp"
#include "coefficient.hpp"
#ifdef MFEM_USE_ALGOIM
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <algoim_quad.hpp>
#pragma GCC diagnostic pop
#endif
namespace mfem
{
/**
@@ -126,349 +116,6 @@ public:
virtual ~CutIntegrationRules() {}
};
#ifdef MFEM_USE_ALGOIM
// define templated element bases
namespace TmplPoly_1D
{
/// Templated version of CalcBinomTerms
template<typename float_type>
void CalcBinomTerms(const int p, const float_type x, const float_type y,
float_type* u)
{
if (p == 0)
{
u[0] = float_type(1.);
}
else
{
int i;
const int *b = Poly_1D::Binom(p);
float_type z = x;
for (i = 1; i < p; i++)
{
u[i] = b[i]*z;
z *= x;
}
u[p] = z;
z = y;
for (i--; i > 0; i--)
{
u[i] *= z;
z *= y;
}
u[0] = z;
}
}
/// Templated version of CalcBinomTerms
template<typename float_type>
void CalcBinomTerms(const int p, const float_type x, const float_type y,
float_type* u, float_type* d)
{
if (p == 0)
{
u[0] = float_type(1.);
d[0] = float_type(0.);
}
else
{
int i;
const int *b = Poly_1D::Binom(p);
const float_type xpy = x + y, ptx = p*x;
float_type z = float_type(1.);
for (i = 1; i < p; i++)
{
d[i] = b[i]*z*(i*xpy - ptx);
z *= x;
u[i] = b[i]*z;
}
d[p] = p*z;
u[p] = z*x;
z = float_type(1.);
for (i--; i > 0; i--)
{
d[i] *= z;
z *= y;
u[i] *= z;
}
d[0] = -p*z;
u[0] = z*y;
}
}
/// Templated evaluation of Bernstein basis
template <typename float_type>
void CalcBernstein(const int p, const float_type x, float_type *u)
{
CalcBinomTerms(p, x, 1. - x, u);
}
/// Templated evaluation of Bernstein basis
template <typename float_type>
void CalcBernstein(const int p, const float_type x,
float_type *u, float_type *d)
{
CalcBinomTerms(p, x, 1. - x, u, d);
}
}
class AlgoimIntegrationRules : public CutIntegrationRules
{
public:
/** @brief Constructor to set up the generated cut IntegrationRules.
@param [in] order Order of the constructed IntegrationRule.
@param [in] lvlset Coefficient whose zero level set specifies the cut.
@param [in] lsO Polynomial degree for projecting the level-set
Coefficient to a GridFunction, which is used to
compute gradients and normals. */
AlgoimIntegrationRules(int order, Coefficient &lvlset, int lsO = 2)
: CutIntegrationRules(order, lvlset, lsO)
{
pe=nullptr;
le=nullptr;
currentLvlSet=nullptr;
currentGeometry=Geometry::Type::INVALID;
currentElementNo = -1;
}
virtual ~AlgoimIntegrationRules()
{
delete pe;
delete le;
}
virtual void SetOrder(int order) override
{
MFEM_VERIFY(order > 0, "Invalid input");
Order = order;
delete pe;
delete le;
pe=nullptr;
le=nullptr;
currentLvlSet=nullptr;
currentGeometry=Geometry::Type::INVALID;
currentElementNo=-1;
}
virtual void SetLevelSetProjectionOrder(int order) override
{
MFEM_VERIFY(order > 0, "Invalid input");
lsOrder = order;
delete pe;
delete le;
pe=nullptr;
le=nullptr;
currentLvlSet=nullptr;
currentGeometry=Geometry::Type::INVALID;
currentElementNo=-1;
}
/**
@brief Construct a cut-surface IntegrationRule.
Construct an IntegrationRule to integrate on the surface given by the
already specified level set function, for the element given by @a Tr.
@param [in] Tr Specifies the IntegrationRule's associated mesh element.
@param [out] result IntegrationRule on the cut-surface
*/
virtual
void GetSurfaceIntegrationRule(ElementTransformation &Tr,
IntegrationRule &result) override;
/**
@brief Construct a cut-volume IntegrationRule.
Construct an IntegrationRule to integrate in the subdomain given by the
positive values of the already specified level set function, for the element
given by @a Tr.
@param [in] Tr Specifies the IntegrationRule's associated mesh element.
@param [out] result IntegrationRule for the cut-volume
@param [in] sir Corresponding IntegrationRule for the surface, which can
be used to avoid computations.
*/
virtual
void GetVolumeIntegrationRule(ElementTransformation &Tr,
IntegrationRule &result,
const IntegrationRule *sir = nullptr) override;
/**
@brief Compute transformation quadrature weights for surface integration.
Compute the transformation weights for integration over the cut-surface in
reference space.
@param [in] Tr Specifies the IntegrationRule's associated element.
@param [in] sir IntegrationRule defining the IntegrationPoints
@param [out] weights Vector containing the transformation weights.
*/
virtual
void GetSurfaceWeights(ElementTransformation &Tr,
const IntegrationRule &sir,
Vector &weights) override;
private:
/// projects the lvlset coefficient onto the lsvec,
/// i.e., represent the level-set using Bernstein bases
void GenerateLSVector(ElementTransformation &Tr, Coefficient* lvlset);
/// Lagrange finite element used for converting coefficients to positive basis
FiniteElement* le;
PositiveTensorFiniteElement *pe;
DenseMatrix T; //Projection matrix from nodal basis to positive basis
Vector lsvec; // level-set in Bernstein basis
Vector lsfun; // level-set in nodal basis
Geometry::Type currentGeometry; // the current element geometry
Coefficient* currentLvlSet; //the current level-set coefficient
int currentElementNo; //the current element No
/// 3D level-set function object required by Algoim.
struct LevelSet3D
{
/// Constructor for 3D level-set function object required by Algoim.
LevelSet3D(PositiveTensorFiniteElement* el_, Vector& lsfun_)
: el(el_), lsfun(lsfun_) { }
/// Returns the value of the LSF for point x.
template<typename T>
T operator() (const blitz::TinyVector<T,3>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
T u3[el_order+1];
TmplPoly_1D::CalcBernstein(el_order, x[0], u1);
TmplPoly_1D::CalcBernstein(el_order, x[1], u2);
TmplPoly_1D::CalcBernstein(el_order, x[2], u3);
const Array<int>& dof_map=el->GetDofMap();
T res=T(0.0);
for (int oo = 0, kk = 0; kk <= el_order; kk++)
for (int jj = 0; jj <= el_order; jj++)
for (int ii = 0; ii <= el_order; ii++)
{
res=res-u1[ii]*u2[jj]*u3[kk]*lsfun(dof_map[oo++]);
}
return res;
}
/// Returns the gradients of the LSF for point x.
template<typename T>
blitz::TinyVector<T,3> grad(const blitz::TinyVector<T,3>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
T u3[el_order+1];
T d1[el_order+1];
T d2[el_order+1];
T d3[el_order+1];
TmplPoly_1D::CalcBernstein(el_order,x[0], u1, d1);
TmplPoly_1D::CalcBernstein(el_order,x[1], u2, d2);
TmplPoly_1D::CalcBernstein(el_order,x[2], u3, d3);
blitz::TinyVector<T,3> res(T(0.0),T(0.0),T(0.0));
const Array<int>& dof_map=el->GetDofMap();
for (int oo = 0, kk = 0; kk <= el_order; kk++)
for (int jj = 0; jj <= el_order; jj++)
for (int ii = 0; ii <= el_order; ii++)
{
res[0]=res[0]-d1[ii]*u2[jj]*u3[kk]*lsfun(dof_map[oo]);
res[1]=res[1]-u1[ii]*d2[jj]*u3[kk]*lsfun(dof_map[oo]);
res[2]=res[2]-u1[ii]*u2[jj]*d3[kk]*lsfun(dof_map[oo]);
oo++;
}
return res;
}
private:
PositiveTensorFiniteElement* el;
Vector& lsfun;
};
/// 2D level-set function object required by Algoim.
struct LevelSet2D
{
/// Constructor for 2D level-set function object required by Algoim.
LevelSet2D(PositiveTensorFiniteElement* el_, Vector& lsfun_)
:el(el_), lsfun(lsfun_) { }
/// Returns the value of the LSF for point x.
template<typename T>
T operator() (const blitz::TinyVector<T,2>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
TmplPoly_1D::CalcBernstein(el_order, x[0], u1);
TmplPoly_1D::CalcBernstein(el_order, x[1], u2);
const Array<int>& dof_map=el->GetDofMap();
T res=T(0.0);
for (int oo = 0, jj = 0; jj <= el_order; jj++)
for (int ii = 0; ii <= el_order; ii++)
{
res=res-u1[ii]*u2[jj]*lsfun(dof_map[oo++]);
}
return res;
}
/// Returns the gradients of the LSF for point x.
template<typename T>
blitz::TinyVector<T,2> grad(const blitz::TinyVector<T,2>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
T d1[el_order+1];
T d2[el_order+1];
TmplPoly_1D::CalcBernstein(el_order,x[0], u1, d1);
TmplPoly_1D::CalcBernstein(el_order,x[1], u2, d2);
blitz::TinyVector<T,2> res(T(0.0),T(0.0));
const Array<int>& dof_map=el->GetDofMap();
for (int oo = 0, jj = 0; jj <= el_order; jj++)
for (int ii = 0; ii <= el_order; ii++)
{
res[0]=res[0]-(d1[ii]*u2[jj])*lsfun(dof_map[oo]);
res[1]=res[1]-(u1[ii]*d2[jj])*lsfun(dof_map[oo]);
oo++;
}
return res;
}
private:
PositiveTensorFiniteElement* el;
Vector& lsfun;
};
};
#endif //MFEM_USE_ALGOIM
#ifdef MFEM_USE_LAPACK
/**
@@ -565,8 +212,10 @@ protected:
rule.
@param [in] Tr ElementTransformation of the current element
@param [in] sir corresponding IntegrationRule on surface
*/
void ComputeVolumeWeights1D(ElementTransformation& Tr);
void ComputeVolumeWeights1D(ElementTransformation& Tr,
const IntegrationRule* sir);
/**
@brief Compute 2D quadrature weights
+7 -13
View File
@@ -78,9 +78,9 @@ namespace mfem
const char *kernel_name = MFEM_KERNEL_NAME(KernelName); \
using KernelSignature = KernelType; \
template <MFEM_PARAM_LIST P3> \
static MFEM_EXPORT KernelSignature Kernel(); \
static MFEM_EXPORT KernelSignature Fallback(MFEM_PARAM_LIST P1); \
static MFEM_EXPORT KernelName &Get() \
static KernelSignature Kernel(); \
static KernelSignature Fallback(MFEM_PARAM_LIST P1); \
static KernelName &Get() \
{ static KernelName table; return table;} \
}
@@ -126,9 +126,9 @@ class KernelDispatchTable<Kernels,
internal::KernelTypeList<Params...>,
internal::KernelTypeList<OptParams...>>
{
using TableType = std::unordered_map<std::tuple<Params...>,
Signature, KernelDispatchKeyHash<Params...>>;
TableType table;
std::unordered_map<std::tuple<Params...>,
Signature,
KernelDispatchKeyHash<Params...>> table;
public:
/// @brief Run the kernel with the given dispatch parameters and arguments.
@@ -162,7 +162,7 @@ public:
{
std::tuple<Params...> param_tuple(PARAMS...);
Kernels::Get().table[param_tuple] =
Kernels:: template Kernel<PARAMS..., OptParams{}...>();
Kernels:: template Kernel<PARAMS...>();
};
// Version with optional parameters
template <OptParams... OPT_PARAMS>
@@ -176,12 +176,6 @@ public:
}
};
};
/// Return the dispatch map table
static const TableType &GetDispatchTable()
{
return Kernels::Get().table;
}
};
}
+1 -1
View File
@@ -676,7 +676,7 @@ public:
int myid;
MPI_Comm_rank(comm, &myid);
int seed = (seed_ > 0) ? seed_ + myid : (int)time(0) + myid;
int seed = (seed_ > 0) ? seed_ + myid : time(0) + myid;
SetSeed(seed);
}
#else
+13 -7
View File
@@ -242,13 +242,13 @@ void BatchedLOR_AMS::FormGradientMatrix()
template <typename T>
static inline const T *HypreRead(const Memory<T> &mem)
{
return mem.Read(GetHypreForallMemoryClass(), mem.Capacity());
return mem.Read(GetHypreMemoryClass(), mem.Capacity());
}
template <typename T>
static inline T *HypreWrite(Memory<T> &mem)
{
return mem.Write(GetHypreForallMemoryClass(), mem.Capacity());
return mem.Write(GetHypreMemoryClass(), mem.Capacity());
}
void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
@@ -278,7 +278,10 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
const int sdim = vert_fes.GetMesh()->SpaceDimension();
const int ntdofs = R->Height();
xyz_tvec = new Vector(ntdofs*sdim, GetHypreMemoryType());
const MemoryClass mc = GetHypreMemoryClass();
bool dev = (mc == MemoryClass::DEVICE);
xyz_tvec = new Vector(ntdofs*sdim);
auto xyz_tv = Reshape(HypreWrite(xyz_tvec->GetMemory()), ntdofs, sdim);
const auto xyz_e =
@@ -301,12 +304,15 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
// Make x, y, z HypreParVectors point to T-vector data
HYPRE_BigInt glob_size = vert_fes.GlobalTrueVSize();
HYPRE_BigInt *cols = vert_fes.GetTrueDofOffsets();
MPI_Comm comm = vert_fes.GetComm();
x = new HypreParVector(comm, glob_size, *xyz_tvec, 0*ntdofs, cols);
y = new HypreParVector(comm, glob_size, *xyz_tvec, 1*ntdofs, cols);
real_t *d_x_ptr = xyz_tv + 0*ntdofs;
x = new HypreParVector(vert_fes.GetComm(), glob_size, d_x_ptr, cols, dev);
real_t *d_y_ptr = xyz_tv + 1*ntdofs;
y = new HypreParVector(vert_fes.GetComm(), glob_size, d_y_ptr, cols, dev);
if (sdim == 3)
{
z = new HypreParVector(comm, glob_size, *xyz_tvec, 2*ntdofs, cols);
real_t *d_z_ptr = xyz_tv + 2*ntdofs;
z = new HypreParVector(vert_fes.GetComm(), glob_size, d_z_ptr, cols, dev);
}
else
{
+1 -1
View File
@@ -16,7 +16,7 @@
#include "bilinearform.hpp"
#include "../linalg/operator.hpp"
#include "../linalg/op_handle.hpp"
#include "../linalg/handle.hpp"
namespace mfem
{
+7 -7
View File
@@ -1984,7 +1984,7 @@ struct PMatrixRow
void write(std::ostream &os, real_t sign) const
{
bin_io::write<int>(os, static_cast<int>(elems.size()));
bin_io::write<int>(os, elems.size());
for (unsigned i = 0; i < elems.size(); i++)
{
const PMatrixElement &e = elems[i];
@@ -2074,7 +2074,7 @@ void NeighborRowMessage::Encode(int rank)
}
Array<GroupId> all_group_ids;
all_group_ids.Reserve(static_cast<int>(rows.size()));
all_group_ids.Reserve(rows.size());
for (int i = 0; i < 3; i++)
{
all_group_ids.Append(group_ids[i]);
@@ -2833,7 +2833,7 @@ HypreParMatrix* ParFiniteElementSpace
}
// create offd column mapping
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(static_cast<int>(col_map.size()));
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(col_map.size());
int offd_col = 0;
for (auto it = col_map.begin(); it != col_map.end(); ++it)
{
@@ -2893,7 +2893,7 @@ HypreParMatrix* ParFiniteElementSpace
row_starts.GetData(), col_starts.GetData(),
I_diag, J_diag, A_diag,
I_offd, J_offd, A_offd,
static_cast<HYPRE_Int>(col_map.size()), cmap);
col_map.size(), cmap);
}
template <typename int_type>
@@ -3119,7 +3119,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
msg.dofs[i] = old_offset + dofs[i];
}
MPI_Isend(&msg.dofs[0], static_cast<int>(msg.dofs.size()), HYPRE_MPI_BIG_INT,
MPI_Isend(&msg.dofs[0], msg.dofs.size(), HYPRE_MPI_BIG_INT,
coarse_rank, 291, MyComm, &msg.request);
}
else if (coarse_rank == MyRank && fine_rank != MyRank)
@@ -3240,7 +3240,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
{
if (row[j] == 0.0) { continue; } // NOTE: lR thresholded
int &lcol = col_map[remote_dofs[j]];
if (!lcol) { lcol = static_cast<int>(col_map.size()); }
if (!lcol) { lcol = col_map.size(); }
offd->_Set_(m, lcol-1, row[j]);
}
mark[m] = 1;
@@ -3252,7 +3252,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
messages.clear();
offd->Finalize(0);
offd->SetWidth(static_cast<int>(col_map.size()));
offd->SetWidth(col_map.size());
// create offd column mapping for use by hypre
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(offd->Width());
+26 -33
View File
@@ -982,65 +982,70 @@ void ParGridFunction::SaveAsSerial(const char *fname, int precision,
MPI_Barrier(pmesh->GetComm());
}
GridFunction ParGridFunction::GetSerialGridFunction(
int save_rank, FiniteElementSpace &serial_fes) const
GridFunction ParGridFunction::GetSerialGridFunction(int save_rank,
Mesh &serial_mesh) const
{
ParFiniteElementSpace *pfespace = ParFESpace();
ParMesh *pmesh = pfespace->GetParMesh();
GridFunction serial_gf(&serial_fes);
int vdim = pfespace->GetVDim();
auto *fec_serial = FiniteElementCollection::New(pfespace->FEColl()->Name());
auto *fespace_serial = new FiniteElementSpace(&serial_mesh,
fec_serial,
vdim,
pfespace->GetOrdering());
GridFunction gf_serial(fespace_serial);
gf_serial.MakeOwner(fec_serial);
Array<real_t> vals;
Array<int> dofs;
MPI_Status status;
int n_send_recv;
const int vdim = pfespace->GetVDim();
int my_rank = pmesh->GetMyRank(),
nranks = pmesh->GetNRanks();
MPI_Comm my_comm = pmesh->GetComm();
const int my_rank = pmesh->GetMyRank();
const int nranks = pmesh->GetNRanks();
MPI_Comm comm = pmesh->GetComm();
int elem_count = 0; // To keep track of element count in serial mesh
if (my_rank == save_rank)
{
int elem_count = 0; // To keep track of element count in serial mesh
Vector nodeval;
for (int e = 0; e < pmesh->GetNE(); e++)
{
GetElementDofValues(e, nodeval);
serial_fes.GetElementVDofs(elem_count++, dofs);
serial_gf.SetSubVector(dofs, nodeval);
fespace_serial->GetElementVDofs(elem_count++, dofs);
gf_serial.SetSubVector(dofs, nodeval);
}
for (int p = 0; p < nranks; p++)
{
if (p == save_rank) { continue; }
int n_send_recv;
MPI_Recv(&n_send_recv, 1, MPI_INT, p, 448, comm, &status);
MPI_Recv(&n_send_recv, 1, MPI_INT, p, 448, my_comm, &status);
vals.SetSize(n_send_recv);
if (n_send_recv)
{
MPI_Recv(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, p, 449, comm,
MPI_Recv(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, p, 449, my_comm,
&status);
}
for (int i = 0; i < n_send_recv; )
{
serial_fes.GetElementVDofs(elem_count++, dofs);
serial_gf.SetSubVector(dofs, &vals[i]);
fespace_serial->GetElementVDofs(elem_count++, dofs);
gf_serial.SetSubVector(dofs, &vals[i]);
i += dofs.Size();
}
}
} // my_rank == save_rank
else
{
int n_send_recv = 0;
n_send_recv = 0;
Vector nodeval;
for (int e = 0; e < pmesh->GetNE(); e++)
{
const FiniteElement *fe = pfespace->GetFE(e);
n_send_recv += vdim*fe->GetDof();
}
MPI_Send(&n_send_recv, 1, MPI_INT, save_rank, 448, comm);
MPI_Send(&n_send_recv, 1, MPI_INT, save_rank, 448, my_comm);
vals.Reserve(n_send_recv);
vals.SetSize(0);
for (int e = 0; e < pmesh->GetNE(); e++)
@@ -1054,24 +1059,12 @@ GridFunction ParGridFunction::GetSerialGridFunction(
if (n_send_recv)
{
MPI_Send(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, save_rank, 449,
comm);
my_comm);
}
}
return serial_gf;
}
GridFunction ParGridFunction::GetSerialGridFunction(int save_rank,
Mesh &serial_mesh) const
{
auto *serial_fec = pfes->FEColl()->Clone(pfes->FEColl()->GetOrder());
auto *serial_fes = new FiniteElementSpace(&serial_mesh,
serial_fec,
pfes->GetVDim(),
pfes->GetOrdering());
GridFunction serial_gf = GetSerialGridFunction(save_rank, *serial_fes);
serial_gf.MakeOwner(serial_fec); // Also assumes ownership of serial_fes
return serial_gf;
MPI_Barrier(my_comm);
return gf_serial;
}
#ifdef MFEM_USE_ADIOS2
+5 -21
View File
@@ -434,29 +434,13 @@ public:
/// be used for ASCII output.
void Save(const char *fname, int precision=16) const override;
/// @brief Returns a GridFunction on MPI rank @a save_rank that does not have
/// any duplication of vertices/nodes at processor boundaries.
///
/// The @a serial_mesh is obtained using ParMesh::GetSerialMesh. Note that
/// the @a save_rank must be the same as that used in ParMesh::GetSerialMesh.
///
/// @note The returned GridFunction will own the newly created
/// FiniteElementCollection and FiniteElementSpace objects.
/// Returns a GridFunction on MPI rank @a save_rank that does not have any
/// duplication of vertices/nodes at processor boundaries.
/// serial_mesh is obtained using ParMesh::GetSerialMesh(save_rank).
/// Note that the @ save_rank argument must match for the
/// ParMesh::GetSerialMesh and GetSerialGridFunction method.
GridFunction GetSerialGridFunction(int save_rank, Mesh &serial_mesh) const;
/// @brief Returns a GridFunction on MPI rank @a save_rank that does not have
/// any duplication of vertices/nodes at processor boundaries.
///
/// The given @a serial_fes must be defined on the mesh returned by
/// ParMesh::GetSerialMesh (with @a save_rank ranks), for example using the
/// space belonging to the GridFunction obtained from @ref
/// ParGridFunction::GetSerialGridFunction(int,Mesh &) const.
///
/// @note The returned GridFunction does not assume ownership of @a
/// serial_fes.
GridFunction GetSerialGridFunction(
int save_rank, FiniteElementSpace &serial_fes) const;
/// Write the serial GridFunction a single file (written using MPI rank 0).
/// The given @a precision will be used for ASCII output.
void SaveAsSerial(const char *fname, int precision=16, int save_rank=0) const;
+9 -229
View File
@@ -43,13 +43,12 @@ static void Derivatives1D(const int NE,
const int q1d)
{
MFEM_CONTRACT_VAR(b_);
const int SDIM = GRAD_PHYS ? sdim : 1;
const auto g = Reshape(g_, q1d, d1d);
const auto j = Reshape(j_, q1d, SDIM, NE);
const auto j = Reshape(j_, q1d, sdim, NE);
const auto x = Reshape(x_, d1d, vdim, NE);
auto y = Q_LAYOUT == QVectorLayout::byNODES ?
Reshape(y_, q1d, vdim, SDIM, NE):
Reshape(y_, vdim, SDIM, q1d, NE);
Reshape(y_, q1d, vdim, sdim, NE):
Reshape(y_, vdim, sdim, q1d, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
@@ -64,8 +63,8 @@ static void Derivatives1D(const int NE,
}
if (GRAD_PHYS)
{
if (SDIM == 1) { du[0] /= j(q, 0, e); }
else if (SDIM == 2)
if (sdim == 1) { du[0] /= j(q, 0, e); }
else if (sdim == 2)
{
const real_t Jloc[2] = {j(q,0,e), j(q,1,e)};
real_t Jinv[3];
@@ -75,7 +74,7 @@ static void Derivatives1D(const int NE,
du[0] = U;
du[1] = V;
}
else // SDIM == 3
else // sdim == 3
{
const real_t Jloc[3] = {j(q,0,e), j(q,1,e), j(q,2,e)};
real_t Jinv[3];
@@ -88,7 +87,7 @@ static void Derivatives1D(const int NE,
du[2] = W;
}
}
for (int d = 0; d < SDIM; ++d)
for (int d = 0; d < sdim; ++d)
{
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c, d, q, e) = du[d]; }
if (Q_LAYOUT == QVectorLayout::byNODES) { y(q, c, d, e) = du[d]; }
@@ -373,222 +372,14 @@ static void Derivatives3D(const int NE,
});
}
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
static void CollocatedDerivatives1D(const int NE,
const real_t *g_,
const real_t *j_,
const real_t *x_,
real_t *y_,
const int sdim,
const int vdim,
const int d1d)
{
Derivatives1D<Q_LAYOUT, GRAD_PHYS>(
NE, nullptr, g_, j_, x_, y_, sdim, vdim, d1d, d1d);
}
// Template compute kernel for derivatives in 2D: tensor product version.
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
int T_VDIM = 0, int T_D1D = 0,
int T_NBZ = 1>
static void CollocatedDerivatives2D(const int NE,
const real_t *g_,
const real_t *j_,
const real_t *x_,
real_t *y_,
const int sdim = 2,
const int vdim = 0,
const int d1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
const int SDIM = GRAD_PHYS ? sdim : 2;
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
const auto g = Reshape(g_, D1D, D1D);
const auto j = Reshape(j_, D1D, D1D, SDIM, 2, NE);
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
Reshape(y_, D1D, D1D, VDIM, SDIM, NE):
Reshape(y_, VDIM, SDIM, D1D, D1D, NE);
mfem::forall_2D_batch(NE, D1D, D1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
const int tidz = MFEM_THREAD_ID(z);
MFEM_SHARED real_t XY[NBZ][MD1*MD1];
DeviceTensor<2> X((real_t*)(XY+tidz), D1D, D1D);
for (int c = 0; c < VDIM; ++c)
{
kernels::internal::LoadX<MD1,NBZ>(e,D1D,c,x,XY);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
real_t u = 0.0;
real_t v = 0.0;
real_t w = 0.0;
for (int dxy = 0; dxy < D1D; ++dxy)
{
u += X(dxy, dy) * g(dx,dxy);
v += X(dx, dxy) * g(dy,dxy);
}
if (GRAD_PHYS)
{
if (SDIM == 2)
{
real_t Jloc[4], Jinv[4];
Jloc[0] = j(dx,dy,0,0,e);
Jloc[1] = j(dx,dy,1,0,e);
Jloc[2] = j(dx,dy,0,1,e);
Jloc[3] = j(dx,dy,1,1,e);
kernels::CalcInverse<2>(Jloc, Jinv);
const real_t U = Jinv[0]*u + Jinv[1]*v;
const real_t V = Jinv[2]*u + Jinv[3]*v;
u = U;
v = V;
}
else
{
real_t Jloc[6], Jinv[6];
Jloc[0] = j(dx,dy,0,0,e);
Jloc[1] = j(dx,dy,1,0,e);
Jloc[2] = j(dx,dy,2,0,e);
Jloc[3] = j(dx,dy,0,1,e);
Jloc[4] = j(dx,dy,1,1,e);
Jloc[5] = j(dx,dy,2,1,e);
kernels::CalcLeftInverse<3,2>(Jloc, Jinv);
const real_t U = Jinv[0]*u + Jinv[1]*v;
const real_t V = Jinv[2]*u + Jinv[3]*v;
const real_t W = Jinv[4]*u + Jinv[5]*v;
u = U;
v = V;
w = W;
}
}
if (Q_LAYOUT == QVectorLayout::byVDIM)
{
y(c,0,dx,dy,e) = u;
y(c,1,dx,dy,e) = v;
if (SDIM == 3) { y(c,2,dx,dy,e) = w; }
}
if (Q_LAYOUT == QVectorLayout::byNODES)
{
y(dx,dy,c,0,e) = u;
y(dx,dy,c,1,e) = v;
if (SDIM == 3) { y(dx,dy,c,2,e) = w; }
}
}
}
MFEM_SYNC_THREAD;
}
});
}
// Template compute kernel for derivatives in 3D: tensor product version.
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
int T_VDIM = 0, int T_D1D = 0>
static void CollocatedDerivatives3D(const int NE,
const real_t *g_,
const real_t *j_,
const real_t *x_,
real_t *y_,
const int sdim = 3,
const int vdim = 0,
const int d1d = 0)
{
MFEM_VERIFY(sdim == 3, "");
const int D1D = T_D1D ? T_D1D : d1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
const auto g = Reshape(g_, D1D, D1D);
const auto j = Reshape(j_, D1D, D1D, D1D, 3, 3, NE);
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
Reshape(y_, D1D, D1D, D1D, VDIM, 3, NE):
Reshape(y_, VDIM, 3, D1D, D1D, D1D, NE);
mfem::forall_3D(NE, D1D, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_INTERP_1D;
MFEM_SHARED real_t uvw[MD1*MD1*MD1];
DeviceTensor<3> X(uvw, D1D, D1D, D1D);
for (int c = 0; c < VDIM; ++c)
{
kernels::internal::LoadX(e,D1D,c,x,X);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
real_t u = 0.0;
real_t v = 0.0;
real_t w = 0.0;
for (int dxyz = 0; dxyz < D1D; ++dxyz)
{
u += X(dxyz, dy, dz) * g(dx,dxyz);
v += X(dx, dxyz, dz) * g(dy,dxyz);
w += X(dx, dy, dxyz) * g(dz,dxyz);
}
if (GRAD_PHYS)
{
real_t Jloc[9], Jinv[9];
for (int col = 0; col < 3; col++)
{
for (int row = 0; row < 3; row++)
{
Jloc[row+3*col] = j(dx,dy,dz,row,col,e);
}
}
kernels::CalcInverse<3>(Jloc, Jinv);
const real_t U = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
const real_t V = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
const real_t W = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
u = U; v = V; w = W;
}
if (Q_LAYOUT == QVectorLayout::byVDIM)
{
y(c,0,dx,dy,dz,e) = u;
y(c,1,dx,dy,dz,e) = v;
y(c,2,dx,dy,dz,e) = w;
}
if (Q_LAYOUT == QVectorLayout::byNODES)
{
y(dx,dy,dz,c,0,e) = u;
y(dx,dy,dz,c,1,e) = v;
y(dx,dy,dz,c,2,e) = w;
}
}
}
}
MFEM_SYNC_THREAD;
}
});
}
} // namespace quadrature_interpolator
} // namespace internal
/// @cond Suppress_Doxygen_warnings
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
int Q1D, int NBZ>
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
int VDIM, int D1D, int Q1D, int NBZ>
QuadratureInterpolator::GradKernelType
QuadratureInterpolator::GradKernels::Kernel()
{
@@ -598,17 +389,6 @@ QuadratureInterpolator::GradKernels::Kernel()
else { MFEM_ABORT(""); }
}
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
int NBZ>
QuadratureInterpolator::CollocatedGradKernelType
QuadratureInterpolator::CollocatedGradKernels::Kernel()
{
if (DIM == 1) { return internal::quadrature_interpolator::CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return internal::quadrature_interpolator::CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, NBZ>; }
else if (DIM == 3) { return internal::quadrature_interpolator::CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D>; }
else { MFEM_ABORT(""); }
}
/// @endcond
} // namespace mfem
+36 -59
View File
@@ -23,73 +23,50 @@ template <bool P>
void InitGradByNodesKernels()
{
using k = QuadratureInterpolator::GradKernels;
constexpr auto L = QVectorLayout::byNODES;
// 2D
k::Specialization<2,L,P,1,3,3>::template Opt<16>::Add();
k::Specialization<2,L,P,1,3,4>::template Opt<16>::Add();
k::Specialization<2,L,P,1,4,3>::template Opt<16>::Add();
k::Specialization<2,L,P,1,4,4>::template Opt<16>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,1,3,3>::template Opt<16>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,1,3,4>::template Opt<16>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,1,4,3>::template Opt<16>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,1,4,4>::template Opt<16>::Add();
k::Specialization<2,L,P,2,2,2>::template Opt<16>::Add();
k::Specialization<2,L,P,2,2,3>::template Opt<8>::Add();
k::Specialization<2,L,P,2,2,4>::template Opt<4>::Add();
k::Specialization<2,L,P,2,2,5>::template Opt<4>::Add();
k::Specialization<2,L,P,2,2,6>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,2,2>::template Opt<16>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,2,3>::template Opt<8>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,2,4>::template Opt<4>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,2,5>::template Opt<4>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,2,6>::template Opt<2>::Add();
k::Specialization<2,L,P,2,3,3>::template Opt<2>::Add();
k::Specialization<2,L,P,2,3,4>::template Opt<4>::Add();
k::Specialization<2,L,P,2,4,3>::template Opt<4>::Add();
k::Specialization<2,L,P,2,3,6>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,3,3>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,3,4>::template Opt<4>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,4,3>::template Opt<4>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,3,6>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,4>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,5>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,6>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,7>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,4,4>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,4,5>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,4,6>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,4,7>::template Opt<2>::Add();
k::Specialization<2,L,P,2,5,6>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byNODES,P,2,5,6>::template Opt<2>::Add();
// 3D
k::Specialization<3,L,P,1,2,4>::Add();
k::Specialization<3,L,P,1,3,3>::Add();
k::Specialization<3,L,P,1,3,4>::Add();
k::Specialization<3,L,P,1,3,6>::Add();
k::Specialization<3,L,P,1,4,4>::Add();
k::Specialization<3,L,P,1,4,8>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,1,2,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,1,3,3>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,1,3,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,1,3,6>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,1,4,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,1,4,8>::template Opt<1>::Add();
k::Specialization<3,L,P,3,2,3>::Add();
k::Specialization<3,L,P,3,2,4>::Add();
k::Specialization<3,L,P,3,2,5>::Add();
k::Specialization<3,L,P,3,2,6>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,2,3>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,2,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,2,5>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,2,6>::template Opt<1>::Add();
k::Specialization<3,L,P,3,3,3>::Add();
k::Specialization<3,L,P,3,3,4>::Add();
k::Specialization<3,L,P,3,3,5>::Add();
k::Specialization<3,L,P,3,3,6>::Add();
k::Specialization<3,L,P,3,4,4>::Add();
k::Specialization<3,L,P,3,4,6>::Add();
k::Specialization<3,L,P,3,4,7>::Add();
k::Specialization<3,L,P,3,4,8>::Add();
using k2 = QuadratureInterpolator::CollocatedGradKernels;
// 2D
k2::Specialization<2,L,P,1,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,3>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,4>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,3>::template Opt<4>::Add();
k2::Specialization<2,L,P,2,4>::template Opt<2>::Add();
k2::Specialization<3,L,P,1,2>::Add();
k2::Specialization<3,L,P,1,3>::Add();
k2::Specialization<3,L,P,1,4>::Add();
k2::Specialization<3,L,P,2,2>::Add();
k2::Specialization<3,L,P,2,3>::Add();
k2::Specialization<3,L,P,2,4>::Add();
k2::Specialization<3,L,P,3,2>::Add();
k2::Specialization<3,L,P,3,3>::Add();
k2::Specialization<3,L,P,3,4>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,3,3>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,3,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,3,5>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,3,6>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,4,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,4,6>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,4,7>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,P,3,4,8>::template Opt<1>::Add();
}
template void InitGradByNodesKernels<true>();
+13 -37
View File
@@ -23,46 +23,22 @@ template <bool P>
void InitGradByVDimKernels()
{
using k = QuadratureInterpolator::GradKernels;
constexpr auto L = QVectorLayout::byVDIM;
// 2D
k::Specialization<2,L,P,1,3,4>::template Opt<8>::Add();
k::Specialization<2,L,P,1,4,6>::template Opt<4>::Add();
k::Specialization<2,L,P,1,5,8>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,1,3,4>::template Opt<8>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,1,4,6>::template Opt<4>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,1,5,8>::template Opt<2>::Add();
k::Specialization<2,L,P,2,3,3>::template Opt<8>::Add();
k::Specialization<2,L,P,2,3,4>::template Opt<8>::Add();
k::Specialization<2,L,P,2,4,6>::template Opt<4>::Add();
k::Specialization<2,L,P,2,5,8>::template Opt<2>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,2,3,3>::template Opt<8>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,2,3,4>::template Opt<8>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,2,4,6>::template Opt<4>::Add();
k::Specialization<2,QVectorLayout::byVDIM,P,2,5,8>::template Opt<2>::Add();
// 3D
k::Specialization<3,L,P,1,3,4>::Add();
k::Specialization<3,L,P,1,4,6>::Add();
k::Specialization<3,L,P,1,5,8>::Add();
k::Specialization<3,L,P,3,3,4>::Add();
k::Specialization<3,L,P,3,4,6>::Add();
k::Specialization<3,L,P,3,5,8>::Add();
using k2 = QuadratureInterpolator::CollocatedGradKernels;
// 2D
k2::Specialization<2,L,P,1,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,3>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,4>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,3>::template Opt<4>::Add();
k2::Specialization<2,L,P,2,4>::template Opt<2>::Add();
// 3D
k2::Specialization<3,L,P,1,2>::Add();
k2::Specialization<3,L,P,1,3>::Add();
k2::Specialization<3,L,P,1,4>::Add();
k2::Specialization<3,L,P,2,2>::Add();
k2::Specialization<3,L,P,2,3>::Add();
k2::Specialization<3,L,P,2,4>::Add();
k2::Specialization<3,L,P,3,2>::Add();
k2::Specialization<3,L,P,3,3>::Add();
k2::Specialization<3,L,P,3,4>::Add();
k::Specialization<3,QVectorLayout::byVDIM,P,1,3,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,P,1,4,6>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,P,1,5,8>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,P,3,3,4>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,P,3,4,6>::template Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,P,3,5,8>::template Opt<1>::Add();
}
template void InitGradByVDimKernels<true>();
+25 -56
View File
@@ -30,29 +30,28 @@ void InitEvalKernels();
void InitDetKernels();
template <bool P> void InitGradByNodesKernels();
template <bool P> void InitGradByVDimKernels();
struct Kernels
{
Kernels()
{
using namespace internal::quadrature_interpolator;
InitEvalByNodesKernels();
InitEvalByVDimKernels();
// Non-phys grad kernels
InitGradByNodesKernels<false>();
InitGradByVDimKernels<false>();
// Phys grad kernels
InitGradByNodesKernels<true>();
InitGradByVDimKernels<true>();
// Determinants
InitDetKernels();
// Non-tensor
InitEvalKernels();
}
};
}
}
QuadratureInterpolator::Kernels QuadratureInterpolator::kernels;
QuadratureInterpolator::Kernels::Kernels()
{
using namespace internal::quadrature_interpolator;
InitEvalByNodesKernels();
InitEvalByVDimKernels();
// Non-phys grad kernels
InitGradByNodesKernels<false>();
InitGradByVDimKernels<false>();
// Phys grad kernels
InitGradByNodesKernels<true>();
InitGradByVDimKernels<true>();
// Determinants
InitDetKernels();
// Non-tensor
InitEvalKernels();
}
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
const IntegrationRule &ir):
@@ -62,8 +61,6 @@ QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
q_layout(QVectorLayout::byNODES),
use_tensor_products(UsesTensorBasis(fes))
{
static internal::quadrature_interpolator::Kernels kernels;
d_buffer.UseDevice(true);
if (fespace->GetNE() == 0) { return; }
const FiniteElement *fe = fespace->GetFE(0);
@@ -603,55 +600,34 @@ void QuadratureInterpolator::Determinants(const Vector &e_vec,
namespace
{
using namespace internal::quadrature_interpolator;
using EvalKernel = QuadratureInterpolator::EvalKernelType;
using TensorEvalKernel = QuadratureInterpolator::TensorEvalKernelType;
using GradKernel = QuadratureInterpolator::GradKernelType;
using CollocatedGradKernel = QuadratureInterpolator::CollocatedGradKernelType;
template <QVectorLayout Q_LAYOUT>
TensorEvalKernel FallbackTensorEvalKernel(int DIM)
{
if (DIM == 1) { return Values1D<Q_LAYOUT>; }
else if (DIM == 2) { return Values2D<Q_LAYOUT>; }
else if (DIM == 3) { return Values3D<Q_LAYOUT>; }
if (DIM == 1) { return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
else if (DIM == 2) { return internal::quadrature_interpolator::Values2D<Q_LAYOUT>; }
else if (DIM == 3) { return internal::quadrature_interpolator::Values3D<Q_LAYOUT>; }
else { MFEM_ABORT(""); }
}
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
GradKernel GetGradKernel(int DIM)
{
if (DIM == 1) { return Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return Derivatives2D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 3) { return Derivatives3D<Q_LAYOUT, GRAD_PHYS>; }
if (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS>; }
else { MFEM_ABORT(""); }
}
template<QVectorLayout Q_LAYOUT>
GradKernel GetGradKernel(int DIM, bool GRAD_PHYS)
{
if (GRAD_PHYS) { return GetGradKernel<Q_LAYOUT, true>(DIM); }
else { return GetGradKernel<Q_LAYOUT, false>(DIM); }
}
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
CollocatedGradKernel GetCollocatedGradKernel(int DIM)
{
if (DIM == 1) { return CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 3) { return CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS>; }
else { MFEM_ABORT(""); }
}
template<QVectorLayout Q_LAYOUT>
CollocatedGradKernel GetCollocatedGradKernel(int DIM, bool GRAD_PHYS)
{
if (GRAD_PHYS) { return GetCollocatedGradKernel<Q_LAYOUT, true>(DIM); }
else { return GetCollocatedGradKernel<Q_LAYOUT, false>(DIM); }
}
} // namespace
template <int DIM, int VDIM, int ND, int NQ>
@@ -697,13 +673,6 @@ GradKernel QuadratureInterpolator::GradKernels::Fallback(
else { return GetGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
}
CollocatedGradKernel QuadratureInterpolator::CollocatedGradKernels::Fallback(
int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int, int)
{
if (Q_LAYOUT == QVectorLayout::byNODES) { return GetCollocatedGradKernel<QVectorLayout::byNODES>(DIM, GRAD_PHYS); }
else { return GetCollocatedGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
}
/// @endcond
namespace internal
+2 -6
View File
@@ -138,10 +138,6 @@ public:
using GradKernelType = void(*)(const int, const real_t *, const real_t *,
const real_t *, const real_t *, real_t *,
const int, const int, const int, const int);
using CollocatedGradKernelType = void(*)(const int, const real_t *,
const real_t *, const real_t *,
real_t *, const int, const int,
const int);
using DetKernelType = void(*)(const int NE, const real_t *, const real_t *,
const real_t *, real_t *, const int, const int,
Vector *);
@@ -156,8 +152,8 @@ public:
(int, QVectorLayout, bool, int, int, int), (int));
MFEM_REGISTER_KERNELS(DetKernels, DetKernelType, (int, int, int, int));
MFEM_REGISTER_KERNELS(EvalKernels, EvalKernelType, (int, int, int, int));
MFEM_REGISTER_KERNELS(CollocatedGradKernels, CollocatedGradKernelType,
(int, QVectorLayout, bool, int, int), (int));
static struct Kernels { Kernels(); } kernels;
};
}
+1 -1
View File
@@ -1631,7 +1631,7 @@ void InterpolationManager::LinearizeInterpolatorMapIntoVector()
const FiniteElement *trace_fe =
fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0));
const int face_dofs = trace_fe->GetDof();
const int nc_size = static_cast<int>(interp_map.size());
const int nc_size = interp_map.size();
MFEM_VERIFY(nc_cpt==nc_size, "Unexpected number of interpolators.");
interpolators.SetSize(face_dofs*face_dofs*nc_size);
auto d_interp = Reshape(interpolators.HostWrite(),face_dofs,face_dofs,nc_size);
+8 -21
View File
@@ -1926,6 +1926,7 @@ void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
ndof = tspec_.FESpace()->GetNDofs();
ncomp += vdim;
// need to append data to tspec
@@ -1949,7 +1950,7 @@ void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
ndof = tspec_.FESpace()->GetNDofs();
MFEM_VERIFY(ndof == tspec.Size()/ncomp, "Inconsistency in SetTspecAtIndex.");
MFEM_VERIFY(ndof == tspec.Size()/ncomp, "Inconsistency in SetTargetSpec.");
const auto tspec__d = tspec_.Read();
auto tspec_d = tspec.ReadWrite();
@@ -2697,18 +2698,16 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
Jtrcomp.Clear();
}
void DiscreteAdaptTC::
UpdateGradientTargetSpecification(const Vector &x, real_t dx,
bool reuse_flag, int x_ordering)
void DiscreteAdaptTC:: UpdateGradientTargetSpecification(const Vector &x,
const real_t dx,
bool reuse_flag,
int x_ordering)
{
if (reuse_flag && good_tspec_grad) { return; }
const int dim = tspec_fesv->GetFE(0)->GetDim(),
cnt = x.Size()/dim;
MFEM_VERIFY(tspec_fesv->GetVSize() / ncomp == cnt,
"FD with discrete adaptivity assume mesh_order = field_order.");
tspec_pert1h.SetSize(x.Size()*ncomp);
Vector TSpecTemp;
@@ -2735,18 +2734,16 @@ UpdateGradientTargetSpecification(const Vector &x, real_t dx,
}
void DiscreteAdaptTC::
UpdateHessianTargetSpecification(const Vector &x, real_t dx,
UpdateHessianTargetSpecification(const Vector &x,real_t dx,
bool reuse_flag, int x_ordering)
{
if (reuse_flag && good_tspec_hess) { return; }
const int dim = tspec_fesv->GetFE(0)->GetDim(),
cnt = x.Size()/dim,
totmix = 1+2*(dim-2);
MFEM_VERIFY(tspec_fesv->GetVSize() / ncomp == cnt,
"FD with discrete adaptivity assume mesh_order = field_order.");
tspec_pert2h.SetSize(cnt*dim*ncomp);
tspec_pertmix.SetSize(cnt*totmix*ncomp);
@@ -2912,11 +2909,6 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0,
Coefficient &coeff,
AdaptivityEvaluator &ae)
{
const char* gf_fe_name = z0.FESpace()->FEColl()->Name();
const char* mesh_fe_name =
z0.FESpace()->GetMesh()->GetNodalFESpace()->FEColl()->Name();
MFEM_VERIFY(strcmp(gf_fe_name, mesh_fe_name) == 0,
"Incompatible FE spaces for the adaptive limiting field.");
adapt_lim_gf0 = &z0;
delete adapt_lim_gf;
adapt_lim_gf = new GridFunction(z0);
@@ -2934,11 +2926,6 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
Coefficient &coeff,
AdaptivityEvaluator &ae)
{
const char* gf_fe_name = z0.FESpace()->FEColl()->Name();
const char* mesh_fe_name =
z0.FESpace()->GetMesh()->GetNodalFESpace()->FEColl()->Name();
MFEM_VERIFY(strcmp(gf_fe_name, mesh_fe_name) == 0,
"Incompatible FE spaces for the adaptive limiting field.");
adapt_lim_gf0 = &z0;
adapt_lim_pgf0 = &z0;
delete adapt_lim_gf;
+11 -69
View File
@@ -118,7 +118,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
h_min = std::min(h_min, m->GetElementSize(i));
}
real_t v_max = 0.0;
const int s = u.Size()/m->Dimension();
const int s = new_field.Size();
u.HostReadWrite();
for (int i = 0; i < s; i++)
@@ -181,7 +181,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
// Trim the overshoots and undershoots.
new_field.HostReadWrite();
for (int i = 0; i < new_field.Size(); i++)
for (int i = 0; i < s; i++)
{
if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
if (new_field(i) > glob_maxv) { new_field(i) = glob_maxv; }
@@ -348,10 +348,8 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
{
nodes0 = init_nodes;
Mesh *m = mesh;
FiniteElementSpace *f = fes;
#ifdef MFEM_USE_MPI
if (pmesh) { m = pmesh; }
if (pfes) { f = pfes; }
#endif
m->SetNodes(nodes0);
@@ -365,9 +363,14 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
delete finder;
}
FiniteElementSpace *f = fes;
#ifdef MFEM_USE_MPI
if (pfes) { finder = new FindPointsGSLIB(pfes->GetComm()); }
else { finder = new FindPointsGSLIB(); }
if (pfes)
{
f = pfes;
finder = new FindPointsGSLIB(pfes->GetComm());
}
else { finder = new FindPointsGSLIB(); }
#else
finder = new FindPointsGSLIB();
#endif
@@ -375,74 +378,13 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
field0_gf.SetSpace(f);
field0_gf = init_field;
// Check if the mesh nodes and the field nodes coincide.
const bool nodes_mismatch = init_nodes.Size() / m->Dimension() !=
field0_gf.Size() / f->GetVDim();
if (nodes_mismatch)
{
delete fes_field_nodes;
fes_field_nodes = new FiniteElementSpace(m, f->FEColl(), m->Dimension());
}
}
void InterpolatorFP::ComputeAtNewPosition(const Vector &new_nodes,
Vector &new_field,
int new_nodes_ordering)
{
// Get physical node locations corresponding to field0_gf
if (fes_field_nodes)
{
Vector mapped_nodes;
GetFieldNodesPosition(new_nodes, mapped_nodes);
finder->Interpolate(mapped_nodes, field0_gf, new_field,
fes_field_nodes->GetOrdering());
}
else
{
finder->Interpolate(new_nodes, field0_gf, new_field, new_nodes_ordering);
}
}
void InterpolatorFP::GetFieldNodesPosition(const Vector &mesh_nodes,
Vector &nodes_pos) const
{
MFEM_VERIFY(fes_field_nodes, "InterpolatorFP: fes_field_nodes is not set.");
Mesh *m = fes_field_nodes->GetMesh();
const int nelem = fes_field_nodes->GetNE();
const int n_f_nodes = fes_field_nodes->GetNDofs();
const int dim = m->Dimension();
if (nelem == 0) { return; }
Array<int> dofs;
Vector e_xyz;
nodes_pos.SetSize(n_f_nodes*dim);
const FiniteElementSpace *mesh_fes = m->GetNodalFESpace();
for (int e = 0; e < nelem; e++)
{
mesh_fes->GetElementVDofs(e, dofs);
int n_mdofs = dofs.Size()/dim;
mesh_nodes.GetSubVector(dofs, e_xyz); //e_xyz is ordered by nodes here
const FiniteElement *mfe = mesh_fes->GetFE(e);
Vector shape(n_mdofs);
auto ir = fes_field_nodes->GetFE(e)->GetNodes();
const int n_gf_pts = ir.GetNPoints();
Vector gf_xyz(n_gf_pts*dim);
for (int q = 0; q < n_gf_pts; q++)
{
IntegrationPoint ip = ir.IntPoint(q);
mfe->CalcShape(ip, shape);
for (int d = 0; d < dim; d++)
{
Vector x(e_xyz.GetData() + d*n_mdofs, n_mdofs);
gf_xyz(d*n_gf_pts + q) = x*shape; // order by nodes
}
}
fes_field_nodes->GetElementVDofs(e, dofs);
nodes_pos.SetSubVector(dofs, gf_xyz);
}
finder->Interpolate(new_nodes, field0_gf, new_field, new_nodes_ordering);
}
#endif
@@ -495,7 +437,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Check for convergence
if (init_fit_max_err < surf_fit_max_err_limit)
{
if (print_options.iterations || print_options.warnings)
if (print_options.iterations)
{
mfem::out << "TMOPNewtonSolver converged "
"based on the surface fitting error.\n";
+1 -8
View File
@@ -58,14 +58,8 @@ private:
Vector nodes0;
GridFunction field0_gf;
FindPointsGSLIB *finder;
// FE space for the nodes of the solution GridFunction.
FiniteElementSpace *fes_field_nodes;
void GetFieldNodesPosition(const Vector &mesh_nodes,
Vector &nodes_pos) const;
public:
InterpolatorFP() : finder(NULL), fes_field_nodes(NULL) { }
InterpolatorFP() : finder(NULL) { }
void SetInitialField(const Vector &init_nodes,
const Vector &init_field) override;
@@ -83,7 +77,6 @@ public:
{
finder->FreeData();
delete finder;
delete fes_field_nodes;
}
};
#endif
+40 -916
View File
File diff suppressed because it is too large Load Diff
+19 -156
View File
@@ -40,10 +40,6 @@ protected:
OperatorHandle fw_t_oper; ///< Forward true-dof operator
OperatorHandle bw_t_oper; ///< Backward true-dof operator
bool use_ea;
MemoryType d_mt;
#ifdef MFEM_USE_MPI
bool parallel;
#endif
@@ -63,23 +59,14 @@ protected:
public:
/** Construct a transfer algorithm between the domain, @a dom_fes_, and
range, @a ran_fes_, FE spaces, d_mt_ will specify memory space for
large data structures */
GridTransfer(FiniteElementSpace &dom_fes_,
FiniteElementSpace &ran_fes_);
range, @a ran_fes_, FE spaces. */
GridTransfer(FiniteElementSpace &dom_fes_, FiniteElementSpace &ran_fes_);
/// Virtual destructor
virtual ~GridTransfer() { }
/** Uses device friendly element assembly versions for L2Projection
transfers, L2, H1 FEM spaces currently supported */
void UseEA(bool use_ea_) { use_ea = use_ea_;}
/** Set memory type for large data structures */
void SetMemType(MemoryType d_mt_) {d_mt = d_mt_;}
/** @brief Set the desired Operator::Type for the construction of all
operators defined by the underlying transfer algorithm. */
operators defined by the underlying transfer algorithm. */
/** The default value is Operator::ANY_TYPE which typically corresponds to a
matrix-free operator representation. Note that derived classes are not
required to support this setting and can ignore it. */
@@ -182,8 +169,7 @@ public:
smaller than the number of coarse dofs. */
class L2ProjectionGridTransfer : public GridTransfer
{
// Must be public due to host device lambdas
public:
protected:
/** Abstract class representing projection operator between a high-order
finite element space on a coarse mesh, and a low-order finite element
space on a refined mesh (LOR). We assume that the low-order space,
@@ -208,13 +194,10 @@ public:
const FiniteElementSpace& fes_ho;
const FiniteElementSpace& fes_lor;
MemoryType d_mt;
Array<int> offsets;
Table ho2lor;
L2Projection(const FiniteElementSpace& fes_ho_,
const FiniteElementSpace& fes_lor_,
MemoryType d_mt_ = Device::GetHostMemoryType());
const FiniteElementSpace& fes_lor_);
void BuildHo2Lor(int nel_ho, int nel_lor,
const CoarseFineTransformations& cf_tr);
@@ -224,50 +207,6 @@ public:
ElementTransformation* tr_lor,
IntegrationPointTransformation& ip_tr,
DenseMatrix& M_mixed_el) const;
void ElemMixedMass(Geometry::Type geom, const FiniteElement& fe_ho,
const FiniteElement& fe_lor,
ElementTransformation* el_tr,
IntegrationPointTransformation& ip_tr,
DenseMatrix& B_L, DenseMatrix& B_H) const;
public:
/* Returns the Mixed Mass M_LH via device element assembly by building the
basis functions and data at the quadrature points. */
void MixedMassEA(const FiniteElementSpace& fes_ho_,
const FiniteElementSpace& fes_lor_,
Vector &M_LH,
MemoryType d_mt_ = Device::GetHostMemoryType());
};
// Class below must be public as we now have device code
public:
class H1SpaceMixedMassOperator : public Operator
{
protected:
const FiniteElementSpace* fes_ho;
const FiniteElementSpace* fes_lor;
Table* ho2lor;
Vector* M_LH_ea;
public:
H1SpaceMixedMassOperator(const FiniteElementSpace* fes_ho_,
const FiniteElementSpace* fes_lor_,
Table* ho2lor_, Vector* M_LH_ea_);
void Mult(const Vector& x, Vector& y) const;
void MultTranspose(const Vector& x, Vector& y) const;
};
class H1SpaceLumpedMassOperator : public Operator
{
protected:
const FiniteElementSpace* fes_ho;
const FiniteElementSpace* fes_lor;
Vector* ML_inv; // inverse of lumped M_L
public:
H1SpaceLumpedMassOperator(const FiniteElementSpace* fes_ho_,
const FiniteElementSpace* fes_lor_,
Vector& ML_inv_);
void Mult(const Vector& x, Vector& y) const;
void MultTranspose(const Vector& x, Vector& y) const;
};
/** Class for projection operator between a L2 high-order finite element
@@ -275,24 +214,17 @@ public:
refined mesh (LOR). */
class L2ProjectionL2Space : public L2Projection
{
/// The restriction and prolongation operators are represented as dense
/// elementwise matrices (of potentially different sizes, because of mixed
/// meshes or p-refinement). The matrix entries are stored in the R and P
/// arrays. The entries of the i'th high-order element are stored at the
/// index given by offsets[i].
// The restriction and prolongation operators are represented as dense
// elementwise matrices (of potentially different sizes, because of mixed
// meshes or p-refinement). The matrix entries are stored in the R and P
// arrays. The entries of the i'th high-order element are stored at the
// index given by offsets[i].
mutable Array<real_t> R, P;
const bool use_ea;
Array<int> offsets;
public:
L2ProjectionL2Space(const FiniteElementSpace& fes_ho_,
const FiniteElementSpace& fes_lor_,
const bool use_ea_,
MemoryType d_mt_ = Device::GetHostMemoryType());
/*Same as above but assembles and stores R_ea, P_ea */
void EAL2ProjectionL2Space();
const FiniteElementSpace& fes_lor_);
/// Maps <tt>x</tt>, primal field coefficients defined on a coarse mesh
/// with a higher order L2 finite element space, to <tt>y</tt>, primal
/// field coefficients defined on a refined mesh with a low order L2
@@ -300,10 +232,6 @@ public:
/// the coarse mesh. Coefficients are computed through minimization of L2
/// error between the fields.
void Mult(const Vector& x, Vector& y) const override;
/// Perform mult on the device (same as above)
void EAMult(const Vector& x, Vector& y) const;
/// Maps <tt>x</tt>, dual field coefficients defined on a refined mesh
/// with a low order L2 finite element space, to <tt>y</tt>, dual field
/// coefficients defined on a coarse mesh with a higher order L2 finite
@@ -312,9 +240,6 @@ public:
/// error between the primal fields. Note, if the <tt>x</tt>-coefficients
/// come from ProlongateTranspose, then mass is conserved.
void MultTranspose(const Vector& x, Vector& y) const override;
void EAMultTranspose(const Vector& x, Vector& y) const;
/// Maps <tt>x</tt>, primal field coefficients defined on a refined mesh
/// with a low order L2 finite element space, to <tt>y</tt>, primal field
/// coefficients defined on a coarse mesh with a higher order L2 finite
@@ -323,9 +248,6 @@ public:
/// left-inverse prolongation operation. This functionality is also
/// provided as an Operator by L2Prolongation.
void Prolongate(const Vector& x, Vector& y) const override;
void EAProlongate(const Vector& x, Vector& y) const;
/// Maps <tt>x</tt>, dual field coefficients defined on a coarse mesh with
/// a higher order L2 finite element space, to <tt>y</tt>, dual field
/// coefficients defined on a refined mesh with a low order L2 finite
@@ -334,46 +256,21 @@ public:
/// conservative left-inverse prolongation operation. This functionality
/// is also provided as an Operator by L2Prolongation.
void ProlongateTranspose(const Vector& x, Vector& y) const override;
void EAProlongateTranspose(const Vector& x, Vector& y) const;
void SetRelTol(real_t p_rtol_) override { } ///< No-op.
void SetAbsTol(real_t p_atol_) override { } ///< No-op.
};
protected:
/// Class below must be public as we now have device code
public:
/** Projection operator between a H1 high-order finite element space on a
coarse mesh, and a H1 low-order finite element space on a refined mesh
(LOR). */
class L2ProjectionH1Space : public L2Projection
{
const bool use_ea;
public:
L2ProjectionH1Space(const FiniteElementSpace &fes_ho_,
const FiniteElementSpace &fes_lor_,
const bool use_ea_,
MemoryType d_mt_ = Device::GetHostMemoryType());
const FiniteElementSpace &fes_lor_);
#ifdef MFEM_USE_MPI
L2ProjectionH1Space(const ParFiniteElementSpace &pfes_ho_,
const ParFiniteElementSpace &pfes_lor_,
const bool use_ea_,
MemoryType d_mt_ = Device::GetHostMemoryType());
#endif
/// Same as above but assembles action of R through 4 parts:
/// ( ) inv( lumped(M_L) ), which is a diagonal matrix (essentially a vector)
/// ( ) ElementRestrictionOperator for LOR space
/// ( ) mixed mass matrix M_{LH}
/// ( ) ElementRestrictionOperator for HO space
void EAL2ProjectionH1Space();
#ifdef MFEM_USE_MPI
void EAL2ProjectionH1Space(const ParFiniteElementSpace &pfes_ho_,
const ParFiniteElementSpace &pfes_lor_);
const ParFiniteElementSpace &pfes_lor_);
#endif
/// Maps <tt>x</tt>, primal field coefficients defined on a coarse mesh
/// with a higher order H1 finite element space, to <tt>y</tt>, primal
@@ -382,7 +279,6 @@ public:
/// the coarse mesh. Coefficients are computed through minimization of L2
/// error between the fields.
void Mult(const Vector& x, Vector& y) const override;
/// Maps <tt>x</tt>, dual field coefficients defined on a refined mesh
/// with a low order H1 finite element space, to <tt>y</tt>, dual field
/// coefficients defined on a coarse mesh with a higher order H1 finite
@@ -391,7 +287,6 @@ public:
/// error between the primal fields. Note, if the <tt>x</tt>-coefficients
/// come from ProlongateTranspose, then mass is conserved.
void MultTranspose(const Vector& x, Vector& y) const override;
/// Maps <tt>x</tt>, primal field coefficients defined on a refined mesh
/// with a low order H1 finite element space, to <tt>y</tt>, primal field
/// coefficients defined on a coarse mesh with a higher order H1 finite
@@ -400,7 +295,6 @@ public:
/// left-inverse prolongation operation. This functionality is also
/// provided as an Operator by L2Prolongation.
void Prolongate(const Vector& x, Vector& y) const override;
/// Maps <tt>x</tt>, dual field coefficients defined on a coarse mesh with
/// a higher order H1 finite element space, to <tt>y</tt>, dual field
/// coefficients defined on a refined mesh with a low order H1 finite
@@ -409,22 +303,14 @@ public:
/// conservative left-inverse prolongation operation. This functionality
/// is also provided as an Operator by L2Prolongation.
void ProlongateTranspose(const Vector& x, Vector& y) const override;
/// Returns the inverse of an on-rank lumped mass matrix
void LumpedMassInverse(Vector& ML_inv) const;
void SetRelTol(real_t p_rtol_) override;
void SetAbsTol(real_t p_atol_) override;
protected:
/// Sets up the PCG solver (sets parameters, operator, and preconditioner)
void SetupPCG();
/// @brief Computes on-rank R and M_LH matrices. If true, computes mixed mass and/or
/// inverse lumped mass matrix error when compared to device implementation.
/// Computes on-rank R and M_LH matrices.
std::pair<std::unique_ptr<SparseMatrix>,
std::unique_ptr<SparseMatrix>> ComputeSparseRAndM_LH();
/// @brief Recovers vector of tdofs given a vector of dofs and a finite
/// element space
void GetTDofs(const FiniteElementSpace& fes, const Vector& x, Vector& X) const;
@@ -447,8 +333,10 @@ public:
void TDofsListByVDim(const FiniteElementSpace& fes,
int vdim,
Array<int>& vdofs_list) const;
/// Returns the inverse of an on-rank lumped mass matrix
void LumpedMassInverse(Vector& ML_inv) const;
/// @brief Computes sparsity pattern and initializes R matrix.
///
/// Based on BilinearForm::AllocMat(), except maps between coarse HO
/// elements and refined LOR elements.
std::unique_ptr<SparseMatrix> AllocR();
@@ -458,34 +346,10 @@ public:
// The restriction operator is represented as an Operator R. The
// prolongation operator is a dense matrix computed as the inverse of (R^T
// M_L R), and hence, is not stored.
// If element assembly is enabled
std::unique_ptr<Operator> R;
// Used to compute P = (RT*M_LH)^(-1) M_LH^T
std::unique_ptr<Operator> M_LH;
// Inverted operator in P = (RT*M_LH)^(-1) M_LH^T. Used to compute P via PCG.
std::unique_ptr<Operator> RTxM_LH;
// Lumped M_L inverse operator built via EA. Wrapped with restriction maps
// to multiply with scalar TDof LOR vectors.
std::unique_ptr<Operator> ML_inv_vea;
// LDof Mixed mass operator built via EA. Wrapped with restrition maps to send
// scalar LDof HO vectors to LDof LOR vectors.
Operator *M_LH_local_op;
// Scalar finite element spaces for stored Tdof-to-and-from-LDof maps.
std::unique_ptr<FiniteElementSpace> fes_ho_scalar;
std::unique_ptr<FiniteElementSpace> fes_lor_scalar;
// Element Assembled mixed mass
Vector M_LH_ea;
// Element Assembled lumped M_L inverse built via EA. Stores diagonal as a Ldof vector.
Vector ML_inv_ea;
#ifdef MFEM_USE_MPI
std::unique_ptr<ParFiniteElementSpace> pfes_ho_scalar;
std::unique_ptr<ParFiniteElementSpace> pfes_lor_scalar;
Vector RML_inv;
#endif
friend class L2ProjectionL2Space;
};
/** Mass-conservative prolongation operator going in the opposite direction
@@ -515,8 +379,7 @@ public:
public:
L2ProjectionGridTransfer(FiniteElementSpace &coarse_fes_,
FiniteElementSpace &fine_fes_,
bool force_l2_space_ = false,
MemoryType d_mt_ = Device::GetHostMemoryType()) //move to method
bool force_l2_space_ = false)
: GridTransfer(coarse_fes_, fine_fes_),
F(NULL), B(NULL), force_l2_space(force_l2_space_)
{ }
-1
View File
@@ -45,7 +45,6 @@ list(APPEND HDRS
gecko.hpp
globals.hpp
zstr.hpp
handle.hpp
hash.hpp
isockstream.hpp
kdtree.hpp
+1 -1
View File
@@ -112,7 +112,7 @@ void Array<T>::PartialSum()
// Sum
template <class T>
T Array<T>::Sum() const
T Array<T>::Sum()
{
T sum = static_cast<T>(0);
for (int i = 0; i < size; i++)
+10 -71
View File
@@ -23,7 +23,6 @@
#include <cstring>
#include <algorithm>
#include <type_traits>
#include <initializer_list>
namespace mfem
{
@@ -53,7 +52,10 @@ protected:
inline void GrowSize(int minsize);
static_assert(std::is_trivial<T>::value, "type T must be trivial");
static inline void TypeAssert()
{
static_assert(std::is_trivial<T>::value, "type T must be trivial");
}
public:
friend void Swap<T>(Array<T> &, Array<T> &);
@@ -89,20 +91,15 @@ public:
template <typename CT>
inline Array(const Array<CT> &src);
/// Construct an Array from a C-style array of static length
/// Deep copy from a braced init-list of convertible type
template <typename CT, int N>
explicit inline Array(const CT (&values)[N]);
/// Construct an Array from a braced initializer list of convertible type
template <typename CT, typename std::enable_if<
std::is_convertible<CT,T>::value,bool>::type = true>
explicit inline Array(std::initializer_list<CT> values);
/// Move constructor ("steals" data from 'src')
inline Array(Array<T> &&src) { Swap(src, *this); }
/// Destructor
inline ~Array() { data.Delete(); }
inline ~Array() { TypeAssert(); data.Delete(); }
/// Assignment operator: deep copy from 'src'.
Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
@@ -207,8 +204,6 @@ public:
/// Delete the whole array.
inline void DeleteAll();
/// Reduces the capacity of the array to exactly match the current size.
inline void ShrinkToFit();
/// Create a copy of the internal array to the provided @a copy.
inline void Copy(Array &copy) const;
@@ -226,18 +221,6 @@ public:
/// Make this Array a reference to 'master'.
inline void MakeRef(const Array &master);
/**
* @brief Permute the array using the provided indices. Sorts the indices
* variable in the process, thereby destroying the permutation. The rvalue
* reference is to be used when this destruction is allowed, whilst the const
* reference preserves at the cost of duplication.
*
* @param indices The indices of the ordering. data[i] = data[indices[i]].
*/
template <typename I>
inline void Permute(I &&indices);
template <typename I>
inline void Permute(const I &indices) { Permute(I(indices)); }
/// Copy sub array starting from @a offset out to the provided @a sa.
inline void GetSubArray(int offset, int sa_size, Array<T> &sa) const;
@@ -286,20 +269,17 @@ public:
void Unique()
{
T* end = std::unique((T*)data, data + size);
SetSize((int)(end - data));
SetSize(end - data);
}
/// Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
int IsSorted() const;
/// Does the Array have Size zero.
bool IsEmpty() const { return Size() == 0; }
/// Fill the entries of the array with the cumulative sum of the entries.
void PartialSum();
/// Return the sum of all the array entries using the '+'' operator for class 'T'.
T Sum() const;
T Sum();
/// Set all entries of the array to the provided constant.
inline void operator=(const T &a);
@@ -512,8 +492,6 @@ public:
BlockArray(int block_size = 16*1024);
BlockArray(const BlockArray<T> &other); // deep copy
BlockArray& operator=(const BlockArray&) = delete; // not supported
BlockArray(BlockArray<T> &&other) = default;
BlockArray& operator=(BlockArray<T> &&other) = default;
~BlockArray() { Destroy(); }
/// Allocate and construct a new item in the array, return its index.
@@ -635,8 +613,6 @@ public:
iterator begin() { return size ? iterator(this) : iterator(true); }
iterator end() { return iterator(); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
const_iterator cbegin() const
{ return size ? const_iterator(this) : const_iterator(true); }
@@ -692,18 +668,10 @@ inline Array<T>::Array(const Array<CT> &src)
for (int i = 0; i < size; i++) { (*this)[i] = T(src[i]); }
}
template <typename T>
template <typename CT, typename std::enable_if<
std::is_convertible<CT,T>::value,bool>::type>
inline Array<T>::Array(std::initializer_list<CT> values) : Array(values.size())
{
std::copy(values.begin(), values.end(), begin());
}
template <typename T> template <typename CT, int N>
inline Array<T>::Array(const CT (&values)[N]) : Array(N)
{
std::copy(values, values + N, begin());
for (int i = 0; i < size; i++) { (*this)[i] = T(values[i]); }
}
template <class T>
@@ -717,35 +685,6 @@ inline void Array<T>::GrowSize(int minsize)
data = p;
}
template <typename T>
inline void Array<T>::ShrinkToFit()
{
if (Capacity() == size) { return; }
Memory<T> p(size, data.GetMemoryType());
p.CopyFrom(data, size);
p.UseDevice(data.UseDevice());
data.Delete();
data = p;
}
template <typename T>
template <typename I>
inline void Array<T>::Permute(I &&indices)
{
for (int i = 0; i < size; i++)
{
auto current = i;
while (i != indices[current])
{
auto next = indices[current];
std::swap(data[current], data[next]);
indices[current] = current;
current = next;
}
indices[current] = current;
}
}
template <typename T> template <typename CT>
inline Array<T> &Array<T>::operator=(const Array<CT> &src)
{
@@ -901,7 +840,7 @@ inline int Array<T>::FindSorted(const T &el) const
const T *begin = data, *end = begin + size;
const T* first = std::lower_bound(begin, end, el);
if (first == end || !(*first == el)) { return -1; }
return (int)(first - begin);
return first - begin;
}
template <class T>
+1 -1
View File
@@ -64,7 +64,7 @@ public:
ArraysByName(ArraysByName &&src) noexcept = default;
/// Return the number of named arrays in the container
int Size() const { return static_cast<int>(data.size()); }
int Size() const { return data.size(); }
/// Return an STL set of strings giving the names of the arrays
inline std::set<std::string> GetNames() const;
+5 -5
View File
@@ -431,8 +431,8 @@ struct VarMessage
void Isend(int rank, MPI_Comm comm)
{
Encode(rank);
MPI_Isend((void*) data.data(), static_cast<int>(data.length()), MPI_BYTE, rank,
Tag, comm, &send_request);
MPI_Isend((void*) data.data(), data.length(), MPI_BYTE, rank, Tag, comm,
&send_request);
}
/** @brief Non-blocking synchronous send to processor 'rank'.
@@ -441,8 +441,8 @@ struct VarMessage
void Issend(int rank, MPI_Comm comm)
{
Encode(rank);
MPI_Issend((void*) data.data(), static_cast<int>(data.length()), MPI_BYTE, rank,
Tag, comm, &send_request);
MPI_Issend((void*) data.data(), data.length(), MPI_BYTE, rank, Tag, comm,
&send_request);
}
/// Helper to send all messages in a rank-to-message map container.
@@ -538,7 +538,7 @@ struct VarMessage
template<typename MapT>
static void RecvAll(MapT& rank_msg, MPI_Comm comm)
{
int recv_left = static_cast<int>(rank_msg.size());
int recv_left = rank_msg.size();
while (recv_left > 0)
{
int rank, size;
+1 -12
View File
@@ -150,9 +150,6 @@ Device::Device()
Device::~Device()
{
#ifdef MFEM_USE_MPI
Hypre::Finalize();
#endif
if ( device_env && !destroy_mm) { return; }
if (!device_env && destroy_mm && !mem_host_env)
{
@@ -258,15 +255,7 @@ void Device::Configure(const std::string &device, const int device_id)
destroy_mm = true;
#ifdef MFEM_USE_MPI
#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
// Skip the call to Hypre::InitDevice() if HYPRE is not initialized, e.g.
// * if running a serial code
// * if running with the environment variable MFEM_DEVICE set.
if (HYPRE_Initialized())
{
Hypre::InitDevice();
}
#endif
Hypre::InitDevice();
#endif
}
-10
View File
@@ -838,16 +838,6 @@ inline void hypre_forall(int N, lambda &&body)
#endif
}
// Return the most general MemoryClass that can be used with mfem::hypre_forall
// kernels. The returned MemoryClass is the same as the one returned by
// GerHypreMemoryClass() except when hypre is configured to use UVM, in which
// case this function returns MemoryClass::HOST or MemoryClass::DEVICE depending
// on the result of HypreUsingGPU().
inline MemoryClass GetHypreForallMemoryClass()
{
return HypreUsingGPU() ? MemoryClass::DEVICE : MemoryClass::HOST;
}
#endif // MFEM_USE_MPI
} // namespace mfem
-9
View File
@@ -9,17 +9,12 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifdef _WIN32
// Turn off CRT deprecation warnings for getenv
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "../config/config.hpp"
#include "globals.hpp"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib> // getenv
namespace mfem
{
@@ -76,8 +71,4 @@ void SetGlobalMPI_Comm(MPI_Comm comm)
#endif
const char* getenv(const char* name)
{
return ::getenv(name);
}
}
-2
View File
@@ -107,8 +107,6 @@ void SetGlobalMPI_Comm(MPI_Comm comm);
#endif
const char* getenv(const char* name);
} // namespace mfem
#endif
-200
View File
@@ -1,200 +0,0 @@
// Copyright (c) 2010-2024, 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_HANDLE_HPP
#define MFEM_HANDLE_HPP
#include "../config/config.hpp"
#include <memory>
namespace mfem
{
/// @brief A smart pointer class that may represent either shared ownership, or
/// a non-owning borrow.
///
/// A Handle may either be owning or non-owning. Non-owning Handle%s point to
/// externally owned data; it is the responsibility of the user both to ensure
/// that the data remains valid as long as the Handle is alive and to delete the
/// pointer when it is no longer needed. Owning Handle%s use <a
/// href="https://en.cppreference.com/w/cpp/memory/shared_ptr">
/// std::shared_ptr</a> to implement reference counting. The underlying data
/// will be valid as long as there is at least one live copy. When the last
/// Handle is destroyed, the pointer is deleted.
///
/// Both types of Handle%s can be copied, moved, stored in standard containers,
/// etc.
///
/// A non-owning Handle may assume ownership over its data, but an owning Handle
/// cannot release ownership over its data.
///
/// It is an invariant of this class that **at most** one of the data members
/// @a not_owned and @a owned will be non-null.
template <typename T>
class Handle
{
/// If this is a non-owning handle, @a not_owned will point to the data.
T *not_owned = nullptr;
/// If this is an owning handle, @a owned will point to the data.
std::shared_ptr<T> owned = nullptr;
/// @brief Types @a Handle<T> and @a %Handle\<U\> are friends to allow
/// construction of one from another when @a T and @a U are convertible
/// types.
template <typename U> friend class Handle;
public:
/// Create an empty (null) Handle.
Handle() = default;
/// @brief Create a Handle pointing to @a t.
///
/// If @a take_ownership is true, then the Handle assumes ownership over the
/// pointer, and it should not be deleted externally. Otherwise, the Handle
/// will be non-owning, and it is the user's responsibility to ensure the
/// correct lifetime of @a t.
Handle(T *t, bool take_ownership)
{
if (take_ownership) { owned.reset(t); }
else { not_owned = t; }
}
/// Create a Handle from a std::shared_ptr (sharing ownership with @a t).
Handle(const std::shared_ptr<T> &t) : owned(t) { }
/// @brief Copy constructor.
///
/// Copying an owning Handle results in another owning handle. Copying a
/// non-owning handle results in a non-owning handle.
Handle(const Handle &other) = default;
/// Move constructor (see Handle(const Handle&)).
Handle(Handle &&other) = default;
/// @brief Constructs a copy of @a u, where type @a U is convertible to @a T.
///
/// This allows the construction of Handle<Base> from Handle<Derived>.
template <typename U>
Handle(const Handle<U> &u) : not_owned(u.not_owned), owned(u.owned) { }
/// @brief Move-constructs from @a u, where type @a U is convertible to @a T.
///
/// See @ref Handle(const Handle<U>&).
template <typename U>
Handle(Handle<U> &&u) : not_owned(u.not_owned), owned(u.owned) { }
/// Destructor. If the Handle is owning, decrement the reference count.
~Handle() = default;
/// Copy assignment (see Handle(const Handle&)).
Handle &operator=(const Handle &other) = default;
/// Move assignment (see Handle(const Handle&)).
Handle &operator=(Handle &&other) = default;
/// Returns the contained pointer (may be null).
T *Get() const
{
if (not_owned) { return not_owned; }
else { return owned.get(); }
}
/// @brief If the Handle is owning, return a copy of the underlying shared
/// pointer.
///
/// @warning If the Handle is non-owning (even if non-null), this will return
/// and empty (null) shared pointer.
std::shared_ptr<T> GetSharedPtr() const { return owned; }
/// Dereference operator. The Handle must be non-null.
T &operator*() const { return *Get(); }
/// Member access (arrow) operator. The Handle must be non-null.
T *operator->() const { return Get(); }
/// @brief Returns true if the Handle is owning, false if it is non-owning.
///
/// Returns false if the Handle is null (empty).
bool IsOwner() const { return owned; }
/// Returns true if the Handle is non-null.
explicit operator bool() const { return not_owned || owned; }
/// @brief Assume owernship of the data.
///
/// If the Handle is already owning, this does nothing.
void MakeOwner()
{
if (owned) { return; }
owned.reset(not_owned);
not_owned = nullptr;
}
/// @brief Reset the Handle to be empty.
///
/// If the Handle is owning, this will decrement the reference count.
void Reset()
{
owned.reset();
not_owned = nullptr;
}
/// @brief Reset the Handle to point to @a t.
///
/// The Handle may assume ownership of the pointer according to @a
/// take_ownership (see @ref Handle(T*, bool)).
void Reset(T *t, bool take_ownership)
{
if (take_ownership)
{
owned.reset(t);
not_owned = nullptr;
}
else
{
owned.reset();
not_owned = t;
}
}
/// Reset the Handle to share ownership with @a t.
void Reset(const std::shared_ptr<T> &t)
{
owned = t;
not_owned = nullptr;
}
};
/// @brief Return a new owning Handle, where the pointed-to object is a new
/// object constructed using the given arguments.
///
/// This is analogous to <a
/// href="https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared">
/// std::make_shared</a>.
template <typename T, typename... Args>
Handle<T> MakeOwning(Args&&... args)
{
T *t = new T(std::forward<Args>(args)...);
return Handle<T>(t, true);
}
/// Return a new owning Handle pointing to @a t.
template <typename T>
Handle<T> Owning(T *t) { return Handle<T>(t, true); }
/// Return a new non-owning Handle pointing to @a t.
template <typename T>
Handle<T> NonOwning(T *t) { return Handle<T>(t, false); }
} // namespace mfem
#endif
+1 -1
View File
@@ -87,7 +87,7 @@ int isockstream::establish()
#if defined(__APPLE__)
if (bind(sfd, (const struct sockaddr *)rp->ai_addr, rp->ai_addrlen) < 0)
#else
if (bind(sfd, rp->ai_addr, static_cast<socklen_t>(rp->ai_addrlen)) < 0)
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) < 0)
#endif
{
mfem::err << "isockstream::establish(): bind() failed!" << std::endl;
+10 -58
View File
@@ -408,26 +408,8 @@ class UvmHostMemorySpace : public HostMemorySpace
{
public:
UvmHostMemorySpace(): HostMemorySpace() { }
void Alloc(void **ptr, size_t bytes) override
{
#ifdef MFEM_USE_CUDA
CuMallocManaged(ptr, bytes == 0 ? 8 : bytes);
#endif
#ifdef MFEM_USE_HIP
HipMallocManaged(ptr, bytes == 0 ? 8 : bytes);
#endif
}
void Dealloc(void *ptr) override
{
#ifdef MFEM_USE_CUDA
CuMemFree(ptr);
#endif
#ifdef MFEM_USE_HIP
HipMemFree(ptr);
#endif
}
void Alloc(void **ptr, size_t bytes) override { CuMallocManaged(ptr, bytes == 0 ? 8 : bytes); }
void Dealloc(void *ptr) override { CuMemFree(ptr); }
};
/// The 'No' device memory space
@@ -522,25 +504,6 @@ public:
}
};
class UvmHipMemorySpace : public DeviceMemorySpace
{
public:
void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
void Dealloc(Memory&) { }
void *HtoD(void *dst, const void *src, size_t bytes)
{
if (dst == src) { MFEM_STREAM_SYNC; return dst; }
return HipMemcpyHtoD(dst, src, bytes);
}
void *DtoD(void* dst, const void* src, size_t bytes)
{ return HipMemcpyDtoD(dst, src, bytes); }
void *DtoH(void *dst, const void *src, size_t bytes)
{
if (dst == src) { MFEM_STREAM_SYNC; return dst; }
return HipMemcpyDtoH(dst, src, bytes);
}
};
/// The MMU device memory space
class MmuDeviceMemorySpace : public DeviceMemorySpace
{
@@ -698,15 +661,7 @@ public:
// Filling the device memory backends, shifting with the device size
constexpr int shift = DeviceMemoryType;
#if defined(MFEM_USE_CUDA)
device[static_cast<int>(MT::MANAGED)-shift] = new UvmCudaMemorySpace();
#elif defined(MFEM_USE_HIP)
device[static_cast<int>(MT::MANAGED)-shift] = new UvmHipMemorySpace();
#else
// this re-creates the original behavior, but should this be nullptr instead?
device[static_cast<int>(MT::MANAGED)-shift] = new UvmCudaMemorySpace();
#endif
// All other devices controllers are delayed
device[static_cast<int>(MemoryType::DEVICE)-shift] = nullptr;
device[static_cast<int>(MT::DEVICE_DEBUG)-shift] = nullptr;
@@ -1238,9 +1193,8 @@ void MemoryManager::Copy_(void *dst_h_ptr, const void *src_h_ptr,
{
if (dst_h_ptr != src_d_ptr && bytes != 0)
{
MemoryType src_d_mt = (src_flags & Mem::ALIAS) ?
maps->aliases.at(src_h_ptr).mem->d_mt :
maps->memories.at(src_h_ptr).d_mt;
internal::Memory &src_d_base = maps->memories.at(src_h_ptr);
MemoryType src_d_mt = src_d_base.d_mt;
ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
}
}
@@ -1300,10 +1254,9 @@ void MemoryManager::CopyToHost_(void *dest_h_ptr, const void *src_h_ptr,
const void *src_d_ptr = (src_flags & Mem::ALIAS) ?
mm.GetAliasDevicePtr(src_h_ptr, bytes, false) :
mm.GetDevicePtr(src_h_ptr, bytes, false);
MemoryType src_d_mt = (src_flags & Mem::ALIAS) ?
maps->aliases.at(src_h_ptr).mem->d_mt :
maps->memories.at(src_h_ptr).d_mt;
ctrl->Device(src_d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
const internal::Memory &base = maps->memories.at(dest_h_ptr);
const MemoryType d_mt = base.d_mt;
ctrl->Device(d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
}
}
@@ -1330,10 +1283,9 @@ void MemoryManager::CopyFromHost_(void *dest_h_ptr, const void *src_h_ptr,
void *dest_d_ptr = (dest_flags & Mem::ALIAS) ?
mm.GetAliasDevicePtr(dest_h_ptr, bytes, false) :
mm.GetDevicePtr(dest_h_ptr, bytes, false);
MemoryType dest_d_mt = (dest_flags & Mem::ALIAS) ?
maps->aliases.at(dest_h_ptr).mem->d_mt :
maps->memories.at(dest_h_ptr).d_mt;
ctrl->Device(dest_d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
const internal::Memory &base = maps->memories.at(dest_h_ptr);
const MemoryType d_mt = base.d_mt;
ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
}
dest_flags = dest_flags &
~(dest_on_host ? Mem::VALID_DEVICE : Mem::VALID_HOST);
+48 -13
View File
@@ -15,45 +15,80 @@
namespace mfem
{
int IntegerSet::PickRandomElement() const
IntegerSet::IntegerSet(IntegerSet &s)
: me(s.me.Size())
{
int i, size = Size();
for (int i = 0; i < me.Size(); i++)
{
me[i] = s.me[i];
}
}
IntegerSet& IntegerSet::operator=(const IntegerSet &s)
{
me.SetSize(s.me.Size());
for (int i = 0; i < me.Size(); i++)
{
me[i] = s.me[i];
}
return *this;
}
int IntegerSet::operator== (IntegerSet &s)
{
if (me.Size() != s.me.Size())
{
return 0;
}
for (int i = 0; i < me.Size(); i++)
if (me[i] != s.me[i])
{
return 0;
}
return 1;
}
int IntegerSet::PickRandomElement()
{
int i, size = me.Size();
unsigned int seed = 0;
for (i = 0; i < size; i++)
{
seed += data[i];
seed += me[i];
}
srand(seed);
return data[rand()/(RAND_MAX/size)];
return me[rand()/(RAND_MAX/size)];
}
void IntegerSet::Recreate(const int n, const int *p)
{
int i, j;
SetSize(n);
me.SetSize(n);
for (i = 0; i < n; i++)
{
data[i] = p[i];
me[i] = p[i];
}
Sort();
me.Sort();
for (j = 0, i = 1; i < n; i++)
if (data[i] != data[j])
if (me[i] != me[j])
{
data[++j] = data[i];
me[++j] = me[i];
}
SetSize(j+1);
me.SetSize(j+1);
}
int ListOfIntegerSets::Insert(const IntegerSet &s)
int ListOfIntegerSets::Insert(IntegerSet &s)
{
for (int i = 0; i < TheList.Size(); i++)
if (*TheList[i] == s)
@@ -66,7 +101,7 @@ int ListOfIntegerSets::Insert(const IntegerSet &s)
return TheList.Size()-1;
}
int ListOfIntegerSets::Lookup(const IntegerSet &s) const
int ListOfIntegerSets::Lookup(IntegerSet &s)
{
for (int i = 0; i < TheList.Size(); i++)
if (*TheList[i] == s)
@@ -78,7 +113,7 @@ int ListOfIntegerSets::Lookup(const IntegerSet &s) const
return -1;
}
void ListOfIntegerSets::AsTable(Table & t) const
void ListOfIntegerSets::AsTable(Table & t)
{
int i;
+29 -17
View File
@@ -20,26 +20,38 @@ namespace mfem
{
/// A set of integers
class IntegerSet : public Array<int>
class IntegerSet
{
private:
Array<int> me;
public:
using Array<int>::Array; ///< Inherit all Array constructors.
// MSVC fails to recognize that rule of zero applies after using base class
// constructors.
IntegerSet() = default; ///< Default construct and empty set.
IntegerSet(const IntegerSet &) = default; ///< Copy constructor.
IntegerSet(IntegerSet &&) = default; ///< Move constructor.
IntegerSet& operator=(const IntegerSet &) = default; ///< Copy assignment.
IntegerSet& operator=(IntegerSet &&) = default; ///< Move assignment.
/// Create an empty set.
IntegerSet() { }
/// Create a copy of set 's'.
IntegerSet(IntegerSet &s);
/// Create an integer set from C-array 'p' of 'n' integers.
IntegerSet(const int n, const int *p) { Recreate(n, p); }
/// Return the size of the set.
int Size() { return me.Size(); }
/// Return a reference to the sorted array of all the set entries.
operator Array<int>& () { return me; }
/// Return the value of the lowest element of the set.
int PickElement() const { return data[0]; }
int PickElement() { return me[0]; }
/// Return the value of a random element of the set.
int PickRandomElement() const;
int PickRandomElement();
/// Create a copy of set 's'.
IntegerSet& operator=(const IntegerSet &s);
/// Return 1 if the sets are equal and 0 otherwise.
int operator==(IntegerSet &s);
/** @brief Create an integer set from C-array 'p' of 'n' integers.
Overwrites any existing set data. */
@@ -55,25 +67,25 @@ private:
public:
/// Return the number of integer sets in the list.
int Size() const { return TheList.Size(); }
int Size() { return TheList.Size(); }
/// Return the value of the first element of the ith set.
int PickElementInSet(int i) const { return TheList[i]->PickElement(); }
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
/// Return a random value from the ith set in the list.
int PickRandomElementInSet(int i) const { return TheList[i]->PickRandomElement(); }
int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); }
/** @brief Check to see if set 's' is in the list. If not append it to the
end of the list. Returns the index of the list where set 's' can be
found. */
int Insert(const IntegerSet &s);
int Insert(IntegerSet &s);
/** Return the index of the list where set 's' can be found. Returns -1 if
not found. */
int Lookup(const IntegerSet &s) const;
int Lookup(IntegerSet &s);
/// Write the list of sets into table 't'.
void AsTable(Table &t) const;
void AsTable(Table &t);
~ListOfIntegerSets();
};
+3 -4
View File
@@ -10,7 +10,7 @@
// CONTRIBUTING.md for details.
#ifdef _WIN32
// Turn off CRT deprecation warnings for strerror
// Turn off CRT deprecation warnings for strerror (VS 2013)
#define _CRT_SECURE_NO_WARNINGS
#endif
@@ -30,13 +30,13 @@
#include <ws2tcpip.h>
#ifdef _MSC_VER
typedef int ssize_t;
typedef int socklen_t;
// Link with ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#endif
#endif
#ifdef MFEM_USE_GNUTLS
#include <cstdlib> // getenv
#ifndef MFEM_USE_GNUTLS_X509
#include <gnutls/openpgp.h>
#endif
@@ -146,8 +146,7 @@ int socketbuf::open(const char hostname[], int port)
}
#endif
if (connect(socket_descriptor, rp->ai_addr,
static_cast<socklen_t>(rp->ai_addrlen)) < 0)
if (connect(socket_descriptor, rp->ai_addr, rp->ai_addrlen) < 0)
{
closesocket(socket_descriptor);
socket_descriptor = -2;
+2 -2
View File
@@ -24,7 +24,7 @@ list(APPEND SRCS
constraints.cpp
densemat.cpp
symmat.cpp
op_handle.cpp
handle.cpp
matrix.cpp
ode.cpp
operator.cpp
@@ -51,7 +51,7 @@ list(APPEND HDRS
dinvariants.hpp
symmat.hpp
dtensor.hpp
op_handle.hpp
handle.hpp
invariants.hpp
kernels.hpp
lapack.hpp
+2 -14
View File
@@ -52,9 +52,9 @@ BatchedLinAlg &BatchedLinAlg::Instance()
}
void BatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x, Vector &y,
real_t alpha, real_t beta, Op op)
real_t alpha, real_t beta)
{
Get(Instance().active_backend).AddMult(A, x, y, alpha, beta, op);
Get(Instance().active_backend).AddMult(A, x, y, alpha, beta);
}
void BatchedLinAlg::Mult(const DenseTensor &A, const Vector &x, Vector &y)
@@ -62,12 +62,6 @@ void BatchedLinAlg::Mult(const DenseTensor &A, const Vector &x, Vector &y)
Get(Instance().active_backend).Mult(A, x, y);
}
void BatchedLinAlg::MultTranspose(const DenseTensor &A, const Vector &x,
Vector &y)
{
Get(Instance().active_backend).MultTranspose(A, x, y);
}
void BatchedLinAlg::Invert(DenseTensor &A)
{
Get(Instance().active_backend).Invert(A);
@@ -113,10 +107,4 @@ void BatchedLinAlgBase::Mult(const DenseTensor &A, const Vector &x,
AddMult(A, x, y, 1.0, 0.0);
}
void BatchedLinAlgBase::MultTranspose(const DenseTensor &A, const Vector &x,
Vector &y) const
{
AddMult(A, x, y, 1.0, 0.0, Op::T);
}
}
+6 -23
View File
@@ -48,14 +48,6 @@ public:
/// Counter for the number of backends.
NUM_BACKENDS
};
/// Operation type (transposed or not transposed)
enum Op
{
N, ///< Not transposed.
T ///< Transposed.
};
private:
/// All available backends. Unavailble backends will be nullptr.
std::array<std::unique_ptr<class BatchedLinAlgBase>,
@@ -66,19 +58,15 @@ private:
/// Return the singleton instance.
static BatchedLinAlg &Instance();
public:
/// @brief Computes $y = \alpha A^{op} x + \beta y$.
/// @brief Computes $y = \alpha A x + \beta y$.
///
/// $A^{op}$ is either $A$ or $A^T$ depending on the value of @a op.
/// $A$ is a block diagonal matrix, represented by the DenseTensor @a A with
/// shape (m, n, n_mat). $x$ has shape (tr?m:n, k, n_mat), and $y$ has shape
/// (tr?n:m, k, n_mat), where 'tr' is true in the transposed case.
/// shape (m, n, n_mat). $x$ has shape (n, k, n_mat), and $y$ has shape
/// (m, k, n_mat).
static void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
real_t alpha = 1.0, real_t beta = 1.0,
Op op = Op::N);
/// Computes $y = A x$ (e.g. by calling @ref AddMult "AddMult(A,x,y,1,0,Op::N)").
real_t alpha = 1.0, real_t beta = 1.0);
/// Computes $y = A x$ (e.g. by calling @ref AddMult "AddMult(A,x,y,1,0)").
static void Mult(const DenseTensor &A, const Vector &x, Vector &y);
/// Computes $y = A^T x$ (e.g. by calling @ref AddMult "AddMult(A,x,y,1,0,Op::T)").
static void MultTranspose(const DenseTensor &A, const Vector &x, Vector &y);
/// @brief Replaces the block diagonal matrix $A$ with its inverse $A^{-1}$.
///
/// $A$ is represented by the DenseTensor @a A with shape (m, m, n_mat).
@@ -121,16 +109,11 @@ public:
class BatchedLinAlgBase
{
public:
using Op = BatchedLinAlg::Op;
/// See BatchedLinAlg::AddMult.
virtual void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
real_t alpha = 1.0, real_t beta = 1.0,
Op op = Op::N) const = 0;
real_t alpha = 1.0, real_t beta = 1.0) const = 0;
/// See BatchedLinAlg::Mult.
virtual void Mult(const DenseTensor &A, const Vector &x, Vector &y) const;
/// See BatchedLinAlg::MultTranspose.
virtual void MultTranspose(const DenseTensor &A, const Vector &x,
Vector &y) const;
/// See BatchedLinAlg::Invert.
virtual void Invert(DenseTensor &A) const = 0;
/// See BatchedLinAlg::LUFactor.
+10 -14
View File
@@ -82,27 +82,23 @@ void GPUBlas::DisableAtomics()
}
void GPUBlasBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
Vector &y, real_t alpha, real_t beta,
Op op) const
Vector &y, real_t alpha, real_t beta) const
{
const bool tr = (op == Op::T);
const int m = tr ? A.SizeJ() : A.SizeI();
const int n = tr ? A.SizeI() : A.SizeJ();
const int m = A.SizeI();
const int n = A.SizeJ();
const int n_mat = A.SizeK();
const int k = x.Size() / n / n_mat;
auto d_A = A.Read();
auto d_x = x.Read(); // Shape: (n, k, n_mat)
auto d_y = beta == 0.0 ? y.Write() : y.ReadWrite(); // Shape (m, k, n_mat)
auto d_A = mfem::Reshape(A.Read(), m, n, n_mat);
auto d_x = mfem::Reshape(x.Read(), n, k, n_mat);
auto d_y = mfem::Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(), m, k, n_mat);
const auto op_A = tr ? MFEM_CU_or_HIP(BLAS_OP_T) : MFEM_CU_or_HIP(BLAS_OP_N);
const auto op_B = MFEM_CU_or_HIP(BLAS_OP_N);
const auto op = MFEM_CU_or_HIP(BLAS_OP_N);
const blasStatus_t status = MFEM_GPUBLAS_PREFIX(gemmStridedBatched)(
GPUBlas::Handle(), op_A, op_B, m, k, n,
&alpha, d_A, m, m*n, d_x, n, n*k, &beta, d_y,
m, m*k, n_mat);
GPUBlas::Handle(), op, op, m, k, n, &alpha,
d_A, m, m*n, d_x, n, n*k, &beta, d_y, m, m*k,
n_mat);
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "GPU BLAS error.");
}
+1 -2
View File
@@ -57,8 +57,7 @@ class GPUBlasBatchedLinAlg : public BatchedLinAlgBase
{
public:
void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
real_t alpha = 1.0, real_t beta = 1.0,
Op op = Op::N) const override;
real_t alpha = 1.0, real_t beta = 1.0) const override;
void Invert(DenseTensor &A) const override;
void LUFactor(DenseTensor &A, Array<int> &P) const override;
void LUSolve(const DenseTensor &LU, const Array<int> &P,
+7 -12
View File
@@ -54,24 +54,19 @@ magma_queue_t Magma::Queue()
}
void MagmaBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
Vector &y, real_t alpha, real_t beta,
Op op) const
Vector &y, real_t alpha, real_t beta) const
{
const bool tr = (op == Op::T);
const int m = tr ? A.SizeJ() : A.SizeI();
const int n = tr ? A.SizeI() : A.SizeJ();
const int m = A.SizeI();
const int n = A.SizeJ();
const int n_mat = A.SizeK();
const int k = x.Size() / n / n_mat;
auto d_A = A.Read();
auto d_x = x.Read(); // Shape (n, k, n_mat);
auto d_y = beta == 0.0 ? y.Write() : y.ReadWrite(); // Shape (m, k, n_mat);
magma_trans_t magma_op = tr ? MagmaNoTrans : MagmaTrans;
auto d_A = mfem::Reshape(A.Read(), m, n, n_mat);
auto d_x = mfem::Reshape(x.Read(), n, k, n_mat);
auto d_y = mfem::Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(), m, k, n_mat);
MFEM_MAGMABLAS_PREFIX(gemm_batched_strided)(
magma_op, MagmaNoTrans, m, k, n, alpha, d_A, m, m*n, d_x, n, n*k,
MagmaNoTrans, MagmaNoTrans, m, k, n, alpha, d_A, m, m*n, d_x, n, n*k,
beta, d_y, m, m*k, n_mat, Magma::Queue());
}
+1 -2
View File
@@ -25,8 +25,7 @@ class MagmaBatchedLinAlg : public BatchedLinAlgBase
{
public:
void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
real_t alpha = 1.0, real_t beta = 1.0,
Op op = Op::N) const override;
real_t alpha = 1.0, real_t beta = 1.0) const override;
void Invert(DenseTensor &A) const override;
void LUFactor(DenseTensor &A, Array<int> &P) const override;
void LUSolve(const DenseTensor &A, const Array<int> &P,
+17 -110
View File
@@ -18,37 +18,22 @@ namespace mfem
{
void NativeBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
Vector &y, real_t alpha, real_t beta,
Op op) const
Vector &y, real_t alpha, real_t beta) const
{
const bool tr = (op == Op::T);
const int m = A.SizeI();
const int n = A.SizeJ();
const int n_mat = A.SizeK();
const int k = x.Size() / (tr ? m : n) / n_mat;
const int k = x.Size() / n / n_mat;
auto d_A = Reshape(A.Read(), m, n, n_mat);
auto d_x = Reshape(x.Read(), (tr ? m : n), k, n_mat);
auto d_y = Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(),
(tr ? n : m), k, n_mat);
auto d_A = mfem::Reshape(A.Read(), m, n, n_mat);
auto d_x = mfem::Reshape(x.Read(), n, k, n_mat);
auto d_y = mfem::Reshape(beta == 0.0 ? y.Write() : y.ReadWrite(), m, k, n_mat);
if (tr)
mfem::forall(n_mat, [=] MFEM_HOST_DEVICE (int i)
{
mfem::forall(n_mat, [=] MFEM_HOST_DEVICE (int i)
{
kernels::AddMultAtB(m, n, k, &d_A(0,0,i), &d_x(0,0,i), &d_y(0,0,i),
alpha, beta);
});
}
else
{
mfem::forall(n_mat, [=] MFEM_HOST_DEVICE (int i)
{
kernels::AddMult(m, k, n, &d_A(0,0,i), &d_x(0,0,i), &d_y(0,0,i),
alpha, beta);
});
}
kernels::AddMult(m, k, n, &d_A(0,0,i), &d_x(0,0,i), &d_y(0,0,i),
alpha, beta);
});
// Alternative approach, threading also over the second index. Which one is
// better?
@@ -63,85 +48,7 @@ void NativeBatchedLinAlg::AddMult(const DenseTensor &A, const Vector &x,
void NativeBatchedLinAlg::Invert(DenseTensor &A) const
{
const int m = A.SizeI();
const int NE = A.SizeK();
DenseTensor LU = A;
Array<int> P(m*NE);
LUFactor(LU, P);
auto data_all = Reshape(LU.Read(), m, m, NE);
auto piv_all = Reshape(P.Read(), m, NE);
auto inv_all = Reshape(A.Write(), m, m, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
// A^{-1} = U^{-1} L^{-1} P
// X <- U^{-1} (set only the upper triangular part of X)
real_t *X = &inv_all(0, 0, e);
real_t *x = X;
const real_t *data = &data_all(0, 0, e);
const int *ipiv = &piv_all(0, e);
for (int k = 0; k < m; k++)
{
const real_t minus_x_k = -(x[k] = 1.0 / data[k + k * m]);
for (int i = 0; i < k; i++)
{
x[i] = data[i + k * m] * minus_x_k;
}
for (int j = k - 1; j >= 0; j--)
{
const real_t x_j = (x[j] /= data[j + j * m]);
for (int i = 0; i < j; i++)
{
x[i] -= data[i + j * m] * x_j;
}
}
x += m;
}
// X <- X L^{-1} (use input only from the upper triangular part of X)
{
int k = m - 1;
for (int j = 0; j < k; j++)
{
const real_t minus_L_kj = -data[k + j * m];
for (int i = 0; i <= j; i++)
{
X[i + j * m] += X[i + k * m] * minus_L_kj;
}
for (int i = j + 1; i < m; i++)
{
X[i + j * m] = X[i + k * m] * minus_L_kj;
}
}
}
for (int k = m - 2; k >= 0; k--)
{
for (int j = 0; j < k; j++)
{
const real_t L_kj = data[k + j * m];
for (int i = 0; i < m; i++)
{
X[i + j * m] -= X[i + k * m] * L_kj;
}
}
}
// X <- X P
for (int k = m - 1; k >= 0; k--)
{
const int piv_k = ipiv[k];
if (k != piv_k)
{
for (int i = 0; i < m; i++)
{
kernels::internal::Swap(X[i + k * m], X[i + piv_k * m]);
}
}
}
});
MFEM_ABORT("");
}
void NativeBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
@@ -151,8 +58,8 @@ void NativeBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
const int NE = A.SizeK();
P.SetSize(m*NE);
auto data_all = Reshape(A.ReadWrite(), m, m, NE);
auto ipiv_all = Reshape(P.Write(), m, NE);
auto data_all = mfem::Reshape(A.ReadWrite(), m, m, NE);
auto ipiv_all = mfem::Reshape(P.Write(), m, NE);
Array<bool> pivot_flag(1);
pivot_flag[0] = true;
bool *d_pivot_flag = pivot_flag.ReadWrite();
@@ -180,12 +87,12 @@ void NativeBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
// swap rows i and piv in both L and U parts
for (int j = 0; j < m; j++)
{
kernels::internal::Swap<real_t>(data_all(i,j,e), data_all(piv,j,e));
mfem::kernels::internal::Swap<real_t>(data_all(i,j,e), data_all(piv,j,e));
}
}
} // pivot end
if (std::abs(data_all(i,i,e)) <= tol)
if (abs(data_all(i,i,e)) <= tol)
{
d_pivot_flag[0] = false;
}
@@ -217,9 +124,9 @@ void NativeBatchedLinAlg::LUSolve(const DenseTensor &LU, const Array<int> &P,
const int n_mat = LU.SizeK();
const int n_rhs = x.Size() / m / n_mat;
auto d_LU = Reshape(LU.Read(), m, m, n_mat);
auto d_P = Reshape(P.Read(), m, n_mat);
auto d_x = Reshape(x.Write(), m, n_rhs, n_mat);
auto d_LU = mfem::Reshape(LU.Read(), m, m, n_mat);
auto d_P = mfem::Reshape(P.Read(), m, n_mat);
auto d_x = mfem::Reshape(x.Write(), m, n_rhs, n_mat);
mfem::forall(n_mat * n_rhs, [=] MFEM_HOST_DEVICE (int idx)
{
+1 -1
View File
@@ -21,7 +21,7 @@ class NativeBatchedLinAlg : public BatchedLinAlgBase
{
public:
void AddMult(const DenseTensor &A, const Vector &x, Vector &y,
real_t alpha, real_t beta, Op op) const override;
real_t alpha, real_t beta) const override;
void Invert(DenseTensor &A) const override;
void LUFactor(DenseTensor &A, Array<int> &P) const override;
void LUSolve(const DenseTensor &LU, const Array<int> &P,
-25
View File
@@ -1174,31 +1174,6 @@ public:
tdata.Wrap(ext_data, i*j*k, false);
}
/// @brief Reset the DenseTensor to use the given external Memory @a mem and
/// dimensions @a i, @a j, and @a k.
///
/// If @a own_mem is false, the DenseTensor will not own any of the pointers
/// of @a mem.
///
/// Note that when @a own_mem is true, the @a mem object can be destroyed
/// immediately by the caller but `mem.Delete()` should NOT be called since
/// the DenseTensor object takes ownership of all pointers owned by @a mem.
void NewMemoryAndSize(const Memory<real_t> &mem, int i, int j, int k,
bool own_mem)
{
tdata.Delete();
Mk.UseExternalData(NULL, i, j);
nk = k;
if (own_mem)
{
tdata = mem;
}
else
{
tdata.MakeAlias(mem, 0, i*j*k);
}
}
/// Sets the tensor elements equal to constant c
DenseTensor &operator=(real_t c);
+3 -3
View File
@@ -9,7 +9,7 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "op_handle.hpp"
#include "handle.hpp"
#include "sparsemat.hpp"
#ifdef MFEM_USE_MPI
#include "petsc.hpp"
@@ -17,8 +17,8 @@
// Make sure that hypre and PETSc use the same size indices.
#if defined(MFEM_USE_MPI) && defined(MFEM_USE_PETSC)
#if ((defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT)) && !defined(PETSC_USE_64BIT_INDICES)) || \
(!defined(HYPRE_BIGINT) && !defined(HYPRE_MIXEDINT) && defined(PETSC_USE_64BIT_INDICES))
#if (defined(HYPRE_BIGINT) && !defined(PETSC_USE_64BIT_INDICES)) || \
(!defined(HYPRE_BIGINT) && defined(PETSC_USE_64BIT_INDICES))
#error HYPRE and PETSC do not use the same size integers!
#endif
#endif
+2 -2
View File
@@ -9,8 +9,8 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_OP_HANDLE_HPP
#define MFEM_OP_HANDLE_HPP
#ifndef MFEM_HANDLE_HPP
#define MFEM_HANDLE_HPP
#include "../config/config.hpp"
#include "operator.hpp"
+16 -67
View File
@@ -28,23 +28,16 @@ namespace mfem
{
bool Hypre::configure_runtime_policy_from_mfem = true;
Hypre::State Hypre::state = Hypre::State::UNINITIALIZED;
void Hypre::Init()
Hypre::Hypre()
{
if (state != State::INITIALIZED)
{
#if MFEM_HYPRE_VERSION >= 21900
HYPRE_Init();
// Initializing hypre
HYPRE_Init();
#endif
SetDefaultOptions();
// Apply the setting of 'configure_runtime_policy_from_mfem' according to
// the current configuration of the mfem::Device (HYPRE >= 2.31.0):
InitDevice();
// Create the singleton Hypre object AFTER initializing HYPRE:
Instance();
}
state = State::INITIALIZED;
// Global hypre options that we set by default
SetDefaultOptions();
}
void Hypre::InitDevice()
@@ -55,8 +48,6 @@ void Hypre::InitDevice()
#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
if (configure_runtime_policy_from_mfem)
{
MFEM_VERIFY(HYPRE_Initialized(), "HYPRE must be initialized before"
" calling Hypre::InitDevice()");
if (Device::Allows(Backend::DEVICE_MASK & ~Backend::DEBUG_DEVICE))
{
HYPRE_SetMemoryLocation(HYPRE_MEMORY_DEVICE);
@@ -74,13 +65,14 @@ void Hypre::InitDevice()
void Hypre::Finalize()
{
if (state != State::UNINITIALIZED)
Hypre &hypre = Instance();
if (!hypre.finalized)
{
#if MFEM_HYPRE_VERSION >= 21900
HYPRE_Finalize();
#endif
hypre.finalized = true;
}
state = State::UNINITIALIZED;
}
void Hypre::SetDefaultOptions()
@@ -219,24 +211,6 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
own_ParVector = 1;
}
HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
Vector &base, int offset, HYPRE_BigInt *col)
: HypreParVector(comm, glob_size, nullptr, col, false)
{
MFEM_ASSERT(CanShallowCopy(base.GetMemory(), GetHypreMemoryClass()),
"the MemoryTypes of 'base' are incompatible with Hypre!");
MFEM_ASSERT(offset + size <= base.Size(),
"the size of 'base' is too small!");
data.Delete();
data.MakeAlias(base.GetMemory(), offset, size);
hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
hypre_VectorData(x_loc) = data.ReadWrite(GetHypreMemoryClass(), size);
#ifdef HYPRE_USING_GPU
hypre_VectorMemoryLocation(x_loc) = GetHypreMemoryLocation();
#endif
}
// Call the move constructor on the "compatible" temp vector
HypreParVector::HypreParVector(const HypreParVector &y) : HypreParVector(
y.CreateCompatibleVector())
@@ -1606,12 +1580,14 @@ void HypreParMatrix::GetDiag(Vector &diag) const
{
const int size = Height();
diag.SetSize(size);
auto hypre_ml = GetHypreMemoryLocation();
// Avoid using GetHypreMemoryClass() since it may be MemoryClass::MANAGED and
// that may not play well with the memory types used by 'diag'.
MemoryClass hypre_mc = GetHypreForallMemoryClass();
MemoryClass hypre_mc = (hypre_ml == HYPRE_MEMORY_HOST) ?
MemoryClass::HOST : MemoryClass::DEVICE;
real_t *diag_hd = diag.GetMemory().Write(hypre_mc, size);
#if MFEM_HYPRE_VERSION >= 21800
MFEM_VERIFY(A->diag->memory_location == GetHypreMemoryLocation(),
MFEM_VERIFY(A->diag->memory_location == hypre_ml,
"unexpected HypreParMatrix memory location!");
#endif
const HYPRE_Int *A_diag_i = A->diag->i;
@@ -2518,7 +2494,7 @@ void HypreParMatrix::EliminateBC(const Array<int> &ess_dofs,
const int n_ess_dofs = ess_dofs.Size();
const auto ess_dofs_d = ess_dofs.GetMemory().Read(
GetHypreForallMemoryClass(), n_ess_dofs);
GetHypreMemoryClass(), n_ess_dofs);
// Start communication to figure out which columns need to be eliminated in
// the off-diagonal block
@@ -2801,33 +2777,6 @@ void HypreParMatrix::PrintHash(std::ostream &os) const
os << "col map offd hash : " << hf.GetHash() << '\n';
}
real_t HypreParMatrix::FNorm() const
{
real_t norm_fro = 0.0;
if (A != NULL)
#if MFEM_HYPRE_VERSION >= 21900
{
const int ierr = hypre_ParCSRMatrixNormFro(A, &norm_fro);
MFEM_VERIFY(ierr == 0, "");
}
#else
{
// HYPRE_USING_GPU is not defined for
// MFEM_HYPRE_VERSION < 22100 and so here it is
// guaranteed that the matrix is in "host" memory
Vector Avec_diag(A->diag->data, A->diag->num_nonzeros);
real_t normsqr_fro = InnerProduct(Avec_diag, Avec_diag);
Vector Avec_offd(A->offd->data, A->offd->num_nonzeros);
normsqr_fro += InnerProduct(Avec_offd, Avec_offd);
MPI_Allreduce(MPI_IN_PLACE, &normsqr_fro, 1, MPITypeMap<real_t>::mpi_type,
MPI_SUM, hypre_ParCSRMatrixComm(A));
norm_fro = sqrt(normsqr_fro);
}
#endif
return norm_fro;
}
inline void delete_hypre_ParCSRMatrixColMapOffd(hypre_ParCSRMatrix *A)
{
HYPRE_BigInt *A_col_map_offd = hypre_ParCSRMatrixColMapOffd(A);
@@ -5363,8 +5312,8 @@ void HypreBoomerAMG::SetAdvectiveOptions(int distanceR,
int ns_down = 0, ns_up = 0, ns_coarse; // init to suppress gcc warnings
if (distanceR > 0)
{
ns_down = static_cast<int>(prerelax.length());
ns_up = static_cast<int>(postrelax.length());
ns_down = prerelax.length();
ns_up = postrelax.length();
ns_coarse = 1;
// Array to store relaxation scheme and pass to Hypre
+12 -36
View File
@@ -68,11 +68,10 @@ class Hypre
public:
/// @brief Initialize hypre by calling HYPRE_Init() and set default options.
/// After calling Hypre::Init(), hypre will be finalized automatically at
/// program exit. May be re-initialized after finalize.
/// program exit.
///
/// Calling HYPRE_Init() or HYPRE_Finalize() manually is only supported for
/// HYPRE 2.29.0+
static void Init();
/// Calling HYPRE_Finalize() manually is not compatible with this class.
static void Init() { Instance(); }
/// @brief Configure HYPRE's compute and memory policy.
///
@@ -95,9 +94,6 @@ public:
///
/// Multiple calls to Hypre::Finalize() have no effect. This function can be
/// called manually to more precisely control when hypre is finalized.
///
/// Calling HYPRE_Init() or HYPRE_Finalize() manually is only supported for
/// HYPRE 2.29.0+
static void Finalize();
/// @brief Use MFEM's device policy to configure HYPRE's device policy, true
@@ -108,20 +104,14 @@ public:
static bool configure_runtime_policy_from_mfem;
private:
/// Default constructor. Singleton object; private.
Hypre() = default;
/// Copy constructor. Deleted.
Hypre(Hypre&) = delete;
/// Move constructor. Deleted.
Hypre(Hypre&&) = delete;
/// Calls HYPRE_Init() when the singleton is constructed.
Hypre();
/// The singleton destructor (called at program exit) finalizes hypre.
~Hypre() { Finalize(); }
/// Set the default hypre global options (mostly GPU-relevant).
static void SetDefaultOptions();
void SetDefaultOptions();
/// Create and return the Hypre singleton object.
static Hypre &Instance()
@@ -130,10 +120,7 @@ private:
return hypre;
}
enum class State { UNINITIALIZED, INITIALIZED };
/// Tracks whether Hypre was initialized or finalized by this class.
static State state;
bool finalized = false; ///< Has Hypre::Finalize() been called already?
};
@@ -260,12 +247,6 @@ public:
allocated in the memory location HYPRE_MEMORY_DEVICE. */
HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size, real_t *data_,
HYPRE_BigInt *col, bool is_device_ptr = false);
/** @brief Creates a vector that uses the data of the Vector @a base,
starting at the given @a offset. */
/** The @a base Vector must have memory types compatible with the MemoryClass
returned by GetHypreMemoryClass(). */
HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size, Vector &base,
int offset, HYPRE_BigInt *col);
/// Creates a deep copy of @a y
HypreParVector(const HypreParVector &y);
/// Move constructor for HypreParVector. "Steals" data from its argument.
@@ -331,8 +312,7 @@ public:
/// Sets the data of the Vector and the hypre_ParVector to @a data_.
/** Must be used only for HypreParVector%s that do not own the data,
e.g. created with the constructor:
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
*/
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *). */
void SetData(real_t *data_);
/** @brief Prepare the HypreParVector for read access in hypre's device
@@ -352,7 +332,7 @@ public:
HYPRE_MEMORY_DEVICE. */
/** This method must be used with HypreParVector%s that do not own the data,
e.g. created with the constructor:
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *).
The Memory @a mem must be accessible with the hypre MemoryClass defined
by GetHypreMemoryClass(). */
@@ -363,7 +343,7 @@ public:
space, HYPRE_MEMORY_DEVICE. */
/** This method must be used with HypreParVector%s that do not own the data,
e.g. created with the constructor:
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *).
The Memory @a mem must be accessible with the hypre MemoryClass defined
by GetHypreMemoryClass(). */
@@ -374,7 +354,7 @@ public:
HYPRE_MEMORY_DEVICE. */
/** This method must be used with HypreParVector%s that do not own the data,
e.g. created with the constructor:
HypreParVector(MPI_Comm, HYPRE_BigInt, real_t *, HYPRE_BigInt *, bool).
HypreParVector(MPI_Comm, HYPRE_BigInt, double *, HYPRE_BigInt *).
The Memory @a mem must be accessible with the hypre MemoryClass defined
by GetHypreMemoryClass(). */
@@ -413,7 +393,7 @@ private:
/// Auxiliary vectors for typecasting
mutable HypreParVector *X, *Y;
/** @brief Auxiliary buffers for the case when the input or output arrays in
methods like Mult(real_t, const Vector &, real_t, Vector &) need to be
methods like Mult(double, const Vector &, double, Vector &) need to be
deep copied in order to be used by hypre. */
mutable Memory<real_t> auxX, auxY;
@@ -958,10 +938,6 @@ public:
without the need to save the whole matrix. */
void PrintHash(std::ostream &out) const;
/// @brief Return the Frobenius norm of the matrix (or 0 if the underlying
/// hypre matrix is NULL)
real_t FNorm() const;
/// Calls hypre's destroy function
virtual ~HypreParMatrix() { Destroy(); }
+14 -38
View File
@@ -402,43 +402,6 @@ void MultABt(const int Aheight, const int Awidth, const int Bheight,
}
}
/** @brief Compute C = alpha*At*B + beta*C.
Multiply the transpose of a matrix of size @a Aheight x @a Awidth and data
@a Adata with a matrix of size @a Aheight x @a Bwidth and data @a Bdata. */
template<typename TA, typename TB, typename TC>
MFEM_HOST_DEVICE inline
void AddMultAtB(const int Aheight, const int Awidth, const int Bwidth,
const TA *Adata, const TB *Bdata, TC *Cdata, const TB alpha,
const TA beta)
{
const int aw_x_bw = Awidth * Bwidth;
if (beta == 0.0)
{
for (int i = 0; i < aw_x_bw; i++) { Cdata[i] = 0.0; }
}
else if (beta != 1.0)
{
for (int i = 0; i < aw_x_bw; i++) { Cdata[i] *= beta; }
}
TC *c = Cdata;
for (int i = 0; i < Bwidth; ++i)
{
for (int j = 0; j < Awidth; ++j)
{
TC val = 0.0;
for (int k = 0; k < Aheight; ++k)
{
val += alpha * Adata[j * Aheight + k] * Bdata[i * Aheight + k];
}
*c += val;
c++;
}
}
}
/** @brief Multiply the transpose of a matrix of size @a Aheight x @a Awidth
and data @a Adata with a matrix of size @a Aheight x @a Bwidth and data @a
Bdata: At * B. Return the result in a matrix with data @a AtBdata. */
@@ -447,7 +410,20 @@ MFEM_HOST_DEVICE inline
void MultAtB(const int Aheight, const int Awidth, const int Bwidth,
const TA *Adata, const TB *Bdata, TC *AtBdata)
{
AddMultAtB(Aheight, Awidth, Bwidth, Adata, Bdata, AtBdata, TB(1.0), TA(0.0));
TC *c = AtBdata;
for (int i = 0; i < Bwidth; ++i)
{
for (int j = 0; j < Awidth; ++j)
{
TC val = 0.0;
for (int k = 0; k < Aheight; ++k)
{
val += Adata[j * Aheight + k] * Bdata[i * Aheight + k];
}
*c = val;
c++;
}
}
}
/// Given a matrix of size 2x1, 3x1, or 3x2, compute the left inverse.
+1 -1
View File
@@ -28,7 +28,7 @@
#include "symmat.hpp"
#include "ode.hpp"
#include "solvers.hpp"
#include "op_handle.hpp"
#include "handle.hpp"
#include "invariants.hpp"
#include "constraints.hpp"
#include "auxiliary.hpp"
+235 -315
View File
@@ -9,155 +9,12 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/communication.hpp"
#include "operator.hpp"
#include "ode.hpp"
namespace mfem
{
std::string ODESolver::ExplicitTypes =
"\n\tExplicit solver: \n\t"
" RK : 1 - Forward Euler, 2 - RK2(0.5), 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
" AB : 11 - AB1, 12 - AB2, 13 - AB3, 14 - AB4, 15 - AB5\n";
std::string ODESolver::ImplicitTypes =
"\n\tImplicit solver: \n\t"
" (L-Stab): 21 - Backward Euler, 22 - SDIRK23(2), 23 - SDIRK33,\n\t"
" (A-Stab): 32 - Implicit Midpoint, 33 - SDIRK23, 34 - SDIRK34,\n\t"
" GA : 40 -- 50 - Generalized-alpha,\n\t"
" AM : 51 - AM1, 52 - AM2, 53 - AM3, 54 - AM4\n";
std::string ODESolver::Types = ODESolver::ExplicitTypes +
ODESolver::ImplicitTypes;
std::unique_ptr<ODESolver> ODESolver::Select(int ode_solver_type)
{
if (ode_solver_type < 20)
{
return SelectExplicit(ode_solver_type);
}
else
{
return SelectImplicit(ode_solver_type);
}
}
std::unique_ptr<ODESolver> ODESolver::SelectExplicit(int ode_solver_type)
{
using ode_ptr = std::unique_ptr<ODESolver>;
switch (ode_solver_type)
{
// Explicit RK methods
case 1: return ode_ptr(new ForwardEulerSolver);
case 2: return ode_ptr(new RK2Solver(0.5)); // midpoint method
case 3: return ode_ptr(new RK3SSPSolver);
case 4: return ode_ptr(new RK4Solver);
case 6: return ode_ptr(new RK6Solver);
// Explicit AB methods
case 11: return ode_ptr(new AB1Solver);
case 12: return ode_ptr(new AB2Solver);
case 13: return ode_ptr(new AB3Solver);
case 14: return ode_ptr(new AB4Solver);
case 15: return ode_ptr(new AB5Solver);
default:
MFEM_ABORT("Unknown ODE solver type: " << ode_solver_type);
}
}
std::unique_ptr<ODESolver> ODESolver::SelectImplicit(int ode_solver_type)
{
using ode_ptr = std::unique_ptr<ODESolver>;
switch (ode_solver_type)
{
// Implicit L-stable methods
case 21: return ode_ptr(new BackwardEulerSolver);
case 22: return ode_ptr(new SDIRK23Solver(2));
case 23: return ode_ptr(new SDIRK33Solver);
// Implicit A-stable methods (not L-stable)
case 32: return ode_ptr(new ImplicitMidpointSolver);
case 33: return ode_ptr(new SDIRK23Solver);
case 34: return ode_ptr(new SDIRK34Solver);
// Implicit generalized alpha
case 40: return ode_ptr(new GeneralizedAlphaSolver(0.0));
case 41: return ode_ptr(new GeneralizedAlphaSolver(0.1));
case 42: return ode_ptr(new GeneralizedAlphaSolver(0.2));
case 43: return ode_ptr(new GeneralizedAlphaSolver(0.3));
case 44: return ode_ptr(new GeneralizedAlphaSolver(0.4));
case 45: return ode_ptr(new GeneralizedAlphaSolver(0.5));
case 46: return ode_ptr(new GeneralizedAlphaSolver(0.6));
case 47: return ode_ptr(new GeneralizedAlphaSolver(0.7));
case 48: return ode_ptr(new GeneralizedAlphaSolver(0.8));
case 49: return ode_ptr(new GeneralizedAlphaSolver(0.9));
case 50: return ode_ptr(new GeneralizedAlphaSolver(1.0));
// Implicit AM methods
case 51: return ode_ptr(new AM1Solver);
case 52: return ode_ptr(new AM2Solver);
case 53: return ode_ptr(new AM3Solver);
case 54: return ode_ptr(new AM4Solver);
default:
MFEM_ABORT("Unknown ODE solver type: " << ode_solver_type );
}
}
void ODEStateDataVector::SetSize( int vsize, MemoryType m_t)
{
mem_type = m_t;
for (int i = 0; i < smax; i++)
{
idx[i] = smax - i - 1;
data[i].SetSize(vsize, mem_type);
}
ss = 0;
}
const Vector &ODEStateDataVector::Get(int i) const
{
MFEM_ASSERT_INDEX_IN_RANGE(i,0,ss);
return data[idx[i]];
}
Vector &ODEStateDataVector::Get(int i)
{
MFEM_ASSERT_INDEX_IN_RANGE(i,0,ss);
return data[idx[i]];
}
void ODEStateDataVector::Get(int i, Vector &vec) const
{
MFEM_ASSERT_INDEX_IN_RANGE(i,0,ss);
vec = data[idx[i]];
}
void ODEStateDataVector::Set(int i, Vector &state)
{
MFEM_ASSERT_INDEX_IN_RANGE(i,0,smax);
data[idx[i]] = state;
}
void ODEStateDataVector::Append(Vector &state)
{
ShiftStages();
data[idx[0]] = state;
Increment();
}
void ODEStateDataVector::Print(std::ostream &os) const
{
os << ss <<"/" <<smax<<std::endl;
idx.Print(os);
for (int i = 0; i < ss; i++) { data[idx[i]].Print(os); }
}
void ODESolver::Init(TimeDependentOperator &f_)
{
this->f = &f_;
@@ -487,65 +344,104 @@ const real_t RK8Solver::c[] =
};
AdamsBashforthSolver::AdamsBashforthSolver(int s_, const real_t *a_):
stages(s_), state(s_)
AdamsBashforthSolver::AdamsBashforthSolver(int s_, const real_t *a_)
{
smax = std::min(s_,5);
a = a_;
k = new Vector[5];
dt_ = -1.0;
if (smax <= 2)
{
RKsolver = new RK2Solver();
}
else if (smax == 3)
{
RKsolver = new RK3SSPSolver();
}
else
{
RKsolver = new RK4Solver();
}
}
void AdamsBashforthSolver::GetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i >= 0) && ( i < s ),
" AdamsBashforthSolver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
state = k[idx[i]];
}
const Vector &AdamsBashforthSolver::GetStateVector(int i)
{
MFEM_ASSERT( (i >= 0) && ( i < s ),
" AdamsBashforthSolver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
return k[idx[i]];
}
void AdamsBashforthSolver::SetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i >= 0) && ( i < smax ),
" AdamsBashforthSolver::SetStateVector \n" <<
" - Tried to set non-existent state "<<i);
k[idx[i]] = state;
s = std::max(i,s);
}
void AdamsBashforthSolver::Init(TimeDependentOperator &f_)
{
ODESolver::Init(f_);
if (RKsolver) { RKsolver->Init(f_); }
state.SetSize(f->Width(), mem_type);
dt_ = -1.0;
RKsolver->Init(f_);
idx.SetSize(smax);
for (int i = 0; i < smax; i++)
{
idx[i] = (smax-i)%smax;
k[i].SetSize(f->Width());
}
s = 0;
}
void AdamsBashforthSolver::Step(Vector &x, real_t &t, real_t &dt)
{
CheckTimestep(dt);
if (state.Size() >= stages -1)
if ( (dt_ > 0.0) && (fabs(dt-dt_) >10*std::numeric_limits<real_t>::epsilon()))
{
f->SetTime(t);
f->Mult(x, state[0]);
state.Increment();
for (int i = 0; i < stages; i++)
{
x.Add(a[i]*dt, state[i]);
}
t += dt;
}
else
{
f->Mult(x,state[0]);
RKsolver->Step(x,t,dt);
state.Increment();
}
state.ShiftStages();
}
void AdamsBashforthSolver::CheckTimestep(real_t dt)
{
if (dt_ < 0.0)
{
dt_ = dt;
return;
}
else if (fabs(dt-dt_) >10*std::numeric_limits<real_t>::epsilon())
{
state.Reset();
s = 0;
dt_ = dt;
if (print())
{
mfem::out << "WARNING:" << std::endl;
mfem::out << " - Time step changed" << std::endl;
mfem::out << " - Purging time stepping history" << std::endl;
mfem::out << " - Purging Adams-Bashforth history" << std::endl;
mfem::out << " - Will run Runge-Kutta to rebuild history" << std::endl;
}
}
s++;
s = std::min(s, smax);
if (s == smax)
{
f->SetTime(t);
f->Mult(x, k[idx[0]]);
for (int i = 0; i < s; i++)
{
x.Add(a[i]*dt, k[idx[i]]);
}
t += dt;
}
else
{
f->Mult(x,k[idx[0]]);
RKsolver->Step(x,t,dt);
}
// Shift the index
for (int i = 0; i < smax; i++) { idx[i] = ++idx[i]%smax; }
}
const real_t AB1Solver::a[] =
@@ -559,68 +455,110 @@ const real_t AB4Solver::a[] =
const real_t AB5Solver::a[] =
{1901.0/720.0,-2774.0/720.0, 2616.0/720.0,-1274.0/720.0, 251.0/720.0};
AdamsMoultonSolver::AdamsMoultonSolver(int s_, const real_t *a_):
stages(s_), state(s_)
AdamsMoultonSolver::AdamsMoultonSolver(int s_, const real_t *a_)
{
s = 0;
smax = std::min(s_+1,5);
a = a_;
k = new Vector[5];
dt_ = -1.0;
if (smax <= 3)
{
RKsolver = new SDIRK23Solver();
}
else
{
RKsolver = new SDIRK34Solver();
}
}
const Vector &AdamsMoultonSolver::GetStateVector(int i)
{
MFEM_ASSERT( (i >= 0) && ( i < s ),
" AdamsMoultonSolver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
return k[idx[i+1]];
}
void AdamsMoultonSolver::GetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i >= 0) && ( i < s ),
" AdamsMoultonSolver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
state = k[idx[i+1]];
}
void AdamsMoultonSolver::SetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i >= 0) && ( i < smax ),
" AdamsMoultonSolver::SetStateVector \n" <<
" - Tried to set non-existent state "<<i);
k[idx[i+1]] = state;
s = std::max(i,s);
}
void AdamsMoultonSolver::Init(TimeDependentOperator &f_)
{
ODESolver::Init(f_);
if (RKsolver) { RKsolver->Init(f_); }
state.SetSize(f->Width(), mem_type);
dt_ = -1.0;
RKsolver->Init(f_);
int n = f->Width();
idx.SetSize(smax);
for (int i = 0; i < smax; i++)
{
idx[i] = (smax-i)%smax;
k[i].SetSize(n);
}
s = 0;
}
void AdamsMoultonSolver::Step(Vector &x, real_t &t, real_t &dt)
{
if (dt_ < 0.0)
if ( (dt_ > 0.0) && (fabs(dt-dt_) >10*std::numeric_limits<real_t>::epsilon()))
{
dt_ = dt;
}
else if (fabs(dt-dt_) > 10*std::numeric_limits<real_t>::epsilon())
{
state.Reset();
s = 0;
dt_ = dt;
if (print())
{
mfem::out << "WARNING:" << std::endl;
mfem::out << " - Time step changed" << std::endl;
mfem::out << " - Purging time stepping history" << std::endl;
mfem::out << " - Purging Adams-Moulton history" << std::endl;
mfem::out << " - Will run Runge-Kutta to rebuild history" << std::endl;
}
}
if ((state.Size() == 0)&&(stages>1))
if ((s == 0)&&(smax>1))
{
f->Mult(x,state[0]);
state.Increment();
f->Mult(x,k[idx[1]]);
}
s++;
s = std::min(s, smax);
if (state.Size() >= stages )
if (s >= smax-1)
{
f->SetTime(t);
for (int i = 0; i < stages; i++)
for (int i = 1; i < smax; i++)
{
x.Add(a[i+1]*dt, state[i]);
x.Add(a[i]*dt, k[idx[i]]);
}
state.ShiftStages();
f->ImplicitSolve(a[0]*dt, x, state[0]);
x.Add(a[0]*dt, state[0]);
f->ImplicitSolve(a[0]*dt, x, k[idx[0]]);
x.Add(a[0]*dt, k[idx[0]]);
t += dt;
}
else
{
state.ShiftStages();
RKsolver->Step(x,t,dt);
f->Mult(x,state[0]);
state.Increment();
f->Mult(x,k[idx[0]]);
}
// Shift the index
for (int i = 0; i < smax; i++) { idx[i] = ++idx[i]%smax; }
}
const real_t AM0Solver::a[] =
{1.0};
const real_t AM1Solver::a[] =
{0.5, 0.5};
const real_t AM2Solver::a[] =
@@ -879,7 +817,34 @@ void GeneralizedAlphaSolver::Init(TimeDependentOperator &f_)
ODESolver::Init(f_);
k.SetSize(f->Width(), mem_type);
y.SetSize(f->Width(), mem_type);
state.SetSize(f->Width(), mem_type);
xdot.SetSize(f->Width(), mem_type);
xdot = 0.0;
nstate = 0;
}
const Vector &GeneralizedAlphaSolver::GetStateVector(int i)
{
MFEM_ASSERT( (i == 0) && (nstate == 1),
"GeneralizedAlphaSolver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
return xdot;
}
void GeneralizedAlphaSolver::GetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i == 0) && (nstate == 1),
"GeneralizedAlphaSolver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
state = xdot;
}
void GeneralizedAlphaSolver::SetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i == 0),
"GeneralizedAlphaSolver::SetStateVector \n" <<
" - Tried to set non-existent state "<<i);
xdot = state;
nstate = 1;
}
void GeneralizedAlphaSolver::SetRhoInf(real_t rho_inf)
@@ -919,17 +884,17 @@ void GeneralizedAlphaSolver::PrintProperties(std::ostream &os)
}
}
// This routine state[0] represents xdot
// This routine assumes xdot is initialized.
void GeneralizedAlphaSolver::Step(Vector &x, real_t &t, real_t &dt)
{
if (state.Size() == 0)
if (nstate == 0)
{
f->Mult(x,state[0]);
state.Increment();
f->Mult(x,xdot);
nstate = 1;
}
// Set y = x + alpha_f*(1.0 - (gamma/alpha_m))*dt*xdot
add(x, alpha_f*(1.0 - (gamma/alpha_m))*dt, state[0], y);
add(x, alpha_f*(1.0 - (gamma/alpha_m))*dt, xdot, y);
// Solve k = f(y + dt_eff*k)
real_t dt_eff = (gamma*alpha_f/alpha_m)*dt;
@@ -937,11 +902,11 @@ void GeneralizedAlphaSolver::Step(Vector &x, real_t &t, real_t &dt)
f->ImplicitSolve(dt_eff, y, k);
// Update x and xdot
x.Add((1.0 - (gamma/alpha_m))*dt, state[0]);
x.Add((1.0 - (gamma/alpha_m))*dt, xdot);
x.Add( (gamma/alpha_m) *dt, k);
state[0] *= (1.0-(1.0/alpha_m));
state[0].Add((1.0/alpha_m),k);
xdot *= (1.0-(1.0/alpha_m));
xdot.Add((1.0/alpha_m),k);
t += dt;
}
@@ -1052,75 +1017,18 @@ SIAVSolver::Step(Vector &q, Vector &p, real_t &t, real_t &dt)
}
}
std::string SecondOrderODESolver::Types =
"ODE solver: \n\t"
" [0--10] - GeneralizedAlpha(0.1 * s),\n\t"
" 11 - Average Acceleration, 12 - Linear Acceleration\n\t"
" 13 - CentralDifference, 14 - FoxGoodwin";
SecondOrderODESolver* SecondOrderODESolver::Select(int ode_solver_type)
{
SecondOrderODESolver* ode_solver = NULL;
switch (ode_solver_type)
{
// Implicit methods
case 0: ode_solver = new GeneralizedAlpha2Solver(0.0); break;
case 1: ode_solver = new GeneralizedAlpha2Solver(0.1); break;
case 2: ode_solver = new GeneralizedAlpha2Solver(0.2); break;
case 3: ode_solver = new GeneralizedAlpha2Solver(0.3); break;
case 4: ode_solver = new GeneralizedAlpha2Solver(0.4); break;
case 5: ode_solver = new GeneralizedAlpha2Solver(0.5); break;
case 6: ode_solver = new GeneralizedAlpha2Solver(0.6); break;
case 7: ode_solver = new GeneralizedAlpha2Solver(0.7); break;
case 8: ode_solver = new GeneralizedAlpha2Solver(0.8); break;
case 9: ode_solver = new GeneralizedAlpha2Solver(0.9); break;
case 10: ode_solver = new GeneralizedAlpha2Solver(1.0); break;
case 11: ode_solver = new AverageAccelerationSolver(); break;
case 12: ode_solver = new LinearAccelerationSolver(); break;
case 13: ode_solver = new CentralDifferenceSolver(); break;
case 14: ode_solver = new FoxGoodwinSolver(); break;
default:
MFEM_ABORT("Unknown ODE solver type: " << ode_solver_type);
}
return ode_solver;
}
// In this routine state[0] represents d2xdt2
void SecondOrderODESolver::EulerStep(Vector &x, Vector &dxdt, real_t &t,
real_t &dt)
{
x.Add(dt, dxdt);
f->SetTime(t + dt);
f->ImplicitSolve(0.5*dt*dt, dt, x, dxdt, state[0]);
x .Add(0.5*dt*dt, state[0]);
dxdt.Add(dt, state[0]);
t += dt;
}
// In this routine state[0] represents d2xdt2
void SecondOrderODESolver::MidPointStep(Vector &x, Vector &dxdt, real_t &t,
real_t &dt)
{
x.Add(0.5*dt, dxdt);
f->SetTime(t + dt);
f->ImplicitSolve(0.25*dt*dt, 0.5*dt, x, dxdt, state[0]);
x.Add(0.5*dt, dxdt);
x.Add(0.5*dt*dt, state[0]);
dxdt.Add(dt, state[0]);
t += dt;
}
void SecondOrderODESolver::Init(SecondOrderTimeDependentOperator &f_)
{
this->f = &f_;
mem_type = GetMemoryType(f_.GetMemoryClass());
state.SetSize(f->Width(), mem_type);
}
void NewmarkSolver::Init(SecondOrderTimeDependentOperator &f_)
{
SecondOrderODESolver::Init(f_);
d2xdt2.SetSize(f->Width());
d2xdt2 = 0.0;
first = true;
}
void NewmarkSolver::PrintProperties(std::ostream &os)
@@ -1152,7 +1060,6 @@ void NewmarkSolver::PrintProperties(std::ostream &os)
}
}
// In this routine state[0] represents d2xdt2
void NewmarkSolver::Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt)
{
real_t fac0 = 0.5 - beta;
@@ -1161,38 +1068,60 @@ void NewmarkSolver::Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt)
real_t fac4 = gamma;
// In the first pass compute d2xdt2 directly from operator.
if (state.Size() == 0)
if (first)
{
if (no_mult)
{
MidPointStep(x, dxdt, t, dt);
return;
}
else
{
f->Mult(x, dxdt, state[0]);
}
f->Mult(x, dxdt, d2xdt2);
first = false;
}
f->SetTime(t + dt);
x.Add(dt, dxdt);
x.Add(fac0*dt*dt, state[0]);
dxdt.Add(fac2*dt, state[0]);
x.Add(fac0*dt*dt, d2xdt2);
dxdt.Add(fac2*dt, d2xdt2);
f->SetTime(t + dt);
f->ImplicitSolve(fac3*dt*dt, fac4*dt, x, dxdt, state[0]);
f->ImplicitSolve(fac3*dt*dt, fac4*dt, x, dxdt, d2xdt2);
x .Add(fac3*dt*dt, state[0]);
dxdt.Add(fac4*dt, state[0]);
x .Add(fac3*dt*dt, d2xdt2);
dxdt.Add(fac4*dt, d2xdt2);
t += dt;
}
void GeneralizedAlpha2Solver::Init(SecondOrderTimeDependentOperator &f_)
{
SecondOrderODESolver::Init(f_);
xa.SetSize(f->Width(), mem_type);
va.SetSize(f->Width(), mem_type);
aa.SetSize(f->Width(), mem_type);
xa.SetSize(f->Width());
va.SetSize(f->Width());
aa.SetSize(f->Width());
d2xdt2.SetSize(f->Width());
d2xdt2 = 0.0;
nstate = 0;
}
const Vector &GeneralizedAlpha2Solver::GetStateVector(int i)
{
MFEM_ASSERT( (i == 0) && (nstate == 1),
"GeneralizedAlpha2Solver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
return d2xdt2;
}
void GeneralizedAlpha2Solver::GetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i == 0) && (nstate == 1),
"GeneralizedAlpha2Solver::GetStateVector \n" <<
" - Tried to get non-existent state "<<i);
state = d2xdt2;
}
void GeneralizedAlpha2Solver::SetStateVector(int i, Vector &state)
{
MFEM_ASSERT( (i == 0),
"GeneralizedAlpha2Solver::SetStateVector \n" <<
" - Tried to set non-existent state "<<i);
d2xdt2 = state;
nstate = 1;
}
void GeneralizedAlpha2Solver::PrintProperties(std::ostream &os)
@@ -1224,7 +1153,6 @@ void GeneralizedAlpha2Solver::PrintProperties(std::ostream &os)
}
}
// In this routine state[0] represents d2xdt2
void GeneralizedAlpha2Solver::Step(Vector &x, Vector &dxdt,
real_t &t, real_t &dt)
{
@@ -1236,24 +1164,16 @@ void GeneralizedAlpha2Solver::Step(Vector &x, Vector &dxdt,
real_t fac5 = alpha_m;
// In the first pass compute d2xdt2 directly from operator.
if (state.Size() == 0)
if (nstate == 0)
{
if (no_mult)
{
MidPointStep(x, dxdt, t, dt);
return;
}
else
{
f->Mult(x, dxdt, state[0]);
}
state.Increment();
f->Mult(x, dxdt, d2xdt2);
nstate = 1;
}
// Predict alpha levels
add(dxdt, fac0*dt, state[0], va);
add(dxdt, fac0*dt, d2xdt2, va);
add(x, fac1*dt, va, xa);
add(dxdt, fac2*dt, state[0], va);
add(dxdt, fac2*dt, d2xdt2, va);
// Solve alpha levels
f->SetTime(t + dt);
@@ -1270,8 +1190,8 @@ void GeneralizedAlpha2Solver::Step(Vector &x, Vector &dxdt,
dxdt *= 1.0 - 1.0/fac1;
dxdt.Add (1.0/fac1, va);
state[0] *= 1.0 - 1.0/fac5;
state[0].Add (1.0/fac5, aa);
d2xdt2 *= 1.0 - 1.0/fac5;
d2xdt2.Add (1.0/fac5, aa);
t += dt;
}
+246 -319
View File
@@ -12,99 +12,13 @@
#ifndef MFEM_ODE
#define MFEM_ODE
#include "../general/communication.hpp"
#include "../config/config.hpp"
#include "operator.hpp"
#include <vector>
#include <memory>
#include "../general/communication.hpp"
namespace mfem
{
/// An interface for storing state of previous timesteps
class ODEStateData
{
public:
/// Get the maximum number of stored stages
virtual int MaxSize() const = 0;
/// Get the current number of stored stages
virtual int Size() const = 0;
/// Get the ith state vector
virtual const Vector &Get(int i) const = 0;
/// Get the ith state vector - non-const version
virtual Vector &Get(int i) = 0;
/// Get the ith state vector - with a copy
virtual void Get(int i, Vector &vec) const = 0;
/// Set the ith state vector
virtual void Set(int i, Vector &state) = 0;
/// Add state vector and increment state size
virtual void Append(Vector &state) = 0;
/// Virtual destructor
virtual ~ODEStateData() = default;
};
/// An implementation of ODEStateData that stores states in an std::vector<Vector>
class ODEStateDataVector : public ODEStateData
{
private:
MemoryType mem_type;
int ss, smax;
std::vector<Vector> data;
Array<int> idx;
public:
ODEStateDataVector (int smax): smax(smax)
{
data.resize(smax);
idx.SetSize(smax);
ss = 0;
};
/// Set the number of stages and the size of the vectors
void SetSize(int vsize, MemoryType mem_type);
/// Shift the stage counter for the next timestep
inline void ShiftStages()
{
for (int i = 0; i < smax; i++) { idx[i] = (++idx[i])%smax; }
};
/// Increment the stage counter
void Increment() { ss++; ss = std::min(ss,smax); };
/// Reset the stage counter
void Reset() { ss = 0; };
/// Reference access to the ith vector.
inline Vector & operator[](int i) { return data[idx[i]]; };
/// Const reference access to the ith vector.
inline const Vector &operator[](int i) const { return data[idx[i]]; };
/// Print state data
void Print(std::ostream &os = mfem::out) const ;
int MaxSize() const override { return smax; };
int Size() const override { return ss; };
const Vector &Get(int i) const override;
Vector &Get(int i) override;
void Get(int i, Vector &vec) const override;
void Set(int i, Vector &state) override;
void Append(Vector &state) override;
};
/// Abstract class for solving systems of ODEs: dx/dt = f(x,t)
class ODESolver
{
@@ -178,48 +92,26 @@ public:
while (t < tf) { Step(x, t, dt); }
}
/// Returns how many State vectors the ODE requires
virtual int GetStateSize() { return 0; };
// Help info for ODESolver options
static MFEM_EXPORT std::string ExplicitTypes;
static MFEM_EXPORT std::string ImplicitTypes;
static MFEM_EXPORT std::string Types;
/// Function for selecting the desired ODESolver (Explicit and Implicit)
/// Returns an ODESolver pointer based on an type
/// Caller gets ownership of the object and is responsible for its deletion
static MFEM_EXPORT std::unique_ptr<ODESolver> Select(const int ode_solver_type);
/// Function for selecting the desired Explicit ODESolver
/// Returns an ODESolver pointer based on an type
/// Caller gets ownership of the object and is responsible for its deletion
static MFEM_EXPORT std::unique_ptr<ODESolver> SelectExplicit(
const int ode_solver_type);
/// Function for selecting the desired Implicit ODESolver
/// Returns an ODESolver pointer based on an type
/// Caller gets ownership of the object and is responsible for its deletion
static MFEM_EXPORT std::unique_ptr<ODESolver> SelectImplicit(
const int ode_solver_type);
/// Function for getting and setting the state vectors
virtual int GetMaxStateSize() { return 0; }
virtual int GetStateSize() { return 0; }
virtual const Vector &GetStateVector(int i)
{
mfem_error("ODESolver has no state vectors");
Vector *s = NULL; return *s; // Make some compiler happy
}
virtual void GetStateVector(int i, Vector &state)
{
mfem_error("ODESolver has no state vectors");
}
virtual void SetStateVector(int i, Vector &state)
{
mfem_error("ODESolver has no state vectors");
}
virtual ~ODESolver() { }
};
/// Abstract class for an ODESolver that has state history implemented as ODEStateData
class ODESolverWithStates : public ODESolver
{
public:
/// Returns the StateData
virtual ODEStateData& GetState() = 0;
/// Returns the StateData
virtual const ODEStateData& GetState() const = 0;
/// Returns how many State vectors the ODE requires
virtual int GetStateSize() { return GetState().MaxSize(); };
};
/// The classical forward Euler method
class ForwardEulerSolver : public ODESolver
@@ -325,13 +217,196 @@ public:
class RK8Solver : public ExplicitRKSolver
{
private:
static MFEM_EXPORT const real_t a[66], b[12], c[11];
static const real_t a[66], b[12], c[11];
public:
RK8Solver() : ExplicitRKSolver(12, a, b, c) { }
};
/** An explicit Adams-Bashforth method. */
class AdamsBashforthSolver : public ODESolver
{
private:
int s, smax;
const real_t *a;
Vector *k;
Array<int> idx;
ODESolver *RKsolver;
real_t dt_;
inline bool print()
{
#ifdef MFEM_USE_MPI
return Mpi::IsInitialized() ? Mpi::Root() : true;
#else
return true;
#endif
}
public:
AdamsBashforthSolver(int s_, const real_t *a_);
void Init(TimeDependentOperator &f_) override;
void Step(Vector &x, real_t &t, real_t &dt) override;
int GetMaxStateSize() override { return smax; };
int GetStateSize() override { return s; };
const Vector &GetStateVector(int i) override;
void GetStateVector(int i, Vector &state) override;
void SetStateVector(int i, Vector &state) override;
~AdamsBashforthSolver()
{
if (RKsolver) { delete RKsolver; }
delete [] k;
}
};
/** A 1-stage, 1st order AB method. */
class AB1Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[1];
public:
AB1Solver() : AdamsBashforthSolver(1, a) { }
};
/** A 2-stage, 2nd order AB method. */
class AB2Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[2];
public:
AB2Solver() : AdamsBashforthSolver(2, a) { }
};
/** A 3-stage, 3rd order AB method. */
class AB3Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[3];
public:
AB3Solver() : AdamsBashforthSolver(3, a) { }
};
/** A 4-stage, 4th order AB method. */
class AB4Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[4];
public:
AB4Solver() : AdamsBashforthSolver(4, a) { }
};
/** A 5-stage, 5th order AB method. */
class AB5Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[5];
public:
AB5Solver() : AdamsBashforthSolver(5, a) { }
};
/** An implicit Adams-Moulton method. */
class AdamsMoultonSolver : public ODESolver
{
private:
int s, smax;
const real_t *a;
Vector *k;
Array<int> idx;
ODESolver *RKsolver;
real_t dt_;
inline bool print()
{
#ifdef MFEM_USE_MPI
return Mpi::IsInitialized() ? Mpi::Root() : true;
#else
return true;
#endif
}
public:
AdamsMoultonSolver(int s_, const real_t *a_);
void Init(TimeDependentOperator &f_) override;
void Step(Vector &x, real_t &t, real_t &dt) override;
int GetMaxStateSize() override { return smax-1; };
int GetStateSize() override { return s-1; };
const Vector &GetStateVector(int i) override;
void GetStateVector(int i, Vector &state) override;
void SetStateVector(int i, Vector &state) override;
~AdamsMoultonSolver()
{
if (RKsolver) { delete RKsolver; }
delete [] k;
};
};
/** A 0-stage, 1st order AM method. */
class AM0Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[1];
public:
AM0Solver() : AdamsMoultonSolver(0, a) { }
};
/** A 1-stage, 2nd order AM method. */
class AM1Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[2];
public:
AM1Solver() : AdamsMoultonSolver(1, a) { }
};
/** A 2-stage, 3rd order AM method. */
class AM2Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[3];
public:
AM2Solver() : AdamsMoultonSolver(2, a) { }
};
/** A 3-stage, 4th order AM method. */
class AM3Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[4];
public:
AM3Solver() : AdamsMoultonSolver(3, a) { }
};
/** A 4-stage, 5th order AM method. */
class AM4Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[5];
public:
AM4Solver() : AdamsMoultonSolver(4, a) { }
};
/// Backward Euler ODE solver. L-stable.
class BackwardEulerSolver : public ODESolver
{
@@ -452,183 +527,31 @@ public:
/// Generalized-alpha ODE solver from "A generalized-α method for integrating
/// the filtered Navier-Stokes equations with a stabilized finite element
/// method" by K.E. Jansen, C.H. Whiting and G.M. Hulbert.
class GeneralizedAlphaSolver : public ODESolverWithStates
class GeneralizedAlphaSolver : public ODESolver
{
ODEStateDataVector state;
protected:
mutable Vector k,y;
mutable Vector xdot,k,y;
real_t alpha_f, alpha_m, gamma;
int nstate;
void SetRhoInf(real_t rho_inf);
void PrintProperties(std::ostream &os = mfem::out);
void PrintProperties(std::ostream &out = mfem::out);
public:
GeneralizedAlphaSolver(real_t rho = 1.0) : state(1) { SetRhoInf(rho); };
GeneralizedAlphaSolver(real_t rho = 1.0) { SetRhoInf(rho); };
void Init(TimeDependentOperator &f_) override;
void Step(Vector &x, real_t &t, real_t &dt) override;
ODEStateData& GetState() override { return state; }
const ODEStateData& GetState() const override { return state; }
int GetMaxStateSize() override { return 1; };
int GetStateSize() override { return nstate; };
const Vector &GetStateVector(int i) override;
void GetStateVector(int i, Vector &state) override;
void SetStateVector(int i, Vector &state) override;
};
/** An explicit Adams-Bashforth method. */
class AdamsBashforthSolver : public ODESolverWithStates
{
private:
const real_t *a;
const int stages;
real_t dt_;
ODEStateDataVector state;
protected:
std::unique_ptr<ODESolver> RKsolver;
inline bool print()
{
#ifdef MFEM_USE_MPI
return Mpi::IsInitialized() ? Mpi::Root() : true;
#else
return true;
#endif
}
void CheckTimestep(real_t dt);
public:
AdamsBashforthSolver(int s_, const real_t *a_);
void Init(TimeDependentOperator &f_) override;
void Step(Vector &x, real_t &t, real_t &dt) override;
ODEStateData& GetState() override { return state; }
const ODEStateData& GetState() const override { return state; }
};
/** A 1-stage, 1st order AB method. */
class AB1Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[1];
public:
AB1Solver() : AdamsBashforthSolver(1, a) { }
};
/** A 2-stage, 2nd order AB method. */
class AB2Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[2];
public:
AB2Solver() : AdamsBashforthSolver(2, a) { RKsolver.reset(new RK2Solver()); }
};
/** A 3-stage, 3rd order AB method. */
class AB3Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[3];
public:
AB3Solver() : AdamsBashforthSolver(3, a) { RKsolver.reset(new RK3SSPSolver()); }
};
/** A 4-stage, 4th order AB method. */
class AB4Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[4];
public:
AB4Solver() : AdamsBashforthSolver(4, a) { RKsolver.reset(new RK4Solver()); }
};
/** A 5-stage, 5th order AB method. */
class AB5Solver : public AdamsBashforthSolver
{
private:
static MFEM_EXPORT const real_t a[5];
public:
AB5Solver() : AdamsBashforthSolver(5, a) { RKsolver.reset(new RK6Solver()); }
};
/** An implicit Adams-Moulton method. */
class AdamsMoultonSolver : public ODESolverWithStates
{
private:
const real_t *a;
const int stages;
real_t dt_;
ODEStateDataVector state;
protected:
std::unique_ptr<ODESolver> RKsolver;
inline bool print()
{
#ifdef MFEM_USE_MPI
return Mpi::IsInitialized() ? Mpi::Root() : true;
#else
return true;
#endif
}
void CheckTimestep(real_t dt);
public:
AdamsMoultonSolver(int s_, const real_t *a_);
void Init(TimeDependentOperator &f_) override;
void Step(Vector &x, real_t &t, real_t &dt) override;
ODEStateData& GetState() override { return state; }
const ODEStateData& GetState() const override { return state; }
};
/** A 1-stage, 2nd order AM method. */
class AM1Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[2];
public:
AM1Solver() : AdamsMoultonSolver(1, a) { RKsolver.reset(new SDIRK23Solver()); }
};
/** A 2-stage, 3rd order AM method. */
class AM2Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[3];
public:
AM2Solver() : AdamsMoultonSolver(2, a) { RKsolver.reset(new SDIRK23Solver()); }
};
/** A 3-stage, 4th order AM method. */
class AM3Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[4];
public:
AM3Solver() : AdamsMoultonSolver(3, a) { RKsolver.reset(new SDIRK23Solver()); }
};
/** A 4-stage, 5th order AM method. */
class AM4Solver : public AdamsMoultonSolver
{
private:
static MFEM_EXPORT const real_t a[5];
public:
AM4Solver() : AdamsMoultonSolver(4, a) { RKsolver.reset(new SDIRK34Solver()); }
};
/// The SIASolver class is based on the Symplectic Integration Algorithm
/// described in "A Symplectic Integration Algorithm for Separable Hamiltonian
/// Functions" by J. Candy and W. Rozmus, Journal of Computational Physics,
@@ -707,10 +630,9 @@ protected:
/// Pointer to the associated TimeDependentOperator.
SecondOrderTimeDependentOperator *f; // f(.,.,t) : R^n x R^n --> R^n
MemoryType mem_type;
ODEStateDataVector state;
public:
SecondOrderODESolver() : f(NULL), state(1) { mem_type = MemoryType::HOST; }
SecondOrderODESolver() : f(NULL) { mem_type = MemoryType::HOST; }
/// Associate a TimeDependentOperator with the ODE solver.
/** This method has to be called:
@@ -758,8 +680,6 @@ public:
sequence, then the ODE solver must be re-initialized by calling Init()
between the two Step() calls. */
virtual void Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt) = 0;
void EulerStep(Vector &x, Vector &dxdt, real_t &t, real_t &dt);
void MidPointStep(Vector &x, Vector &dxdt, real_t &t, real_t &dt);
/// Perform time integration from time @a t [in] to time @a tf [in].
/** @param[in,out] x Approximate solution.
@@ -785,18 +705,22 @@ public:
while (t < tf) { Step(x, dxdt, t, dt); }
}
/// Functions for getting the state vectors
ODEStateData& GetState() { return state; }
const ODEStateData& GetState() const { return state; }
/// Returns how many State vectors the ODE requires
int GetStateSize() { return GetState().MaxSize(); };
/// Help info for SecondOrderODESolver options
static MFEM_EXPORT std::string Types;
/// Function selecting the desired SecondOrderODESolver
static MFEM_EXPORT SecondOrderODESolver *Select(const int ode_solver_type);
/// Function for getting and setting the state vectors
virtual int GetMaxStateSize() { return 0; };
virtual int GetStateSize() { return 0; }
virtual const Vector &GetStateVector(int i)
{
mfem_error("ODESolver has no state vectors");
Vector *s = NULL; return *s; // Make some compiler happy
}
virtual void GetStateVector(int i, Vector &state)
{
mfem_error("ODESolver has no state vectors");
}
virtual void SetStateVector(int i, Vector &state)
{
mfem_error("ODESolver has no state vectors");
}
virtual ~SecondOrderODESolver() { }
};
@@ -807,18 +731,17 @@ public:
class NewmarkSolver : public SecondOrderODESolver
{
private:
Vector d2xdt2;
real_t beta, gamma;
bool no_mult;
bool first;
public:
NewmarkSolver(real_t beta_ = 0.25, real_t gamma_ = 0.5, bool no_mult_ = false)
{
beta = beta_;
gamma = gamma_;
no_mult = no_mult_;
};
NewmarkSolver(real_t beta_ = 0.25, real_t gamma_ = 0.5) { beta = beta_; gamma = gamma_; };
void PrintProperties(std::ostream &os = mfem::out);
void PrintProperties(std::ostream &out = mfem::out);
void Init(SecondOrderTimeDependentOperator &f_) override;
void Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt) override;
};
@@ -850,14 +773,13 @@ public:
class GeneralizedAlpha2Solver : public SecondOrderODESolver
{
protected:
Vector xa,va,aa;
Vector xa,va,aa,d2xdt2;
real_t alpha_f, alpha_m, beta, gamma;
bool no_mult;
int nstate;
public:
GeneralizedAlpha2Solver(real_t rho_inf = 1.0, bool no_mult_ = false)
GeneralizedAlpha2Solver(real_t rho_inf = 1.0)
{
no_mult = no_mult_;
rho_inf = (rho_inf > 1.0) ? 1.0 : rho_inf;
rho_inf = (rho_inf < 0.0) ? 0.0 : rho_inf;
@@ -867,12 +789,17 @@ public:
gamma = 0.5 + alpha_m - alpha_f;
};
void PrintProperties(std::ostream &os = mfem::out);
void PrintProperties(std::ostream &out = mfem::out);
void Init(SecondOrderTimeDependentOperator &f_) override;
void Step(Vector &x, Vector &dxdt, real_t &t, real_t &dt) override;
int GetMaxStateSize() override { return 1; };
int GetStateSize() override { return nstate; };
const Vector &GetStateVector(int i) override;
void GetStateVector(int i, Vector &state) override;
void SetStateVector(int i, Vector &state) override;
};
/// The classical midpoint method.
+63 -44
View File
@@ -183,8 +183,8 @@ Operator * Operator::SetupRAP(const Operator *Pi, const Operator *Po)
{
if (!IsIdentityProlongation(Po))
{
rap = new ProductOperator(Owning(new TransposeOperator(Po)),
NonOwning(this));
TransposeOperator * PoT = new TransposeOperator(Po);
rap = new ProductOperator(PoT, this, true,false);
}
else
{
@@ -365,10 +365,11 @@ void SecondOrderTimeDependentOperator::ImplicitSolve(const real_t dt0,
mfem_error("SecondOrderTimeDependentOperator::ImplicitSolve() is not overridden!");
}
SumOperator::SumOperator(Handle<const Operator> A_, const real_t alpha,
Handle<const Operator> B_, const real_t beta)
: Operator(A_->Height(), A_->Width()),
A(A_), B(B_), alpha(alpha), beta(beta),
SumOperator::SumOperator(const Operator *A, const real_t alpha,
const Operator *B, const real_t beta,
bool ownA, bool ownB)
: Operator(A->Height(), A->Width()),
A(A), B(B), alpha(alpha), beta(beta), ownA(ownA), ownB(ownB),
z(A->Height())
{
MFEM_VERIFY(A->Width() == B->Width(),
@@ -380,43 +381,53 @@ SumOperator::SumOperator(Handle<const Operator> A_, const real_t alpha,
<< "A->Height() = " << A->Height()
<< ", B->Height() = " << B->Height() );
if (auto SolverA = dynamic_cast<const Solver*>(A.Get()))
{
MFEM_VERIFY(!(SolverA->iterative_mode),
"Operator A of a SumOperator should not be in iterative mode");
}
if (auto SolverB = dynamic_cast<const Solver*>(B.Get()))
{
MFEM_VERIFY(!(SolverB->iterative_mode),
"Operator B of a SumOperator should not be in iterative mode");
const Solver* SolverA = dynamic_cast<const Solver*>(A);
const Solver* SolverB = dynamic_cast<const Solver*>(B);
if (SolverA)
{
MFEM_VERIFY(!(SolverA->iterative_mode),
"Operator A of a SumOperator should not be in iterative mode");
}
if (SolverB)
{
MFEM_VERIFY(!(SolverB->iterative_mode),
"Operator B of a SumOperator should not be in iterative mode");
}
}
}
SumOperator::SumOperator(const Operator *A_, const real_t alpha,
const Operator *B_, const real_t beta,
bool own_A, bool own_B)
: SumOperator({A_, own_A}, alpha, {B_, own_B}, beta) { }
SumOperator::~SumOperator()
{
if (ownA) { delete A; }
if (ownB) { delete B; }
}
ProductOperator::ProductOperator(Handle<const Operator> A_,
Handle<const Operator> B_)
: Operator(A_->Height(), B_->Width()),
A(A_), B(B_), z(A->Width())
ProductOperator::ProductOperator(const Operator *A, const Operator *B,
bool ownA, bool ownB)
: Operator(A->Height(), B->Width()),
A(A), B(B), ownA(ownA), ownB(ownB), z(A->Width())
{
MFEM_VERIFY(A->Width() == B->Height(),
"incompatible Operators: A->Width() = " << A->Width()
<< ", B->Height() = " << B->Height());
if (auto SolverB = dynamic_cast<const Solver*>(B.Get()))
{
MFEM_VERIFY(!(SolverB->iterative_mode),
"Operator B of a ProductOperator should not be in iterative mode");
const Solver* SolverB = dynamic_cast<const Solver*>(B);
if (SolverB)
{
MFEM_VERIFY(!(SolverB->iterative_mode),
"Operator B of a ProductOperator should not be in iterative mode");
}
}
}
ProductOperator::ProductOperator(const Operator *A_, const Operator *B_,
bool own_A, bool own_B)
: ProductOperator({A_, own_A}, {B_, own_B}) { }
ProductOperator::~ProductOperator()
{
if (ownA) { delete A; }
if (ownB) { delete B; }
}
RAPOperator::RAPOperator(const Operator &Rt_, const Operator &A_,
@@ -454,9 +465,11 @@ RAPOperator::RAPOperator(const Operator &Rt_, const Operator &A_,
TripleProductOperator::TripleProductOperator(
Handle<const Operator> A_, Handle<const Operator> B_, Handle<const Operator> C_)
: Operator(A_->Height(), C_->Width()),
A(A_), B(B_), C(C_)
const Operator *A, const Operator *B, const Operator *C,
bool ownA, bool ownB, bool ownC)
: Operator(A->Height(), C->Width())
, A(A), B(B), C(C)
, ownA(ownA), ownB(ownB), ownC(ownC)
{
MFEM_VERIFY(A->Width() == B->Height(),
"incompatible Operators: A->Width() = " << A->Width()
@@ -465,16 +478,20 @@ TripleProductOperator::TripleProductOperator(
"incompatible Operators: B->Width() = " << B->Width()
<< ", C->Height() = " << C->Height());
if (auto SolverB = dynamic_cast<const Solver*>(B.Get()))
{
MFEM_VERIFY(!(SolverB->iterative_mode),
"Operator B of a TripleProductOperator should not be in iterative mode");
}
const Solver* SolverB = dynamic_cast<const Solver*>(B);
if (SolverB)
{
MFEM_VERIFY(!(SolverB->iterative_mode),
"Operator B of a TripleProductOperator should not be in iterative mode");
}
if (auto SolverC = dynamic_cast<const Solver*>(C.Get()))
{
MFEM_VERIFY(!(SolverC->iterative_mode),
"Operator C of a TripleProductOperator should not be in iterative mode");
const Solver* SolverC = dynamic_cast<const Solver*>(C);
if (SolverC)
{
MFEM_VERIFY(!(SolverC->iterative_mode),
"Operator C of a TripleProductOperator should not be in iterative mode");
}
}
mem_class = A->GetMemoryClass()*C->GetMemoryClass();
@@ -483,10 +500,12 @@ TripleProductOperator::TripleProductOperator(
t2.SetSize(B->Height(), mem_type);
}
TripleProductOperator::TripleProductOperator(
const Operator *A_, const Operator *B_, const Operator *C_,
bool own_A, bool own_B, bool own_C)
: TripleProductOperator({A_, own_A}, {B_, own_B}, {C_, own_C}) { }
TripleProductOperator::~TripleProductOperator()
{
if (ownA) { delete A; }
if (ownB) { delete B; }
if (ownC) { delete C; }
}
ConstrainedOperator::ConstrainedOperator(Operator *A, const Array<int> &list,
+21 -22
View File
@@ -13,7 +13,6 @@
#define MFEM_OPERATOR
#include "vector.hpp"
#include "../general/handle.hpp"
namespace mfem
{
@@ -870,42 +869,43 @@ public:
/// General linear combination operator: x -> a A(x) + b B(x).
class SumOperator : public Operator
{
Handle<const Operator> A, B;
const Operator *A, *B;
const real_t alpha, beta;
bool ownA, ownB;
mutable Vector z;
public:
SumOperator(Handle<const Operator> A_, const real_t alpha,
Handle<const Operator> B_, const real_t beta);
SumOperator(const Operator *A_, const real_t alpha,
const Operator *B_, const real_t beta,
bool own_A, bool own_B);
SumOperator(
const Operator *A, const real_t alpha,
const Operator *B, const real_t beta,
bool ownA, bool ownB);
void Mult(const Vector &x, Vector &y) const override
{ z.SetSize(A->Height()); A->Mult(x, z); B->Mult(x, y); add(alpha, z, beta, y, y); }
void MultTranspose(const Vector &x, Vector &y) const override
{ z.SetSize(A->Width()); A->MultTranspose(x, z); B->MultTranspose(x, y); add(alpha, z, beta, y, y); }
virtual ~SumOperator();
};
/// General product operator: x -> (A*B)(x) = A(B(x)).
class ProductOperator : public Operator
{
Handle<const Operator> A, B;
const Operator *A, *B;
bool ownA, ownB;
mutable Vector z;
public:
ProductOperator(Handle<const Operator> A_, Handle<const Operator> B_);
ProductOperator(const Operator *A_, const Operator *B_,
bool own_A, bool own_B);
ProductOperator(const Operator *A, const Operator *B, bool ownA, bool ownB);
void Mult(const Vector &x, Vector &y) const override
{ B->Mult(x, z); A->Mult(z, y); }
void MultTranspose(const Vector &x, Vector &y) const override
{ A->MultTranspose(x, z); B->MultTranspose(z, y); }
virtual ~ProductOperator();
};
@@ -956,19 +956,16 @@ public:
/// General triple product operator x -> A*B*C*x, with ownership of the factors.
class TripleProductOperator : public Operator
{
Handle<const Operator> A;
Handle<const Operator> B;
Handle<const Operator> C;
const Operator *A;
const Operator *B;
const Operator *C;
bool ownA, ownB, ownC;
mutable Vector t1, t2;
MemoryClass mem_class;
public:
TripleProductOperator(Handle<const Operator> A_, Handle<const Operator> B_,
Handle<const Operator> C_);
TripleProductOperator(
const Operator *A_, const Operator *B_, const Operator *C_,
bool own_A, bool own_B, bool own_C);
TripleProductOperator(const Operator *A, const Operator *B,
const Operator *C, bool ownA, bool ownB, bool ownC);
MemoryClass GetMemoryClass() const override { return mem_class; }
@@ -977,6 +974,8 @@ public:
void MultTranspose(const Vector &x, Vector &y) const override
{ A->MultTranspose(x, t2); B->MultTranspose(t2, t1); C->MultTranspose(t1, y); }
virtual ~TripleProductOperator();
};
+3 -3
View File
@@ -21,7 +21,7 @@
#include <limits>
#include "op_handle.hpp"
#include "handle.hpp"
#include "hypre.hpp"
#include "ode.hpp"
#include "../general/mem_manager.hpp"
@@ -36,10 +36,10 @@
#if defined(PETSC_USE_COMPLEX)
#error "MFEM does not work with PETSc compiled with complex numbers support"
#endif
#if defined(PETSC_USE_64BIT_INDICES) && !defined(HYPRE_BIGINT) && !defined(HYPRE_MIXEDINT)
#if defined(PETSC_USE_64BIT_INDICES) && !defined(HYPRE_BIGINT)
#error "Mismatch between HYPRE (32bit) and PETSc (64bit) integer types"
#endif
#if !defined(PETSC_USE_64BIT_INDICES) && (defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT))
#if !defined(PETSC_USE_64BIT_INDICES) && defined(HYPRE_BIGINT)
#error "Mismatch between HYPRE (64bit) and PETSc (32bit) integer types"
#endif
+10 -12
View File
@@ -1919,8 +1919,7 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const
print_options.first_and_last)
{
mfem::out << "Newton: Number of iterations: " << final_iter << '\n'
<< " ||r|| = " << final_norm
<< ", ||r||/||r_0|| = " << final_norm/norm0 << '\n';
<< " ||r|| = " << final_norm << '\n';
}
if (!converged && (print_options.summary || print_options.warnings))
{
@@ -2142,8 +2141,7 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const
print_options.first_and_last)
{
mfem::out << "LBFGS: Number of iterations: " << final_iter << '\n'
<< " ||r|| = " << final_norm
<< ", ||r||/||r_0|| = " << final_norm/norm0 << '\n';
<< " ||r|| = " << final_norm << '\n';
}
if (print_options.summary || (!converged && print_options.warnings))
{
@@ -2572,7 +2570,7 @@ struct WeightMinHeap
for (; pos > 0 && w[c[(pos-1)/2]] > val; pos = (pos-1)/2)
{
c[pos] = c[(pos-1)/2];
loc[c[(pos-1)/2]] = static_cast<int>(pos);
loc[c[(pos-1)/2]] = pos;
}
return pos;
}
@@ -2589,7 +2587,7 @@ struct WeightMinHeap
if (w[c[tgt]] < val)
{
c[pos] = c[tgt];
loc[c[tgt]] = static_cast<int>(pos);
loc[c[tgt]] = pos;
pos = tgt;
}
else
@@ -2607,7 +2605,7 @@ struct WeightMinHeap
size_t pos = c.size()-1;
pos = percolate_up(pos, val);
c[pos] = i;
loc[i] = static_cast<int>(pos);
loc[i] = pos;
}
int pop()
@@ -2617,13 +2615,13 @@ struct WeightMinHeap
c.pop_back();
// Mark as removed
loc[i] = -1;
if (c.empty()) { return static_cast<int>(i); }
if (c.empty()) { return i; }
real_t val = w[j];
size_t pos = 0;
pos = percolate_down(pos, val);
c[pos] = j;
loc[j] = static_cast<int>(pos);
return static_cast<int>(i);
loc[j] = pos;
return i;
}
void update(size_t i)
@@ -2633,7 +2631,7 @@ struct WeightMinHeap
pos = percolate_up(pos, val);
pos = percolate_down(pos, val);
c[pos] = i;
loc[i] = static_cast<int>(pos);
loc[i] = pos;
}
bool picked(size_t i)
@@ -2821,7 +2819,7 @@ void BlockILU::CreateBlockPattern(const SparseMatrix &A)
unique_block_cols[iblock].insert(J[k] / block_size);
}
}
nnz += static_cast<int>(unique_block_cols[iblock].size());
nnz += unique_block_cols[iblock].size();
}
if (reordering != Reordering::NONE)
+1 -1
View File
@@ -14,7 +14,7 @@
#include "../config/config.hpp"
#include "densemat.hpp"
#include "op_handle.hpp"
#include "handle.hpp"
#include <memory>
#ifdef MFEM_USE_MPI
+79 -132
View File
@@ -95,7 +95,7 @@ MFEM_DEPRECATED void* CVodeCreate(int lmm, SUNContext)
/// (DEPRECATED) Wrapper function for backwards compatibility with SUNDIALS
/// version < 6
MFEM_DEPRECATED void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, sunrealtype t0,
MFEM_DEPRECATED void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, realtype t0,
N_Vector y0, SUNContext)
{
return ARKStepCreate(fe, fi, t0, y0);
@@ -127,7 +127,7 @@ MFEM_DEPRECATED N_Vector N_VNewEmpty_Parallel(MPI_Comm comm,
/// (DEPRECATED) Wrapper function for backwards compatibility with SUNDIALS
/// version < 6
MFEM_DEPRECATED N_Vector SUN_Hip_OR_Cuda(N_VNewWithMemHelp)(sunindextype length,
sunbooleantype use_managed_mem,
booleantype use_managed_mem,
SUNMemoryHelper helper,
SUNContext)
{
@@ -157,16 +157,6 @@ MFEM_DEPRECATED N_Vector N_VMake_MPIPlusX(MPI_Comm comm, N_Vector local_vector,
#endif // SUNDIALS_VERSION_MAJOR < 6
#if MFEM_SUNDIALS_VERSION < 70100
#define MFEM_ARKode(FUNC) ARKStep##FUNC
#else
#define MFEM_ARKode(FUNC) ARKode##FUNC
#endif
// Macro STR(): expand the argument and add double quotes
#define STR1(s) #s
#define STR(s) STR1(s)
namespace mfem
{
@@ -197,21 +187,11 @@ SundialsMemHelper &Sundials::GetMemHelper()
Sundials::Sundials()
{
#ifdef MFEM_USE_MPI
int mpi_initialized = 0;
MPI_Initialized(&mpi_initialized);
MPI_Comm communicator = mpi_initialized ? MPI_COMM_WORLD : MPI_COMM_NULL;
#if SUNDIALS_VERSION_MAJOR < 7
MPI_Comm communicator = MPI_COMM_WORLD;
int return_val = SUNContext_Create((void*) &communicator, &context);
#else
int return_val = SUNContext_Create(communicator, &context);
#endif
#else // #ifdef MFEM_USE_MPI
#if SUNDIALS_VERSION_MAJOR < 7
int return_val = SUNContext_Create(nullptr, &context);
#else
int return_val = SUNContext_Create((SUNComm)(0), &context);
#endif
#endif // #ifdef MFEM_USE_MPI
MFEM_VERIFY(return_val == 0, "Call to SUNContext_Create failed");
SundialsMemHelper actual_helper(context);
memHelper = std::move(actual_helper);
@@ -270,11 +250,7 @@ int SundialsMemHelper::SundialsMemHelper_Alloc(SUNMemoryHelper helper,
#endif
)
{
#if (SUNDIALS_VERSION_MAJOR < 7)
SUNMemory sunmem = SUNMemoryNewEmpty();
#else
SUNMemory sunmem = SUNMemoryNewEmpty(helper->sunctx);
#endif
sunmem->ptr = NULL;
sunmem->own = SUNTRUE;
@@ -655,7 +631,7 @@ static int LSFree(SUNLinearSolver LS)
// ---------------------------------------------------------------------------
// CVODE interface
// ---------------------------------------------------------------------------
int CVODESolver::RHS(sunrealtype t, const N_Vector y, N_Vector ydot,
int CVODESolver::RHS(realtype t, const N_Vector y, N_Vector ydot,
void *user_data)
{
// At this point the up-to-date data for N_Vector y and ydot is on the device.
@@ -672,8 +648,7 @@ int CVODESolver::RHS(sunrealtype t, const N_Vector y, N_Vector ydot,
return (0);
}
int CVODESolver::root(sunrealtype t, N_Vector y, sunrealtype *gout,
void *user_data)
int CVODESolver::root(realtype t, N_Vector y, realtype *gout, void *user_data)
{
CVODESolver *self = static_cast<CVODESolver*>(user_data);
@@ -693,9 +668,8 @@ void CVODESolver::SetRootFinder(int components, RootFunction func)
MFEM_VERIFY(flag == CV_SUCCESS, "error in SetRootFinder()");
}
int CVODESolver::LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy,
SUNMatrix A, sunbooleantype jok,
sunbooleantype *jcur, sunrealtype gamma,
int CVODESolver::LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
booleantype jok, booleantype *jcur, realtype gamma,
void*, N_Vector, N_Vector, N_Vector)
{
// Get data from N_Vectors
@@ -709,7 +683,7 @@ int CVODESolver::LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy,
}
int CVODESolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
N_Vector b, sunrealtype tol)
N_Vector b, realtype tol)
{
SundialsNVector mfem_x(x);
const SundialsNVector mfem_b(b);
@@ -885,7 +859,7 @@ void CVODESolver::UseSundialsLinearSolver()
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
// Create linear solver
LSA = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
LSA = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
MFEM_VERIFY(LSA, "error in SUNLinSol_SPGMR()");
// Attach linear solver
@@ -1176,7 +1150,7 @@ void CVODESSolver::UseSundialsLinearSolverB()
if (LSB != NULL) { SUNLinSolFree(LSB); LSB = NULL; }
// Set default linear solver (Newton is the default Nonlinear Solver)
LSB = SUNLinSol_SPGMR(*yB, SUN_PREC_NONE, 0, Sundials::GetContext());
LSB = SUNLinSol_SPGMR(*yB, PREC_NONE, 0, Sundials::GetContext());
MFEM_VERIFY(LSB, "error in SUNLinSol_SPGMR()");
/* Attach the matrix and linear solver */
@@ -1184,11 +1158,11 @@ void CVODESSolver::UseSundialsLinearSolverB()
MFEM_VERIFY(flag == CV_SUCCESS, "error in CVodeSetLinearSolverB()");
}
int CVODESSolver::LinSysSetupB(sunrealtype t, N_Vector y, N_Vector yB,
int CVODESSolver::LinSysSetupB(realtype t, N_Vector y, N_Vector yB,
N_Vector fyB, SUNMatrix AB,
sunbooleantype jokB, sunbooleantype *jcurB,
sunrealtype gammaB, void *user_data,
N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
booleantype jokB, booleantype *jcurB,
realtype gammaB, void *user_data, N_Vector tmp1,
N_Vector tmp2, N_Vector tmp3)
{
// Get data from N_Vectors
const SundialsNVector mfem_y(y);
@@ -1204,7 +1178,7 @@ int CVODESSolver::LinSysSetupB(sunrealtype t, N_Vector y, N_Vector yB,
}
int CVODESSolver::LinSysSolveB(SUNLinearSolver LS, SUNMatrix AB, N_Vector yB,
N_Vector Rb, sunrealtype tol)
N_Vector Rb, realtype tol)
{
SundialsNVector mfem_yB(yB);
const SundialsNVector mfem_Rb(Rb);
@@ -1242,7 +1216,7 @@ void CVODESSolver::SetWFTolerances(EWTFunction func)
// CVODESSolver static functions
int CVODESSolver::RHSQ(sunrealtype t, const N_Vector y, N_Vector qdot,
int CVODESSolver::RHSQ(realtype t, const N_Vector y, N_Vector qdot,
void *user_data)
{
CVODESSolver *self = static_cast<CVODESSolver*>(user_data);
@@ -1255,7 +1229,7 @@ int CVODESSolver::RHSQ(sunrealtype t, const N_Vector y, N_Vector qdot,
return 0;
}
int CVODESSolver::RHSQB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector qBdot,
int CVODESSolver::RHSQB(realtype t, N_Vector y, N_Vector yB, N_Vector qBdot,
void *user_dataB)
{
CVODESSolver *self = static_cast<CVODESSolver*>(user_dataB);
@@ -1269,7 +1243,7 @@ int CVODESSolver::RHSQB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector qBdot,
return 0;
}
int CVODESSolver::RHSB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector yBdot,
int CVODESSolver::RHSB(realtype t, N_Vector y, N_Vector yB, N_Vector yBdot,
void *user_dataB)
{
CVODESSolver *self = static_cast<CVODESSolver*>(user_dataB);
@@ -1367,7 +1341,7 @@ CVODESSolver::~CVODESSolver()
// ARKStep interface
// ---------------------------------------------------------------------------
int ARKStepSolver::RHS1(sunrealtype t, const N_Vector y, N_Vector result,
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector result,
void *user_data)
{
// Get data from N_Vectors
@@ -1399,7 +1373,7 @@ int ARKStepSolver::RHS1(sunrealtype t, const N_Vector y, N_Vector result,
return (0);
}
int ARKStepSolver::RHS2(sunrealtype t, const N_Vector y, N_Vector result,
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector result,
void *user_data)
{
// Get data from N_Vectors
@@ -1425,9 +1399,9 @@ int ARKStepSolver::RHS2(sunrealtype t, const N_Vector y, N_Vector result,
return (0);
}
int ARKStepSolver::LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy,
SUNMatrix A, SUNMatrix, sunbooleantype jok,
sunbooleantype *jcur, sunrealtype gamma,
int ARKStepSolver::LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
SUNMatrix, booleantype jok, booleantype *jcur,
realtype gamma,
void*, N_Vector, N_Vector, N_Vector)
{
// Get data from N_Vectors
@@ -1445,7 +1419,7 @@ int ARKStepSolver::LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy,
}
int ARKStepSolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
N_Vector b, sunrealtype tol)
N_Vector b, realtype tol)
{
SundialsNVector mfem_x(x);
const SundialsNVector mfem_b(b);
@@ -1459,7 +1433,7 @@ int ARKStepSolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
return (self->f->SUNImplicitSolve(mfem_b, mfem_x, tol));
}
int ARKStepSolver::MassSysSetup(sunrealtype t, SUNMatrix M,
int ARKStepSolver::MassSysSetup(realtype t, SUNMatrix M,
void*, N_Vector, N_Vector, N_Vector)
{
ARKStepSolver *self = static_cast<ARKStepSolver*>(GET_CONTENT(M));
@@ -1470,7 +1444,7 @@ int ARKStepSolver::MassSysSetup(sunrealtype t, SUNMatrix M,
}
int ARKStepSolver::MassSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector x,
N_Vector b, sunrealtype tol)
N_Vector b, realtype tol)
{
SundialsNVector mfem_x(x);
const SundialsNVector mfem_b(b);
@@ -1490,7 +1464,7 @@ int ARKStepSolver::MassMult1(SUNMatrix M, N_Vector x, N_Vector v)
return (self->f->SUNMassMult(mfem_x, mfem_v));
}
int ARKStepSolver::MassMult2(N_Vector x, N_Vector v, sunrealtype t,
int ARKStepSolver::MassMult2(N_Vector x, N_Vector v, realtype t,
void* mtimes_data)
{
const SundialsNVector mfem_x(x);
@@ -1561,7 +1535,7 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
// Free existing solver memory and re-create with new vector size
if (resize)
{
MFEM_ARKode(Free)(&sundials_mem);
ARKStepFree(&sundials_mem);
sundials_mem = NULL;
}
}
@@ -1599,15 +1573,12 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
MFEM_VERIFY(sundials_mem, "error in ARKStepCreate()");
// Attach the ARKStepSolver as user-defined data
flag = MFEM_ARKode(SetUserData)(sundials_mem, this);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetUserData)) "()");
flag = ARKStepSetUserData(sundials_mem, this);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetUserData()");
// Set default tolerances
flag = MFEM_ARKode(SStolerances)(sundials_mem, default_rel_tol,
default_abs_tol);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SStolerances)) "()");
flag = ARKStepSStolerances(sundials_mem, default_rel_tol, default_abs_tol);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetSStolerances()");
// If implicit, attach MFEM linear solver by default
if (use_implicit) { UseMFEMLinearSolver(); }
@@ -1646,16 +1617,15 @@ void ARKStepSolver::Step(Vector &x, real_t &t, real_t &dt)
// Integrate the system
double tout = t + dt;
flag = MFEM_ARKode(Evolve)(sundials_mem, tout, *Y, &t, step_mode);
MFEM_VERIFY(flag >= 0, "error in " STR(MFEM_ARKode(Evolve)) "()");
flag = ARKStepEvolve(sundials_mem, tout, *Y, &t, step_mode);
MFEM_VERIFY(flag >= 0, "error in ARKStepEvolve()");
// Make sure host is up to date
Y->HostRead();
// Return the last incremental step size
flag = MFEM_ARKode(GetLastStep)(sundials_mem, &dt);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(GetLastStep)) "()");
flag = ARKStepGetLastStep(sundials_mem, &dt);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepGetLastStep()");
}
void ARKStepSolver::UseMFEMLinearSolver()
@@ -1681,14 +1651,12 @@ void ARKStepSolver::UseMFEMLinearSolver()
A->ops->destroy = MatDestroy;
// Attach the linear solver and matrix
flag = MFEM_ARKode(SetLinearSolver)(sundials_mem, LSA, A);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetLinearSolver)) "()");
flag = ARKStepSetLinearSolver(sundials_mem, LSA, A);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinearSolver()");
// Set the linear system evaluation function
flag = MFEM_ARKode(SetLinSysFn)(sundials_mem, ARKStepSolver::LinSysSetup);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetLinSysFn)) "()");
flag = ARKStepSetLinSysFn(sundials_mem, ARKStepSolver::LinSysSetup);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinSysFn()");
}
void ARKStepSolver::UseSundialsLinearSolver()
@@ -1698,13 +1666,12 @@ void ARKStepSolver::UseSundialsLinearSolver()
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
// Create linear solver
LSA = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
LSA = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
MFEM_VERIFY(LSA, "error in SUNLinSol_SPGMR()");
// Attach linear solver
flag = MFEM_ARKode(SetLinearSolver)(sundials_mem, LSA, NULL);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetLinearSolver)) "()");
flag = ARKStepSetLinearSolver(sundials_mem, LSA, NULL);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinearSolver()");
}
void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
@@ -1731,14 +1698,12 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
M->ops->destroy = MatDestroy;
// Attach the linear solver and matrix
flag = MFEM_ARKode(SetMassLinearSolver)(sundials_mem, LSM, M, tdep);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetMassLinearSolver)) "()");
flag = ARKStepSetMassLinearSolver(sundials_mem, LSM, M, tdep);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetLinearSolver()");
// Set the linear system function
flag = MFEM_ARKode(SetMassFn)(sundials_mem, ARKStepSolver::MassSysSetup);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetMassFn)) "()");
flag = ARKStepSetMassFn(sundials_mem, ARKStepSolver::MassSysSetup);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassFn()");
// Check that the ODE is not expressed in EXPLICIT form
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
@@ -1751,19 +1716,17 @@ void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
if (LSM != NULL) { SUNLinSolFree(LSM); LSM = NULL; }
// Create linear solver
LSM = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
LSM = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
MFEM_VERIFY(LSM, "error in SUNLinSol_SPGMR()");
// Attach linear solver
flag = MFEM_ARKode(SetMassLinearSolver)(sundials_mem, LSM, NULL, tdep);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetMassLinearSolver)) "()");
flag = ARKStepSetMassLinearSolver(sundials_mem, LSM, NULL, tdep);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassLinearSolver()");
// Attach matrix multiplication function
flag = MFEM_ARKode(SetMassTimes)(sundials_mem, NULL,
ARKStepSolver::MassMult2, this);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetMassTimes)) "()");
flag = ARKStepSetMassTimes(sundials_mem, NULL, ARKStepSolver::MassMult2,
this);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassTimes()");
// Check that the ODE is not expressed in EXPLICIT form
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
@@ -1776,23 +1739,20 @@ void ARKStepSolver::SetStepMode(int itask)
void ARKStepSolver::SetSStolerances(double reltol, double abstol)
{
flag = MFEM_ARKode(SStolerances)(sundials_mem, reltol, abstol);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SStolerances)) "()");
flag = ARKStepSStolerances(sundials_mem, reltol, abstol);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSStolerances()");
}
void ARKStepSolver::SetMaxStep(double dt_max)
{
flag = MFEM_ARKode(SetMaxStep)(sundials_mem, dt_max);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetMaxStep)) "()");
flag = ARKStepSetMaxStep(sundials_mem, dt_max);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMaxStep()");
}
void ARKStepSolver::SetOrder(int order)
{
flag = MFEM_ARKode(SetOrder)(sundials_mem, order);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetOrder)) "()");
flag = ARKStepSetOrder(sundials_mem, order);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetOrder()");
}
void ARKStepSolver::SetERKTableNum(ARKODE_ERKTableID table_id)
@@ -1816,9 +1776,8 @@ void ARKStepSolver::SetIMEXTableNum(ARKODE_ERKTableID etable_id,
void ARKStepSolver::SetFixedStep(double dt)
{
flag = MFEM_ARKode(SetFixedStep)(sundials_mem, dt);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(SetFixedStep)) "()");
flag = ARKStepSetFixedStep(sundials_mem, dt);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetFixedStep()");
}
void ARKStepSolver::PrintInfo() const
@@ -1840,19 +1799,18 @@ void ARKStepSolver::PrintInfo() const
&netfails);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepGetTimestepperStats()");
flag = MFEM_ARKode(GetStepStats)(sundials_mem,
&nsteps,
&hinused,
&hlast,
&hcur,
&tcur);
flag = ARKStepGetStepStats(sundials_mem,
&nsteps,
&hinused,
&hlast,
&hcur,
&tcur);
// Get nonlinear solver stats
flag = MFEM_ARKode(GetNonlinSolvStats)(sundials_mem,
&nniters,
&nncfails);
MFEM_VERIFY(flag == ARK_SUCCESS,
"error in " STR(MFEM_ARKode(GetNonlinSolvStats)) "()");
flag = ARKStepGetNonlinSolvStats(sundials_mem,
&nniters,
&nncfails);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepGetNonlinSolvStats()");
mfem::out <<
"ARKStep:\n"
@@ -1880,7 +1838,7 @@ ARKStepSolver::~ARKStepSolver()
SUNMatDestroy(A);
SUNLinSolFree(LSA);
SUNNonlinSolFree(NLS);
MFEM_ARKode(Free)(&sundials_mem);
ARKStepFree(&sundials_mem);
}
// ---------------------------------------------------------------------------
@@ -1903,7 +1861,7 @@ int KINSolver::Mult(const N_Vector u, N_Vector fu, void *user_data)
// Wrapper for computing Jacobian-vector products
int KINSolver::GradientMult(N_Vector v, N_Vector Jv, N_Vector u,
sunbooleantype *new_u, void *user_data)
booleantype *new_u, void *user_data)
{
const SundialsNVector mfem_v(v);
SundialsNVector mfem_Jv(Jv);
@@ -1943,7 +1901,7 @@ int KINSolver::LinSysSetup(N_Vector u, N_Vector, SUNMatrix J,
// Wrapper for solving linear systems J u = b
int KINSolver::LinSysSolve(SUNLinearSolver LS, SUNMatrix, N_Vector u,
N_Vector b, sunrealtype)
N_Vector b, realtype)
{
SundialsNVector mfem_u(u), mfem_b(b);
KINSolver *self = static_cast<KINSolver*>(GET_CONTENT(LS));
@@ -2002,11 +1960,7 @@ KINSolver::KINSolver(int strategy, bool oper_grad)
f_scale = new SundialsNVector();
// Default abs_tol and print_level
#if MFEM_SUNDIALS_VERSION < 70000
abs_tol = pow(UNIT_ROUNDOFF, 1.0/3.0);
#else
abs_tol = pow(SUN_UNIT_ROUNDOFF, 1.0/3.0);
#endif
print_level = 0;
}
@@ -2020,11 +1974,7 @@ KINSolver::KINSolver(MPI_Comm comm, int strategy, bool oper_grad)
f_scale = new SundialsNVector(comm);
// Default abs_tol and print_level
#if MFEM_SUNDIALS_VERSION < 70000
abs_tol = pow(UNIT_ROUNDOFF, 1.0/3.0);
#else
abs_tol = pow(SUN_UNIT_ROUNDOFF, 1.0/3.0);
#endif
print_level = 0;
}
#endif
@@ -2136,7 +2086,7 @@ void KINSolver::SetOperator(const Operator &op)
if (A != NULL) { SUNMatDestroy(A); A = NULL; }
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
LSA = SUNLinSol_SPGMR(*Y, SUN_PREC_NONE, 0, Sundials::GetContext());
LSA = SUNLinSol_SPGMR(*Y, PREC_NONE, 0, Sundials::GetContext());
MFEM_VERIFY(LSA, "error in SUNLinSol_SPGMR()");
flag = KINSetLinearSolver(sundials_mem, LSA, NULL);
@@ -2205,12 +2155,12 @@ void KINSolver::SetJFNKSolver(Solver &solver)
if (LSA != NULL) { SUNLinSolFree(LSA); LSA = NULL; }
// Setup FGMRES
LSA = SUNLinSol_SPFGMR(*Y, prec ? SUN_PREC_RIGHT : SUN_PREC_NONE, maxli,
LSA = SUNLinSol_SPFGMR(*Y, prec ? PREC_RIGHT : PREC_NONE, maxli,
Sundials::GetContext());
MFEM_VERIFY(LSA, "error in SUNLinSol_SPFGMR()");
flag = SUNLinSol_SPFGMRSetMaxRestarts(LSA, maxlrs);
MFEM_VERIFY(flag == SUN_SUCCESS, "error in SUNLinSol_SPFGMR()");
MFEM_VERIFY(flag == SUNLS_SUCCESS, "error in SUNLinSol_SPFGMR()");
flag = KINSetLinearSolver(sundials_mem, LSA, NULL);
MFEM_VERIFY(flag == KIN_SUCCESS, "error in KINSetLinearSolver()");
@@ -2367,21 +2317,18 @@ void KINSolver::Mult(Vector &x,
if (rank == 0)
{
#if MFEM_SUNDIALS_VERSION < 70000
flag = KINSetPrintLevel(sundials_mem, print_level);
MFEM_VERIFY(flag == KIN_SUCCESS, "KINSetPrintLevel() failed!");
#endif
// NOTE: there is no KINSetPrintLevel in SUNDIALS v7!
#ifdef SUNDIALS_BUILD_WITH_MONITORING
if (jfnk && print_level)
{
flag = SUNLinSolSetInfoFile_SPFGMR(LSA, stdout);
MFEM_VERIFY(flag == SUN_SUCCESS,
MFEM_VERIFY(flag == SUNLS_SUCCESS,
"error in SUNLinSolSetInfoFile_SPFGMR()");
flag = SUNLinSolSetPrintLevel_SPFGMR(LSA, 1);
MFEM_VERIFY(flag == SUN_SUCCESS,
MFEM_VERIFY(flag == SUNLS_SUCCESS,
"error in SUNLinSolSetPrintLevel_SPFGMR()");
}
#endif
+31 -65
View File
@@ -54,10 +54,6 @@
#include <functional>
#define MFEM_SUNDIALS_VERSION \
(SUNDIALS_VERSION_MAJOR*10000 + SUNDIALS_VERSION_MINOR*100 + \
SUNDIALS_VERSION_PATCH)
#if (SUNDIALS_VERSION_MAJOR < 6)
/// (DEPRECATED) Map SUNDIALS version >= 6 datatypes and constants to
@@ -72,30 +68,13 @@ constexpr ARKODE_ERKTableID ARKODE_FEHLBERG_13_7_8 = FEHLBERG_13_7_8;
/// arbitrary type for more compact backwards compatibility
using SUNContext = void*;
/// 'sunrealtype' was first introduced in v6.0.0
typedef realtype sunrealtype;
/// 'sunbooleantype' was first introduced in v6.0.0
typedef booleantype sunbooleantype;
/// New constant names introduced in v6.0.0
enum { SUN_PREC_NONE, SUN_PREC_LEFT, SUN_PREC_RIGHT, SUN_PREC_BOTH };
// KIN_ORTH_MGS was introduced in SUNDIALS v6; here, we define it just so that
// it can be used as the default option in the second parameter of
// KINSolver::EnableAndersonAcc -- the actual value of the parameter will be
// ignored when using SUNDIALS < v6.
#define KIN_ORTH_MGS 0
#endif // #if SUNDIALS_VERSION_MAJOR < 6
#if (SUNDIALS_VERSION_MAJOR < 7)
/** @brief The enum constant SUN_SUCCESS was added in v7 as a replacement of
various *_SUCCESS macros that were removed in v7. */
enum { SUN_SUCCESS = 0 };
#endif // #if SUNDIALS_VERSION_MAJOR < 7
#endif // SUNDIALS_VERSION_MAJOR < 6
namespace mfem
{
@@ -265,14 +244,7 @@ public:
#ifdef MFEM_USE_MPI
/// Returns the MPI communicator for the internal N_Vector x.
inline MPI_Comm GetComm() const
{
#if SUNDIALS_VERSION_MAJOR < 7
return *static_cast<MPI_Comm*>(N_VGetCommunicator(x));
#else
return N_VGetCommunicator(x);
#endif
}
inline MPI_Comm GetComm() const { return *static_cast<MPI_Comm*>(N_VGetCommunicator(x)); }
/// Returns the MPI global length for the internal N_Vector x.
inline long GlobalSize() const { return N_VGetLength(x); }
@@ -424,26 +396,24 @@ protected:
int root_components; /// Number of components in gout
/// Wrapper to compute the ODE rhs function.
static int RHS(sunrealtype t, const N_Vector y, N_Vector ydot,
void *user_data);
static int RHS(realtype t, const N_Vector y, N_Vector ydot, void *user_data);
/// Setup the linear system $ A x = b $.
static int LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy, SUNMatrix A,
sunbooleantype jok, sunbooleantype *jcur,
sunrealtype gamma, void *user_data, N_Vector tmp1,
static int LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
booleantype jok, booleantype *jcur,
realtype gamma, void *user_data, N_Vector tmp1,
N_Vector tmp2, N_Vector tmp3);
/// Solve the linear system $ A x = b $.
static int LinSysSolve(SUNLinearSolver LS, SUNMatrix A, N_Vector x,
N_Vector b, sunrealtype tol);
N_Vector b, realtype tol);
/// Prototype to define root finding for CVODE
static int root(sunrealtype t, N_Vector y, sunrealtype *gout,
void *user_data);
static int root(realtype t, N_Vector y, realtype *gout, void *user_data);
/// Typedef for root finding functions
typedef std::function<int(sunrealtype t, Vector y, Vector gout,
CVODESolver *)> RootFunction;
typedef std::function<int(realtype t, Vector y, Vector gout, CVODESolver *)>
RootFunction;
/// A class member to facilitate pointing to a user-specified root function
RootFunction root_func;
@@ -451,8 +421,7 @@ protected:
/// Typedef declaration for error weight functions
typedef std::function<int(Vector y, Vector w, CVODESolver*)> EWTFunction;
/** @brief A class member to facilitate pointing to a user-specified error
weight function */
/// A class member to facilitate pointing to a user-specified error weight function
EWTFunction ewt_func;
public:
@@ -486,7 +455,7 @@ public:
@note If this method is called a second time with a different problem
size, then any non-default user-set options will be lost and will need
to be set again. */
void Init(TimeDependentOperator &f_) override;
void Init(TimeDependentOperator &f_);
/// Integrate the ODE with CVODE using the specified step mode.
/** @param[in,out] x On output, the solution vector at the requested output
@@ -562,15 +531,14 @@ protected:
int indexB; ///< backward problem index
/// Wrapper to compute the ODE RHS Quadrature function.
static int RHSQ(sunrealtype t, const N_Vector y, N_Vector qdot,
void *user_data);
static int RHSQ(realtype t, const N_Vector y, N_Vector qdot, void *user_data);
/// Wrapper to compute the ODE RHS backward function.
static int RHSB(sunrealtype t, N_Vector y,
static int RHSB(realtype t, N_Vector y,
N_Vector yB, N_Vector yBdot, void *user_dataB);
/// Wrapper to compute the ODE RHS Backwards Quadrature function.
static int RHSQB(sunrealtype t, N_Vector y, N_Vector yB,
static int RHSQB(realtype t, N_Vector y, N_Vector yB,
N_Vector qBdot, void *user_dataB);
/// Error control function
@@ -686,15 +654,15 @@ public:
void SetSVtolerancesB(double reltol, Vector abstol);
/// Setup the linear system A x = b
static int LinSysSetupB(sunrealtype t, N_Vector y, N_Vector yB, N_Vector fyB,
static int LinSysSetupB(realtype t, N_Vector y, N_Vector yB, N_Vector fyB,
SUNMatrix A,
sunbooleantype jok, sunbooleantype *jcur,
sunrealtype gamma, void *user_data, N_Vector tmp1,
booleantype jok, booleantype *jcur,
realtype gamma, void *user_data, N_Vector tmp1,
N_Vector tmp2, N_Vector tmp3);
/// Solve the linear system A x = b
static int LinSysSolveB(SUNLinearSolver LS, SUNMatrix A, N_Vector x,
N_Vector b, sunrealtype tol);
N_Vector b, realtype tol);
/// Destroy the associated CVODES memory and SUNDIALS objects.
@@ -727,35 +695,33 @@ protected:
RHS1 is explicit RHS and RHS2 the implicit RHS for IMEX integration. When
purely implicit or explicit only RHS1 is used. */
///@{
static int RHS1(sunrealtype t, const N_Vector y, N_Vector ydot,
void *user_data);
static int RHS2(sunrealtype t, const N_Vector y, N_Vector ydot,
void *user_data);
static int RHS1(realtype t, const N_Vector y, N_Vector ydot, void *user_data);
static int RHS2(realtype t, const N_Vector y, N_Vector ydot, void *user_data);
///@}
/// Setup the linear system $ A x = b $.
static int LinSysSetup(sunrealtype t, N_Vector y, N_Vector fy, SUNMatrix A,
SUNMatrix M, sunbooleantype jok, sunbooleantype *jcur,
sunrealtype gamma, void *user_data, N_Vector tmp1,
static int LinSysSetup(realtype t, N_Vector y, N_Vector fy, SUNMatrix A,
SUNMatrix M, booleantype jok, booleantype *jcur,
realtype gamma, void *user_data, N_Vector tmp1,
N_Vector tmp2, N_Vector tmp3);
/// Solve the linear system $ A x = b $.
static int LinSysSolve(SUNLinearSolver LS, SUNMatrix A, N_Vector x,
N_Vector b, sunrealtype tol);
N_Vector b, realtype tol);
/// Setup the linear system $ M x = b $.
static int MassSysSetup(sunrealtype t, SUNMatrix M, void *user_data,
static int MassSysSetup(realtype t, SUNMatrix M, void *user_data,
N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
/// Solve the linear system $ M x = b $.
static int MassSysSolve(SUNLinearSolver LS, SUNMatrix M, N_Vector x,
N_Vector b, sunrealtype tol);
N_Vector b, realtype tol);
/// Compute the matrix-vector product $ v = M x $.
static int MassMult1(SUNMatrix M, N_Vector x, N_Vector v);
/// Compute the matrix-vector product $v = M_t x $ at time t.
static int MassMult2(N_Vector x, N_Vector v, sunrealtype t,
static int MassMult2(N_Vector x, N_Vector v, realtype t,
void* mtimes_data);
public:
@@ -791,7 +757,7 @@ public:
@note If this method is called a second time with a different problem
size, then any non-default user-set options will be lost and will need
to be set again. */
void Init(TimeDependentOperator &f_) override;
void Init(TimeDependentOperator &f_);
/// Integrate the ODE with ARKode using the specified step mode.
/**
@@ -905,7 +871,7 @@ protected:
/// Wrapper to compute the Jacobian-vector product $ J(u) v = Jv $.
static int GradientMult(N_Vector v, N_Vector Jv, N_Vector u,
sunbooleantype *new_u, void *user_data);
booleantype *new_u, void *user_data);
/// Setup the linear system $ J u = b $.
static int LinSysSetup(N_Vector u, N_Vector fu, SUNMatrix J,
@@ -913,7 +879,7 @@ protected:
/// Solve the linear system $ J u = b $.
static int LinSysSolve(SUNLinearSolver LS, SUNMatrix J, N_Vector u,
N_Vector b, sunrealtype tol);
N_Vector b, realtype tol);
/// Setup the preconditioner.
static int PrecSetup(N_Vector uu,
+3 -11
View File
@@ -24,8 +24,6 @@
#include <cstdlib>
#include <iostream>
#include <limits>
#include <type_traits>
#include <initializer_list>
#if defined(_MSC_VER) && (_MSC_VER < 1800)
#include <float.h>
#define isfinite _finite
@@ -121,16 +119,10 @@ public:
Vector(int size_, MemoryType h_mt, MemoryType d_mt)
: data(size_, h_mt, d_mt), size(size_) { }
/// Create a vector from a statically sized C-style array of convertible type
template <typename CT, int N>
explicit Vector(const CT (&values)[N]) : Vector(N)
{ std::copy(values, values + N, begin()); }
/// Create a vector using a braced initializer list
template <typename CT, typename std::enable_if<
std::is_convertible<CT,real_t>::value,bool>::type = true>
explicit Vector(std::initializer_list<CT> values) : Vector(values.size())
{ std::copy(values.begin(), values.end(), begin()); }
template <int N, typename T = real_t>
explicit Vector(const T (&values)[N]) : Vector(N)
{ std::copy(values, values + N, GetData()); }
/// Enable execution of Vector operations using the mfem::Device.
/** The default is to use Backend::CPU (serial execution on each MPI rank),
+4 -8
View File
@@ -32,7 +32,6 @@ set(SRCS
vtk.cpp
wedge.cpp
submesh/submesh.cpp
submesh/ncsubmesh.cpp
submesh/submesh_utils.cpp
submesh/transfermap.cpp
)
@@ -59,7 +58,6 @@ set(HDRS
vertex.hpp
vtk.hpp
wedge.hpp
submesh/ncsubmesh.hpp
submesh/submesh.hpp
submesh/submesh_utils.hpp
submesh/transfer_category.hpp
@@ -70,17 +68,15 @@ if (MFEM_USE_MPI)
list(APPEND SRCS
pmesh.cpp
pncmesh.cpp
submesh/pncsubmesh.cpp
submesh/psubmesh.cpp
submesh/ptransfermap.cpp)
submesh/ptransfermap.cpp
submesh/psubmesh.cpp)
# If this list (HDRS -> HEADERS) is used for install, we probably want the
# headers added all the time.
list(APPEND HDRS
pmesh.hpp
pncmesh.hpp
submesh/pncsubmesh.hpp
submesh/psubmesh.hpp
submesh/ptransfermap.hpp)
submesh/ptransfermap.hpp
submesh/psubmesh.hpp)
endif()
if (MFEM_USE_PUMI)
+5 -65
View File
@@ -2033,18 +2033,6 @@ int Mesh::AddBdrElement(Element *elem)
return NumOfBdrElements++;
}
void Mesh::AddBdrElements(Array<Element *> &bdr_elems,
const Array<int> &new_be_to_face)
{
boundary.Reserve(boundary.Size() + bdr_elems.Size());
MFEM_ASSERT(bdr_elems.Size() == new_be_to_face.Size(), "wrong size");
for (int i = 0; i < bdr_elems.Size(); i++)
{
AddBdrElement(bdr_elems[i]);
}
be_to_face.Append(new_be_to_face);
}
int Mesh::AddBdrSegment(int v1, int v2, int attr)
{
CheckEnlarge(boundary, NumOfBdrElements);
@@ -4411,49 +4399,6 @@ Mesh::Mesh(real_t *vertices_, int num_vertices,
FinalizeTopology();
}
Mesh::Mesh( const NURBSExtension& ext )
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
{
SetEmpty();
/// make an internal copy of the NURBSExtension
NURBSext = new NURBSExtension( ext );
Dim = NURBSext->Dimension();
NumOfVertices = NURBSext->GetNV();
NumOfElements = NURBSext->GetNE();
NumOfBdrElements = NURBSext->GetNBE();
NURBSext->GetElementTopo(elements);
NURBSext->GetBdrElementTopo(boundary);
vertices.SetSize(NumOfVertices);
if (NURBSext->HavePatches())
{
NURBSFECollection *fec = new NURBSFECollection(NURBSext->GetOrder());
FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
Ordering::byVDIM);
Nodes = new GridFunction(fes);
Nodes->MakeOwner(fec);
NURBSext->SetCoordsFromPatches(*Nodes);
own_nodes = 1;
spaceDim = Nodes->VectorDim();
for (int i = 0; i < spaceDim; i++)
{
Vector vert_val;
Nodes->GetNodalValues(vert_val, i+1);
for (int j = 0; j < NumOfVertices; j++)
{
vertices[j](i) = vert_val(j);
}
}
}
else
{
MFEM_ABORT("NURBS mesh has no patches.");
}
FinalizeMesh();
}
Element *Mesh::NewElement(int geom)
{
switch (geom)
@@ -5672,7 +5617,7 @@ std::vector<int> Mesh::CreatePeriodicVertexMapping(
std::vector<int> v2v(GetNV());
for (size_t i = 0; i < v2v.size(); i++)
{
v2v[i] = static_cast<int>(i);
v2v[i] = i;
}
for (const auto &r2p : replica2primary)
{
@@ -7401,12 +7346,6 @@ void Mesh::GetBdrElementAdjacentElement2(
info = fi.Elem1Inf + ori;
}
void Mesh::SetAttribute(int i, int attr)
{
elements[i]->SetAttribute(attr);
if (ncmesh) ncmesh->SetAttribute(i, attr);
}
Element::Type Mesh::GetElementType(int i) const
{
return elements[i]->GetType();
@@ -7733,6 +7672,7 @@ void Mesh::AddQuadFaceElement(int lf, int gf, int el,
void Mesh::GenerateFaces()
{
int nfaces = GetNumFaces();
for (auto &f : faces)
{
FreeElement(f);
@@ -11204,14 +11144,14 @@ const CoarseFineTransformations &Mesh::GetRefinementTransforms() const
if (code)
{
int &matrix = mat_no[code];
if (!matrix) { matrix = static_cast<int>(mat_no.size()); }
if (!matrix) { matrix = mat_no.size(); }
index = matrix-1;
}
CoarseFineTr.embeddings[j].matrix = index;
}
DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
pmats.SetSize(Dim, Dim+1, static_cast<int>((mat_no.size())));
pmats.SetSize(Dim, Dim+1, mat_no.size());
// calculate the point matrices used
std::map<unsigned, int>::iterator it;
@@ -13931,7 +13871,7 @@ void MeshPartitioner::ExtractPart(int part_id, MeshPart &mesh_part) const
const int *v = elem->GetVertices();
vertex_set.insert(v, v + nv);
}
vertex_loc_to_glob.SetSize(static_cast<int>(vertex_set.size()));
vertex_loc_to_glob.SetSize(vertex_set.size());
std::copy(vertex_set.begin(), vertex_set.end(), // src
vertex_loc_to_glob.begin()); // dest
}
+1 -24
View File
@@ -895,9 +895,6 @@ public:
///@}
/// Construct a Mesh from a NURBSExtension
explicit Mesh( const NURBSExtension& ext );
/** @anchor mfem_Mesh_construction
@name Methods for piecewise Mesh construction.
@@ -996,17 +993,6 @@ public:
/// @note Ownership of @a elem will pass to the Mesh object
int AddBdrElement(Element *elem);
/**
* @brief Add an array of boundary elements to the mesh, along with map from
* the elements to their faces
* @param[in] bdr_elems The set of boundary element pointers, ownership of
* the pointers will be transferred to the Mesh object
* @param[in] be_to_face The map from the boundary element index to the face
* index
*/
void AddBdrElements(Array<Element *> &bdr_elems,
const Array<int> &be_to_face);
int AddBdrSegment(int v1, int v2, int attr = 1);
int AddBdrSegment(const int *vi, int attr = 1);
@@ -1116,15 +1102,6 @@ public:
have two adjacent faces in 3D, or edges in 2D. */
void RemoveInternalBoundaries();
/**
* @brief Clear the boundary element to edge map.
*/
void DeleteBoundaryElementToEdge()
{
delete bel_to_edge;
bel_to_edge = nullptr;
}
/// @}
/// @name Element ordering methods
@@ -1389,7 +1366,7 @@ public:
int GetAttribute(int i) const { return elements[i]->GetAttribute(); }
/// Set the attribute of element i.
void SetAttribute(int i, int attr);
void SetAttribute(int i, int attr) { elements[i]->SetAttribute(attr); }
/// Return the attribute of boundary element i.
int GetBdrAttribute(int i) const { return boundary[i]->GetAttribute(); }

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