Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e11faf07 | ||
|
|
2a482c0c9e |
@@ -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
|
||||
@@ -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"
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
# Object and library files
|
||||
*.o
|
||||
*.o.tmp
|
||||
/libmfem.*
|
||||
/miniapps/common/libmfem-common.*
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MassIntegrator::Kernels MassIntegrator::kernels;
|
||||
MassIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -16,7 +16,7 @@
|
||||
#include "bilinearform.hpp"
|
||||
|
||||
#include "../linalg/operator.hpp"
|
||||
#include "../linalg/op_handle.hpp"
|
||||
#include "../linalg/handle.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
+7
-7
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+19
-156
@@ -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_)
|
||||
{ }
|
||||
|
||||
@@ -45,7 +45,6 @@ list(APPEND HDRS
|
||||
gecko.hpp
|
||||
globals.hpp
|
||||
zstr.hpp
|
||||
handle.hpp
|
||||
hash.hpp
|
||||
isockstream.hpp
|
||||
kdtree.hpp
|
||||
|
||||
+1
-1
@@ -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
@@ -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 ©) 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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,8 +107,6 @@ void SetGlobalMPI_Comm(MPI_Comm comm);
|
||||
|
||||
#endif
|
||||
|
||||
const char* getenv(const char* name);
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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.");
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user