mirror of
https://github.com/paboyle/Grid.git
synced 2026-08-20 01:19:35 +01:00
Compare commits
176
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4ec5d0009 | ||
|
|
a5e4ce3e48 | ||
|
|
2900ce33b5 | ||
|
|
ea5bf89955 | ||
|
|
109b77ea75 | ||
|
|
333315569c | ||
|
|
995e149256 | ||
|
|
971b0f3546 | ||
|
|
ab9603b28d | ||
|
|
adfd5853cc | ||
|
|
cc54c90ddc | ||
|
|
6a4071cdc2 | ||
|
|
e92be14df8 | ||
|
|
e9be1a91b3 | ||
|
|
7db3b96d2d | ||
|
|
429ad2a71a | ||
|
|
0b1598e9ef | ||
|
|
8d04b91932 | ||
|
|
665094d94b | ||
|
|
919d126af1 | ||
|
|
abd5df1729 | ||
|
|
3243ad91e8 | ||
|
|
c10d451f4d | ||
|
|
9c4a61850e | ||
|
|
5e3fe24412 | ||
|
|
7b81ca6b52 | ||
|
|
8c9ea4cde2 | ||
|
|
0ac72cb6a3 | ||
|
|
c4b089cf15 | ||
|
|
85e1bbf4bc | ||
|
|
032f111c8b | ||
|
|
e38528888a | ||
|
|
7c9a6d354e | ||
|
|
3ec90803ac | ||
|
|
c22473f15d | ||
|
|
55c064de28 | ||
|
|
06ce057920 | ||
|
|
76b4bd6d12 | ||
|
|
b5541aab55 | ||
|
|
a7160ac513 | ||
|
|
02d0301c9f | ||
|
|
a6cdf20c18 | ||
|
|
ad9a413892 | ||
|
|
1fddd2c29b | ||
|
|
2f75067569 | ||
|
|
6e8a00f215 | ||
|
|
702773e5fb | ||
|
|
4dfbd850ff | ||
|
|
b039e659af | ||
|
|
d16d44dda0 | ||
|
|
1c19389ba6 | ||
|
|
02fdff674c | ||
|
|
fd8b6a23a6 | ||
|
|
9e3a51d078 | ||
|
|
6f7a2ad7c7 | ||
|
|
499d656949 | ||
|
|
ba68f09026 | ||
|
|
3bdeeb73ef | ||
|
|
19868a800f | ||
|
|
df908ee872 | ||
|
|
84715ff4b9 | ||
|
|
5792195073 | ||
|
|
fb5662a449 | ||
|
|
6b2ad3db80 | ||
|
|
f1a969f0c3 | ||
|
|
f18320a152 | ||
|
|
bfcde59199 | ||
|
|
f23e9e70cd | ||
|
|
06fcd31da0 | ||
|
|
7e4fe99b1e | ||
|
|
159ea3d64d | ||
|
|
1f55c13bc4 | ||
|
|
d68b111d06 | ||
|
|
41f5a02204 | ||
|
|
7647576863 | ||
|
|
f11ba18df2 | ||
|
|
cf8587e401 | ||
|
|
7dd35ef749 | ||
|
|
41e570ddce | ||
|
|
a452131b50 | ||
|
|
4e49ca55ab | ||
|
|
c3f4474401 | ||
|
|
3d3eff86f3 | ||
|
|
fc9f154ac1 | ||
|
|
4aa0bca4dc | ||
|
|
905da6f083 | ||
|
|
86c7f29183 | ||
|
|
b0c99f876e | ||
|
|
bf5fcdc860 | ||
|
|
b58a1508fa | ||
|
|
4d527e81fa | ||
|
|
7803580aa6 | ||
|
|
32654db366 | ||
|
|
cd340cfab3 | ||
|
|
f32866b2ff | ||
|
|
1cd1dc091e | ||
|
|
0493656e86 | ||
|
|
66fd504c4d | ||
|
|
be4dd2b52f | ||
|
|
707d059766 | ||
|
|
f08c755ae6 | ||
|
|
dbbfdd4e4b | ||
|
|
f967fb40bf | ||
|
|
74e0f846cb | ||
|
|
303a4d26e5 | ||
|
|
119888653c | ||
|
|
a9f42c08f9 | ||
|
|
e79adc9d31 | ||
|
|
5a9056cd93 | ||
|
|
012c36ab5a | ||
|
|
5c4574f9aa | ||
|
|
a424775884 | ||
|
|
d6b1388741 | ||
|
|
796c6cae4e | ||
|
|
1a8064d6d9 | ||
|
|
43648924c3 | ||
|
|
bf2140e74d | ||
|
|
a1119266c1 | ||
|
|
a0f00c0eca | ||
|
|
d358954a84 | ||
|
|
aee00bdfb5 | ||
|
|
cf324b0fa1 | ||
|
|
b314dc224d | ||
|
|
1bbd62498e | ||
|
|
f3c3b1c04b | ||
|
|
069f98b253 | ||
|
|
dfd0503eae | ||
|
|
c629b2e87e | ||
|
|
7c8462abd1 | ||
|
|
95a6a0bde7 | ||
|
|
bba328fac5 | ||
|
|
41362349f3 | ||
|
|
12e3499b6d | ||
|
|
9576011011 | ||
|
|
155b34c1aa | ||
|
|
982ffe9ebe | ||
|
|
0251ecaeab | ||
|
|
372a27d645 | ||
|
|
72b4a061f3 | ||
|
|
29198efabe | ||
|
|
50aa51f93a | ||
|
|
79ccc81a86 | ||
|
|
3f0fdbb597 | ||
|
|
ea57bd8f03 | ||
|
|
bdba5b8403 | ||
|
|
58cc6ca9c0 | ||
|
|
e5996b440d | ||
|
|
ad9d03fd85 | ||
|
|
4de160ce20 | ||
|
|
fc8c8ce6e7 | ||
|
|
ddbb7f07c8 | ||
|
|
1e29c59bcc | ||
|
|
b6abdc3845 | ||
|
|
2fadd8bb62 | ||
|
|
60df2dd5d0 | ||
|
|
66b529b345 | ||
|
|
1304172a93 | ||
|
|
1315d4604d | ||
|
|
a31af31328 | ||
|
|
26c3c7d8f9 | ||
|
|
0650d7c7eb | ||
|
|
068f95ad2d | ||
|
|
f4fbf7c9ca | ||
|
|
843d6497b2 | ||
|
|
747c167658 | ||
|
|
fca2c5dba0 | ||
|
|
e12bc7f07c | ||
|
|
dc6ae51cab | ||
|
|
baa70d8ec9 | ||
|
|
c93b338bdd | ||
|
|
c0472aa0ec | ||
|
|
09552cfd73 | ||
|
|
003fec509c | ||
|
|
773a82d87f | ||
|
|
286c29d6fb | ||
|
|
969b0a3922 |
@@ -0,0 +1,183 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## What This Is
|
||||||
|
|
||||||
|
Grid is a data-parallel C++ library for lattice QCD. It provides SIMD-vectorised lattice containers, MPI-based domain decomposition, GPU acceleration (CUDA/HIP/SYCL), and a full suite of QCD algorithms including HMC.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Uses GNU Autotools. The bootstrap step only needs to run once (or after `configure.ac` changes).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./bootstrap.sh # downloads Eigen 3.4.0, generates configure
|
||||||
|
mkdir build && cd build
|
||||||
|
../configure [options]
|
||||||
|
make -j$(nproc)
|
||||||
|
make check # run root-level tests
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Key configure options:
|
||||||
|
|
||||||
|
| Option | Common values |
|
||||||
|
|--------|---------------|
|
||||||
|
| `--enable-simd=` | `AVX2`, `AVX512`, `KNL`, `A64FX`, `NEONv8`, `GPU` |
|
||||||
|
| `--enable-comms=` | `mpi-auto`, `mpi3-auto`, `none` |
|
||||||
|
| `--enable-accelerator=` | `cuda`, `hip`, `sycl` |
|
||||||
|
| `--enable-shm=` | `shmopen`, `hugetlbfs`, `nvlink` |
|
||||||
|
| `--enable-Nc=` | `3` (default), `2`, `4`, `5` |
|
||||||
|
| `--with-gmp=`, `--with-mpfr=`, `--with-fftw=`, `--with-lime=` | paths to libs |
|
||||||
|
| `--enable-hdf5`, `--enable-mkl`, `--enable-lapack` | optional features |
|
||||||
|
|
||||||
|
GPU builds additionally need `--enable-gen-simd-width=64` (sets 512-bit SIMD width for GPU warp/wavefront sizing) and `--enable-unified=no --enable-shm=nvlink` for multi-GPU runs.
|
||||||
|
|
||||||
|
To speed up compilation, `--disable-fermion-reps --disable-gparity` skips instantiating G-parity and higher-representation fermion operators.
|
||||||
|
|
||||||
|
Platform recipes from `README.md`:
|
||||||
|
- **KNL**: `--enable-simd=KNL --enable-comms=mpi3-auto --enable-mkl`
|
||||||
|
- **Skylake/Haswell**: `--enable-simd=AVX512` or `AVX2` + `--enable-comms=mpi3-auto`
|
||||||
|
- **AMD EPYC**: `--enable-simd=AVX2 --enable-comms=mpi3`
|
||||||
|
- **A64FX (Fugaku)**: `--enable-simd=A64FX --enable-comms=mpi3 --enable-shm=shmget` (see `SVE_README.txt`)
|
||||||
|
|
||||||
|
Complete, working `configure` invocations for specific HPC systems (Frontier/ROCm, Perlmutter/CUDA, Summit, SDCC-A100, etc.) live in `systems/<platform>/config-command`. These are the canonical references for production builds.
|
||||||
|
|
||||||
|
Required external libs: GMP, MPFR, OpenSSL, zlib.
|
||||||
|
|
||||||
|
### Use `systems/` for real machines
|
||||||
|
|
||||||
|
`systems/<machine>/` holds the known-good build for each production platform (`Frontier`, `Aurora`, `Perlmutter`, `Summit`, `Tursa`, `Lumi`, `Booster`, `Crusher`, `SDCC-*`, `mac-arm`, …). Each contains a `config-command` (the exact `../../configure` invocation) and a `sourceme.sh` (module loads and env). **Prefer copying/adapting these over hand-rolling configure flags** — they encode compiler workarounds, `LDFLAGS`, and shared-memory settings that are easy to get wrong. `systems/WorkArounds.txt` records known vendor bugs.
|
||||||
|
|
||||||
|
Note the GPU builds use `--enable-simd=GPU --enable-gen-simd-width=64`, so `Nsimd` is *not* 1 on device (it is `64/sizeof(scalar)`).
|
||||||
|
|
||||||
|
### Regenerating `Make.inc` — required after adding or deleting source files
|
||||||
|
|
||||||
|
`Make.inc` files are generated, not tracked in git (`.gitignore`d). `scripts/filelist` walks `Grid/`, `tests/*`, `benchmarks/`, `examples/`, and `HMC/` and writes the file lists and per-test `bin_PROGRAMS` rules. Every new `.cc`/`.h` in `Grid/`, and every new `Test_*.cc` / `Benchmark_*.cc` / `Example_*.cc`, is invisible to the build until you run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/filelist # from the source root, then re-run configure/make
|
||||||
|
```
|
||||||
|
|
||||||
|
`bootstrap.sh` runs it for you on the first setup.
|
||||||
|
|
||||||
|
## Running Tests and Benchmarks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From build directory
|
||||||
|
make check # root-level tests (Test_simd, Test_cshift, etc.)
|
||||||
|
make -C tests/<subdir> tests # build tests in a subdirectory
|
||||||
|
make tests # build all tests across all subdirectories
|
||||||
|
./tests/core/Test_simd # run a single test binary directly
|
||||||
|
mpirun -n 4 ./tests/core/Test_cshift --grid 16.16.16.16 --mpi 1.1.1.4
|
||||||
|
```
|
||||||
|
|
||||||
|
`make check` is a thin smoke test — building a subdirectory with `make -C tests/<subdir> tests` and running the relevant binaries directly is the normal development loop. Test binaries take Grid's standard command-line arguments (`--grid`, `--mpi`, `--accelerator-threads`, `--threads`, `--debug-signals`, `--log`); see `Grid/util/Init.cc`.
|
||||||
|
|
||||||
|
Test subdirectories and their focus: `core` (SIMD, stencil, comms), `solver` (CG, GMRES, eigensolvers), `hmc` (MD integrators), `forces` (fermion forces), `lanczos`, `IO`, `smearing`, `sp2n`, `debug`.
|
||||||
|
|
||||||
|
Tests and benchmarks that need optional fermion representations are guarded by `disable_tests_without_instantiations.h` / `disable_benchmarks_without_instantiations.h`, so a `--disable-fermion-reps --disable-gparity` build silently compiles them to no-ops.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Layer stack (bottom to top)
|
||||||
|
|
||||||
|
1. **SIMD layer** (`Grid/simd/`) — platform-specific intrinsics wrapped into `vRealF`, `vComplexD`, etc. The SIMD width and layout are compile-time constants controlled by `--enable-simd`.
|
||||||
|
|
||||||
|
2. **Tensor layer** (`Grid/tensors/`) — Lorentz/colour/spin tensor algebra built on top of SIMD types. `iMatrix`, `iVector`, `iScalar` templates compose into QCD types like `ColourMatrix`, `SpinColourVector`.
|
||||||
|
|
||||||
|
3. **Lattice layer** (`Grid/lattice/`) — `Lattice<T>` container: a site-local tensor replicated across a distributed Cartesian grid. All arithmetic is site-parallel and expression-template-fused.
|
||||||
|
|
||||||
|
4. **Cartesian/comms layer** (`Grid/cartesian/`, `Grid/communicator/`) — `GridCartesian` holds the MPI topology and local/global geometry. `Grid/cshift/` implements nearest-neighbour halo exchange; `Grid/stencil/` is the optimised multi-hop stencil used by Dirac operators.
|
||||||
|
|
||||||
|
5. **Algorithm layer** (`Grid/algorithms/`) — iterative solvers (CG, GMRES, BiCGSTAB, mixed-precision), eigensolvers (Lanczos, LAPACK), FFT, smearing, and multigrid.
|
||||||
|
|
||||||
|
6. **QCD layer** (`Grid/qcd/`) — gauge and fermion actions, HMC integrators, observables.
|
||||||
|
|
||||||
|
### QCD subsystem (`Grid/qcd/`)
|
||||||
|
|
||||||
|
- `action/fermion/` — Wilson, Clover, DWF (Mobius), Staggered, twisted-mass, G-parity variants
|
||||||
|
- `action/gauge/` — Wilson gauge, Symanzik, Iwasaki, DBW2, plaquette+rect
|
||||||
|
- `representations/` — Fundamental, Adjoint, Two-index, Sp(2n)
|
||||||
|
- `hmc/` — Leapfrog, OMF2/OMF4 integrators; pseudofermion refreshment; Metropolis accept/reject
|
||||||
|
- `smearing/` — APE, Stout, HEX, gradient flow
|
||||||
|
- `observables/` — Polyakov loop, plaquette, topological charge
|
||||||
|
|
||||||
|
### GPU acceleration and the view/memory-manager discipline
|
||||||
|
### Multigrid (`Grid/algorithms/multigrid/`)
|
||||||
|
|
||||||
|
Aggregation-based algebraic multigrid for Wilson-type fermions. Key files: `CoarsenedMatrix.h` (coarse operator), `GeneralCoarsenedMatrix.h` and `GeneralCoarsenedMatrixMultiRHS.h` (general coarsening supporting multi-RHS solves), `Aggregates.h` (near-null vector construction), `Geometry.h` (coarse-grid geometry). `MultiGrid.h` is the top-level include.
|
||||||
|
|
||||||
|
### GPU acceleration
|
||||||
|
|
||||||
|
GPU support is injected via macros in `Grid/threads/Accelerator.h` — `accelerator_for(i, n, nsimd, {...})`, `accelerator_forNB` (non-blocking, must be followed by `accelerator_barrier()`), `accelerator_for2dNB`, and `accelerator_inline`. On a CPU build these degrade to `thread_for` (OpenMP). Unified virtual memory is on by default (`--enable-unified=yes`); device-aware MPI (`--enable-accelerator-aware-mpi`) avoids device→host copies on transfers.
|
||||||
|
|
||||||
|
Lattice data is **not** directly addressable inside a kernel. You must open a view with the correct access mode so `Grid/allocator/MemoryManager.h` can move/mark the data:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
autoView(out_v, out, AcceleratorWriteDiscard); // RAII; closes at end of scope
|
||||||
|
autoView(in_v, in, AcceleratorRead);
|
||||||
|
accelerator_for(ss, grid->oSites(), Nsimd, {
|
||||||
|
coalescedWrite(out_v[ss], coalescedRead(in_v[ss]));
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Modes are `AcceleratorRead/Write/WriteDiscard` and `CpuRead/Write/WriteDiscard`. Getting the mode wrong (e.g. `AcceleratorRead` on a field you write) produces stale-data bugs that only appear on GPU builds. Inside kernels use `coalescedRead`/`coalescedWrite` rather than raw `operator[]` — they map the SIMD lane onto `threadIdx.x` so accesses stay coalesced.
|
||||||
|
|
||||||
|
### Repo-local debugging skills (`skills/`)
|
||||||
|
|
||||||
|
`skills/` contains hard-won, Grid-specific playbooks written as invocable skill files. Consult them before debugging in these areas rather than reasoning from first principles:
|
||||||
|
|
||||||
|
| File | Covers |
|
||||||
|
|---|---|
|
||||||
|
| `gpu-memory-performance.md` | `acceleratorThreads()`, LambdaApply thread mapping, `coalescedRead` idiom, fused vs staged HBM access |
|
||||||
|
| `gpu-runtime-correctness.md` | GPU runtime returning early from sync, silent wrong answers |
|
||||||
|
| `communication-overlap.md` | 7-phase halo pipeline, per-packet events, host-staging vs GPU-direct RDMA |
|
||||||
|
| `mpi-heterogeneous.md` | `MPI_Sendrecv` device-buffer aliasing, deterministic reductions |
|
||||||
|
| `compiler-validation.md` | Isolating GPU compiler codegen bugs, minimal reproducers |
|
||||||
|
| `correctness-verification.md` | Double-run fingerprinting, per-packet checksums, flight recorder |
|
||||||
|
| `hang-diagnosis.md` | Diagnosing MPI/accelerator hangs |
|
||||||
|
|
||||||
|
The key loop macros (defined in `Grid/threads/Accelerator.h`) are:
|
||||||
|
- `accelerator_for(iter, num, nsimd, {...})` — maps to CUDA/HIP kernel or OpenMP loop; `nsimd` is the innermost SIMD lane count
|
||||||
|
- `accelerator_forNB(...)` — non-blocking variant (no implicit barrier)
|
||||||
|
- `accelerator_for2dNB(iter1, num1, iter2, num2, nsimd, {...})` — 2D kernel launch
|
||||||
|
- `thread_for(iter, num, {...})` — CPU OpenMP loop (never dispatches to GPU)
|
||||||
|
|
||||||
|
On CPU builds, `accelerator_for` aliases to `thread_for`.
|
||||||
|
|
||||||
|
### Solver patterns
|
||||||
|
|
||||||
|
`SchurRedBlack` (`Grid/algorithms/iterative/SchurRedBlack.h`) implements red-black (even/odd) preconditioning for fermion operators. Most production fermion solves use `SchurRedBlackDiagMooeeSolve` or similar wrappers that internally call a `ConjugateGradient` on the Schur complement.
|
||||||
|
|
||||||
|
Mixed-precision solvers (`ConjugateGradientMixedPrec`, `BiCGSTABMixedPrec`) drive a double-precision outer loop with single-precision inner solves.
|
||||||
|
|
||||||
|
### Memory and I/O
|
||||||
|
|
||||||
|
- `Grid/allocator/` — aligned/NUMA-aware allocators; caching allocator via `--enable-alloc-cache`
|
||||||
|
- `Grid/parallelIO/` — distributed parallel reader/writer for ILDG (via LIME), SciDAC, and native binary formats
|
||||||
|
- `Grid/serialisation/` — text, binary, HDF5, XML/JSON serialisation of arbitrary Grid objects
|
||||||
|
|
||||||
|
### Executables
|
||||||
|
|
||||||
|
- `HMC/` — production HMC driver programmes (e.g. `Mobius2p1f.cc`, `DWF_plus_DSDR_nf2plus1_Shamir_Gparity.cc`)
|
||||||
|
- `benchmarks/` — `Benchmark_dwf`, `Benchmark_ITT`, `Benchmark_comms`, `Benchmark_memory_bandwidth`, … used to qualify a new machine
|
||||||
|
- `examples/` — small, readable programmes (`Example_plaquette.cc`, `Example_Mobius_spectrum.cc`) that are the best starting point for learning the API
|
||||||
|
|
||||||
|
Each of these directories auto-builds every top-level `.cc` as its own binary via `scripts/filelist`.
|
||||||
|
|
||||||
|
Every programme is wrapped in `Grid_init(&argc, &argv)` / `Grid_finalize()` (`Grid/util/Init.h`).
|
||||||
|
|
||||||
|
## Key Conventions
|
||||||
|
|
||||||
|
- **C++17** is required throughout.
|
||||||
|
- Template structure: most classes are templated on `<_FImpl>` (fermion impl) or `<Gimpl>` (gauge impl), which encode the representation and precision. Instantiation is controlled by `--enable-fermion-instantiations`.
|
||||||
|
- **Tensor indices are positional, not labelled.** The `Grid/tensors/` arithmetic recurses structurally over the `iScalar`/`iVector`/`iMatrix` nest: each level defines only the {scalar,vector,matrix}² products at its own level, with element types resolved by automatic type deduction, so every colour/spin/lorentz combination composes from ~200 lines (versus the pre-C++11 QDP++/PETE approach of machine-generating every case). An index's meaning derives entirely from its nesting depth counted from the outside; `iScalar` is the identity/broadcast case at every level. Never insert or remove a nesting level casually — the multiplication tables contract by position.
|
||||||
|
- **Multigrid coarsening deepens the tensor nest by one level.** A coarse site vector is `iVector<CComplex,nbasis>`, and `innerProduct` on it returns `iScalar<CComplex>` — one level deeper than the fine block scalar. So the block-inner-product scalar type gains one `iScalar` wrapper per MG level (fine: `vTComplex`; level 2: `iScalar<vTComplex>`; see `examples/Example_pvdagm_3level.cc`). When calling `blockInnerProduct`/`blockZAXPY`/`blockOrthogonalise` on coarse fields, the coarse scalar type must match `decltype(innerProduct(siteVector(),siteVector()))` exactly; a wrong depth fails to compile (no viable `operator=` deep in the instantiation chain) rather than mis-contracting.
|
||||||
|
- The `RealD`/`RealF`/`ComplexD`/`ComplexF` typedefs are used everywhere; avoid raw `double`/`float`.
|
||||||
|
- Use `GRID_ASSERT(cond)` (defined in `Grid/GridStd.h`), not bare `assert` — it prints a Grid-formatted message and aborts cleanly under MPI.
|
||||||
|
- Logging is stream-based, not macro-based: `std::cout << GridLogMessage << ... << std::endl;`. Channels declared in `Grid/log/Log.h` include `GridLogError`, `GridLogWarning`, `GridLogDebug`, `GridLogPerformance`, `GridLogIterative`, `GridLogSolver`, `GridLogHMC`, `GridLogComms`, `GridLogMemory`, `GridLogDslash`, `GridLogIRL`, `GridLogMG`. A subset is switched on at runtime with e.g. `--log Error,Warning,Message,Performance,Iterative,Integrator,Debug,Colours` (names given without the `GridLog` prefix).
|
||||||
|
- Performance-critical paths use `GRID_TRACE(name)` from `Grid/perfmon/Tracing.h` (compiled out unless `--enable-tracing` selects a backend) and the `GridStopWatch` timers in `Grid/perfmon/Timer.h`.
|
||||||
|
- Reductions across MPI ranks go through `GridBase::GlobalSum` / `GlobalMax`; never reduce with bare MPI calls inside library code.
|
||||||
|
- Everything lives in `NAMESPACE_BEGIN(Grid)` / `NAMESPACE_END(Grid)` macros; follow the surrounding file rather than writing `namespace Grid { }`.
|
||||||
|
- British spelling is used in identifiers and comments (`colour`, `neighbour`, `serialisation`).
|
||||||
+169
-172
@@ -75,7 +75,6 @@ public:
|
|||||||
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
||||||
hipfftResult rv;
|
hipfftResult rv;
|
||||||
if ( sign == forward ) rv =hipfftExecZ2Z(p,in,out,HIPFFT_FORWARD);
|
if ( sign == forward ) rv =hipfftExecZ2Z(p,in,out,HIPFFT_FORWARD);
|
||||||
@@ -83,9 +82,7 @@ public:
|
|||||||
accelerator_barrier();
|
accelerator_barrier();
|
||||||
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
||||||
}
|
}
|
||||||
inline static void fftw_destroy_plan(const FFTW_plan p) {
|
inline static void fftw_destroy_plan(const FFTW_plan p) { hipfftDestroy(p); }
|
||||||
hipfftDestroy(p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
template<> struct FFTW<ComplexF> {
|
template<> struct FFTW<ComplexF> {
|
||||||
public:
|
public:
|
||||||
@@ -93,7 +90,6 @@ public:
|
|||||||
static const int backward=FFTW_BACKWARD;
|
static const int backward=FFTW_BACKWARD;
|
||||||
typedef hipfftComplex FFTW_scalar;
|
typedef hipfftComplex FFTW_scalar;
|
||||||
typedef hipfftHandle FFTW_plan;
|
typedef hipfftHandle FFTW_plan;
|
||||||
|
|
||||||
static FFTW_plan fftw_plan_many_dft(int rank, int *n,int howmany,
|
static FFTW_plan fftw_plan_many_dft(int rank, int *n,int howmany,
|
||||||
FFTW_scalar *in, int *inembed,
|
FFTW_scalar *in, int *inembed,
|
||||||
int istride, int idist,
|
int istride, int idist,
|
||||||
@@ -105,7 +101,6 @@ public:
|
|||||||
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
||||||
hipfftResult rv;
|
hipfftResult rv;
|
||||||
if ( sign == forward ) rv =hipfftExecC2C(p,in,out,HIPFFT_FORWARD);
|
if ( sign == forward ) rv =hipfftExecC2C(p,in,out,HIPFFT_FORWARD);
|
||||||
@@ -113,9 +108,7 @@ public:
|
|||||||
accelerator_barrier();
|
accelerator_barrier();
|
||||||
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
GRID_ASSERT(rv==HIPFFT_SUCCESS);
|
||||||
}
|
}
|
||||||
inline static void fftw_destroy_plan(const FFTW_plan p) {
|
inline static void fftw_destroy_plan(const FFTW_plan p) { hipfftDestroy(p); }
|
||||||
hipfftDestroy(p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -126,7 +119,6 @@ public:
|
|||||||
static const int backward=FFTW_BACKWARD;
|
static const int backward=FFTW_BACKWARD;
|
||||||
typedef cufftDoubleComplex FFTW_scalar;
|
typedef cufftDoubleComplex FFTW_scalar;
|
||||||
typedef cufftHandle FFTW_plan;
|
typedef cufftHandle FFTW_plan;
|
||||||
|
|
||||||
static FFTW_plan fftw_plan_many_dft(int rank, int *n,int howmany,
|
static FFTW_plan fftw_plan_many_dft(int rank, int *n,int howmany,
|
||||||
FFTW_scalar *in, int *inembed,
|
FFTW_scalar *in, int *inembed,
|
||||||
int istride, int idist,
|
int istride, int idist,
|
||||||
@@ -137,15 +129,12 @@ public:
|
|||||||
cufftPlanMany(&p,rank,n,n,istride,idist,n,ostride,odist,CUFFT_Z2Z,howmany);
|
cufftPlanMany(&p,rank,n,n,istride,idist,n,ostride,odist,CUFFT_Z2Z,howmany);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
||||||
if ( sign == forward ) cufftExecZ2Z(p,in,out,CUFFT_FORWARD);
|
if ( sign == forward ) cufftExecZ2Z(p,in,out,CUFFT_FORWARD);
|
||||||
else cufftExecZ2Z(p,in,out,CUFFT_INVERSE);
|
else cufftExecZ2Z(p,in,out,CUFFT_INVERSE);
|
||||||
accelerator_barrier();
|
accelerator_barrier();
|
||||||
}
|
}
|
||||||
inline static void fftw_destroy_plan(const FFTW_plan p) {
|
inline static void fftw_destroy_plan(const FFTW_plan p) { cufftDestroy(p); }
|
||||||
cufftDestroy(p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
template<> struct FFTW<ComplexF> {
|
template<> struct FFTW<ComplexF> {
|
||||||
public:
|
public:
|
||||||
@@ -153,7 +142,6 @@ public:
|
|||||||
static const int backward=FFTW_BACKWARD;
|
static const int backward=FFTW_BACKWARD;
|
||||||
typedef cufftComplex FFTW_scalar;
|
typedef cufftComplex FFTW_scalar;
|
||||||
typedef cufftHandle FFTW_plan;
|
typedef cufftHandle FFTW_plan;
|
||||||
|
|
||||||
static FFTW_plan fftw_plan_many_dft(int rank, int *n,int howmany,
|
static FFTW_plan fftw_plan_many_dft(int rank, int *n,int howmany,
|
||||||
FFTW_scalar *in, int *inembed,
|
FFTW_scalar *in, int *inembed,
|
||||||
int istride, int idist,
|
int istride, int idist,
|
||||||
@@ -164,15 +152,12 @@ public:
|
|||||||
cufftPlanMany(&p,rank,n,n,istride,idist,n,ostride,odist,CUFFT_C2C,howmany);
|
cufftPlanMany(&p,rank,n,n,istride,idist,n,ostride,odist,CUFFT_C2C,howmany);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
||||||
if ( sign == forward ) cufftExecC2C(p,in,out,CUFFT_FORWARD);
|
if ( sign == forward ) cufftExecC2C(p,in,out,CUFFT_FORWARD);
|
||||||
else cufftExecC2C(p,in,out,CUFFT_INVERSE);
|
else cufftExecC2C(p,in,out,CUFFT_INVERSE);
|
||||||
accelerator_barrier();
|
accelerator_barrier();
|
||||||
}
|
}
|
||||||
inline static void fftw_destroy_plan(const FFTW_plan p) {
|
inline static void fftw_destroy_plan(const FFTW_plan p) { cufftDestroy(p); }
|
||||||
cufftDestroy(p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -190,13 +175,10 @@ public:
|
|||||||
int sign, unsigned flags) {
|
int sign, unsigned flags) {
|
||||||
return ::fftw_plan_many_dft(rank,n,howmany,in,inembed,istride,idist,out,onembed,ostride,odist,sign,flags);
|
return ::fftw_plan_many_dft(rank,n,howmany,in,inembed,istride,idist,out,onembed,ostride,odist,sign,flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
||||||
::fftw_execute_dft(p,in,out);
|
::fftw_execute_dft(p,in,out);
|
||||||
}
|
}
|
||||||
inline static void fftw_destroy_plan(const FFTW_plan p) {
|
inline static void fftw_destroy_plan(const FFTW_plan p) { ::fftw_destroy_plan(p); }
|
||||||
::fftw_destroy_plan(p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
template<> struct FFTW<ComplexF> {
|
template<> struct FFTW<ComplexF> {
|
||||||
public:
|
public:
|
||||||
@@ -210,25 +192,19 @@ public:
|
|||||||
int sign, unsigned flags) {
|
int sign, unsigned flags) {
|
||||||
return ::fftwf_plan_many_dft(rank,n,howmany,in,inembed,istride,idist,out,onembed,ostride,odist,sign,flags);
|
return ::fftwf_plan_many_dft(rank,n,howmany,in,inembed,istride,idist,out,onembed,ostride,odist,sign,flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
inline static void fftw_execute_dft(const FFTW_plan p,FFTW_scalar *in,FFTW_scalar *out, int sign) {
|
||||||
::fftwf_execute_dft(p,in,out);
|
::fftwf_execute_dft(p,in,out);
|
||||||
}
|
}
|
||||||
inline static void fftw_destroy_plan(const FFTW_plan p) {
|
inline static void fftw_destroy_plan(const FFTW_plan p) { ::fftwf_destroy_plan(p); }
|
||||||
::fftwf_destroy_plan(p);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class FFT {
|
struct FFTbase {
|
||||||
private:
|
|
||||||
|
|
||||||
double flops;
|
double flops;
|
||||||
double flops_call;
|
double flops_call;
|
||||||
uint64_t usec;
|
uint64_t usec;
|
||||||
|
GridCartesian *_grid;
|
||||||
public:
|
|
||||||
|
|
||||||
static const int forward = FFTW_FORWARD;
|
static const int forward = FFTW_FORWARD;
|
||||||
static const int backward = FFTW_BACKWARD;
|
static const int backward = FFTW_BACKWARD;
|
||||||
@@ -237,168 +213,87 @@ public:
|
|||||||
double MFlops(void) { return flops / usec; }
|
double MFlops(void) { return flops / usec; }
|
||||||
double USec(void) { return (double)usec; }
|
double USec(void) { return (double)usec; }
|
||||||
|
|
||||||
FFT ( GridCartesian * grid )
|
FFTbase(GridCartesian *grid) : _grid(grid), flops(0), flops_call(0), usec(0) {}
|
||||||
{
|
|
||||||
flops=0;
|
|
||||||
usec =0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
~FFT ( void) {
|
// Barrel-shift gather, FFT execute, and insert. Called by both FFT and PlannedFFT.
|
||||||
// delete sgrid;
|
// The caller is responsible for plan acquisition and destruction.
|
||||||
}
|
|
||||||
|
|
||||||
template<class vobj>
|
template<class vobj>
|
||||||
void FFT_dim_mask(Lattice<vobj> &result,const Lattice<vobj> &source,Coordinate mask,int sign){
|
static void FFT_dim_execute(
|
||||||
|
Lattice<vobj> &result,
|
||||||
// vgrid=result.Grid();
|
const Lattice<vobj> &source,
|
||||||
// conformable(result.Grid(),vgrid);
|
int dim, int sign,
|
||||||
// conformable(source.Grid(),vgrid);
|
typename FFTW<typename vobj::scalar_type>::FFTW_plan p,
|
||||||
const int Ndim = source.Grid()->Nd();
|
GridCartesian *grid,
|
||||||
Lattice<vobj> tmp = source;
|
double &flops, double &flops_call, uint64_t &usec)
|
||||||
for(int d=0;d<Ndim;d++){
|
{
|
||||||
if( mask[d] ) {
|
|
||||||
FFT_dim(result,tmp,d,sign);
|
|
||||||
tmp=result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class vobj>
|
|
||||||
void FFT_all_dim(Lattice<vobj> &result,const Lattice<vobj> &source,int sign){
|
|
||||||
const int Ndim = source.Grid()->Nd();
|
|
||||||
Coordinate mask(Ndim,1);
|
|
||||||
FFT_dim_mask(result,source,mask,sign);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class vobj>
|
|
||||||
void FFT_dim(Lattice<vobj> &result,const Lattice<vobj> &source,int dim, int sign){
|
|
||||||
const int Ndim = source.Grid()->Nd();
|
|
||||||
GridBase *grid = source.Grid();
|
|
||||||
conformable(result.Grid(),source.Grid());
|
|
||||||
|
|
||||||
int L = grid->_ldimensions[dim];
|
|
||||||
int G = grid->_fdimensions[dim];
|
|
||||||
|
|
||||||
Coordinate layout(Ndim,1);
|
|
||||||
|
|
||||||
// Construct pencils
|
|
||||||
typedef typename vobj::scalar_object sobj;
|
|
||||||
typedef typename vobj::scalar_type scalar;
|
typedef typename vobj::scalar_type scalar;
|
||||||
|
typedef typename vobj::scalar_object sobj;
|
||||||
typedef typename vobj::scalar_type scalar_type;
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
typedef typename vobj::vector_type vector_type;
|
typedef typename vobj::vector_type vector_type;
|
||||||
|
|
||||||
//std::cout << "CPU view" << std::endl;
|
|
||||||
|
|
||||||
typedef typename FFTW<scalar>::FFTW_scalar FFTW_scalar;
|
typedef typename FFTW<scalar>::FFTW_scalar FFTW_scalar;
|
||||||
typedef typename FFTW<scalar>::FFTW_plan FFTW_plan;
|
|
||||||
|
|
||||||
|
const int Ndim = grid->Nd();
|
||||||
|
int L = grid->_ldimensions[dim];
|
||||||
|
int G = grid->_fdimensions[dim];
|
||||||
int Ncomp = sizeof(sobj) / sizeof(scalar);
|
int Ncomp = sizeof(sobj) / sizeof(scalar);
|
||||||
int64_t Nlow = 1;
|
int64_t Nlow = 1, Nhigh = 1;
|
||||||
int64_t Nhigh = 1;
|
for (int d = 0; d < dim; d++) Nlow *= grid->_ldimensions[d];
|
||||||
|
for (int d = dim+1; d < Ndim; d++) Nhigh *= grid->_ldimensions[d];
|
||||||
for(int d=0;d<dim;d++){
|
|
||||||
Nlow*=grid->_ldimensions[d];
|
|
||||||
}
|
|
||||||
for(int d=dim+1;d<Ndim;d++){
|
|
||||||
Nhigh*=grid->_ldimensions[d];
|
|
||||||
}
|
|
||||||
int64_t Nperp = Nlow * Nhigh;
|
int64_t Nperp = Nlow * Nhigh;
|
||||||
|
|
||||||
deviceVector<scalar> pgbuf; // Layout is [perp][component][dim]
|
deviceVector<scalar> pgbuf(Nperp * Ncomp * G);
|
||||||
pgbuf.resize(Nperp*Ncomp*G);
|
|
||||||
scalar *pgbuf_v = &pgbuf[0];
|
scalar *pgbuf_v = &pgbuf[0];
|
||||||
|
|
||||||
int rank = 1; /* 1d transforms */
|
|
||||||
int n[] = {G}; /* 1d transforms of length G */
|
|
||||||
int howmany = Ncomp * Nperp;
|
int howmany = Ncomp * Nperp;
|
||||||
int odist,idist,istride,ostride;
|
|
||||||
idist = odist = G; /* Distance between consecutive FT's */
|
|
||||||
istride = ostride = 1; /* Distance between two elements in the same FT */
|
|
||||||
int *inembed = n, *onembed = n;
|
|
||||||
|
|
||||||
scalar div;
|
scalar div;
|
||||||
if ( sign == backward ) div = 1.0/G;
|
if (sign == FFTW_BACKWARD) div = 1.0 / G;
|
||||||
else if ( sign == forward ) div = 1.0;
|
else if (sign == FFTW_FORWARD) div = 1.0;
|
||||||
else GRID_ASSERT(0);
|
else GRID_ASSERT(0);
|
||||||
|
|
||||||
double t_pencil=0;
|
double t_pencil = 0, t_fft = 0, t_copy = 0, t_shift = 0;
|
||||||
double t_fft =0;
|
|
||||||
double t_total = -usecond();
|
double t_total = -usecond();
|
||||||
// std::cout << GridLogPerformance<<"Making FFTW plan" << std::endl;
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
FFTW_plan p;
|
|
||||||
{
|
|
||||||
FFTW_scalar *in = (FFTW_scalar *)&pgbuf_v[0];
|
|
||||||
FFTW_scalar *out= (FFTW_scalar *)&pgbuf_v[0];
|
|
||||||
p = FFTW<scalar>::fftw_plan_many_dft(rank,n,howmany,
|
|
||||||
in,inembed,
|
|
||||||
istride,idist,
|
|
||||||
out,onembed,
|
|
||||||
ostride, odist,
|
|
||||||
sign,FFTW_ESTIMATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Barrel shift and collect global pencil
|
|
||||||
// std::cout << GridLogPerformance<<"Making pencil" << std::endl;
|
|
||||||
Coordinate lcoor(Ndim), gcoor(Ndim);
|
|
||||||
double t_copy=0;
|
|
||||||
double t_shift=0;
|
|
||||||
t_pencil = -usecond();
|
|
||||||
result = source;
|
result = source;
|
||||||
int pc = grid->_processor_coor[dim];
|
int pc = grid->_processor_coor[dim];
|
||||||
|
|
||||||
const Coordinate ldims = grid->_ldimensions;
|
const Coordinate ldims = grid->_ldimensions;
|
||||||
const Coordinate rdims = grid->_rdimensions;
|
const Coordinate rdims = grid->_rdimensions;
|
||||||
const Coordinate sdims = grid->_simd_layout;
|
const Coordinate sdims = grid->_simd_layout;
|
||||||
|
const Coordinate processors = grid->_processors;
|
||||||
|
|
||||||
Coordinate processors = grid->_processors;
|
|
||||||
Coordinate pgdims(Ndim);
|
Coordinate pgdims(Ndim);
|
||||||
pgdims[0] = G;
|
pgdims[0] = G;
|
||||||
for(int d=0, dd=1;d<Ndim;d++){
|
for (int d = 0, dd = 1; d < Ndim; d++)
|
||||||
if (d != dim) pgdims[dd++] = ldims[d];
|
if (d != dim) pgdims[dd++] = ldims[d];
|
||||||
}
|
|
||||||
int64_t pgvol = 1;
|
int64_t pgvol = 1;
|
||||||
for (int d = 0; d < Ndim; d++) pgvol *= pgdims[d];
|
for (int d = 0; d < Ndim; d++) pgvol *= pgdims[d];
|
||||||
|
|
||||||
const int Nsimd = vobj::Nsimd();
|
const int Nsimd = vobj::Nsimd();
|
||||||
for(int p=0;p<processors[dim];p++) {
|
t_pencil = -usecond();
|
||||||
|
for (int p_idx = 0; p_idx < processors[dim]; p_idx++) {
|
||||||
t_copy -= usecond();
|
t_copy -= usecond();
|
||||||
autoView(r_v, result, AcceleratorRead);
|
autoView(r_v, result, AcceleratorRead);
|
||||||
accelerator_for(idx, grid->oSites(), vobj::Nsimd(), {
|
accelerator_for(idx, grid->oSites(), vobj::Nsimd(), {
|
||||||
#ifdef GRID_SIMT
|
#ifdef GRID_SIMT
|
||||||
{
|
{
|
||||||
int lane=acceleratorSIMTlane(Nsimd); // buffer lane
|
int lane = acceleratorSIMTlane(Nsimd);
|
||||||
#else
|
#else
|
||||||
for (int lane = 0; lane < Nsimd; lane++) {
|
for (int lane = 0; lane < Nsimd; lane++) {
|
||||||
#endif
|
#endif
|
||||||
Coordinate icoor;
|
Coordinate icoor, ocoor, pgcoor;
|
||||||
Coordinate ocoor;
|
|
||||||
Coordinate pgcoor;
|
|
||||||
|
|
||||||
Lexicographic::CoorFromIndex(icoor, lane, sdims);
|
Lexicographic::CoorFromIndex(icoor, lane, sdims);
|
||||||
Lexicographic::CoorFromIndex(ocoor, idx, rdims);
|
Lexicographic::CoorFromIndex(ocoor, idx, rdims);
|
||||||
|
pgcoor[0] = ocoor[dim] + icoor[dim]*rdims[dim] + ((pc+p_idx)%processors[dim])*L;
|
||||||
pgcoor[0] = ocoor[dim] + icoor[dim]*rdims[dim] + ((pc+p)%processors[dim])*L;
|
for (int d = 0, dd = 1; d < Ndim; d++)
|
||||||
for(int d=0,dd=1;d<Ndim;d++){
|
if (d != dim) { pgcoor[dd] = ocoor[d] + icoor[d]*rdims[d]; dd++; }
|
||||||
if ( d!=dim ) {
|
|
||||||
pgcoor[dd] = ocoor[d] + icoor[d]*rdims[d];
|
|
||||||
dd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map coordinates in lattice layout to FFTW index
|
|
||||||
int64_t pgidx;
|
int64_t pgidx;
|
||||||
Lexicographic::IndexFromCoor(pgcoor, pgidx, pgdims);
|
Lexicographic::IndexFromCoor(pgcoor, pgidx, pgdims);
|
||||||
|
|
||||||
vector_type *from = (vector_type *)&r_v[idx];
|
vector_type *from = (vector_type *)&r_v[idx];
|
||||||
scalar_type stmp;
|
scalar_type stmp;
|
||||||
for (int w = 0; w < Ncomp; w++) {
|
for (int w = 0; w < Ncomp; w++) {
|
||||||
int64_t pg_idx = pgidx + w*pgvol;
|
|
||||||
stmp = getlane(from[w], lane);
|
stmp = getlane(from[w], lane);
|
||||||
pgbuf_v[pg_idx] = stmp;
|
pgbuf_v[pgidx + w*pgvol] = stmp;
|
||||||
}
|
}
|
||||||
#ifdef GRID_SIMT
|
#ifdef GRID_SIMT
|
||||||
}
|
}
|
||||||
@@ -406,9 +301,8 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
t_copy += usecond();
|
t_copy += usecond();
|
||||||
if (p != processors[dim] - 1) {
|
if (p_idx != processors[dim] - 1) {
|
||||||
Lattice<vobj> temp(grid);
|
Lattice<vobj> temp(grid);
|
||||||
t_shift -= usecond();
|
t_shift -= usecond();
|
||||||
temp = Cshift(result, dim, L); result = temp;
|
temp = Cshift(result, dim, L); result = temp;
|
||||||
@@ -423,49 +317,35 @@ public:
|
|||||||
FFTW<scalar>::fftw_execute_dft(p, in, out, sign);
|
FFTW<scalar>::fftw_execute_dft(p, in, out, sign);
|
||||||
t_fft += usecond();
|
t_fft += usecond();
|
||||||
|
|
||||||
// performance counting
|
|
||||||
flops_call = 5.0 * howmany * G * log2(G);
|
flops_call = 5.0 * howmany * G * log2(G);
|
||||||
usec = t_fft;
|
usec = t_fft;
|
||||||
flops = flops_call;
|
flops = flops_call;
|
||||||
|
|
||||||
result = Zero();
|
result = Zero();
|
||||||
|
|
||||||
double t_insert = -usecond();
|
double t_insert = -usecond();
|
||||||
{
|
{
|
||||||
autoView(r_v, result, AcceleratorWrite);
|
autoView(r_v, result, AcceleratorWrite);
|
||||||
accelerator_for(idx, grid->oSites(), Nsimd, {
|
accelerator_for(idx, grid->oSites(), Nsimd, {
|
||||||
#ifdef GRID_SIMT
|
#ifdef GRID_SIMT
|
||||||
{
|
{
|
||||||
int lane=acceleratorSIMTlane(Nsimd); // buffer lane
|
int lane = acceleratorSIMTlane(Nsimd);
|
||||||
#else
|
#else
|
||||||
for (int lane = 0; lane < Nsimd; lane++) {
|
for (int lane = 0; lane < Nsimd; lane++) {
|
||||||
#endif
|
#endif
|
||||||
Coordinate icoor(Ndim);
|
Coordinate icoor(Ndim), ocoor(Ndim), pgcoor(Ndim);
|
||||||
Coordinate ocoor(Ndim);
|
|
||||||
Coordinate pgcoor(Ndim);
|
|
||||||
|
|
||||||
Lexicographic::CoorFromIndex(icoor, lane, sdims);
|
Lexicographic::CoorFromIndex(icoor, lane, sdims);
|
||||||
Lexicographic::CoorFromIndex(ocoor, idx, rdims);
|
Lexicographic::CoorFromIndex(ocoor, idx, rdims);
|
||||||
|
|
||||||
pgcoor[0] = ocoor[dim] + icoor[dim]*rdims[dim] + pc*L;
|
pgcoor[0] = ocoor[dim] + icoor[dim]*rdims[dim] + pc*L;
|
||||||
for(int d=0,dd=1;d<Ndim;d++){
|
for (int d = 0, dd = 1; d < Ndim; d++)
|
||||||
if ( d!=dim ) {
|
if (d != dim) { pgcoor[dd] = ocoor[d] + icoor[d]*rdims[d]; dd++; }
|
||||||
pgcoor[dd] = ocoor[d] + icoor[d]*rdims[d];
|
|
||||||
dd++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Map coordinates in lattice layout to FFTW index
|
|
||||||
int64_t pgidx;
|
int64_t pgidx;
|
||||||
Lexicographic::IndexFromCoor(pgcoor, pgidx, pgdims);
|
Lexicographic::IndexFromCoor(pgcoor, pgidx, pgdims);
|
||||||
|
|
||||||
vector_type *to = (vector_type *)&r_v[idx];
|
vector_type *to = (vector_type *)&r_v[idx];
|
||||||
scalar_type stmp;
|
scalar_type stmp;
|
||||||
for (int w = 0; w < Ncomp; w++) {
|
for (int w = 0; w < Ncomp; w++) {
|
||||||
int64_t pg_idx = pgidx + w*pgvol;
|
stmp = pgbuf_v[pgidx + w*pgvol];
|
||||||
stmp = pgbuf_v[pg_idx];
|
|
||||||
putlane(to[w], stmp, lane);
|
putlane(to[w], stmp, lane);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GRID_SIMT
|
#ifdef GRID_SIMT
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -473,14 +353,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
result = result * div;
|
result = result * div;
|
||||||
|
|
||||||
t_insert += usecond();
|
t_insert += usecond();
|
||||||
|
|
||||||
// destroying plan
|
|
||||||
FFTW<scalar>::fftw_destroy_plan(p);
|
|
||||||
|
|
||||||
t_total += usecond();
|
t_total += usecond();
|
||||||
|
|
||||||
std::cout << GridLogPerformance << " FFT took " << t_total/1.0e6 << " s" << std::endl;
|
std::cout << GridLogPerformance << " FFT took " << t_total/1.0e6 << " s" << std::endl;
|
||||||
@@ -489,7 +363,130 @@ public:
|
|||||||
std::cout << GridLogPerformance << " of which shift" << t_shift/1.0e6 << " s" << std::endl;
|
std::cout << GridLogPerformance << " of which shift" << t_shift/1.0e6 << " s" << std::endl;
|
||||||
std::cout << GridLogPerformance << " FFT kernels " << t_fft/1.0e6 << " s" << std::endl;
|
std::cout << GridLogPerformance << " FFT kernels " << t_fft/1.0e6 << " s" << std::endl;
|
||||||
std::cout << GridLogPerformance << " FFT insert " << t_insert/1.0e6 << " s" << std::endl;
|
std::cout << GridLogPerformance << " FFT insert " << t_insert/1.0e6 << " s" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FFT : public FFTbase {
|
||||||
|
public:
|
||||||
|
FFT(GridCartesian *grid) : FFTbase(grid) {}
|
||||||
|
~FFT() {}
|
||||||
|
|
||||||
|
template<class vobj>
|
||||||
|
void FFT_dim_mask(Lattice<vobj> &result, const Lattice<vobj> &source, Coordinate mask, int sign) {
|
||||||
|
const int Ndim = _grid->Nd();
|
||||||
|
Lattice<vobj> tmp = source;
|
||||||
|
for (int d = 0; d < Ndim; d++) {
|
||||||
|
if (mask[d]) {
|
||||||
|
FFT_dim(result, tmp, d, sign);
|
||||||
|
tmp = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class vobj>
|
||||||
|
void FFT_all_dim(Lattice<vobj> &result, const Lattice<vobj> &source, int sign) {
|
||||||
|
Coordinate mask(_grid->Nd(), 1);
|
||||||
|
FFT_dim_mask(result, source, mask, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class vobj>
|
||||||
|
void FFT_dim(Lattice<vobj> &result, const Lattice<vobj> &source, int dim, int sign) {
|
||||||
|
GRID_ASSERT(source.Grid() == _grid);
|
||||||
|
GRID_ASSERT(result.Grid() == _grid);
|
||||||
|
conformable(result.Grid(), source.Grid());
|
||||||
|
|
||||||
|
typedef typename vobj::scalar_type scalar;
|
||||||
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
typedef typename FFTW<scalar>::FFTW_scalar FFTW_scalar;
|
||||||
|
typedef typename FFTW<scalar>::FFTW_plan FFTW_plan;
|
||||||
|
|
||||||
|
const int Ndim = _grid->Nd();
|
||||||
|
int G = _grid->_fdimensions[dim];
|
||||||
|
int Ncomp = sizeof(sobj) / sizeof(scalar);
|
||||||
|
int64_t Nperp = 1;
|
||||||
|
for (int d = 0; d < Ndim; d++)
|
||||||
|
if (d != dim) Nperp *= _grid->_ldimensions[d];
|
||||||
|
int n[] = {G};
|
||||||
|
int howmany = Ncomp * Nperp;
|
||||||
|
|
||||||
|
deviceVector<scalar> dummy(2);
|
||||||
|
FFTW_scalar *buf = (FFTW_scalar *)&dummy[0];
|
||||||
|
FFTW_plan p = FFTW<scalar>::fftw_plan_many_dft(1, n, howmany,
|
||||||
|
buf, n, 1, G,
|
||||||
|
buf, n, 1, G,
|
||||||
|
sign, FFTW_ESTIMATE);
|
||||||
|
FFT_dim_execute(result, source, dim, sign, p, _grid, flops, flops_call, usec);
|
||||||
|
FFTW<scalar>::fftw_destroy_plan(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class vobj>
|
||||||
|
class PlannedFFT : public FFTbase {
|
||||||
|
private:
|
||||||
|
typedef typename vobj::scalar_type scalar;
|
||||||
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
typedef typename vobj::vector_type vector_type;
|
||||||
|
typedef typename FFTW<scalar>::FFTW_scalar FFTW_scalar;
|
||||||
|
typedef typename FFTW<scalar>::FFTW_plan FFTW_plan;
|
||||||
|
|
||||||
|
std::vector<FFTW_plan> forward_plans;
|
||||||
|
std::vector<FFTW_plan> backward_plans;
|
||||||
|
|
||||||
|
void PlanCreate() {
|
||||||
|
const int Ndim = _grid->Nd();
|
||||||
|
forward_plans.resize(Ndim);
|
||||||
|
backward_plans.resize(Ndim);
|
||||||
|
|
||||||
|
for (int d = 0; d < Ndim; d++) {
|
||||||
|
int G = _grid->_fdimensions[d];
|
||||||
|
int Ncomp = sizeof(sobj) / sizeof(scalar);
|
||||||
|
int64_t Nperp = 1;
|
||||||
|
for (int dd = 0; dd < Ndim; dd++)
|
||||||
|
if (dd != d) Nperp *= _grid->_ldimensions[dd];
|
||||||
|
int howmany = Ncomp * (int)Nperp;
|
||||||
|
int n[] = {G};
|
||||||
|
|
||||||
|
deviceVector<scalar> dummy(2);
|
||||||
|
FFTW_scalar *buf = (FFTW_scalar *)&dummy[0];
|
||||||
|
|
||||||
|
forward_plans[d] = FFTW<scalar>::fftw_plan_many_dft(1, n, howmany, buf, n, 1, G, buf, n, 1, G, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||||
|
backward_plans[d] = FFTW<scalar>::fftw_plan_many_dft(1, n, howmany, buf, n, 1, G, buf, n, 1, G, FFTW_BACKWARD, FFTW_ESTIMATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanDestroy() {
|
||||||
|
for (auto p : forward_plans) FFTW<scalar>::fftw_destroy_plan(p);
|
||||||
|
for (auto p : backward_plans) FFTW<scalar>::fftw_destroy_plan(p);
|
||||||
|
forward_plans.clear();
|
||||||
|
backward_plans.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlannedFFT(GridCartesian *grid) : FFTbase(grid) { PlanCreate(); }
|
||||||
|
~PlannedFFT() { PlanDestroy(); }
|
||||||
|
|
||||||
|
void FFT_dim_mask(Lattice<vobj> &result, const Lattice<vobj> &source, Coordinate mask, int sign) {
|
||||||
|
const int Ndim = _grid->Nd();
|
||||||
|
Lattice<vobj> tmp = source;
|
||||||
|
for (int d = 0; d < Ndim; d++) {
|
||||||
|
if (mask[d]) {
|
||||||
|
FFT_dim(result, tmp, d, sign);
|
||||||
|
tmp = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FFT_all_dim(Lattice<vobj> &result, const Lattice<vobj> &source, int sign) {
|
||||||
|
Coordinate mask(_grid->Nd(), 1);
|
||||||
|
FFT_dim_mask(result, source, mask, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FFT_dim(Lattice<vobj> &result, const Lattice<vobj> &source, int dim, int sign) {
|
||||||
|
GRID_ASSERT(source.Grid() == _grid);
|
||||||
|
GRID_ASSERT(result.Grid() == _grid);
|
||||||
|
GRID_ASSERT((int)forward_plans.size() == _grid->Nd());
|
||||||
|
conformable(result.Grid(), source.Grid());
|
||||||
|
FFTW_plan p = (sign == forward ? forward_plans : backward_plans)[dim];
|
||||||
|
FFT_dim_execute(result, source, dim, sign, p, _grid, flops, flops_call, usec);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,59 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
enum GridBLASOperation_t { GridBLAS_OP_N, GridBLAS_OP_T, GridBLAS_OP_C } ;
|
enum GridBLASOperation_t { GridBLAS_OP_N, GridBLAS_OP_T, GridBLAS_OP_C } ;
|
||||||
enum GridBLASPrecision_t { GridBLAS_PRECISION_DEFAULT, GridBLAS_PRECISION_16F, GridBLAS_PRECISION_16BF, GridBLAS_PRECISION_TF32 };
|
enum GridBLASPrecision_t { GridBLAS_PRECISION_DEFAULT, GridBLAS_PRECISION_16F, GridBLAS_PRECISION_16BF, GridBLAS_PRECISION_TF32 };
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// BLAS scalar constants: the put() wrapper OWNS the residency policy so
|
||||||
|
// call sites just pass values (scalars-live-on-the-host rule).
|
||||||
|
//
|
||||||
|
// Policy per backend:
|
||||||
|
// - CUDA / HIP : handles are put in HOST pointer mode at Init (cuBLAS docs
|
||||||
|
// 2.2.7: host mode is the documented default; 2.1.5: host-mode scalars
|
||||||
|
// are consumed AT CALL TIME, "can be freed just after the return of the
|
||||||
|
// call even though the kernel launch is asynchronous"). put() stores
|
||||||
|
// the value in persistent host memory and returns its address: ZERO
|
||||||
|
// host->device copies.
|
||||||
|
// - SYCL : the oneMKL group-API alpha/beta arrays are dereferenced
|
||||||
|
// USM-side (spec is silent for the group API; implementation observed
|
||||||
|
// to require USM-accessible storage -- host stack pointers fault).
|
||||||
|
// put() keeps a device-resident copy with VALUE CACHING: the copy is
|
||||||
|
// issued only when the value changes (accumulation pattern
|
||||||
|
// beta = (p==0 ? 0 : 1) costs two copies per Mult instead of npoint).
|
||||||
|
//
|
||||||
|
// Motivation (rocprof, Frontier, 2026-08-13): per-call alpha/beta device
|
||||||
|
// staging generated ~92k tiny staged hipMemcpys in a 12s solve window
|
||||||
|
// (~26% of host API time) at the latency-bound coarse level.
|
||||||
|
// NB not thread safe -- matches the single-threaded host BLAS call
|
||||||
|
// pattern of the per-call staging it replaces.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class T>
|
||||||
|
class GridBLASDeviceConstant {
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
deviceVector<T> dev;
|
||||||
|
T host;
|
||||||
|
int valid;
|
||||||
|
public:
|
||||||
|
GridBLASDeviceConstant() : dev(1), valid(0) {};
|
||||||
|
T * put(T v) {
|
||||||
|
if ( (!valid) || (v != host) ) {
|
||||||
|
acceleratorCopyToDevice((void *)&v,(void *)&dev[0],sizeof(T));
|
||||||
|
host = v;
|
||||||
|
valid = 1;
|
||||||
|
}
|
||||||
|
return &dev[0];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// CUDA / HIP in HOST pointer mode (and CPU/Eigen, where the pointer is
|
||||||
|
// unused): persistent host storage, no copies ever.
|
||||||
|
T host;
|
||||||
|
public:
|
||||||
|
GridBLASDeviceConstant() {};
|
||||||
|
T * put(T v) {
|
||||||
|
host = v;
|
||||||
|
return &host;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
class GridBLAS {
|
class GridBLAS {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -81,11 +134,31 @@ public:
|
|||||||
#ifdef GRID_CUDA
|
#ifdef GRID_CUDA
|
||||||
std::cout << "cublasCreate"<<std::endl;
|
std::cout << "cublasCreate"<<std::endl;
|
||||||
cublasCreate(&gridblasHandle);
|
cublasCreate(&gridblasHandle);
|
||||||
cublasSetPointerMode(gridblasHandle, CUBLAS_POINTER_MODE_DEVICE);
|
// HOST pointer mode: scalars consumed at call time from host memory
|
||||||
|
// (cuBLAS docs 2.1.5/2.2.7) -- no device staging of alpha/beta.
|
||||||
|
// DEVICE mode would be a deliberate opt-in for device-produced
|
||||||
|
// scalars (e.g. a future graph-captured solver).
|
||||||
|
cublasSetPointerMode(gridblasHandle, CUBLAS_POINTER_MODE_HOST);
|
||||||
|
{
|
||||||
|
cublasPointerMode_t pm;
|
||||||
|
cublasGetPointerMode(gridblasHandle,&pm);
|
||||||
|
std::cout << "GridBLAS: cuBLAS pointer mode "
|
||||||
|
<< ((pm==CUBLAS_POINTER_MODE_DEVICE)?"DEVICE":"HOST") <<std::endl;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef GRID_HIP
|
#ifdef GRID_HIP
|
||||||
std::cout << "hipblasCreate"<<std::endl;
|
std::cout << "hipblasCreate"<<std::endl;
|
||||||
hipblasCreate(&gridblasHandle);
|
hipblasCreate(&gridblasHandle);
|
||||||
|
// Explicit HOST mode: the hipBLAS default is UNDOCUMENTED in the
|
||||||
|
// headers (enum 0 == HOST by cuBLAS-mirroring convention only);
|
||||||
|
// set it and print it so every log carries the ground truth.
|
||||||
|
hipblasSetPointerMode(gridblasHandle, HIPBLAS_POINTER_MODE_HOST);
|
||||||
|
{
|
||||||
|
hipblasPointerMode_t pm;
|
||||||
|
hipblasGetPointerMode(gridblasHandle,&pm);
|
||||||
|
std::cout << "GridBLAS: hipBLAS pointer mode "
|
||||||
|
<< ((pm==HIPBLAS_POINTER_MODE_DEVICE)?"DEVICE":"HOST") <<std::endl;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef GRID_SYCL
|
#ifdef GRID_SYCL
|
||||||
gridblasHandle = theGridAccelerator;
|
gridblasHandle = theGridAccelerator;
|
||||||
@@ -240,11 +313,11 @@ public:
|
|||||||
if(OpB!=GridBLAS_OP_N)
|
if(OpB!=GridBLAS_OP_N)
|
||||||
ldb = n;
|
ldb = n;
|
||||||
|
|
||||||
static deviceVector<ComplexD> alpha_p(1);
|
// Cached device constants: copy only on value change (see GridBLASDeviceConstant)
|
||||||
static deviceVector<ComplexD> beta_p(1);
|
static GridBLASDeviceConstant<ComplexD> alpha_c;
|
||||||
// can prestore the 1 and the zero on device
|
static GridBLASDeviceConstant<ComplexD> beta_c;
|
||||||
acceleratorCopyToDevice((void *)&alpha,(void *)&alpha_p[0],sizeof(ComplexD));
|
ComplexD *alpha_p = alpha_c.put(alpha);
|
||||||
acceleratorCopyToDevice((void *)&beta ,(void *)&beta_p[0],sizeof(ComplexD));
|
ComplexD *beta_p = beta_c.put(beta);
|
||||||
RealD t0=usecond();
|
RealD t0=usecond();
|
||||||
// std::cout << "ZgemmBatched mnk "<<m<<","<<n<<","<<k<<" count "<<batchCount<<std::endl;
|
// std::cout << "ZgemmBatched mnk "<<m<<","<<n<<","<<k<<" count "<<batchCount<<std::endl;
|
||||||
#ifdef GRID_HIP
|
#ifdef GRID_HIP
|
||||||
@@ -498,11 +571,11 @@ public:
|
|||||||
lda = k;
|
lda = k;
|
||||||
if(OpB!=GridBLAS_OP_N)
|
if(OpB!=GridBLAS_OP_N)
|
||||||
ldb = n;
|
ldb = n;
|
||||||
static deviceVector<ComplexF> alpha_p(1);
|
// Cached device constants: copy only on value change (see GridBLASDeviceConstant)
|
||||||
static deviceVector<ComplexF> beta_p(1);
|
static GridBLASDeviceConstant<ComplexF> alpha_c;
|
||||||
// can prestore the 1 and the zero on device
|
static GridBLASDeviceConstant<ComplexF> beta_c;
|
||||||
acceleratorCopyToDevice((void *)&alpha,(void *)&alpha_p[0],sizeof(ComplexF));
|
ComplexF *alpha_p = alpha_c.put(alpha);
|
||||||
acceleratorCopyToDevice((void *)&beta ,(void *)&beta_p[0],sizeof(ComplexF));
|
ComplexF *beta_p = beta_c.put(beta);
|
||||||
RealD t0=usecond();
|
RealD t0=usecond();
|
||||||
|
|
||||||
GRID_ASSERT(Bkn.size()==batchCount);
|
GRID_ASSERT(Bkn.size()==batchCount);
|
||||||
@@ -695,6 +768,456 @@ public:
|
|||||||
RealD bytes = 1.0*sizeof(ComplexF)*(m*k+k*n+m*n)*batchCount;
|
RealD bytes = 1.0*sizeof(ComplexF)*(m*k+k*n+m*n)*batchCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Explicit-leading-dimension complex single GEMM.
|
||||||
|
//
|
||||||
|
// A,B,C may be SLICES of larger parent allocations: lda/ldb/ldc are the
|
||||||
|
// PARENT strides (>= the compact values the ten-argument overload derives).
|
||||||
|
// Motivating use: software split-K for tiny-output/huge-K dense multiplies
|
||||||
|
// (arXiv:2409.03904 fig 11; cf MultiRHSBlockCGLinalg) -- batch over K-chunks
|
||||||
|
// of a dense slab by pointer offset j*Kchunk with lda = the full K extent,
|
||||||
|
// then reduce the partial C's. Backends pass lda straight through; only
|
||||||
|
// the compact overload invented them.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void gemmBatched(GridBLASOperation_t OpA,
|
||||||
|
GridBLASOperation_t OpB,
|
||||||
|
int m,int n, int k,
|
||||||
|
ComplexF alpha,
|
||||||
|
deviceVector<ComplexF*> &Amk, int lda,
|
||||||
|
deviceVector<ComplexF*> &Bkn, int ldb,
|
||||||
|
ComplexF beta,
|
||||||
|
deviceVector<ComplexF*> &Cmn, int ldc,
|
||||||
|
GridBLASPrecision_t precision = GridBLAS_PRECISION_DEFAULT)
|
||||||
|
{
|
||||||
|
RealD t2=usecond();
|
||||||
|
int32_t batchCount = Amk.size();
|
||||||
|
|
||||||
|
GRID_ASSERT( lda >= ((OpA==GridBLAS_OP_N) ? m : k) );
|
||||||
|
GRID_ASSERT( ldb >= ((OpB==GridBLAS_OP_N) ? k : n) );
|
||||||
|
GRID_ASSERT( ldc >= m );
|
||||||
|
|
||||||
|
// Cached device constants: copy only on value change (see GridBLASDeviceConstant)
|
||||||
|
static GridBLASDeviceConstant<ComplexF> alpha_c;
|
||||||
|
static GridBLASDeviceConstant<ComplexF> beta_c;
|
||||||
|
ComplexF *alpha_p = alpha_c.put(alpha);
|
||||||
|
ComplexF *beta_p = beta_c.put(beta);
|
||||||
|
RealD t0=usecond();
|
||||||
|
|
||||||
|
GRID_ASSERT(Bkn.size()==batchCount);
|
||||||
|
GRID_ASSERT(Cmn.size()==batchCount);
|
||||||
|
#ifdef GRID_HIP
|
||||||
|
GRID_ASSERT(precision == GridBLAS_PRECISION_DEFAULT);
|
||||||
|
hipblasOperation_t hOpA;
|
||||||
|
hipblasOperation_t hOpB;
|
||||||
|
if ( OpA == GridBLAS_OP_N ) hOpA = HIPBLAS_OP_N;
|
||||||
|
if ( OpA == GridBLAS_OP_T ) hOpA = HIPBLAS_OP_T;
|
||||||
|
if ( OpA == GridBLAS_OP_C ) hOpA = HIPBLAS_OP_C;
|
||||||
|
if ( OpB == GridBLAS_OP_N ) hOpB = HIPBLAS_OP_N;
|
||||||
|
if ( OpB == GridBLAS_OP_T ) hOpB = HIPBLAS_OP_T;
|
||||||
|
if ( OpB == GridBLAS_OP_C ) hOpB = HIPBLAS_OP_C;
|
||||||
|
#if defined(HIP_VERSION_MAJOR) && (HIP_VERSION_MAJOR >=7)
|
||||||
|
auto err = hipblasCgemmBatched(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(hipComplex *) &alpha_p[0],
|
||||||
|
(hipComplex **)&Amk[0], lda,
|
||||||
|
(hipComplex **)&Bkn[0], ldb,
|
||||||
|
(hipComplex *) &beta_p[0],
|
||||||
|
(hipComplex **)&Cmn[0], ldc,
|
||||||
|
batchCount);
|
||||||
|
#else
|
||||||
|
auto err = hipblasCgemmBatched(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(hipblasComplex *) &alpha_p[0],
|
||||||
|
(hipblasComplex **)&Amk[0], lda,
|
||||||
|
(hipblasComplex **)&Bkn[0], ldb,
|
||||||
|
(hipblasComplex *) &beta_p[0],
|
||||||
|
(hipblasComplex **)&Cmn[0], ldc,
|
||||||
|
batchCount);
|
||||||
|
#endif
|
||||||
|
GRID_ASSERT(err==HIPBLAS_STATUS_SUCCESS);
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_CUDA
|
||||||
|
cublasOperation_t hOpA;
|
||||||
|
cublasOperation_t hOpB;
|
||||||
|
if ( OpA == GridBLAS_OP_N ) hOpA = CUBLAS_OP_N;
|
||||||
|
if ( OpA == GridBLAS_OP_T ) hOpA = CUBLAS_OP_T;
|
||||||
|
if ( OpA == GridBLAS_OP_C ) hOpA = CUBLAS_OP_C;
|
||||||
|
if ( OpB == GridBLAS_OP_N ) hOpB = CUBLAS_OP_N;
|
||||||
|
if ( OpB == GridBLAS_OP_T ) hOpB = CUBLAS_OP_T;
|
||||||
|
if ( OpB == GridBLAS_OP_C ) hOpB = CUBLAS_OP_C;
|
||||||
|
cublasStatus_t err;
|
||||||
|
if (precision == GridBLAS_PRECISION_DEFAULT) {
|
||||||
|
err = cublasCgemmBatched(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(cuComplex *) &alpha_p[0],
|
||||||
|
(cuComplex **)&Amk[0], lda,
|
||||||
|
(cuComplex **)&Bkn[0], ldb,
|
||||||
|
(cuComplex *) &beta_p[0],
|
||||||
|
(cuComplex **)&Cmn[0], ldc,
|
||||||
|
batchCount);
|
||||||
|
} else {
|
||||||
|
cublasComputeType_t compute_precision = toDataType(precision);
|
||||||
|
err = cublasGemmBatchedEx(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(void *) &alpha_p[0],
|
||||||
|
(void **)&Amk[0], CUDA_C_32F, lda,
|
||||||
|
(void **)&Bkn[0], CUDA_C_32F, ldb,
|
||||||
|
(void *) &beta_p[0],
|
||||||
|
(void **)&Cmn[0], CUDA_C_32F, ldc,
|
||||||
|
batchCount, compute_precision, CUBLAS_GEMM_DEFAULT);
|
||||||
|
}
|
||||||
|
GRID_ASSERT(err==CUBLAS_STATUS_SUCCESS);
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
GRID_ASSERT(precision == GridBLAS_PRECISION_DEFAULT);
|
||||||
|
int64_t m64=m;
|
||||||
|
int64_t n64=n;
|
||||||
|
int64_t k64=k;
|
||||||
|
int64_t lda64=lda;
|
||||||
|
int64_t ldb64=ldb;
|
||||||
|
int64_t ldc64=ldc;
|
||||||
|
int64_t batchCount64=batchCount;
|
||||||
|
|
||||||
|
oneapi::mkl::transpose iOpA;
|
||||||
|
oneapi::mkl::transpose iOpB;
|
||||||
|
|
||||||
|
if ( OpA == GridBLAS_OP_N ) iOpA = oneapi::mkl::transpose::N;
|
||||||
|
if ( OpA == GridBLAS_OP_T ) iOpA = oneapi::mkl::transpose::T;
|
||||||
|
if ( OpA == GridBLAS_OP_C ) iOpA = oneapi::mkl::transpose::C;
|
||||||
|
if ( OpB == GridBLAS_OP_N ) iOpB = oneapi::mkl::transpose::N;
|
||||||
|
if ( OpB == GridBLAS_OP_T ) iOpB = oneapi::mkl::transpose::T;
|
||||||
|
if ( OpB == GridBLAS_OP_C ) iOpB = oneapi::mkl::transpose::C;
|
||||||
|
|
||||||
|
oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle,
|
||||||
|
&iOpA,
|
||||||
|
&iOpB,
|
||||||
|
&m64,&n64,&k64,
|
||||||
|
(ComplexF *) &alpha_p[0],
|
||||||
|
(const ComplexF **)&Amk[0], (const int64_t *)&lda64,
|
||||||
|
(const ComplexF **)&Bkn[0], (const int64_t *)&ldb64,
|
||||||
|
(ComplexF *) &beta_p[0],
|
||||||
|
(ComplexF **)&Cmn[0], (const int64_t *)&ldc64,
|
||||||
|
(int64_t)1,&batchCount64,std::vector<sycl::event>());
|
||||||
|
synchronise();
|
||||||
|
#endif
|
||||||
|
#if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP)
|
||||||
|
GRID_ASSERT(precision == GridBLAS_PRECISION_DEFAULT);
|
||||||
|
// Reference implementation: Eigen with explicit outer stride
|
||||||
|
typedef Eigen::Map<Eigen::MatrixXcf,0,Eigen::OuterStride<> > eMat;
|
||||||
|
if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_N) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],m,k,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],k,n,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk * eBkn ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk * eBkn ;
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_N) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],k,n,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk.adjoint() * eBkn ;
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_N) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],k,n,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk.transpose() * eBkn ;
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_C) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],m,k,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk * eBkn.adjoint() ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk * eBkn.adjoint() ;
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_T) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],m,k,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk * eBkn.transpose() ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk * eBkn.transpose() ;
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_C) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn.adjoint() ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk.adjoint() * eBkn.adjoint() ;
|
||||||
|
} );
|
||||||
|
} else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_T) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn.transpose() ;
|
||||||
|
else
|
||||||
|
eCmn = alpha * eAmk.transpose() * eBkn.transpose() ;
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RealD t1=usecond();
|
||||||
|
RealD flops = 8.0*m*n*k*batchCount;
|
||||||
|
RealD bytes = 1.0*sizeof(ComplexF)*(m*k+k*n+m*n)*batchCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Explicit-leading-dimension complex double GEMM. Mirror of the ComplexF
|
||||||
|
// overload above; motivating use is the fp64 distributed recursive Schur
|
||||||
|
// inversion (RecursiveSchurInverse), whose operands are column windows of
|
||||||
|
// larger row-slab allocations.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void gemmBatched(GridBLASOperation_t OpA,
|
||||||
|
GridBLASOperation_t OpB,
|
||||||
|
int m,int n, int k,
|
||||||
|
ComplexD alpha,
|
||||||
|
deviceVector<ComplexD*> &Amk, int lda,
|
||||||
|
deviceVector<ComplexD*> &Bkn, int ldb,
|
||||||
|
ComplexD beta,
|
||||||
|
deviceVector<ComplexD*> &Cmn, int ldc)
|
||||||
|
{
|
||||||
|
RealD t2=usecond();
|
||||||
|
int32_t batchCount = Amk.size();
|
||||||
|
|
||||||
|
GRID_ASSERT( lda >= ((OpA==GridBLAS_OP_N) ? m : k) );
|
||||||
|
GRID_ASSERT( ldb >= ((OpB==GridBLAS_OP_N) ? k : n) );
|
||||||
|
GRID_ASSERT( ldc >= m );
|
||||||
|
|
||||||
|
// Cached device constants: copy only on value change (see GridBLASDeviceConstant)
|
||||||
|
static GridBLASDeviceConstant<ComplexD> alpha_c;
|
||||||
|
static GridBLASDeviceConstant<ComplexD> beta_c;
|
||||||
|
ComplexD *alpha_p = alpha_c.put(alpha);
|
||||||
|
ComplexD *beta_p = beta_c.put(beta);
|
||||||
|
RealD t0=usecond();
|
||||||
|
|
||||||
|
GRID_ASSERT(Bkn.size()==batchCount);
|
||||||
|
GRID_ASSERT(Cmn.size()==batchCount);
|
||||||
|
#ifdef GRID_HIP
|
||||||
|
hipblasOperation_t hOpA;
|
||||||
|
hipblasOperation_t hOpB;
|
||||||
|
if ( OpA == GridBLAS_OP_N ) hOpA = HIPBLAS_OP_N;
|
||||||
|
if ( OpA == GridBLAS_OP_T ) hOpA = HIPBLAS_OP_T;
|
||||||
|
if ( OpA == GridBLAS_OP_C ) hOpA = HIPBLAS_OP_C;
|
||||||
|
if ( OpB == GridBLAS_OP_N ) hOpB = HIPBLAS_OP_N;
|
||||||
|
if ( OpB == GridBLAS_OP_T ) hOpB = HIPBLAS_OP_T;
|
||||||
|
if ( OpB == GridBLAS_OP_C ) hOpB = HIPBLAS_OP_C;
|
||||||
|
#if defined(HIP_VERSION_MAJOR) && (HIP_VERSION_MAJOR >=7)
|
||||||
|
auto err = hipblasZgemmBatched(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(hipDoubleComplex *) &alpha_p[0],
|
||||||
|
(hipDoubleComplex **)&Amk[0], lda,
|
||||||
|
(hipDoubleComplex **)&Bkn[0], ldb,
|
||||||
|
(hipDoubleComplex *) &beta_p[0],
|
||||||
|
(hipDoubleComplex **)&Cmn[0], ldc,
|
||||||
|
batchCount);
|
||||||
|
#else
|
||||||
|
auto err = hipblasZgemmBatched(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(hipblasDoubleComplex *) &alpha_p[0],
|
||||||
|
(hipblasDoubleComplex **)&Amk[0], lda,
|
||||||
|
(hipblasDoubleComplex **)&Bkn[0], ldb,
|
||||||
|
(hipblasDoubleComplex *) &beta_p[0],
|
||||||
|
(hipblasDoubleComplex **)&Cmn[0], ldc,
|
||||||
|
batchCount);
|
||||||
|
#endif
|
||||||
|
GRID_ASSERT(err==HIPBLAS_STATUS_SUCCESS);
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_CUDA
|
||||||
|
cublasOperation_t hOpA;
|
||||||
|
cublasOperation_t hOpB;
|
||||||
|
if ( OpA == GridBLAS_OP_N ) hOpA = CUBLAS_OP_N;
|
||||||
|
if ( OpA == GridBLAS_OP_T ) hOpA = CUBLAS_OP_T;
|
||||||
|
if ( OpA == GridBLAS_OP_C ) hOpA = CUBLAS_OP_C;
|
||||||
|
if ( OpB == GridBLAS_OP_N ) hOpB = CUBLAS_OP_N;
|
||||||
|
if ( OpB == GridBLAS_OP_T ) hOpB = CUBLAS_OP_T;
|
||||||
|
if ( OpB == GridBLAS_OP_C ) hOpB = CUBLAS_OP_C;
|
||||||
|
auto err = cublasZgemmBatched(gridblasHandle,
|
||||||
|
hOpA,
|
||||||
|
hOpB,
|
||||||
|
m,n,k,
|
||||||
|
(cuDoubleComplex *) &alpha_p[0],
|
||||||
|
(cuDoubleComplex **)&Amk[0], lda,
|
||||||
|
(cuDoubleComplex **)&Bkn[0], ldb,
|
||||||
|
(cuDoubleComplex *) &beta_p[0],
|
||||||
|
(cuDoubleComplex **)&Cmn[0], ldc,
|
||||||
|
batchCount);
|
||||||
|
GRID_ASSERT(err==CUBLAS_STATUS_SUCCESS);
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
int64_t m64=m;
|
||||||
|
int64_t n64=n;
|
||||||
|
int64_t k64=k;
|
||||||
|
int64_t lda64=lda;
|
||||||
|
int64_t ldb64=ldb;
|
||||||
|
int64_t ldc64=ldc;
|
||||||
|
int64_t batchCount64=batchCount;
|
||||||
|
|
||||||
|
oneapi::mkl::transpose iOpA;
|
||||||
|
oneapi::mkl::transpose iOpB;
|
||||||
|
|
||||||
|
if ( OpA == GridBLAS_OP_N ) iOpA = oneapi::mkl::transpose::N;
|
||||||
|
if ( OpA == GridBLAS_OP_T ) iOpA = oneapi::mkl::transpose::T;
|
||||||
|
if ( OpA == GridBLAS_OP_C ) iOpA = oneapi::mkl::transpose::C;
|
||||||
|
if ( OpB == GridBLAS_OP_N ) iOpB = oneapi::mkl::transpose::N;
|
||||||
|
if ( OpB == GridBLAS_OP_T ) iOpB = oneapi::mkl::transpose::T;
|
||||||
|
if ( OpB == GridBLAS_OP_C ) iOpB = oneapi::mkl::transpose::C;
|
||||||
|
|
||||||
|
oneapi::mkl::blas::column_major::gemm_batch(*gridblasHandle,
|
||||||
|
&iOpA,
|
||||||
|
&iOpB,
|
||||||
|
&m64,&n64,&k64,
|
||||||
|
(ComplexD *) &alpha_p[0],
|
||||||
|
(const ComplexD **)&Amk[0], (const int64_t *)&lda64,
|
||||||
|
(const ComplexD **)&Bkn[0], (const int64_t *)&ldb64,
|
||||||
|
(ComplexD *) &beta_p[0],
|
||||||
|
(ComplexD **)&Cmn[0], (const int64_t *)&ldc64,
|
||||||
|
(int64_t)1,&batchCount64,std::vector<sycl::event>());
|
||||||
|
synchronise();
|
||||||
|
#endif
|
||||||
|
#if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP)
|
||||||
|
// Reference implementation: Eigen with explicit outer stride
|
||||||
|
typedef Eigen::Map<Eigen::MatrixXcd,0,Eigen::OuterStride<> > eMat;
|
||||||
|
if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_N) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],m,k,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],k,n,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk * eBkn;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk * eBkn;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_N) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],k,n,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk.adjoint() * eBkn;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_N) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],k,n,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk.transpose() * eBkn;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_C) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],m,k,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk * eBkn.adjoint();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk * eBkn.adjoint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_N ) && (OpB == GridBLAS_OP_T) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],m,k,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk * eBkn.transpose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk * eBkn.transpose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_C ) && (OpB == GridBLAS_OP_C) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.adjoint() * eBkn.adjoint();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk.adjoint() * eBkn.adjoint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ( (OpA == GridBLAS_OP_T ) && (OpB == GridBLAS_OP_T) ) {
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
eMat eAmk(Amk[p],k,m,Eigen::OuterStride<>(lda));
|
||||||
|
eMat eBkn(Bkn[p],n,k,Eigen::OuterStride<>(ldb));
|
||||||
|
eMat eCmn(Cmn[p],m,n,Eigen::OuterStride<>(ldc));
|
||||||
|
if (std::abs(beta) != 0.0)
|
||||||
|
{
|
||||||
|
eCmn = beta * eCmn + alpha * eAmk.transpose() * eBkn.transpose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eCmn = alpha * eAmk.transpose() * eBkn.transpose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RealD t1=usecond();
|
||||||
|
RealD flops = 8.0*m*n*k*batchCount;
|
||||||
|
RealD bytes = 1.0*sizeof(ComplexD)*(m*k+k*n+m*n)*batchCount;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Single precision real GEMM
|
// Single precision real GEMM
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@@ -721,11 +1244,11 @@ public:
|
|||||||
lda = k;
|
lda = k;
|
||||||
if(OpB!=GridBLAS_OP_N)
|
if(OpB!=GridBLAS_OP_N)
|
||||||
ldb = n;
|
ldb = n;
|
||||||
static deviceVector<RealF> alpha_p(1);
|
// Cached device constants: copy only on value change (see GridBLASDeviceConstant)
|
||||||
static deviceVector<RealF> beta_p(1);
|
static GridBLASDeviceConstant<RealF> alpha_c;
|
||||||
// can prestore the 1 and the zero on device
|
static GridBLASDeviceConstant<RealF> beta_c;
|
||||||
acceleratorCopyToDevice((void *)&alpha,(void *)&alpha_p[0],sizeof(RealF));
|
RealF *alpha_p = alpha_c.put(alpha);
|
||||||
acceleratorCopyToDevice((void *)&beta ,(void *)&beta_p[0],sizeof(RealF));
|
RealF *beta_p = beta_c.put(beta);
|
||||||
RealD t0=usecond();
|
RealD t0=usecond();
|
||||||
|
|
||||||
GRID_ASSERT(Bkn.size()==batchCount);
|
GRID_ASSERT(Bkn.size()==batchCount);
|
||||||
@@ -882,11 +1405,11 @@ public:
|
|||||||
if(OpB!=GridBLAS_OP_N)
|
if(OpB!=GridBLAS_OP_N)
|
||||||
ldb = n;
|
ldb = n;
|
||||||
|
|
||||||
static deviceVector<RealD> alpha_p(1);
|
// Cached device constants: copy only on value change (see GridBLASDeviceConstant)
|
||||||
static deviceVector<RealD> beta_p(1);
|
static GridBLASDeviceConstant<RealD> alpha_c;
|
||||||
// can prestore the 1 and the zero on device
|
static GridBLASDeviceConstant<RealD> beta_c;
|
||||||
acceleratorCopyToDevice((void *)&alpha,(void *)&alpha_p[0],sizeof(RealD));
|
RealD *alpha_p = alpha_c.put(alpha);
|
||||||
acceleratorCopyToDevice((void *)&beta ,(void *)&beta_p[0],sizeof(RealD));
|
RealD *beta_p = beta_c.put(beta);
|
||||||
RealD t0=usecond();
|
RealD t0=usecond();
|
||||||
|
|
||||||
GRID_ASSERT(Bkn.size()==batchCount);
|
GRID_ASSERT(Bkn.size()==batchCount);
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: BatchedInverse.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Grid/algorithms/blas/BatchedBlas.h>
|
||||||
|
|
||||||
|
#ifdef GRID_HIP
|
||||||
|
#include <rocsolver/rocsolver.h>
|
||||||
|
#endif
|
||||||
|
// GRID_CUDA: batched LU inversion lives in cuBLAS (getrfBatched/getriBatched);
|
||||||
|
// cublas_v2.h already included via BatchedBlas.h.
|
||||||
|
// GRID_SYCL: oneapi/mkl.hpp already included via BatchedBlas.h (lapack::getrf/getri).
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GridBLASInverse: cross-platform batched dense matrix inversion.
|
||||||
|
//
|
||||||
|
// HIGH LEVEL contract (deliberately NOT a getrf/getrs interface): invert a
|
||||||
|
// batch of dense N x N matrices IN PLACE,
|
||||||
|
//
|
||||||
|
// A[i] <- A[i]^{-1} i = 0 .. batchCount-1
|
||||||
|
//
|
||||||
|
// Layout: column major, lda = N, contiguous per batch element; pointer list
|
||||||
|
// exactly as GridBLAS::gemmBatched (deviceVector<T*> of device pointers).
|
||||||
|
// Each backend chooses HOW:
|
||||||
|
// HIP : rocSOLVER getrf_batched + getri_batched
|
||||||
|
// CUDA : cuBLAS getrfBatched + getriBatched (out-of-place getri; workspace
|
||||||
|
// hidden here, result copied back so the surface stays in-place)
|
||||||
|
// SYCL : oneMKL LAPACK getrf + getri per batch element (USM, in-order queue)
|
||||||
|
// CPU : Eigen PartialPivLU (the correctness oracle for all of the above)
|
||||||
|
//
|
||||||
|
// The int32 vendor-batched entry points bound N < 2^31 (asserted); the huge
|
||||||
|
// single-matrix ILP64 path (getrf_64 + blocked identity-getrs harvest, proven
|
||||||
|
// in the dense coarse-coarse setup at N=69120) migrates here as a batch==1
|
||||||
|
// large-N dispatch in a follow-up -- the recursive Schur leaves are the
|
||||||
|
// batched consumers this surface is shaped for.
|
||||||
|
//
|
||||||
|
// NB GPU-backend call signatures are written to vendor documentation but the
|
||||||
|
// air-gapped development loop compiles only the CPU/Eigen path; verify the
|
||||||
|
// rocSOLVER/cuBLAS/oneMKL calls against headers on first device compile.
|
||||||
|
// Semantics are locked by the CPU unit test (Test_batched_blas).
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
class GridBLASInverse {
|
||||||
|
public:
|
||||||
|
|
||||||
|
#ifdef GRID_HIP
|
||||||
|
// rocSOLVER runs on a rocblas_handle (distinct type from hipblasHandle_t)
|
||||||
|
static rocblas_handle & Handle(void) {
|
||||||
|
static rocblas_handle h;
|
||||||
|
static int init = 0;
|
||||||
|
if ( !init ) {
|
||||||
|
auto st = rocblas_create_handle(&h);
|
||||||
|
GRID_ASSERT(st == rocblas_status_success);
|
||||||
|
init = 1;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_CUDA
|
||||||
|
// cuBLAS batched LU shares the GridBLAS handle
|
||||||
|
static cublasHandle_t & Handle(void) {
|
||||||
|
GridBLAS::Init();
|
||||||
|
return GridBLAS::gridblasHandle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
static sycl::queue * & Handle(void) {
|
||||||
|
GridBLAS::Init();
|
||||||
|
return GridBLAS::gridblasHandle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GridBLASInverse() {};
|
||||||
|
~GridBLASInverse() {};
|
||||||
|
|
||||||
|
void inverseBatched(int64_t N, deviceVector<ComplexF*> &Amat)
|
||||||
|
{
|
||||||
|
int32_t batchCount = Amat.size();
|
||||||
|
GRID_ASSERT(batchCount > 0);
|
||||||
|
|
||||||
|
#ifdef GRID_HIP
|
||||||
|
GRID_ASSERT( N < 2147483647L );
|
||||||
|
rocblas_int n = (rocblas_int)N;
|
||||||
|
rocblas_int lda = (rocblas_int)N;
|
||||||
|
|
||||||
|
deviceVector<rocblas_int> ipiv((uint64_t)batchCount*N);
|
||||||
|
deviceVector<rocblas_int> info(batchCount);
|
||||||
|
|
||||||
|
auto st1 = rocsolver_cgetrf_batched(Handle(), n, n,
|
||||||
|
(rocblas_float_complex *const *)&Amat[0], lda,
|
||||||
|
&ipiv[0], (rocblas_stride)N,
|
||||||
|
&info[0], batchCount);
|
||||||
|
GRID_ASSERT(st1 == rocblas_status_success);
|
||||||
|
auto st2 = rocsolver_cgetri_batched(Handle(), n,
|
||||||
|
(rocblas_float_complex *const *)&Amat[0], lda,
|
||||||
|
&ipiv[0], (rocblas_stride)N,
|
||||||
|
&info[0], batchCount);
|
||||||
|
GRID_ASSERT(st2 == rocblas_status_success);
|
||||||
|
accelerator_barrier();
|
||||||
|
std::vector<rocblas_int> info_h(batchCount);
|
||||||
|
acceleratorCopyFromDevice(&info[0],&info_h[0],batchCount*sizeof(rocblas_int));
|
||||||
|
for(int i=0;i<batchCount;i++) GRID_ASSERT(info_h[i]==0); // singular pivot => abort loudly
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_CUDA
|
||||||
|
GRID_ASSERT( N < 2147483647L );
|
||||||
|
int n = (int)N;
|
||||||
|
|
||||||
|
deviceVector<int> ipiv((uint64_t)batchCount*N);
|
||||||
|
deviceVector<int> info(batchCount);
|
||||||
|
|
||||||
|
auto st1 = cublasCgetrfBatched(Handle(), n,
|
||||||
|
(cuComplex **)&Amat[0], n,
|
||||||
|
&ipiv[0], &info[0], batchCount);
|
||||||
|
GRID_ASSERT(st1 == CUBLAS_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
// getri is OUT of place: hidden workspace keeps the surface in-place
|
||||||
|
deviceVector<ComplexF> work((uint64_t)batchCount*N*N);
|
||||||
|
deviceVector<ComplexF*> Cptr(batchCount);
|
||||||
|
std::vector<ComplexF*> Cptr_h(batchCount);
|
||||||
|
std::vector<ComplexF*> Aptr_h(batchCount);
|
||||||
|
for(int i=0;i<batchCount;i++) Cptr_h[i] = &work[(uint64_t)i*N*N];
|
||||||
|
acceleratorCopyToDevice(&Cptr_h[0],&Cptr[0],batchCount*sizeof(ComplexF*));
|
||||||
|
acceleratorCopyFromDevice(&Amat[0],&Aptr_h[0],batchCount*sizeof(ComplexF*));
|
||||||
|
|
||||||
|
auto st2 = cublasCgetriBatched(Handle(), n,
|
||||||
|
(const cuComplex *const *)&Amat[0], n,
|
||||||
|
&ipiv[0],
|
||||||
|
(cuComplex **)&Cptr[0], n,
|
||||||
|
&info[0], batchCount);
|
||||||
|
GRID_ASSERT(st2 == CUBLAS_STATUS_SUCCESS);
|
||||||
|
accelerator_barrier();
|
||||||
|
std::vector<int> info_h(batchCount);
|
||||||
|
acceleratorCopyFromDevice(&info[0],&info_h[0],batchCount*sizeof(int));
|
||||||
|
for(int i=0;i<batchCount;i++) GRID_ASSERT(info_h[i]==0);
|
||||||
|
for(int i=0;i<batchCount;i++)
|
||||||
|
acceleratorCopyDeviceToDevice(Cptr_h[i],Aptr_h[i],(uint64_t)N*N*sizeof(ComplexF));
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
// Per-element oneMKL LAPACK on the in-order queue; group API optimisation later.
|
||||||
|
sycl::queue *q = Handle();
|
||||||
|
std::vector<ComplexF*> Aptr_h(batchCount);
|
||||||
|
acceleratorCopyFromDevice(&Amat[0],&Aptr_h[0],batchCount*sizeof(ComplexF*));
|
||||||
|
|
||||||
|
int64_t lwf = oneapi::mkl::lapack::getrf_scratchpad_size<std::complex<float> >(*q,N,N,N);
|
||||||
|
int64_t lwi = oneapi::mkl::lapack::getri_scratchpad_size<std::complex<float> >(*q,N,N);
|
||||||
|
deviceVector<ComplexF> scratchf(lwf);
|
||||||
|
deviceVector<ComplexF> scratchi(lwi);
|
||||||
|
deviceVector<int64_t> ipiv(N);
|
||||||
|
for(int i=0;i<batchCount;i++){
|
||||||
|
oneapi::mkl::lapack::getrf(*q,N,N,(std::complex<float>*)Aptr_h[i],N,&ipiv[0],
|
||||||
|
(std::complex<float>*)&scratchf[0],lwf);
|
||||||
|
oneapi::mkl::lapack::getri(*q,N, (std::complex<float>*)Aptr_h[i],N,&ipiv[0],
|
||||||
|
(std::complex<float>*)&scratchi[0],lwi);
|
||||||
|
}
|
||||||
|
q->wait();
|
||||||
|
#endif
|
||||||
|
#if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP)
|
||||||
|
// Reference implementation; the oracle the unit test locks semantics with.
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
Eigen::Map<Eigen::MatrixXcf> eA(Amat[p],N,N);
|
||||||
|
Eigen::PartialPivLU<Eigen::MatrixXcf> lu(eA);
|
||||||
|
eA = lu.inverse();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void inverseBatched(int64_t N, deviceVector<ComplexD*> &Amat)
|
||||||
|
{
|
||||||
|
int32_t batchCount = Amat.size();
|
||||||
|
GRID_ASSERT(batchCount > 0);
|
||||||
|
|
||||||
|
#ifdef GRID_HIP
|
||||||
|
GRID_ASSERT( N < 2147483647L );
|
||||||
|
rocblas_int n = (rocblas_int)N;
|
||||||
|
rocblas_int lda = (rocblas_int)N;
|
||||||
|
|
||||||
|
deviceVector<rocblas_int> ipiv((uint64_t)batchCount*N);
|
||||||
|
deviceVector<rocblas_int> info(batchCount);
|
||||||
|
|
||||||
|
auto st1 = rocsolver_zgetrf_batched(Handle(), n, n,
|
||||||
|
(rocblas_double_complex *const *)&Amat[0], lda,
|
||||||
|
&ipiv[0], (rocblas_stride)N,
|
||||||
|
&info[0], batchCount);
|
||||||
|
GRID_ASSERT(st1 == rocblas_status_success);
|
||||||
|
auto st2 = rocsolver_zgetri_batched(Handle(), n,
|
||||||
|
(rocblas_double_complex *const *)&Amat[0], lda,
|
||||||
|
&ipiv[0], (rocblas_stride)N,
|
||||||
|
&info[0], batchCount);
|
||||||
|
GRID_ASSERT(st2 == rocblas_status_success);
|
||||||
|
accelerator_barrier();
|
||||||
|
std::vector<rocblas_int> info_h(batchCount);
|
||||||
|
acceleratorCopyFromDevice(&info[0],&info_h[0],batchCount*sizeof(rocblas_int));
|
||||||
|
for(int i=0;i<batchCount;i++) GRID_ASSERT(info_h[i]==0);
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_CUDA
|
||||||
|
GRID_ASSERT( N < 2147483647L );
|
||||||
|
int n = (int)N;
|
||||||
|
|
||||||
|
deviceVector<int> ipiv((uint64_t)batchCount*N);
|
||||||
|
deviceVector<int> info(batchCount);
|
||||||
|
|
||||||
|
auto st1 = cublasZgetrfBatched(Handle(), n,
|
||||||
|
(cuDoubleComplex **)&Amat[0], n,
|
||||||
|
&ipiv[0], &info[0], batchCount);
|
||||||
|
GRID_ASSERT(st1 == CUBLAS_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
deviceVector<ComplexD> work((uint64_t)batchCount*N*N);
|
||||||
|
deviceVector<ComplexD*> Cptr(batchCount);
|
||||||
|
std::vector<ComplexD*> Cptr_h(batchCount);
|
||||||
|
std::vector<ComplexD*> Aptr_h(batchCount);
|
||||||
|
for(int i=0;i<batchCount;i++) Cptr_h[i] = &work[(uint64_t)i*N*N];
|
||||||
|
acceleratorCopyToDevice(&Cptr_h[0],&Cptr[0],batchCount*sizeof(ComplexD*));
|
||||||
|
acceleratorCopyFromDevice(&Amat[0],&Aptr_h[0],batchCount*sizeof(ComplexD*));
|
||||||
|
|
||||||
|
auto st2 = cublasZgetriBatched(Handle(), n,
|
||||||
|
(const cuDoubleComplex *const *)&Amat[0], n,
|
||||||
|
&ipiv[0],
|
||||||
|
(cuDoubleComplex **)&Cptr[0], n,
|
||||||
|
&info[0], batchCount);
|
||||||
|
GRID_ASSERT(st2 == CUBLAS_STATUS_SUCCESS);
|
||||||
|
accelerator_barrier();
|
||||||
|
std::vector<int> info_h(batchCount);
|
||||||
|
acceleratorCopyFromDevice(&info[0],&info_h[0],batchCount*sizeof(int));
|
||||||
|
for(int i=0;i<batchCount;i++) GRID_ASSERT(info_h[i]==0);
|
||||||
|
for(int i=0;i<batchCount;i++)
|
||||||
|
acceleratorCopyDeviceToDevice(Cptr_h[i],Aptr_h[i],(uint64_t)N*N*sizeof(ComplexD));
|
||||||
|
#endif
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
sycl::queue *q = Handle();
|
||||||
|
std::vector<ComplexD*> Aptr_h(batchCount);
|
||||||
|
acceleratorCopyFromDevice(&Amat[0],&Aptr_h[0],batchCount*sizeof(ComplexD*));
|
||||||
|
|
||||||
|
int64_t lwf = oneapi::mkl::lapack::getrf_scratchpad_size<std::complex<double> >(*q,N,N,N);
|
||||||
|
int64_t lwi = oneapi::mkl::lapack::getri_scratchpad_size<std::complex<double> >(*q,N,N);
|
||||||
|
deviceVector<ComplexD> scratchf(lwf);
|
||||||
|
deviceVector<ComplexD> scratchi(lwi);
|
||||||
|
deviceVector<int64_t> ipiv(N);
|
||||||
|
for(int i=0;i<batchCount;i++){
|
||||||
|
oneapi::mkl::lapack::getrf(*q,N,N,(std::complex<double>*)Aptr_h[i],N,&ipiv[0],
|
||||||
|
(std::complex<double>*)&scratchf[0],lwf);
|
||||||
|
oneapi::mkl::lapack::getri(*q,N, (std::complex<double>*)Aptr_h[i],N,&ipiv[0],
|
||||||
|
(std::complex<double>*)&scratchi[0],lwi);
|
||||||
|
}
|
||||||
|
q->wait();
|
||||||
|
#endif
|
||||||
|
#if !defined(GRID_SYCL) && !defined(GRID_CUDA) && !defined(GRID_HIP)
|
||||||
|
thread_for (p, batchCount, {
|
||||||
|
Eigen::Map<Eigen::MatrixXcd> eA(Amat[p],N,N);
|
||||||
|
Eigen::PartialPivLU<Eigen::MatrixXcd> lu(eA);
|
||||||
|
eA = lu.inverse();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -61,6 +61,17 @@ public:
|
|||||||
uint64_t coarse_vol;
|
uint64_t coarse_vol;
|
||||||
uint64_t words;
|
uint64_t words;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Blocking geometry in full local coordinates. Addressing in lSites rather
|
||||||
|
// than (lane,oSite) lets the fine and coarse spaces carry different SIMD
|
||||||
|
// layouts, so an unvectorised coarse space may block a vectorised fine one.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
Coordinate fine_ldimensions;
|
||||||
|
Coordinate coarse_ldimensions;
|
||||||
|
Coordinate block_ldimensions;
|
||||||
|
Coordinate fine_simd;
|
||||||
|
Coordinate coarse_simd;
|
||||||
|
|
||||||
// Row major layout "C" order:
|
// Row major layout "C" order:
|
||||||
// BLAS_V[coarse_vol][nbasis][block_vol][words]
|
// BLAS_V[coarse_vol][nbasis][block_vol][words]
|
||||||
// BLAS_F[coarse_vol][nrhs][block_vol][words]
|
// BLAS_F[coarse_vol][nrhs][block_vol][words]
|
||||||
@@ -123,6 +134,23 @@ public:
|
|||||||
|
|
||||||
words = sizeof(scalar_object)/sizeof(scalar);
|
words = sizeof(scalar_object)/sizeof(scalar);
|
||||||
|
|
||||||
|
int nd = coarse_grid->_ndimension;
|
||||||
|
GRID_ASSERT(fine_grid->_ndimension == nd);
|
||||||
|
|
||||||
|
fine_ldimensions.resize(nd);
|
||||||
|
coarse_ldimensions.resize(nd);
|
||||||
|
block_ldimensions.resize(nd);
|
||||||
|
fine_simd = fine_grid->_simd_layout;
|
||||||
|
coarse_simd = coarse_grid->_simd_layout;
|
||||||
|
for(int d=0;d<nd;d++){
|
||||||
|
GRID_ASSERT(fine_grid->_processors[d] == coarse_grid->_processors[d]);
|
||||||
|
fine_ldimensions [d] = fine_grid->_rdimensions [d]*fine_grid->_simd_layout [d];
|
||||||
|
coarse_ldimensions[d] = coarse_grid->_rdimensions[d]*coarse_grid->_simd_layout[d];
|
||||||
|
block_ldimensions [d] = fine_ldimensions[d]/coarse_ldimensions[d];
|
||||||
|
GRID_ASSERT(block_ldimensions[d]*coarse_ldimensions[d] == fine_ldimensions[d]);
|
||||||
|
}
|
||||||
|
GRID_ASSERT(block_vol == fine_vol/coarse_vol);
|
||||||
|
|
||||||
BLAS_V.resize (fine_vol * words * nbasis );
|
BLAS_V.resize (fine_vol * words * nbasis );
|
||||||
}
|
}
|
||||||
void ImportFineGridVectors(std::vector <Field > &vecs, deviceVector<scalar> &blas)
|
void ImportFineGridVectors(std::vector <Field > &vecs, deviceVector<scalar> &blas)
|
||||||
@@ -133,22 +161,16 @@ public:
|
|||||||
|
|
||||||
GRID_ASSERT(vecs[0].Grid()==fine_grid);
|
GRID_ASSERT(vecs[0].Grid()==fine_grid);
|
||||||
|
|
||||||
subdivides(coarse_grid,fine_grid); // require they map
|
|
||||||
|
|
||||||
int _ndimension = coarse_grid->_ndimension;
|
int _ndimension = coarse_grid->_ndimension;
|
||||||
GRID_ASSERT(block_vol == fine_grid->oSites() / coarse_grid->oSites());
|
|
||||||
|
|
||||||
Coordinate block_r (_ndimension);
|
|
||||||
for(int d=0 ; d<_ndimension;d++){
|
|
||||||
block_r[d] = fine_grid->_rdimensions[d] / coarse_grid->_rdimensions[d];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t sz = blas.size();
|
uint64_t sz = blas.size();
|
||||||
|
|
||||||
acceleratorMemSet(&blas[0],0,blas.size()*sizeof(scalar));
|
acceleratorMemSet(&blas[0],0,blas.size()*sizeof(scalar));
|
||||||
|
|
||||||
Coordinate fine_rdimensions = fine_grid->_rdimensions;
|
Coordinate fine_rdimensions = fine_grid->_rdimensions;
|
||||||
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate block_l = block_ldimensions;
|
||||||
|
Coordinate fsimd = fine_simd;
|
||||||
int64_t bv= block_vol;
|
int64_t bv= block_vol;
|
||||||
for(int v=0;v<vecs.size();v++){
|
for(int v=0;v<vecs.size();v++){
|
||||||
|
|
||||||
@@ -162,9 +184,7 @@ public:
|
|||||||
|
|
||||||
// loop over fine sites
|
// loop over fine sites
|
||||||
const int Nsimd = vobj::Nsimd();
|
const int Nsimd = vobj::Nsimd();
|
||||||
// std::cout << "sz "<<sz<<std::endl;
|
GRID_ASSERT(sz == coarse_vol * block_vol * nvec * words);
|
||||||
// std::cout << "prod "<<Nsimd * coarse_grid->oSites() * block_vol * nvec * words<<std::endl;
|
|
||||||
GRID_ASSERT(sz == Nsimd * coarse_grid->oSites() * block_vol * nvec * words);
|
|
||||||
uint64_t lwords= words; // local variable for copy in to GPU
|
uint64_t lwords= words; // local variable for copy in to GPU
|
||||||
accelerator_for(sf,osites,Nsimd,{
|
accelerator_for(sf,osites,Nsimd,{
|
||||||
#ifdef GRID_SIMT
|
#ifdef GRID_SIMT
|
||||||
@@ -175,27 +195,27 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
// One thread per fine site
|
// One thread per fine site
|
||||||
Coordinate coor_f(_ndimension);
|
Coordinate coor_f(_ndimension);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
Coordinate coor_b(_ndimension);
|
Coordinate coor_b(_ndimension);
|
||||||
Coordinate coor_c(_ndimension);
|
Coordinate coor_c(_ndimension);
|
||||||
|
|
||||||
// Fine site to fine coor
|
// Fine (oSite,lane) to full local coor
|
||||||
Lexicographic::CoorFromIndex(coor_f,sf,fine_rdimensions);
|
Lexicographic::CoorFromIndex(coor_f,sf,fine_rdimensions);
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,fsimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_f[d] += fine_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
for(int d=0;d<_ndimension;d++) coor_b[d] = coor_f[d]%block_r[d];
|
for(int d=0;d<_ndimension;d++) coor_b[d] = coor_f[d]%block_l[d];
|
||||||
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_f[d]/block_r[d];
|
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_f[d]/block_l[d];
|
||||||
|
|
||||||
int sc;// coarse site
|
int sc;// coarse site
|
||||||
int sb;// block site
|
int sb;// block site
|
||||||
Lexicographic::IndexFromCoor(coor_c,sc,coarse_rdimensions);
|
Lexicographic::IndexFromCoor(coor_c,sc,coarse_l);
|
||||||
Lexicographic::IndexFromCoor(coor_b,sb,block_r);
|
Lexicographic::IndexFromCoor(coor_b,sb,block_l);
|
||||||
|
|
||||||
scalar_object data = extractLane(lane,fineData[sf]);
|
scalar_object data = extractLane(lane,fineData[sf]);
|
||||||
|
|
||||||
// BLAS layout address calculation
|
// BLAS_F[coarse_vol][nvec][block_vol][words]
|
||||||
// words * block_vol * nbasis x coarse_vol
|
int64_t site = (sc*nvec + v)*bv
|
||||||
// coarse oSite x block vole x lanes
|
|
||||||
int64_t site = (lane*osites + sc*bv)*nvec
|
|
||||||
+ v*bv
|
|
||||||
+ sb;
|
+ sb;
|
||||||
|
|
||||||
// GRID_ASSERT(site*lwords<sz);
|
// GRID_ASSERT(site*lwords<sz);
|
||||||
@@ -213,6 +233,318 @@ public:
|
|||||||
// std::cout << " BlockProjector imported vector"<<v<<std::endl;
|
// std::cout << " BlockProjector imported vector"<<v<<std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Import direct from multiRHS fine order, avoiding the unpack to a vector
|
||||||
|
// of single RHS fields.
|
||||||
|
//
|
||||||
|
// fine mrhs grid : rhs is dimension 0, undistributed, unvectorised
|
||||||
|
// Grid order : F[fine_vol][nrhs][words]
|
||||||
|
// BLAS order : BLAS_F[lane][coarse_vol][nrhs][block_vol][words]
|
||||||
|
//
|
||||||
|
// The gather of block_vol from fine_vol, and the transpose of nrhs against
|
||||||
|
// block_vol, are the irreducible part: this is not the identity.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
void ImportFineGridMrhsVectors(Field &vec_mrhs, deviceVector<scalar> &blas)
|
||||||
|
{
|
||||||
|
typedef typename Field::vector_object vobj;
|
||||||
|
|
||||||
|
GridBase *fine_mrhs_grid = vec_mrhs.Grid();
|
||||||
|
int _ndimension = coarse_grid->_ndimension;
|
||||||
|
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_ndimension == _ndimension+1);
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_simd_layout[0] == 1);
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_processors[0] == 1);
|
||||||
|
for(int d=0;d<_ndimension;d++){
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_rdimensions[d+1] == fine_grid->_rdimensions[d]);
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_simd_layout[d+1] == fine_grid->_simd_layout[d]);
|
||||||
|
}
|
||||||
|
int nvec = fine_mrhs_grid->_rdimensions[0]; // nrhs
|
||||||
|
|
||||||
|
uint64_t sz = blas.size();
|
||||||
|
acceleratorMemSet(&blas[0],0,blas.size()*sizeof(scalar));
|
||||||
|
|
||||||
|
Coordinate fine_mrhs_rdimensions = fine_mrhs_grid->_rdimensions;
|
||||||
|
Coordinate fine_rdimensions = fine_grid->_rdimensions;
|
||||||
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate block_l = block_ldimensions;
|
||||||
|
Coordinate fsimd = fine_simd;
|
||||||
|
int64_t bv= block_vol;
|
||||||
|
|
||||||
|
autoView( fineData , vec_mrhs, AcceleratorRead);
|
||||||
|
auto blasData_p = &blas[0];
|
||||||
|
auto fineData_p = &fineData[0];
|
||||||
|
|
||||||
|
int64_t osites = fine_grid->oSites(); // D dimensional
|
||||||
|
int64_t osites_hi = fine_mrhs_grid->oSites(); // nvec * osites
|
||||||
|
|
||||||
|
const int Nsimd = vobj::Nsimd();
|
||||||
|
GRID_ASSERT(sz == coarse_vol * block_vol * nvec * words);
|
||||||
|
uint64_t lwords= words;
|
||||||
|
int64_t lnvec = nvec;
|
||||||
|
|
||||||
|
accelerator_for(sfr,osites_hi,Nsimd,{
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
{
|
||||||
|
int lane=acceleratorSIMTlane(Nsimd); // buffer lane
|
||||||
|
#else
|
||||||
|
for(int lane=0;lane<Nsimd;lane++) {
|
||||||
|
#endif
|
||||||
|
Coordinate coor_hi(_ndimension+1);
|
||||||
|
Coordinate coor_f(_ndimension);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
|
Coordinate coor_b(_ndimension);
|
||||||
|
Coordinate coor_c(_ndimension);
|
||||||
|
|
||||||
|
// rhs is dimension 0 of the D+1 grid
|
||||||
|
Lexicographic::CoorFromIndex(coor_hi,sfr,fine_mrhs_rdimensions);
|
||||||
|
int v = coor_hi[0];
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_f[d] = coor_hi[d+1];
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,fsimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_f[d] += fine_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_b[d] = coor_f[d]%block_l[d];
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_f[d]/block_l[d];
|
||||||
|
|
||||||
|
int sc;// coarse site
|
||||||
|
int sb;// block site
|
||||||
|
Lexicographic::IndexFromCoor(coor_c,sc,coarse_l);
|
||||||
|
Lexicographic::IndexFromCoor(coor_b,sb,block_l);
|
||||||
|
|
||||||
|
scalar_object data = extractLane(lane,fineData[sfr]);
|
||||||
|
|
||||||
|
int64_t site = (sc*lnvec + v)*bv
|
||||||
|
+ sb;
|
||||||
|
|
||||||
|
scalar_object * ptr = (scalar_object *)&blasData_p[site*lwords];
|
||||||
|
*ptr = data;
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Export direct to multiRHS coarse order.
|
||||||
|
//
|
||||||
|
// Grid order : C[coarse_vol][nrhs][nbasis]
|
||||||
|
// BLAS order : BLAS_C[lane][coarse_vol][nrhs][nbasis]
|
||||||
|
//
|
||||||
|
// At Nsimd()==1 these are the same sequence of addresses.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class vobj>
|
||||||
|
void ExportCoarseGridMrhsVectors(Lattice<vobj> &vec_mrhs, deviceVector<scalar> &blas)
|
||||||
|
{
|
||||||
|
typedef typename vobj::scalar_object coarse_scalar_object;
|
||||||
|
|
||||||
|
GridBase *coarse_mrhs_grid = vec_mrhs.Grid();
|
||||||
|
int _ndimension = coarse_grid->_ndimension;
|
||||||
|
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_ndimension == _ndimension+1);
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_simd_layout[0] == 1);
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_processors[0] == 1);
|
||||||
|
for(int d=0;d<_ndimension;d++){
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_rdimensions[d+1] == coarse_grid->_rdimensions[d]);
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_simd_layout[d+1] == coarse_grid->_simd_layout[d]);
|
||||||
|
}
|
||||||
|
int nvec = coarse_mrhs_grid->_rdimensions[0]; // nrhs
|
||||||
|
|
||||||
|
Coordinate coarse_mrhs_rdimensions = coarse_mrhs_grid->_rdimensions;
|
||||||
|
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
||||||
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate csimd = coarse_simd;
|
||||||
|
|
||||||
|
autoView( coarseData , vec_mrhs, AcceleratorWrite);
|
||||||
|
auto blasData_p = &blas[0];
|
||||||
|
auto coarseData_p = &coarseData[0];
|
||||||
|
|
||||||
|
int64_t osites = coarse_grid->oSites(); // D dimensional
|
||||||
|
int64_t osites_hi = coarse_mrhs_grid->oSites(); // nvec * osites
|
||||||
|
|
||||||
|
const int Nsimd = vobj::Nsimd();
|
||||||
|
uint64_t cwords=sizeof(typename vobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(cwords==nbasis);
|
||||||
|
int64_t lnvec = nvec;
|
||||||
|
|
||||||
|
accelerator_for(scr,osites_hi,Nsimd,{
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
{
|
||||||
|
int lane=acceleratorSIMTlane(Nsimd); // buffer lane
|
||||||
|
#else
|
||||||
|
for(int lane=0;lane<Nsimd;lane++) {
|
||||||
|
#endif
|
||||||
|
Coordinate coor_hi(_ndimension+1);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
|
Coordinate coor_c(_ndimension);
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_hi,scr,coarse_mrhs_rdimensions);
|
||||||
|
int v = coor_hi[0];
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_hi[d+1];
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,csimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] += coarse_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
|
int sc;
|
||||||
|
Lexicographic::IndexFromCoor(coor_c,sc,coarse_l);
|
||||||
|
|
||||||
|
int64_t blas_site = (sc*lnvec + v)*cwords;
|
||||||
|
coarse_scalar_object * ptr = (coarse_scalar_object *)&blasData_p[blas_site];
|
||||||
|
coarse_scalar_object data = *ptr;
|
||||||
|
insertLane(lane,coarseData[scr],data);
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Reverse directions: BLAS_F -> fine mrhs field, coarse mrhs field -> BLAS_C
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
void ExportFineGridMrhsVectors(Field &vec_mrhs, deviceVector<scalar> &blas)
|
||||||
|
{
|
||||||
|
typedef typename Field::vector_object vobj;
|
||||||
|
|
||||||
|
GridBase *fine_mrhs_grid = vec_mrhs.Grid();
|
||||||
|
int _ndimension = coarse_grid->_ndimension;
|
||||||
|
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_ndimension == _ndimension+1);
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_simd_layout[0] == 1);
|
||||||
|
for(int d=0;d<_ndimension;d++){
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_rdimensions[d+1] == fine_grid->_rdimensions[d]);
|
||||||
|
GRID_ASSERT(fine_mrhs_grid->_simd_layout[d+1] == fine_grid->_simd_layout[d]);
|
||||||
|
}
|
||||||
|
int nvec = fine_mrhs_grid->_rdimensions[0];
|
||||||
|
|
||||||
|
Coordinate fine_mrhs_rdimensions = fine_mrhs_grid->_rdimensions;
|
||||||
|
Coordinate fine_rdimensions = fine_grid->_rdimensions;
|
||||||
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate block_l = block_ldimensions;
|
||||||
|
Coordinate fsimd = fine_simd;
|
||||||
|
int64_t bv= block_vol;
|
||||||
|
|
||||||
|
autoView( fineData , vec_mrhs, AcceleratorWrite);
|
||||||
|
auto blasData_p = &blas[0];
|
||||||
|
auto fineData_p = &fineData[0];
|
||||||
|
|
||||||
|
int64_t osites = fine_grid->oSites();
|
||||||
|
int64_t osites_hi = fine_mrhs_grid->oSites();
|
||||||
|
|
||||||
|
const int Nsimd = vobj::Nsimd();
|
||||||
|
uint64_t lwords= words;
|
||||||
|
int64_t lnvec = nvec;
|
||||||
|
|
||||||
|
accelerator_for(sfr,osites_hi,Nsimd,{
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
{
|
||||||
|
int lane=acceleratorSIMTlane(Nsimd);
|
||||||
|
#else
|
||||||
|
for(int lane=0;lane<Nsimd;lane++) {
|
||||||
|
#endif
|
||||||
|
Coordinate coor_hi(_ndimension+1);
|
||||||
|
Coordinate coor_f(_ndimension);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
|
Coordinate coor_b(_ndimension);
|
||||||
|
Coordinate coor_c(_ndimension);
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_hi,sfr,fine_mrhs_rdimensions);
|
||||||
|
int v = coor_hi[0];
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_f[d] = coor_hi[d+1];
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,fsimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_f[d] += fine_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_b[d] = coor_f[d]%block_l[d];
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_f[d]/block_l[d];
|
||||||
|
|
||||||
|
int sc,sb;
|
||||||
|
Lexicographic::IndexFromCoor(coor_c,sc,coarse_l);
|
||||||
|
Lexicographic::IndexFromCoor(coor_b,sb,block_l);
|
||||||
|
|
||||||
|
int64_t site = (sc*lnvec + v)*bv
|
||||||
|
+ sb;
|
||||||
|
|
||||||
|
scalar_object * ptr = (scalar_object *)&blasData_p[site*lwords];
|
||||||
|
scalar_object data = *ptr;
|
||||||
|
insertLane(lane,fineData[sfr],data);
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class vobj>
|
||||||
|
void ImportCoarseGridMrhsVectors(Lattice<vobj> &vec_mrhs, deviceVector<scalar> &blas)
|
||||||
|
{
|
||||||
|
typedef typename vobj::scalar_object coarse_scalar_object;
|
||||||
|
|
||||||
|
GridBase *coarse_mrhs_grid = vec_mrhs.Grid();
|
||||||
|
int _ndimension = coarse_grid->_ndimension;
|
||||||
|
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_ndimension == _ndimension+1);
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_simd_layout[0] == 1);
|
||||||
|
for(int d=0;d<_ndimension;d++){
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_rdimensions[d+1] == coarse_grid->_rdimensions[d]);
|
||||||
|
GRID_ASSERT(coarse_mrhs_grid->_simd_layout[d+1] == coarse_grid->_simd_layout[d]);
|
||||||
|
}
|
||||||
|
int nvec = coarse_mrhs_grid->_rdimensions[0];
|
||||||
|
|
||||||
|
Coordinate coarse_mrhs_rdimensions = coarse_mrhs_grid->_rdimensions;
|
||||||
|
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
||||||
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate csimd = coarse_simd;
|
||||||
|
|
||||||
|
autoView( coarseData , vec_mrhs, AcceleratorRead);
|
||||||
|
auto blasData_p = &blas[0];
|
||||||
|
auto coarseData_p = &coarseData[0];
|
||||||
|
|
||||||
|
int64_t osites = coarse_grid->oSites();
|
||||||
|
int64_t osites_hi = coarse_mrhs_grid->oSites();
|
||||||
|
|
||||||
|
const int Nsimd = vobj::Nsimd();
|
||||||
|
uint64_t cwords=sizeof(typename vobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(cwords==nbasis);
|
||||||
|
int64_t lnvec = nvec;
|
||||||
|
|
||||||
|
accelerator_for(scr,osites_hi,Nsimd,{
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
{
|
||||||
|
int lane=acceleratorSIMTlane(Nsimd);
|
||||||
|
#else
|
||||||
|
for(int lane=0;lane<Nsimd;lane++) {
|
||||||
|
#endif
|
||||||
|
Coordinate coor_hi(_ndimension+1);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
|
Coordinate coor_c(_ndimension);
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_hi,scr,coarse_mrhs_rdimensions);
|
||||||
|
int v = coor_hi[0];
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_hi[d+1];
|
||||||
|
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,csimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] += coarse_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
|
int sc;
|
||||||
|
Lexicographic::IndexFromCoor(coor_c,sc,coarse_l);
|
||||||
|
|
||||||
|
coarse_scalar_object data = extractLane(lane,coarseData[scr]);
|
||||||
|
|
||||||
|
int64_t blas_site = (sc*lnvec + v)*cwords;
|
||||||
|
coarse_scalar_object * ptr = (coarse_scalar_object *)&blasData_p[blas_site];
|
||||||
|
*ptr = data;
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ExportFineGridVectors(std::vector <Field> &vecs, deviceVector<scalar> &blas)
|
void ExportFineGridVectors(std::vector <Field> &vecs, deviceVector<scalar> &blas)
|
||||||
{
|
{
|
||||||
typedef typename Field::vector_object vobj;
|
typedef typename Field::vector_object vobj;
|
||||||
@@ -221,17 +553,12 @@ public:
|
|||||||
|
|
||||||
GRID_ASSERT(vecs[0].Grid()==fine_grid);
|
GRID_ASSERT(vecs[0].Grid()==fine_grid);
|
||||||
|
|
||||||
subdivides(coarse_grid,fine_grid); // require they map
|
|
||||||
|
|
||||||
int _ndimension = coarse_grid->_ndimension;
|
int _ndimension = coarse_grid->_ndimension;
|
||||||
GRID_ASSERT(block_vol == fine_grid->oSites() / coarse_grid->oSites());
|
|
||||||
|
|
||||||
Coordinate block_r (_ndimension);
|
|
||||||
for(int d=0 ; d<_ndimension;d++){
|
|
||||||
block_r[d] = fine_grid->_rdimensions[d] / coarse_grid->_rdimensions[d];
|
|
||||||
}
|
|
||||||
Coordinate fine_rdimensions = fine_grid->_rdimensions;
|
Coordinate fine_rdimensions = fine_grid->_rdimensions;
|
||||||
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate block_l = block_ldimensions;
|
||||||
|
Coordinate fsimd = fine_simd;
|
||||||
|
|
||||||
// std::cout << " export fine Blas norm "<<blasNorm2(blas)<<std::endl;
|
// std::cout << " export fine Blas norm "<<blasNorm2(blas)<<std::endl;
|
||||||
|
|
||||||
@@ -259,23 +586,24 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
// One thread per fine site
|
// One thread per fine site
|
||||||
Coordinate coor_f(_ndimension);
|
Coordinate coor_f(_ndimension);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
Coordinate coor_b(_ndimension);
|
Coordinate coor_b(_ndimension);
|
||||||
Coordinate coor_c(_ndimension);
|
Coordinate coor_c(_ndimension);
|
||||||
|
|
||||||
Lexicographic::CoorFromIndex(coor_f,sf,fine_rdimensions);
|
Lexicographic::CoorFromIndex(coor_f,sf,fine_rdimensions);
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,fsimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_f[d] += fine_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
for(int d=0;d<_ndimension;d++) coor_b[d] = coor_f[d]%block_r[d];
|
for(int d=0;d<_ndimension;d++) coor_b[d] = coor_f[d]%block_l[d];
|
||||||
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_f[d]/block_r[d];
|
for(int d=0;d<_ndimension;d++) coor_c[d] = coor_f[d]/block_l[d];
|
||||||
|
|
||||||
int sc;
|
int sc;
|
||||||
int sb;
|
int sb;
|
||||||
Lexicographic::IndexFromCoor(coor_c,sc,coarse_rdimensions);
|
Lexicographic::IndexFromCoor(coor_c,sc,coarse_l);
|
||||||
Lexicographic::IndexFromCoor(coor_b,sb,block_r);
|
Lexicographic::IndexFromCoor(coor_b,sb,block_l);
|
||||||
|
|
||||||
// BLAS layout address calculation
|
// BLAS_F[coarse_vol][nvec][block_vol][words]
|
||||||
// words * block_vol * nbasis x coarse_vol
|
int64_t site = (sc*nvec + v)*bv
|
||||||
int64_t site = (lane*osites + sc*bv)*nvec
|
|
||||||
+ v*bv
|
|
||||||
+ sb;
|
+ sb;
|
||||||
|
|
||||||
scalar_object * ptr = (scalar_object *)&blasData_p[site*lwords];
|
scalar_object * ptr = (scalar_object *)&blasData_p[site*lwords];
|
||||||
@@ -306,6 +634,8 @@ public:
|
|||||||
uint64_t sz = blas.size();
|
uint64_t sz = blas.size();
|
||||||
|
|
||||||
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
||||||
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate csimd = coarse_simd;
|
||||||
|
|
||||||
for(int v=0;v<vecs.size();v++){
|
for(int v=0;v<vecs.size();v++){
|
||||||
|
|
||||||
@@ -330,7 +660,16 @@ public:
|
|||||||
for(int lane=0;lane<Nsimd;lane++) {
|
for(int lane=0;lane<Nsimd;lane++) {
|
||||||
#endif
|
#endif
|
||||||
// C_br per site
|
// C_br per site
|
||||||
int64_t blas_site = (lane*osites + sc)*nvec*cwords + v*cwords;
|
Coordinate coor_c(_ndimension);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
|
Lexicographic::CoorFromIndex(coor_c,sc,coarse_rdimensions);
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,csimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] += coarse_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
|
int scl;
|
||||||
|
Lexicographic::IndexFromCoor(coor_c,scl,coarse_l);
|
||||||
|
|
||||||
|
int64_t blas_site = (scl*nvec + v)*cwords;
|
||||||
|
|
||||||
coarse_scalar_object data = extractLane(lane,coarseData[sc]);
|
coarse_scalar_object data = extractLane(lane,coarseData[sc]);
|
||||||
|
|
||||||
@@ -360,6 +699,8 @@ public:
|
|||||||
uint64_t sz = blas.size();
|
uint64_t sz = blas.size();
|
||||||
|
|
||||||
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
Coordinate coarse_rdimensions = coarse_grid->_rdimensions;
|
||||||
|
Coordinate coarse_l = coarse_ldimensions;
|
||||||
|
Coordinate csimd = coarse_simd;
|
||||||
|
|
||||||
// std::cout << " export coarsee Blas norm "<<blasNorm2(blas)<<std::endl;
|
// std::cout << " export coarsee Blas norm "<<blasNorm2(blas)<<std::endl;
|
||||||
for(int v=0;v<vecs.size();v++){
|
for(int v=0;v<vecs.size();v++){
|
||||||
@@ -385,7 +726,16 @@ public:
|
|||||||
#else
|
#else
|
||||||
for(int lane=0;lane<Nsimd;lane++) {
|
for(int lane=0;lane<Nsimd;lane++) {
|
||||||
#endif
|
#endif
|
||||||
int64_t blas_site = (lane*osites + sc)*nvec*cwords + v*cwords;
|
Coordinate coor_c(_ndimension);
|
||||||
|
Coordinate coor_l(_ndimension);
|
||||||
|
Lexicographic::CoorFromIndex(coor_c,sc,coarse_rdimensions);
|
||||||
|
Lexicographic::CoorFromIndex(coor_l,lane,csimd);
|
||||||
|
for(int d=0;d<_ndimension;d++) coor_c[d] += coarse_rdimensions[d]*coor_l[d];
|
||||||
|
|
||||||
|
int scl;
|
||||||
|
Lexicographic::IndexFromCoor(coor_c,scl,coarse_l);
|
||||||
|
|
||||||
|
int64_t blas_site = (scl*nvec + v)*cwords;
|
||||||
coarse_scalar_object * ptr = (coarse_scalar_object *)&blasData_p[blas_site];
|
coarse_scalar_object * ptr = (coarse_scalar_object *)&blasData_p[blas_site];
|
||||||
coarse_scalar_object data = *ptr;
|
coarse_scalar_object data = *ptr;
|
||||||
insertLane(lane,coarseData[sc],data);
|
insertLane(lane,coarseData[sc],data);
|
||||||
@@ -508,6 +858,168 @@ public:
|
|||||||
ExportFineGridVectors(fine, BLAS_F);
|
ExportFineGridVectors(fine, BLAS_F);
|
||||||
// std::cout << " exported "<<std::endl;
|
// std::cout << " exported "<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// multiRHS ordered interfaces. The GEMM is identical; only the import and
|
||||||
|
// export differ, so those are the whole of the layout question.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class cobj>
|
||||||
|
void blockProject(Field &fine_mrhs,Lattice<cobj> &coarse_mrhs)
|
||||||
|
{
|
||||||
|
int nrhs = fine_mrhs.Grid()->_rdimensions[0];
|
||||||
|
int _nbasis = sizeof(typename cobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(nbasis==_nbasis);
|
||||||
|
GRID_ASSERT(coarse_mrhs.Grid()->_rdimensions[0]==nrhs);
|
||||||
|
|
||||||
|
BLAS_F.resize (fine_vol * words * nrhs );
|
||||||
|
BLAS_C.resize (coarse_vol * nbasis * nrhs );
|
||||||
|
|
||||||
|
ImportFineGridMrhsVectors(fine_mrhs,BLAS_F);
|
||||||
|
ProjectBLAS(nrhs);
|
||||||
|
ExportCoarseGridMrhsVectors(coarse_mrhs,BLAS_C);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class cobj>
|
||||||
|
void blockPromote(Field &fine_mrhs,Lattice<cobj> &coarse_mrhs)
|
||||||
|
{
|
||||||
|
int nrhs = fine_mrhs.Grid()->_rdimensions[0];
|
||||||
|
int _nbasis = sizeof(typename cobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(nbasis==_nbasis);
|
||||||
|
GRID_ASSERT(coarse_mrhs.Grid()->_rdimensions[0]==nrhs);
|
||||||
|
|
||||||
|
BLAS_F.resize (fine_vol * words * nrhs );
|
||||||
|
BLAS_C.resize (coarse_vol * nbasis * nrhs );
|
||||||
|
|
||||||
|
ImportCoarseGridMrhsVectors(coarse_mrhs,BLAS_C);
|
||||||
|
PromoteBLAS(nrhs);
|
||||||
|
ExportFineGridMrhsVectors(fine_mrhs,BLAS_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Mixed orderings. A single RHS fine operator produces a vector of fine
|
||||||
|
// fields with no packing; the coarse side is still wanted in mrhs order.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class cobj>
|
||||||
|
void blockProject(std::vector<Field> &fine,Lattice<cobj> &coarse_mrhs)
|
||||||
|
{
|
||||||
|
int nrhs = fine.size();
|
||||||
|
int _nbasis = sizeof(typename cobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(nbasis==_nbasis);
|
||||||
|
GRID_ASSERT(coarse_mrhs.Grid()->_rdimensions[0]==nrhs);
|
||||||
|
|
||||||
|
BLAS_F.resize (fine_vol * words * nrhs );
|
||||||
|
BLAS_C.resize (coarse_vol * nbasis * nrhs );
|
||||||
|
|
||||||
|
ImportFineGridVectors(fine,BLAS_F);
|
||||||
|
ProjectBLAS(nrhs);
|
||||||
|
ExportCoarseGridMrhsVectors(coarse_mrhs,BLAS_C);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class cobj>
|
||||||
|
void blockProject(Field &fine_mrhs,std::vector< Lattice<cobj> > &coarse)
|
||||||
|
{
|
||||||
|
int nrhs = fine_mrhs.Grid()->_rdimensions[0];
|
||||||
|
int _nbasis = sizeof(typename cobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(nbasis==_nbasis);
|
||||||
|
GRID_ASSERT(coarse.size()==nrhs);
|
||||||
|
|
||||||
|
BLAS_F.resize (fine_vol * words * nrhs );
|
||||||
|
BLAS_C.resize (coarse_vol * nbasis * nrhs );
|
||||||
|
|
||||||
|
ImportFineGridMrhsVectors(fine_mrhs,BLAS_F);
|
||||||
|
ProjectBLAS(nrhs);
|
||||||
|
ExportCoarseGridVectors(coarse,BLAS_C);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class cobj>
|
||||||
|
void blockPromote(std::vector<Field> &fine,Lattice<cobj> &coarse_mrhs)
|
||||||
|
{
|
||||||
|
int nrhs = fine.size();
|
||||||
|
int _nbasis = sizeof(typename cobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(nbasis==_nbasis);
|
||||||
|
GRID_ASSERT(coarse_mrhs.Grid()->_rdimensions[0]==nrhs);
|
||||||
|
|
||||||
|
BLAS_F.resize (fine_vol * words * nrhs );
|
||||||
|
BLAS_C.resize (coarse_vol * nbasis * nrhs );
|
||||||
|
|
||||||
|
ImportCoarseGridMrhsVectors(coarse_mrhs,BLAS_C);
|
||||||
|
PromoteBLAS(nrhs);
|
||||||
|
ExportFineGridVectors(fine,BLAS_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class cobj>
|
||||||
|
void blockPromote(Field &fine_mrhs,std::vector< Lattice<cobj> > &coarse)
|
||||||
|
{
|
||||||
|
int nrhs = fine_mrhs.Grid()->_rdimensions[0];
|
||||||
|
int _nbasis = sizeof(typename cobj::scalar_object)/sizeof(scalar);
|
||||||
|
GRID_ASSERT(nbasis==_nbasis);
|
||||||
|
GRID_ASSERT(coarse.size()==nrhs);
|
||||||
|
|
||||||
|
BLAS_F.resize (fine_vol * words * nrhs );
|
||||||
|
BLAS_C.resize (coarse_vol * nbasis * nrhs );
|
||||||
|
|
||||||
|
ImportCoarseGridVectors(coarse,BLAS_C);
|
||||||
|
PromoteBLAS(nrhs);
|
||||||
|
ExportFineGridMrhsVectors(fine_mrhs,BLAS_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pointer tables and the batched GEMM, shared by both orderings
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
void BLASPointers(int nrhs,
|
||||||
|
deviceVector<scalar *> &Vd,
|
||||||
|
deviceVector<scalar *> &Fd,
|
||||||
|
deviceVector<scalar *> &Cd)
|
||||||
|
{
|
||||||
|
for(int c=0;c<coarse_vol;c++){
|
||||||
|
scalar * Vh = & BLAS_V[c*nbasis*block_vol*words];
|
||||||
|
scalar * Fh = & BLAS_F[c*nrhs*block_vol*words];
|
||||||
|
scalar * Ch = & BLAS_C[c*nrhs*nbasis];
|
||||||
|
acceleratorPut(Vd[c],Vh);
|
||||||
|
acceleratorPut(Fd[c],Fh);
|
||||||
|
acceleratorPut(Cd[c],Ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// C_br = V^dag F
|
||||||
|
void ProjectBLAS(int nrhs)
|
||||||
|
{
|
||||||
|
deviceVector<scalar *> Vd(coarse_vol);
|
||||||
|
deviceVector<scalar *> Fd(coarse_vol);
|
||||||
|
deviceVector<scalar *> Cd(coarse_vol);
|
||||||
|
BLASPointers(nrhs,Vd,Fd,Cd);
|
||||||
|
|
||||||
|
GridBLAS BLAS;
|
||||||
|
int64_t vw = block_vol * words;
|
||||||
|
BLAS.gemmBatched(GridBLAS_OP_C,GridBLAS_OP_N,
|
||||||
|
nbasis,nrhs,vw,
|
||||||
|
scalar(1.0),
|
||||||
|
Vd,
|
||||||
|
Fd,
|
||||||
|
scalar(0.0), // wipe out C
|
||||||
|
Cd);
|
||||||
|
BLAS.synchronise();
|
||||||
|
}
|
||||||
|
|
||||||
|
// F_xr = Vxb Cbr
|
||||||
|
void PromoteBLAS(int nrhs)
|
||||||
|
{
|
||||||
|
deviceVector<scalar *> Vd(coarse_vol);
|
||||||
|
deviceVector<scalar *> Fd(coarse_vol);
|
||||||
|
deviceVector<scalar *> Cd(coarse_vol);
|
||||||
|
BLASPointers(nrhs,Vd,Fd,Cd);
|
||||||
|
|
||||||
|
GridBLAS BLAS;
|
||||||
|
int64_t vw = block_vol * words;
|
||||||
|
BLAS.gemmBatched(GridBLAS_OP_N,GridBLAS_OP_N,
|
||||||
|
vw,nrhs,nbasis,
|
||||||
|
scalar(1.0),
|
||||||
|
Vd,
|
||||||
|
Cd,
|
||||||
|
scalar(0.0), // wipe out F
|
||||||
|
Fd);
|
||||||
|
BLAS.synchronise();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -54,6 +54,21 @@ class TwoLevelCG : public LinearFunction<Field>
|
|||||||
LinearOperatorBase<Field> &_FineLinop;
|
LinearOperatorBase<Field> &_FineLinop;
|
||||||
LinearFunction<Field> &_Smoother;
|
LinearFunction<Field> &_Smoother;
|
||||||
|
|
||||||
|
GridStopWatch ProjectTimer;
|
||||||
|
GridStopWatch PromoteTimer;
|
||||||
|
GridStopWatch CoarseTimer;
|
||||||
|
GridStopWatch SmoothTimer;
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch M3Timer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
|
||||||
|
int64_t M3Calls;
|
||||||
|
int64_t SmoothCalls;
|
||||||
|
int64_t MatrixCalls;
|
||||||
|
int64_t ProjectCalls;
|
||||||
|
int64_t CoarseCalls;
|
||||||
|
int64_t PromoteCalls;
|
||||||
|
|
||||||
// more most opertor functions
|
// more most opertor functions
|
||||||
TwoLevelCG(RealD tol,
|
TwoLevelCG(RealD tol,
|
||||||
Integer maxit,
|
Integer maxit,
|
||||||
@@ -103,6 +118,14 @@ class TwoLevelCG : public LinearFunction<Field>
|
|||||||
RealD tn;
|
RealD tn;
|
||||||
|
|
||||||
GridStopWatch HDCGTimer;
|
GridStopWatch HDCGTimer;
|
||||||
|
ProjectTimer.Reset();
|
||||||
|
PromoteTimer.Reset();
|
||||||
|
CoarseTimer.Reset();
|
||||||
|
SmoothTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
M3Timer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
M3Calls = SmoothCalls = MatrixCalls = ProjectCalls = CoarseCalls = PromoteCalls = 0;
|
||||||
HDCGTimer.Start();
|
HDCGTimer.Start();
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
// x0 = Vstart -- possibly modify guess
|
// x0 = Vstart -- possibly modify guess
|
||||||
@@ -145,14 +168,19 @@ class TwoLevelCG : public LinearFunction<Field>
|
|||||||
int peri_kp = (k+1) % mmax;
|
int peri_kp = (k+1) % mmax;
|
||||||
|
|
||||||
rtz=rtzp;
|
rtz=rtzp;
|
||||||
|
M3Timer.Start();
|
||||||
d= PcgM3(p[peri_k],mmp[peri_k]);
|
d= PcgM3(p[peri_k],mmp[peri_k]);
|
||||||
|
M3Timer.Stop();
|
||||||
|
M3Calls++;
|
||||||
a = rtz/d;
|
a = rtz/d;
|
||||||
|
|
||||||
// Memorise this
|
// Memorise this
|
||||||
pAp[peri_k] = d;
|
pAp[peri_k] = d;
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
axpy(x,a,p[peri_k],x);
|
axpy(x,a,p[peri_k],x);
|
||||||
RealD rn = axpy_norm(r,-a,mmp[peri_k],r);
|
RealD rn = axpy_norm(r,-a,mmp[peri_k],r);
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
// Compute z = M x
|
// Compute z = M x
|
||||||
PcgM1(r,z);
|
PcgM1(r,z);
|
||||||
@@ -163,7 +191,9 @@ class TwoLevelCG : public LinearFunction<Field>
|
|||||||
n2=norm2(z);
|
n2=norm2(z);
|
||||||
std::cout << GridLogMessage<<"HDCG::fPcg iteration "<<k<<" : vector r,z "<<n1<<" "<<n2<<"\n";
|
std::cout << GridLogMessage<<"HDCG::fPcg iteration "<<k<<" : vector r,z "<<n1<<" "<<n2<<"\n";
|
||||||
}
|
}
|
||||||
|
LinalgTimer.Start();
|
||||||
rtzp =real(innerProduct(r,z));
|
rtzp =real(innerProduct(r,z));
|
||||||
|
LinalgTimer.Stop();
|
||||||
std::cout << GridLogMessage<<"HDCG::fPcg iteration "<<k<<" : inner rtzp "<<rtzp<<"\n";
|
std::cout << GridLogMessage<<"HDCG::fPcg iteration "<<k<<" : inner rtzp "<<rtzp<<"\n";
|
||||||
|
|
||||||
// PcgM2(z,p[0]);
|
// PcgM2(z,p[0]);
|
||||||
@@ -202,7 +232,24 @@ class TwoLevelCG : public LinearFunction<Field>
|
|||||||
if ( rn <= rsq ) {
|
if ( rn <= rsq ) {
|
||||||
|
|
||||||
HDCGTimer.Stop();
|
HDCGTimer.Stop();
|
||||||
std::cout<<GridLogMessage<<"HDCG: fPcg converged in "<<k<<" iterations and "<<HDCGTimer.Elapsed()<<std::endl;;
|
std::cout<<GridLogMessage<<"HDCG: fPcg converged in "<<k<<" iterations and "<<HDCGTimer.Elapsed()<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg breakdown"<<std::endl;
|
||||||
|
auto mspc = [](GridStopWatch &sw, int64_t n) -> double {
|
||||||
|
return (n > 0) ? sw.useconds() * 1e-3 / n : 0.0;
|
||||||
|
};
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg M3 (fine MVM) "<<M3Timer.Elapsed()
|
||||||
|
<<" "<<M3Calls<<" calls "<<mspc(M3Timer,M3Calls)<<" ms/call"<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg linalg "<<LinalgTimer.Elapsed()<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg smoother "<<SmoothTimer.Elapsed()
|
||||||
|
<<" "<<SmoothCalls<<" calls "<<mspc(SmoothTimer,SmoothCalls)<<" ms/call"<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg matrix (in M1) "<<MatrixTimer.Elapsed()
|
||||||
|
<<" "<<MatrixCalls<<" calls "<<mspc(MatrixTimer,MatrixCalls)<<" ms/call"<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg project "<<ProjectTimer.Elapsed()
|
||||||
|
<<" "<<ProjectCalls<<" calls "<<mspc(ProjectTimer,ProjectCalls)<<" ms/call"<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg coarse "<<CoarseTimer.Elapsed()
|
||||||
|
<<" "<<CoarseCalls<<" calls "<<mspc(CoarseTimer,CoarseCalls)<<" ms/call"<<std::endl;
|
||||||
|
std::cout<<GridLogMessage<<"HDCG: fPcg promote "<<PromoteTimer.Elapsed()
|
||||||
|
<<" "<<PromoteCalls<<" calls "<<mspc(PromoteTimer,PromoteCalls)<<" ms/call"<<std::endl;
|
||||||
|
|
||||||
_FineLinop.HermOp(x,mmp[0]);
|
_FineLinop.HermOp(x,mmp[0]);
|
||||||
axpy(tmp,-1.0,src,mmp[0]);
|
axpy(tmp,-1.0,src,mmp[0]);
|
||||||
@@ -475,35 +522,29 @@ class TwoLevelADEF2 : public TwoLevelCG<Field>
|
|||||||
CoarseField PleftProj(this->coarsegrid);
|
CoarseField PleftProj(this->coarsegrid);
|
||||||
CoarseField PleftMss_proj(this->coarsegrid);
|
CoarseField PleftMss_proj(this->coarsegrid);
|
||||||
|
|
||||||
GridStopWatch SmootherTimer;
|
this->SmoothTimer.Start();
|
||||||
GridStopWatch MatrixTimer;
|
|
||||||
SmootherTimer.Start();
|
|
||||||
this->_Smoother(in,Min);
|
this->_Smoother(in,Min);
|
||||||
SmootherTimer.Stop();
|
this->SmoothTimer.Stop();
|
||||||
|
this->SmoothCalls++;
|
||||||
|
|
||||||
MatrixTimer.Start();
|
this->MatrixTimer.Start();
|
||||||
this->_FineLinop.HermOp(Min,out);
|
this->_FineLinop.HermOp(Min,out);
|
||||||
MatrixTimer.Stop();
|
this->MatrixTimer.Stop();
|
||||||
|
this->MatrixCalls++;
|
||||||
axpy(tmp,-1.0,out,in); // tmp = in - A Min
|
axpy(tmp,-1.0,out,in); // tmp = in - A Min
|
||||||
|
|
||||||
GridStopWatch ProjTimer;
|
this->ProjectTimer.Start();
|
||||||
GridStopWatch CoarseTimer;
|
|
||||||
GridStopWatch PromTimer;
|
|
||||||
ProjTimer.Start();
|
|
||||||
this->_Aggregates.ProjectToSubspace(PleftProj,tmp);
|
this->_Aggregates.ProjectToSubspace(PleftProj,tmp);
|
||||||
ProjTimer.Stop();
|
this->ProjectTimer.Stop();
|
||||||
CoarseTimer.Start();
|
this->ProjectCalls++;
|
||||||
|
this->CoarseTimer.Start();
|
||||||
this->_CoarseSolver(PleftProj,PleftMss_proj); // Ass^{-1} [in - A Min]_s
|
this->_CoarseSolver(PleftProj,PleftMss_proj); // Ass^{-1} [in - A Min]_s
|
||||||
CoarseTimer.Stop();
|
this->CoarseTimer.Stop();
|
||||||
PromTimer.Start();
|
this->CoarseCalls++;
|
||||||
|
this->PromoteTimer.Start();
|
||||||
this->_Aggregates.PromoteFromSubspace(PleftMss_proj,tmp);// tmp = Q[in - A Min]
|
this->_Aggregates.PromoteFromSubspace(PleftMss_proj,tmp);// tmp = Q[in - A Min]
|
||||||
PromTimer.Stop();
|
this->PromoteTimer.Stop();
|
||||||
std::cout << GridLogPerformance << "PcgM1 breakdown "<<std::endl;
|
this->PromoteCalls++;
|
||||||
std::cout << GridLogPerformance << "\tSmoother " << SmootherTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogPerformance << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogPerformance << "\tProj " << ProjTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogPerformance << "\tCoarse " << CoarseTimer.Elapsed() <<std::endl;
|
|
||||||
std::cout << GridLogPerformance << "\tProm " << PromTimer.Elapsed() <<std::endl;
|
|
||||||
|
|
||||||
axpy(out,1.0,Min,tmp); // Min+tmp
|
axpy(out,1.0,Min,tmp); // Min+tmp
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,13 +212,17 @@ public:
|
|||||||
<< "\tTarget " << Tolerance << std::endl;
|
<< "\tTarget " << Tolerance << std::endl;
|
||||||
|
|
||||||
// std::cout << GridLogMessage << "\tPreamble " << PreambleTimer.Elapsed() <<std::endl;
|
// std::cout << GridLogMessage << "\tPreamble " << PreambleTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogMessage << "\tSolver Elapsed " << SolverTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tPreamble " << PreambleTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogPerformance << "Time breakdown "<<std::endl;
|
std::cout << GridLogMessage << "\tConstruct " << ConstructTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogPerformance << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tNorm " << NormTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogPerformance << "\tLinalg " << LinalgTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tAssign " << AssignTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogPerformance << "\t\tInner " << InnerTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tSolver " << SolverTimer.Elapsed() <<std::endl;
|
||||||
std::cout << GridLogPerformance << "\t\tAxpyNorm " << AxpyNormTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "Solver breakdown "<<std::endl;
|
||||||
std::cout << GridLogPerformance << "\t\tLinearComb " << LinearCombTimer.Elapsed() <<std::endl;
|
std::cout << GridLogMessage << "\tMatrix " << MatrixTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\tLinalg " << LinalgTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\t\tInner " << InnerTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\t\tAxpyNorm " << AxpyNormTimer.Elapsed() <<std::endl;
|
||||||
|
std::cout << GridLogMessage << "\t\tLinearComb " << LinearCombTimer.Elapsed() <<std::endl;
|
||||||
|
|
||||||
std::cout << GridLogDebug << "\tMobius flop rate " << DwfFlops/ usecs<< " Gflops " <<std::endl;
|
std::cout << GridLogDebug << "\tMobius flop rate " << DwfFlops/ usecs<< " Gflops " <<std::endl;
|
||||||
|
|
||||||
|
|||||||
@@ -236,4 +236,5 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
#undef GCRLogLevel
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -38,13 +38,14 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
#define GCRLogLevel std::cout << GridLogMessage <<std::string(level,'\t')<< " Level "<<level<<" "
|
#define GCRLogLevel std::cout << GridLogMessage <<std::string(level,'\t')<< name<<" "
|
||||||
|
|
||||||
template<class Field>
|
template<class Field>
|
||||||
class PrecGeneralisedConjugateResidualNonHermitian : public LinearFunction<Field> {
|
class PrecGeneralisedConjugateResidualNonHermitian : public LinearFunction<Field> {
|
||||||
public:
|
public:
|
||||||
using LinearFunction<Field>::operator();
|
using LinearFunction<Field>::operator();
|
||||||
RealD Tolerance;
|
RealD Tolerance;
|
||||||
|
RealD SSQ;
|
||||||
Integer MaxIterations;
|
Integer MaxIterations;
|
||||||
int verbose;
|
int verbose;
|
||||||
int mmax;
|
int mmax;
|
||||||
@@ -54,11 +55,18 @@ public:
|
|||||||
GridStopWatch PrecTimer;
|
GridStopWatch PrecTimer;
|
||||||
GridStopWatch MatTimer;
|
GridStopWatch MatTimer;
|
||||||
GridStopWatch LinalgTimer;
|
GridStopWatch LinalgTimer;
|
||||||
|
std::string name;
|
||||||
|
int ZeroGuess = 0; // caller contract: guess is always zero => first-cycle r0 = src, skip the apply
|
||||||
|
int FirstCycle = 0;
|
||||||
|
|
||||||
LinearFunction<Field> &Preconditioner;
|
LinearFunction<Field> &Preconditioner;
|
||||||
LinearOperatorBase<Field> &Linop;
|
LinearOperatorBase<Field> &Linop;
|
||||||
|
|
||||||
void Level(int lv) { level=lv; };
|
void Name(std::string _name) { name = _name; };
|
||||||
|
|
||||||
|
void Level(int n) { Name("Level " + std::to_string(n)); level = n; }
|
||||||
|
|
||||||
|
void SetZeroGuess(int z) { ZeroGuess = z; };
|
||||||
|
|
||||||
PrecGeneralisedConjugateResidualNonHermitian(RealD tol,Integer maxit,LinearOperatorBase<Field> &_Linop,LinearFunction<Field> &Prec,int _mmax,int _nstep) :
|
PrecGeneralisedConjugateResidualNonHermitian(RealD tol,Integer maxit,LinearOperatorBase<Field> &_Linop,LinearFunction<Field> &Prec,int _mmax,int _nstep) :
|
||||||
Tolerance(tol),
|
Tolerance(tol),
|
||||||
@@ -68,7 +76,7 @@ public:
|
|||||||
mmax(_mmax),
|
mmax(_mmax),
|
||||||
nstep(_nstep)
|
nstep(_nstep)
|
||||||
{
|
{
|
||||||
level=1;
|
Level(1);
|
||||||
verbose=1;
|
verbose=1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,6 +85,7 @@ public:
|
|||||||
// psi=Zero();
|
// psi=Zero();
|
||||||
RealD cp, ssq,rsq;
|
RealD cp, ssq,rsq;
|
||||||
ssq=norm2(src);
|
ssq=norm2(src);
|
||||||
|
SSQ=ssq;
|
||||||
rsq=Tolerance*Tolerance*ssq;
|
rsq=Tolerance*Tolerance*ssq;
|
||||||
|
|
||||||
Field r(src.Grid());
|
Field r(src.Grid());
|
||||||
@@ -89,11 +98,12 @@ public:
|
|||||||
SolverTimer.Start();
|
SolverTimer.Start();
|
||||||
|
|
||||||
steps=0;
|
steps=0;
|
||||||
|
FirstCycle=1;
|
||||||
for(int k=0;k<MaxIterations;k++){
|
for(int k=0;k<MaxIterations;k++){
|
||||||
|
|
||||||
cp=GCRnStep(src,psi,rsq);
|
cp=GCRnStep(src,psi,rsq);
|
||||||
|
|
||||||
GCRLogLevel <<"PGCR("<<mmax<<","<<nstep<<") "<< steps <<" steps cp = "<<cp<<" target "<<rsq <<std::endl;
|
GCRLogLevel <<"PGCR("<<mmax<<","<<nstep<<") "<< steps <<" steps cp = "<<sqrt(cp/ssq)<<" target "<<sqrt(rsq/ssq) <<std::endl;
|
||||||
|
|
||||||
if(cp<rsq) {
|
if(cp<rsq) {
|
||||||
|
|
||||||
@@ -142,20 +152,24 @@ public:
|
|||||||
GCRLogLevel<< "PGCR nStep("<<nstep<<")"<<std::endl;
|
GCRLogLevel<< "PGCR nStep("<<nstep<<")"<<std::endl;
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// initial guess x0 is taken as nonzero.
|
// r0 = src - A x0. ZeroGuess: on the first cycle x0==0 by caller
|
||||||
// r0=src-A x0 = src
|
// contract (enforced here), so r0 = src exactly; skip the apply.
|
||||||
|
// Restart cycles (psi!=0) always do the full computation.
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
if (ZeroGuess && FirstCycle) {
|
||||||
|
psi = Zero();
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
} else {
|
||||||
MatTimer.Start();
|
MatTimer.Start();
|
||||||
Linop.Op(psi,Az);
|
Linop.Op(psi,Az);
|
||||||
// zAz = innerProduct(Az,psi);
|
|
||||||
zAAz= norm2(Az);
|
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
|
||||||
LinalgTimer.Start();
|
LinalgTimer.Start();
|
||||||
r=src-Az;
|
r=src-Az;
|
||||||
LinalgTimer.Stop();
|
LinalgTimer.Stop();
|
||||||
GCRLogLevel<< "PGCR true residual r = src - A psi "<<norm2(r) <<std::endl;
|
}
|
||||||
|
FirstCycle=0;
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// p = Prec(r)
|
// p = Prec(r)
|
||||||
@@ -181,6 +195,7 @@ public:
|
|||||||
|
|
||||||
cp =norm2(r);
|
cp =norm2(r);
|
||||||
LinalgTimer.Stop();
|
LinalgTimer.Stop();
|
||||||
|
GCRLogLevel<< "PGCR true residual "<< sqrt(cp/SSQ) <<std::endl;
|
||||||
|
|
||||||
for(int k=0;k<nstep;k++){
|
for(int k=0;k<nstep;k++){
|
||||||
|
|
||||||
@@ -199,13 +214,12 @@ public:
|
|||||||
cp = axpy_norm(r,-a,q[peri_k],r);
|
cp = axpy_norm(r,-a,q[peri_k],r);
|
||||||
LinalgTimer.Stop();
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
GCRLogLevel<< "PGCR step["<<steps<<"] resid " << cp << " target " <<rsq<<std::endl;
|
GCRLogLevel<< "PGCR step["<<steps<<"] resid " << sqrt(cp/SSQ)<<std::endl;
|
||||||
|
|
||||||
if((k==nstep-1)||(cp<rsq)){
|
if((k==nstep-1)||(cp<rsq)){
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PrecTimer.Start();
|
PrecTimer.Start();
|
||||||
Preconditioner(r,z);// solve Az = r
|
Preconditioner(r,z);// solve Az = r
|
||||||
PrecTimer.Stop();
|
PrecTimer.Stop();
|
||||||
@@ -239,4 +253,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
#undef GCRLogLevel
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -66,7 +66,21 @@ public:
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void GlobalOrthonormalise(void)
|
||||||
|
{
|
||||||
|
// Normalise all vectors
|
||||||
|
for(int i=0;i<nbasis; i++){
|
||||||
|
RealD scale = std::pow(norm2(subspace[i]),-0.5);
|
||||||
|
subspace[i] = subspace[i]*scale;
|
||||||
|
}
|
||||||
|
for(int i=0;i<nbasis; i++){
|
||||||
|
for(int j=0;j<i; j++){
|
||||||
|
basisOrthogonalize(subspace,subspace[i],j);
|
||||||
|
}
|
||||||
|
RealD scale = std::pow(norm2(subspace[i]),-0.5);
|
||||||
|
subspace[i] = subspace[i]*scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
void Orthogonalise(void){
|
void Orthogonalise(void){
|
||||||
CoarseScalar InnerProd(CoarseGrid);
|
CoarseScalar InnerProd(CoarseGrid);
|
||||||
// std::cout << GridLogMessage <<" Block Gramm-Schmidt pass 1"<<std::endl;
|
// std::cout << GridLogMessage <<" Block Gramm-Schmidt pass 1"<<std::endl;
|
||||||
@@ -110,7 +124,7 @@ public:
|
|||||||
|
|
||||||
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "noise ["<<b<<"] <n|MdagM|n> "<<norm2(Mn)<<std::endl;
|
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "noise ["<<b<<"] <n|MdagM|n> "<<norm2(Mn)<<std::endl;
|
||||||
|
|
||||||
for(int i=0;i<4;i++){
|
for(int i=0;i<2;i++){
|
||||||
|
|
||||||
CG(hermop,noise,subspace[b]);
|
CG(hermop,noise,subspace[b]);
|
||||||
|
|
||||||
@@ -118,6 +132,8 @@ public:
|
|||||||
scale = std::pow(norm2(noise),-0.5);
|
scale = std::pow(norm2(noise),-0.5);
|
||||||
noise=noise*scale;
|
noise=noise*scale;
|
||||||
|
|
||||||
|
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "intermediate["<<i<<"] <i|MdagM|i> "<<norm2(Mn)<<std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "filtered["<<b<<"] <f|MdagM|f> "<<norm2(Mn)<<std::endl;
|
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "filtered["<<b<<"] <f|MdagM|f> "<<norm2(Mn)<<std::endl;
|
||||||
@@ -134,7 +150,8 @@ public:
|
|||||||
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,10,DiracOp,simple_fine,30,30);
|
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,10,DiracOp,simple_fine,30,30);
|
||||||
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,10,DiracOp,simple_fine,12,12);
|
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,10,DiracOp,simple_fine,12,12);
|
||||||
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,30,DiracOp,simple_fine,12,12);
|
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,30,DiracOp,simple_fine,12,12);
|
||||||
PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.001,30,DiracOp,simple_fine,10,10);
|
// PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.0005,30,DiracOp,simple_fine,20,20);
|
||||||
|
PrecGeneralisedConjugateResidualNonHermitian<FineField> GCR(0.0005,30,DiracOp,simple_fine,10,10);
|
||||||
FineField noise(FineGrid);
|
FineField noise(FineGrid);
|
||||||
FineField src(FineGrid);
|
FineField src(FineGrid);
|
||||||
FineField guess(FineGrid);
|
FineField guess(FineGrid);
|
||||||
@@ -168,12 +185,15 @@ public:
|
|||||||
scale = std::pow(norm2(noise),-0.5);
|
scale = std::pow(norm2(noise),-0.5);
|
||||||
noise=noise*scale;
|
noise=noise*scale;
|
||||||
|
|
||||||
|
DiracOp.Op(noise,Mn); std::cout<<GridLogMessage << "intermediate["<<i<<"] <f|Op|f> "<<innerProduct(noise,Mn)<<" <f|OpDagOp|f>"<<norm2(Mn)<<std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DiracOp.Op(noise,Mn); std::cout<<GridLogMessage << "filtered["<<b<<"] <f|Op|f> "<<innerProduct(noise,Mn)<<" <f|OpDagOp|f>"<<norm2(Mn)<<std::endl;
|
DiracOp.Op(noise,Mn); std::cout<<GridLogMessage << "filtered["<<b<<"] <f|Op|f> "<<innerProduct(noise,Mn)<<" <f|OpDagOp|f>"<<norm2(Mn)<<std::endl;
|
||||||
subspace[b] = noise;
|
subspace[b] = noise;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
GlobalOrthonormalise();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@ Author: Peter Boyle <pboyle@bnl.gov>
|
|||||||
|
|
||||||
#include <Grid/lattice/PaddedCell.h>
|
#include <Grid/lattice/PaddedCell.h>
|
||||||
#include <Grid/stencil/GeneralLocalStencil.h>
|
#include <Grid/stencil/GeneralLocalStencil.h>
|
||||||
|
#include <Grid/algorithms/deflation/MultiRHSBlockProject.h>
|
||||||
|
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
@@ -66,6 +67,10 @@ public:
|
|||||||
std::vector<CoarseMatrix> _Adag;
|
std::vector<CoarseMatrix> _Adag;
|
||||||
std::vector<CoarseVector> MultTemporaries;
|
std::vector<CoarseVector> MultTemporaries;
|
||||||
|
|
||||||
|
int64_t MultCalls;
|
||||||
|
double MultFlopsAccum;
|
||||||
|
double MultUsecAccum;
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
// Interface
|
// Interface
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@@ -104,19 +109,20 @@ public:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GeneralCoarsenedMatrix(NonLocalStencilGeometry &_geom,GridBase *FineGrid, GridCartesian * CoarseGrid)
|
GeneralCoarsenedMatrix(NonLocalStencilGeometry &_geom,GridBase *FineGrid, GridCartesian * CoarseGrid,int _herm=1)
|
||||||
: geom(_geom),
|
: geom(_geom),
|
||||||
_FineGrid(FineGrid),
|
_FineGrid(FineGrid),
|
||||||
_CoarseGrid(CoarseGrid),
|
_CoarseGrid(CoarseGrid),
|
||||||
hermitian(1),
|
hermitian(_herm),
|
||||||
Cell(_geom.Depth(),_CoarseGrid),
|
Cell(_geom.Depth(),_CoarseGrid),
|
||||||
Stencil(Cell.grids.back(),geom.shifts)
|
Stencil(Cell.grids.back(),geom.shifts),
|
||||||
|
MultCalls(0), MultFlopsAccum(0.0), MultUsecAccum(0.0)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
int npoint = _geom.npoint;
|
int npoint = _geom.npoint;
|
||||||
}
|
}
|
||||||
_A.resize(geom.npoint,CoarseGrid);
|
_A.resize(geom.npoint,CoarseGrid);
|
||||||
// _Adag.resize(geom.npoint,CoarseGrid);
|
if ( !hermitian ) _Adag.resize(geom.npoint,CoarseGrid);
|
||||||
}
|
}
|
||||||
void M (const CoarseVector &in, CoarseVector &out)
|
void M (const CoarseVector &in, CoarseVector &out)
|
||||||
{
|
{
|
||||||
@@ -124,10 +130,10 @@ public:
|
|||||||
}
|
}
|
||||||
void Mdag (const CoarseVector &in, CoarseVector &out)
|
void Mdag (const CoarseVector &in, CoarseVector &out)
|
||||||
{
|
{
|
||||||
GRID_ASSERT(hermitian);
|
if(hermitian)
|
||||||
Mult(_A,in,out);
|
Mult(_A,in,out);
|
||||||
// if ( hermitian ) M(in,out);
|
else
|
||||||
// else Mult(_Adag,in,out);
|
Mult(_Adag,in,out);
|
||||||
}
|
}
|
||||||
void Mult (std::vector<CoarseMatrix> &A,const CoarseVector &in, CoarseVector &out)
|
void Mult (std::vector<CoarseMatrix> &A,const CoarseVector &in, CoarseVector &out)
|
||||||
{
|
{
|
||||||
@@ -227,25 +233,24 @@ public:
|
|||||||
text+=usecond();
|
text+=usecond();
|
||||||
ttot+=usecond();
|
ttot+=usecond();
|
||||||
|
|
||||||
std::cout << GridLogPerformance<<"Coarse 1rhs Mult Aviews "<<tviews<<" us"<<std::endl;
|
MultCalls++;
|
||||||
std::cout << GridLogPerformance<<"Coarse Mult exch "<<texch<<" us"<<std::endl;
|
MultFlopsAccum += flops;
|
||||||
std::cout << GridLogPerformance<<"Coarse Mult mult "<<tmult<<" us"<<std::endl;
|
MultUsecAccum += ttot;
|
||||||
std::cout << GridLogPerformance<<" of which mult2 "<<tmult2<<" us"<<std::endl;
|
std::cout << GridLogPerformance
|
||||||
std::cout << GridLogPerformance<<"Coarse Mult ext "<<text<<" us"<<std::endl;
|
<< "Coarse Mult call " << MultCalls
|
||||||
std::cout << GridLogPerformance<<"Coarse Mult temps "<<ttemps<<" us"<<std::endl;
|
<< " tot " << ttot << " us"
|
||||||
std::cout << GridLogPerformance<<"Coarse Mult copy "<<tcopy<<" us"<<std::endl;
|
<< " kernel " << tmult << " us"
|
||||||
std::cout << GridLogPerformance<<"Coarse Mult tot "<<ttot<<" us"<<std::endl;
|
<< " kernel " << flops/tmult*1e-3 << " GFlop/s"
|
||||||
// std::cout << GridLogPerformance<<std::endl;
|
<< " overall " << MultFlopsAccum/MultUsecAccum*1e-3 << " GFlop/s (cumul)"
|
||||||
std::cout << GridLogPerformance<<"Coarse Kernel flops "<< flops<<std::endl;
|
<< " bw " << bytes/tmult*1e-3 << " GB/s"
|
||||||
std::cout << GridLogPerformance<<"Coarse Kernel flop/s "<< flops/tmult<<" mflop/s"<<std::endl;
|
<< std::endl;
|
||||||
std::cout << GridLogPerformance<<"Coarse Kernel bytes/s "<< bytes/tmult<<" MB/s"<<std::endl;
|
|
||||||
std::cout << GridLogPerformance<<"Coarse overall flops/s "<< flops/ttot<<" mflop/s"<<std::endl;
|
|
||||||
std::cout << GridLogPerformance<<"Coarse total bytes "<< bytes/1e6<<" MB"<<std::endl;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void PopulateAdag(void)
|
void PopulateAdag(void)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
// Serial global peek/poke reference implementation
|
||||||
for(int64_t bidx=0;bidx<CoarseGrid()->gSites() ;bidx++){
|
for(int64_t bidx=0;bidx<CoarseGrid()->gSites() ;bidx++){
|
||||||
Coordinate bcoor;
|
Coordinate bcoor;
|
||||||
CoarseGrid()->GlobalIndexToGlobalCoor(bidx,bcoor);
|
CoarseGrid()->GlobalIndexToGlobalCoor(bidx,bcoor);
|
||||||
@@ -262,6 +267,36 @@ public:
|
|||||||
pokeSite(adj(link),_Adag[pp],bcoor);
|
pokeSite(adj(link),_Adag[pp],bcoor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// Parallel: _Adag[pp](x) = adj( _A[p](x + s_pp) ), pp = Reverse(p), s_pp = -s_p.
|
||||||
|
// The neighbour fetch reuses the same padded-cell + stencil machinery as Mult,
|
||||||
|
// reading one matrix element per coalesced access so no whole site matrix
|
||||||
|
// (230KB at nbasis=60) ever lands on a GPU thread stack (HIP limit 128KB).
|
||||||
|
// Halo sites compute garbage neighbours; Cell.Extract discards them.
|
||||||
|
// Must run on the unpadded _A, i.e. before ExchangeCoarseLinks.
|
||||||
|
const int Nsimd = CComplex::Nsimd();
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
int pp = geom.Reverse(p);
|
||||||
|
CoarseMatrix Apad = Cell.ExchangePeriodic(_A[p]);
|
||||||
|
CoarseMatrix Dpad(Apad.Grid());
|
||||||
|
int64_t osites = Apad.Grid()->oSites();
|
||||||
|
{
|
||||||
|
autoView( Apad_v , Apad, AcceleratorRead);
|
||||||
|
autoView( Dpad_v , Dpad, AcceleratorWriteDiscard);
|
||||||
|
autoView( Stencil_v, Stencil, AcceleratorRead);
|
||||||
|
accelerator_for(sj, osites*nbasis, Nsimd, {
|
||||||
|
int32_t ss = sj/nbasis;
|
||||||
|
int32_t j = sj%nbasis;
|
||||||
|
auto SE = Stencil_v.GetEntry(pp,ss);
|
||||||
|
for(int i=0;i<nbasis;i++){
|
||||||
|
auto z = coalescedReadGeneralPermute(Apad_v[SE->_offset](i,j),SE->_permute,Nd);
|
||||||
|
coalescedWrite(Dpad_v[ss](j,i),conjugate(z));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_Adag[pp] = Cell.Extract(Dpad);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -417,10 +452,19 @@ public:
|
|||||||
int osites=CoarseGrid()->oSites();
|
int osites=CoarseGrid()->oSites();
|
||||||
autoView( A_v , _A[k], AcceleratorWrite);
|
autoView( A_v , _A[k], AcceleratorWrite);
|
||||||
autoView( FT_v , FT[k], AcceleratorRead);
|
autoView( FT_v , FT[k], AcceleratorRead);
|
||||||
accelerator_for(sss, osites, 1, {
|
accelerator_for(sss, osites, nbasis, {
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
int j = acceleratorSIMTlane(nbasis);
|
||||||
|
A_v[sss](i,j) = FT_v[sss](j);
|
||||||
|
#else
|
||||||
|
// CPU build: acceleratorSIMTlane()==0 -- an un-looped SIMT tensor
|
||||||
|
// index writes ONLY j=0 and silently drops the other nbasis-1
|
||||||
|
// columns (caught by Test_schur_dense_coarse import certificate,
|
||||||
|
// 2026-08-14). Loop explicitly.
|
||||||
for(int j=0;j<nbasis;j++){
|
for(int j=0;j<nbasis;j++){
|
||||||
A_v[sss](i,j) = FT_v[sss](j);
|
A_v[sss](i,j) = FT_v[sss](j);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tinv+=usecond();
|
tinv+=usecond();
|
||||||
@@ -428,8 +472,8 @@ public:
|
|||||||
|
|
||||||
// Only needed if nonhermitian
|
// Only needed if nonhermitian
|
||||||
if ( ! hermitian ) {
|
if ( ! hermitian ) {
|
||||||
// std::cout << GridLogMessage<<"PopulateAdag "<<std::endl;
|
std::cout << GridLogMessage<<"PopulateAdag "<<std::endl;
|
||||||
// PopulateAdag();
|
PopulateAdag();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to write something to populate Adag from A
|
// Need to write something to populate Adag from A
|
||||||
@@ -517,13 +561,9 @@ public:
|
|||||||
// Now compute the matrix elements of linop between the orthonormal
|
// Now compute the matrix elements of linop between the orthonormal
|
||||||
// set of vectors.
|
// set of vectors.
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
FineField phaV(grid); // Phased block basis vector
|
|
||||||
FineField MphaV(grid);// Matrix applied
|
|
||||||
std::vector<FineComplexField> phaF(npoint,grid);
|
std::vector<FineComplexField> phaF(npoint,grid);
|
||||||
std::vector<CoarseComplexField> pha(npoint,CoarseGrid());
|
std::vector<CoarseComplexField> pha(npoint,CoarseGrid());
|
||||||
|
|
||||||
CoarseVector coarseInner(CoarseGrid());
|
|
||||||
|
|
||||||
typedef typename CComplex::scalar_type SComplex;
|
typedef typename CComplex::scalar_type SComplex;
|
||||||
FineComplexField one(grid); one=SComplex(1.0);
|
FineComplexField one(grid); one=SComplex(1.0);
|
||||||
FineComplexField zz(grid); zz = Zero();
|
FineComplexField zz(grid); zz = Zero();
|
||||||
@@ -546,33 +586,48 @@ public:
|
|||||||
}
|
}
|
||||||
tphase+=usecond();
|
tphase+=usecond();
|
||||||
|
|
||||||
|
// Import basis into BLAS layout once; blockProject then reads it once per
|
||||||
|
// basis vector rather than once per (i,p) as in scalar blockProject.
|
||||||
|
// Process all npoint in a single batch.
|
||||||
|
MultiRHSBlockProject<FineField> Projector;
|
||||||
|
Projector.Allocate(nbasis, grid, CoarseGrid());
|
||||||
|
Projector.ImportBasis(U.subspace);
|
||||||
|
|
||||||
|
std::vector<FineField> phaV_batch(npoint, grid);
|
||||||
|
std::vector<FineField> MphaV_batch(npoint, grid);
|
||||||
|
std::vector<CoarseVector> proj_batch(npoint, CoarseGrid());
|
||||||
std::vector<CoarseVector> ComputeProj(npoint, CoarseGrid());
|
std::vector<CoarseVector> ComputeProj(npoint, CoarseGrid());
|
||||||
std::vector<CoarseVector> FT(npoint, CoarseGrid());
|
std::vector<CoarseVector> FT(npoint, CoarseGrid());
|
||||||
|
|
||||||
|
// Pre-allocate BLAS_F and BLAS_C to avoid repeated hipMalloc/hipFree of
|
||||||
|
// ~5.6 GB per blockProject call, which hangs on ROCm for large allocations.
|
||||||
|
Projector.BLAS_F.resize(Projector.fine_vol * Projector.words * npoint);
|
||||||
|
Projector.BLAS_C.resize(Projector.coarse_vol * nbasis * npoint);
|
||||||
|
|
||||||
for(int i=0;i<nbasis;i++){// Loop over basis vectors
|
for(int i=0;i<nbasis;i++){// Loop over basis vectors
|
||||||
|
accelerator_barrier(); // ensure prior iteration's async writes are retired
|
||||||
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i<<"/"<<nbasis<< std::endl;
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i<<"/"<<nbasis<< std::endl;
|
||||||
for(int p=0;p<npoint;p++){ // Loop over momenta in npoint
|
|
||||||
tphaseBZ-=usecond();
|
tphaseBZ-=usecond();
|
||||||
phaV = phaF[p]*V.subspace[i];
|
for(int p=0;p<npoint;p++)
|
||||||
|
phaV_batch[p] = phaF[p] * V.subspace[i];
|
||||||
tphaseBZ+=usecond();
|
tphaseBZ+=usecond();
|
||||||
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i<<" phaseBZ done"<< std::endl;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
|
||||||
// Multiple phased subspace vector by matrix and project to subspace
|
|
||||||
// Remove local bulk phase to leave relative phases
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
|
||||||
tmat-=usecond();
|
tmat-=usecond();
|
||||||
linop.Op(phaV,MphaV);
|
for(int p=0;p<npoint;p++)
|
||||||
|
linop.Op(phaV_batch[p], MphaV_batch[p]);
|
||||||
tmat+=usecond();
|
tmat+=usecond();
|
||||||
// std::cout << i << " " <<p << " MphaV "<<norm2(MphaV)<<" "<<norm2(phaV)<<std::endl;
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i<<" mat done"<< std::endl;
|
||||||
|
|
||||||
|
// One batched GEMM reads BLAS_V once for all npoint vectors.
|
||||||
tproj-=usecond();
|
tproj-=usecond();
|
||||||
blockProject(coarseInner,MphaV,U.subspace);
|
Projector.blockProject(MphaV_batch, proj_batch);
|
||||||
coarseInner = conjugate(pha[p]) * coarseInner;
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i<<" blockProject done"<< std::endl;
|
||||||
|
for(int p=0;p<npoint;p++)
|
||||||
ComputeProj[p] = coarseInner;
|
ComputeProj[p] = conjugate(pha[p]) * proj_batch[p];
|
||||||
tproj+=usecond();
|
tproj+=usecond();
|
||||||
// std::cout << i << " " <<p << " ComputeProj "<<norm2(ComputeProj[p])<<std::endl;
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i<<" proj done"<< std::endl;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tinv-=usecond();
|
tinv-=usecond();
|
||||||
for(int k=0;k<npoint;k++){
|
for(int k=0;k<npoint;k++){
|
||||||
@@ -584,10 +639,19 @@ public:
|
|||||||
int osites=CoarseGrid()->oSites();
|
int osites=CoarseGrid()->oSites();
|
||||||
autoView( A_v , _A[k], AcceleratorWrite);
|
autoView( A_v , _A[k], AcceleratorWrite);
|
||||||
autoView( FT_v , FT[k], AcceleratorRead);
|
autoView( FT_v , FT[k], AcceleratorRead);
|
||||||
accelerator_for(sss, osites, 1, {
|
accelerator_for(sss, osites, nbasis, {
|
||||||
|
#ifdef GRID_SIMT
|
||||||
|
int j = acceleratorSIMTlane(nbasis);
|
||||||
|
A_v[sss](i,j) = FT_v[sss](j);
|
||||||
|
#else
|
||||||
|
// CPU build: acceleratorSIMTlane()==0 -- an un-looped SIMT tensor
|
||||||
|
// index writes ONLY j=0 and silently drops the other nbasis-1
|
||||||
|
// columns (caught by Test_schur_dense_coarse import certificate,
|
||||||
|
// 2026-08-14). Loop explicitly.
|
||||||
for(int j=0;j<nbasis;j++){
|
for(int j=0;j<nbasis;j++){
|
||||||
A_v[sss](i,j) = FT_v[sss](j);
|
A_v[sss](i,j) = FT_v[sss](j);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tinv+=usecond();
|
tinv+=usecond();
|
||||||
@@ -595,13 +659,13 @@ public:
|
|||||||
|
|
||||||
// Only needed if nonhermitian
|
// Only needed if nonhermitian
|
||||||
if ( ! hermitian ) {
|
if ( ! hermitian ) {
|
||||||
// std::cout << GridLogMessage<<"PopulateAdag "<<std::endl;
|
std::cout << GridLogMessage<<"PopulateAdag "<<std::endl;
|
||||||
// PopulateAdag();
|
PopulateAdag();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int p=0;p<geom.npoint;p++){
|
// for(int p=0;p<geom.npoint;p++){
|
||||||
std::cout << " _A["<<p<<"] "<<norm2(_A[p])<<std::endl;
|
// std::cout << " _A["<<p<<"] "<<norm2(_A[p])<<std::endl;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Need to write something to populate Adag from A
|
// Need to write something to populate Adag from A
|
||||||
ExchangeCoarseLinks();
|
ExchangeCoarseLinks();
|
||||||
@@ -616,7 +680,7 @@ public:
|
|||||||
void ExchangeCoarseLinks(void){
|
void ExchangeCoarseLinks(void){
|
||||||
for(int p=0;p<geom.npoint;p++){
|
for(int p=0;p<geom.npoint;p++){
|
||||||
_A[p] = Cell.ExchangePeriodic(_A[p]);
|
_A[p] = Cell.ExchangePeriodic(_A[p]);
|
||||||
// _Adag[p]= Cell.ExchangePeriodic(_Adag[p]);
|
if ( !hermitian ) _Adag[p]= Cell.ExchangePeriodic(_Adag[p]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void Mdiag (const Field &in, Field &out){ GRID_ASSERT(0);};
|
virtual void Mdiag (const Field &in, Field &out){ GRID_ASSERT(0);};
|
||||||
|
|||||||
@@ -0,0 +1,851 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/GeneralCoarsenedMatrixMultiRHS.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
|
||||||
|
// Fine Object == (per site) type of fine field
|
||||||
|
// nbasis == number of deflation vectors
|
||||||
|
template<class Fobj,class CComplex,int nbasis>
|
||||||
|
class MultiGeneralCoarsenedOperatorV2 : public SparseMatrixBase<Lattice<iVector<CComplex,nbasis > > > {
|
||||||
|
public:
|
||||||
|
typedef typename CComplex::scalar_object SComplex;
|
||||||
|
typedef GeneralCoarsenedMatrix<Fobj,CComplex,nbasis> GeneralCoarseOp;
|
||||||
|
typedef MultiGeneralCoarsenedOperatorV2<Fobj,CComplex,nbasis> MultiGeneralCoarseOp;
|
||||||
|
|
||||||
|
typedef iVector<CComplex,nbasis > siteVector;
|
||||||
|
typedef iMatrix<CComplex,nbasis > siteMatrix;
|
||||||
|
typedef iVector<SComplex,nbasis > calcVector;
|
||||||
|
typedef iMatrix<SComplex,nbasis > calcMatrix;
|
||||||
|
typedef Lattice<iScalar<CComplex> > CoarseComplexField;
|
||||||
|
typedef Lattice<siteVector> CoarseVector;
|
||||||
|
typedef Lattice<iMatrix<CComplex,nbasis > > CoarseMatrix;
|
||||||
|
typedef iMatrix<CComplex,nbasis > Cobj;
|
||||||
|
typedef iVector<CComplex,nbasis > Cvec;
|
||||||
|
typedef Lattice< CComplex > CoarseScalar; // used for inner products on fine field
|
||||||
|
typedef Lattice<Fobj > FineField;
|
||||||
|
typedef CoarseVector Field;
|
||||||
|
|
||||||
|
// Block operations on the fine vectors carry the fine layout, which need
|
||||||
|
// not be the coarse one
|
||||||
|
typedef decltype(innerProduct(Fobj(),Fobj())) FineInner;
|
||||||
|
typedef Lattice<FineInner> FineComplexField;
|
||||||
|
typedef Lattice<FineInner> BlockComplexField;
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Data members
|
||||||
|
//
|
||||||
|
// Nrhs independent: the D dimensional coarse grid, the geometry, the padded
|
||||||
|
// cell that supplies the stencil grid, the stencil, and the matrix elements.
|
||||||
|
//
|
||||||
|
// Nrhs dependent: the D+1 grid, its padded cell, and the BLAS B/C buffers
|
||||||
|
// with their pointer tables. Owned by SetNRHS().
|
||||||
|
////////////////////
|
||||||
|
GridCartesian * _CoarseGrid; // D dimensional
|
||||||
|
NonLocalStencilGeometry geom;
|
||||||
|
NonLocalStencilGeometry geom_srhs;
|
||||||
|
PaddedCell CellD; // D dimensional, supplies stencil grid
|
||||||
|
GeneralLocalStencil Stencil; // D dimensional
|
||||||
|
|
||||||
|
int _Nrhs;
|
||||||
|
GridCartesian * _CoarseGridMulti; // D+1 dimensional, SetNRHS
|
||||||
|
PaddedCell * CellMulti; // D+1 dimensional, SetNRHS
|
||||||
|
|
||||||
|
deviceVector<calcVector> BLAS_B;
|
||||||
|
deviceVector<calcVector> BLAS_C;
|
||||||
|
std::vector<deviceVector<calcMatrix> > BLAS_A;
|
||||||
|
|
||||||
|
std::vector<deviceVector<ComplexD *> > BLAS_AP;
|
||||||
|
std::vector<deviceVector<ComplexD *> > BLAS_BP;
|
||||||
|
deviceVector<ComplexD *> BLAS_CP;
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Interface
|
||||||
|
///////////////////////
|
||||||
|
GridBase * Grid(void) { CheckGridSet(); return _CoarseGridMulti; };
|
||||||
|
GridCartesian * CoarseGrid(void) { CheckGridSet(); return _CoarseGridMulti; };
|
||||||
|
GridCartesian * CoarseGridD(void) { return _CoarseGrid; }; // lower dimensional grid
|
||||||
|
int Nrhs(void) { CheckGridSet(); return _Nrhs; };
|
||||||
|
|
||||||
|
void CheckGridSet(void)
|
||||||
|
{
|
||||||
|
if ( _CoarseGridMulti == nullptr ) {
|
||||||
|
std::cout << GridLogError
|
||||||
|
<< "MultiGeneralCoarsenedOperatorV2: the multiRHS grid has not been set."
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << GridLogError
|
||||||
|
<< " Call SetGrid(CoarseGridMulti) with the D+1 dimensional grid your"
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << GridLogError
|
||||||
|
<< " coarse vectors live on, before Grid(), Nrhs() or M()."
|
||||||
|
<< std::endl;
|
||||||
|
GRID_ASSERT(_CoarseGridMulti != nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can be used to do I/O on the operator matrices externally
|
||||||
|
void SetMatrix (int p,CoarseMatrix & A)
|
||||||
|
{
|
||||||
|
GRID_ASSERT(A.size()==geom_srhs.npoint);
|
||||||
|
GridtoBLAS(A[p],BLAS_A[p]);
|
||||||
|
}
|
||||||
|
void GetMatrix (int p,CoarseMatrix & A)
|
||||||
|
{
|
||||||
|
GRID_ASSERT(A.size()==geom_srhs.npoint);
|
||||||
|
BLAStoGrid(A[p],BLAS_A[p]);
|
||||||
|
}
|
||||||
|
void CopyMatrix (GeneralCoarseOp &_Op)
|
||||||
|
{
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
auto Aup = _Op.Cell.Extract(_Op._A[p]);
|
||||||
|
//Unpadded
|
||||||
|
GridtoBLAS(Aup,BLAS_A[p]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void CheckMatrix (GeneralCoarseOp &_Op)
|
||||||
|
{
|
||||||
|
std::cout <<"************* Checking the little direc operator mRHS"<<std::endl;
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
//Unpadded
|
||||||
|
auto Aup = _Op.Cell.Extract(_Op._A[p]);
|
||||||
|
auto Ack = Aup;
|
||||||
|
BLAStoGrid(Ack,BLAS_A[p]);
|
||||||
|
std::cout << p<<" Ack "<<norm2(Ack)<<std::endl;
|
||||||
|
std::cout << p<<" Aup "<<norm2(Aup)<<std::endl;
|
||||||
|
}
|
||||||
|
std::cout <<"************* "<<std::endl;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor takes the D dimensional coarse grid. Everything built here
|
||||||
|
// is independent of Nrhs, in particular the matrix elements, which must
|
||||||
|
// survive a change of Nrhs untouched.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
MultiGeneralCoarsenedOperatorV2(NonLocalStencilGeometry &_geom,GridCartesian *CoarseGrid) :
|
||||||
|
_CoarseGrid(CoarseGrid),
|
||||||
|
geom_srhs(_geom),
|
||||||
|
geom(CoarseGrid,_geom.hops,_geom.skip),
|
||||||
|
CellD(geom.Depth(),CoarseGrid),
|
||||||
|
Stencil(CellD.grids.back(),geom.shifts), // D dimensional padded cell stencil
|
||||||
|
_Nrhs(-1),
|
||||||
|
_CoarseGridMulti(nullptr),
|
||||||
|
CellMulti(nullptr)
|
||||||
|
{
|
||||||
|
int32_t unpadded_sites = _CoarseGrid->lSites();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Matrix elements and their pointer table
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
BLAS_A.resize(geom.npoint);
|
||||||
|
BLAS_AP.resize(geom.npoint);
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
BLAS_A[p].resize (unpadded_sites); // no ghost zone, npoint elements
|
||||||
|
BLAS_AP[p].resize(unpadded_sites);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Site identity mapping for A
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
for(int ss=0;ss<unpadded_sites;ss++){
|
||||||
|
ComplexD *ptr = (ComplexD *)&BLAS_A[p][ss];
|
||||||
|
acceleratorPut(BLAS_AP[p][ss],ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~MultiGeneralCoarsenedOperatorV2()
|
||||||
|
{
|
||||||
|
ReleaseGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Free everything SetGrid allocated. The D+1 grid is borrowed from the
|
||||||
|
// caller and is never deleted here. Safe to call repeatedly and before
|
||||||
|
// the destructor.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void ReleaseGrid(void)
|
||||||
|
{
|
||||||
|
if ( CellMulti != nullptr ) { delete CellMulti; CellMulti = nullptr; }
|
||||||
|
|
||||||
|
_CoarseGridMulti = nullptr; // borrowed, not owned
|
||||||
|
_Nrhs = -1;
|
||||||
|
|
||||||
|
BLAS_B.resize(0);
|
||||||
|
BLAS_C.resize(0);
|
||||||
|
for(int p=0;p<BLAS_BP.size();p++){
|
||||||
|
BLAS_BP[p].resize(0);
|
||||||
|
}
|
||||||
|
BLAS_BP.resize(0);
|
||||||
|
BLAS_CP.resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Everything that depends on Nrhs. Idempotent; lazy called on demand.
|
||||||
|
//
|
||||||
|
// The stencil lives on the D dimensional padded grid. PaddedCell only pads
|
||||||
|
// a dimension when it is distributed, and the rhs direction never is, so
|
||||||
|
// the D+1 padded grid is exactly Nrhs copies of the D dimensional padded
|
||||||
|
// grid with rhs innermost. The neighbour offset therefore carries an Nrhs
|
||||||
|
// factor, in the same way the Nsimd factor is carried.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void SetGrid(GridCartesian *CoarseGridMulti)
|
||||||
|
{
|
||||||
|
GRID_ASSERT(CoarseGridMulti != nullptr);
|
||||||
|
|
||||||
|
if ( CoarseGridMulti == _CoarseGridMulti ) return; // idempotent on identity
|
||||||
|
|
||||||
|
ReleaseGrid();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// The D+1 grid is supplied and owned by the caller. Two operators over
|
||||||
|
// the same coarse space must share one grid object or their fields will
|
||||||
|
// not conform, so this is never manufactured internally.
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
int nd = _CoarseGrid->_ndimension;
|
||||||
|
|
||||||
|
GRID_ASSERT(CoarseGridMulti->_ndimension == nd+1);
|
||||||
|
GRID_ASSERT(CoarseGridMulti->_processors[0] == 1); // rhs is not distributed
|
||||||
|
for(int d=0;d<nd;d++){
|
||||||
|
GRID_ASSERT(CoarseGridMulti->_fdimensions[d+1] == _CoarseGrid->_fdimensions[d]);
|
||||||
|
GRID_ASSERT(CoarseGridMulti->_processors [d+1] == _CoarseGrid->_processors [d]);
|
||||||
|
GRID_ASSERT(CoarseGridMulti->_simd_layout[d+1] == _CoarseGrid->_simd_layout[d]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_CoarseGridMulti = CoarseGridMulti;
|
||||||
|
_Nrhs = CoarseGridMulti->_fdimensions[0];
|
||||||
|
GRID_ASSERT(_Nrhs>=1);
|
||||||
|
|
||||||
|
int nrhs = _Nrhs;
|
||||||
|
|
||||||
|
CellMulti = new PaddedCell(geom.Depth(),_CoarseGridMulti);
|
||||||
|
|
||||||
|
int32_t padded_sites = CellD.grids.back()->lSites(); // D dimensional
|
||||||
|
int32_t unpadded_sites = _CoarseGrid->lSites(); // D dimensional
|
||||||
|
|
||||||
|
// The neighbour offset multiplication by nrhs is exact only if the D+1
|
||||||
|
// padded volume is nrhs copies of the D dimensional one. Check it.
|
||||||
|
GRID_ASSERT(CellMulti->grids.back()->lSites() == nrhs*padded_sites);
|
||||||
|
GRID_ASSERT(_CoarseGridMulti->lSites() == nrhs*unpadded_sites);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Device data vector storage
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
BLAS_B.resize(nrhs *padded_sites); // includes ghost zone
|
||||||
|
BLAS_C.resize(nrhs *unpadded_sites); // no ghost zone
|
||||||
|
BLAS_BP.resize(geom.npoint);
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
BLAS_BP[p].resize(unpadded_sites);
|
||||||
|
}
|
||||||
|
BLAS_CP.resize(unpadded_sites);
|
||||||
|
|
||||||
|
// Site identity mapping for C
|
||||||
|
for(int ss=0;ss<unpadded_sites;ss++){
|
||||||
|
ComplexD *ptr = (ComplexD *)&BLAS_C[ss*nrhs];
|
||||||
|
acceleratorPut(BLAS_CP[ss],ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neighbour table is more complicated
|
||||||
|
int32_t j=0; // Interior point counter (unpadded)
|
||||||
|
for(int32_t s=0;s<padded_sites;s++){ // D volume, padded
|
||||||
|
int ghost_zone=0;
|
||||||
|
for(int32_t point = 0 ; point < geom.npoint; point++){
|
||||||
|
int i=s*geom.npoint+point;
|
||||||
|
if( Stencil._entries[i]._wrap ) { // stencil is indexed by the oSite of the D dim grid
|
||||||
|
ghost_zone=1; // If general stencil wrapped in any direction, wrap=1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ghost_zone==0) {
|
||||||
|
for(int32_t point = 0 ; point < geom.npoint; point++){
|
||||||
|
int i=s*geom.npoint+point;
|
||||||
|
int32_t nbr = Stencil._entries[i]._offset*CComplex::Nsimd(); // oSite -> lSite, D dim
|
||||||
|
nbr = nbr*nrhs; // D -> D+1, rhs innermost
|
||||||
|
GRID_ASSERT(nbr<BLAS_B.size());
|
||||||
|
ComplexD * ptr = (ComplexD *)&BLAS_B[nbr];
|
||||||
|
acceleratorPut(BLAS_BP[point][j],ptr); // neighbour indexing in ghost zone volume
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GRID_ASSERT(j==unpadded_sites);
|
||||||
|
}
|
||||||
|
template<class vobj> void GridtoBLAS(const Lattice<vobj> &from,deviceVector<typename vobj::scalar_object> &to)
|
||||||
|
{
|
||||||
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
|
typedef typename vobj::vector_type vector_type;
|
||||||
|
|
||||||
|
GridBase *Fg = from.Grid();
|
||||||
|
GRID_ASSERT(!Fg->_isCheckerBoarded);
|
||||||
|
int nd = Fg->_ndimension;
|
||||||
|
|
||||||
|
to.resize(Fg->lSites());
|
||||||
|
|
||||||
|
Coordinate LocalLatt = Fg->LocalDimensions();
|
||||||
|
size_t nsite = 1;
|
||||||
|
for(int i=0;i<nd;i++) nsite *= LocalLatt[i];
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// do the index calc on the GPU
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Coordinate f_ostride = Fg->_ostride;
|
||||||
|
Coordinate f_istride = Fg->_istride;
|
||||||
|
Coordinate f_rdimensions = Fg->_rdimensions;
|
||||||
|
|
||||||
|
autoView(from_v,from,AcceleratorRead);
|
||||||
|
auto to_v = &to[0];
|
||||||
|
|
||||||
|
const int words=sizeof(vobj)/sizeof(vector_type);
|
||||||
|
accelerator_for(idx,nsite,1,{
|
||||||
|
|
||||||
|
Coordinate from_coor, base;
|
||||||
|
Lexicographic::CoorFromIndex(base,idx,LocalLatt);
|
||||||
|
for(int i=0;i<nd;i++){
|
||||||
|
from_coor[i] = base[i];
|
||||||
|
}
|
||||||
|
int from_oidx = 0; for(int d=0;d<nd;d++) from_oidx+=f_ostride[d]*(from_coor[d]%f_rdimensions[d]);
|
||||||
|
int from_lane = 0; for(int d=0;d<nd;d++) from_lane+=f_istride[d]*(from_coor[d]/f_rdimensions[d]);
|
||||||
|
|
||||||
|
const vector_type* from = (const vector_type *)&from_v[from_oidx];
|
||||||
|
scalar_type* to = (scalar_type *)&to_v[idx];
|
||||||
|
|
||||||
|
scalar_type stmp;
|
||||||
|
for(int w=0;w<words;w++){
|
||||||
|
stmp = getlane(from[w], from_lane);
|
||||||
|
to[w] = stmp;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
template<class vobj> void BLAStoGrid(Lattice<vobj> &grid,deviceVector<typename vobj::scalar_object> &in)
|
||||||
|
{
|
||||||
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
typedef typename vobj::scalar_type scalar_type;
|
||||||
|
typedef typename vobj::vector_type vector_type;
|
||||||
|
|
||||||
|
GridBase *Tg = grid.Grid();
|
||||||
|
GRID_ASSERT(!Tg->_isCheckerBoarded);
|
||||||
|
int nd = Tg->_ndimension;
|
||||||
|
|
||||||
|
GRID_ASSERT(in.size()==Tg->lSites());
|
||||||
|
|
||||||
|
Coordinate LocalLatt = Tg->LocalDimensions();
|
||||||
|
size_t nsite = 1;
|
||||||
|
for(int i=0;i<nd;i++) nsite *= LocalLatt[i];
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// do the index calc on the GPU
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Coordinate t_ostride = Tg->_ostride;
|
||||||
|
Coordinate t_istride = Tg->_istride;
|
||||||
|
Coordinate t_rdimensions = Tg->_rdimensions;
|
||||||
|
|
||||||
|
autoView(to_v,grid,AcceleratorWrite);
|
||||||
|
auto from_v = &in[0];
|
||||||
|
|
||||||
|
const int words=sizeof(vobj)/sizeof(vector_type);
|
||||||
|
accelerator_for(idx,nsite,1,{
|
||||||
|
|
||||||
|
Coordinate to_coor, base;
|
||||||
|
Lexicographic::CoorFromIndex(base,idx,LocalLatt);
|
||||||
|
for(int i=0;i<nd;i++){
|
||||||
|
to_coor[i] = base[i];
|
||||||
|
}
|
||||||
|
int to_oidx = 0; for(int d=0;d<nd;d++) to_oidx+=t_ostride[d]*(to_coor[d]%t_rdimensions[d]);
|
||||||
|
int to_lane = 0; for(int d=0;d<nd;d++) to_lane+=t_istride[d]*(to_coor[d]/t_rdimensions[d]);
|
||||||
|
|
||||||
|
vector_type* to = (vector_type *)&to_v[to_oidx];
|
||||||
|
scalar_type* from = (scalar_type *)&from_v[idx];
|
||||||
|
|
||||||
|
scalar_type stmp;
|
||||||
|
for(int w=0;w<words;w++){
|
||||||
|
stmp=from[w];
|
||||||
|
putlane(to[w], stmp, to_lane);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Shared by both CoarsenOperator variants
|
||||||
|
//
|
||||||
|
// conj(pha[block]) proj[k (which mom)][j (basis vec cpt)][block]
|
||||||
|
// = \sum_{l in ball} e^{i q_k . delta_l} < phi_{block,j} | MdagM | phi_{(block+delta_l),i} >
|
||||||
|
// = \sum_{l in ball} e^{iqk.delta_l} A_ji^{b.b+l}
|
||||||
|
// = M_{kl} A_ji^{b.b+l}
|
||||||
|
//
|
||||||
|
// Where q_k = delta_k . (2*M_PI/global_nb[mu])
|
||||||
|
// Then A{ji}^{b,b+l} = M^{-1}_{lm} ComputeProj_{m,b,i,j}
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void CoarsenFourierMatrix(GridBase *CoarseGrid,Eigen::MatrixXcd &invMkl)
|
||||||
|
{
|
||||||
|
const int npoint = geom_srhs.npoint;
|
||||||
|
Coordinate clatt = CoarseGrid->GlobalDimensions();
|
||||||
|
int Nd = CoarseGrid->Nd();
|
||||||
|
|
||||||
|
Eigen::MatrixXcd Mkl = Eigen::MatrixXcd::Zero(npoint,npoint);
|
||||||
|
ComplexD ci(0.0,1.0);
|
||||||
|
for(int k=0;k<npoint;k++){ // Loop over momenta
|
||||||
|
for(int l=0;l<npoint;l++){ // Loop over nbr relative
|
||||||
|
ComplexD phase(0.0,0.0);
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
RealD TwoPiL = M_PI * 2.0/ clatt[mu];
|
||||||
|
phase=phase+TwoPiL*geom_srhs.shifts[k][mu]*geom_srhs.shifts[l][mu];
|
||||||
|
}
|
||||||
|
phase=exp(phase*ci);
|
||||||
|
Mkl(k,l) = phase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invMkl = Mkl.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// blockOrthogonalise and blockZAXPY are block operations on the fine
|
||||||
|
// vectors, using a coarse shaped field only as an index set. They need a
|
||||||
|
// grid carrying the fine SIMD layout, which the coarse space no longer
|
||||||
|
// does. Constructed local to the caller so it cannot be mistaken for the
|
||||||
|
// coarse grid.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void CoarsenBlockGridLayout(GridBase *grid,GridBase *CoarseGrid,
|
||||||
|
Coordinate &latt,Coordinate &simd,Coordinate &mpi)
|
||||||
|
{
|
||||||
|
int nd = CoarseGrid->_ndimension;
|
||||||
|
latt.resize(nd); simd.resize(nd); mpi.resize(nd);
|
||||||
|
for(int d=0;d<nd;d++){
|
||||||
|
latt[d] = CoarseGrid->_fdimensions[d];
|
||||||
|
simd[d] = grid->_simd_layout[d];
|
||||||
|
mpi [d] = CoarseGrid->_processors[d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// D+1 coarse grid holding the batch, rhs innermost and unvectorised
|
||||||
|
void CoarsenBatchGridLayout(GridBase *CoarseGrid,int batch,
|
||||||
|
Coordinate &latt,Coordinate &simd,Coordinate &mpi)
|
||||||
|
{
|
||||||
|
latt.resize(1,batch); simd.resize(1,1); mpi.resize(1,1);
|
||||||
|
latt[0]=batch; simd[0]=1; mpi[0]=1;
|
||||||
|
for(int d=0;d<CoarseGrid->_ndimension;d++){
|
||||||
|
latt.push_back(CoarseGrid->_fdimensions[d]);
|
||||||
|
simd.push_back(CoarseGrid->_simd_layout[d]);
|
||||||
|
mpi .push_back(CoarseGrid->_processors[d]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Fourier inverse needs the phase in the coarse layout and the basis
|
||||||
|
// phasing needs it in the fine layout; each is built from its own
|
||||||
|
// coordinates rather than transferred.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void CoarsenPhases(GridBase *grid,GridBase *CoarseGrid,GridCartesian *BlockGrid,
|
||||||
|
std::vector<CoarseComplexField> &pha,
|
||||||
|
std::vector<FineComplexField> &phaF)
|
||||||
|
{
|
||||||
|
const int npoint = geom_srhs.npoint;
|
||||||
|
Coordinate clatt = CoarseGrid->GlobalDimensions();
|
||||||
|
int Nd = CoarseGrid->Nd();
|
||||||
|
ComplexD ci(0.0,1.0);
|
||||||
|
|
||||||
|
typedef typename CComplex::scalar_type SComplex;
|
||||||
|
FineComplexField one(grid); one=SComplex(1.0);
|
||||||
|
FineComplexField zz(grid); zz = Zero();
|
||||||
|
BlockComplexField pha_blk (BlockGrid);
|
||||||
|
BlockComplexField blk_coor(BlockGrid);
|
||||||
|
|
||||||
|
for(int p=0;p<npoint;p++){ // Loop over momenta in npoint
|
||||||
|
CoarseComplexField coor(CoarseGrid);
|
||||||
|
pha[p] =Zero();
|
||||||
|
pha_blk=Zero();
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
RealD TwoPiL = M_PI * 2.0/ clatt[mu];
|
||||||
|
LatticeCoordinate(coor,mu);
|
||||||
|
pha[p] = pha[p] + (TwoPiL * geom_srhs.shifts[p][mu]) * coor;
|
||||||
|
LatticeCoordinate(blk_coor,mu);
|
||||||
|
pha_blk = pha_blk + (TwoPiL * geom_srhs.shifts[p][mu]) * blk_coor;
|
||||||
|
}
|
||||||
|
pha[p] =exp(pha[p] *ci);
|
||||||
|
pha_blk=exp(pha_blk*ci);
|
||||||
|
|
||||||
|
blockZAXPY(phaF[p],pha_blk,one,zz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Remove the bulk phase from the batch of coarse projections and
|
||||||
|
// accumulate the Fourier inverse into A. Both variants reach here with
|
||||||
|
// TmpProj in the same batch coarse order, so this is shared verbatim.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void CoarsenAccumulate(int p,int i0,int nbv,int batch,
|
||||||
|
Eigen::MatrixXcd &invMkl,
|
||||||
|
std::vector<CoarseComplexField> &pha,
|
||||||
|
CoarseComplexField &phaB,
|
||||||
|
CoarseVector &TmpProj,
|
||||||
|
std::vector<CoarseMatrix> &_A,
|
||||||
|
GridBase *CoarseGrid)
|
||||||
|
{
|
||||||
|
typedef typename CComplex::scalar_type SComplex;
|
||||||
|
const int npoint = geom_srhs.npoint;
|
||||||
|
|
||||||
|
for(int b=0;b<batch;b++) InsertSliceFast(pha[p],phaB,b,0);
|
||||||
|
TmpProj = conjugate(phaB)*TmpProj;
|
||||||
|
|
||||||
|
int osites=CoarseGrid->oSites();
|
||||||
|
for(int k=0;k<npoint;k++){
|
||||||
|
SComplex sc(invMkl(p,k).real(),invMkl(p,k).imag());
|
||||||
|
CComplex coef(sc);
|
||||||
|
autoView( A_v , _A[k], AcceleratorWrite);
|
||||||
|
autoView( TP_v , TmpProj, AcceleratorRead);
|
||||||
|
accelerator_for(sss, osites, 1, {
|
||||||
|
for(int b=0;b<nbv;b++){
|
||||||
|
for(int j=0;j<nbasis;j++){
|
||||||
|
A_v[sss](i0+b,j) = A_v[sss](i0+b,j) + coef*TP_v[b+batch*sss](j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoarsenReport(RealD tphase,RealD tphaseBZ,RealD tslice,
|
||||||
|
RealD tmat,RealD tproj,RealD tinv)
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage<<"CoarsenOperator phase "<<tphase<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"CoarsenOperator phaseBZ "<<tphaseBZ<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"CoarsenOperator slice "<<tslice <<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"CoarsenOperator mat "<<tmat <<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"CoarsenOperator proj "<<tproj<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"CoarsenOperator inv "<<tinv<<" us"<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Coarsen a NATIVELY multiRHS fine operator.
|
||||||
|
//
|
||||||
|
// linop acts on the D+1 dimensional fine grid FineGridMulti, with the batch
|
||||||
|
// of phased basis vectors carried in the rhs direction. A single RHS
|
||||||
|
// operator can be promoted with MrhsPromotedOperator, but that pays an
|
||||||
|
// ExtractSlice/InsertSlice pair per rhs; prefer the single RHS variant
|
||||||
|
// below in that case.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void CoarsenOperator(LinearOperatorBase<Lattice<Fobj> > &linop,
|
||||||
|
GridCartesian *FineGridMulti,
|
||||||
|
std::vector<FineField> &Subspace,
|
||||||
|
GridBase *CoarseGrid)
|
||||||
|
{
|
||||||
|
RealD tproj=0.0, tmat=0.0, tphase=0.0, tphaseBZ=0.0, tslice=0.0, tinv=0.0;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage<< "GeneralCoarsenMatrixMrhs (multiRHS fine operator)"<< std::endl;
|
||||||
|
|
||||||
|
GRID_ASSERT(Subspace.size()==nbasis);
|
||||||
|
GridBase *grid = Subspace[0].Grid();
|
||||||
|
|
||||||
|
GRID_ASSERT(FineGridMulti->_ndimension == grid->_ndimension+1);
|
||||||
|
GRID_ASSERT(FineGridMulti->_processors[0] == 1);
|
||||||
|
for(int d=0;d<grid->_ndimension;d++){
|
||||||
|
GRID_ASSERT(FineGridMulti->_fdimensions[d+1] == grid->_fdimensions[d]);
|
||||||
|
GRID_ASSERT(FineGridMulti->_processors [d+1] == grid->_processors [d]);
|
||||||
|
}
|
||||||
|
int batch = FineGridMulti->_fdimensions[0];
|
||||||
|
|
||||||
|
Coordinate blatt,bsimd,bmpi;
|
||||||
|
CoarsenBlockGridLayout(grid,CoarseGrid,blatt,bsimd,bmpi);
|
||||||
|
GridCartesian BlockGrid(blatt,bsimd,bmpi);
|
||||||
|
|
||||||
|
BlockComplexField InnerProd(&BlockGrid);
|
||||||
|
blockOrthogonalise(InnerProd,Subspace);
|
||||||
|
|
||||||
|
MultiRHSBlockProject<Lattice<Fobj> > Projector;
|
||||||
|
Projector.Allocate(nbasis,grid,CoarseGrid);
|
||||||
|
Projector.ImportBasis(Subspace);
|
||||||
|
|
||||||
|
const int npoint = geom_srhs.npoint;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd invMkl;
|
||||||
|
CoarsenFourierMatrix(CoarseGrid,invMkl);
|
||||||
|
|
||||||
|
FineField phaV(grid);
|
||||||
|
std::vector<FineComplexField> phaF(npoint,grid);
|
||||||
|
std::vector<CoarseComplexField> pha (npoint,CoarseGrid);
|
||||||
|
|
||||||
|
tphase=-usecond();
|
||||||
|
CoarsenPhases(grid,CoarseGrid,&BlockGrid,pha,phaF);
|
||||||
|
tphase+=usecond();
|
||||||
|
|
||||||
|
std::vector<CoarseMatrix> _A;
|
||||||
|
_A.resize(npoint,CoarseGrid);
|
||||||
|
for(int k=0;k<npoint;k++) _A[k] = Zero();
|
||||||
|
|
||||||
|
Coordinate cmlatt,cmsimd,cmmpi;
|
||||||
|
CoarsenBatchGridLayout(CoarseGrid,batch,cmlatt,cmsimd,cmmpi);
|
||||||
|
GridCartesian CoarseBatchGrid(cmlatt,cmsimd,cmmpi);
|
||||||
|
|
||||||
|
CoarseVector TmpProj(&CoarseBatchGrid);
|
||||||
|
CoarseComplexField phaB(&CoarseBatchGrid);
|
||||||
|
|
||||||
|
FineField hi_in (FineGridMulti);
|
||||||
|
FineField hi_out(FineGridMulti);
|
||||||
|
FineField zzF(grid); zzF = Zero();
|
||||||
|
|
||||||
|
for(int i0=0;i0<nbasis;i0+=batch){ // Loop over batches of basis vectors
|
||||||
|
|
||||||
|
int nbv = MIN(batch,nbasis-i0);
|
||||||
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i0<<"/"<<nbasis<< std::endl;
|
||||||
|
|
||||||
|
for(int p=0;p<npoint;p++){ // Loop over momenta
|
||||||
|
|
||||||
|
// One phase, applied to the whole batch. Tail slices are zeroed so
|
||||||
|
// the operator never sees undefined data.
|
||||||
|
for(int b=0;b<nbv;b++){
|
||||||
|
tphaseBZ-=usecond();
|
||||||
|
phaV = phaF[p]*Subspace[i0+b];
|
||||||
|
tphaseBZ+=usecond();
|
||||||
|
tslice-=usecond();
|
||||||
|
InsertSliceFast(phaV,hi_in,b,0);
|
||||||
|
tslice+=usecond();
|
||||||
|
}
|
||||||
|
tslice-=usecond();
|
||||||
|
for(int b=nbv;b<batch;b++){
|
||||||
|
InsertSliceFast(zzF,hi_in,b,0);
|
||||||
|
}
|
||||||
|
tslice+=usecond();
|
||||||
|
|
||||||
|
tmat-=usecond();
|
||||||
|
linop.Op(hi_in,hi_out);
|
||||||
|
tmat+=usecond();
|
||||||
|
|
||||||
|
tproj-=usecond();
|
||||||
|
Projector.blockProject(hi_out,TmpProj);
|
||||||
|
tproj+=usecond();
|
||||||
|
|
||||||
|
tinv-=usecond();
|
||||||
|
CoarsenAccumulate(p,i0,nbv,batch,invMkl,pha,phaB,TmpProj,_A,CoarseGrid);
|
||||||
|
tinv+=usecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int p=0;p<npoint;p++){
|
||||||
|
GridtoBLAS(_A[p],BLAS_A[p]);
|
||||||
|
}
|
||||||
|
CoarsenReport(tphase,tphaseBZ,tslice,tmat,tproj,tinv);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Coarsen a SINGLE RHS fine operator.
|
||||||
|
//
|
||||||
|
// No multiRHS packing: the operator is applied once per phased basis
|
||||||
|
// vector and the batch is assembled on the coarse side by the mixed
|
||||||
|
// blockProject, which takes a vector of fine fields and writes the batch
|
||||||
|
// coarse field the accumulate expects. Only nbv applications per momentum,
|
||||||
|
// so a batch that does not divide nbasis wastes nothing, and the live fine
|
||||||
|
// storage is batch fields rather than two D+1 fields of extent batch.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void CoarsenOperator(LinearOperatorBase<Lattice<Fobj> > &linop,
|
||||||
|
std::vector<FineField> &Subspace,
|
||||||
|
GridBase *CoarseGrid,
|
||||||
|
int batch)
|
||||||
|
{
|
||||||
|
RealD tproj=0.0, tmat=0.0, tphase=0.0, tphaseBZ=0.0, tslice=0.0, tinv=0.0;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage<< "GeneralCoarsenMatrixMrhs (single RHS fine operator)"<< std::endl;
|
||||||
|
|
||||||
|
GRID_ASSERT(Subspace.size()==nbasis);
|
||||||
|
GRID_ASSERT(batch>=1);
|
||||||
|
GridBase *grid = Subspace[0].Grid();
|
||||||
|
|
||||||
|
Coordinate blatt,bsimd,bmpi;
|
||||||
|
CoarsenBlockGridLayout(grid,CoarseGrid,blatt,bsimd,bmpi);
|
||||||
|
GridCartesian BlockGrid(blatt,bsimd,bmpi);
|
||||||
|
|
||||||
|
BlockComplexField InnerProd(&BlockGrid);
|
||||||
|
blockOrthogonalise(InnerProd,Subspace);
|
||||||
|
|
||||||
|
MultiRHSBlockProject<Lattice<Fobj> > Projector;
|
||||||
|
Projector.Allocate(nbasis,grid,CoarseGrid);
|
||||||
|
Projector.ImportBasis(Subspace);
|
||||||
|
|
||||||
|
const int npoint = geom_srhs.npoint;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd invMkl;
|
||||||
|
CoarsenFourierMatrix(CoarseGrid,invMkl);
|
||||||
|
|
||||||
|
FineField phaV(grid);
|
||||||
|
std::vector<FineComplexField> phaF(npoint,grid);
|
||||||
|
std::vector<CoarseComplexField> pha (npoint,CoarseGrid);
|
||||||
|
|
||||||
|
tphase=-usecond();
|
||||||
|
CoarsenPhases(grid,CoarseGrid,&BlockGrid,pha,phaF);
|
||||||
|
tphase+=usecond();
|
||||||
|
|
||||||
|
std::vector<CoarseMatrix> _A;
|
||||||
|
_A.resize(npoint,CoarseGrid);
|
||||||
|
for(int k=0;k<npoint;k++) _A[k] = Zero();
|
||||||
|
|
||||||
|
Coordinate cmlatt,cmsimd,cmmpi;
|
||||||
|
CoarsenBatchGridLayout(CoarseGrid,batch,cmlatt,cmsimd,cmmpi);
|
||||||
|
GridCartesian CoarseBatchGrid(cmlatt,cmsimd,cmmpi);
|
||||||
|
|
||||||
|
CoarseVector TmpProj(&CoarseBatchGrid);
|
||||||
|
CoarseComplexField phaB(&CoarseBatchGrid);
|
||||||
|
|
||||||
|
std::vector<FineField> MphaV(batch,grid);
|
||||||
|
|
||||||
|
for(int i0=0;i0<nbasis;i0+=batch){ // Loop over batches of basis vectors
|
||||||
|
|
||||||
|
int nbv = MIN(batch,nbasis-i0);
|
||||||
|
std::cout << GridLogMessage<< "CoarsenMatrixColoured vec "<<i0<<"/"<<nbasis<< std::endl;
|
||||||
|
|
||||||
|
for(int p=0;p<npoint;p++){ // Loop over momenta
|
||||||
|
|
||||||
|
for(int b=0;b<nbv;b++){
|
||||||
|
tphaseBZ-=usecond();
|
||||||
|
phaV = phaF[p]*Subspace[i0+b];
|
||||||
|
tphaseBZ+=usecond();
|
||||||
|
tmat-=usecond();
|
||||||
|
linop.Op(phaV,MphaV[b]);
|
||||||
|
tmat+=usecond();
|
||||||
|
}
|
||||||
|
// The accumulate reads only the first nbv slices, but the projector
|
||||||
|
// sees the whole vector, so the tail must not be undefined.
|
||||||
|
for(int b=nbv;b<batch;b++) MphaV[b] = Zero();
|
||||||
|
|
||||||
|
tproj-=usecond();
|
||||||
|
Projector.blockProject(MphaV,TmpProj);
|
||||||
|
tproj+=usecond();
|
||||||
|
|
||||||
|
tinv-=usecond();
|
||||||
|
CoarsenAccumulate(p,i0,nbv,batch,invMkl,pha,phaB,TmpProj,_A,CoarseGrid);
|
||||||
|
tinv+=usecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int p=0;p<npoint;p++){
|
||||||
|
GridtoBLAS(_A[p],BLAS_A[p]);
|
||||||
|
}
|
||||||
|
CoarsenReport(tphase,tphaseBZ,tslice,tmat,tproj,tinv);
|
||||||
|
}
|
||||||
|
void Mdag(const CoarseVector &in, CoarseVector &out)
|
||||||
|
{
|
||||||
|
this->M(in,out);
|
||||||
|
}
|
||||||
|
void M (const CoarseVector &in, CoarseVector &out)
|
||||||
|
{
|
||||||
|
// std::cout << GridLogMessage << "New Mrhs coarse"<<std::endl;
|
||||||
|
conformable(CoarseGrid(),in.Grid());
|
||||||
|
conformable(in.Grid(),out.Grid());
|
||||||
|
out.Checkerboard() = in.Checkerboard();
|
||||||
|
|
||||||
|
RealD t_tot;
|
||||||
|
RealD t_exch;
|
||||||
|
RealD t_GtoB;
|
||||||
|
RealD t_BtoG;
|
||||||
|
RealD t_mult;
|
||||||
|
|
||||||
|
CheckGridSet();
|
||||||
|
if ( in.Grid() != _CoarseGridMulti ) {
|
||||||
|
std::cout << GridLogError
|
||||||
|
<< "MultiGeneralCoarsenedOperatorV2::M called with a field on a"
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << GridLogError
|
||||||
|
<< " different grid object from the one given to SetGrid(). Two"
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << GridLogError
|
||||||
|
<< " grids of identical shape do not conform; share one object."
|
||||||
|
<< std::endl;
|
||||||
|
GRID_ASSERT(in.Grid() == _CoarseGridMulti);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_tot=-usecond();
|
||||||
|
CoarseVector tin=in;
|
||||||
|
t_exch=-usecond();
|
||||||
|
CoarseVector pin = CellMulti->ExchangePeriodic(tin); //padded input
|
||||||
|
t_exch+=usecond();
|
||||||
|
|
||||||
|
CoarseVector pout(pin.Grid());
|
||||||
|
|
||||||
|
int npoint = geom.npoint;
|
||||||
|
typedef calcMatrix* Aview;
|
||||||
|
typedef LatticeView<Cvec> Vview;
|
||||||
|
|
||||||
|
const int Nsimd = CComplex::Nsimd();
|
||||||
|
|
||||||
|
int64_t nrhs =pin.Grid()->GlobalDimensions()[0];
|
||||||
|
GRID_ASSERT(nrhs>=1);
|
||||||
|
|
||||||
|
RealD flops,bytes;
|
||||||
|
int64_t osites=in.Grid()->oSites(); // unpadded
|
||||||
|
int64_t unpadded_vol = CoarseGrid()->lSites()/nrhs;
|
||||||
|
|
||||||
|
flops = 1.0* npoint * nbasis * nbasis * 8.0 * osites * CComplex::Nsimd();
|
||||||
|
bytes = 1.0*osites*sizeof(siteMatrix)*npoint/pin.Grid()->GlobalDimensions()[0]
|
||||||
|
+ 2.0*osites*sizeof(siteVector)*npoint;
|
||||||
|
|
||||||
|
|
||||||
|
t_GtoB=-usecond();
|
||||||
|
GridtoBLAS(pin,BLAS_B);
|
||||||
|
t_GtoB+=usecond();
|
||||||
|
|
||||||
|
GridBLAS BLAS;
|
||||||
|
|
||||||
|
t_mult=-usecond();
|
||||||
|
for(int p=0;p<geom.npoint;p++){
|
||||||
|
RealD c = 1.0;
|
||||||
|
if (p==0) c = 0.0;
|
||||||
|
ComplexD beta(c);
|
||||||
|
|
||||||
|
BLAS.gemmBatched(nbasis,nrhs,nbasis,
|
||||||
|
ComplexD(1.0),
|
||||||
|
BLAS_AP[p],
|
||||||
|
BLAS_BP[p],
|
||||||
|
ComplexD(c),
|
||||||
|
BLAS_CP);
|
||||||
|
}
|
||||||
|
BLAS.synchronise();
|
||||||
|
t_mult+=usecond();
|
||||||
|
|
||||||
|
t_BtoG=-usecond();
|
||||||
|
BLAStoGrid(out,BLAS_C);
|
||||||
|
t_BtoG+=usecond();
|
||||||
|
t_tot+=usecond();
|
||||||
|
/*
|
||||||
|
std::cout << GridLogMessage << "New Mrhs coarse DONE "<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"Coarse Mult exch "<<t_exch<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"Coarse Mult mult "<<t_mult<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"Coarse Mult GtoB "<<t_GtoB<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"Coarse Mult BtoG "<<t_BtoG<<" us"<<std::endl;
|
||||||
|
std::cout << GridLogMessage<<"Coarse Mult tot "<<t_tot<<" us"<<std::endl;
|
||||||
|
*/
|
||||||
|
// std::cout << GridLogMessage<<std::endl;
|
||||||
|
// std::cout << GridLogMessage<<"Coarse Kernel flops "<< flops<<std::endl;
|
||||||
|
// std::cout << GridLogMessage<<"Coarse Kernel flop/s "<< flops/t_mult<<" mflop/s"<<std::endl;
|
||||||
|
// std::cout << GridLogMessage<<"Coarse Kernel bytes/s "<< bytes/t_mult/1000<<" GB/s"<<std::endl;
|
||||||
|
// std::cout << GridLogMessage<<"Coarse overall flops/s "<< flops/t_tot<<" mflop/s"<<std::endl;
|
||||||
|
// std::cout << GridLogMessage<<"Coarse total bytes "<< bytes/1e6<<" MB"<<std::endl;
|
||||||
|
};
|
||||||
|
virtual void Mdiag (const Field &in, Field &out){ GRID_ASSERT(0);};
|
||||||
|
virtual void Mdir (const Field &in, Field &out,int dir, int disp){assert(0);};
|
||||||
|
virtual void MdirAll (const Field &in, std::vector<Field> &out){assert(0);};
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/multigrid/MrhsPromotedOperator.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Present a D dimensional operator as a D+1 dimensional operator with Nrhs in
|
||||||
|
// dimension 0. Field type is unchanged; only the Grid differs, so this is a
|
||||||
|
// LinearOperatorBase and callers need no template parameter: a native mrhs
|
||||||
|
// operator derives from the same base and substitutes without a call site
|
||||||
|
// change.
|
||||||
|
//
|
||||||
|
// Slices in and out around the wrapped operator. No arithmetic beyond the
|
||||||
|
// wrapped call, but one ExtractSliceFast/InsertSliceFast pair per right hand
|
||||||
|
// side: data motion, not work.
|
||||||
|
//
|
||||||
|
// AdjOp is carried so that A^dag may be coarsened as a separate coarse
|
||||||
|
// operator when needed, rather than doubling coarse storage.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Field>
|
||||||
|
class MrhsPromotedOperator : public LinearOperatorBase<Field>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
LinearOperatorBase<Field> &_LinOp;
|
||||||
|
GridBase *_LowGrid;
|
||||||
|
int _Nrhs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MrhsPromotedOperator(LinearOperatorBase<Field> &LinOp,GridBase *LowGrid,int Nrhs)
|
||||||
|
: _LinOp(LinOp), _LowGrid(LowGrid), _Nrhs(Nrhs)
|
||||||
|
{
|
||||||
|
GRID_ASSERT(_Nrhs>=1);
|
||||||
|
}
|
||||||
|
|
||||||
|
GridBase *LowGrid(void) { return _LowGrid; }
|
||||||
|
int Nrhs(void) { return _Nrhs; }
|
||||||
|
|
||||||
|
// Reset on each call; retrieve and accumulate in the caller
|
||||||
|
RealD tslice;
|
||||||
|
RealD top;
|
||||||
|
|
||||||
|
void OpDiag (const Field &in, Field &out)
|
||||||
|
{
|
||||||
|
SliceLoop(in,out,[&](Field &i,Field &o){ _LinOp.OpDiag(i,o); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Op (const Field &in, Field &out)
|
||||||
|
{
|
||||||
|
SliceLoop(in,out,[&](Field &i,Field &o){ _LinOp.Op(i,o); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdjOp (const Field &in, Field &out)
|
||||||
|
{
|
||||||
|
SliceLoop(in,out,[&](Field &i,Field &o){ _LinOp.AdjOp(i,o); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void HermOp (const Field &in, Field &out)
|
||||||
|
{
|
||||||
|
SliceLoop(in,out,[&](Field &i,Field &o){ _LinOp.HermOp(i,o); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpDir (const Field &in, Field &out,int dir,int disp)
|
||||||
|
{
|
||||||
|
SliceLoop(in,out,[&](Field &i,Field &o){ _LinOp.OpDir(i,o,dir,disp); });
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// Norms of the D+1 field are the sums over slices
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
void HermOpAndNorm(const Field &in, Field &out,RealD &n1,RealD &n2)
|
||||||
|
{
|
||||||
|
Conformable(in,out);
|
||||||
|
Field lo_in (_LowGrid);
|
||||||
|
Field lo_out(_LowGrid);
|
||||||
|
n1=0.0;
|
||||||
|
n2=0.0;
|
||||||
|
for(int r=0;r<_Nrhs;r++){
|
||||||
|
RealD r1,r2;
|
||||||
|
ExtractSliceFast(lo_in,in,r,0);
|
||||||
|
_LinOp.HermOpAndNorm(lo_in,lo_out,r1,r2);
|
||||||
|
InsertSliceFast(lo_out,out,r,0);
|
||||||
|
n1=n1+r1;
|
||||||
|
n2=n2+r2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpDirAll(const Field &in, std::vector<Field> &out)
|
||||||
|
{
|
||||||
|
int npoint = out.size();
|
||||||
|
Field lo_in(_LowGrid);
|
||||||
|
std::vector<Field> lo_out(npoint,_LowGrid);
|
||||||
|
for(int r=0;r<_Nrhs;r++){
|
||||||
|
ExtractSliceFast(lo_in,in,r,0);
|
||||||
|
_LinOp.OpDirAll(lo_in,lo_out);
|
||||||
|
for(int p=0;p<npoint;p++){
|
||||||
|
InsertSliceFast(lo_out[p],out[p],r,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Conformable(const Field &in,const Field &out)
|
||||||
|
{
|
||||||
|
conformable(in.Grid(),out.Grid());
|
||||||
|
GRID_ASSERT(in.Grid()->_ndimension == _LowGrid->_ndimension+1);
|
||||||
|
GRID_ASSERT(in.Grid()->_fdimensions[0] == _Nrhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Kernel>
|
||||||
|
void SliceLoop(const Field &in,Field &out,Kernel K)
|
||||||
|
{
|
||||||
|
Conformable(in,out);
|
||||||
|
Field lo_in (_LowGrid);
|
||||||
|
Field lo_out(_LowGrid);
|
||||||
|
tslice=0.0;
|
||||||
|
top=0.0;
|
||||||
|
for(int r=0;r<_Nrhs;r++){
|
||||||
|
tslice-=usecond();
|
||||||
|
ExtractSliceFast(lo_in,in,r,0);
|
||||||
|
tslice+=usecond();
|
||||||
|
top-=usecond();
|
||||||
|
K(lo_in,lo_out);
|
||||||
|
top+=usecond();
|
||||||
|
tslice-=usecond();
|
||||||
|
InsertSliceFast(lo_out,out,r,0);
|
||||||
|
tslice+=usecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -32,3 +32,5 @@ Author: Peter Boyle <pboyle@bnl.gov>
|
|||||||
#include <Grid/algorithms/multigrid/CoarsenedMatrix.h>
|
#include <Grid/algorithms/multigrid/CoarsenedMatrix.h>
|
||||||
#include <Grid/algorithms/multigrid/GeneralCoarsenedMatrix.h>
|
#include <Grid/algorithms/multigrid/GeneralCoarsenedMatrix.h>
|
||||||
#include <Grid/algorithms/multigrid/GeneralCoarsenedMatrixMultiRHS.h>
|
#include <Grid/algorithms/multigrid/GeneralCoarsenedMatrixMultiRHS.h>
|
||||||
|
#include <Grid/algorithms/multigrid/GeneralCoarsenedMatrixMultiRHSV2.h>
|
||||||
|
#include <Grid/algorithms/multigrid/MrhsPromotedOperator.h>
|
||||||
|
|||||||
@@ -0,0 +1,617 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: RecursiveSchurInverse.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Grid/algorithms/blas/BatchedBlas.h>
|
||||||
|
#include <Grid/algorithms/blas/BatchedInverse.h>
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RecursiveSchurInverse: distributed dense inversion by recursive Schur
|
||||||
|
// complement over a binary rank-range tree.
|
||||||
|
//
|
||||||
|
// Contract: rank r owns global rows [rowStart[r], rowStart[r+1]) of an
|
||||||
|
// N x N matrix in rank-major ordering, and receives its rows of the
|
||||||
|
// inverse in the same layout. Consumes GridBase collectives, GridBLAS
|
||||||
|
// and GridBLASInverse only; Eigen reference backends permit CPU unit
|
||||||
|
// testing under mpirun (Test_schur_inverse).
|
||||||
|
//
|
||||||
|
// Arithmetic is fp64 throughout; the caller rounds once into fp32 storage.
|
||||||
|
//
|
||||||
|
// Execution: SPMD full-tree walk. Every rank makes the identical call
|
||||||
|
// sequence; data participation is ownership-gated; all collectives are
|
||||||
|
// world-wide, so no deadlock surface exists.
|
||||||
|
//
|
||||||
|
// Storage: BlockRows is column-major, ld = rows; element (i,j) at
|
||||||
|
// data[i + j*ld]; a column window is the contiguous slice at data[col0*ld].
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// My rows of a distributed dense matrix: rows x cols, column major, ld = rows.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
class BlockRows
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
deviceVector<ComplexD> data;
|
||||||
|
int64_t rows;
|
||||||
|
int64_t cols;
|
||||||
|
int64_t ld;
|
||||||
|
|
||||||
|
BlockRows()
|
||||||
|
{
|
||||||
|
rows = 0;
|
||||||
|
cols = 0;
|
||||||
|
ld = 0;
|
||||||
|
}
|
||||||
|
void Resize(int64_t r, int64_t c)
|
||||||
|
{
|
||||||
|
rows = r;
|
||||||
|
cols = c;
|
||||||
|
ld = r;
|
||||||
|
data.resize((uint64_t)r*c);
|
||||||
|
}
|
||||||
|
ComplexD *ColumnWindow(int64_t col0)
|
||||||
|
{
|
||||||
|
GRID_ASSERT( col0 >= 0 );
|
||||||
|
GRID_ASSERT( col0 <= cols );
|
||||||
|
return &data[(uint64_t)col0*ld];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RecursiveSchurInverse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GridBase *grid; // world collectives only
|
||||||
|
int64_t N; // global matrix dimension
|
||||||
|
int P; // ranks
|
||||||
|
int me; // this rank
|
||||||
|
std::vector<int64_t> rowStart; // P+1 entries: rank-major row ownership
|
||||||
|
int64_t myRow0;
|
||||||
|
int64_t myNrows;
|
||||||
|
int64_t panelBytes; // gather panel budget (DENSE_PANEL_BYTES)
|
||||||
|
|
||||||
|
GridBLAS BLAS;
|
||||||
|
GridBLASInverse INV;
|
||||||
|
|
||||||
|
// Growth telemetry: one entry per merge node, walk order
|
||||||
|
std::vector<double> telNormB; // ||B||_F = ||A11inv A12||_F
|
||||||
|
std::vector<double> telSratio; // ||S||_F / ||A22||_F
|
||||||
|
double telLeafMaxInv; // max |(leaf inverse)_ij| over leaves
|
||||||
|
|
||||||
|
// Phase timers/counters, reported by ReportTelemetry
|
||||||
|
double tMemset; // device panel zero-fill
|
||||||
|
double tDeposit; // owner rows -> panel (device kernel)
|
||||||
|
double tAllreduce; // GlobalSumVector on device panels
|
||||||
|
double tGemm; // strided gemm + synchronise
|
||||||
|
double tLeaf; // leaf inversions
|
||||||
|
double tARmin; // fastest single panel collective
|
||||||
|
double tARmax; // slowest single panel collective
|
||||||
|
uint64_t bytesAllreduce;
|
||||||
|
uint64_t nAllreduce; // panel collectives
|
||||||
|
uint64_t nGatherGemm; // GatherGemm calls
|
||||||
|
|
||||||
|
// Persistent grow-only device panel; assembly and collectives are
|
||||||
|
// device-resident. Device builds require GPU-aware MPI.
|
||||||
|
deviceVector<ComplexD> dPanelBuf;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Ownership-table validation: a proper partition of [0,N).
|
||||||
|
// Static and communicator-free so synthetic tables unit-test directly.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
static void CheckRowStart(const std::vector<int64_t> &table, int64_t N)
|
||||||
|
{
|
||||||
|
int P = (int)table.size() - 1;
|
||||||
|
GRID_ASSERT( P >= 1 );
|
||||||
|
GRID_ASSERT( table[0] == 0 );
|
||||||
|
GRID_ASSERT( table[P] == N );
|
||||||
|
for(int r=0; r<P; r++)
|
||||||
|
{
|
||||||
|
GRID_ASSERT( table[r+1] >= table[r] ); // zero-row ranks permitted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Build the ownership table from each rank's local row count: zero-fill
|
||||||
|
// allgather (the standing comms idiom) then prefix sum. Every rank
|
||||||
|
// returns the identical table.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
static std::vector<int64_t> MakeRowStart(GridBase *g, int64_t myNrows)
|
||||||
|
{
|
||||||
|
int P = g->ProcessorCount();
|
||||||
|
int me = g->ThisRank();
|
||||||
|
|
||||||
|
std::vector<uint64_t> counts(P, 0);
|
||||||
|
counts[me] = (uint64_t)myNrows;
|
||||||
|
g->GlobalSumVector(&counts[0], P);
|
||||||
|
|
||||||
|
std::vector<int64_t> table(P+1);
|
||||||
|
table[0] = 0;
|
||||||
|
for(int r=0; r<P; r++)
|
||||||
|
{
|
||||||
|
table[r+1] = table[r] + (int64_t)counts[r];
|
||||||
|
}
|
||||||
|
CheckRowStart(table, table[P]);
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecursiveSchurInverse(GridBase *g,
|
||||||
|
int64_t N_,
|
||||||
|
std::vector<int64_t> &rowStart_,
|
||||||
|
int64_t panelBytes_)
|
||||||
|
{
|
||||||
|
grid = g;
|
||||||
|
N = N_;
|
||||||
|
P = g->ProcessorCount();
|
||||||
|
me = g->ThisRank();
|
||||||
|
rowStart = rowStart_;
|
||||||
|
panelBytes = panelBytes_;
|
||||||
|
|
||||||
|
GRID_ASSERT( (int)rowStart.size() == P+1 );
|
||||||
|
CheckRowStart(rowStart, N);
|
||||||
|
|
||||||
|
myRow0 = rowStart[me];
|
||||||
|
myNrows = rowStart[me+1] - rowStart[me];
|
||||||
|
|
||||||
|
telLeafMaxInv = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// The communication primitive.
|
||||||
|
//
|
||||||
|
// C(:, colC : colC+widthB) <- beta * C(:, colC : colC+widthB)
|
||||||
|
// + alpha * A(:, colA : colA+widthA) * Bsub
|
||||||
|
//
|
||||||
|
// Bsub is the widthA x widthB sub-block of a row-distributed operand
|
||||||
|
// owned by ranks [rB0, rB1): owner r contributes its rows of
|
||||||
|
// B(:, colB : colB+widthB) at sub-block row offset
|
||||||
|
// rowStart[r] - rowStart[rB0], gathered in panelBytes row-chunks by
|
||||||
|
// device zero-fill + deposit kernel + GlobalSumVector.
|
||||||
|
//
|
||||||
|
// Every rank calls; non-owners of B add zeros; ranks with A.rows == 0
|
||||||
|
// skip local compute but make every collective call. Column offsets
|
||||||
|
// are local buffer offsets -- non-participants pass 0.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void GatherGemm(ComplexD alpha,
|
||||||
|
BlockRows &A, int64_t colA, int64_t widthA,
|
||||||
|
int rB0, int rB1,
|
||||||
|
BlockRows &B, int64_t colB, int64_t widthB,
|
||||||
|
ComplexD beta,
|
||||||
|
BlockRows &C, int64_t colC)
|
||||||
|
{
|
||||||
|
GRID_ASSERT( rB0 >= 0 );
|
||||||
|
GRID_ASSERT( rB1 > rB0 );
|
||||||
|
GRID_ASSERT( rB1 <= P );
|
||||||
|
|
||||||
|
int64_t k = rowStart[rB1] - rowStart[rB0];
|
||||||
|
int64_t m = A.rows;
|
||||||
|
int64_t n = widthB;
|
||||||
|
GRID_ASSERT( widthA == k );
|
||||||
|
GRID_ASSERT( n >= 1 );
|
||||||
|
|
||||||
|
int owner = ( me >= rB0 ) && ( me < rB1 ) && ( B.rows > 0 );
|
||||||
|
int64_t myOff = 0;
|
||||||
|
if ( owner )
|
||||||
|
{
|
||||||
|
myOff = rowStart[me] - rowStart[rB0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m > 0 )
|
||||||
|
{
|
||||||
|
GRID_ASSERT( colA + widthA <= A.cols );
|
||||||
|
GRID_ASSERT( colC + widthB <= C.cols );
|
||||||
|
GRID_ASSERT( C.rows == m );
|
||||||
|
}
|
||||||
|
|
||||||
|
nGatherGemm++;
|
||||||
|
GRID_TRACE("GatherGemm");
|
||||||
|
|
||||||
|
if ( owner )
|
||||||
|
{
|
||||||
|
GRID_ASSERT( colB + widthB <= B.cols );
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t kc = panelBytes / ( (int64_t)sizeof(ComplexD) * n );
|
||||||
|
if ( kc < 1 ) kc = 1;
|
||||||
|
if ( kc > k ) kc = k;
|
||||||
|
GRID_ASSERT( kc*n < 2147483647L ); // GlobalSumVector count is int
|
||||||
|
|
||||||
|
deviceVector<ComplexD> &dPanel = dPanelBuf;
|
||||||
|
if ( dPanel.size() < (uint64_t)kc*n ) dPanel.resize((uint64_t)kc*n);
|
||||||
|
deviceVector<ComplexD*> ap(1);
|
||||||
|
deviceVector<ComplexD*> bp(1);
|
||||||
|
deviceVector<ComplexD*> cp(1);
|
||||||
|
std::vector<ComplexD*> ptr(1);
|
||||||
|
|
||||||
|
for(int64_t k0=0; k0<k; k0+=kc)
|
||||||
|
{
|
||||||
|
int64_t kchunk = std::min(kc, k-k0);
|
||||||
|
|
||||||
|
// Zeroing must complete before MPI reads the panel; it is the sole
|
||||||
|
// producer on non-owner ranks.
|
||||||
|
tMemset -= usecond();
|
||||||
|
acceleratorMemSet(&dPanel[0], 0, (uint64_t)kchunk*n*sizeof(ComplexD));
|
||||||
|
tMemset += usecond();
|
||||||
|
if ( owner )
|
||||||
|
{
|
||||||
|
int64_t i0 = std::max(k0, myOff);
|
||||||
|
int64_t i1 = std::min(k0+kchunk, myOff+B.rows);
|
||||||
|
if ( i1 > i0 )
|
||||||
|
{
|
||||||
|
// Deposit my rows: strided block copy, len rows x n columns
|
||||||
|
int64_t len = i1-i0;
|
||||||
|
int64_t brows = B.rows;
|
||||||
|
int64_t dof = i0-k0;
|
||||||
|
int64_t sof = i0-myOff;
|
||||||
|
ComplexD *src = B.ColumnWindow(colB);
|
||||||
|
ComplexD *dst = &dPanel[0];
|
||||||
|
tDeposit -= usecond();
|
||||||
|
accelerator_for(idx, (uint64_t)(len*n), 1, {
|
||||||
|
int64_t j = idx / len;
|
||||||
|
int64_t i = idx % len;
|
||||||
|
dst[(uint64_t)(dof + i + j*kchunk)] = src[(uint64_t)(sof + i + j*brows)];
|
||||||
|
});
|
||||||
|
tDeposit += usecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double tar = -usecond();
|
||||||
|
grid->GlobalSumVector(&dPanel[0], (int)(kchunk*n));
|
||||||
|
tar += usecond();
|
||||||
|
tAllreduce += tar;
|
||||||
|
tARmin = std::min(tARmin, tar);
|
||||||
|
tARmax = std::max(tARmax, tar);
|
||||||
|
bytesAllreduce += (uint64_t)kchunk*n*sizeof(ComplexD);
|
||||||
|
nAllreduce++;
|
||||||
|
|
||||||
|
if ( m > 0 )
|
||||||
|
{
|
||||||
|
ComplexD beta_use = ( k0==0 ) ? beta : ComplexD(1.0,0.0);
|
||||||
|
|
||||||
|
ptr[0] = A.ColumnWindow(colA + k0);
|
||||||
|
acceleratorCopyToDevice(&ptr[0], &ap[0], sizeof(ComplexD*));
|
||||||
|
ptr[0] = &dPanel[0];
|
||||||
|
acceleratorCopyToDevice(&ptr[0], &bp[0], sizeof(ComplexD*));
|
||||||
|
ptr[0] = C.ColumnWindow(colC);
|
||||||
|
acceleratorCopyToDevice(&ptr[0], &cp[0], sizeof(ComplexD*));
|
||||||
|
|
||||||
|
tGemm -= usecond();
|
||||||
|
BLAS.gemmBatched(GridBLAS_OP_N, GridBLAS_OP_N,
|
||||||
|
(int)m, (int)n, (int)kchunk,
|
||||||
|
alpha, ap, (int)A.ld,
|
||||||
|
bp, (int)kchunk,
|
||||||
|
beta_use, cp, (int)C.ld);
|
||||||
|
BLAS.synchronise();
|
||||||
|
tGemm += usecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Local Frobenius norm-squared of a full-height column window.
|
||||||
|
// NO comms; callers GlobalSum the result. Host staging, setup-scale.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
double FrobNorm2Local(BlockRows &X, int64_t col0, int64_t w)
|
||||||
|
{
|
||||||
|
if ( X.rows == 0 ) return 0.0;
|
||||||
|
GRID_ASSERT( col0 + w <= X.cols );
|
||||||
|
uint64_t len = (uint64_t)X.rows*w;
|
||||||
|
std::vector<ComplexD> h(len);
|
||||||
|
acceleratorCopyFromDevice(X.ColumnWindow(col0), &h[0], len*sizeof(ComplexD));
|
||||||
|
// Member real()/imag(): portable across std::complex (CPU) and
|
||||||
|
// thrust::complex (HIP), where std::norm does not resolve.
|
||||||
|
double s = 0.0;
|
||||||
|
for(uint64_t i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
double re = h[i].real();
|
||||||
|
double im = h[i].imag();
|
||||||
|
s += re*re + im*im;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// dst(:, dcol0 : dcol0+w) = - src(:, 0:w). Both operands have ld == rows
|
||||||
|
// so full-height windows are contiguous: flat elementwise device copy.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void NegateCopy(BlockRows &src, BlockRows &dst, int64_t dcol0, int64_t w)
|
||||||
|
{
|
||||||
|
GRID_ASSERT( src.rows == dst.rows );
|
||||||
|
GRID_ASSERT( w <= src.cols );
|
||||||
|
GRID_ASSERT( dcol0 + w <= dst.cols );
|
||||||
|
if ( src.rows == 0 ) return;
|
||||||
|
uint64_t len = (uint64_t)src.rows*w;
|
||||||
|
ComplexD *s = &src.data[0];
|
||||||
|
ComplexD *d = dst.ColumnWindow(dcol0);
|
||||||
|
accelerator_for(i, len, 1, {
|
||||||
|
d[i] = -s[i];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Leaf inversion: local, in place on the contiguous diagonal window.
|
||||||
|
// No collectives.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void LeafInvert(int64_t col0, int64_t width, BlockRows &Arows)
|
||||||
|
{
|
||||||
|
GRID_TRACE("SchurLeaf");
|
||||||
|
GRID_ASSERT( width == Arows.rows );
|
||||||
|
GRID_ASSERT( col0 + width <= Arows.cols );
|
||||||
|
int64_t w = width;
|
||||||
|
uint64_t len = (uint64_t)w*w;
|
||||||
|
tLeaf -= usecond();
|
||||||
|
|
||||||
|
deviceVector<ComplexD*> bp(1);
|
||||||
|
std::vector<ComplexD*> ptr(1);
|
||||||
|
ptr[0] = Arows.ColumnWindow(col0);
|
||||||
|
acceleratorCopyToDevice(&ptr[0], &bp[0], sizeof(ComplexD*));
|
||||||
|
INV.inverseBatched(w, bp);
|
||||||
|
|
||||||
|
// Telemetry: max |element| of the leaf inverse
|
||||||
|
{
|
||||||
|
std::vector<ComplexD> h(len);
|
||||||
|
acceleratorCopyFromDevice(Arows.ColumnWindow(col0), &h[0], len*sizeof(ComplexD));
|
||||||
|
double mx = 0.0;
|
||||||
|
for(uint64_t i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
double re = h[i].real();
|
||||||
|
double im = h[i].imag();
|
||||||
|
mx = std::max(mx, re*re + im*im);
|
||||||
|
}
|
||||||
|
telLeafMaxInv = std::max(telLeafMaxInv, std::sqrt(mx));
|
||||||
|
}
|
||||||
|
tLeaf += usecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// The recursion (plan 3.5 / 4B.3). Inverts the diagonal block of the
|
||||||
|
// rank-major matrix spanned by ranks [r0, r1), living in every member
|
||||||
|
// rank's column window [col0, col0+width) -- IN PLACE.
|
||||||
|
//
|
||||||
|
// SPMD: every rank calls with IDENTICAL (r0, r1, width) and its own
|
||||||
|
// local (col0, Arows); ranks outside [r0, r1) participate in the
|
||||||
|
// collectives only (dummy operands, zero contributions). The collective
|
||||||
|
// sequence -- 5 GatherGemm calls + 3 scalar GlobalSums per merge node --
|
||||||
|
// is identical on every rank by construction.
|
||||||
|
//
|
||||||
|
// I = [r0, mid) J = [mid, r1) widths WI, WJ
|
||||||
|
// 1. recurse I: A11 -> A11inv
|
||||||
|
// 2. B = A11inv.A12 (I rows)
|
||||||
|
// 3. C = A21.A11inv (J rows)
|
||||||
|
// 4. S = A22 - A21.B in place (J rows) [alpha=-1, beta=1]
|
||||||
|
// 5. recurse J: S -> Sinv
|
||||||
|
// 6. T = Sinv.C (J rows)
|
||||||
|
// 7. U = B.Sinv (I rows)
|
||||||
|
// 8. X11 = A11inv + U.C in place (I rows) [beta=1]
|
||||||
|
// 9. X12 = -U, X21 = -T local negates; X22 = Sinv already in place
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void SchurNode(int r0, int r1, int64_t col0, int64_t width, BlockRows &Arows)
|
||||||
|
{
|
||||||
|
int span = r1 - r0;
|
||||||
|
GRID_ASSERT( span >= 1 );
|
||||||
|
GRID_ASSERT( width == rowStart[r1] - rowStart[r0] );
|
||||||
|
|
||||||
|
if ( span == 1 )
|
||||||
|
{
|
||||||
|
if ( ( me == r0 ) && ( myNrows > 0 ) )
|
||||||
|
{
|
||||||
|
LeafInvert(col0, width, Arows);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mid = ( r0 + r1 ) / 2;
|
||||||
|
int64_t WI = rowStart[mid] - rowStart[r0];
|
||||||
|
int64_t WJ = rowStart[r1] - rowStart[mid];
|
||||||
|
|
||||||
|
// Zero-width child ranges (all ranks of a half owning no rows) are a
|
||||||
|
// KNOWN LIMITATION: fail loudly rather than divide mysteriously.
|
||||||
|
GRID_ASSERT( WI > 0 );
|
||||||
|
GRID_ASSERT( WJ > 0 );
|
||||||
|
|
||||||
|
int inI = ( me >= r0 ) && ( me < mid );
|
||||||
|
int inJ = ( me >= mid ) && ( me < r1 );
|
||||||
|
|
||||||
|
ComplexD one ( 1.0,0.0);
|
||||||
|
ComplexD mone (-1.0,0.0);
|
||||||
|
ComplexD zero ( 0.0,0.0);
|
||||||
|
|
||||||
|
BlockRows dummy;
|
||||||
|
|
||||||
|
// 1. A11 -> A11inv
|
||||||
|
SchurNode(r0, mid, col0, WI, Arows);
|
||||||
|
|
||||||
|
// 2. B = A11inv . A12 (I rows; gather A12 from I owners)
|
||||||
|
BlockRows Bbuf;
|
||||||
|
if ( inI ) Bbuf.Resize(myNrows, WJ);
|
||||||
|
{
|
||||||
|
BlockRows &Aop = inI ? Arows : dummy;
|
||||||
|
BlockRows &Cop = inI ? Bbuf : dummy;
|
||||||
|
int64_t cA = inI ? col0 : 0;
|
||||||
|
GatherGemm(one, Aop, cA, WI,
|
||||||
|
r0, mid,
|
||||||
|
Arows, col0+WI, WJ,
|
||||||
|
zero, Cop, 0);
|
||||||
|
}
|
||||||
|
double nB = FrobNorm2Local(Bbuf, 0, inI ? WJ : 0);
|
||||||
|
grid->GlobalSumVector(&nB, 1);
|
||||||
|
telNormB.push_back(std::sqrt(nB));
|
||||||
|
|
||||||
|
// 3. C = A21 . A11inv (J rows; gather A11inv from I owners)
|
||||||
|
BlockRows Cbuf;
|
||||||
|
if ( inJ ) Cbuf.Resize(myNrows, WI);
|
||||||
|
{
|
||||||
|
BlockRows &Aop = inJ ? Arows : dummy;
|
||||||
|
BlockRows &Cop = inJ ? Cbuf : dummy;
|
||||||
|
int64_t cA = inJ ? col0 : 0;
|
||||||
|
GatherGemm(one, Aop, cA, WI,
|
||||||
|
r0, mid,
|
||||||
|
Arows, col0, WI,
|
||||||
|
zero, Cop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. S = A22 - A21 . B in place on my A22 window (J rows)
|
||||||
|
double nA22 = FrobNorm2Local( inJ ? Arows : dummy, inJ ? col0+WI : 0, inJ ? WJ : 0 );
|
||||||
|
grid->GlobalSumVector(&nA22, 1);
|
||||||
|
{
|
||||||
|
BlockRows &Aop = inJ ? Arows : dummy;
|
||||||
|
BlockRows &Cop = inJ ? Arows : dummy;
|
||||||
|
int64_t cA = inJ ? col0 : 0;
|
||||||
|
int64_t cC = inJ ? col0+WI : 0;
|
||||||
|
GatherGemm(mone, Aop, cA, WI,
|
||||||
|
r0, mid,
|
||||||
|
Bbuf, 0, WJ,
|
||||||
|
one, Cop, cC);
|
||||||
|
}
|
||||||
|
double nS = FrobNorm2Local( inJ ? Arows : dummy, inJ ? col0+WI : 0, inJ ? WJ : 0 );
|
||||||
|
grid->GlobalSumVector(&nS, 1);
|
||||||
|
telSratio.push_back( std::sqrt(nS) / ( std::sqrt(nA22) + 1.0e-300 ) );
|
||||||
|
|
||||||
|
// 5. S -> Sinv
|
||||||
|
SchurNode(mid, r1, col0+WI, WJ, Arows);
|
||||||
|
|
||||||
|
// 6. T = Sinv . C (J rows; gather C from J owners)
|
||||||
|
BlockRows Tbuf;
|
||||||
|
if ( inJ ) Tbuf.Resize(myNrows, WI);
|
||||||
|
{
|
||||||
|
BlockRows &Aop = inJ ? Arows : dummy;
|
||||||
|
BlockRows &Cop = inJ ? Tbuf : dummy;
|
||||||
|
int64_t cA = inJ ? col0+WI : 0;
|
||||||
|
GatherGemm(one, Aop, cA, WJ,
|
||||||
|
mid, r1,
|
||||||
|
Cbuf, 0, WI,
|
||||||
|
zero, Cop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. U = B . Sinv (I rows; gather Sinv from J owners)
|
||||||
|
BlockRows Ubuf;
|
||||||
|
if ( inI ) Ubuf.Resize(myNrows, WJ);
|
||||||
|
{
|
||||||
|
BlockRows &Aop = inI ? Bbuf : dummy;
|
||||||
|
BlockRows &Cop = inI ? Ubuf : dummy;
|
||||||
|
GatherGemm(one, Aop, 0, WJ,
|
||||||
|
mid, r1,
|
||||||
|
Arows, col0+WI, WJ,
|
||||||
|
zero, Cop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. X11 = A11inv + U . C in place (I rows; gather C from J owners)
|
||||||
|
{
|
||||||
|
BlockRows &Aop = inI ? Ubuf : dummy;
|
||||||
|
BlockRows &Cop = inI ? Arows : dummy;
|
||||||
|
int64_t cC = inI ? col0 : 0;
|
||||||
|
GatherGemm(one, Aop, 0, WJ,
|
||||||
|
mid, r1,
|
||||||
|
Cbuf, 0, WI,
|
||||||
|
one, Cop, cC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. Off-diagonal signs, local
|
||||||
|
if ( inI ) NegateCopy(Ubuf, Arows, col0+WI, WJ);
|
||||||
|
if ( inJ ) NegateCopy(Tbuf, Arows, col0, WI);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC ENTRY. Arows: my rows of the rank-major N x N matrix (fp64).
|
||||||
|
// On exit Arows holds my rows of the inverse, still fp64; the caller
|
||||||
|
// owns the single terminal rounding into its fp32 apply storage.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
void Invert(BlockRows &Arows)
|
||||||
|
{
|
||||||
|
GRID_ASSERT( Arows.rows == myNrows );
|
||||||
|
GRID_ASSERT( Arows.cols == N );
|
||||||
|
|
||||||
|
telNormB.resize(0);
|
||||||
|
telSratio.resize(0);
|
||||||
|
telLeafMaxInv = 0.0;
|
||||||
|
|
||||||
|
tMemset = 0.0;
|
||||||
|
tDeposit = 0.0;
|
||||||
|
tAllreduce = 0.0;
|
||||||
|
tGemm = 0.0;
|
||||||
|
tLeaf = 0.0;
|
||||||
|
tARmin = 1.0e30;
|
||||||
|
tARmax = 0.0;
|
||||||
|
bytesAllreduce = 0;
|
||||||
|
nAllreduce = 0;
|
||||||
|
nGatherGemm = 0;
|
||||||
|
|
||||||
|
SchurNode(0, P, 0, N, Arows);
|
||||||
|
|
||||||
|
RealD mx = telLeafMaxInv;
|
||||||
|
grid->GlobalMax(mx);
|
||||||
|
telLeafMaxInv = mx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All telemetry values are globally reduced or boss-local; safe to
|
||||||
|
// stream on every rank (Grid quiesces stdout to the boss unless
|
||||||
|
// --debug-stdout). NOTE: tAllreduce INCLUDES wait/imbalance -- a rank
|
||||||
|
// arriving early books its wait here; the min/max spread across ranks
|
||||||
|
// separates true wire time (~min) from skew (max-min).
|
||||||
|
void ReportTelemetry(void)
|
||||||
|
{
|
||||||
|
for(uint64_t i=0; i<telNormB.size(); i++)
|
||||||
|
{
|
||||||
|
std::cout << GridLogPerformance
|
||||||
|
<< "SchurNode " << i
|
||||||
|
<< " ||B||_F " << telNormB[i]
|
||||||
|
<< " ||S||/||A22|| " << telSratio[i]
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
std::cout << GridLogPerformance
|
||||||
|
<< "Schur leaves max|Ainv| " << telLeafMaxInv
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
RealD armax = tAllreduce;
|
||||||
|
RealD armin = -tAllreduce;
|
||||||
|
grid->GlobalMax(armax);
|
||||||
|
grid->GlobalMax(armin);
|
||||||
|
armin = -armin;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Schur phases (boss rank, seconds):"
|
||||||
|
<< " memset " << tMemset/1.0e6
|
||||||
|
<< " deposit " << tDeposit/1.0e6
|
||||||
|
<< " allreduce " << tAllreduce/1.0e6
|
||||||
|
<< " gemm " << tGemm/1.0e6
|
||||||
|
<< " leaf " << tLeaf/1.0e6
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << GridLogMessage << "Schur comms:"
|
||||||
|
<< " GatherGemm calls " << nGatherGemm
|
||||||
|
<< " panel allreduces " << nAllreduce
|
||||||
|
<< " allreduce GB " << bytesAllreduce/1024./1024./1024.
|
||||||
|
<< " allreduce s min/max over ranks " << armin/1.0e6
|
||||||
|
<< " / " << armax/1.0e6
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << GridLogMessage << "Schur comms per-call (boss):"
|
||||||
|
<< " min " << (nAllreduce ? tARmin/1.0e3 : 0.0) << " ms"
|
||||||
|
<< " avg " << (nAllreduce ? tAllreduce/nAllreduce/1.0e3 : 0.0) << " ms"
|
||||||
|
<< " max " << tARmax/1.0e3 << " ms"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -63,12 +63,10 @@ void MemoryManager::PrintBytes(void)
|
|||||||
std::cout << " MemoryManager : "<<(total_device>>20)<<" accelerator Mbytes "<<std::endl;
|
std::cout << " MemoryManager : "<<(total_device>>20)<<" accelerator Mbytes "<<std::endl;
|
||||||
std::cout << " MemoryManager : "<<(total_host>>20) <<" cpu Mbytes "<<std::endl;
|
std::cout << " MemoryManager : "<<(total_host>>20) <<" cpu Mbytes "<<std::endl;
|
||||||
uint64_t cacheBytes;
|
uint64_t cacheBytes;
|
||||||
cacheBytes = CacheBytes[Cpu];
|
cacheBytes = HostCacheBytes();
|
||||||
std::cout << " MemoryManager : "<<(cacheBytes>>20) <<" cpu cache Mbytes "<<std::endl;
|
std::cout << " MemoryManager : "<<(cacheBytes>>20) <<" cpu alloc cache Mbytes "<<std::endl;
|
||||||
cacheBytes = CacheBytes[Acc];
|
cacheBytes = DeviceCacheBytes();
|
||||||
std::cout << " MemoryManager : "<<(cacheBytes>>20) <<" acc cache Mbytes "<<std::endl;
|
std::cout << " MemoryManager : "<<(cacheBytes>>20) <<" acc alloc cache Mbytes "<<std::endl;
|
||||||
cacheBytes = CacheBytes[Shared];
|
|
||||||
std::cout << " MemoryManager : "<<(cacheBytes>>20) <<" shared cache Mbytes "<<std::endl;
|
|
||||||
|
|
||||||
#ifdef GRID_CUDA
|
#ifdef GRID_CUDA
|
||||||
cuda_mem();
|
cuda_mem();
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ private:
|
|||||||
static void NotifyDeletion(void * CpuPtr);
|
static void NotifyDeletion(void * CpuPtr);
|
||||||
static void Print(void);
|
static void Print(void);
|
||||||
static void PrintAll(void);
|
static void PrintAll(void);
|
||||||
|
static void EvictAll(void);
|
||||||
static void PrintState( void* CpuPtr);
|
static void PrintState( void* CpuPtr);
|
||||||
static int isOpen (void* CpuPtr);
|
static int isOpen (void* CpuPtr);
|
||||||
static void ViewClose(void* CpuPtr,ViewMode mode);
|
static void ViewClose(void* CpuPtr,ViewMode mode);
|
||||||
|
|||||||
@@ -79,6 +79,25 @@ void MemoryManager::EntryErase(uint64_t CpuPtr)
|
|||||||
auto AccCache = EntryLookup(CpuPtr);
|
auto AccCache = EntryLookup(CpuPtr);
|
||||||
AccViewTable.erase(CpuPtr);
|
AccViewTable.erase(CpuPtr);
|
||||||
}
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// LRU membership invariant:
|
||||||
|
//
|
||||||
|
// LRU_valid == 1 <=> AccPtr != NULL && accLock == 0 && cpuLock == 0
|
||||||
|
//
|
||||||
|
// i.e. the LRU queue contains exactly the device-resident, completely unlocked
|
||||||
|
// entries -- the evictable set. Membership is maintained EAGERLY at the lock
|
||||||
|
// 0<->1 edges, O(1) via the stored LRU_entry iterator:
|
||||||
|
//
|
||||||
|
// AcceleratorViewOpen lock 0->1 : LRUremove (gated on LRU_valid)
|
||||||
|
// AcceleratorViewClose accLock->0: LRUinsert (AccPtr necessarily exists)
|
||||||
|
// CpuViewOpen lock 0->1 : LRUremove (gated on LRU_valid)
|
||||||
|
// CpuViewClose cpuLock->0: LRUinsert (iff AccPtr exists)
|
||||||
|
// Evict/AccDiscard : LRUremove (frees the device copy)
|
||||||
|
//
|
||||||
|
// Consequences: victims taken from LRU.back() are evictable by construction;
|
||||||
|
// Evict() on a locked entry is an invariant violation (asserted), and the
|
||||||
|
// eviction loops (EvictVictims/EvictAll) cannot spin.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
void MemoryManager::LRUinsert(AcceleratorViewEntry &AccCache)
|
void MemoryManager::LRUinsert(AcceleratorViewEntry &AccCache)
|
||||||
{
|
{
|
||||||
GRID_ASSERT(AccCache.LRU_valid==0);
|
GRID_ASSERT(AccCache.LRU_valid==0);
|
||||||
@@ -130,21 +149,21 @@ void MemoryManager::Evict(AcceleratorViewEntry &AccCache)
|
|||||||
{
|
{
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Make CPU consistent, remove from Accelerator, remove from LRU, LEAVE CPU only entry
|
// Make CPU consistent, remove from Accelerator, remove from LRU, LEAVE CPU only entry
|
||||||
// Cannot be acclocked. If allocated must be in LRU pool.
|
// Cannot be locked. If allocated must be in LRU pool.
|
||||||
//
|
//
|
||||||
// Nov 2022... Felix issue: Allocating two CpuPtrs, can have an entry in LRU-q with CPUlock.
|
// (Historical: a Nov 2022 incident (two CpuPtrs; eviction called from
|
||||||
// and require to evict the AccPtr copy. Eviction was a mistake in CpuViewOpen
|
// CpuViewOpen -- since excised) could present a cpuLocked entry here, and
|
||||||
// but there is a weakness where CpuLock entries are attempted for erase
|
// silent-return guards were added. The LRU membership invariant (see
|
||||||
// Take these OUT LRU queue when CPU locked?
|
// LRUinsert) now excludes ALL locked entries from the queue eagerly at the
|
||||||
// Cannot take out the table as cpuLock data is important.
|
// lock edges, so a locked victim is an invariant violation: asserted.)
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
GRID_ASSERT(AccCache.state!=Empty);
|
GRID_ASSERT(AccCache.state!=Empty);
|
||||||
|
|
||||||
mprintf("MemoryManager: Evict CpuPtr %lx AccPtr %lx cpuLock %ld accLock %ld",
|
mprintf("MemoryManager: Evict CpuPtr %lx AccPtr %lx cpuLock %ld accLock %ld",
|
||||||
(uint64_t)AccCache.CpuPtr,(uint64_t)AccCache.AccPtr,
|
(uint64_t)AccCache.CpuPtr,(uint64_t)AccCache.AccPtr,
|
||||||
(uint64_t)AccCache.cpuLock,(uint64_t)AccCache.accLock);
|
(uint64_t)AccCache.cpuLock,(uint64_t)AccCache.accLock);
|
||||||
if (AccCache.accLock!=0) return;
|
GRID_ASSERT(AccCache.accLock==0);
|
||||||
if (AccCache.cpuLock!=0) return;
|
GRID_ASSERT(AccCache.cpuLock==0);
|
||||||
if(AccCache.state==AccDirty) {
|
if(AccCache.state==AccDirty) {
|
||||||
Flush(AccCache);
|
Flush(AccCache);
|
||||||
}
|
}
|
||||||
@@ -250,6 +269,19 @@ void MemoryManager::EvictVictims(uint64_t bytes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void MemoryManager::EvictAll(void)
|
||||||
|
{
|
||||||
|
while(LRU.size()>0){
|
||||||
|
if ( DeviceLRUBytes > 0){
|
||||||
|
uint64_t victim = LRU.back(); // From the LRU
|
||||||
|
auto AccCacheIterator = EntryLookup(victim);
|
||||||
|
auto & AccCache = AccCacheIterator->second;
|
||||||
|
Evict(AccCache);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
uint64_t MemoryManager::AcceleratorViewOpen(uint64_t CpuPtr,size_t bytes,ViewMode mode,ViewAdvise hint)
|
uint64_t MemoryManager::AcceleratorViewOpen(uint64_t CpuPtr,size_t bytes,ViewMode mode,ViewAdvise hint)
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -383,6 +415,13 @@ void MemoryManager::CpuViewClose(uint64_t CpuPtr)
|
|||||||
GRID_ASSERT(AccCache.accLock==0);
|
GRID_ASSERT(AccCache.accLock==0);
|
||||||
|
|
||||||
AccCache.cpuLock--;
|
AccCache.cpuLock--;
|
||||||
|
// Return to LRU queue when fully unlocked -- mirrors AcceleratorViewClose.
|
||||||
|
// Asymmetry vs the Acc side: a device copy need not exist for a host view;
|
||||||
|
// only device-resident entries belong in the (evictable) LRU queue.
|
||||||
|
if( (AccCache.cpuLock==0) && (AccCache.AccPtr!=(uint64_t)NULL) ) {
|
||||||
|
dprintf("CpuViewClose %lx cpuLock decremented to zero, move to LRU queue",(uint64_t)CpuPtr);
|
||||||
|
LRUinsert(AccCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Action State StateNext Flush Clone
|
* Action State StateNext Flush Clone
|
||||||
@@ -449,6 +488,14 @@ uint64_t MemoryManager::CpuViewOpen(uint64_t CpuPtr,size_t bytes,ViewMode mode,V
|
|||||||
GRID_ASSERT(0); // should be unreachable
|
GRID_ASSERT(0); // should be unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GRID_ASSERT(AccCache.cpuLock>0);
|
||||||
|
// If view is opened on host must remove from LRU -- mirrors AcceleratorViewOpen.
|
||||||
|
// LRU_valid==1 here implies this is the 0->1 lock edge of a device-resident entry.
|
||||||
|
if(AccCache.LRU_valid==1){
|
||||||
|
dprintf("CpuViewOpen: entry removed from LRU ");
|
||||||
|
LRUremove(AccCache);
|
||||||
|
}
|
||||||
|
|
||||||
AccCache.transient= transient? EvictNext : 0;
|
AccCache.transient= transient? EvictNext : 0;
|
||||||
|
|
||||||
return AccCache.CpuPtr;
|
return AccCache.CpuPtr;
|
||||||
|
|||||||
@@ -239,6 +239,16 @@ public:
|
|||||||
void AllToAll(int dim ,void *in,void *out,uint64_t words,uint64_t bytes);
|
void AllToAll(int dim ,void *in,void *out,uint64_t words,uint64_t bytes);
|
||||||
void AllToAll(void *in,void *out,uint64_t words ,uint64_t bytes);
|
void AllToAll(void *in,void *out,uint64_t words ,uint64_t bytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Variable count all to all. Counts and displacements are in units of
|
||||||
|
// "bytes" sized words and are indexed by rank within this communicator.
|
||||||
|
// For exchanges that are a permutation but do not divide evenly between
|
||||||
|
// ranks; AllToAll above is the uniform count special case.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
void AllToAllV(void *in ,const std::vector<int> &sendcounts,const std::vector<int> &senddispls,
|
||||||
|
void *out,const std::vector<int> &recvcounts,const std::vector<int> &recvdispls,
|
||||||
|
uint64_t bytes);
|
||||||
|
|
||||||
template<class obj> void Broadcast(int root,obj &data)
|
template<class obj> void Broadcast(int root,obj &data)
|
||||||
{
|
{
|
||||||
Broadcast(root,(void *)&data,sizeof(data));
|
Broadcast(root,(void *)&data,sizeof(data));
|
||||||
|
|||||||
@@ -945,5 +945,25 @@ void CartesianCommunicator::AllToAll(void *in,void *out,uint64_t words,uint64_t
|
|||||||
MPI_Alltoall(in,iwords,object,out,iwords,object,communicator);
|
MPI_Alltoall(in,iwords,object,out,iwords,object,communicator);
|
||||||
MPI_Type_free(&object);
|
MPI_Type_free(&object);
|
||||||
}
|
}
|
||||||
|
void CartesianCommunicator::AllToAllV(void *in ,const std::vector<int> &sendcounts,const std::vector<int> &senddispls,
|
||||||
|
void *out,const std::vector<int> &recvcounts,const std::vector<int> &recvdispls,
|
||||||
|
uint64_t bytes)
|
||||||
|
{
|
||||||
|
FlightRecorder::StepLog("AllToAllV");
|
||||||
|
GRID_ASSERT(sendcounts.size()==(size_t)_Nprocessors);
|
||||||
|
GRID_ASSERT(senddispls.size()==(size_t)_Nprocessors);
|
||||||
|
GRID_ASSERT(recvcounts.size()==(size_t)_Nprocessors);
|
||||||
|
GRID_ASSERT(recvdispls.size()==(size_t)_Nprocessors);
|
||||||
|
// MPI counts are "int"; the caller sizes the word to keep them in range
|
||||||
|
int ibytes = bytes;
|
||||||
|
GRID_ASSERT(bytes == (uint64_t)ibytes);
|
||||||
|
MPI_Datatype object;
|
||||||
|
MPI_Type_contiguous(ibytes,MPI_BYTE,&object);
|
||||||
|
MPI_Type_commit(&object);
|
||||||
|
int ierr = MPI_Alltoallv(in ,(int *)&sendcounts[0],(int *)&senddispls[0],object,
|
||||||
|
out,(int *)&recvcounts[0],(int *)&recvdispls[0],object,communicator);
|
||||||
|
GRID_ASSERT(ierr==0);
|
||||||
|
MPI_Type_free(&object);
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -113,6 +113,17 @@ void CartesianCommunicator::AllToAll(void *in,void *out,uint64_t words,uint64_t
|
|||||||
{
|
{
|
||||||
bcopy(in,out,bytes*words);
|
bcopy(in,out,bytes*words);
|
||||||
}
|
}
|
||||||
|
void CartesianCommunicator::AllToAllV(void *in ,const std::vector<int> &sendcounts,const std::vector<int> &senddispls,
|
||||||
|
void *out,const std::vector<int> &recvcounts,const std::vector<int> &recvdispls,
|
||||||
|
uint64_t bytes)
|
||||||
|
{
|
||||||
|
// Single rank: the exchange degenerates to a copy of our own segment
|
||||||
|
GRID_ASSERT(sendcounts.size()==1);
|
||||||
|
GRID_ASSERT(recvcounts.size()==1);
|
||||||
|
GRID_ASSERT(sendcounts[0]==recvcounts[0]);
|
||||||
|
bcopy((char *)in +(uint64_t)senddispls[0]*bytes,
|
||||||
|
(char *)out+(uint64_t)recvdispls[0]*bytes,bytes*(uint64_t)sendcounts[0]);
|
||||||
|
}
|
||||||
|
|
||||||
int CartesianCommunicator::RankWorld(void){return 0;}
|
int CartesianCommunicator::RankWorld(void){return 0;}
|
||||||
void CartesianCommunicator::Barrier(void){}
|
void CartesianCommunicator::Barrier(void){}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ accelerator_inline vobj predicatedWhere(const iobj &predicate,
|
|||||||
|
|
||||||
extract(iftrue, truevals);
|
extract(iftrue, truevals);
|
||||||
extract(iffalse, falsevals);
|
extract(iffalse, falsevals);
|
||||||
extract<vInteger, Integer>(TensorRemove(predicate), mask);
|
extract(TensorRemove(predicate), mask);
|
||||||
|
|
||||||
for (int s = 0; s < Nsimd; s++) {
|
for (int s = 0; s < Nsimd; s++) {
|
||||||
if (mask[s]) falsevals[s] = truevals[s];
|
if (mask[s]) falsevals[s] = truevals[s];
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ public:
|
|||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
// move constructor
|
// move constructor
|
||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
Lattice(Lattice && r){
|
Lattice(Lattice && r) noexcept {
|
||||||
this->_grid = r.Grid();
|
this->_grid = r.Grid();
|
||||||
this->_odata = r._odata;
|
this->_odata = r._odata;
|
||||||
this->_odata_size = r._odata_size;
|
this->_odata_size = r._odata_size;
|
||||||
@@ -330,7 +330,7 @@ public:
|
|||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
// Move assignment possible if same type
|
// Move assignment possible if same type
|
||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
inline Lattice<vobj> & operator = (Lattice<vobj> && r){
|
inline Lattice<vobj> & operator = (Lattice<vobj> && r) noexcept {
|
||||||
|
|
||||||
resize(0); // deletes if appropriate
|
resize(0); // deletes if appropriate
|
||||||
this->_grid = r.Grid();
|
this->_grid = r.Grid();
|
||||||
|
|||||||
@@ -40,16 +40,16 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
//Query supporting logical &&, ||,
|
//Query supporting logical &&, ||,
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef iScalar<vInteger> vPredicate ;
|
template<class vobj> using vPredicate = iScalar<IntegerPredicate<vobj> > ;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// compare lattice to lattice
|
// compare lattice to lattice
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<class vfunctor,class lobj,class robj>
|
template<class vfunctor,class lobj,class robj>
|
||||||
inline Lattice<vPredicate> LLComparison(vfunctor op,const Lattice<lobj> &lhs,const Lattice<robj> &rhs)
|
inline Lattice<vPredicate<lobj> > LLComparison(vfunctor op,const Lattice<lobj> &lhs,const Lattice<robj> &rhs)
|
||||||
{
|
{
|
||||||
Lattice<vPredicate> ret(rhs.Grid());
|
Lattice<vPredicate<lobj> > ret(rhs.Grid());
|
||||||
autoView( lhs_v, lhs, CpuRead);
|
autoView( lhs_v, lhs, CpuRead);
|
||||||
autoView( rhs_v, rhs, CpuRead);
|
autoView( rhs_v, rhs, CpuRead);
|
||||||
autoView( ret_v, ret, CpuWrite);
|
autoView( ret_v, ret, CpuWrite);
|
||||||
@@ -62,9 +62,9 @@ inline Lattice<vPredicate> LLComparison(vfunctor op,const Lattice<lobj> &lhs,con
|
|||||||
// compare lattice to scalar
|
// compare lattice to scalar
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
template<class vfunctor,class lobj,class robj>
|
template<class vfunctor,class lobj,class robj>
|
||||||
inline Lattice<vPredicate> LSComparison(vfunctor op,const Lattice<lobj> &lhs,const robj &rhs)
|
inline Lattice<vPredicate<lobj> > LSComparison(vfunctor op,const Lattice<lobj> &lhs,const robj &rhs)
|
||||||
{
|
{
|
||||||
Lattice<vPredicate> ret(lhs.Grid());
|
Lattice<vPredicate<lobj> > ret(lhs.Grid());
|
||||||
autoView( lhs_v, lhs, CpuRead);
|
autoView( lhs_v, lhs, CpuRead);
|
||||||
autoView( ret_v, ret, CpuWrite);
|
autoView( ret_v, ret, CpuWrite);
|
||||||
thread_for( ss, lhs_v.size(), {
|
thread_for( ss, lhs_v.size(), {
|
||||||
@@ -76,9 +76,9 @@ inline Lattice<vPredicate> LSComparison(vfunctor op,const Lattice<lobj> &lhs,con
|
|||||||
// compare scalar to lattice
|
// compare scalar to lattice
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
template<class vfunctor,class lobj,class robj>
|
template<class vfunctor,class lobj,class robj>
|
||||||
inline Lattice<vPredicate> SLComparison(vfunctor op,const lobj &lhs,const Lattice<robj> &rhs)
|
inline Lattice<vPredicate<robj> > SLComparison(vfunctor op,const lobj &lhs,const Lattice<robj> &rhs)
|
||||||
{
|
{
|
||||||
Lattice<vPredicate> ret(rhs.Grid());
|
Lattice<vPredicate<robj> > ret(rhs.Grid());
|
||||||
autoView( rhs_v, rhs, CpuRead);
|
autoView( rhs_v, rhs, CpuRead);
|
||||||
autoView( ret_v, ret, CpuWrite);
|
autoView( ret_v, ret, CpuWrite);
|
||||||
thread_for( ss, rhs_v.size(), {
|
thread_for( ss, rhs_v.size(), {
|
||||||
@@ -92,87 +92,87 @@ inline Lattice<vPredicate> SLComparison(vfunctor op,const lobj &lhs,const Lattic
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Less than
|
// Less than
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator < (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<lobj> > operator < (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
||||||
return LLComparison(vlt<lobj,robj>(),lhs,rhs);
|
return LLComparison(vlt<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator < (const Lattice<lobj> & lhs, const robj & rhs) {
|
inline Lattice<vPredicate<lobj> > operator < (const Lattice<lobj> & lhs, const robj & rhs) {
|
||||||
return LSComparison(vlt<lobj,robj>(),lhs,rhs);
|
return LSComparison(vlt<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator < (const lobj & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<robj> > operator < (const lobj & lhs, const Lattice<robj> & rhs) {
|
||||||
return SLComparison(vlt<lobj,robj>(),lhs,rhs);
|
return SLComparison(vlt<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less than equal
|
// Less than equal
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator <= (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<lobj> > operator <= (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
||||||
return LLComparison(vle<lobj,robj>(),lhs,rhs);
|
return LLComparison(vle<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator <= (const Lattice<lobj> & lhs, const robj & rhs) {
|
inline Lattice<vPredicate<lobj> > operator <= (const Lattice<lobj> & lhs, const robj & rhs) {
|
||||||
return LSComparison(vle<lobj,robj>(),lhs,rhs);
|
return LSComparison(vle<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator <= (const lobj & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<robj> > operator <= (const lobj & lhs, const Lattice<robj> & rhs) {
|
||||||
return SLComparison(vle<lobj,robj>(),lhs,rhs);
|
return SLComparison(vle<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Greater than
|
// Greater than
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator > (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<lobj> > operator > (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
||||||
return LLComparison(vgt<lobj,robj>(),lhs,rhs);
|
return LLComparison(vgt<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator > (const Lattice<lobj> & lhs, const robj & rhs) {
|
inline Lattice<vPredicate<lobj> > operator > (const Lattice<lobj> & lhs, const robj & rhs) {
|
||||||
return LSComparison(vgt<lobj,robj>(),lhs,rhs);
|
return LSComparison(vgt<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator > (const lobj & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<robj> > operator > (const lobj & lhs, const Lattice<robj> & rhs) {
|
||||||
return SLComparison(vgt<lobj,robj>(),lhs,rhs);
|
return SLComparison(vgt<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Greater than equal
|
// Greater than equal
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator >= (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<lobj> > operator >= (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
||||||
return LLComparison(vge<lobj,robj>(),lhs,rhs);
|
return LLComparison(vge<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator >= (const Lattice<lobj> & lhs, const robj & rhs) {
|
inline Lattice<vPredicate<lobj> > operator >= (const Lattice<lobj> & lhs, const robj & rhs) {
|
||||||
return LSComparison(vge<lobj,robj>(),lhs,rhs);
|
return LSComparison(vge<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator >= (const lobj & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<robj> > operator >= (const lobj & lhs, const Lattice<robj> & rhs) {
|
||||||
return SLComparison(vge<lobj,robj>(),lhs,rhs);
|
return SLComparison(vge<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// equal
|
// equal
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator == (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<lobj> > operator == (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
||||||
return LLComparison(veq<lobj,robj>(),lhs,rhs);
|
return LLComparison(veq<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator == (const Lattice<lobj> & lhs, const robj & rhs) {
|
inline Lattice<vPredicate<lobj> > operator == (const Lattice<lobj> & lhs, const robj & rhs) {
|
||||||
return LSComparison(veq<lobj,robj>(),lhs,rhs);
|
return LSComparison(veq<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator == (const lobj & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<robj> > operator == (const lobj & lhs, const Lattice<robj> & rhs) {
|
||||||
return SLComparison(veq<lobj,robj>(),lhs,rhs);
|
return SLComparison(veq<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// not equal
|
// not equal
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator != (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<lobj> > operator != (const Lattice<lobj> & lhs, const Lattice<robj> & rhs) {
|
||||||
return LLComparison(vne<lobj,robj>(),lhs,rhs);
|
return LLComparison(vne<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator != (const Lattice<lobj> & lhs, const robj & rhs) {
|
inline Lattice<vPredicate<lobj> > operator != (const Lattice<lobj> & lhs, const robj & rhs) {
|
||||||
return LSComparison(vne<lobj,robj>(),lhs,rhs);
|
return LSComparison(vne<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
template<class lobj,class robj>
|
template<class lobj,class robj>
|
||||||
inline Lattice<vPredicate> operator != (const lobj & lhs, const Lattice<robj> & rhs) {
|
inline Lattice<vPredicate<robj> > operator != (const lobj & lhs, const Lattice<robj> & rhs) {
|
||||||
return SLComparison(vne<lobj,robj>(),lhs,rhs);
|
return SLComparison(vne<lobj,robj>(),lhs,rhs);
|
||||||
}
|
}
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -39,47 +39,53 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
//
|
//
|
||||||
// Should guard this with isGridTensor<> enable if?
|
// Should guard this with isGridTensor<> enable if?
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Predicate type matching the operand's vectorisation
|
||||||
|
//
|
||||||
|
template<class obj> using IntegerPredicate =
|
||||||
|
typename GridTypeMapper<typename GridTypeMapper<obj>::vector_type>::Integerified;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Generic list of functors
|
// Generic list of functors
|
||||||
//
|
//
|
||||||
template<class lobj,class robj> class veq {
|
template<class lobj,class robj> class veq {
|
||||||
public:
|
public:
|
||||||
accelerator vInteger operator()(const lobj &lhs, const robj &rhs)
|
accelerator IntegerPredicate<lobj> operator()(const lobj &lhs, const robj &rhs)
|
||||||
{
|
{
|
||||||
return (lhs) == (rhs);
|
return (lhs) == (rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class lobj,class robj> class vne {
|
template<class lobj,class robj> class vne {
|
||||||
public:
|
public:
|
||||||
accelerator vInteger operator()(const lobj &lhs, const robj &rhs)
|
accelerator IntegerPredicate<lobj> operator()(const lobj &lhs, const robj &rhs)
|
||||||
{
|
{
|
||||||
return (lhs) != (rhs);
|
return (lhs) != (rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class lobj,class robj> class vlt {
|
template<class lobj,class robj> class vlt {
|
||||||
public:
|
public:
|
||||||
accelerator vInteger operator()(const lobj &lhs, const robj &rhs)
|
accelerator IntegerPredicate<lobj> operator()(const lobj &lhs, const robj &rhs)
|
||||||
{
|
{
|
||||||
return (lhs) < (rhs);
|
return (lhs) < (rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class lobj,class robj> class vle {
|
template<class lobj,class robj> class vle {
|
||||||
public:
|
public:
|
||||||
accelerator vInteger operator()(const lobj &lhs, const robj &rhs)
|
accelerator IntegerPredicate<lobj> operator()(const lobj &lhs, const robj &rhs)
|
||||||
{
|
{
|
||||||
return (lhs) <= (rhs);
|
return (lhs) <= (rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class lobj,class robj> class vgt {
|
template<class lobj,class robj> class vgt {
|
||||||
public:
|
public:
|
||||||
accelerator vInteger operator()(const lobj &lhs, const robj &rhs)
|
accelerator IntegerPredicate<lobj> operator()(const lobj &lhs, const robj &rhs)
|
||||||
{
|
{
|
||||||
return (lhs) > (rhs);
|
return (lhs) > (rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class lobj,class robj> class vge {
|
template<class lobj,class robj> class vge {
|
||||||
public:
|
public:
|
||||||
accelerator vInteger operator()(const lobj &lhs, const robj &rhs)
|
accelerator IntegerPredicate<lobj> operator()(const lobj &lhs, const robj &rhs)
|
||||||
{
|
{
|
||||||
return (lhs) >= (rhs);
|
return (lhs) >= (rhs);
|
||||||
}
|
}
|
||||||
@@ -133,78 +139,78 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
// Integer and real get extra relational functions.
|
// Integer and real get extra relational functions.
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>
|
template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>
|
||||||
accelerator_inline vInteger Comparison(sfunctor sop,const vsimd & lhs, const vsimd & rhs)
|
accelerator_inline IntegerPredicate<vsimd> Comparison(sfunctor sop,const vsimd & lhs, const vsimd & rhs)
|
||||||
{
|
{
|
||||||
typedef typename vsimd::scalar_type scalar;
|
typedef typename vsimd::scalar_type scalar;
|
||||||
ExtractBuffer<scalar> vlhs(vsimd::Nsimd()); // Use functors to reduce this to single implementation
|
ExtractBuffer<scalar> vlhs(vsimd::Nsimd()); // Use functors to reduce this to single implementation
|
||||||
ExtractBuffer<scalar> vrhs(vsimd::Nsimd());
|
ExtractBuffer<scalar> vrhs(vsimd::Nsimd());
|
||||||
ExtractBuffer<Integer> vpred(vsimd::Nsimd());
|
ExtractBuffer<Integer> vpred(vsimd::Nsimd());
|
||||||
vInteger ret;
|
IntegerPredicate<vsimd> ret;
|
||||||
extract<vsimd,scalar>(lhs,vlhs);
|
extract<vsimd,scalar>(lhs,vlhs);
|
||||||
extract<vsimd,scalar>(rhs,vrhs);
|
extract<vsimd,scalar>(rhs,vrhs);
|
||||||
for(int s=0;s<vsimd::Nsimd();s++){
|
for(int s=0;s<vsimd::Nsimd();s++){
|
||||||
vpred[s] = sop(vlhs[s],vrhs[s]);
|
vpred[s] = sop(vlhs[s],vrhs[s]);
|
||||||
}
|
}
|
||||||
merge<vInteger,Integer>(ret,vpred);
|
merge<IntegerPredicate<vsimd>,Integer>(ret,vpred);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>
|
template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>
|
||||||
accelerator_inline vInteger Comparison(sfunctor sop,const vsimd & lhs, const typename vsimd::scalar_type & rhs)
|
accelerator_inline IntegerPredicate<vsimd> Comparison(sfunctor sop,const vsimd & lhs, const typename vsimd::scalar_type & rhs)
|
||||||
{
|
{
|
||||||
typedef typename vsimd::scalar_type scalar;
|
typedef typename vsimd::scalar_type scalar;
|
||||||
ExtractBuffer<scalar> vlhs(vsimd::Nsimd()); // Use functors to reduce this to single implementation
|
ExtractBuffer<scalar> vlhs(vsimd::Nsimd()); // Use functors to reduce this to single implementation
|
||||||
ExtractBuffer<Integer> vpred(vsimd::Nsimd());
|
ExtractBuffer<Integer> vpred(vsimd::Nsimd());
|
||||||
vInteger ret;
|
IntegerPredicate<vsimd> ret;
|
||||||
extract<vsimd,scalar>(lhs,vlhs);
|
extract<vsimd,scalar>(lhs,vlhs);
|
||||||
for(int s=0;s<vsimd::Nsimd();s++){
|
for(int s=0;s<vsimd::Nsimd();s++){
|
||||||
vpred[s] = sop(vlhs[s],rhs);
|
vpred[s] = sop(vlhs[s],rhs);
|
||||||
}
|
}
|
||||||
merge<vInteger,Integer>(ret,vpred);
|
merge<IntegerPredicate<vsimd>,Integer>(ret,vpred);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>
|
template<class sfunctor, class vsimd,IfNotComplex<vsimd> = 0>
|
||||||
accelerator_inline vInteger Comparison(sfunctor sop,const typename vsimd::scalar_type & lhs, const vsimd & rhs)
|
accelerator_inline IntegerPredicate<vsimd> Comparison(sfunctor sop,const typename vsimd::scalar_type & lhs, const vsimd & rhs)
|
||||||
{
|
{
|
||||||
typedef typename vsimd::scalar_type scalar;
|
typedef typename vsimd::scalar_type scalar;
|
||||||
ExtractBuffer<scalar> vrhs(vsimd::Nsimd()); // Use functors to reduce this to single implementation
|
ExtractBuffer<scalar> vrhs(vsimd::Nsimd()); // Use functors to reduce this to single implementation
|
||||||
ExtractBuffer<Integer> vpred(vsimd::Nsimd());
|
ExtractBuffer<Integer> vpred(vsimd::Nsimd());
|
||||||
vInteger ret;
|
IntegerPredicate<vsimd> ret;
|
||||||
extract<vsimd,scalar>(rhs,vrhs);
|
extract<vsimd,scalar>(rhs,vrhs);
|
||||||
for(int s=0;s<vsimd::Nsimd();s++){
|
for(int s=0;s<vsimd::Nsimd();s++){
|
||||||
vpred[s] = sop(lhs,vrhs[s]);
|
vpred[s] = sop(lhs,vrhs[s]);
|
||||||
}
|
}
|
||||||
merge<vInteger,Integer>(ret,vpred);
|
merge<IntegerPredicate<vsimd>,Integer>(ret,vpred);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_RELATIONAL_EQ(op,functor) \
|
#define DECLARE_RELATIONAL_EQ(op,functor) \
|
||||||
template<class vsimd,IfSimd<vsimd> = 0>\
|
template<class vsimd,IfSimd<vsimd> = 0>\
|
||||||
accelerator_inline vInteger operator op (const vsimd & lhs, const vsimd & rhs)\
|
accelerator_inline IntegerPredicate<vsimd> operator op (const vsimd & lhs, const vsimd & rhs)\
|
||||||
{\
|
{\
|
||||||
typedef typename vsimd::scalar_type scalar;\
|
typedef typename vsimd::scalar_type scalar;\
|
||||||
return Comparison(functor<scalar,scalar>(),lhs,rhs);\
|
return Comparison(functor<scalar,scalar>(),lhs,rhs);\
|
||||||
}\
|
}\
|
||||||
template<class vsimd,IfSimd<vsimd> = 0>\
|
template<class vsimd,IfSimd<vsimd> = 0>\
|
||||||
accelerator_inline vInteger operator op (const vsimd & lhs, const typename vsimd::scalar_type & rhs) \
|
accelerator_inline IntegerPredicate<vsimd> operator op (const vsimd & lhs, const typename vsimd::scalar_type & rhs) \
|
||||||
{\
|
{\
|
||||||
typedef typename vsimd::scalar_type scalar;\
|
typedef typename vsimd::scalar_type scalar;\
|
||||||
return Comparison(functor<scalar,scalar>(),lhs,rhs);\
|
return Comparison(functor<scalar,scalar>(),lhs,rhs);\
|
||||||
}\
|
}\
|
||||||
template<class vsimd,IfSimd<vsimd> = 0>\
|
template<class vsimd,IfSimd<vsimd> = 0>\
|
||||||
accelerator_inline vInteger operator op (const typename vsimd::scalar_type & lhs, const vsimd & rhs) \
|
accelerator_inline IntegerPredicate<vsimd> operator op (const typename vsimd::scalar_type & lhs, const vsimd & rhs) \
|
||||||
{\
|
{\
|
||||||
typedef typename vsimd::scalar_type scalar;\
|
typedef typename vsimd::scalar_type scalar;\
|
||||||
return Comparison(functor<scalar,scalar>(),lhs,rhs);\
|
return Comparison(functor<scalar,scalar>(),lhs,rhs);\
|
||||||
}\
|
}\
|
||||||
template<class vsimd>\
|
template<class vsimd>\
|
||||||
accelerator_inline vInteger operator op(const iScalar<vsimd> &lhs,const typename vsimd::scalar_type &rhs) \
|
accelerator_inline IntegerPredicate<vsimd> operator op(const iScalar<vsimd> &lhs,const typename vsimd::scalar_type &rhs) \
|
||||||
{ \
|
{ \
|
||||||
return lhs._internal op rhs; \
|
return lhs._internal op rhs; \
|
||||||
} \
|
} \
|
||||||
template<class vsimd>\
|
template<class vsimd>\
|
||||||
accelerator_inline vInteger operator op(const typename vsimd::scalar_type &lhs,const iScalar<vsimd> &rhs) \
|
accelerator_inline IntegerPredicate<vsimd> operator op(const typename vsimd::scalar_type &lhs,const iScalar<vsimd> &rhs) \
|
||||||
{ \
|
{ \
|
||||||
return lhs op rhs._internal; \
|
return lhs op rhs._internal; \
|
||||||
} \
|
} \
|
||||||
@@ -212,7 +218,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
#define DECLARE_RELATIONAL(op,functor) \
|
#define DECLARE_RELATIONAL(op,functor) \
|
||||||
DECLARE_RELATIONAL_EQ(op,functor) \
|
DECLARE_RELATIONAL_EQ(op,functor) \
|
||||||
template<class vsimd>\
|
template<class vsimd>\
|
||||||
accelerator_inline vInteger operator op(const iScalar<vsimd> &lhs,const iScalar<vsimd> &rhs)\
|
accelerator_inline IntegerPredicate<vsimd> operator op(const iScalar<vsimd> &lhs,const iScalar<vsimd> &rhs)\
|
||||||
{ \
|
{ \
|
||||||
return lhs._internal op rhs._internal; \
|
return lhs._internal op rhs._internal; \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,6 +197,9 @@ __global__ void reduceKernel(const vobj *lat, sobj *buffer, Iterator n) {
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Possibly promote to double and sum
|
// Possibly promote to double and sum
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#undef GRID_REDUCTION_TIMING
|
||||||
|
|
||||||
template <class vobj>
|
template <class vobj>
|
||||||
inline typename vobj::scalar_objectD sumD_gpu_small(const vobj *lat, Integer osites)
|
inline typename vobj::scalar_objectD sumD_gpu_small(const vobj *lat, Integer osites)
|
||||||
{
|
{
|
||||||
@@ -211,41 +214,188 @@ inline typename vobj::scalar_objectD sumD_gpu_small(const vobj *lat, Integer osi
|
|||||||
GRID_ASSERT(ok);
|
GRID_ASSERT(ok);
|
||||||
|
|
||||||
Integer smemSize = numThreads * sizeof(sobj);
|
Integer smemSize = numThreads * sizeof(sobj);
|
||||||
// Move out of UVM
|
|
||||||
// Turns out I had messed up the synchronise after move to compute stream
|
|
||||||
// as running this on the default stream fools the synchronise
|
|
||||||
deviceVector<sobj> buffer(numBlocks);
|
deviceVector<sobj> buffer(numBlocks);
|
||||||
sobj *buffer_v = &buffer[0];
|
sobj *buffer_v = &buffer[0];
|
||||||
sobj result;
|
sobj result;
|
||||||
|
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
RealD t_kernel = -usecond();
|
||||||
|
#endif
|
||||||
reduceKernel<<< numBlocks, numThreads, smemSize, computeStream >>>(lat, buffer_v, size);
|
reduceKernel<<< numBlocks, numThreads, smemSize, computeStream >>>(lat, buffer_v, size);
|
||||||
accelerator_barrier();
|
accelerator_barrier();
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
t_kernel += usecond();
|
||||||
|
RealD t_d2h = -usecond();
|
||||||
|
#endif
|
||||||
acceleratorCopyFromDevice(buffer_v,&result,sizeof(result));
|
acceleratorCopyFromDevice(buffer_v,&result,sizeof(result));
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
t_d2h += usecond();
|
||||||
|
std::cout << GridLogDebug << " sumD_gpu_small"
|
||||||
|
<< " sizeof(sobj)=" << sizeof(sobj)
|
||||||
|
<< " blocks=" << numBlocks << " threads=" << numThreads
|
||||||
|
<< " kernel+barrier=" << t_kernel << " us"
|
||||||
|
<< " D2H=" << t_d2h << " us" << std::endl;
|
||||||
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fused pack+reduce: reads R words of each vobj at word offset 'base',
|
||||||
|
// accumulates directly into iVector<iScalar<scalarD>,R> without staging
|
||||||
|
// through an intermediate bundle buffer. One HBM pass instead of three.
|
||||||
|
template <int R, class vobj, class sobj, class Iterator>
|
||||||
|
__device__ void packReduceBlocks(
|
||||||
|
const iScalar<typename vobj::vector_type> *idat,
|
||||||
|
sobj *g_odata, Iterator osites, int base, int words)
|
||||||
|
{
|
||||||
|
constexpr Iterator nsimd = vobj::Nsimd();
|
||||||
|
Iterator blockSize = blockDim.x;
|
||||||
|
|
||||||
|
extern __shared__ __align__(COALESCE_GRANULARITY) unsigned char shmem_pointer[];
|
||||||
|
sobj *sdata = (sobj *)shmem_pointer;
|
||||||
|
|
||||||
|
Iterator tid = threadIdx.x;
|
||||||
|
Iterator i = blockIdx.x * (blockSize * 2) + threadIdx.x;
|
||||||
|
Iterator gridSize = blockSize * 2 * gridDim.x;
|
||||||
|
sobj mySum = Zero();
|
||||||
|
|
||||||
|
while (i < osites * nsimd) {
|
||||||
|
Iterator lane = i % nsimd;
|
||||||
|
Iterator ss = i / nsimd;
|
||||||
|
sobj tmpD; zeroit(tmpD);
|
||||||
|
for (int k = 0; k < R; k++) {
|
||||||
|
auto w = extractLane(lane, idat[ss * words + base + k]);
|
||||||
|
iScalar<typename vobj::scalar_typeD> wd; wd = w;
|
||||||
|
tmpD._internal[k] = wd;
|
||||||
|
}
|
||||||
|
mySum += tmpD;
|
||||||
|
|
||||||
|
if (i + blockSize < osites * nsimd) {
|
||||||
|
lane = (i + blockSize) % nsimd;
|
||||||
|
ss = (i + blockSize) / nsimd;
|
||||||
|
sobj tmpD2; zeroit(tmpD2);
|
||||||
|
for (int k = 0; k < R; k++) {
|
||||||
|
auto w = extractLane(lane, idat[ss * words + base + k]);
|
||||||
|
iScalar<typename vobj::scalar_typeD> wd; wd = w;
|
||||||
|
tmpD2._internal[k] = wd;
|
||||||
|
}
|
||||||
|
mySum += tmpD2;
|
||||||
|
}
|
||||||
|
i += gridSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
reduceBlock(sdata, mySum, tid);
|
||||||
|
if (tid == 0) g_odata[blockIdx.x] = sdata[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int R, class vobj, class sobj, class Iterator>
|
||||||
|
__global__ void packReduceKernel(
|
||||||
|
const iScalar<typename vobj::vector_type> *idat,
|
||||||
|
sobj *buffer, Iterator osites, int base, int words)
|
||||||
|
{
|
||||||
|
Iterator blockSize = blockDim.x;
|
||||||
|
|
||||||
|
packReduceBlocks<R, vobj, sobj>(idat, buffer, osites, base, words);
|
||||||
|
|
||||||
|
if (gridDim.x > 1) {
|
||||||
|
const Iterator tid = threadIdx.x;
|
||||||
|
__shared__ bool amLast;
|
||||||
|
extern __shared__ __align__(COALESCE_GRANULARITY) unsigned char shmem_pointer[];
|
||||||
|
sobj *smem = (sobj *)shmem_pointer;
|
||||||
|
|
||||||
|
acceleratorFence();
|
||||||
|
|
||||||
|
if (tid == 0) {
|
||||||
|
unsigned int ticket = atomicInc(&retirementCount, gridDim.x);
|
||||||
|
amLast = (ticket == gridDim.x - 1);
|
||||||
|
}
|
||||||
|
acceleratorSynchroniseAll();
|
||||||
|
|
||||||
|
if (amLast) {
|
||||||
|
Iterator i = tid;
|
||||||
|
sobj mySum = Zero();
|
||||||
|
while (i < (Iterator)gridDim.x) {
|
||||||
|
mySum += buffer[i];
|
||||||
|
i += blockSize;
|
||||||
|
}
|
||||||
|
reduceBlock(smem, mySum, tid);
|
||||||
|
if (tid == 0) {
|
||||||
|
buffer[0] = smem[0];
|
||||||
|
retirementCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int R, class vobj>
|
||||||
|
inline void sumD_gpu_reduce_words(const vobj *lat, Integer osites,
|
||||||
|
typename vobj::scalar_typeD *ret_p, int base)
|
||||||
|
{
|
||||||
|
typedef typename vobj::vector_type vector;
|
||||||
|
typedef typename vobj::scalar_typeD scalarD;
|
||||||
|
using BundleScalarD = iVector<iScalar<scalarD>, R>;
|
||||||
|
|
||||||
|
constexpr int Nsimd = vobj::Nsimd();
|
||||||
|
const int words = sizeof(vobj) / sizeof(vector);
|
||||||
|
const iScalar<vector> *idat = (const iScalar<vector> *)lat;
|
||||||
|
|
||||||
|
Integer size = (Integer)osites * Nsimd;
|
||||||
|
Integer numThreads, numBlocks;
|
||||||
|
int ok = getNumBlocksAndThreads(size, sizeof(BundleScalarD), numThreads, numBlocks);
|
||||||
|
GRID_ASSERT(ok);
|
||||||
|
|
||||||
|
Integer smemSize = numThreads * sizeof(BundleScalarD);
|
||||||
|
deviceVector<BundleScalarD> buffer(numBlocks);
|
||||||
|
BundleScalarD *buffer_v = &buffer[0];
|
||||||
|
BundleScalarD result;
|
||||||
|
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
RealD t_kernel = -usecond();
|
||||||
|
#endif
|
||||||
|
packReduceKernel<R, vobj, BundleScalarD, Integer>
|
||||||
|
<<<numBlocks, numThreads, smemSize, computeStream>>>
|
||||||
|
(idat, buffer_v, osites, base, words);
|
||||||
|
accelerator_barrier();
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
t_kernel += usecond();
|
||||||
|
RealD t_d2h = -usecond();
|
||||||
|
#endif
|
||||||
|
acceleratorCopyFromDevice(buffer_v, &result, sizeof(result));
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
t_d2h += usecond();
|
||||||
|
std::cout << GridLogDebug << " sumD_gpu_reduce_words R=" << R
|
||||||
|
<< " base=" << base
|
||||||
|
<< " kernel=" << t_kernel << " D2H=" << t_d2h << " us" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int k = 0; k < R; k++)
|
||||||
|
ret_p[base + k] = TensorRemove(result._internal[k]);
|
||||||
|
}
|
||||||
|
|
||||||
template <class vobj>
|
template <class vobj>
|
||||||
inline typename vobj::scalar_objectD sumD_gpu_large(const vobj *lat, Integer osites)
|
inline typename vobj::scalar_objectD sumD_gpu_large(const vobj *lat, Integer osites)
|
||||||
{
|
{
|
||||||
typedef typename vobj::vector_type vector;
|
typedef typename vobj::vector_type vector;
|
||||||
typedef typename vobj::scalar_typeD scalarD;
|
typedef typename vobj::scalar_typeD scalarD;
|
||||||
typedef typename vobj::scalar_objectD sobj;
|
typedef typename vobj::scalar_objectD sobjD;
|
||||||
sobj ret;
|
|
||||||
scalarD *ret_p = (scalarD *)&ret;
|
|
||||||
|
|
||||||
const int words = sizeof(vobj) / sizeof(vector);
|
const int words = sizeof(vobj) / sizeof(vector);
|
||||||
|
sobjD ret; zeroit(ret);
|
||||||
|
scalarD *ret_p = (scalarD *)&ret;
|
||||||
|
|
||||||
deviceVector<vector> buffer(osites);
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
vector *dat = (vector *)lat;
|
RealD t_large = -usecond();
|
||||||
vector *buf = &buffer[0];
|
#endif
|
||||||
iScalar<vector> *tbuf =(iScalar<vector> *) &buffer[0];
|
int w = 0;
|
||||||
for(int w=0;w<words;w++) {
|
while (w + 12 <= words) { sumD_gpu_reduce_words<12>(lat, osites, ret_p, w); w += 12; }
|
||||||
|
while (w + 4 <= words) { sumD_gpu_reduce_words< 4>(lat, osites, ret_p, w); w += 4; }
|
||||||
|
while (w < words) { sumD_gpu_reduce_words< 1>(lat, osites, ret_p, w); w += 1; }
|
||||||
|
#ifdef GRID_REDUCTION_TIMING
|
||||||
|
t_large += usecond();
|
||||||
|
std::cout << GridLogDebug << "sumD_gpu_large"
|
||||||
|
<< " sizeof(sobjD)=" << sizeof(sobjD)
|
||||||
|
<< " words=" << words << " total=" << t_large << " us" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
accelerator_for(ss,osites,1,{
|
|
||||||
buf[ss] = dat[ss*words+w];
|
|
||||||
});
|
|
||||||
|
|
||||||
ret_p[w] = sumD_gpu_small(tbuf,osites);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,5 +438,11 @@ inline typename vobj::scalar_object sum_gpu_large(const vobj *lat, Integer osite
|
|||||||
result = sumD_gpu_large(lat,osites);
|
result = sumD_gpu_large(lat,osites);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
template<class Word> Word checksum_gpu(Word *vec,uint64_t L)
|
||||||
|
{
|
||||||
|
Word w;
|
||||||
|
bzero(&w,sizeof(w));
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -11,23 +11,22 @@ inline typename vobj::scalar_objectD sumD_gpu_tensor(const vobj *lat, Integer os
|
|||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
typedef typename vobj::scalar_objectD sobjD;
|
typedef typename vobj::scalar_objectD sobjD;
|
||||||
|
|
||||||
sobj identity; zeroit(identity);
|
sobjD identity; zeroit(identity);
|
||||||
sobj ret; zeroit(ret);
|
sobjD ret; zeroit(ret);
|
||||||
Integer nsimd= vobj::Nsimd();
|
|
||||||
{
|
{
|
||||||
sycl::buffer<sobj, 1> abuff(&ret, {1});
|
sycl::buffer<sobjD, 1> abuff(&ret, {1});
|
||||||
theGridAccelerator->submit([&](sycl::handler &cgh) {
|
theGridAccelerator->submit([&](sycl::handler &cgh) {
|
||||||
auto Reduction = sycl::reduction(abuff, cgh, identity, std::plus<>());
|
auto Reduction = sycl::reduction(abuff, cgh, identity, std::plus<>());
|
||||||
cgh.parallel_for(sycl::range<1>{osites},
|
cgh.parallel_for(sycl::range<1>{(size_t)osites},
|
||||||
Reduction,
|
Reduction,
|
||||||
[=](sycl::id<1> item, auto &sum) {
|
[=](sycl::id<1> item, auto &sum) {
|
||||||
auto osite = item[0];
|
sobj s = Reduce(lat[item[0]]);
|
||||||
sum +=Reduce(lat[osite]);
|
sobjD sd; sd = s;
|
||||||
|
sum += sd;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
sobjD dret; convertType(dret,ret);
|
return ret;
|
||||||
return dret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class vobj>
|
template <class vobj>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ inline void sliceSumReduction_cub_small(const vobj *Data,
|
|||||||
#if defined(__CUDACC__) && (__CUDACC_VER_MAJOR__ >= 13)
|
#if defined(__CUDACC__) && (__CUDACC_VER_MAJOR__ >= 13)
|
||||||
#define GRID_CUB_SUM_OP ::cuda::std::plus<>{}
|
#define GRID_CUB_SUM_OP ::cuda::std::plus<>{}
|
||||||
#else
|
#else
|
||||||
#define GRID_CUB_SUM_OP ::cub::Sum()
|
#define GRID_CUB_SUM_OP ::gpucub::Sum()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gpuError_t gpuErr = gpucub::DeviceSegmentedReduce::Reduce(temp_storage_array, temp_storage_bytes, rb_p,d_out, rd, d_offsets, d_offsets+1, GRID_CUB_SUM_OP, zero_init, computeStream);
|
gpuError_t gpuErr = gpucub::DeviceSegmentedReduce::Reduce(temp_storage_array, temp_storage_bytes, rb_p,d_out, rd, d_offsets, d_offsets+1, GRID_CUB_SUM_OP, zero_init, computeStream);
|
||||||
|
|||||||
@@ -124,6 +124,68 @@ Lattice<iScalar<iScalar<iMatrix<vComplexD, N> > > > Inverse(const Lattice<iScala
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
Lattice<iMatrix<iScalar<iScalar<iScalar<vComplexD> > > , N> > Inverse(const Lattice<iMatrix<iScalar<iScalar<iScalar<vComplexD> > >, N> > &Umu)
|
||||||
|
{
|
||||||
|
GridBase *grid=Umu.Grid();
|
||||||
|
auto lvol = grid->lSites();
|
||||||
|
Lattice<iMatrix<iScalar<iScalar<iScalar<vComplexD> > >, N > > ret(grid);
|
||||||
|
|
||||||
|
autoView(Umu_v,Umu,CpuRead);
|
||||||
|
autoView(ret_v,ret,CpuWrite);
|
||||||
|
thread_for(site,lvol,{
|
||||||
|
Eigen::MatrixXcd EigenU = Eigen::MatrixXcd::Zero(N,N);
|
||||||
|
Coordinate lcoor;
|
||||||
|
grid->LocalIndexToLocalCoor(site, lcoor);
|
||||||
|
iMatrix<iScalar<iScalar<iScalar<ComplexD> > >, N > Us;
|
||||||
|
iMatrix<iScalar<iScalar<iScalar<ComplexD> > >, N > Ui;
|
||||||
|
peekLocalSite(Us, Umu_v, lcoor);
|
||||||
|
for(int i=0;i<N;i++){
|
||||||
|
for(int j=0;j<N;j++){
|
||||||
|
EigenU(i,j) = Us(i,j)()()();
|
||||||
|
}}
|
||||||
|
Eigen::MatrixXcd EigenUinv = EigenU.inverse();
|
||||||
|
for(int i=0;i<N;i++){
|
||||||
|
for(int j=0;j<N;j++){
|
||||||
|
Ui(i,j)()()() = EigenUinv(i,j);
|
||||||
|
}}
|
||||||
|
pokeLocalSite(Ui,ret_v,lcoor);
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
Lattice<iMatrix<iScalar<iScalar<iScalar<iScalar<vComplexD> > > > , N> > Inverse(const Lattice<iMatrix<iScalar<iScalar<iScalar<iScalar<vComplexD> > > >, N> > &Umu)
|
||||||
|
{
|
||||||
|
GridBase *grid=Umu.Grid();
|
||||||
|
auto lvol = grid->lSites();
|
||||||
|
Lattice<iMatrix<iScalar<iScalar<iScalar<iScalar<vComplexD> > > >, N > > ret(grid);
|
||||||
|
|
||||||
|
autoView(Umu_v,Umu,CpuRead);
|
||||||
|
autoView(ret_v,ret,CpuWrite);
|
||||||
|
thread_for(site,lvol,{
|
||||||
|
Eigen::MatrixXcd EigenU = Eigen::MatrixXcd::Zero(N,N);
|
||||||
|
Coordinate lcoor;
|
||||||
|
grid->LocalIndexToLocalCoor(site, lcoor);
|
||||||
|
iMatrix<iScalar<iScalar<iScalar<iScalar<ComplexD> > > >, N > Us;
|
||||||
|
iMatrix<iScalar<iScalar<iScalar<iScalar<ComplexD> > > >, N > Ui;
|
||||||
|
peekLocalSite(Us, Umu_v, lcoor);
|
||||||
|
for(int i=0;i<N;i++){
|
||||||
|
for(int j=0;j<N;j++){
|
||||||
|
EigenU(i,j) = Us(i,j)()()()();
|
||||||
|
}}
|
||||||
|
Eigen::MatrixXcd EigenUinv = EigenU.inverse();
|
||||||
|
for(int i=0;i<N;i++){
|
||||||
|
for(int j=0;j<N;j++){
|
||||||
|
Ui(i,j)()()()() = EigenUinv(i,j);
|
||||||
|
}}
|
||||||
|
pokeLocalSite(Ui,ret_v,lcoor);
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,3 +2,7 @@
|
|||||||
|
|
||||||
int Grid::BinaryIO::latticeWriteMaxRetry = -1;
|
int Grid::BinaryIO::latticeWriteMaxRetry = -1;
|
||||||
Grid::BinaryIO::IoPerf Grid::BinaryIO::lastPerf;
|
Grid::BinaryIO::IoPerf Grid::BinaryIO::lastPerf;
|
||||||
|
|
||||||
|
// Target size of a single contiguous file extent under BINARYIO_AGGREGATE.
|
||||||
|
// 4MB is around the knee for Lustre; exposed so it can be swept at runtime.
|
||||||
|
uint64_t Grid::BinaryIO::aggregateTargetBytes = 4*1024*1024;
|
||||||
|
|||||||
+462
-11
@@ -39,6 +39,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
@@ -87,6 +88,7 @@ class BinaryIO {
|
|||||||
|
|
||||||
static IoPerf lastPerf;
|
static IoPerf lastPerf;
|
||||||
static int latticeWriteMaxRetry;
|
static int latticeWriteMaxRetry;
|
||||||
|
static uint64_t aggregateTargetBytes;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// more byte manipulation helpers
|
// more byte manipulation helpers
|
||||||
@@ -253,12 +255,402 @@ class BinaryIO {
|
|||||||
// Read or Write distributed lexico array of ANY object to a specific location in file
|
// Read or Write distributed lexico array of ANY object to a specific location in file
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static const int BINARYIO_AGGREGATE = 0x20;
|
||||||
static const int BINARYIO_MASTER_APPEND = 0x10;
|
static const int BINARYIO_MASTER_APPEND = 0x10;
|
||||||
static const int BINARYIO_UNORDERED = 0x08;
|
static const int BINARYIO_UNORDERED = 0x08;
|
||||||
static const int BINARYIO_LEXICOGRAPHIC = 0x04;
|
static const int BINARYIO_LEXICOGRAPHIC = 0x04;
|
||||||
static const int BINARYIO_READ = 0x02;
|
static const int BINARYIO_READ = 0x02;
|
||||||
static const int BINARYIO_WRITE = 0x01;
|
static const int BINARYIO_WRITE = 0x01;
|
||||||
|
|
||||||
|
// Single point of control for the aggregated path. Setting
|
||||||
|
// GRID_BINARYIO_NOAGGREGATE falls back to plain lexicographic I/O.
|
||||||
|
static int DefaultControl(void)
|
||||||
|
{
|
||||||
|
static int ctrl = getenv("GRID_BINARYIO_NOAGGREGATE")
|
||||||
|
? BINARYIO_LEXICOGRAPHIC
|
||||||
|
: BINARYIO_LEXICOGRAPHIC|BINARYIO_AGGREGATE;
|
||||||
|
return ctrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MPI_IO
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Aggregation: self controlled transposition onto an I/O friendly layout.
|
||||||
|
//
|
||||||
|
// Under BINARYIO_LEXICOGRAPHIC the subarray file view handed to MPI-IO has
|
||||||
|
// contiguous runs of only lLattice[0]*sizeof(fobj) bytes -- a few KB for
|
||||||
|
// typical local volumes. Rather than rely on collective buffering to repair
|
||||||
|
// that, redistribute the payload ourselves so every rank owns a contiguous
|
||||||
|
// range of the global lexicographic site ordering, then issue large plain
|
||||||
|
// contiguous writes.
|
||||||
|
//
|
||||||
|
// "Un-splitting" the nunsplit fastest dimensions means the row of ranks
|
||||||
|
// sharing the remaining process coordinates collectively owns whole global
|
||||||
|
// hyperplanes. All data movement is then confined to that row communicator.
|
||||||
|
// Every rank still owns exactly lSites() sites afterwards, so the exchange is
|
||||||
|
// a pure permutation and needs no divisibility condition on the process grid.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct AggregationPlan {
|
||||||
|
int nunsplit{0}; // number of fastest dimensions un-split
|
||||||
|
int rowsize{0}; // ranks in the aggregation (row) communicator
|
||||||
|
int rowrank{0}; // our logical (lexicographic) index within the row
|
||||||
|
uint64_t lsites{0}; // sites per rank -- invariant under the permutation
|
||||||
|
uint64_t chunk{0}; // sites in one globally contiguous run owned by the row
|
||||||
|
std::unique_ptr<CartesianCommunicator> rowcomm;
|
||||||
|
// counts and displacements are indexed by rank within rowcomm
|
||||||
|
std::vector<int> sendcounts, senddispls, recvcounts, recvdispls;
|
||||||
|
std::vector<uint64_t> scatter; // recv slot -> slot in the aggregated buffer
|
||||||
|
std::vector<uint64_t> extentGsite; // global lex site index of extent start
|
||||||
|
std::vector<uint64_t> extentLocal; // offset of extent within aggregated buffer
|
||||||
|
std::vector<uint64_t> extentSites; // sites in this extent
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void BuildAggregationPlan(GridBase *grid,uint64_t fobjSize,AggregationPlan &p)
|
||||||
|
{
|
||||||
|
int ndim = grid->Dimensions();
|
||||||
|
Coordinate psizes = grid->ProcessorGrid();
|
||||||
|
Coordinate pcoor = grid->ThisProcessorCoor();
|
||||||
|
Coordinate gLattice= grid->GlobalDimensions();
|
||||||
|
Coordinate lLattice= grid->LocalDimensions();
|
||||||
|
Coordinate lstart = grid->LocalStarts();
|
||||||
|
|
||||||
|
uint64_t lsites = grid->lSites();
|
||||||
|
p.lsites = lsites;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Un-splitting dims 0..k-1 gives the row a contiguous run of
|
||||||
|
// chunk(k) = prod_{d<k} gLattice[d] * lLattice[k]
|
||||||
|
// sites, and each rank writes extents of min(chunk,lsites). Take the
|
||||||
|
// smallest k that reaches the target so we disturb as few dimensions --
|
||||||
|
// and move as little data -- as possible.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
int k = ndim-1;
|
||||||
|
for(int trial=1; trial<ndim; trial++){
|
||||||
|
uint64_t chunk = lLattice[trial];
|
||||||
|
for(int d=0; d<trial; d++) chunk *= gLattice[d];
|
||||||
|
if ( std::min(chunk,lsites)*fobjSize >= aggregateTargetBytes ) { k = trial; break; }
|
||||||
|
}
|
||||||
|
p.nunsplit = k;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// The box the row collectively owns, expressed in global coordinates.
|
||||||
|
// Restricting the global lexicographic order to this box preserves the
|
||||||
|
// ordering, so the row index below is monotone in the global index.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
Coordinate B(ndim), S(ndim);
|
||||||
|
for(int d=0; d<ndim; d++){
|
||||||
|
if ( d<k ) { B[d] = gLattice[d]; S[d] = 0; }
|
||||||
|
else { B[d] = lLattice[d]; S[d] = lstart[d]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t chunk = lLattice[k];
|
||||||
|
for(int d=0; d<k; d++) chunk *= gLattice[d];
|
||||||
|
p.chunk = chunk;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Row communicator: the ranks sharing the process coordinates of the slow
|
||||||
|
// (still split) dimensions. This is the sub-division the Cartesian
|
||||||
|
// communicator already performs for AllToAll(dim,...), widened from one
|
||||||
|
// dimension to the k fastest.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
Coordinate row(ndim,1);
|
||||||
|
for(int d=0; d<k; d++) row[d] = psizes[d];
|
||||||
|
int srank;
|
||||||
|
p.rowcomm.reset(new CartesianCommunicator(row,*grid,srank));
|
||||||
|
p.rowsize = p.rowcomm->ProcessorCount();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Our logical index in the row is the forward lexicographic index of the
|
||||||
|
// un-split process coordinates, so that increasing logical index means
|
||||||
|
// increasing global lexicographic position in the file. The communicator
|
||||||
|
// numbers its own ranks by the reversed (MPI) convention, so build the map
|
||||||
|
// between the two rather than assuming either.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
int64_t logical=0, lstride=1;
|
||||||
|
for(int d=0; d<k; d++){ logical += pcoor[d]*lstride; lstride *= psizes[d]; }
|
||||||
|
GRID_ASSERT(lstride == (int64_t)p.rowsize);
|
||||||
|
p.rowrank = (int)logical;
|
||||||
|
|
||||||
|
std::vector<uint64_t> commOf(p.rowsize,0);
|
||||||
|
commOf[p.rowrank] = (uint64_t)p.rowcomm->ThisRank();
|
||||||
|
p.rowcomm->GlobalSumVector(&commOf[0],p.rowsize);
|
||||||
|
|
||||||
|
uint64_t mystart = (uint64_t)p.rowrank * lsites;
|
||||||
|
uint64_t myend = mystart + lsites;
|
||||||
|
|
||||||
|
Coordinate lcoor(ndim), bcoor(ndim), gcoor(ndim);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Send side. Walking our local sites in local lexicographic order walks
|
||||||
|
// the row index monotonically, so the send buffer is iodata untouched and
|
||||||
|
// we need only the per destination counts.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
std::vector<int> sendLogical(p.rowsize,0);
|
||||||
|
for(uint64_t L=0; L<lsites; L++){
|
||||||
|
Lexicographic::CoorFromIndex(lcoor,L,lLattice);
|
||||||
|
for(int d=0; d<ndim; d++) bcoor[d] = (d<k) ? (lstart[d]+lcoor[d]) : lcoor[d];
|
||||||
|
int64_t ri; Lexicographic::IndexFromCoor(bcoor,ri,B);
|
||||||
|
sendLogical[ ri/(int64_t)lsites ]++;
|
||||||
|
}
|
||||||
|
p.sendcounts.assign(p.rowsize,0);
|
||||||
|
p.senddispls.assign(p.rowsize,0);
|
||||||
|
{ int64_t disp=0;
|
||||||
|
for(int d=0; d<p.rowsize; d++){ // send buffer is in logical order
|
||||||
|
int c = (int)commOf[d];
|
||||||
|
p.sendcounts[c] = sendLogical[d];
|
||||||
|
p.senddispls[c] = (int)disp;
|
||||||
|
disp += sendLogical[d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Receive side. For each slot of our aggregated range work out which rank
|
||||||
|
// of the row owns it. Within one source the slots arrive in increasing row
|
||||||
|
// index order, which is the order the source sends them in.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
std::vector<int> recvLogical(p.rowsize,0), recvDisplLogical(p.rowsize,0);
|
||||||
|
std::vector<int> source(lsites);
|
||||||
|
for(uint64_t pos=0; pos<lsites; pos++){
|
||||||
|
Lexicographic::CoorFromIndex(bcoor,(int64_t)(mystart+pos),B);
|
||||||
|
int64_t j=0, jstride=1;
|
||||||
|
for(int d=0; d<k; d++){ j += (bcoor[d]/lLattice[d])*jstride; jstride *= psizes[d]; }
|
||||||
|
source[pos] = (int)j;
|
||||||
|
recvLogical[j]++;
|
||||||
|
}
|
||||||
|
p.recvcounts.assign(p.rowsize,0);
|
||||||
|
p.recvdispls.assign(p.rowsize,0);
|
||||||
|
{ int64_t disp=0;
|
||||||
|
for(int s=0; s<p.rowsize; s++){ // recv buffer is in logical order
|
||||||
|
int c = (int)commOf[s];
|
||||||
|
recvDisplLogical[s] = (int)disp;
|
||||||
|
p.recvcounts[c] = recvLogical[s];
|
||||||
|
p.recvdispls[c] = (int)disp;
|
||||||
|
disp += recvLogical[s];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.scatter.resize(lsites);
|
||||||
|
{
|
||||||
|
std::vector<int> fill(p.rowsize,0);
|
||||||
|
for(uint64_t pos=0; pos<lsites; pos++){
|
||||||
|
int j = source[pos];
|
||||||
|
p.scatter[ recvDisplLogical[j] + fill[j]++ ] = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// The two sides are derived independently; make them check each other.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> sendc(p.rowsize),recvc(p.rowsize);
|
||||||
|
for(int c=0;c<p.rowsize;c++) sendc[c]=(uint64_t)p.sendcounts[c];
|
||||||
|
p.rowcomm->AllToAll(&sendc[0],&recvc[0],1,sizeof(uint64_t));
|
||||||
|
for(int c=0;c<p.rowsize;c++) GRID_ASSERT((int)recvc[c]==p.recvcounts[c]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Decompose our range into globally contiguous file extents.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
for(uint64_t c = mystart/chunk; c <= (myend-1)/chunk; c++){
|
||||||
|
uint64_t lo = std::max(mystart, c*chunk);
|
||||||
|
uint64_t hi = std::min(myend, (c+1)*chunk);
|
||||||
|
Lexicographic::CoorFromIndex(bcoor,(int64_t)(c*chunk),B);
|
||||||
|
for(int d=0;d<ndim;d++) gcoor[d] = (d<k) ? bcoor[d] : bcoor[d]+S[d];
|
||||||
|
int64_t gbase; Lexicographic::IndexFromCoor(gcoor,gbase,gLattice);
|
||||||
|
p.extentGsite.push_back( (uint64_t)gbase + (lo - c*chunk) );
|
||||||
|
p.extentLocal.push_back( lo - mystart );
|
||||||
|
p.extentSites.push_back( hi - lo );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ReportAggregationPlan(GridBase *grid,const AggregationPlan &p,uint64_t fobjSize,const char *what)
|
||||||
|
{
|
||||||
|
if ( !grid->IsBoss() ) return;
|
||||||
|
std::cout << GridLogMessage << "IOobject: aggregate " << what
|
||||||
|
<< " un-splitting " << p.nunsplit << " fastest dimensions, row of "
|
||||||
|
<< p.rowsize << " ranks" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "IOobject: aggregate " << p.extentSites.size()
|
||||||
|
<< " extent(s)/rank, first " << p.extentSites[0]*fobjSize/1024./1024. << " MB"
|
||||||
|
<< " (target " << aggregateTargetBytes/1024./1024. << " MB)" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "IOobject: aggregate buffer overhead "
|
||||||
|
<< p.lsites*fobjSize/1024./1024. << " MB/rank" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stage timings. The interesting quantity is the slowest rank, since every
|
||||||
|
// stage is followed sooner or later by a synchronisation, so reduce with
|
||||||
|
// GlobalMax rather than reporting whatever the boss happened to see.
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
static inline void ReportStages(GridBase *grid,const char *what,
|
||||||
|
const std::vector<const char *> &names,
|
||||||
|
std::vector<RealD> &useconds)
|
||||||
|
{
|
||||||
|
GRID_ASSERT(names.size()==useconds.size());
|
||||||
|
for(uint64_t i=0;i<useconds.size();i++) grid->GlobalMax(useconds[i]);
|
||||||
|
if ( grid->IsBoss() ) {
|
||||||
|
std::cout << GridLogMessage << "IOobject: aggregate " << what << " stages (max over ranks, s):";
|
||||||
|
for(uint64_t i=0;i<names.size();i++)
|
||||||
|
std::cout << " " << names[i] << " " << useconds[i]/1.0e6;
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class fobj>
|
||||||
|
static inline void AggregateExchange(GridBase *grid,AggregationPlan &p,std::vector<fobj> &iodata,
|
||||||
|
std::vector<fobj> &aggregated,int forward)
|
||||||
|
{
|
||||||
|
uint64_t lsites = p.lsites;
|
||||||
|
GridStopWatch talloc,tperm,tcomm;
|
||||||
|
|
||||||
|
talloc.Start();
|
||||||
|
std::vector<fobj> tmp(lsites);
|
||||||
|
talloc.Stop();
|
||||||
|
|
||||||
|
if ( forward ) { // iodata (local order) -> aggregated (lexicographic order)
|
||||||
|
tcomm.Start();
|
||||||
|
p.rowcomm->AllToAllV(&iodata[0],p.sendcounts,p.senddispls,
|
||||||
|
&tmp[0], p.recvcounts,p.recvdispls,sizeof(fobj));
|
||||||
|
tcomm.Stop();
|
||||||
|
tperm.Start();
|
||||||
|
thread_for(s,lsites,{ aggregated[p.scatter[s]] = tmp[s]; });
|
||||||
|
tperm.Stop();
|
||||||
|
} else { // aggregated -> iodata, the exact mirror
|
||||||
|
tperm.Start();
|
||||||
|
thread_for(s,lsites,{ tmp[s] = aggregated[p.scatter[s]]; });
|
||||||
|
tperm.Stop();
|
||||||
|
tcomm.Start();
|
||||||
|
p.rowcomm->AllToAllV(&tmp[0], p.recvcounts,p.recvdispls,
|
||||||
|
&iodata[0],p.sendcounts,p.senddispls,sizeof(fobj));
|
||||||
|
tcomm.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RealD> us = { (RealD)talloc.useconds(), (RealD)tperm.useconds(), (RealD)tcomm.useconds() };
|
||||||
|
ReportStages(grid,forward?"exchange (write)":"exchange (read)",
|
||||||
|
{"alloc","permute","alltoallv"},us);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class fobj>
|
||||||
|
static inline void AggregateWrite(GridBase *grid,AggregationPlan &p,std::vector<fobj> &aggregated,
|
||||||
|
std::string file,uint64_t offset)
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// All ranks write concurrently into a shared file, so the file must exist
|
||||||
|
// before any of them open it for update, but it does NOT have to be the
|
||||||
|
// right length first: the extents tile the record exactly, so writing them
|
||||||
|
// extends a short file to precisely offset+payload.
|
||||||
|
//
|
||||||
|
// Records are created in sequence, so this payload ends the file: the
|
||||||
|
// length must end up precisely offset+payload. Anything beyond is left
|
||||||
|
// over from whatever the file previously held and must not survive -- a
|
||||||
|
// shorter new record written over a longer old one would otherwise leave
|
||||||
|
// a trailing fragment of the previous contents masquerading as data.
|
||||||
|
// That is the only case needing a truncate, so stat first and truncate
|
||||||
|
// afterwards only when the size actually came out wrong. Measured on
|
||||||
|
// Frontier, an unconditional truncate up front cost 0.22 to 5.4 s per
|
||||||
|
// record -- 15 to 25% of a 19 GB write and 100% of a small one -- while
|
||||||
|
// create, open and close together cost a few milliseconds. It is per
|
||||||
|
// record, so multi record files do not amortise it away.
|
||||||
|
//
|
||||||
|
// ::truncate is used because the C++ standard library cannot express this.
|
||||||
|
// std::filebuf has no length operation at all; ios::trunc only truncates to
|
||||||
|
// zero; seeking past the end and writing a byte can grow a file but never
|
||||||
|
// shrink one; and there is no portable way to recover a descriptor from a
|
||||||
|
// stream in order to call ftruncate. C++17 does finally offer
|
||||||
|
// std::filesystem::resize_file, but that would be Grid's first <filesystem>
|
||||||
|
// dependency and needs -lstdc++fs on the older toolchains still in use.
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
GridStopWatch tcreate,ttrunc,tbar,topen,twrite,tclose,tskew;
|
||||||
|
uint64_t need = offset + (uint64_t)grid->_gsites*sizeof(fobj);
|
||||||
|
|
||||||
|
tcreate.Start();
|
||||||
|
if ( grid->IsBoss() ) {
|
||||||
|
// opening for update needs the file to exist; create one only if not
|
||||||
|
std::fstream probe(file,std::ios::binary|std::ios::out|std::ios::in);
|
||||||
|
if ( !probe.is_open() ) {
|
||||||
|
std::ofstream create(file,std::ios::binary|std::ios::out);
|
||||||
|
create.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcreate.Stop();
|
||||||
|
|
||||||
|
tbar.Start();
|
||||||
|
grid->Barrier();
|
||||||
|
tbar.Stop();
|
||||||
|
|
||||||
|
std::ofstream fout;
|
||||||
|
fout.exceptions( std::fstream::failbit | std::fstream::badbit );
|
||||||
|
try {
|
||||||
|
topen.Start();
|
||||||
|
fout.open(file,std::ios::binary|std::ios::out|std::ios::in);
|
||||||
|
topen.Stop();
|
||||||
|
twrite.Start();
|
||||||
|
for(uint64_t e=0;e<p.extentSites.size();e++){
|
||||||
|
fout.seekp(offset + p.extentGsite[e]*sizeof(fobj));
|
||||||
|
fout.write((char *)&aggregated[p.extentLocal[e]],p.extentSites[e]*sizeof(fobj));
|
||||||
|
}
|
||||||
|
twrite.Stop();
|
||||||
|
tclose.Start();
|
||||||
|
fout.close(); // flushes the stream buffer; does not force writeback
|
||||||
|
tclose.Stop();
|
||||||
|
} catch (const std::fstream::failure& exc) {
|
||||||
|
std::cout << GridLogError << "Error in aggregate write to " << file << std::endl;
|
||||||
|
std::cout << GridLogError << "Exception description: " << exc.what() << std::endl;
|
||||||
|
GridAbort();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Timed apart from the truncate that follows it. seek+write above is the
|
||||||
|
// slowest rank; this barrier is what the fastest rank then waits, so the
|
||||||
|
// pair separates the write cost from the spread across ranks. Folding it
|
||||||
|
// into the truncate makes a millisecond stat look like a second.
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
tskew.Start();
|
||||||
|
grid->Barrier(); // every extent must be on its way first
|
||||||
|
tskew.Stop();
|
||||||
|
|
||||||
|
ttrunc.Start();
|
||||||
|
if ( grid->IsBoss() ) {
|
||||||
|
struct stat sb;
|
||||||
|
int ierr = ::stat(file.c_str(),&sb);
|
||||||
|
GRID_ASSERT(ierr==0);
|
||||||
|
if ( (uint64_t)sb.st_size != need ) { // only when a longer record preceded us
|
||||||
|
ierr = ::truncate(file.c_str(),(off_t)need);
|
||||||
|
GRID_ASSERT(ierr==0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grid->Barrier();
|
||||||
|
ttrunc.Stop();
|
||||||
|
|
||||||
|
std::vector<RealD> us = { (RealD)tcreate.useconds(), (RealD)tbar.useconds(),
|
||||||
|
(RealD)topen.useconds(), (RealD)twrite.useconds(),
|
||||||
|
(RealD)tclose.useconds(), (RealD)tskew.useconds(),
|
||||||
|
(RealD)ttrunc.useconds() };
|
||||||
|
ReportStages(grid,"write",{"create","barrier","open","seek+write","close","skew","stat+truncate"},us);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class fobj>
|
||||||
|
static inline void AggregateRead(GridBase *grid,AggregationPlan &p,std::vector<fobj> &aggregated,
|
||||||
|
std::string file,uint64_t offset)
|
||||||
|
{
|
||||||
|
GridStopWatch topen,tread,tclose;
|
||||||
|
std::ifstream fin;
|
||||||
|
topen.Start();
|
||||||
|
fin.open(file,std::ios::binary|std::ios::in);
|
||||||
|
topen.Stop();
|
||||||
|
tread.Start();
|
||||||
|
for(uint64_t e=0;e<p.extentSites.size();e++){
|
||||||
|
fin.seekg(offset + p.extentGsite[e]*sizeof(fobj));
|
||||||
|
fin.read((char *)&aggregated[p.extentLocal[e]],p.extentSites[e]*sizeof(fobj));
|
||||||
|
GRID_ASSERT(fin.fail()==0);
|
||||||
|
}
|
||||||
|
tread.Stop();
|
||||||
|
tclose.Start();
|
||||||
|
fin.close();
|
||||||
|
tclose.Stop();
|
||||||
|
|
||||||
|
std::vector<RealD> us = { (RealD)topen.useconds(), (RealD)tread.useconds(), (RealD)tclose.useconds() };
|
||||||
|
ReportStages(grid,"read",{"open","seek+read","close"},us);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<class word,class fobj>
|
template<class word,class fobj>
|
||||||
static inline void IOobject(word w,
|
static inline void IOobject(word w,
|
||||||
GridBase *grid,
|
GridBase *grid,
|
||||||
@@ -302,6 +694,18 @@ class BinaryIO {
|
|||||||
lStart[d] = 0;
|
lStart[d] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Aggregate the lexicographic layout onto contiguous per rank extents
|
||||||
|
// ourselves rather than leaving it to MPI-IO collective buffering
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
int aggregate = (control & BINARYIO_AGGREGATE)
|
||||||
|
&& (control & BINARYIO_LEXICOGRAPHIC)
|
||||||
|
&& !(control & BINARYIO_MASTER_APPEND)
|
||||||
|
&& (nrank > 1);
|
||||||
|
#ifndef USE_MPI_IO
|
||||||
|
GRID_ASSERT(aggregate==0); // BINARYIO_AGGREGATE requires MPI
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MPI_IO
|
#ifdef USE_MPI_IO
|
||||||
std::vector<int> distribs(ndim,MPI_DISTRIBUTE_BLOCK);
|
std::vector<int> distribs(ndim,MPI_DISTRIBUTE_BLOCK);
|
||||||
std::vector<int> dargs (ndim,MPI_DISTRIBUTE_DFLT_DARG);
|
std::vector<int> dargs (ndim,MPI_DISTRIBUTE_DFLT_DARG);
|
||||||
@@ -329,6 +733,8 @@ class BinaryIO {
|
|||||||
ierr = MPI_Type_contiguous(numword,mpiword,&mpiObject); GRID_ASSERT(ierr==0);
|
ierr = MPI_Type_contiguous(numword,mpiword,&mpiObject); GRID_ASSERT(ierr==0);
|
||||||
ierr = MPI_Type_commit(&mpiObject);
|
ierr = MPI_Type_commit(&mpiObject);
|
||||||
|
|
||||||
|
// The subarray view is what aggregation exists to avoid; do not build it
|
||||||
|
if ( !aggregate ) {
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// File global array data type
|
// File global array data type
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -340,6 +746,7 @@ class BinaryIO {
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
ierr=MPI_Type_create_subarray(ndim,&lLattice[0],&lLattice[0],&lStart[0],MPI_ORDER_FORTRAN, mpiObject,&localArray); GRID_ASSERT(ierr==0);
|
ierr=MPI_Type_create_subarray(ndim,&lLattice[0],&lLattice[0],&lStart[0],MPI_ORDER_FORTRAN, mpiObject,&localArray); GRID_ASSERT(ierr==0);
|
||||||
ierr=MPI_Type_commit(&localArray); GRID_ASSERT(ierr==0);
|
ierr=MPI_Type_commit(&localArray); GRID_ASSERT(ierr==0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -358,7 +765,19 @@ class BinaryIO {
|
|||||||
|
|
||||||
timer.Start();
|
timer.Start();
|
||||||
|
|
||||||
if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) {
|
if ( aggregate ) {
|
||||||
|
#ifdef USE_MPI_IO
|
||||||
|
std::cout<< GridLogMessage<<"IOobject: aggregate read I/O "<< file<< std::endl;
|
||||||
|
AggregationPlan plan;
|
||||||
|
BuildAggregationPlan(grid,sizeof(fobj),plan);
|
||||||
|
ReportAggregationPlan(grid,plan,sizeof(fobj),"read");
|
||||||
|
std::vector<fobj> aggregated(lsites);
|
||||||
|
AggregateRead(grid,plan,aggregated,file,offset);
|
||||||
|
AggregateExchange(grid,plan,iodata,aggregated,0);
|
||||||
|
#else
|
||||||
|
GRID_ASSERT(0);
|
||||||
|
#endif
|
||||||
|
} else if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) {
|
||||||
#ifdef USE_MPI_IO
|
#ifdef USE_MPI_IO
|
||||||
std::cout<< GridLogMessage<<"IOobject: MPI read I/O "<< file<< std::endl;
|
std::cout<< GridLogMessage<<"IOobject: MPI read I/O "<< file<< std::endl;
|
||||||
ierr=MPI_File_open(grid->communicator,(char *) file.c_str(), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); GRID_ASSERT(ierr==0);
|
ierr=MPI_File_open(grid->communicator,(char *) file.c_str(), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); GRID_ASSERT(ierr==0);
|
||||||
@@ -416,7 +835,25 @@ class BinaryIO {
|
|||||||
grid->Barrier();
|
grid->Barrier();
|
||||||
|
|
||||||
timer.Start();
|
timer.Start();
|
||||||
if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) {
|
if ( aggregate ) {
|
||||||
|
#ifdef USE_MPI_IO
|
||||||
|
std::cout << GridLogMessage <<"IOobject: aggregate write I/O " << file << std::endl;
|
||||||
|
AggregationPlan plan;
|
||||||
|
BuildAggregationPlan(grid,sizeof(fobj),plan);
|
||||||
|
ReportAggregationPlan(grid,plan,sizeof(fobj),"write");
|
||||||
|
std::vector<fobj> aggregated(lsites);
|
||||||
|
AggregateExchange(grid,plan,iodata,aggregated,1);
|
||||||
|
AggregateWrite(grid,plan,aggregated,file,offset);
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Not every rank ends at the end of the payload, so the position can
|
||||||
|
// not be recovered from a file handle. Callers (Lime record chaining)
|
||||||
|
// rely on this being the first byte past the record.
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
offset = offset + (uint64_t)grid->_gsites*sizeof(fobj);
|
||||||
|
#else
|
||||||
|
GRID_ASSERT(0);
|
||||||
|
#endif
|
||||||
|
} else if ( (control & BINARYIO_LEXICOGRAPHIC) && (nrank > 1) ) {
|
||||||
#ifdef USE_MPI_IO
|
#ifdef USE_MPI_IO
|
||||||
std::cout << GridLogMessage <<"IOobject: MPI write I/O " << file << std::endl;
|
std::cout << GridLogMessage <<"IOobject: MPI write I/O " << file << std::endl;
|
||||||
ierr = MPI_File_open(grid->communicator, (char *)file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_INFO_NULL, &fh);
|
ierr = MPI_File_open(grid->communicator, (char *)file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_INFO_NULL, &fh);
|
||||||
@@ -461,12 +898,26 @@ class BinaryIO {
|
|||||||
|
|
||||||
std::ofstream fout;
|
std::ofstream fout;
|
||||||
fout.exceptions ( std::fstream::failbit | std::fstream::badbit );
|
fout.exceptions ( std::fstream::failbit | std::fstream::badbit );
|
||||||
try {
|
|
||||||
if (offset) { // Must already exist and contain data
|
////////////////////////////////////////////////////////////////////
|
||||||
fout.open(file,std::ios::binary|std::ios::out|std::ios::in);
|
// Grid's model is that the boss rank performs the metadata
|
||||||
} else { // Allow create
|
// operations and every other rank only seeks and writes into a file
|
||||||
fout.open(file,std::ios::binary|std::ios::out);
|
// that already exists. Opening with ios::out on all ranks broke that:
|
||||||
|
// it is O_TRUNC, so a rank opening late truncated the file back to
|
||||||
|
// zero after an earlier rank had written its segment, leaving a hole
|
||||||
|
// in its place. The barriers around this block are outside it and do
|
||||||
|
// not order the opens against the writes. Let the boss create and
|
||||||
|
// empty the file, then everyone opens for update only. Same resulting
|
||||||
|
// length, one metadata operation instead of one per rank, no race.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
if ( !offset && grid->IsBoss() ) { // offset zero: this record starts the file
|
||||||
|
std::ofstream create(file,std::ios::binary|std::ios::out);
|
||||||
|
create.close();
|
||||||
}
|
}
|
||||||
|
grid->Barrier();
|
||||||
|
|
||||||
|
try {
|
||||||
|
fout.open(file,std::ios::binary|std::ios::out|std::ios::in);
|
||||||
} catch (const std::fstream::failure& exc) {
|
} catch (const std::fstream::failure& exc) {
|
||||||
std::cout << GridLogError << "Error in opening the file " << file << " for output" <<std::endl;
|
std::cout << GridLogError << "Error in opening the file " << file << " for output" <<std::endl;
|
||||||
std::cout << GridLogError << "Exception description: " << exc.what() << std::endl;
|
std::cout << GridLogError << "Exception description: " << exc.what() << std::endl;
|
||||||
@@ -548,7 +999,7 @@ class BinaryIO {
|
|||||||
uint32_t &nersc_csum,
|
uint32_t &nersc_csum,
|
||||||
uint32_t &scidac_csuma,
|
uint32_t &scidac_csuma,
|
||||||
uint32_t &scidac_csumb,
|
uint32_t &scidac_csumb,
|
||||||
int control=BINARYIO_LEXICOGRAPHIC
|
int control=DefaultControl()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
@@ -587,7 +1038,7 @@ class BinaryIO {
|
|||||||
uint32_t &nersc_csum,
|
uint32_t &nersc_csum,
|
||||||
uint32_t &scidac_csuma,
|
uint32_t &scidac_csuma,
|
||||||
uint32_t &scidac_csumb,
|
uint32_t &scidac_csumb,
|
||||||
int control=BINARYIO_LEXICOGRAPHIC)
|
int control=DefaultControl())
|
||||||
{
|
{
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
typedef typename vobj::Realified::scalar_type word; word w=0;
|
typedef typename vobj::Realified::scalar_type word; word w=0;
|
||||||
@@ -674,7 +1125,7 @@ class BinaryIO {
|
|||||||
std::cout << GridLogMessage << "RNG read I/O on file " << file << std::endl;
|
std::cout << GridLogMessage << "RNG read I/O on file " << file << std::endl;
|
||||||
|
|
||||||
std::vector<RNGstate> iodata(lsites);
|
std::vector<RNGstate> iodata(lsites);
|
||||||
IOobject(w,grid,iodata,file,offset,format,BINARYIO_READ|BINARYIO_LEXICOGRAPHIC,
|
IOobject(w,grid,iodata,file,offset,format,BINARYIO_READ|DefaultControl(),
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
|
|
||||||
timer.Start();
|
timer.Start();
|
||||||
@@ -753,7 +1204,7 @@ class BinaryIO {
|
|||||||
});
|
});
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
|
|
||||||
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|DefaultControl(),
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
iodata.resize(1);
|
iodata.resize(1);
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ class GridLimeReader : public BinaryIO {
|
|||||||
// Read a generic lattice field and verify checksum
|
// Read a generic lattice field and verify checksum
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
template<class vobj>
|
template<class vobj>
|
||||||
void readLimeLatticeBinaryObject(Lattice<vobj> &field,std::string record_name,int control=BINARYIO_LEXICOGRAPHIC)
|
void readLimeLatticeBinaryObject(Lattice<vobj> &field,std::string record_name,int control=BINARYIO_LEXICOGRAPHIC|BINARYIO_AGGREGATE)
|
||||||
{
|
{
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
scidacChecksum scidacChecksum_;
|
scidacChecksum scidacChecksum_;
|
||||||
@@ -414,7 +414,7 @@ class GridLimeWriter : public BinaryIO
|
|||||||
// in communicator used by the field.Grid()
|
// in communicator used by the field.Grid()
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
template<class vobj>
|
template<class vobj>
|
||||||
void writeLimeLatticeBinaryObject(Lattice<vobj> &field,std::string record_name,int control=BINARYIO_LEXICOGRAPHIC)
|
void writeLimeLatticeBinaryObject(Lattice<vobj> &field,std::string record_name,int control=BINARYIO_LEXICOGRAPHIC|BINARYIO_AGGREGATE)
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// NB: FILE and iostream are jointly writing disjoint sequences in the
|
// NB: FILE and iostream are jointly writing disjoint sequences in the
|
||||||
@@ -519,7 +519,7 @@ class ScidacWriter : public GridLimeWriter {
|
|||||||
template <class vobj, class userRecord>
|
template <class vobj, class userRecord>
|
||||||
void writeScidacFieldRecord(Lattice<vobj> &field,userRecord _userRecord,
|
void writeScidacFieldRecord(Lattice<vobj> &field,userRecord _userRecord,
|
||||||
const unsigned int recordScientificPrec = 0,
|
const unsigned int recordScientificPrec = 0,
|
||||||
int control=BINARYIO_LEXICOGRAPHIC)
|
int control=BINARYIO_LEXICOGRAPHIC|BINARYIO_AGGREGATE)
|
||||||
{
|
{
|
||||||
GridBase * grid = field.Grid();
|
GridBase * grid = field.Grid();
|
||||||
|
|
||||||
@@ -561,7 +561,7 @@ class ScidacReader : public GridLimeReader {
|
|||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
template <class vobj, class userRecord>
|
template <class vobj, class userRecord>
|
||||||
void readScidacFieldRecord(Lattice<vobj> &field,userRecord &_userRecord,
|
void readScidacFieldRecord(Lattice<vobj> &field,userRecord &_userRecord,
|
||||||
int control=BINARYIO_LEXICOGRAPHIC)
|
int control=BINARYIO_LEXICOGRAPHIC|BINARYIO_AGGREGATE)
|
||||||
{
|
{
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
GridBase * grid = field.Grid();
|
GridBase * grid = field.Grid();
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ template<class Impl>
|
|||||||
class GaugeStatistics
|
class GaugeStatistics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void operator()(Lattice<vLorentzColourMatrixD> & data,FieldMetaData &header)
|
void operator()(typename Impl::Field & data,FieldMetaData &header)
|
||||||
{
|
{
|
||||||
header.link_trace = WilsonLoops<Impl>::linkTrace(data);
|
header.link_trace = WilsonLoops<Impl>::linkTrace(data);
|
||||||
header.plaquette = WilsonLoops<Impl>::avgPlaquette(data);
|
header.plaquette = WilsonLoops<Impl>::avgPlaquette(data);
|
||||||
@@ -188,6 +188,8 @@ public:
|
|||||||
};
|
};
|
||||||
typedef GaugeStatistics<PeriodicGimplD> PeriodicGaugeStatistics;
|
typedef GaugeStatistics<PeriodicGimplD> PeriodicGaugeStatistics;
|
||||||
typedef GaugeStatistics<ConjugateGimplD> ConjugateGaugeStatistics;
|
typedef GaugeStatistics<ConjugateGimplD> ConjugateGaugeStatistics;
|
||||||
|
typedef GaugeStatistics<lexPeriodicGimplD> lexPeriodicGaugeStatistics;
|
||||||
|
typedef GaugeStatistics<lexConjugateGimplD> lexConjugateGaugeStatistics;
|
||||||
template<> inline void PrepareMetaData<vLorentzColourMatrixD>(Lattice<vLorentzColourMatrixD> & field, FieldMetaData &header)
|
template<> inline void PrepareMetaData<vLorentzColourMatrixD>(Lattice<vLorentzColourMatrixD> & field, FieldMetaData &header)
|
||||||
{
|
{
|
||||||
GridBase *grid = field.Grid();
|
GridBase *grid = field.Grid();
|
||||||
@@ -197,6 +199,15 @@ template<> inline void PrepareMetaData<vLorentzColourMatrixD>(Lattice<vLorentzCo
|
|||||||
GridMetaData(grid,header);
|
GridMetaData(grid,header);
|
||||||
MachineCharacteristics(header);
|
MachineCharacteristics(header);
|
||||||
}
|
}
|
||||||
|
template<> inline void PrepareMetaData<sLorentzColourMatrixD>(Lattice<sLorentzColourMatrixD> & field, FieldMetaData &header)
|
||||||
|
{
|
||||||
|
GridBase *grid = field.Grid();
|
||||||
|
std::string format = getFormatString<sLorentzColourMatrixD>();
|
||||||
|
header.floating_point = format;
|
||||||
|
header.checksum = 0x0; // Nersc checksum unused in ILDG, Scidac
|
||||||
|
GridMetaData(grid,header);
|
||||||
|
MachineCharacteristics(header);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Utilities ; these are QCD aware
|
// Utilities ; these are QCD aware
|
||||||
|
|||||||
+72
-15
@@ -136,12 +136,14 @@ public:
|
|||||||
// Now the meat: the object readers
|
// Now the meat: the object readers
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<class GaugeStats=PeriodicGaugeStatistics>
|
template<class GaugeFieldType,class GaugeStats>
|
||||||
static inline void readConfiguration(GaugeField &Umu,
|
static inline void readConfigurationInternal(GaugeFieldType &Umu,
|
||||||
FieldMetaData& header,
|
FieldMetaData& header,
|
||||||
std::string file,
|
std::string file,
|
||||||
GaugeStats GaugeStatisticsCalculator=GaugeStats())
|
GaugeStats GaugeStatisticsCalculator)
|
||||||
{
|
{
|
||||||
|
typedef typename GaugeFieldType::vector_object vobj;
|
||||||
|
typedef typename GaugeFieldType::scalar_object sobj;
|
||||||
|
|
||||||
GridBase *grid = Umu.Grid();
|
GridBase *grid = Umu.Grid();
|
||||||
uint64_t offset = readHeader(file,Umu.Grid(),header);
|
uint64_t offset = readHeader(file,Umu.Grid(),header);
|
||||||
@@ -162,24 +164,24 @@ public:
|
|||||||
const std::string stNC = std::to_string( Nc ) ;
|
const std::string stNC = std::to_string( Nc ) ;
|
||||||
if ( header.data_type == std::string("4D_SU"+stNC+"_GAUGE") ) {
|
if ( header.data_type == std::string("4D_SU"+stNC+"_GAUGE") ) {
|
||||||
if ( ieee32 || ieee32big ) {
|
if ( ieee32 || ieee32big ) {
|
||||||
BinaryIO::readLatticeObject<vLorentzColourMatrixD, LorentzColour2x3F>
|
BinaryIO::readLatticeObject<vobj, LorentzColour2x3F>
|
||||||
(Umu,file,Gauge3x2munger<LorentzColour2x3F,LorentzColourMatrix>(), offset,format,
|
(Umu,file,Gauge3x2munger<LorentzColour2x3F,sobj>(), offset,format,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
}
|
}
|
||||||
if ( ieee64 || ieee64big ) {
|
if ( ieee64 || ieee64big ) {
|
||||||
BinaryIO::readLatticeObject<vLorentzColourMatrixD, LorentzColour2x3D>
|
BinaryIO::readLatticeObject<vobj, LorentzColour2x3D>
|
||||||
(Umu,file,Gauge3x2munger<LorentzColour2x3D,LorentzColourMatrix>(),offset,format,
|
(Umu,file,Gauge3x2munger<LorentzColour2x3D,sobj>(),offset,format,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
}
|
}
|
||||||
} else if ( header.data_type == std::string("4D_SU"+stNC+"_GAUGE_"+stNC+"x"+stNC) ) {
|
} else if ( header.data_type == std::string("4D_SU"+stNC+"_GAUGE_"+stNC+"x"+stNC) ) {
|
||||||
if ( ieee32 || ieee32big ) {
|
if ( ieee32 || ieee32big ) {
|
||||||
BinaryIO::readLatticeObject<vLorentzColourMatrixD,LorentzColourMatrixF>
|
BinaryIO::readLatticeObject<vobj,LorentzColourMatrixF>
|
||||||
(Umu,file,GaugeSimpleMunger<LorentzColourMatrixF,LorentzColourMatrix>(),offset,format,
|
(Umu,file,GaugeSimpleMunger<LorentzColourMatrixF,sobj>(),offset,format,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
}
|
}
|
||||||
if ( ieee64 || ieee64big ) {
|
if ( ieee64 || ieee64big ) {
|
||||||
BinaryIO::readLatticeObject<vLorentzColourMatrixD,LorentzColourMatrixD>
|
BinaryIO::readLatticeObject<vobj,LorentzColourMatrixD>
|
||||||
(Umu,file,GaugeSimpleMunger<LorentzColourMatrixD,LorentzColourMatrix>(),offset,format,
|
(Umu,file,GaugeSimpleMunger<LorentzColourMatrixD,sobj>(),offset,format,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -203,7 +205,6 @@ public:
|
|||||||
std::cerr << " plaqs " << clone.plaquette << " " << header.plaquette << std::endl;
|
std::cerr << " plaqs " << clone.plaquette << " " << header.plaquette << std::endl;
|
||||||
std::cerr << " trace " << clone.link_trace<< " " << header.link_trace<< std::endl;
|
std::cerr << " trace " << clone.link_trace<< " " << header.link_trace<< std::endl;
|
||||||
std::cerr << " nersc_csum " <<std::hex<< nersc_csum << " " << header.checksum<< std::dec<< std::endl;
|
std::cerr << " nersc_csum " <<std::hex<< nersc_csum << " " << header.checksum<< std::dec<< std::endl;
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
if(exitOnReadPlaquetteMismatch()) GRID_ASSERT(fabs(clone.plaquette -header.plaquette ) < 1.0e-5 );
|
if(exitOnReadPlaquetteMismatch()) GRID_ASSERT(fabs(clone.plaquette -header.plaquette ) < 1.0e-5 );
|
||||||
GRID_ASSERT(fabs(clone.link_trace-header.link_trace) < 1.0e-6 );
|
GRID_ASSERT(fabs(clone.link_trace-header.link_trace) < 1.0e-6 );
|
||||||
@@ -212,6 +213,26 @@ public:
|
|||||||
std::cout<<GridLogMessage <<"NERSC Configuration "<<file<< " and plaquette, link trace, and checksum agree"<<std::endl;
|
std::cout<<GridLogMessage <<"NERSC Configuration "<<file<< " and plaquette, link trace, and checksum agree"<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constrained frontends: vectorised and lexicographic gauge fields
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class GaugeStats=PeriodicGaugeStatistics>
|
||||||
|
static inline void readConfiguration(Lattice<vLorentzColourMatrixD> &Umu,
|
||||||
|
FieldMetaData& header,
|
||||||
|
std::string file,
|
||||||
|
GaugeStats GaugeStatisticsCalculator=GaugeStats())
|
||||||
|
{
|
||||||
|
readConfigurationInternal(Umu,header,file,GaugeStatisticsCalculator);
|
||||||
|
}
|
||||||
|
template<class GaugeStats=lexPeriodicGaugeStatistics>
|
||||||
|
static inline void readConfiguration(Lattice<sLorentzColourMatrixD> &Umu,
|
||||||
|
FieldMetaData& header,
|
||||||
|
std::string file,
|
||||||
|
GaugeStats GaugeStatisticsCalculator=GaugeStats())
|
||||||
|
{
|
||||||
|
readConfigurationInternal(Umu,header,file,GaugeStatisticsCalculator);
|
||||||
|
}
|
||||||
|
|
||||||
// Preferred interface
|
// Preferred interface
|
||||||
template<class GaugeStats=PeriodicGaugeStatistics>
|
template<class GaugeStats=PeriodicGaugeStatistics>
|
||||||
static inline void writeConfiguration(Lattice<vLorentzColourMatrixD > &Umu,
|
static inline void writeConfiguration(Lattice<vLorentzColourMatrixD > &Umu,
|
||||||
@@ -220,7 +241,16 @@ public:
|
|||||||
std::string ens_id = std::string("UKQCD"),
|
std::string ens_id = std::string("UKQCD"),
|
||||||
unsigned int sequence_number = 1)
|
unsigned int sequence_number = 1)
|
||||||
{
|
{
|
||||||
writeConfiguration(Umu,file,0,1,ens_label,ens_id,sequence_number);
|
writeConfigurationInternal<Lattice<vLorentzColourMatrixD>,GaugeStats>(Umu,file,0,1,ens_label,ens_id,sequence_number);
|
||||||
|
}
|
||||||
|
template<class GaugeStats=lexPeriodicGaugeStatistics>
|
||||||
|
static inline void writeConfiguration(Lattice<sLorentzColourMatrixD > &Umu,
|
||||||
|
std::string file,
|
||||||
|
std::string ens_label = std::string("DWF"),
|
||||||
|
std::string ens_id = std::string("UKQCD"),
|
||||||
|
unsigned int sequence_number = 1)
|
||||||
|
{
|
||||||
|
writeConfigurationInternal<Lattice<sLorentzColourMatrixD>,GaugeStats>(Umu,file,0,1,ens_label,ens_id,sequence_number);
|
||||||
}
|
}
|
||||||
template<class GaugeStats=PeriodicGaugeStatistics>
|
template<class GaugeStats=PeriodicGaugeStatistics>
|
||||||
static inline void writeConfiguration(Lattice<vLorentzColourMatrixD > &Umu,
|
static inline void writeConfiguration(Lattice<vLorentzColourMatrixD > &Umu,
|
||||||
@@ -231,7 +261,29 @@ public:
|
|||||||
std::string ens_id = std::string("UKQCD"),
|
std::string ens_id = std::string("UKQCD"),
|
||||||
unsigned int sequence_number = 1)
|
unsigned int sequence_number = 1)
|
||||||
{
|
{
|
||||||
typedef vLorentzColourMatrixD vobj;
|
writeConfigurationInternal<Lattice<vLorentzColourMatrixD>,GaugeStats>(Umu,file,two_row,bits32,ens_label,ens_id,sequence_number);
|
||||||
|
}
|
||||||
|
template<class GaugeStats=lexPeriodicGaugeStatistics>
|
||||||
|
static inline void writeConfiguration(Lattice<sLorentzColourMatrixD > &Umu,
|
||||||
|
std::string file,
|
||||||
|
int two_row,
|
||||||
|
int bits32,
|
||||||
|
std::string ens_label = std::string("DWF"),
|
||||||
|
std::string ens_id = std::string("UKQCD"),
|
||||||
|
unsigned int sequence_number = 1)
|
||||||
|
{
|
||||||
|
writeConfigurationInternal<Lattice<sLorentzColourMatrixD>,GaugeStats>(Umu,file,two_row,bits32,ens_label,ens_id,sequence_number);
|
||||||
|
}
|
||||||
|
template<class GaugeFieldType,class GaugeStats>
|
||||||
|
static inline void writeConfigurationInternal(GaugeFieldType &Umu,
|
||||||
|
std::string file,
|
||||||
|
int two_row,
|
||||||
|
int bits32,
|
||||||
|
std::string ens_label = std::string("DWF"),
|
||||||
|
std::string ens_id = std::string("UKQCD"),
|
||||||
|
unsigned int sequence_number = 1)
|
||||||
|
{
|
||||||
|
typedef typename GaugeFieldType::vector_object vobj;
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
|
||||||
FieldMetaData header;
|
FieldMetaData header;
|
||||||
@@ -280,6 +332,9 @@ public:
|
|||||||
if ( grid->IsBoss() ) {
|
if ( grid->IsBoss() ) {
|
||||||
writeHeader(header,file);
|
writeHeader(header,file);
|
||||||
}
|
}
|
||||||
|
// The header is written twice; the checksum is only known after the data.
|
||||||
|
// Other ranks must not proceed to read it until the rewrite has landed.
|
||||||
|
grid->Barrier();
|
||||||
|
|
||||||
std::cout<<GridLogMessage <<"Written NERSC Configuration on "<< file << " checksum "
|
std::cout<<GridLogMessage <<"Written NERSC Configuration on "<< file << " checksum "
|
||||||
<<std::hex<<header.checksum
|
<<std::hex<<header.checksum
|
||||||
@@ -333,6 +388,9 @@ public:
|
|||||||
if ( grid->IsBoss() ) {
|
if ( grid->IsBoss() ) {
|
||||||
offset = writeHeader(header,file);
|
offset = writeHeader(header,file);
|
||||||
}
|
}
|
||||||
|
// As for the gauge field: the checksum is only known after the data, so
|
||||||
|
// the header is rewritten. Hold the other ranks until that has landed.
|
||||||
|
grid->Barrier();
|
||||||
|
|
||||||
std::cout<<GridLogMessage
|
std::cout<<GridLogMessage
|
||||||
<<"Written NERSC RNG STATE "<<file<< " checksum "
|
<<"Written NERSC RNG STATE "<<file<< " checksum "
|
||||||
@@ -374,7 +432,6 @@ public:
|
|||||||
|
|
||||||
if ( nersc_csum != header.checksum ) {
|
if ( nersc_csum != header.checksum ) {
|
||||||
std::cerr << "checksum mismatch "<<std::hex<< nersc_csum <<" "<<header.checksum<<std::dec<<std::endl;
|
std::cerr << "checksum mismatch "<<std::hex<< nersc_csum <<" "<<header.checksum<<std::dec<<std::endl;
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
GRID_ASSERT(nersc_csum == header.checksum );
|
GRID_ASSERT(nersc_csum == header.checksum );
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ Author: paboyle <paboyle@ph.ed.ac.uk>
|
|||||||
#endif
|
#endif
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
#ifdef GRID_CUDA
|
#ifdef GRID_CUDA
|
||||||
//accelerator_inline uint64_t __rdtsc(void) { return 0; }
|
accelerator_inline uint64_t __rdtsc(void) { return 0; }
|
||||||
//accelerator_inline uint64_t __rdpmc(int ) { return 0; }
|
accelerator_inline uint64_t __rdpmc(int ) { return 0; }
|
||||||
#else
|
#else
|
||||||
#include <x86intrin.h>
|
#include <x86intrin.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -93,8 +93,7 @@ inline uint64_t cyclecount(void){
|
|||||||
}
|
}
|
||||||
#elif defined __x86_64__
|
#elif defined __x86_64__
|
||||||
inline uint64_t cyclecount(void){
|
inline uint64_t cyclecount(void){
|
||||||
uint64_t ret = __rdtsc();
|
return (uint64_t)0;
|
||||||
return (uint64_t)ret;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
+92
-43
@@ -127,7 +127,6 @@ typedef iSpinMatrix<ComplexD > SpinMatrixD;
|
|||||||
typedef iSpinMatrix<vComplex > vSpinMatrix;
|
typedef iSpinMatrix<vComplex > vSpinMatrix;
|
||||||
typedef iSpinMatrix<vComplexF> vSpinMatrixF;
|
typedef iSpinMatrix<vComplexF> vSpinMatrixF;
|
||||||
typedef iSpinMatrix<vComplexD> vSpinMatrixD;
|
typedef iSpinMatrix<vComplexD> vSpinMatrixD;
|
||||||
typedef iSpinMatrix<vComplexD2> vSpinMatrixD2;
|
|
||||||
|
|
||||||
// Colour Matrix
|
// Colour Matrix
|
||||||
typedef iColourMatrix<Complex > ColourMatrix;
|
typedef iColourMatrix<Complex > ColourMatrix;
|
||||||
@@ -137,7 +136,6 @@ typedef iColourMatrix<ComplexD > ColourMatrixD;
|
|||||||
typedef iColourMatrix<vComplex > vColourMatrix;
|
typedef iColourMatrix<vComplex > vColourMatrix;
|
||||||
typedef iColourMatrix<vComplexF> vColourMatrixF;
|
typedef iColourMatrix<vComplexF> vColourMatrixF;
|
||||||
typedef iColourMatrix<vComplexD> vColourMatrixD;
|
typedef iColourMatrix<vComplexD> vColourMatrixD;
|
||||||
typedef iColourMatrix<vComplexD2> vColourMatrixD2;
|
|
||||||
|
|
||||||
// SpinColour matrix
|
// SpinColour matrix
|
||||||
typedef iSpinColourMatrix<Complex > SpinColourMatrix;
|
typedef iSpinColourMatrix<Complex > SpinColourMatrix;
|
||||||
@@ -147,7 +145,6 @@ typedef iSpinColourMatrix<ComplexD > SpinColourMatrixD;
|
|||||||
typedef iSpinColourMatrix<vComplex > vSpinColourMatrix;
|
typedef iSpinColourMatrix<vComplex > vSpinColourMatrix;
|
||||||
typedef iSpinColourMatrix<vComplexF> vSpinColourMatrixF;
|
typedef iSpinColourMatrix<vComplexF> vSpinColourMatrixF;
|
||||||
typedef iSpinColourMatrix<vComplexD> vSpinColourMatrixD;
|
typedef iSpinColourMatrix<vComplexD> vSpinColourMatrixD;
|
||||||
typedef iSpinColourMatrix<vComplexD2> vSpinColourMatrixD2;
|
|
||||||
|
|
||||||
// SpinColourSpinColour matrix
|
// SpinColourSpinColour matrix
|
||||||
typedef iSpinColourSpinColourMatrix<Complex > SpinColourSpinColourMatrix;
|
typedef iSpinColourSpinColourMatrix<Complex > SpinColourSpinColourMatrix;
|
||||||
@@ -157,17 +154,6 @@ typedef iSpinColourSpinColourMatrix<ComplexD > SpinColourSpinColourMatrixD;
|
|||||||
typedef iSpinColourSpinColourMatrix<vComplex > vSpinColourSpinColourMatrix;
|
typedef iSpinColourSpinColourMatrix<vComplex > vSpinColourSpinColourMatrix;
|
||||||
typedef iSpinColourSpinColourMatrix<vComplexF> vSpinColourSpinColourMatrixF;
|
typedef iSpinColourSpinColourMatrix<vComplexF> vSpinColourSpinColourMatrixF;
|
||||||
typedef iSpinColourSpinColourMatrix<vComplexD> vSpinColourSpinColourMatrixD;
|
typedef iSpinColourSpinColourMatrix<vComplexD> vSpinColourSpinColourMatrixD;
|
||||||
typedef iSpinColourSpinColourMatrix<vComplexD2> vSpinColourSpinColourMatrixD2;
|
|
||||||
|
|
||||||
// SpinColourSpinColour matrix
|
|
||||||
typedef iSpinColourSpinColourMatrix<Complex > SpinColourSpinColourMatrix;
|
|
||||||
typedef iSpinColourSpinColourMatrix<ComplexF > SpinColourSpinColourMatrixF;
|
|
||||||
typedef iSpinColourSpinColourMatrix<ComplexD > SpinColourSpinColourMatrixD;
|
|
||||||
|
|
||||||
typedef iSpinColourSpinColourMatrix<vComplex > vSpinColourSpinColourMatrix;
|
|
||||||
typedef iSpinColourSpinColourMatrix<vComplexF> vSpinColourSpinColourMatrixF;
|
|
||||||
typedef iSpinColourSpinColourMatrix<vComplexD> vSpinColourSpinColourMatrixD;
|
|
||||||
typedef iSpinColourSpinColourMatrix<vComplexD2> vSpinColourSpinColourMatrixD2;
|
|
||||||
|
|
||||||
// LorentzColour
|
// LorentzColour
|
||||||
typedef iLorentzColourMatrix<Complex > LorentzColourMatrix;
|
typedef iLorentzColourMatrix<Complex > LorentzColourMatrix;
|
||||||
@@ -177,7 +163,6 @@ typedef iLorentzColourMatrix<ComplexD > LorentzColourMatrixD;
|
|||||||
typedef iLorentzColourMatrix<vComplex > vLorentzColourMatrix;
|
typedef iLorentzColourMatrix<vComplex > vLorentzColourMatrix;
|
||||||
typedef iLorentzColourMatrix<vComplexF> vLorentzColourMatrixF;
|
typedef iLorentzColourMatrix<vComplexF> vLorentzColourMatrixF;
|
||||||
typedef iLorentzColourMatrix<vComplexD> vLorentzColourMatrixD;
|
typedef iLorentzColourMatrix<vComplexD> vLorentzColourMatrixD;
|
||||||
typedef iLorentzColourMatrix<vComplexD2> vLorentzColourMatrixD2;
|
|
||||||
|
|
||||||
// LorentzComplex
|
// LorentzComplex
|
||||||
typedef iLorentzComplex<Complex > LorentzComplex;
|
typedef iLorentzComplex<Complex > LorentzComplex;
|
||||||
@@ -196,7 +181,6 @@ typedef iDoubleStoredColourMatrix<ComplexD > DoubleStoredColourMatrixD;
|
|||||||
typedef iDoubleStoredColourMatrix<vComplex > vDoubleStoredColourMatrix;
|
typedef iDoubleStoredColourMatrix<vComplex > vDoubleStoredColourMatrix;
|
||||||
typedef iDoubleStoredColourMatrix<vComplexF> vDoubleStoredColourMatrixF;
|
typedef iDoubleStoredColourMatrix<vComplexF> vDoubleStoredColourMatrixF;
|
||||||
typedef iDoubleStoredColourMatrix<vComplexD> vDoubleStoredColourMatrixD;
|
typedef iDoubleStoredColourMatrix<vComplexD> vDoubleStoredColourMatrixD;
|
||||||
typedef iDoubleStoredColourMatrix<vComplexD2> vDoubleStoredColourMatrixD2;
|
|
||||||
|
|
||||||
//G-parity flavour matrix
|
//G-parity flavour matrix
|
||||||
typedef iGparityFlavourMatrix<Complex> GparityFlavourMatrix;
|
typedef iGparityFlavourMatrix<Complex> GparityFlavourMatrix;
|
||||||
@@ -206,7 +190,6 @@ typedef iGparityFlavourMatrix<ComplexD> GparityFlavourMatrixD;
|
|||||||
typedef iGparityFlavourMatrix<vComplex> vGparityFlavourMatrix;
|
typedef iGparityFlavourMatrix<vComplex> vGparityFlavourMatrix;
|
||||||
typedef iGparityFlavourMatrix<vComplexF> vGparityFlavourMatrixF;
|
typedef iGparityFlavourMatrix<vComplexF> vGparityFlavourMatrixF;
|
||||||
typedef iGparityFlavourMatrix<vComplexD> vGparityFlavourMatrixD;
|
typedef iGparityFlavourMatrix<vComplexD> vGparityFlavourMatrixD;
|
||||||
typedef iGparityFlavourMatrix<vComplexD2> vGparityFlavourMatrixD2;
|
|
||||||
|
|
||||||
|
|
||||||
// Spin vector
|
// Spin vector
|
||||||
@@ -217,7 +200,6 @@ typedef iSpinVector<ComplexD> SpinVectorD;
|
|||||||
typedef iSpinVector<vComplex > vSpinVector;
|
typedef iSpinVector<vComplex > vSpinVector;
|
||||||
typedef iSpinVector<vComplexF> vSpinVectorF;
|
typedef iSpinVector<vComplexF> vSpinVectorF;
|
||||||
typedef iSpinVector<vComplexD> vSpinVectorD;
|
typedef iSpinVector<vComplexD> vSpinVectorD;
|
||||||
typedef iSpinVector<vComplexD2> vSpinVectorD2;
|
|
||||||
|
|
||||||
// Colour vector
|
// Colour vector
|
||||||
typedef iColourVector<Complex > ColourVector;
|
typedef iColourVector<Complex > ColourVector;
|
||||||
@@ -227,7 +209,6 @@ typedef iColourVector<ComplexD> ColourVectorD;
|
|||||||
typedef iColourVector<vComplex > vColourVector;
|
typedef iColourVector<vComplex > vColourVector;
|
||||||
typedef iColourVector<vComplexF> vColourVectorF;
|
typedef iColourVector<vComplexF> vColourVectorF;
|
||||||
typedef iColourVector<vComplexD> vColourVectorD;
|
typedef iColourVector<vComplexD> vColourVectorD;
|
||||||
typedef iColourVector<vComplexD2> vColourVectorD2;
|
|
||||||
|
|
||||||
// SpinColourVector
|
// SpinColourVector
|
||||||
typedef iSpinColourVector<Complex > SpinColourVector;
|
typedef iSpinColourVector<Complex > SpinColourVector;
|
||||||
@@ -237,7 +218,6 @@ typedef iSpinColourVector<ComplexD> SpinColourVectorD;
|
|||||||
typedef iSpinColourVector<vComplex > vSpinColourVector;
|
typedef iSpinColourVector<vComplex > vSpinColourVector;
|
||||||
typedef iSpinColourVector<vComplexF> vSpinColourVectorF;
|
typedef iSpinColourVector<vComplexF> vSpinColourVectorF;
|
||||||
typedef iSpinColourVector<vComplexD> vSpinColourVectorD;
|
typedef iSpinColourVector<vComplexD> vSpinColourVectorD;
|
||||||
typedef iSpinColourVector<vComplexD2> vSpinColourVectorD2;
|
|
||||||
|
|
||||||
// HalfSpin vector
|
// HalfSpin vector
|
||||||
typedef iHalfSpinVector<Complex > HalfSpinVector;
|
typedef iHalfSpinVector<Complex > HalfSpinVector;
|
||||||
@@ -247,7 +227,6 @@ typedef iHalfSpinVector<ComplexD> HalfSpinVectorD;
|
|||||||
typedef iHalfSpinVector<vComplex > vHalfSpinVector;
|
typedef iHalfSpinVector<vComplex > vHalfSpinVector;
|
||||||
typedef iHalfSpinVector<vComplexF> vHalfSpinVectorF;
|
typedef iHalfSpinVector<vComplexF> vHalfSpinVectorF;
|
||||||
typedef iHalfSpinVector<vComplexD> vHalfSpinVectorD;
|
typedef iHalfSpinVector<vComplexD> vHalfSpinVectorD;
|
||||||
typedef iHalfSpinVector<vComplexD2> vHalfSpinVectorD2;
|
|
||||||
|
|
||||||
// HalfSpinColour vector
|
// HalfSpinColour vector
|
||||||
typedef iHalfSpinColourVector<Complex > HalfSpinColourVector;
|
typedef iHalfSpinColourVector<Complex > HalfSpinColourVector;
|
||||||
@@ -257,7 +236,6 @@ typedef iHalfSpinColourVector<ComplexD> HalfSpinColourVectorD;
|
|||||||
typedef iHalfSpinColourVector<vComplex > vHalfSpinColourVector;
|
typedef iHalfSpinColourVector<vComplex > vHalfSpinColourVector;
|
||||||
typedef iHalfSpinColourVector<vComplexF> vHalfSpinColourVectorF;
|
typedef iHalfSpinColourVector<vComplexF> vHalfSpinColourVectorF;
|
||||||
typedef iHalfSpinColourVector<vComplexD> vHalfSpinColourVectorD;
|
typedef iHalfSpinColourVector<vComplexD> vHalfSpinColourVectorD;
|
||||||
typedef iHalfSpinColourVector<vComplexD2> vHalfSpinColourVectorD2;
|
|
||||||
|
|
||||||
//G-parity flavour vector
|
//G-parity flavour vector
|
||||||
typedef iGparityFlavourVector<Complex > GparityFlavourVector;
|
typedef iGparityFlavourVector<Complex > GparityFlavourVector;
|
||||||
@@ -267,7 +245,6 @@ typedef iGparityFlavourVector<ComplexD> GparityFlavourVectorD;
|
|||||||
typedef iGparityFlavourVector<vComplex > vGparityFlavourVector;
|
typedef iGparityFlavourVector<vComplex > vGparityFlavourVector;
|
||||||
typedef iGparityFlavourVector<vComplexF> vGparityFlavourVectorF;
|
typedef iGparityFlavourVector<vComplexF> vGparityFlavourVectorF;
|
||||||
typedef iGparityFlavourVector<vComplexD> vGparityFlavourVectorD;
|
typedef iGparityFlavourVector<vComplexD> vGparityFlavourVectorD;
|
||||||
typedef iGparityFlavourVector<vComplexD2> vGparityFlavourVectorD2;
|
|
||||||
|
|
||||||
// singlets
|
// singlets
|
||||||
typedef iSinglet<Complex > TComplex; // FIXME This is painful. Tensor singlet complex type.
|
typedef iSinglet<Complex > TComplex; // FIXME This is painful. Tensor singlet complex type.
|
||||||
@@ -277,7 +254,6 @@ typedef iSinglet<ComplexD> TComplexD; // FIXME This is painful. Tenso
|
|||||||
typedef iSinglet<vComplex > vTComplex ; // what if we don't know the tensor structure
|
typedef iSinglet<vComplex > vTComplex ; // what if we don't know the tensor structure
|
||||||
typedef iSinglet<vComplexF> vTComplexF; // what if we don't know the tensor structure
|
typedef iSinglet<vComplexF> vTComplexF; // what if we don't know the tensor structure
|
||||||
typedef iSinglet<vComplexD> vTComplexD; // what if we don't know the tensor structure
|
typedef iSinglet<vComplexD> vTComplexD; // what if we don't know the tensor structure
|
||||||
typedef iSinglet<vComplexD2> vTComplexD2; // what if we don't know the tensor structure
|
|
||||||
|
|
||||||
typedef iSinglet<Real > TReal; // Shouldn't need these; can I make it work without?
|
typedef iSinglet<Real > TReal; // Shouldn't need these; can I make it work without?
|
||||||
typedef iSinglet<RealF> TRealF; // Shouldn't need these; can I make it work without?
|
typedef iSinglet<RealF> TRealF; // Shouldn't need these; can I make it work without?
|
||||||
@@ -295,27 +271,22 @@ typedef iSinglet<Integer > TInteger;
|
|||||||
typedef Lattice<vColourMatrix> LatticeColourMatrix;
|
typedef Lattice<vColourMatrix> LatticeColourMatrix;
|
||||||
typedef Lattice<vColourMatrixF> LatticeColourMatrixF;
|
typedef Lattice<vColourMatrixF> LatticeColourMatrixF;
|
||||||
typedef Lattice<vColourMatrixD> LatticeColourMatrixD;
|
typedef Lattice<vColourMatrixD> LatticeColourMatrixD;
|
||||||
typedef Lattice<vColourMatrixD2> LatticeColourMatrixD2;
|
|
||||||
|
|
||||||
typedef Lattice<vSpinMatrix> LatticeSpinMatrix;
|
typedef Lattice<vSpinMatrix> LatticeSpinMatrix;
|
||||||
typedef Lattice<vSpinMatrixF> LatticeSpinMatrixF;
|
typedef Lattice<vSpinMatrixF> LatticeSpinMatrixF;
|
||||||
typedef Lattice<vSpinMatrixD> LatticeSpinMatrixD;
|
typedef Lattice<vSpinMatrixD> LatticeSpinMatrixD;
|
||||||
typedef Lattice<vSpinMatrixD2> LatticeSpinMatrixD2;
|
|
||||||
|
|
||||||
typedef Lattice<vSpinColourMatrix> LatticeSpinColourMatrix;
|
typedef Lattice<vSpinColourMatrix> LatticeSpinColourMatrix;
|
||||||
typedef Lattice<vSpinColourMatrixF> LatticeSpinColourMatrixF;
|
typedef Lattice<vSpinColourMatrixF> LatticeSpinColourMatrixF;
|
||||||
typedef Lattice<vSpinColourMatrixD> LatticeSpinColourMatrixD;
|
typedef Lattice<vSpinColourMatrixD> LatticeSpinColourMatrixD;
|
||||||
typedef Lattice<vSpinColourMatrixD2> LatticeSpinColourMatrixD2;
|
|
||||||
|
|
||||||
typedef Lattice<vSpinColourSpinColourMatrix> LatticeSpinColourSpinColourMatrix;
|
typedef Lattice<vSpinColourSpinColourMatrix> LatticeSpinColourSpinColourMatrix;
|
||||||
typedef Lattice<vSpinColourSpinColourMatrixF> LatticeSpinColourSpinColourMatrixF;
|
typedef Lattice<vSpinColourSpinColourMatrixF> LatticeSpinColourSpinColourMatrixF;
|
||||||
typedef Lattice<vSpinColourSpinColourMatrixD> LatticeSpinColourSpinColourMatrixD;
|
typedef Lattice<vSpinColourSpinColourMatrixD> LatticeSpinColourSpinColourMatrixD;
|
||||||
typedef Lattice<vSpinColourSpinColourMatrixD2> LatticeSpinColourSpinColourMatrixD2;
|
|
||||||
|
|
||||||
typedef Lattice<vLorentzColourMatrix> LatticeLorentzColourMatrix;
|
typedef Lattice<vLorentzColourMatrix> LatticeLorentzColourMatrix;
|
||||||
typedef Lattice<vLorentzColourMatrixF> LatticeLorentzColourMatrixF;
|
typedef Lattice<vLorentzColourMatrixF> LatticeLorentzColourMatrixF;
|
||||||
typedef Lattice<vLorentzColourMatrixD> LatticeLorentzColourMatrixD;
|
typedef Lattice<vLorentzColourMatrixD> LatticeLorentzColourMatrixD;
|
||||||
typedef Lattice<vLorentzColourMatrixD2> LatticeLorentzColourMatrixD2;
|
|
||||||
|
|
||||||
typedef Lattice<vLorentzComplex> LatticeLorentzComplex;
|
typedef Lattice<vLorentzComplex> LatticeLorentzComplex;
|
||||||
typedef Lattice<vLorentzComplexF> LatticeLorentzComplexF;
|
typedef Lattice<vLorentzComplexF> LatticeLorentzComplexF;
|
||||||
@@ -325,32 +296,26 @@ typedef Lattice<vLorentzComplexD> LatticeLorentzComplexD;
|
|||||||
typedef Lattice<vDoubleStoredColourMatrix> LatticeDoubleStoredColourMatrix;
|
typedef Lattice<vDoubleStoredColourMatrix> LatticeDoubleStoredColourMatrix;
|
||||||
typedef Lattice<vDoubleStoredColourMatrixF> LatticeDoubleStoredColourMatrixF;
|
typedef Lattice<vDoubleStoredColourMatrixF> LatticeDoubleStoredColourMatrixF;
|
||||||
typedef Lattice<vDoubleStoredColourMatrixD> LatticeDoubleStoredColourMatrixD;
|
typedef Lattice<vDoubleStoredColourMatrixD> LatticeDoubleStoredColourMatrixD;
|
||||||
typedef Lattice<vDoubleStoredColourMatrixD2> LatticeDoubleStoredColourMatrixD2;
|
|
||||||
|
|
||||||
typedef Lattice<vSpinVector> LatticeSpinVector;
|
typedef Lattice<vSpinVector> LatticeSpinVector;
|
||||||
typedef Lattice<vSpinVectorF> LatticeSpinVectorF;
|
typedef Lattice<vSpinVectorF> LatticeSpinVectorF;
|
||||||
typedef Lattice<vSpinVectorD> LatticeSpinVectorD;
|
typedef Lattice<vSpinVectorD> LatticeSpinVectorD;
|
||||||
typedef Lattice<vSpinVectorD2> LatticeSpinVectorD2;
|
|
||||||
|
|
||||||
typedef Lattice<vColourVector> LatticeColourVector;
|
typedef Lattice<vColourVector> LatticeColourVector;
|
||||||
typedef Lattice<vColourVectorF> LatticeColourVectorF;
|
typedef Lattice<vColourVectorF> LatticeColourVectorF;
|
||||||
typedef Lattice<vColourVectorD> LatticeColourVectorD;
|
typedef Lattice<vColourVectorD> LatticeColourVectorD;
|
||||||
typedef Lattice<vColourVectorD2> LatticeColourVectorD2;
|
|
||||||
|
|
||||||
typedef Lattice<vSpinColourVector> LatticeSpinColourVector;
|
typedef Lattice<vSpinColourVector> LatticeSpinColourVector;
|
||||||
typedef Lattice<vSpinColourVectorF> LatticeSpinColourVectorF;
|
typedef Lattice<vSpinColourVectorF> LatticeSpinColourVectorF;
|
||||||
typedef Lattice<vSpinColourVectorD> LatticeSpinColourVectorD;
|
typedef Lattice<vSpinColourVectorD> LatticeSpinColourVectorD;
|
||||||
typedef Lattice<vSpinColourVectorD2> LatticeSpinColourVectorD2;
|
|
||||||
|
|
||||||
typedef Lattice<vHalfSpinVector> LatticeHalfSpinVector;
|
typedef Lattice<vHalfSpinVector> LatticeHalfSpinVector;
|
||||||
typedef Lattice<vHalfSpinVectorF> LatticeHalfSpinVectorF;
|
typedef Lattice<vHalfSpinVectorF> LatticeHalfSpinVectorF;
|
||||||
typedef Lattice<vHalfSpinVectorD> LatticeHalfSpinVectorD;
|
typedef Lattice<vHalfSpinVectorD> LatticeHalfSpinVectorD;
|
||||||
typedef Lattice<vHalfSpinVectorD2> LatticeHalfSpinVectorD2;
|
|
||||||
|
|
||||||
typedef Lattice<vHalfSpinColourVector> LatticeHalfSpinColourVector;
|
typedef Lattice<vHalfSpinColourVector> LatticeHalfSpinColourVector;
|
||||||
typedef Lattice<vHalfSpinColourVectorF> LatticeHalfSpinColourVectorF;
|
typedef Lattice<vHalfSpinColourVectorF> LatticeHalfSpinColourVectorF;
|
||||||
typedef Lattice<vHalfSpinColourVectorD> LatticeHalfSpinColourVectorD;
|
typedef Lattice<vHalfSpinColourVectorD> LatticeHalfSpinColourVectorD;
|
||||||
typedef Lattice<vHalfSpinColourVectorD2> LatticeHalfSpinColourVectorD2;
|
|
||||||
|
|
||||||
typedef Lattice<vTReal> LatticeReal;
|
typedef Lattice<vTReal> LatticeReal;
|
||||||
typedef Lattice<vTRealF> LatticeRealF;
|
typedef Lattice<vTRealF> LatticeRealF;
|
||||||
@@ -359,7 +324,6 @@ typedef Lattice<vTRealD> LatticeRealD;
|
|||||||
typedef Lattice<vTComplex> LatticeComplex;
|
typedef Lattice<vTComplex> LatticeComplex;
|
||||||
typedef Lattice<vTComplexF> LatticeComplexF;
|
typedef Lattice<vTComplexF> LatticeComplexF;
|
||||||
typedef Lattice<vTComplexD> LatticeComplexD;
|
typedef Lattice<vTComplexD> LatticeComplexD;
|
||||||
typedef Lattice<vTComplexD2> LatticeComplexD2;
|
|
||||||
|
|
||||||
typedef Lattice<vTInteger> LatticeInteger; // Predicates for "where"
|
typedef Lattice<vTInteger> LatticeInteger; // Predicates for "where"
|
||||||
|
|
||||||
@@ -370,39 +334,124 @@ typedef Lattice<vTInteger> LatticeInteger; // Predicates for "where"
|
|||||||
typedef LatticeHalfSpinColourVector LatticeHalfFermion;
|
typedef LatticeHalfSpinColourVector LatticeHalfFermion;
|
||||||
typedef LatticeHalfSpinColourVectorF LatticeHalfFermionF;
|
typedef LatticeHalfSpinColourVectorF LatticeHalfFermionF;
|
||||||
typedef LatticeHalfSpinColourVectorD LatticeHalfFermionD;
|
typedef LatticeHalfSpinColourVectorD LatticeHalfFermionD;
|
||||||
typedef LatticeHalfSpinColourVectorD2 LatticeHalfFermionD2;
|
|
||||||
|
|
||||||
typedef LatticeSpinColourVector LatticeFermion;
|
typedef LatticeSpinColourVector LatticeFermion;
|
||||||
typedef LatticeSpinColourVectorF LatticeFermionF;
|
typedef LatticeSpinColourVectorF LatticeFermionF;
|
||||||
typedef LatticeSpinColourVectorD LatticeFermionD;
|
typedef LatticeSpinColourVectorD LatticeFermionD;
|
||||||
typedef LatticeSpinColourVectorD2 LatticeFermionD2;
|
|
||||||
|
|
||||||
typedef LatticeSpinColourMatrix LatticePropagator;
|
typedef LatticeSpinColourMatrix LatticePropagator;
|
||||||
typedef LatticeSpinColourMatrixF LatticePropagatorF;
|
typedef LatticeSpinColourMatrixF LatticePropagatorF;
|
||||||
typedef LatticeSpinColourMatrixD LatticePropagatorD;
|
typedef LatticeSpinColourMatrixD LatticePropagatorD;
|
||||||
typedef LatticeSpinColourMatrixD2 LatticePropagatorD2;
|
|
||||||
|
|
||||||
typedef LatticeLorentzColourMatrix LatticeGaugeField;
|
typedef LatticeLorentzColourMatrix LatticeGaugeField;
|
||||||
typedef LatticeLorentzColourMatrixF LatticeGaugeFieldF;
|
typedef LatticeLorentzColourMatrixF LatticeGaugeFieldF;
|
||||||
typedef LatticeLorentzColourMatrixD LatticeGaugeFieldD;
|
typedef LatticeLorentzColourMatrixD LatticeGaugeFieldD;
|
||||||
typedef LatticeLorentzColourMatrixD2 LatticeGaugeFieldD2;
|
|
||||||
|
|
||||||
typedef LatticeDoubleStoredColourMatrix LatticeDoubledGaugeField;
|
typedef LatticeDoubleStoredColourMatrix LatticeDoubledGaugeField;
|
||||||
typedef LatticeDoubleStoredColourMatrixF LatticeDoubledGaugeFieldF;
|
typedef LatticeDoubleStoredColourMatrixF LatticeDoubledGaugeFieldF;
|
||||||
typedef LatticeDoubleStoredColourMatrixD LatticeDoubledGaugeFieldD;
|
typedef LatticeDoubleStoredColourMatrixD LatticeDoubledGaugeFieldD;
|
||||||
typedef LatticeDoubleStoredColourMatrixD2 LatticeDoubledGaugeFieldD2;
|
|
||||||
|
|
||||||
template<class GF> using LorentzScalar = Lattice<iScalar<typename GF::vector_object::element> >;
|
template<class GF> using LorentzScalar = Lattice<iScalar<typename GF::vector_object::element> >;
|
||||||
|
|
||||||
typedef Lattice<vColourVector> LatticeStaggeredFermion;
|
typedef Lattice<vColourVector> LatticeStaggeredFermion;
|
||||||
typedef Lattice<vColourVectorF> LatticeStaggeredFermionF;
|
typedef Lattice<vColourVectorF> LatticeStaggeredFermionF;
|
||||||
typedef Lattice<vColourVectorD> LatticeStaggeredFermionD;
|
typedef Lattice<vColourVectorD> LatticeStaggeredFermionD;
|
||||||
typedef Lattice<vColourVectorD2> LatticeStaggeredFermionD2;
|
|
||||||
|
|
||||||
typedef Lattice<vColourMatrix> LatticeStaggeredPropagator;
|
typedef Lattice<vColourMatrix> LatticeStaggeredPropagator;
|
||||||
typedef Lattice<vColourMatrixF> LatticeStaggeredPropagatorF;
|
typedef Lattice<vColourMatrixF> LatticeStaggeredPropagatorF;
|
||||||
typedef Lattice<vColourMatrixD> LatticeStaggeredPropagatorD;
|
typedef Lattice<vColourMatrixD> LatticeStaggeredPropagatorD;
|
||||||
typedef Lattice<vColourMatrixD2> LatticeStaggeredPropagatorD2;
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lexicographic lattice types: Nsimd()==1 containers of the same tensors.
|
||||||
|
// Single and double precision only; no default precision alias.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Site objects over the width one simd types
|
||||||
|
typedef iSpinMatrix<sComplexF> sSpinMatrixF;
|
||||||
|
typedef iSpinMatrix<sComplexD> sSpinMatrixD;
|
||||||
|
typedef iColourMatrix<sComplexF> sColourMatrixF;
|
||||||
|
typedef iColourMatrix<sComplexD> sColourMatrixD;
|
||||||
|
typedef iSpinColourMatrix<sComplexF> sSpinColourMatrixF;
|
||||||
|
typedef iSpinColourMatrix<sComplexD> sSpinColourMatrixD;
|
||||||
|
typedef iSpinColourSpinColourMatrix<sComplexF> sSpinColourSpinColourMatrixF;
|
||||||
|
typedef iSpinColourSpinColourMatrix<sComplexD> sSpinColourSpinColourMatrixD;
|
||||||
|
typedef iLorentzColourMatrix<sComplexF> sLorentzColourMatrixF;
|
||||||
|
typedef iLorentzColourMatrix<sComplexD> sLorentzColourMatrixD;
|
||||||
|
typedef iLorentzComplex<sComplexF> sLorentzComplexF;
|
||||||
|
typedef iLorentzComplex<sComplexD> sLorentzComplexD;
|
||||||
|
typedef iDoubleStoredColourMatrix<sComplexF> sDoubleStoredColourMatrixF;
|
||||||
|
typedef iDoubleStoredColourMatrix<sComplexD> sDoubleStoredColourMatrixD;
|
||||||
|
typedef iGparityFlavourMatrix<sComplexF> sGparityFlavourMatrixF;
|
||||||
|
typedef iGparityFlavourMatrix<sComplexD> sGparityFlavourMatrixD;
|
||||||
|
typedef iSpinVector<sComplexF> sSpinVectorF;
|
||||||
|
typedef iSpinVector<sComplexD> sSpinVectorD;
|
||||||
|
typedef iColourVector<sComplexF> sColourVectorF;
|
||||||
|
typedef iColourVector<sComplexD> sColourVectorD;
|
||||||
|
typedef iSpinColourVector<sComplexF> sSpinColourVectorF;
|
||||||
|
typedef iSpinColourVector<sComplexD> sSpinColourVectorD;
|
||||||
|
typedef iHalfSpinVector<sComplexF> sHalfSpinVectorF;
|
||||||
|
typedef iHalfSpinVector<sComplexD> sHalfSpinVectorD;
|
||||||
|
typedef iHalfSpinColourVector<sComplexF> sHalfSpinColourVectorF;
|
||||||
|
typedef iHalfSpinColourVector<sComplexD> sHalfSpinColourVectorD;
|
||||||
|
typedef iGparityFlavourVector<sComplexF> sGparityFlavourVectorF;
|
||||||
|
typedef iGparityFlavourVector<sComplexD> sGparityFlavourVectorD;
|
||||||
|
typedef iSinglet<sComplexF> sTComplexF;
|
||||||
|
typedef iSinglet<sComplexD> sTComplexD;
|
||||||
|
typedef iSinglet<sRealF> sTRealF;
|
||||||
|
typedef iSinglet<sRealD> sTRealD;
|
||||||
|
typedef iSinglet<sInteger> sTInteger;
|
||||||
|
|
||||||
|
// Lattices of these
|
||||||
|
typedef Lattice<sColourMatrixF> lexLatticeColourMatrixF;
|
||||||
|
typedef Lattice<sColourMatrixD> lexLatticeColourMatrixD;
|
||||||
|
typedef Lattice<sSpinMatrixF> lexLatticeSpinMatrixF;
|
||||||
|
typedef Lattice<sSpinMatrixD> lexLatticeSpinMatrixD;
|
||||||
|
typedef Lattice<sSpinColourMatrixF> lexLatticeSpinColourMatrixF;
|
||||||
|
typedef Lattice<sSpinColourMatrixD> lexLatticeSpinColourMatrixD;
|
||||||
|
typedef Lattice<sSpinColourSpinColourMatrixF> lexLatticeSpinColourSpinColourMatrixF;
|
||||||
|
typedef Lattice<sSpinColourSpinColourMatrixD> lexLatticeSpinColourSpinColourMatrixD;
|
||||||
|
typedef Lattice<sLorentzColourMatrixF> lexLatticeLorentzColourMatrixF;
|
||||||
|
typedef Lattice<sLorentzColourMatrixD> lexLatticeLorentzColourMatrixD;
|
||||||
|
typedef Lattice<sLorentzComplexF> lexLatticeLorentzComplexF;
|
||||||
|
typedef Lattice<sLorentzComplexD> lexLatticeLorentzComplexD;
|
||||||
|
typedef Lattice<sDoubleStoredColourMatrixF> lexLatticeDoubleStoredColourMatrixF;
|
||||||
|
typedef Lattice<sDoubleStoredColourMatrixD> lexLatticeDoubleStoredColourMatrixD;
|
||||||
|
typedef Lattice<sSpinVectorF> lexLatticeSpinVectorF;
|
||||||
|
typedef Lattice<sSpinVectorD> lexLatticeSpinVectorD;
|
||||||
|
typedef Lattice<sColourVectorF> lexLatticeColourVectorF;
|
||||||
|
typedef Lattice<sColourVectorD> lexLatticeColourVectorD;
|
||||||
|
typedef Lattice<sSpinColourVectorF> lexLatticeSpinColourVectorF;
|
||||||
|
typedef Lattice<sSpinColourVectorD> lexLatticeSpinColourVectorD;
|
||||||
|
typedef Lattice<sHalfSpinVectorF> lexLatticeHalfSpinVectorF;
|
||||||
|
typedef Lattice<sHalfSpinVectorD> lexLatticeHalfSpinVectorD;
|
||||||
|
typedef Lattice<sHalfSpinColourVectorF> lexLatticeHalfSpinColourVectorF;
|
||||||
|
typedef Lattice<sHalfSpinColourVectorD> lexLatticeHalfSpinColourVectorD;
|
||||||
|
typedef Lattice<sTRealF> lexLatticeRealF;
|
||||||
|
typedef Lattice<sTRealD> lexLatticeRealD;
|
||||||
|
typedef Lattice<sTComplexF> lexLatticeComplexF;
|
||||||
|
typedef Lattice<sTComplexD> lexLatticeComplexD;
|
||||||
|
typedef Lattice<sTInteger> lexLatticeInteger;
|
||||||
|
typedef Lattice<sColourVectorF> lexLatticeStaggeredFermionF;
|
||||||
|
typedef Lattice<sColourVectorD> lexLatticeStaggeredFermionD;
|
||||||
|
typedef Lattice<sColourMatrixF> lexLatticeStaggeredPropagatorF;
|
||||||
|
typedef Lattice<sColourMatrixD> lexLatticeStaggeredPropagatorD;
|
||||||
|
|
||||||
|
// Physical names for things
|
||||||
|
typedef lexLatticeHalfSpinColourVectorF lexLatticeHalfFermionF;
|
||||||
|
typedef lexLatticeHalfSpinColourVectorD lexLatticeHalfFermionD;
|
||||||
|
typedef lexLatticeSpinColourVectorF lexLatticeFermionF;
|
||||||
|
typedef lexLatticeSpinColourVectorD lexLatticeFermionD;
|
||||||
|
typedef lexLatticeSpinColourMatrixF lexLatticePropagatorF;
|
||||||
|
typedef lexLatticeSpinColourMatrixD lexLatticePropagatorD;
|
||||||
|
typedef lexLatticeLorentzColourMatrixF lexLatticeGaugeFieldF;
|
||||||
|
typedef lexLatticeLorentzColourMatrixD lexLatticeGaugeFieldD;
|
||||||
|
typedef lexLatticeDoubleStoredColourMatrixF lexLatticeDoubledGaugeFieldF;
|
||||||
|
typedef lexLatticeDoubleStoredColourMatrixD lexLatticeDoubledGaugeFieldD;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// End lexicographic lattice types
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Peek and Poke named after physics attributes
|
// Peek and Poke named after physics attributes
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ public:
|
|||||||
static int getNMAX(Lattice<iImplClover<vComplexD2>> &t, RealD R) {return getNMAX(1e-12,R);}
|
static int getNMAX(Lattice<iImplClover<vComplexD2>> &t, RealD R) {return getNMAX(1e-12,R);}
|
||||||
static int getNMAX(Lattice<iImplClover<vComplexD>> &t, RealD R) {return getNMAX(1e-12,R);}
|
static int getNMAX(Lattice<iImplClover<vComplexD>> &t, RealD R) {return getNMAX(1e-12,R);}
|
||||||
static int getNMAX(Lattice<iImplClover<vComplexF>> &t, RealD R) {return getNMAX(1e-6,R);}
|
static int getNMAX(Lattice<iImplClover<vComplexF>> &t, RealD R) {return getNMAX(1e-6,R);}
|
||||||
|
static int getNMAX(Lattice<iImplClover<sComplexD>> &t, RealD R) {return getNMAX(1e-12,R);}
|
||||||
|
static int getNMAX(Lattice<iImplClover<sComplexF>> &t, RealD R) {return getNMAX(1e-6,R);}
|
||||||
|
|
||||||
static void Instantiate(CloverField& Clover, CloverField& CloverInv, RealD csw_t, RealD diag_mass) {
|
static void Instantiate(CloverField& Clover, CloverField& CloverInv, RealD csw_t, RealD diag_mass) {
|
||||||
GridBase* grid = Clover.Grid();
|
GridBase* grid = Clover.Grid();
|
||||||
@@ -268,6 +270,8 @@ public:
|
|||||||
|
|
||||||
static int getNMAX(Lattice<iImplClover<vComplexD>> &t, RealD R) {return getNMAX(1e-12,R);}
|
static int getNMAX(Lattice<iImplClover<vComplexD>> &t, RealD R) {return getNMAX(1e-12,R);}
|
||||||
static int getNMAX(Lattice<iImplClover<vComplexF>> &t, RealD R) {return getNMAX(1e-6,R);}
|
static int getNMAX(Lattice<iImplClover<vComplexF>> &t, RealD R) {return getNMAX(1e-6,R);}
|
||||||
|
static int getNMAX(Lattice<iImplClover<sComplexD>> &t, RealD R) {return getNMAX(1e-12,R);}
|
||||||
|
static int getNMAX(Lattice<iImplClover<sComplexF>> &t, RealD R) {return getNMAX(1e-6,R);}
|
||||||
|
|
||||||
static void InstantiateClover(CloverField& Clover, CloverField& CloverInv, RealD csw_t, RealD diag_mass) {
|
static void InstantiateClover(CloverField& Clover, CloverField& CloverInv, RealD csw_t, RealD diag_mass) {
|
||||||
|
|
||||||
|
|||||||
@@ -40,15 +40,12 @@ public:
|
|||||||
static const int Dimension = Representation::Dimension;
|
static const int Dimension = Representation::Dimension;
|
||||||
static const bool isFundamental = Representation::isFundamental;
|
static const bool isFundamental = Representation::isFundamental;
|
||||||
static const bool LsVectorised=true;
|
static const bool LsVectorised=true;
|
||||||
static const int Nhcs = Options::Nhcs;
|
|
||||||
|
|
||||||
typedef typename Options::_Coeff_t Coeff_t;
|
typedef typename Options::_Coeff_t Coeff_t;
|
||||||
typedef typename Options::template PrecisionMapper<Simd>::LowerPrecVector SimdL;
|
|
||||||
|
|
||||||
template <typename vtype> using iImplSpinor = iScalar<iVector<iVector<vtype, Dimension>, Ns> >;
|
template <typename vtype> using iImplSpinor = iScalar<iVector<iVector<vtype, Dimension>, Ns> >;
|
||||||
template <typename vtype> using iImplPropagator = iScalar<iMatrix<iMatrix<vtype, Dimension>, Ns> >;
|
template <typename vtype> using iImplPropagator = iScalar<iMatrix<iMatrix<vtype, Dimension>, Ns> >;
|
||||||
template <typename vtype> using iImplHalfSpinor = iScalar<iVector<iVector<vtype, Dimension>, Nhs> >;
|
template <typename vtype> using iImplHalfSpinor = iScalar<iVector<iVector<vtype, Dimension>, Nhs> >;
|
||||||
template <typename vtype> using iImplHalfCommSpinor = iScalar<iVector<iVector<vtype, Dimension>, Nhcs> >;
|
|
||||||
template <typename vtype> using iImplDoubledGaugeField = iVector<iScalar<iMatrix<vtype, Dimension> >, Nds>;
|
template <typename vtype> using iImplDoubledGaugeField = iVector<iScalar<iMatrix<vtype, Dimension> >, Nds>;
|
||||||
template <typename vtype> using iImplGaugeField = iVector<iScalar<iMatrix<vtype, Dimension> >, Nd>;
|
template <typename vtype> using iImplGaugeField = iVector<iScalar<iMatrix<vtype, Dimension> >, Nd>;
|
||||||
template <typename vtype> using iImplGaugeLink = iScalar<iScalar<iMatrix<vtype, Dimension> > >;
|
template <typename vtype> using iImplGaugeLink = iScalar<iScalar<iMatrix<vtype, Dimension> > >;
|
||||||
@@ -56,7 +53,6 @@ public:
|
|||||||
typedef iImplSpinor<Simd> SiteSpinor;
|
typedef iImplSpinor<Simd> SiteSpinor;
|
||||||
typedef iImplPropagator<Simd> SitePropagator;
|
typedef iImplPropagator<Simd> SitePropagator;
|
||||||
typedef iImplHalfSpinor<Simd> SiteHalfSpinor;
|
typedef iImplHalfSpinor<Simd> SiteHalfSpinor;
|
||||||
typedef iImplHalfCommSpinor<SimdL> SiteHalfCommSpinor;
|
|
||||||
typedef Lattice<SiteSpinor> FermionField;
|
typedef Lattice<SiteSpinor> FermionField;
|
||||||
typedef Lattice<SitePropagator> PropagatorField;
|
typedef Lattice<SitePropagator> PropagatorField;
|
||||||
|
|
||||||
@@ -68,7 +64,7 @@ public:
|
|||||||
typedef iImplGaugeLink<typename Simd::scalar_type> SiteScalarGaugeLink; // scalar
|
typedef iImplGaugeLink<typename Simd::scalar_type> SiteScalarGaugeLink; // scalar
|
||||||
typedef Lattice<SiteDoubledGaugeField> DoubledGaugeField;
|
typedef Lattice<SiteDoubledGaugeField> DoubledGaugeField;
|
||||||
|
|
||||||
typedef WilsonCompressor<SiteHalfCommSpinor,SiteHalfSpinor, SiteSpinor> Compressor;
|
typedef WilsonCompressor<SiteHalfSpinor, SiteSpinor> Compressor;
|
||||||
typedef WilsonImplParams ImplParams;
|
typedef WilsonImplParams ImplParams;
|
||||||
typedef WilsonStencil<SiteSpinor, SiteHalfSpinor,ImplParams> StencilImpl;
|
typedef WilsonStencil<SiteSpinor, SiteHalfSpinor,ImplParams> StencilImpl;
|
||||||
typedef typename StencilImpl::View_type StencilView;
|
typedef typename StencilImpl::View_type StencilView;
|
||||||
@@ -201,16 +197,8 @@ typedef DomainWallVec5dImpl<vComplex ,FundamentalRepresentation, CoeffReal> Doma
|
|||||||
typedef DomainWallVec5dImpl<vComplexF,FundamentalRepresentation, CoeffReal> DomainWallVec5dImplF; // Float
|
typedef DomainWallVec5dImpl<vComplexF,FundamentalRepresentation, CoeffReal> DomainWallVec5dImplF; // Float
|
||||||
typedef DomainWallVec5dImpl<vComplexD,FundamentalRepresentation, CoeffReal> DomainWallVec5dImplD; // Double
|
typedef DomainWallVec5dImpl<vComplexD,FundamentalRepresentation, CoeffReal> DomainWallVec5dImplD; // Double
|
||||||
|
|
||||||
typedef DomainWallVec5dImpl<vComplex ,FundamentalRepresentation, CoeffRealHalfComms> DomainWallVec5dImplRL; // Real.. whichever prec
|
|
||||||
typedef DomainWallVec5dImpl<vComplexF,FundamentalRepresentation, CoeffRealHalfComms> DomainWallVec5dImplFH; // Float
|
|
||||||
typedef DomainWallVec5dImpl<vComplexD,FundamentalRepresentation, CoeffRealHalfComms> DomainWallVec5dImplDF; // Double
|
|
||||||
|
|
||||||
typedef DomainWallVec5dImpl<vComplex ,FundamentalRepresentation,CoeffComplex> ZDomainWallVec5dImplR; // Real.. whichever prec
|
typedef DomainWallVec5dImpl<vComplex ,FundamentalRepresentation,CoeffComplex> ZDomainWallVec5dImplR; // Real.. whichever prec
|
||||||
typedef DomainWallVec5dImpl<vComplexF,FundamentalRepresentation,CoeffComplex> ZDomainWallVec5dImplF; // Float
|
typedef DomainWallVec5dImpl<vComplexF,FundamentalRepresentation,CoeffComplex> ZDomainWallVec5dImplF; // Float
|
||||||
typedef DomainWallVec5dImpl<vComplexD,FundamentalRepresentation,CoeffComplex> ZDomainWallVec5dImplD; // Double
|
typedef DomainWallVec5dImpl<vComplexD,FundamentalRepresentation,CoeffComplex> ZDomainWallVec5dImplD; // Double
|
||||||
|
|
||||||
typedef DomainWallVec5dImpl<vComplex ,FundamentalRepresentation,CoeffComplexHalfComms> ZDomainWallVec5dImplRL; // Real.. whichever prec
|
|
||||||
typedef DomainWallVec5dImpl<vComplexF,FundamentalRepresentation,CoeffComplexHalfComms> ZDomainWallVec5dImplFH; // Float
|
|
||||||
typedef DomainWallVec5dImpl<vComplexD,FundamentalRepresentation,CoeffComplexHalfComms> ZDomainWallVec5dImplDF; // Double
|
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ NAMESPACE_CHECK(DWFutils);
|
|||||||
// Cayley 5d
|
// Cayley 5d
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
typedef WilsonFermion<WilsonImplD2> WilsonFermionD2;
|
//typedef WilsonFermion<WilsonImplD2> WilsonFermionD2;
|
||||||
typedef WilsonFermion<WilsonImplF> WilsonFermionF;
|
typedef WilsonFermion<WilsonImplF> WilsonFermionF;
|
||||||
typedef WilsonFermion<WilsonImplD> WilsonFermionD;
|
typedef WilsonFermion<WilsonImplD> WilsonFermionD;
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ typedef WilsonFermion<SpWilsonTwoIndexSymmetricImplF> SpWilsonTwoIndexSymmetricF
|
|||||||
typedef WilsonFermion<SpWilsonTwoIndexSymmetricImplD> SpWilsonTwoIndexSymmetricFermionD;
|
typedef WilsonFermion<SpWilsonTwoIndexSymmetricImplD> SpWilsonTwoIndexSymmetricFermionD;
|
||||||
|
|
||||||
// Twisted mass fermion
|
// Twisted mass fermion
|
||||||
typedef WilsonTMFermion<WilsonImplD2> WilsonTMFermionD2;
|
//typedef WilsonTMFermion<WilsonImplD2> WilsonTMFermionD2;
|
||||||
typedef WilsonTMFermion<WilsonImplF> WilsonTMFermionF;
|
typedef WilsonTMFermion<WilsonImplF> WilsonTMFermionF;
|
||||||
typedef WilsonTMFermion<WilsonImplD> WilsonTMFermionD;
|
typedef WilsonTMFermion<WilsonImplD> WilsonTMFermionD;
|
||||||
|
|
||||||
@@ -146,11 +146,11 @@ typedef WilsonTMFermion<WilsonImplD> WilsonTMFermionD;
|
|||||||
template <typename WImpl> using WilsonClover = WilsonCloverFermion<WImpl, CloverHelpers<WImpl>>;
|
template <typename WImpl> using WilsonClover = WilsonCloverFermion<WImpl, CloverHelpers<WImpl>>;
|
||||||
template <typename WImpl> using WilsonExpClover = WilsonCloverFermion<WImpl, ExpCloverHelpers<WImpl>>;
|
template <typename WImpl> using WilsonExpClover = WilsonCloverFermion<WImpl, ExpCloverHelpers<WImpl>>;
|
||||||
|
|
||||||
typedef WilsonClover<WilsonImplD2> WilsonCloverFermionD2;
|
//typedef WilsonClover<WilsonImplD2> WilsonCloverFermionD2;
|
||||||
typedef WilsonClover<WilsonImplF> WilsonCloverFermionF;
|
typedef WilsonClover<WilsonImplF> WilsonCloverFermionF;
|
||||||
typedef WilsonClover<WilsonImplD> WilsonCloverFermionD;
|
typedef WilsonClover<WilsonImplD> WilsonCloverFermionD;
|
||||||
|
|
||||||
typedef WilsonExpClover<WilsonImplD2> WilsonExpCloverFermionD2;
|
//typedef WilsonExpClover<WilsonImplD2> WilsonExpCloverFermionD2;
|
||||||
typedef WilsonExpClover<WilsonImplF> WilsonExpCloverFermionF;
|
typedef WilsonExpClover<WilsonImplF> WilsonExpCloverFermionF;
|
||||||
typedef WilsonExpClover<WilsonImplD> WilsonExpCloverFermionD;
|
typedef WilsonExpClover<WilsonImplD> WilsonExpCloverFermionD;
|
||||||
|
|
||||||
@@ -168,15 +168,15 @@ template <typename WImpl> using CompactWilsonClover = CompactWilsonCloverFermion
|
|||||||
template <typename WImpl> using CompactWilsonClover5D = CompactWilsonCloverFermion5D<WImpl, CompactCloverHelpers<WImpl>>;
|
template <typename WImpl> using CompactWilsonClover5D = CompactWilsonCloverFermion5D<WImpl, CompactCloverHelpers<WImpl>>;
|
||||||
template <typename WImpl> using CompactWilsonExpClover = CompactWilsonCloverFermion<WImpl, CompactExpCloverHelpers<WImpl>>;
|
template <typename WImpl> using CompactWilsonExpClover = CompactWilsonCloverFermion<WImpl, CompactExpCloverHelpers<WImpl>>;
|
||||||
|
|
||||||
typedef CompactWilsonClover<WilsonImplD2> CompactWilsonCloverFermionD2;
|
//typedef CompactWilsonClover<WilsonImplD2> CompactWilsonCloverFermionD2;
|
||||||
typedef CompactWilsonClover<WilsonImplF> CompactWilsonCloverFermionF;
|
typedef CompactWilsonClover<WilsonImplF> CompactWilsonCloverFermionF;
|
||||||
typedef CompactWilsonClover<WilsonImplD> CompactWilsonCloverFermionD;
|
typedef CompactWilsonClover<WilsonImplD> CompactWilsonCloverFermionD;
|
||||||
|
|
||||||
typedef CompactWilsonClover5D<WilsonImplD2> CompactWilsonCloverFermion5DD2;
|
//typedef CompactWilsonClover5D<WilsonImplD2> CompactWilsonCloverFermion5DD2;
|
||||||
typedef CompactWilsonClover5D<WilsonImplF> CompactWilsonCloverFermion5DF;
|
typedef CompactWilsonClover5D<WilsonImplF> CompactWilsonCloverFermion5DF;
|
||||||
typedef CompactWilsonClover5D<WilsonImplD> CompactWilsonCloverFermion5DD;
|
typedef CompactWilsonClover5D<WilsonImplD> CompactWilsonCloverFermion5DD;
|
||||||
|
|
||||||
typedef CompactWilsonExpClover<WilsonImplD2> CompactWilsonExpCloverFermionD2;
|
//typedef CompactWilsonExpClover<WilsonImplD2> CompactWilsonExpCloverFermionD2;
|
||||||
typedef CompactWilsonExpClover<WilsonImplF> CompactWilsonExpCloverFermionF;
|
typedef CompactWilsonExpClover<WilsonImplF> CompactWilsonExpCloverFermionF;
|
||||||
typedef CompactWilsonExpClover<WilsonImplD> CompactWilsonExpCloverFermionD;
|
typedef CompactWilsonExpClover<WilsonImplD> CompactWilsonExpCloverFermionD;
|
||||||
|
|
||||||
@@ -192,56 +192,56 @@ typedef CompactWilsonClover<WilsonTwoIndexAntiSymmetricImplD> CompactWilsonClove
|
|||||||
// Domain Wall fermions
|
// Domain Wall fermions
|
||||||
typedef DomainWallFermion<WilsonImplF> DomainWallFermionF;
|
typedef DomainWallFermion<WilsonImplF> DomainWallFermionF;
|
||||||
typedef DomainWallFermion<WilsonImplD> DomainWallFermionD;
|
typedef DomainWallFermion<WilsonImplD> DomainWallFermionD;
|
||||||
typedef DomainWallFermion<WilsonImplD2> DomainWallFermionD2;
|
//typedef DomainWallFermion<WilsonImplD2> DomainWallFermionD2;
|
||||||
|
|
||||||
typedef DomainWallEOFAFermion<WilsonImplD2> DomainWallEOFAFermionD2;
|
//typedef DomainWallEOFAFermion<WilsonImplD2> DomainWallEOFAFermionD2;
|
||||||
typedef DomainWallEOFAFermion<WilsonImplF> DomainWallEOFAFermionF;
|
typedef DomainWallEOFAFermion<WilsonImplF> DomainWallEOFAFermionF;
|
||||||
typedef DomainWallEOFAFermion<WilsonImplD> DomainWallEOFAFermionD;
|
typedef DomainWallEOFAFermion<WilsonImplD> DomainWallEOFAFermionD;
|
||||||
|
|
||||||
typedef MobiusFermion<WilsonImplD2> MobiusFermionD2;
|
//typedef MobiusFermion<WilsonImplD2> MobiusFermionD2;
|
||||||
typedef MobiusFermion<WilsonImplF> MobiusFermionF;
|
typedef MobiusFermion<WilsonImplF> MobiusFermionF;
|
||||||
typedef MobiusFermion<WilsonImplD> MobiusFermionD;
|
typedef MobiusFermion<WilsonImplD> MobiusFermionD;
|
||||||
|
|
||||||
typedef MobiusEOFAFermion<WilsonImplD2> MobiusEOFAFermionD2;
|
//typedef MobiusEOFAFermion<WilsonImplD2> MobiusEOFAFermionD2;
|
||||||
typedef MobiusEOFAFermion<WilsonImplF> MobiusEOFAFermionF;
|
typedef MobiusEOFAFermion<WilsonImplF> MobiusEOFAFermionF;
|
||||||
typedef MobiusEOFAFermion<WilsonImplD> MobiusEOFAFermionD;
|
typedef MobiusEOFAFermion<WilsonImplD> MobiusEOFAFermionD;
|
||||||
|
|
||||||
typedef ZMobiusFermion<ZWilsonImplD2> ZMobiusFermionD2;
|
//typedef ZMobiusFermion<ZWilsonImplD2> ZMobiusFermionD2;
|
||||||
typedef ZMobiusFermion<ZWilsonImplF> ZMobiusFermionF;
|
typedef ZMobiusFermion<ZWilsonImplF> ZMobiusFermionF;
|
||||||
typedef ZMobiusFermion<ZWilsonImplD> ZMobiusFermionD;
|
typedef ZMobiusFermion<ZWilsonImplD> ZMobiusFermionD;
|
||||||
|
|
||||||
typedef ScaledShamirFermion<WilsonImplD2> ScaledShamirFermionD2;
|
//typedef ScaledShamirFermion<WilsonImplD2> ScaledShamirFermionD2;
|
||||||
typedef ScaledShamirFermion<WilsonImplF> ScaledShamirFermionF;
|
typedef ScaledShamirFermion<WilsonImplF> ScaledShamirFermionF;
|
||||||
typedef ScaledShamirFermion<WilsonImplD> ScaledShamirFermionD;
|
typedef ScaledShamirFermion<WilsonImplD> ScaledShamirFermionD;
|
||||||
|
|
||||||
typedef MobiusZolotarevFermion<WilsonImplD2> MobiusZolotarevFermionD2;
|
//typedef MobiusZolotarevFermion<WilsonImplD2> MobiusZolotarevFermionD2;
|
||||||
typedef MobiusZolotarevFermion<WilsonImplF> MobiusZolotarevFermionF;
|
typedef MobiusZolotarevFermion<WilsonImplF> MobiusZolotarevFermionF;
|
||||||
typedef MobiusZolotarevFermion<WilsonImplD> MobiusZolotarevFermionD;
|
typedef MobiusZolotarevFermion<WilsonImplD> MobiusZolotarevFermionD;
|
||||||
typedef ShamirZolotarevFermion<WilsonImplD2> ShamirZolotarevFermionD2;
|
//typedef ShamirZolotarevFermion<WilsonImplD2> ShamirZolotarevFermionD2;
|
||||||
typedef ShamirZolotarevFermion<WilsonImplF> ShamirZolotarevFermionF;
|
typedef ShamirZolotarevFermion<WilsonImplF> ShamirZolotarevFermionF;
|
||||||
typedef ShamirZolotarevFermion<WilsonImplD> ShamirZolotarevFermionD;
|
typedef ShamirZolotarevFermion<WilsonImplD> ShamirZolotarevFermionD;
|
||||||
|
|
||||||
typedef OverlapWilsonCayleyTanhFermion<WilsonImplD2> OverlapWilsonCayleyTanhFermionD2;
|
//typedef OverlapWilsonCayleyTanhFermion<WilsonImplD2> OverlapWilsonCayleyTanhFermionD2;
|
||||||
typedef OverlapWilsonCayleyTanhFermion<WilsonImplF> OverlapWilsonCayleyTanhFermionF;
|
typedef OverlapWilsonCayleyTanhFermion<WilsonImplF> OverlapWilsonCayleyTanhFermionF;
|
||||||
typedef OverlapWilsonCayleyTanhFermion<WilsonImplD> OverlapWilsonCayleyTanhFermionD;
|
typedef OverlapWilsonCayleyTanhFermion<WilsonImplD> OverlapWilsonCayleyTanhFermionD;
|
||||||
typedef OverlapWilsonCayleyZolotarevFermion<WilsonImplD2> OverlapWilsonCayleyZolotarevFermionD2;
|
//typedef OverlapWilsonCayleyZolotarevFermion<WilsonImplD2> OverlapWilsonCayleyZolotarevFermionD2;
|
||||||
typedef OverlapWilsonCayleyZolotarevFermion<WilsonImplF> OverlapWilsonCayleyZolotarevFermionF;
|
typedef OverlapWilsonCayleyZolotarevFermion<WilsonImplF> OverlapWilsonCayleyZolotarevFermionF;
|
||||||
typedef OverlapWilsonCayleyZolotarevFermion<WilsonImplD> OverlapWilsonCayleyZolotarevFermionD;
|
typedef OverlapWilsonCayleyZolotarevFermion<WilsonImplD> OverlapWilsonCayleyZolotarevFermionD;
|
||||||
|
|
||||||
// Continued fraction
|
// Continued fraction
|
||||||
typedef OverlapWilsonContFracTanhFermion<WilsonImplD2> OverlapWilsonContFracTanhFermionD2;
|
//typedef OverlapWilsonContFracTanhFermion<WilsonImplD2> OverlapWilsonContFracTanhFermionD2;
|
||||||
typedef OverlapWilsonContFracTanhFermion<WilsonImplF> OverlapWilsonContFracTanhFermionF;
|
typedef OverlapWilsonContFracTanhFermion<WilsonImplF> OverlapWilsonContFracTanhFermionF;
|
||||||
typedef OverlapWilsonContFracTanhFermion<WilsonImplD> OverlapWilsonContFracTanhFermionD;
|
typedef OverlapWilsonContFracTanhFermion<WilsonImplD> OverlapWilsonContFracTanhFermionD;
|
||||||
typedef OverlapWilsonContFracZolotarevFermion<WilsonImplD2> OverlapWilsonContFracZolotarevFermionD2;
|
//typedef OverlapWilsonContFracZolotarevFermion<WilsonImplD2> OverlapWilsonContFracZolotarevFermionD2;
|
||||||
typedef OverlapWilsonContFracZolotarevFermion<WilsonImplF> OverlapWilsonContFracZolotarevFermionF;
|
typedef OverlapWilsonContFracZolotarevFermion<WilsonImplF> OverlapWilsonContFracZolotarevFermionF;
|
||||||
typedef OverlapWilsonContFracZolotarevFermion<WilsonImplD> OverlapWilsonContFracZolotarevFermionD;
|
typedef OverlapWilsonContFracZolotarevFermion<WilsonImplD> OverlapWilsonContFracZolotarevFermionD;
|
||||||
|
|
||||||
// Partial fraction
|
// Partial fraction
|
||||||
typedef OverlapWilsonPartialFractionTanhFermion<WilsonImplD2> OverlapWilsonPartialFractionTanhFermionD2;
|
//typedef OverlapWilsonPartialFractionTanhFermion<WilsonImplD2> OverlapWilsonPartialFractionTanhFermionD2;
|
||||||
typedef OverlapWilsonPartialFractionTanhFermion<WilsonImplF> OverlapWilsonPartialFractionTanhFermionF;
|
typedef OverlapWilsonPartialFractionTanhFermion<WilsonImplF> OverlapWilsonPartialFractionTanhFermionF;
|
||||||
typedef OverlapWilsonPartialFractionTanhFermion<WilsonImplD> OverlapWilsonPartialFractionTanhFermionD;
|
typedef OverlapWilsonPartialFractionTanhFermion<WilsonImplD> OverlapWilsonPartialFractionTanhFermionD;
|
||||||
|
|
||||||
typedef OverlapWilsonPartialFractionZolotarevFermion<WilsonImplD2> OverlapWilsonPartialFractionZolotarevFermionD2;
|
//typedef OverlapWilsonPartialFractionZolotarevFermion<WilsonImplD2> OverlapWilsonPartialFractionZolotarevFermionD2;
|
||||||
typedef OverlapWilsonPartialFractionZolotarevFermion<WilsonImplF> OverlapWilsonPartialFractionZolotarevFermionF;
|
typedef OverlapWilsonPartialFractionZolotarevFermion<WilsonImplF> OverlapWilsonPartialFractionZolotarevFermionF;
|
||||||
typedef OverlapWilsonPartialFractionZolotarevFermion<WilsonImplD> OverlapWilsonPartialFractionZolotarevFermionD;
|
typedef OverlapWilsonPartialFractionZolotarevFermion<WilsonImplD> OverlapWilsonPartialFractionZolotarevFermionD;
|
||||||
|
|
||||||
@@ -252,19 +252,19 @@ typedef WilsonFermion<GparityWilsonImplD> GparityWilsonFermionD;
|
|||||||
typedef DomainWallFermion<GparityWilsonImplF> GparityDomainWallFermionF;
|
typedef DomainWallFermion<GparityWilsonImplF> GparityDomainWallFermionF;
|
||||||
typedef DomainWallFermion<GparityWilsonImplD> GparityDomainWallFermionD;
|
typedef DomainWallFermion<GparityWilsonImplD> GparityDomainWallFermionD;
|
||||||
|
|
||||||
typedef DomainWallEOFAFermion<GparityWilsonImplR> GparityDomainWallEOFAFermionD2;
|
//typedef DomainWallEOFAFermion<GparityWilsonImplR> GparityDomainWallEOFAFermionD2;
|
||||||
typedef DomainWallEOFAFermion<GparityWilsonImplF> GparityDomainWallEOFAFermionF;
|
typedef DomainWallEOFAFermion<GparityWilsonImplF> GparityDomainWallEOFAFermionF;
|
||||||
typedef DomainWallEOFAFermion<GparityWilsonImplD> GparityDomainWallEOFAFermionD;
|
typedef DomainWallEOFAFermion<GparityWilsonImplD> GparityDomainWallEOFAFermionD;
|
||||||
|
|
||||||
typedef WilsonTMFermion<GparityWilsonImplR> GparityWilsonTMFermionD2;
|
//typedef WilsonTMFermion<GparityWilsonImplR> GparityWilsonTMFermionD2;
|
||||||
typedef WilsonTMFermion<GparityWilsonImplF> GparityWilsonTMFermionF;
|
typedef WilsonTMFermion<GparityWilsonImplF> GparityWilsonTMFermionF;
|
||||||
typedef WilsonTMFermion<GparityWilsonImplD> GparityWilsonTMFermionD;
|
typedef WilsonTMFermion<GparityWilsonImplD> GparityWilsonTMFermionD;
|
||||||
|
|
||||||
typedef MobiusFermion<GparityWilsonImplR> GparityMobiusFermionD2;
|
//typedef MobiusFermion<GparityWilsonImplR> GparityMobiusFermionD2;
|
||||||
typedef MobiusFermion<GparityWilsonImplF> GparityMobiusFermionF;
|
typedef MobiusFermion<GparityWilsonImplF> GparityMobiusFermionF;
|
||||||
typedef MobiusFermion<GparityWilsonImplD> GparityMobiusFermionD;
|
typedef MobiusFermion<GparityWilsonImplD> GparityMobiusFermionD;
|
||||||
|
|
||||||
typedef MobiusEOFAFermion<GparityWilsonImplR> GparityMobiusEOFAFermionD2;
|
//typedef MobiusEOFAFermion<GparityWilsonImplR> GparityMobiusEOFAFermionD2;
|
||||||
typedef MobiusEOFAFermion<GparityWilsonImplF> GparityMobiusEOFAFermionF;
|
typedef MobiusEOFAFermion<GparityWilsonImplF> GparityMobiusEOFAFermionF;
|
||||||
typedef MobiusEOFAFermion<GparityWilsonImplD> GparityMobiusEOFAFermionD;
|
typedef MobiusEOFAFermion<GparityWilsonImplD> GparityMobiusEOFAFermionD;
|
||||||
|
|
||||||
|
|||||||
@@ -88,51 +88,14 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
// }
|
// }
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
template <class T> struct SamePrecisionMapper {
|
|
||||||
typedef T HigherPrecVector ;
|
|
||||||
typedef T LowerPrecVector ;
|
|
||||||
};
|
|
||||||
template <class T> struct LowerPrecisionMapper { };
|
|
||||||
template <> struct LowerPrecisionMapper<vRealF> {
|
|
||||||
typedef vRealF HigherPrecVector ;
|
|
||||||
typedef vRealH LowerPrecVector ;
|
|
||||||
};
|
|
||||||
template <> struct LowerPrecisionMapper<vRealD> {
|
|
||||||
typedef vRealD HigherPrecVector ;
|
|
||||||
typedef vRealF LowerPrecVector ;
|
|
||||||
};
|
|
||||||
template <> struct LowerPrecisionMapper<vComplexF> {
|
|
||||||
typedef vComplexF HigherPrecVector ;
|
|
||||||
typedef vComplexH LowerPrecVector ;
|
|
||||||
};
|
|
||||||
template <> struct LowerPrecisionMapper<vComplexD> {
|
|
||||||
typedef vComplexD HigherPrecVector ;
|
|
||||||
typedef vComplexF LowerPrecVector ;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CoeffReal {
|
struct CoeffReal {
|
||||||
public:
|
public:
|
||||||
typedef RealD _Coeff_t;
|
typedef RealD _Coeff_t;
|
||||||
static const int Nhcs = 2;
|
|
||||||
template<class Simd> using PrecisionMapper = SamePrecisionMapper<Simd>;
|
|
||||||
};
|
|
||||||
struct CoeffRealHalfComms {
|
|
||||||
public:
|
|
||||||
typedef RealD _Coeff_t;
|
|
||||||
static const int Nhcs = 1;
|
|
||||||
template<class Simd> using PrecisionMapper = LowerPrecisionMapper<Simd>;
|
|
||||||
};
|
};
|
||||||
struct CoeffComplex {
|
struct CoeffComplex {
|
||||||
public:
|
public:
|
||||||
typedef ComplexD _Coeff_t;
|
typedef ComplexD _Coeff_t;
|
||||||
static const int Nhcs = 2;
|
|
||||||
template<class Simd> using PrecisionMapper = SamePrecisionMapper<Simd>;
|
|
||||||
};
|
|
||||||
struct CoeffComplexHalfComms {
|
|
||||||
public:
|
|
||||||
typedef ComplexD _Coeff_t;
|
|
||||||
static const int Nhcs = 1;
|
|
||||||
template<class Simd> using PrecisionMapper = LowerPrecisionMapper<Simd>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ public:
|
|||||||
|
|
||||||
static const int Dimension = Representation::Dimension;
|
static const int Dimension = Representation::Dimension;
|
||||||
static const bool isFundamental = Representation::isFundamental;
|
static const bool isFundamental = Representation::isFundamental;
|
||||||
static const int Nhcs = Options::Nhcs;
|
|
||||||
static const bool LsVectorised=false;
|
static const bool LsVectorised=false;
|
||||||
static const bool isGparity=true;
|
static const bool isGparity=true;
|
||||||
|
|
||||||
@@ -56,18 +55,15 @@ public:
|
|||||||
INHERIT_GIMPL_TYPES(Gimpl);
|
INHERIT_GIMPL_TYPES(Gimpl);
|
||||||
|
|
||||||
typedef typename Options::_Coeff_t Coeff_t;
|
typedef typename Options::_Coeff_t Coeff_t;
|
||||||
typedef typename Options::template PrecisionMapper<Simd>::LowerPrecVector SimdL;
|
|
||||||
|
|
||||||
template <typename vtype> using iImplSpinor = iVector<iVector<iVector<vtype, Dimension>, Ns>, Ngp>;
|
template <typename vtype> using iImplSpinor = iVector<iVector<iVector<vtype, Dimension>, Ns>, Ngp>;
|
||||||
template <typename vtype> using iImplPropagator = iMatrix<iMatrix<iMatrix<vtype, Dimension>, Ns>, Ngp>;
|
template <typename vtype> using iImplPropagator = iMatrix<iMatrix<iMatrix<vtype, Dimension>, Ns>, Ngp>;
|
||||||
template <typename vtype> using iImplHalfSpinor = iVector<iVector<iVector<vtype, Dimension>, Nhs>, Ngp>;
|
template <typename vtype> using iImplHalfSpinor = iVector<iVector<iVector<vtype, Dimension>, Nhs>, Ngp>;
|
||||||
template <typename vtype> using iImplHalfCommSpinor = iVector<iVector<iVector<vtype, Dimension>, Nhcs>, Ngp>;
|
|
||||||
template <typename vtype> using iImplDoubledGaugeField = iVector<iVector<iScalar<iMatrix<vtype, Dimension> >, Nds>, Ngp>;
|
template <typename vtype> using iImplDoubledGaugeField = iVector<iVector<iScalar<iMatrix<vtype, Dimension> >, Nds>, Ngp>;
|
||||||
|
|
||||||
typedef iImplSpinor<Simd> SiteSpinor;
|
typedef iImplSpinor<Simd> SiteSpinor;
|
||||||
typedef iImplPropagator<Simd> SitePropagator;
|
typedef iImplPropagator<Simd> SitePropagator;
|
||||||
typedef iImplHalfSpinor<Simd> SiteHalfSpinor;
|
typedef iImplHalfSpinor<Simd> SiteHalfSpinor;
|
||||||
typedef iImplHalfCommSpinor<SimdL> SiteHalfCommSpinor;
|
|
||||||
typedef iImplDoubledGaugeField<Simd> SiteDoubledGaugeField;
|
typedef iImplDoubledGaugeField<Simd> SiteDoubledGaugeField;
|
||||||
|
|
||||||
typedef Lattice<SiteSpinor> FermionField;
|
typedef Lattice<SiteSpinor> FermionField;
|
||||||
@@ -75,7 +71,7 @@ public:
|
|||||||
typedef Lattice<SiteDoubledGaugeField> DoubledGaugeField;
|
typedef Lattice<SiteDoubledGaugeField> DoubledGaugeField;
|
||||||
|
|
||||||
typedef GparityWilsonImplParams ImplParams;
|
typedef GparityWilsonImplParams ImplParams;
|
||||||
typedef WilsonCompressor<SiteHalfCommSpinor,SiteHalfSpinor, SiteSpinor> Compressor;
|
typedef WilsonCompressor<SiteHalfSpinor, SiteSpinor> Compressor;
|
||||||
typedef WilsonStencil<SiteSpinor, SiteHalfSpinor, ImplParams> StencilImpl;
|
typedef WilsonStencil<SiteSpinor, SiteHalfSpinor, ImplParams> StencilImpl;
|
||||||
typedef typename StencilImpl::View_type StencilView;
|
typedef typename StencilImpl::View_type StencilView;
|
||||||
|
|
||||||
@@ -409,8 +405,4 @@ typedef GparityWilsonImpl<vComplex , FundamentalRepresentation,CoeffReal> Gparit
|
|||||||
typedef GparityWilsonImpl<vComplexF, FundamentalRepresentation,CoeffReal> GparityWilsonImplF; // Float
|
typedef GparityWilsonImpl<vComplexF, FundamentalRepresentation,CoeffReal> GparityWilsonImplF; // Float
|
||||||
typedef GparityWilsonImpl<vComplexD, FundamentalRepresentation,CoeffReal> GparityWilsonImplD; // Double
|
typedef GparityWilsonImpl<vComplexD, FundamentalRepresentation,CoeffReal> GparityWilsonImplD; // Double
|
||||||
|
|
||||||
//typedef GparityWilsonImpl<vComplex , FundamentalRepresentation,CoeffRealHalfComms> GparityWilsonImplRL; // Real.. whichever prec
|
|
||||||
//typedef GparityWilsonImpl<vComplexF, FundamentalRepresentation,CoeffRealHalfComms> GparityWilsonImplFH; // Float
|
|
||||||
//typedef GparityWilsonImpl<vComplexD, FundamentalRepresentation,CoeffRealHalfComms> GparityWilsonImplDF; // Double
|
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -176,4 +176,13 @@ typedef StaggeredImpl<vComplex, FundamentalRepresentation > StaggeredImplR; /
|
|||||||
typedef StaggeredImpl<vComplexF, FundamentalRepresentation > StaggeredImplF; // Float
|
typedef StaggeredImpl<vComplexF, FundamentalRepresentation > StaggeredImplF; // Float
|
||||||
typedef StaggeredImpl<vComplexD, FundamentalRepresentation > StaggeredImplD; // Double
|
typedef StaggeredImpl<vComplexD, FundamentalRepresentation > StaggeredImplD; // Double
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lexicographic staggered implementations
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef StaggeredImpl<sComplexF, FundamentalRepresentation > lexStaggeredImplF;
|
||||||
|
typedef StaggeredImpl<sComplexD, FundamentalRepresentation > lexStaggeredImplD;
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// End lexicographic staggered implementations
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
|
|
||||||
|
|
||||||
//Could make FaceGather a template param, but then behaviour is runtime not compile time
|
//Could make FaceGather a template param, but then behaviour is runtime not compile time
|
||||||
template<class _HCspinor,class _Hspinor,class _Spinor, class projector>
|
template<class _Hspinor,class _Spinor, class projector>
|
||||||
class WilsonCompressorTemplate : public FaceGatherSimple
|
class WilsonCompressorTemplate : public FaceGatherSimple
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -53,13 +53,11 @@ public:
|
|||||||
|
|
||||||
typedef _Spinor SiteSpinor;
|
typedef _Spinor SiteSpinor;
|
||||||
typedef _Hspinor SiteHalfSpinor;
|
typedef _Hspinor SiteHalfSpinor;
|
||||||
typedef _HCspinor SiteHalfCommSpinor;
|
typedef typename SiteHalfSpinor::vector_type vector_type;
|
||||||
typedef typename SiteHalfCommSpinor::vector_type vComplexLow;
|
constexpr static int Nw=sizeof(SiteHalfSpinor)/sizeof(vector_type);
|
||||||
typedef typename SiteHalfSpinor::vector_type vComplexHigh;
|
|
||||||
constexpr static int Nw=sizeof(SiteHalfSpinor)/sizeof(vComplexHigh);
|
|
||||||
|
|
||||||
accelerator_inline int CommDatumSize(void) const {
|
accelerator_inline int CommDatumSize(void) const {
|
||||||
return sizeof(SiteHalfCommSpinor);
|
return sizeof(SiteHalfSpinor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
@@ -159,7 +157,7 @@ public:
|
|||||||
spProj(result,in); \
|
spProj(result,in); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
template<typename HCS,typename HS,typename S> using Compressor = WilsonCompressorTemplate<HCS,HS,S,Projector>;
|
template<typename HS,typename S> using Compressor = WilsonCompressorTemplate<HS,S,Projector>;
|
||||||
|
|
||||||
DECLARE_PROJ(WilsonXpProjector,WilsonXpCompressor,spProjXp);
|
DECLARE_PROJ(WilsonXpProjector,WilsonXpCompressor,spProjXp);
|
||||||
DECLARE_PROJ(WilsonYpProjector,WilsonYpCompressor,spProjYp);
|
DECLARE_PROJ(WilsonYpProjector,WilsonYpCompressor,spProjYp);
|
||||||
@@ -188,7 +186,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<typename HCS,typename HS,typename S> using WilsonCompressor = WilsonCompressorTemplate<HCS,HS,S,WilsonProjector>;
|
template<typename HS,typename S> using WilsonCompressor = WilsonCompressorTemplate<HS,S,WilsonProjector>;
|
||||||
|
|
||||||
// Fast comms buffer manipulation which should inline right through (avoid direction
|
// Fast comms buffer manipulation which should inline right through (avoid direction
|
||||||
// dependent logic that prevents inlining
|
// dependent logic that prevents inlining
|
||||||
@@ -237,7 +235,6 @@ public:
|
|||||||
// Use types to select the write direction by directon compressor
|
// Use types to select the write direction by directon compressor
|
||||||
typedef typename compressor::SiteSpinor SiteSpinor;
|
typedef typename compressor::SiteSpinor SiteSpinor;
|
||||||
typedef typename compressor::SiteHalfSpinor SiteHalfSpinor;
|
typedef typename compressor::SiteHalfSpinor SiteHalfSpinor;
|
||||||
typedef typename compressor::SiteHalfCommSpinor SiteHalfCommSpinor;
|
|
||||||
|
|
||||||
this->_grid->StencilBarrier();
|
this->_grid->StencilBarrier();
|
||||||
|
|
||||||
@@ -245,14 +242,14 @@ public:
|
|||||||
|
|
||||||
this->u_comm_offset=0;
|
this->u_comm_offset=0;
|
||||||
|
|
||||||
WilsonXpCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> XpCompress;
|
WilsonXpCompressor<SiteHalfSpinor,SiteSpinor> XpCompress;
|
||||||
WilsonYpCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> YpCompress;
|
WilsonYpCompressor<SiteHalfSpinor,SiteSpinor> YpCompress;
|
||||||
WilsonZpCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> ZpCompress;
|
WilsonZpCompressor<SiteHalfSpinor,SiteSpinor> ZpCompress;
|
||||||
WilsonTpCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> TpCompress;
|
WilsonTpCompressor<SiteHalfSpinor,SiteSpinor> TpCompress;
|
||||||
WilsonXmCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> XmCompress;
|
WilsonXmCompressor<SiteHalfSpinor,SiteSpinor> XmCompress;
|
||||||
WilsonYmCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> YmCompress;
|
WilsonYmCompressor<SiteHalfSpinor,SiteSpinor> YmCompress;
|
||||||
WilsonZmCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> ZmCompress;
|
WilsonZmCompressor<SiteHalfSpinor,SiteSpinor> ZmCompress;
|
||||||
WilsonTmCompressor<SiteHalfCommSpinor,SiteHalfSpinor,SiteSpinor> TmCompress;
|
WilsonTmCompressor<SiteHalfSpinor,SiteSpinor> TmCompress;
|
||||||
|
|
||||||
int dag = compress.dag;
|
int dag = compress.dag;
|
||||||
int face_idx=0;
|
int face_idx=0;
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ public:
|
|||||||
static const bool isFundamental = Representation::isFundamental;
|
static const bool isFundamental = Representation::isFundamental;
|
||||||
static const bool LsVectorised=false;
|
static const bool LsVectorised=false;
|
||||||
static const bool isGparity=false;
|
static const bool isGparity=false;
|
||||||
static const int Nhcs = Options::Nhcs;
|
|
||||||
|
|
||||||
typedef PeriodicGaugeImpl<GaugeImplTypes<S, Dimension > > Gimpl;
|
typedef PeriodicGaugeImpl<GaugeImplTypes<S, Dimension > > Gimpl;
|
||||||
INHERIT_GIMPL_TYPES(Gimpl);
|
INHERIT_GIMPL_TYPES(Gimpl);
|
||||||
@@ -51,25 +50,22 @@ public:
|
|||||||
constexpr bool is_fundamental() const{return Dimension == Nc ? 1 : 0;}
|
constexpr bool is_fundamental() const{return Dimension == Nc ? 1 : 0;}
|
||||||
|
|
||||||
typedef typename Options::_Coeff_t Coeff_t;
|
typedef typename Options::_Coeff_t Coeff_t;
|
||||||
typedef typename Options::template PrecisionMapper<Simd>::LowerPrecVector SimdL;
|
|
||||||
|
|
||||||
template <typename vtype> using iImplSpinor = iScalar<iVector<iVector<vtype, Dimension>, Ns> >;
|
template <typename vtype> using iImplSpinor = iScalar<iVector<iVector<vtype, Dimension>, Ns> >;
|
||||||
template <typename vtype> using iImplPropagator = iScalar<iMatrix<iMatrix<vtype, Dimension>, Ns> >;
|
template <typename vtype> using iImplPropagator = iScalar<iMatrix<iMatrix<vtype, Dimension>, Ns> >;
|
||||||
template <typename vtype> using iImplHalfSpinor = iScalar<iVector<iVector<vtype, Dimension>, Nhs> >;
|
template <typename vtype> using iImplHalfSpinor = iScalar<iVector<iVector<vtype, Dimension>, Nhs> >;
|
||||||
template <typename vtype> using iImplHalfCommSpinor = iScalar<iVector<iVector<vtype, Dimension>, Nhcs> >;
|
|
||||||
template <typename vtype> using iImplDoubledGaugeField = iVector<iScalar<iMatrix<vtype, Dimension> >, Nds>;
|
template <typename vtype> using iImplDoubledGaugeField = iVector<iScalar<iMatrix<vtype, Dimension> >, Nds>;
|
||||||
|
|
||||||
typedef iImplSpinor<Simd> SiteSpinor;
|
typedef iImplSpinor<Simd> SiteSpinor;
|
||||||
typedef iImplPropagator<Simd> SitePropagator;
|
typedef iImplPropagator<Simd> SitePropagator;
|
||||||
typedef iImplHalfSpinor<Simd> SiteHalfSpinor;
|
typedef iImplHalfSpinor<Simd> SiteHalfSpinor;
|
||||||
typedef iImplHalfCommSpinor<SimdL> SiteHalfCommSpinor;
|
|
||||||
typedef iImplDoubledGaugeField<Simd> SiteDoubledGaugeField;
|
typedef iImplDoubledGaugeField<Simd> SiteDoubledGaugeField;
|
||||||
|
|
||||||
typedef Lattice<SiteSpinor> FermionField;
|
typedef Lattice<SiteSpinor> FermionField;
|
||||||
typedef Lattice<SitePropagator> PropagatorField;
|
typedef Lattice<SitePropagator> PropagatorField;
|
||||||
typedef Lattice<SiteDoubledGaugeField> DoubledGaugeField;
|
typedef Lattice<SiteDoubledGaugeField> DoubledGaugeField;
|
||||||
|
|
||||||
typedef WilsonCompressor<SiteHalfCommSpinor,SiteHalfSpinor, SiteSpinor> Compressor;
|
typedef WilsonCompressor<SiteHalfSpinor, SiteSpinor> Compressor;
|
||||||
typedef WilsonImplParams ImplParams;
|
typedef WilsonImplParams ImplParams;
|
||||||
typedef WilsonStencil<SiteSpinor, SiteHalfSpinor,ImplParams> StencilImpl;
|
typedef WilsonStencil<SiteSpinor, SiteHalfSpinor,ImplParams> StencilImpl;
|
||||||
typedef const typename StencilImpl::View_type StencilView;
|
typedef const typename StencilImpl::View_type StencilView;
|
||||||
@@ -242,12 +238,19 @@ public:
|
|||||||
typedef WilsonImpl<vComplex, FundamentalRepresentation, CoeffReal > WilsonImplR; // Real.. whichever prec
|
typedef WilsonImpl<vComplex, FundamentalRepresentation, CoeffReal > WilsonImplR; // Real.. whichever prec
|
||||||
typedef WilsonImpl<vComplexF, FundamentalRepresentation, CoeffReal > WilsonImplF; // Float
|
typedef WilsonImpl<vComplexF, FundamentalRepresentation, CoeffReal > WilsonImplF; // Float
|
||||||
typedef WilsonImpl<vComplexD, FundamentalRepresentation, CoeffReal > WilsonImplD; // Double
|
typedef WilsonImpl<vComplexD, FundamentalRepresentation, CoeffReal > WilsonImplD; // Double
|
||||||
typedef WilsonImpl<vComplexD2, FundamentalRepresentation, CoeffReal > WilsonImplD2; // Double
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lexicographic Wilson implementations
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef WilsonImpl<sComplexF, FundamentalRepresentation, CoeffReal > lexWilsonImplF;
|
||||||
|
typedef WilsonImpl<sComplexD, FundamentalRepresentation, CoeffReal > lexWilsonImplD;
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// End lexicographic Wilson implementations
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef WilsonImpl<vComplex, FundamentalRepresentation, CoeffComplex > ZWilsonImplR; // Real.. whichever prec
|
typedef WilsonImpl<vComplex, FundamentalRepresentation, CoeffComplex > ZWilsonImplR; // Real.. whichever prec
|
||||||
typedef WilsonImpl<vComplexF, FundamentalRepresentation, CoeffComplex > ZWilsonImplF; // Float
|
typedef WilsonImpl<vComplexF, FundamentalRepresentation, CoeffComplex > ZWilsonImplF; // Float
|
||||||
typedef WilsonImpl<vComplexD, FundamentalRepresentation, CoeffComplex > ZWilsonImplD; // Double
|
typedef WilsonImpl<vComplexD, FundamentalRepresentation, CoeffComplex > ZWilsonImplD; // Double
|
||||||
typedef WilsonImpl<vComplexD2, FundamentalRepresentation, CoeffComplex > ZWilsonImplD2; // Double
|
|
||||||
|
|
||||||
typedef WilsonImpl<vComplex, AdjointRepresentation, CoeffReal > WilsonAdjImplR; // Real.. whichever prec
|
typedef WilsonImpl<vComplex, AdjointRepresentation, CoeffReal > WilsonAdjImplR; // Real.. whichever prec
|
||||||
typedef WilsonImpl<vComplexF, AdjointRepresentation, CoeffReal > WilsonAdjImplF; // Float
|
typedef WilsonImpl<vComplexF, AdjointRepresentation, CoeffReal > WilsonAdjImplF; // Float
|
||||||
|
|||||||
@@ -684,7 +684,7 @@ void StaggeredKernels<Impl>::DhopSiteAsm(StencilView &st,
|
|||||||
#ifdef STAG_VEC5D
|
#ifdef STAG_VEC5D
|
||||||
// This is the single precision 5th direction vectorised kernel
|
// This is the single precision 5th direction vectorised kernel
|
||||||
#include <Grid/simd/Intel512single.h>
|
#include <Grid/simd/Intel512single.h>
|
||||||
template <> void StaggeredKernels<StaggeredVec5dImplF>::DhopSiteAsm(StencilView &st,
|
template <> inline void StaggeredKernels<StaggeredVec5dImplF>::DhopSiteAsm(StencilView &st,
|
||||||
DoubledGaugeFieldView &U,
|
DoubledGaugeFieldView &U,
|
||||||
DoubledGaugeFieldView &UUU,
|
DoubledGaugeFieldView &UUU,
|
||||||
SiteSpinor *buf, int sF,
|
SiteSpinor *buf, int sF,
|
||||||
@@ -739,7 +739,7 @@ template <> void StaggeredKernels<StaggeredVec5dImplF>::DhopSiteAsm(StencilView
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include <Grid/simd/Intel512double.h>
|
#include <Grid/simd/Intel512double.h>
|
||||||
template <> void StaggeredKernels<StaggeredVec5dImplD>::DhopSiteAsm(StencilView &st,
|
template <> inline void StaggeredKernels<StaggeredVec5dImplD>::DhopSiteAsm(StencilView &st,
|
||||||
DoubledGaugeFieldView &U,
|
DoubledGaugeFieldView &U,
|
||||||
DoubledGaugeFieldView &UUU,
|
DoubledGaugeFieldView &UUU,
|
||||||
SiteSpinor *buf, int sF,
|
SiteSpinor *buf, int sF,
|
||||||
@@ -825,7 +825,7 @@ template <> void StaggeredKernels<StaggeredVec5dImplD>::DhopSiteAsm(StencilView
|
|||||||
// This is the single precision 5th direction vectorised kernel
|
// This is the single precision 5th direction vectorised kernel
|
||||||
|
|
||||||
#include <Grid/simd/Intel512single.h>
|
#include <Grid/simd/Intel512single.h>
|
||||||
template <> void StaggeredKernels<StaggeredImplF>::DhopSiteAsm(StencilView &st,
|
template <> inline void StaggeredKernels<StaggeredImplF>::DhopSiteAsm(StencilView &st,
|
||||||
DoubledGaugeFieldView &U,
|
DoubledGaugeFieldView &U,
|
||||||
DoubledGaugeFieldView &UUU,
|
DoubledGaugeFieldView &UUU,
|
||||||
SiteSpinor *buf, int sF,
|
SiteSpinor *buf, int sF,
|
||||||
@@ -894,7 +894,7 @@ template <> void StaggeredKernels<StaggeredImplF>::DhopSiteAsm(StencilView &st,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include <Grid/simd/Intel512double.h>
|
#include <Grid/simd/Intel512double.h>
|
||||||
template <> void StaggeredKernels<StaggeredImplD>::DhopSiteAsm(StencilView &st,
|
template <> inline void StaggeredKernels<StaggeredImplD>::DhopSiteAsm(StencilView &st,
|
||||||
DoubledGaugeFieldView &U,
|
DoubledGaugeFieldView &U,
|
||||||
DoubledGaugeFieldView &UUU,
|
DoubledGaugeFieldView &UUU,
|
||||||
SiteSpinor *buf, int sF,
|
SiteSpinor *buf, int sF,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ directory
|
|||||||
#include <Grid/qcd/action/fermion/FermionCore.h>
|
#include <Grid/qcd/action/fermion/FermionCore.h>
|
||||||
#include <Grid/qcd/action/fermion/implementation/StaggeredKernelsImplementation.h>
|
#include <Grid/qcd/action/fermion/implementation/StaggeredKernelsImplementation.h>
|
||||||
#include <Grid/qcd/action/fermion/implementation/StaggeredKernelsHand.h>
|
#include <Grid/qcd/action/fermion/implementation/StaggeredKernelsHand.h>
|
||||||
|
#include <Grid/qcd/action/fermion/implementation/StaggeredKernelsAsm.h>
|
||||||
|
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,15 @@
|
|||||||
|
|
||||||
STAG_IMPL_LIST=" \
|
STAG_IMPL_LIST=" \
|
||||||
StaggeredImplF \
|
StaggeredImplF \
|
||||||
StaggeredImplD "
|
StaggeredImplD \
|
||||||
|
lexStaggeredImplF \
|
||||||
STAG5_IMPL_LIST=""
|
lexStaggeredImplD "
|
||||||
|
|
||||||
WILSON_IMPL_LIST=" \
|
WILSON_IMPL_LIST=" \
|
||||||
WilsonImplF \
|
WilsonImplF \
|
||||||
WilsonImplD \
|
WilsonImplD \
|
||||||
WilsonImplD2 \
|
lexWilsonImplF \
|
||||||
|
lexWilsonImplD \
|
||||||
SpWilsonImplF \
|
SpWilsonImplF \
|
||||||
SpWilsonImplD \
|
SpWilsonImplD \
|
||||||
WilsonAdjImplF \
|
WilsonAdjImplF \
|
||||||
@@ -32,9 +33,10 @@ COMPACT_WILSON_IMPL_LIST=" \
|
|||||||
DWF_IMPL_LIST=" \
|
DWF_IMPL_LIST=" \
|
||||||
WilsonImplF \
|
WilsonImplF \
|
||||||
WilsonImplD \
|
WilsonImplD \
|
||||||
WilsonImplD2 \
|
lexWilsonImplF \
|
||||||
|
lexWilsonImplD \
|
||||||
ZWilsonImplF \
|
ZWilsonImplF \
|
||||||
ZWilsonImplD2 "
|
ZWilsonImplD "
|
||||||
|
|
||||||
GDWF_IMPL_LIST=" \
|
GDWF_IMPL_LIST=" \
|
||||||
GparityWilsonImplF \
|
GparityWilsonImplF \
|
||||||
@@ -109,8 +111,3 @@ do
|
|||||||
ln -f -s ../$f.cc.master $impl/$f$impl.cc
|
ln -f -s ../$f.cc.master $impl/$f$impl.cc
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
CC_LIST=" \
|
|
||||||
ImprovedStaggeredFermion5DInstantiation \
|
|
||||||
StaggeredKernelsInstantiation "
|
|
||||||
|
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../ImprovedStaggeredFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../ImprovedStaggeredFermionInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../NaiveStaggeredFermionInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../StaggeredKernelsInstantiation.cc.master
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#define IMPLEMENTATION lexStaggeredImplD
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../ImprovedStaggeredFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../ImprovedStaggeredFermionInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../NaiveStaggeredFermionInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../StaggeredKernelsInstantiation.cc.master
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#define IMPLEMENTATION lexStaggeredImplF
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../CayleyFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../ContinuedFractionFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../DomainWallEOFAFermionInstantiation.cc.master
|
||||||
Grid/qcd/action/fermion/instantiation/lexWilsonImplD/MobiusEOFAFermionInstantiationlexWilsonImplD.cc
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../MobiusEOFAFermionInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../PartialFractionFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonCloverFermionInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonFermion5DInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonFermionInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonKernelsInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonTMFermionInstantiation.cc.master
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#define IMPLEMENTATION lexWilsonImplD
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../CayleyFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../ContinuedFractionFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../DomainWallEOFAFermionInstantiation.cc.master
|
||||||
Grid/qcd/action/fermion/instantiation/lexWilsonImplF/MobiusEOFAFermionInstantiationlexWilsonImplF.cc
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../MobiusEOFAFermionInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../PartialFractionFermion5DInstantiation.cc.master
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonCloverFermionInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonFermion5DInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonFermionInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonKernelsInstantiation.cc.master
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../WilsonTMFermionInstantiation.cc.master
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#define IMPLEMENTATION lexWilsonImplF
|
||||||
@@ -60,8 +60,10 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef typename Impl::SiteField SiteField; \
|
typedef typename Impl::SiteField SiteField; \
|
||||||
typedef typename Impl::Field Field;
|
typedef typename Impl::Field Field;
|
||||||
|
|
||||||
// hardcodes the exponential approximation in the template
|
// Order of the exponential approximation
|
||||||
template <class S, int Nrepresentation = Nc, int Nexp = 12, class Group = SU<Nc> > class GaugeImplTypes {
|
const int NexpDefault = 12;
|
||||||
|
|
||||||
|
template <class S, int Nrepresentation = Nc, int Nexp = NexpDefault, class Group = SU<Nc> > class GaugeImplTypes {
|
||||||
public:
|
public:
|
||||||
typedef S Simd;
|
typedef S Simd;
|
||||||
typedef typename Simd::scalar_type scalar_type;
|
typedef typename Simd::scalar_type scalar_type;
|
||||||
@@ -188,14 +190,29 @@ typedef GaugeImplTypes<vComplex, Nc> GimplTypesR;
|
|||||||
typedef GaugeImplTypes<vComplexF, Nc> GimplTypesF;
|
typedef GaugeImplTypes<vComplexF, Nc> GimplTypesF;
|
||||||
typedef GaugeImplTypes<vComplexD, Nc> GimplTypesD;
|
typedef GaugeImplTypes<vComplexD, Nc> GimplTypesD;
|
||||||
|
|
||||||
typedef GaugeImplTypes<vComplex, Nc, 12, Sp<Nc> > SpGimplTypesR;
|
typedef GaugeImplTypes<vComplex, Nc, NexpDefault, Sp<Nc> > SpGimplTypesR;
|
||||||
typedef GaugeImplTypes<vComplexF, Nc, 12, Sp<Nc> > SpGimplTypesF;
|
typedef GaugeImplTypes<vComplexF, Nc, NexpDefault, Sp<Nc> > SpGimplTypesF;
|
||||||
typedef GaugeImplTypes<vComplexD, Nc, 12, Sp<Nc> > SpGimplTypesD;
|
typedef GaugeImplTypes<vComplexD, Nc, NexpDefault, Sp<Nc> > SpGimplTypesD;
|
||||||
|
|
||||||
typedef GaugeImplTypes<vComplex, SU<Nc>::AdjointDimension> GimplAdjointTypesR;
|
typedef GaugeImplTypes<vComplex, SU<Nc>::AdjointDimension> GimplAdjointTypesR;
|
||||||
typedef GaugeImplTypes<vComplexF, SU<Nc>::AdjointDimension> GimplAdjointTypesF;
|
typedef GaugeImplTypes<vComplexF, SU<Nc>::AdjointDimension> GimplAdjointTypesF;
|
||||||
typedef GaugeImplTypes<vComplexD, SU<Nc>::AdjointDimension> GimplAdjointTypesD;
|
typedef GaugeImplTypes<vComplexD, SU<Nc>::AdjointDimension> GimplAdjointTypesD;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lexicographic gauge implementation types
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef GaugeImplTypes<sComplexF, Nc> lexGimplTypesF;
|
||||||
|
typedef GaugeImplTypes<sComplexD, Nc> lexGimplTypesD;
|
||||||
|
|
||||||
|
typedef GaugeImplTypes<sComplexF, Nc, NexpDefault, Sp<Nc> > lexSpGimplTypesF;
|
||||||
|
typedef GaugeImplTypes<sComplexD, Nc, NexpDefault, Sp<Nc> > lexSpGimplTypesD;
|
||||||
|
|
||||||
|
typedef GaugeImplTypes<sComplexF, SU<Nc>::AdjointDimension> lexGimplAdjointTypesF;
|
||||||
|
typedef GaugeImplTypes<sComplexD, SU<Nc>::AdjointDimension> lexGimplAdjointTypesD;
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// End lexicographic gauge implementation types
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -197,6 +197,24 @@ typedef PeriodicGaugeImpl<SpGimplTypesR> SpPeriodicGimplR; // Real.. whichever p
|
|||||||
typedef PeriodicGaugeImpl<SpGimplTypesF> SpPeriodicGimplF; // Float
|
typedef PeriodicGaugeImpl<SpGimplTypesF> SpPeriodicGimplF; // Float
|
||||||
typedef PeriodicGaugeImpl<SpGimplTypesD> SpPeriodicGimplD; // Double
|
typedef PeriodicGaugeImpl<SpGimplTypesD> SpPeriodicGimplD; // Double
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lexicographic gauge implementations
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef PeriodicGaugeImpl<lexGimplTypesF> lexPeriodicGimplF;
|
||||||
|
typedef PeriodicGaugeImpl<lexGimplTypesD> lexPeriodicGimplD;
|
||||||
|
|
||||||
|
typedef PeriodicGaugeImpl<lexGimplAdjointTypesF> lexPeriodicGimplAdjF;
|
||||||
|
typedef PeriodicGaugeImpl<lexGimplAdjointTypesD> lexPeriodicGimplAdjD;
|
||||||
|
|
||||||
|
typedef ConjugateGaugeImpl<lexGimplTypesF> lexConjugateGimplF;
|
||||||
|
typedef ConjugateGaugeImpl<lexGimplTypesD> lexConjugateGimplD;
|
||||||
|
|
||||||
|
typedef PeriodicGaugeImpl<lexSpGimplTypesF> lexSpPeriodicGimplF;
|
||||||
|
typedef PeriodicGaugeImpl<lexSpGimplTypesD> lexSpPeriodicGimplD;
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// End lexicographic gauge implementations
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/qcd/action/pseudofermion/TwoFlavourBosonPseudoFermion.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Two flavour BOSON (wrong-sign) pseudofermion for any FermionOperator B:
|
||||||
|
//
|
||||||
|
// S2 = chi^dag Bdag B chi = |B chi|^2
|
||||||
|
//
|
||||||
|
// integral ==> det( Bdag B )^-1 = |det B|^-2
|
||||||
|
//
|
||||||
|
// A compensator monomial: supplies an INVERSE determinant with NO solve in
|
||||||
|
// the force or the action -- both are matrix multiplies. The only solve is
|
||||||
|
// the heatbath chi = B^-1 eta, once per trajectory (for B = the
|
||||||
|
// Pauli-Villars operator this is a mass-one solve, trivially cheap).
|
||||||
|
//
|
||||||
|
// Primary use: two instances with B = PV cancel the |det PV|^2 excess of
|
||||||
|
// TwoFlavourPVdagMPseudoFermionAction down to the DWF quotient
|
||||||
|
// |det M|^2/|det PV|^2 (two unsquared instances rather than one squared
|
||||||
|
// kernel: first powers of PV in the force, milder). Being generic in B it
|
||||||
|
// also serves Hasenbusch-chain compensation at intermediate masses, or any
|
||||||
|
// future inverse-det bookkeeping. (Sibling of the domain-decomposed boson
|
||||||
|
// in DomainDecomposedBoundaryTwoFlavourBosonPseudoFermion.h, without the
|
||||||
|
// boundary machinery.)
|
||||||
|
//
|
||||||
|
// Heatbath exact by construction: S2 after refresh = |B B^-1 eta|^2 = |eta|^2.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Impl>
|
||||||
|
class TwoFlavourBosonPseudoFermionAction : public Action<typename Impl::GaugeField> {
|
||||||
|
public:
|
||||||
|
INHERIT_IMPL_TYPES(Impl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FermionOperator<Impl> & BOp; // the operator whose |det|^-2 is supplied
|
||||||
|
|
||||||
|
LinearFunction<FermionField> &HeatbathSolver; // b -> B^-1 b (heatbath only)
|
||||||
|
|
||||||
|
FermionField Chi; // the pseudo fermion field for this trajectory
|
||||||
|
|
||||||
|
public:
|
||||||
|
TwoFlavourBosonPseudoFermionAction(FermionOperator<Impl> &_BOp,
|
||||||
|
LinearFunction<FermionField> & HS
|
||||||
|
) : BOp(_BOp),
|
||||||
|
HeatbathSolver(HS),
|
||||||
|
Chi(_BOp.FermionGrid())
|
||||||
|
{};
|
||||||
|
|
||||||
|
virtual std::string action_name(){return "TwoFlavourBosonPseudoFermionAction";}
|
||||||
|
|
||||||
|
virtual std::string LogParameters(){
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] has no parameters" << std::endl;
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
|
// P(chi) = e^{- chi^dag BdagB chi} ; chi = B^-1 eta ; P(eta) = e^{-eta^dag eta}
|
||||||
|
// e^{-x^2/2 sig^2} => sig^2 = 0.5 ; eta enters with width 1/sqrt(2).
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
FermionField eta(BOp.FermionGrid());
|
||||||
|
gaussian(pRNG,eta);
|
||||||
|
eta = eta * scale;
|
||||||
|
refresh(U,eta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic-noise variant (test hook):
|
||||||
|
// after this, S(U) == norm2(eta) exactly (to solver tolerance).
|
||||||
|
void refresh(const GaugeField &U, const FermionField &eta) {
|
||||||
|
BOp.ImportGauge(U);
|
||||||
|
Chi = Zero();
|
||||||
|
HeatbathSolver(eta,Chi); // Chi = B^-1 eta : the ONLY solve
|
||||||
|
std::cout << GridLogMessage << action_name() << " refresh |Chi|^2 = "<< norm2(Chi)<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// S2 = |B chi|^2 -- matrix multiply only
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual RealD S(const GaugeField &U) {
|
||||||
|
BOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField w(BOp.FermionGrid());
|
||||||
|
BOp.M(Chi,w); // w = B chi
|
||||||
|
RealD action = norm2(w);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// dS2 = chi^dag dBdag w + w^dag dB chi , w = B chi
|
||||||
|
// NO solves.
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual void deriv(const GaugeField &U,GaugeField & dSdU) {
|
||||||
|
BOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField w(BOp.FermionGrid());
|
||||||
|
GaugeField force(BOp.GaugeGrid());
|
||||||
|
|
||||||
|
BOp.M(Chi,w); // w = B chi
|
||||||
|
|
||||||
|
BOp.MDeriv(force, Chi, w, DaggerYes); dSdU = force;
|
||||||
|
BOp.MDeriv(force, w, Chi, DaggerNo ); dSdU = dSdU+force;
|
||||||
|
|
||||||
|
dSdU *= -1.0; // Grid action sign convention (cf TwoFlavourRatio.h)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/qcd/action/pseudofermion/TwoFlavourPVdagMPseudoFermion.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Two flavour pseudofermion on the COMPOSITE operator F = PVdag M :
|
||||||
|
//
|
||||||
|
// S1 = phi^dag (Fdag F)^-1 phi
|
||||||
|
//
|
||||||
|
// integral ==> det( Mdag PV PVdag M ) = |det M|^2 |det PV|^2
|
||||||
|
//
|
||||||
|
// i.e. the target two-flavour |det M|^2 TIMES an excess |det PV|^2, to be
|
||||||
|
// cancelled by compensator monomials (two TwoFlavourBosonPseudoFermionAction
|
||||||
|
// instances on PV, each contributing |det PV|^-2, net |det PV|^-4; together
|
||||||
|
// with this action's |det PV|^2 the ensemble carries |det M|^2/|det PV|^2 --
|
||||||
|
// the standard DWF quotient).
|
||||||
|
//
|
||||||
|
// Why this shape: F = PVdag M is exactly the operator the non-Hermitian
|
||||||
|
// multigrid coarsens, so its cycles precondition (Fdag F) natively. The
|
||||||
|
// outer solve is CG on a Hermitian positive definite system -- the
|
||||||
|
// non-normality is quarantined inside the preconditioner. One solve per
|
||||||
|
// force evaluation; all other force ingredients are matrix multiplies.
|
||||||
|
//
|
||||||
|
// Heatbath is exact by OPERATOR ALGEBRA (no wall/projection identity):
|
||||||
|
// refresh: phi = Fdag eta ==> S1 = eta^dag F (Fdag F)^-1 Fdag eta
|
||||||
|
// = |eta|^2 (to solver tol)
|
||||||
|
//
|
||||||
|
// Hasenbusch: nothing here requires PVOp to have mass one. Any
|
||||||
|
// (heavier,lighter) pair F(m1,m2) = D^dag(m1) D(m2) works, each rung
|
||||||
|
// coarsenable by the same machinery; compensate intermediate-mass excess
|
||||||
|
// dets with boson monomials on the heavier operator.
|
||||||
|
//
|
||||||
|
// Solver slots map b -> (Fdag F)^-1 b (full grid, zero guess imposed
|
||||||
|
// internally). The class is agnostic to the implementation: plain CG on
|
||||||
|
// the normal equations for testing; sequential MG solves of Fdag and F, or
|
||||||
|
// preconditioned CG with a frozen-cycle G Gdag preconditioner in production.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Impl>
|
||||||
|
class TwoFlavourPVdagMPseudoFermionAction : public Action<typename Impl::GaugeField> {
|
||||||
|
public:
|
||||||
|
INHERIT_IMPL_TYPES(Impl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FermionOperator<Impl> & PVOp; // the heavier / Pauli-Villars operator
|
||||||
|
FermionOperator<Impl> & MOp; // the lighter operator
|
||||||
|
|
||||||
|
LinearFunction<FermionField> &DerivSolver; // b -> (FdagF)^-1 b, MD tolerance
|
||||||
|
LinearFunction<FermionField> &ActionSolver; // b -> (FdagF)^-1 b, accept/reject tolerance
|
||||||
|
|
||||||
|
FermionField Phi; // the pseudo fermion field for this trajectory
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// F = PVdag M and Fdag = Mdag PV
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void Fapply(const FermionField &in, FermionField &out) {
|
||||||
|
FermionField tmp(MOp.FermionGrid());
|
||||||
|
MOp.M(in,tmp);
|
||||||
|
PVOp.Mdag(tmp,out);
|
||||||
|
}
|
||||||
|
void FdagApply(const FermionField &in, FermionField &out) {
|
||||||
|
FermionField tmp(MOp.FermionGrid());
|
||||||
|
PVOp.M(in,tmp);
|
||||||
|
MOp.Mdag(tmp,out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
TwoFlavourPVdagMPseudoFermionAction(FermionOperator<Impl> &_PVOp,
|
||||||
|
FermionOperator<Impl> &_MOp,
|
||||||
|
LinearFunction<FermionField> & DS,
|
||||||
|
LinearFunction<FermionField> & AS
|
||||||
|
) : PVOp(_PVOp),
|
||||||
|
MOp(_MOp),
|
||||||
|
DerivSolver(DS),
|
||||||
|
ActionSolver(AS),
|
||||||
|
Phi(_MOp.FermionGrid())
|
||||||
|
{};
|
||||||
|
|
||||||
|
virtual std::string action_name(){return "TwoFlavourPVdagMPseudoFermionAction";}
|
||||||
|
|
||||||
|
virtual std::string LogParameters(){
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] has no parameters" << std::endl;
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
|
// P(phi) = e^{- phi^dag (FdagF)^-1 phi} ; phi = Fdag eta ; P(eta) = e^{-eta^dag eta}
|
||||||
|
// e^{-x^2/2 sig^2} => sig^2 = 0.5 ; eta enters with width 1/sqrt(2).
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
FermionField eta(MOp.FermionGrid());
|
||||||
|
gaussian(pRNG,eta);
|
||||||
|
eta = eta * scale;
|
||||||
|
refresh(U,eta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic-noise variant (test hook, TwoFlavourEvenOddRatio idiom):
|
||||||
|
// after this, S(U) == norm2(eta) exactly (to solver tolerance).
|
||||||
|
void refresh(const GaugeField &U, const FermionField &eta) {
|
||||||
|
PVOp.ImportGauge(U);
|
||||||
|
MOp.ImportGauge(U);
|
||||||
|
FdagApply(eta,Phi); // NO solve: heatbath is two matmuls
|
||||||
|
std::cout << GridLogMessage << action_name() << " refresh |Phi|^2 = "<< norm2(Phi)<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// S1 = phi^dag (FdagF)^-1 phi
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual RealD S(const GaugeField &U) {
|
||||||
|
PVOp.ImportGauge(U);
|
||||||
|
MOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField X(MOp.FermionGrid());
|
||||||
|
X = Zero();
|
||||||
|
ActionSolver(Phi,X); // X = (FdagF)^-1 phi
|
||||||
|
|
||||||
|
RealD action = real(innerProduct(Phi,X)); // Hermitian positive kernel
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// dS1 = - X^dag [ dFdag F + Fdag dF ] X , X = (FdagF)^-1 phi, Y = F X
|
||||||
|
//
|
||||||
|
// dF = dPVdag M + PVdag dM ==> with A = M X, B = PV Y :
|
||||||
|
//
|
||||||
|
// dS1 = - X^dag dMdag B - B^dag dM X - A^dag dPV Y - Y^dag dPVdag A
|
||||||
|
//
|
||||||
|
// ONE solve; A,Y,B by matrix multiply (Y = PVdag A reuses A).
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual void deriv(const GaugeField &U,GaugeField & dSdU) {
|
||||||
|
PVOp.ImportGauge(U);
|
||||||
|
MOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField X(MOp.FermionGrid());
|
||||||
|
FermionField Y(MOp.FermionGrid());
|
||||||
|
FermionField A(MOp.FermionGrid());
|
||||||
|
FermionField B(MOp.FermionGrid());
|
||||||
|
|
||||||
|
GaugeField force(MOp.GaugeGrid());
|
||||||
|
|
||||||
|
X = Zero();
|
||||||
|
DerivSolver(Phi,X); // X = (FdagF)^-1 phi
|
||||||
|
MOp.M(X,A); // A = M X
|
||||||
|
PVOp.Mdag(A,Y); // Y = PVdag A = F X
|
||||||
|
PVOp.M(Y,B); // B = PV Y
|
||||||
|
|
||||||
|
// dS1 = -( X^dag dMdag B + B^dag dM X + A^dag dPV Y + Y^dag dPVdag A )
|
||||||
|
MOp.MDeriv (force, X, B, DaggerYes); dSdU = -force;
|
||||||
|
MOp.MDeriv (force, B, X, DaggerNo ); dSdU = dSdU -force;
|
||||||
|
PVOp.MDeriv(force, A, Y, DaggerNo ); dSdU = dSdU -force;
|
||||||
|
PVOp.MDeriv(force, Y, A, DaggerYes); dSdU = dSdU -force;
|
||||||
|
|
||||||
|
dSdU *= -1.0; // Grid action sign convention (cf TwoFlavourRatio.h)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/qcd/action/pseudofermion/TwoFlavourRatio4DPseudoFermion.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Two flavour ratio with FOUR dimensional pseudofermion, UNpreconditioned
|
||||||
|
// (full grid) solves.
|
||||||
|
//
|
||||||
|
// Companion to TwoFlavourRatioEO4DPseudoFermion.h but with the solver
|
||||||
|
// plumbing exposed as LinearFunction<FermionField> objects that already
|
||||||
|
// know their operator -- the natural interface for the non-Hermitian
|
||||||
|
// multigrid GCR stack (PVdagM), which solves M and Mdag DIRECTLY rather
|
||||||
|
// than through SchurRedBlack normal equations.
|
||||||
|
//
|
||||||
|
// Why: with 5D pseudofermions the squared-operator formulation hands
|
||||||
|
// normal-equation solvers (MdagM)^-1 phi AND Mdag^-1 phi from ONE Krylov
|
||||||
|
// space; a direct solver must solve twice, halving its per-solve gain.
|
||||||
|
// The 4D pseudofermion action needs one M^-1 and one M^-dag solve per
|
||||||
|
// force evaluation FOR BOTH solver families, so the direct-solver gain
|
||||||
|
// carries through undiluted. In addition phi4 is Ls-agnostic, so the
|
||||||
|
// force can be evaluated with a reduced-Ls operator pair while the
|
||||||
|
// accept/reject uses full Ls (inexact force, exact action).
|
||||||
|
//
|
||||||
|
// Solver slots (all full-grid 5D LinearFunctions, solution overwritten,
|
||||||
|
// zero guess imposed internally):
|
||||||
|
// DerivMinvSolver : x = M^-1 b (DenOp)
|
||||||
|
// DerivMdagInvSolver : x = M^-dag b (DenOp). For G5R5-hermitian
|
||||||
|
// actions this may be implemented by the caller as
|
||||||
|
// G5R5 . DerivMinvSolver . G5R5 -- no adjoint
|
||||||
|
// multigrid needed.
|
||||||
|
// ActionMinvSolver : x = M^-1 b (DenOp, accept/reject tolerance)
|
||||||
|
// HeatbathVinvSolver : x = V^-1 b (NumOp)
|
||||||
|
//
|
||||||
|
// 4D <-> 5D wall maps: the action is S = | P (M^-1 V) Pdag phi4 |^2 where
|
||||||
|
// (P,Pdag) MUST be a mutually adjoint pair for S and deriv to be
|
||||||
|
// consistent. Two candidate conventions, selected by solution_walls:
|
||||||
|
// true : P = P_- psi(0) + P_+ psi(Ls-1) (solution walls, matches
|
||||||
|
// ExportPhysicalFermionSolution) and Pdag its literal adjoint.
|
||||||
|
// false : P = P_+ psi(0) + P_- psi(Ls-1) (source walls, Pdag matches
|
||||||
|
// ImportUnphysicalFermion).
|
||||||
|
// The heatbath is exact iff [P M^-1 V Pdag][P V^-1 M Pdag] = 1 (the 4D
|
||||||
|
// effective-operator composition identity); which convention satisfies it
|
||||||
|
// is settled numerically by the refresh test S == 0.5*|eta4|^2 exactly.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Impl>
|
||||||
|
class TwoFlavourRatio4DPseudoFermionAction : public Action<typename Impl::GaugeField> {
|
||||||
|
public:
|
||||||
|
INHERIT_IMPL_TYPES(Impl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef FermionOperator<Impl> FermOp;
|
||||||
|
FermionOperator<Impl> & NumOp;// the basic operator (V)
|
||||||
|
FermionOperator<Impl> & DenOp;// the basic operator (M)
|
||||||
|
|
||||||
|
LinearFunction<FermionField> &DerivMinvSolver;
|
||||||
|
LinearFunction<FermionField> &DerivMdagInvSolver;
|
||||||
|
LinearFunction<FermionField> &ActionMinvSolver;
|
||||||
|
LinearFunction<FermionField> &HeatbathVinvSolver;
|
||||||
|
|
||||||
|
FermionField phi4; // the pseudo fermion field for this trajectory
|
||||||
|
|
||||||
|
int solution_walls; // wall convention for the (P,Pdag) pair; see header
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// The mutually adjoint 4D <-> 5D pair.
|
||||||
|
// Wall4D : q4 = P psi5 (extract)
|
||||||
|
// Wall4DAdj : psi5 = Pdag q4 (insert; literal adjoint of Wall4D)
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void Wall4D(const FermionField &psi5, FermionField &q4)
|
||||||
|
{
|
||||||
|
int Ls = NumOp.FermionGrid()->_fdimensions[0];
|
||||||
|
FermionField tmp(NumOp.FermionGrid());
|
||||||
|
if ( solution_walls ) {
|
||||||
|
// q4 = P_- psi(0) + P_+ psi(Ls-1)
|
||||||
|
axpby_ssp_pminus(tmp, 0., psi5, 1., psi5, 0, 0);
|
||||||
|
axpby_ssp_pplus (tmp, 1., tmp , 1., psi5, 0, Ls-1);
|
||||||
|
} else {
|
||||||
|
// q4 = P_+ psi(0) + P_- psi(Ls-1)
|
||||||
|
axpby_ssp_pplus (tmp, 0., psi5, 1., psi5, 0, 0);
|
||||||
|
axpby_ssp_pminus(tmp, 1., tmp , 1., psi5, 0, Ls-1);
|
||||||
|
}
|
||||||
|
ExtractSlice(q4, tmp, 0, 0);
|
||||||
|
}
|
||||||
|
void Wall4DAdj(const FermionField &q4, FermionField &psi5)
|
||||||
|
{
|
||||||
|
int Ls = NumOp.FermionGrid()->_fdimensions[0];
|
||||||
|
FermionField tmp(NumOp.FermionGrid());
|
||||||
|
tmp = Zero();
|
||||||
|
InsertSlice(q4, tmp, 0 , 0);
|
||||||
|
InsertSlice(q4, tmp, Ls-1, 0);
|
||||||
|
if ( solution_walls ) {
|
||||||
|
// psi(0) = P_- q4 ; psi(Ls-1) = P_+ q4
|
||||||
|
axpby_ssp_pminus(tmp, 0., tmp, 1., tmp, 0 , 0);
|
||||||
|
axpby_ssp_pplus (tmp, 0., tmp, 1., tmp, Ls-1, Ls-1);
|
||||||
|
} else {
|
||||||
|
// psi(0) = P_+ q4 ; psi(Ls-1) = P_- q4
|
||||||
|
axpby_ssp_pplus (tmp, 0., tmp, 1., tmp, 0 , 0);
|
||||||
|
axpby_ssp_pminus(tmp, 0., tmp, 1., tmp, Ls-1, Ls-1);
|
||||||
|
}
|
||||||
|
psi5 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
TwoFlavourRatio4DPseudoFermionAction(FermionOperator<Impl> &_NumOp,
|
||||||
|
FermionOperator<Impl> &_DenOp,
|
||||||
|
LinearFunction<FermionField> & DMS,
|
||||||
|
LinearFunction<FermionField> & DMDS,
|
||||||
|
LinearFunction<FermionField> & AMS,
|
||||||
|
LinearFunction<FermionField> & HVS,
|
||||||
|
int _solution_walls = 1
|
||||||
|
) : NumOp(_NumOp),
|
||||||
|
DenOp(_DenOp),
|
||||||
|
DerivMinvSolver(DMS),
|
||||||
|
DerivMdagInvSolver(DMDS),
|
||||||
|
ActionMinvSolver(AMS),
|
||||||
|
HeatbathVinvSolver(HVS),
|
||||||
|
phi4(_NumOp.GaugeGrid()),
|
||||||
|
solution_walls(_solution_walls)
|
||||||
|
{};
|
||||||
|
|
||||||
|
virtual std::string action_name(){return "TwoFlavourRatio4DPseudoFermionAction";}
|
||||||
|
|
||||||
|
virtual std::string LogParameters(){
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] solution_walls " << solution_walls << std::endl;
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
|
|
||||||
|
// P(phi4) = e^{- phi4^dag Beff^dag Beff phi4} ; Beff = P M^-1 V Pdag
|
||||||
|
//
|
||||||
|
// NumOp == V
|
||||||
|
// DenOp == M
|
||||||
|
//
|
||||||
|
// Take phi4 = P V^-1 M Pdag eta4 ( = Beff^-1 eta4 by the composition
|
||||||
|
// identity; verified numerically by S == 0.5 |eta4|^2 after refresh )
|
||||||
|
//
|
||||||
|
// P(eta) = e^{- eta^dag eta} ; e^{-x^2/2 sig^2} => sig^2 = 0.5
|
||||||
|
// so eta enters with width 1/sqrt(2).
|
||||||
|
//
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
|
||||||
|
FermionField eta4(NumOp.GaugeGrid());
|
||||||
|
FermionField eta5(NumOp.FermionGrid());
|
||||||
|
FermionField tmp (NumOp.FermionGrid());
|
||||||
|
FermionField phi5(NumOp.FermionGrid());
|
||||||
|
|
||||||
|
gaussian(pRNG,eta4);
|
||||||
|
|
||||||
|
NumOp.ImportGauge(U);
|
||||||
|
DenOp.ImportGauge(U);
|
||||||
|
|
||||||
|
Wall4DAdj(eta4,eta5); // eta5 = Pdag eta4
|
||||||
|
DenOp.M(eta5,tmp); // tmp = M eta5
|
||||||
|
phi5 = Zero();
|
||||||
|
HeatbathVinvSolver(tmp,phi5); // phi5 = V^-1 M eta5
|
||||||
|
Wall4D(phi5,phi4); // phi4 = P phi5
|
||||||
|
phi4 = phi4*scale;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "4d pf (non-EO) refresh "<< norm2(phi4)<<"\n";
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// S = phi4^dag (Pdag^dag V^dag M^-dag P^dag) (P M^-1 V Pdag) phi4
|
||||||
|
// = | P M^-1 V Pdag phi4 |^2
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual RealD S(const GaugeField &U) {
|
||||||
|
|
||||||
|
NumOp.ImportGauge(U);
|
||||||
|
DenOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField Y4 (NumOp.GaugeGrid());
|
||||||
|
FermionField phi5(NumOp.FermionGrid());
|
||||||
|
FermionField X (NumOp.FermionGrid());
|
||||||
|
FermionField Y (NumOp.FermionGrid());
|
||||||
|
|
||||||
|
Wall4DAdj(phi4,phi5); // phi5 = Pdag phi4
|
||||||
|
NumOp.M(phi5,X); // X = V phi5
|
||||||
|
Y = Zero();
|
||||||
|
ActionMinvSolver(X,Y); // Y = M^-1 V phi5
|
||||||
|
Wall4D(Y,Y4); // Y4 = P Y
|
||||||
|
|
||||||
|
RealD action = norm2(Y4);
|
||||||
|
|
||||||
|
return action;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// dS/du = 2 Re [ (M^-dag Pdag w4)^dag dV Pdag phi4 ]
|
||||||
|
// - 2 Re [ (M^-dag Pdag w4)^dag dM (M^-1 V Pdag phi4) ]
|
||||||
|
// with w4 = P M^-1 V Pdag phi4.
|
||||||
|
// Two first-power solves: one M^-1, one M^-dag.
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual void deriv(const GaugeField &U,GaugeField & dSdU) {
|
||||||
|
|
||||||
|
NumOp.ImportGauge(U);
|
||||||
|
DenOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField phi5 (NumOp.FermionGrid());
|
||||||
|
FermionField Vphi (NumOp.FermionGrid());
|
||||||
|
FermionField MinvVphi (NumOp.FermionGrid());
|
||||||
|
FermionField w4 (NumOp.GaugeGrid());
|
||||||
|
FermionField Y (NumOp.FermionGrid());
|
||||||
|
FermionField MdagInvPdagW (NumOp.FermionGrid());
|
||||||
|
|
||||||
|
GaugeField force(NumOp.GaugeGrid());
|
||||||
|
|
||||||
|
Wall4DAdj(phi4,phi5); // phi5 = Pdag phi4
|
||||||
|
NumOp.M(phi5,Vphi); // Vphi = V phi5
|
||||||
|
MinvVphi = Zero();
|
||||||
|
DerivMinvSolver(Vphi,MinvVphi); // MinvVphi = M^-1 V phi5
|
||||||
|
std::cout << GridLogMessage << "4d pf (non-EO) deriv solve "<< norm2(MinvVphi)<<"\n";
|
||||||
|
|
||||||
|
// Project onto the physical 4D subspace and back: Y = Pdag P MinvVphi.
|
||||||
|
// Pdag here MUST be the literal adjoint of the P used in S, else the
|
||||||
|
// force is inconsistent with the action.
|
||||||
|
Wall4D(MinvVphi,w4); // w4 = P MinvVphi
|
||||||
|
Wall4DAdj(w4,Y); // Y = Pdag w4
|
||||||
|
|
||||||
|
MdagInvPdagW = Zero();
|
||||||
|
DerivMdagInvSolver(Y,MdagInvPdagW); // = M^-dag Pdag w4 (adjoint solve)
|
||||||
|
std::cout << GridLogMessage << "4d pf (non-EO) deriv solve dag "<< norm2(MdagInvPdagW)<<"\n";
|
||||||
|
|
||||||
|
// phi^dag (Pdag' Vdag Mdag^-1 P') (dV) Pdag phi + h.c.
|
||||||
|
NumOp.MDeriv(force, MdagInvPdagW, phi5, DaggerNo ); dSdU=force;
|
||||||
|
NumOp.MDeriv(force, phi5, MdagInvPdagW, DaggerYes); dSdU=dSdU+force;
|
||||||
|
|
||||||
|
// - phi^dag ( ... Mdag^-1 ) dM ( M^-1 V ... ) phi + h.c.
|
||||||
|
DenOp.MDeriv(force, MdagInvPdagW, MinvVphi, DaggerNo ); dSdU=dSdU-force;
|
||||||
|
DenOp.MDeriv(force, MinvVphi, MdagInvPdagW, DaggerYes); dSdU=dSdU-force;
|
||||||
|
|
||||||
|
dSdU *= -1.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/qcd/action/pseudofermion/TwoFlavourRatioLeftPrec.h
|
||||||
|
|
||||||
|
Copyright (C) 2026
|
||||||
|
|
||||||
|
Author: Peter Boyle <pboyle@bnl.gov>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
See the full license in the file "LICENSE" in the top level distribution directory
|
||||||
|
*************************************************************************************/
|
||||||
|
/* END LEGAL */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Two flavour ratio with LEFT-PRECONDITIONED solves.
|
||||||
|
//
|
||||||
|
// Same action content as TwoFlavourRatio.h:
|
||||||
|
//
|
||||||
|
// S = phi^dag V (Mdag M)^-1 Vdag phi ==> det[ Mdag M / Vdag V ]
|
||||||
|
//
|
||||||
|
// (V = NumOp the heavier / Pauli-Villars operator, M = DenOp the lighter),
|
||||||
|
// but organised around the composite
|
||||||
|
//
|
||||||
|
// F = Vdag M
|
||||||
|
//
|
||||||
|
// which is the 2-hop-coarsenable operator the non-Hermitian multigrid
|
||||||
|
// serves. Solving M X = b as F X = Vdag b is LEFT PRECONDITIONING by
|
||||||
|
// Vdag; the determinant/action layer is the standard quotient, and all
|
||||||
|
// novelty is confined to the solver contract.
|
||||||
|
//
|
||||||
|
// TwoFlavourRatio.h is tied to a normal-equations solver: one (MdagM)^-1
|
||||||
|
// solve, then Y = M X gives Mdag^-1 Vdag phi almost free. The left-
|
||||||
|
// preconditioned idiom is DIFFERENT: the chain
|
||||||
|
//
|
||||||
|
// b = Vdag phi
|
||||||
|
// z : Fdag z = b (adjoint F solve)
|
||||||
|
// Y = V z (= Mdag^-1 Vdag phi -- harvested from solve 1)
|
||||||
|
// s = Vdag Y (= Vdag V z)
|
||||||
|
// X : F X = s (forward F solve; X = (MdagM)^-1 Vdag phi)
|
||||||
|
//
|
||||||
|
// yields Y BEFORE X (so S(U) needs only the adjoint solve), with Y's
|
||||||
|
// accuracy independent of the second solve. Force terms are then the
|
||||||
|
// standard four MDeriv insertions of TwoFlavourRatio.
|
||||||
|
//
|
||||||
|
// Solver slots are LinearFunctions with the F-SOLVE contract (solution
|
||||||
|
// overwritten, zero guess imposed internally):
|
||||||
|
// ForwardSolver(b,x) : F x = b
|
||||||
|
// AdjointSolver(b,z) : Fdag z = b
|
||||||
|
// implemented in production by the multigrid-GCR stack (forward cycle and
|
||||||
|
// adjoint cycle); in tests by CG on the composite normal equations.
|
||||||
|
// HeatbathSolver(b,x) : x = (Vdag V)^-1 b -- heavy operator, plain CG.
|
||||||
|
//
|
||||||
|
// Heatbath is exact by operator algebra: phi = V (VdagV)^-1 Mdag eta
|
||||||
|
// ==> S = | Mdag^-1 Vdag phi |^2 = |eta|^2 (to solver tolerance); the
|
||||||
|
// deterministic refresh(U,eta) hook below is the test point.
|
||||||
|
//
|
||||||
|
// Hasenbusch: nothing requires V to have mass one; any (heavier,lighter)
|
||||||
|
// pair works, F(V,M) = Vdag M coarsenable by the same machinery, rungs'
|
||||||
|
// solves are F-family (mrhs-batchable, mass-shared coarse space).
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class Impl>
|
||||||
|
class TwoFlavourRatioLeftPrecPseudoFermionAction : public Action<typename Impl::GaugeField> {
|
||||||
|
public:
|
||||||
|
INHERIT_IMPL_TYPES(Impl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FermionOperator<Impl> & NumOp;// V
|
||||||
|
FermionOperator<Impl> & DenOp;// M
|
||||||
|
|
||||||
|
LinearFunction<FermionField> &DerivForwardSolver; // F x = b, MD tolerance
|
||||||
|
LinearFunction<FermionField> &DerivAdjointSolver; // Fdag z = b, MD tolerance
|
||||||
|
LinearFunction<FermionField> &ActionAdjointSolver; // Fdag z = b, accept/reject tolerance
|
||||||
|
LinearFunction<FermionField> &HeatbathSolver; // (VdagV)^-1 b, heavy op
|
||||||
|
|
||||||
|
FermionField Phi; // the pseudo fermion field for this trajectory
|
||||||
|
|
||||||
|
public:
|
||||||
|
TwoFlavourRatioLeftPrecPseudoFermionAction(FermionOperator<Impl> &_NumOp,
|
||||||
|
FermionOperator<Impl> &_DenOp,
|
||||||
|
LinearFunction<FermionField> & DFS,
|
||||||
|
LinearFunction<FermionField> & DAS,
|
||||||
|
LinearFunction<FermionField> & AAS,
|
||||||
|
LinearFunction<FermionField> & HS
|
||||||
|
) : NumOp(_NumOp),
|
||||||
|
DenOp(_DenOp),
|
||||||
|
DerivForwardSolver(DFS),
|
||||||
|
DerivAdjointSolver(DAS),
|
||||||
|
ActionAdjointSolver(AAS),
|
||||||
|
HeatbathSolver(HS),
|
||||||
|
Phi(_NumOp.FermionGrid())
|
||||||
|
{};
|
||||||
|
|
||||||
|
virtual std::string action_name(){return "TwoFlavourRatioLeftPrecPseudoFermionAction";}
|
||||||
|
|
||||||
|
virtual std::string LogParameters(){
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << GridLogMessage << "["<<action_name()<<"] has no parameters" << std::endl;
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void refresh(const GaugeField &U, GridSerialRNG &sRNG, GridParallelRNG& pRNG) {
|
||||||
|
// P(phi) = e^{- phi^dag V (MdagM)^-1 Vdag phi} ; phi = Vdag^-1 Mdag eta
|
||||||
|
// e^{-x^2/2 sig^2} => sig^2 = 0.5 ; eta enters with width 1/sqrt(2).
|
||||||
|
RealD scale = std::sqrt(0.5);
|
||||||
|
FermionField eta(NumOp.FermionGrid());
|
||||||
|
gaussian(pRNG,eta);
|
||||||
|
eta = eta * scale;
|
||||||
|
refresh(U,eta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic-noise variant (test hook):
|
||||||
|
// after this, S(U) == norm2(eta) exactly (to solver tolerance).
|
||||||
|
void refresh(const GaugeField &U, const FermionField &eta) {
|
||||||
|
NumOp.ImportGauge(U);
|
||||||
|
DenOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField tmp(NumOp.FermionGrid());
|
||||||
|
FermionField w (NumOp.FermionGrid());
|
||||||
|
|
||||||
|
DenOp.Mdag(eta,tmp); // tmp = Mdag eta
|
||||||
|
w = Zero();
|
||||||
|
HeatbathSolver(tmp,w); // w = (VdagV)^-1 Mdag eta
|
||||||
|
NumOp.M(w,Phi); // Phi = V (VdagV)^-1 Mdag eta = Vdag^-1 Mdag eta
|
||||||
|
std::cout << GridLogMessage << action_name() << " refresh |Phi|^2 = "<< norm2(Phi)<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// S = phi^dag V (MdagM)^-1 Vdag phi = | Mdag^-1 Vdag phi |^2
|
||||||
|
// ONE adjoint F solve: Y = V Fdag^-1 Vdag phi = Mdag^-1 Vdag phi
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual RealD S(const GaugeField &U) {
|
||||||
|
NumOp.ImportGauge(U);
|
||||||
|
DenOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField b(NumOp.FermionGrid());
|
||||||
|
FermionField z(NumOp.FermionGrid());
|
||||||
|
FermionField Y(NumOp.FermionGrid());
|
||||||
|
|
||||||
|
NumOp.Mdag(Phi,b); // b = Vdag phi
|
||||||
|
z = Zero();
|
||||||
|
ActionAdjointSolver(b,z); // Fdag z = b
|
||||||
|
NumOp.M(z,Y); // Y = V z = Mdag^-1 Vdag phi
|
||||||
|
|
||||||
|
RealD action = norm2(Y);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// dS/du = phi^dag dV (MdagM)^-1 Vdag phi
|
||||||
|
// - phi^dag V (MdagM)^-1 [ Mdag dM + dMdag M ] (MdagM)^-1 Vdag phi
|
||||||
|
// + phi^dag V (MdagM)^-1 dVdag phi
|
||||||
|
// Identical force insertions to TwoFlavourRatio.h; X and Y from the
|
||||||
|
// left-preconditioned chain (Y harvested from the adjoint solve).
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
virtual void deriv(const GaugeField &U,GaugeField & dSdU) {
|
||||||
|
NumOp.ImportGauge(U);
|
||||||
|
DenOp.ImportGauge(U);
|
||||||
|
|
||||||
|
FermionField b(NumOp.FermionGrid());
|
||||||
|
FermionField z(NumOp.FermionGrid());
|
||||||
|
FermionField Y(NumOp.FermionGrid());
|
||||||
|
FermionField s(NumOp.FermionGrid());
|
||||||
|
FermionField X(NumOp.FermionGrid());
|
||||||
|
|
||||||
|
GaugeField force(NumOp.GaugeGrid());
|
||||||
|
|
||||||
|
NumOp.Mdag(Phi,b); // b = Vdag phi
|
||||||
|
z = Zero();
|
||||||
|
DerivAdjointSolver(b,z); // Fdag z = b
|
||||||
|
NumOp.M(z,Y); // Y = V z = Mdag^-1 Vdag phi (solve-1 harvest)
|
||||||
|
NumOp.Mdag(Y,s); // s = Vdag V z
|
||||||
|
X = Zero();
|
||||||
|
DerivForwardSolver(s,X); // F X = s ==> X = (MdagM)^-1 Vdag phi
|
||||||
|
|
||||||
|
// phi^dag V (MdagM)^-1 dVdag phi
|
||||||
|
NumOp.MDeriv(force , X, Phi, DaggerYes); dSdU = force;
|
||||||
|
// phi^dag dV (MdagM)^-1 Vdag phi
|
||||||
|
NumOp.MDeriv(force , Phi, X, DaggerNo ); dSdU = dSdU+force;
|
||||||
|
// - phi^dag V (MdagM)^-1 Mdag dM (MdagM)^-1 Vdag phi
|
||||||
|
// - phi^dag V (MdagM)^-1 dMdag M (MdagM)^-1 Vdag phi
|
||||||
|
DenOp.MDeriv(force, Y, X, DaggerNo ); dSdU = dSdU-force;
|
||||||
|
DenOp.MDeriv(force, X, Y, DaggerYes); dSdU = dSdU-force;
|
||||||
|
|
||||||
|
dSdU *= -1.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
+12
-12
@@ -89,10 +89,8 @@ template <int ncolour, class group_name>
|
|||||||
class GaugeGroup {
|
class GaugeGroup {
|
||||||
public:
|
public:
|
||||||
static const int Dimension = ncolour;
|
static const int Dimension = ncolour;
|
||||||
static const int AdjointDimension =
|
static const int AdjointDimension = compute_adjoint_dimension<group_name>(ncolour);
|
||||||
compute_adjoint_dimension<group_name>(ncolour);
|
static const int AlgebraDimension = compute_adjoint_dimension<group_name>(ncolour);
|
||||||
static const int AlgebraDimension =
|
|
||||||
compute_adjoint_dimension<group_name>(ncolour);
|
|
||||||
|
|
||||||
template <typename vtype>
|
template <typename vtype>
|
||||||
using iSU2Matrix = iScalar<iScalar<iMatrix<vtype, 2> > >;
|
using iSU2Matrix = iScalar<iScalar<iMatrix<vtype, 2> > >;
|
||||||
@@ -101,8 +99,7 @@ class GaugeGroup {
|
|||||||
template <typename vtype>
|
template <typename vtype>
|
||||||
using iAlgebraVector = iScalar<iScalar<iVector<vtype, AdjointDimension> > >;
|
using iAlgebraVector = iScalar<iScalar<iVector<vtype, AdjointDimension> > >;
|
||||||
template <typename vtype>
|
template <typename vtype>
|
||||||
using iSUnAlgebraMatrix =
|
using iSUnAlgebraMatrix = iScalar<iScalar<iMatrix<vtype, AdjointDimension> > >;
|
||||||
iScalar<iScalar<iMatrix<vtype, AdjointDimension> > >;
|
|
||||||
static int su2subgroups(void) { return su2subgroups(group_name()); }
|
static int su2subgroups(void) { return su2subgroups(group_name()); }
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -297,15 +294,17 @@ class GaugeGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <int N,class vComplex_t>
|
template <int N,class vComplex_t>
|
||||||
static Lattice<iScalar<iScalar<iMatrix<vComplex_t, N> > > > ProjectOnGeneralGroup(const Lattice<iScalar<iScalar<iMatrix<vComplex_t, N> > > > &Umu) {
|
static Lattice<iScalar<iScalar<iMatrix<vComplex_t, N> > > >
|
||||||
|
ProjectOnGeneralGroup(const Lattice<iScalar<iScalar<iMatrix<vComplex_t, N> > > > &Umu)
|
||||||
|
{
|
||||||
return ProjectOnGeneralGroup(Umu, group_name());
|
return ProjectOnGeneralGroup(Umu, group_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N,class vComplex_t> // Projects on SU(N), Sp(2N), with unit determinant, by first projecting on general group and then enforcing unit determinant
|
// Projects on SU(N), Sp(2N), with unit determinant, by first projecting on general group and then enforcing unit determinant
|
||||||
static void ProjectOnSpecialGroup(Lattice<iScalar<iScalar<iMatrix<vComplex_t, N> > > > &Umu) {
|
template <int N,class vComplex_t>
|
||||||
|
static void ProjectOnSpecialGroup(Lattice<iScalar<iScalar<iMatrix<vComplex_t, N> > > > &Umu)
|
||||||
|
{
|
||||||
Umu = ProjectOnGeneralGroup(Umu);
|
Umu = ProjectOnGeneralGroup(Umu);
|
||||||
auto det = Determinant(Umu);
|
auto det = Determinant(Umu);
|
||||||
|
|
||||||
@@ -319,7 +318,8 @@ class GaugeGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <int N,class vComplex_t> // reunitarise, resimplectify... previously ProjectSUn
|
template <int N,class vComplex_t> // reunitarise, resimplectify... previously ProjectSUn
|
||||||
static void ProjectOnSpecialGroup(Lattice<iVector<iScalar<iMatrix<vComplex_t, N> >, Nd> > &U) {
|
static void ProjectOnSpecialGroup(Lattice<iVector<iScalar<iMatrix<vComplex_t, N> >, Nd> > &U)
|
||||||
|
{
|
||||||
// Reunitarise
|
// Reunitarise
|
||||||
for (int mu = 0; mu < Nd; mu++) {
|
for (int mu = 0; mu < Nd; mu++) {
|
||||||
auto Umu = PeekIndex<LorentzIndex>(U, mu);
|
auto Umu = PeekIndex<LorentzIndex>(U, mu);
|
||||||
|
|||||||
@@ -933,6 +933,8 @@ typedef Optimization::Div DivSIMD;
|
|||||||
typedef Optimization::Mult MultSIMD;
|
typedef Optimization::Mult MultSIMD;
|
||||||
typedef Optimization::MultComplex MultComplexSIMD;
|
typedef Optimization::MultComplex MultComplexSIMD;
|
||||||
typedef Optimization::MultAddComplex MultAddComplexSIMD;
|
typedef Optimization::MultAddComplex MultAddComplexSIMD;
|
||||||
|
// Asserts MultAddComplexSIMD and a three argument MultSIMD operator()
|
||||||
|
#define GRID_ARCH_HAS_COMPLEX_MULT_ADD 1
|
||||||
typedef Optimization::MultRealPart MultRealPartSIMD;
|
typedef Optimization::MultRealPart MultRealPartSIMD;
|
||||||
typedef Optimization::MaddRealPart MaddRealPartSIMD;
|
typedef Optimization::MaddRealPart MaddRealPartSIMD;
|
||||||
typedef Optimization::Conj ConjSIMD;
|
typedef Optimization::Conj ConjSIMD;
|
||||||
|
|||||||
@@ -760,6 +760,8 @@ typedef Optimization::Div DivSIMD;
|
|||||||
typedef Optimization::Mult MultSIMD;
|
typedef Optimization::Mult MultSIMD;
|
||||||
typedef Optimization::MultComplex MultComplexSIMD;
|
typedef Optimization::MultComplex MultComplexSIMD;
|
||||||
typedef Optimization::MultAddComplex MultAddComplexSIMD;
|
typedef Optimization::MultAddComplex MultAddComplexSIMD;
|
||||||
|
// Asserts MultAddComplexSIMD and a three argument MultSIMD operator()
|
||||||
|
#define GRID_ARCH_HAS_COMPLEX_MULT_ADD 1
|
||||||
typedef Optimization::MultRealPart MultRealPartSIMD;
|
typedef Optimization::MultRealPart MultRealPartSIMD;
|
||||||
typedef Optimization::MaddRealPart MaddRealPartSIMD;
|
typedef Optimization::MaddRealPart MaddRealPartSIMD;
|
||||||
typedef Optimization::Conj ConjSIMD;
|
typedef Optimization::Conj ConjSIMD;
|
||||||
|
|||||||
@@ -339,54 +339,6 @@ typedef Grid_simd2<complex<double> , vComplexD> vComplexD2;
|
|||||||
typedef Grid_simd2<double , vRealD> vRealD2;
|
typedef Grid_simd2<double , vRealD> vRealD2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////
|
|
||||||
// Some traits to recognise the types
|
|
||||||
/////////////////////////////////////////
|
|
||||||
template <typename T>
|
|
||||||
struct is_simd : public std::false_type {};
|
|
||||||
template <> struct is_simd<vRealF> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vRealD> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vRealH> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vComplexF> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vComplexD> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vComplexH> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vInteger> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vRealD2> : public std::true_type {};
|
|
||||||
template <> struct is_simd<vComplexD2> : public std::true_type {};
|
|
||||||
|
|
||||||
template <typename T> using IfSimd = Invoke<std::enable_if<is_simd<T>::value, int> >;
|
|
||||||
template <typename T> using IfNotSimd = Invoke<std::enable_if<!is_simd<T>::value, unsigned> >;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////
|
|
||||||
// insert / extract with complex support
|
|
||||||
///////////////////////////////////////////////
|
|
||||||
template <class S, class V>
|
|
||||||
accelerator_inline S getlane(const Grid_simd<S, V> &in,int lane) {
|
|
||||||
return in.getlane(lane);
|
|
||||||
}
|
|
||||||
template <class S, class V>
|
|
||||||
accelerator_inline void putlane(Grid_simd<S, V> &vec,const S &_S, int lane){
|
|
||||||
vec.putlane(_S,lane);
|
|
||||||
}
|
|
||||||
template <class S,IfNotSimd<S> = 0 >
|
|
||||||
accelerator_inline S getlane(const S &in,int lane) {
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
template <class S,IfNotSimd<S> = 0 >
|
|
||||||
accelerator_inline void putlane(S &vec,const S &_S, int lane){
|
|
||||||
vec = _S;
|
|
||||||
}
|
|
||||||
template <class S, class V>
|
|
||||||
accelerator_inline S getlane(const Grid_simd2<S, V> &in,int lane) {
|
|
||||||
return in.getlane(lane);
|
|
||||||
}
|
|
||||||
template <class S, class V>
|
|
||||||
accelerator_inline void putlane(Grid_simd2<S, V> &vec,const S &_S, int lane){
|
|
||||||
vec.putlane(_S,lane);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// General rotate
|
// General rotate
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -42,6 +42,16 @@
|
|||||||
#define GEN_SIMD_WIDTH 16u
|
#define GEN_SIMD_WIDTH 16u
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ARMv8.3 complex assist (FCMLA). Kept separate from the ACLE
|
||||||
|
// __ARM_FEATURE_COMPLEX: the instructions are also present on A64FX, where
|
||||||
|
// their throughput is 1:4 and this path would be a regression. Revisit the
|
||||||
|
// rule once measured per target.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef __ARM_FEATURE_COMPLEX
|
||||||
|
#define GRID_ARM_FEATURE_COMPLEX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Grid_generic_types.h"
|
#include "Grid_generic_types.h"
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
|
|
||||||
@@ -226,6 +236,22 @@ struct Div{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MultComplex{
|
struct MultComplex{
|
||||||
|
#ifdef GRID_ARM_FEATURE_COMPLEX
|
||||||
|
// fcmla #0 : r += (ar,ar)*(br,bi) = ( ar*br, ar*bi)
|
||||||
|
// fcmla #90 : r += (-ai,ai)*(bi,br) = (-ai*bi, ai*br)
|
||||||
|
// Complex float: two products, two instructions
|
||||||
|
inline float32x4_t operator()(float32x4_t a, float32x4_t b){
|
||||||
|
float32x4_t r = vdupq_n_f32(0.0f);
|
||||||
|
r = vcmlaq_f32(r, a, b);
|
||||||
|
return vcmlaq_rot90_f32(r, a, b);
|
||||||
|
}
|
||||||
|
// Complex double
|
||||||
|
inline float64x2_t operator()(float64x2_t a, float64x2_t b){
|
||||||
|
float64x2_t r = vdupq_n_f64(0.0);
|
||||||
|
r = vcmlaq_f64(r, a, b);
|
||||||
|
return vcmlaq_rot90_f64(r, a, b);
|
||||||
|
}
|
||||||
|
#else
|
||||||
// Complex float
|
// Complex float
|
||||||
inline float32x4_t operator()(float32x4_t a, float32x4_t b){
|
inline float32x4_t operator()(float32x4_t a, float32x4_t b){
|
||||||
|
|
||||||
@@ -273,8 +299,23 @@ struct MultComplex{
|
|||||||
// r5 = vmulq_f64(r0, a);
|
// r5 = vmulq_f64(r0, a);
|
||||||
// return vaddq_f64(r4, r5);
|
// return vaddq_f64(r4, r5);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef GRID_ARM_FEATURE_COMPLEX
|
||||||
|
struct MultAddComplex{
|
||||||
|
// Complex a*b+c
|
||||||
|
inline float32x4_t operator()(float32x4_t a, float32x4_t b, float32x4_t c){
|
||||||
|
c = vcmlaq_f32(c, a, b);
|
||||||
|
return vcmlaq_rot90_f32(c, a, b);
|
||||||
|
}
|
||||||
|
inline float64x2_t operator()(float64x2_t a, float64x2_t b, float64x2_t c){
|
||||||
|
c = vcmlaq_f64(c, a, b);
|
||||||
|
return vcmlaq_rot90_f64(c, a, b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct Mult{
|
struct Mult{
|
||||||
// Real float
|
// Real float
|
||||||
inline float32x4_t mac(float32x4_t a, float32x4_t b, float32x4_t c){
|
inline float32x4_t mac(float32x4_t a, float32x4_t b, float32x4_t c){
|
||||||
@@ -285,6 +326,13 @@ struct Mult{
|
|||||||
//return vaddq_f64(vmulq_f64(b,c),a);
|
//return vaddq_f64(vmulq_f64(b,c),a);
|
||||||
return vfmaq_f64(a, b, c);
|
return vfmaq_f64(a, b, c);
|
||||||
}
|
}
|
||||||
|
// Real a*b+c
|
||||||
|
inline float32x4_t operator()(float32x4_t a, float32x4_t b, float32x4_t c){
|
||||||
|
return vfmaq_f32(c, a, b);
|
||||||
|
}
|
||||||
|
inline float64x2_t operator()(float64x2_t a, float64x2_t b, float64x2_t c){
|
||||||
|
return vfmaq_f64(c, a, b);
|
||||||
|
}
|
||||||
inline float32x4_t operator()(float32x4_t a, float32x4_t b){
|
inline float32x4_t operator()(float32x4_t a, float32x4_t b){
|
||||||
return vmulq_f32(a,b);
|
return vmulq_f32(a,b);
|
||||||
}
|
}
|
||||||
@@ -585,6 +633,11 @@ typedef Optimization::Sub SubSIMD;
|
|||||||
typedef Optimization::Div DivSIMD;
|
typedef Optimization::Div DivSIMD;
|
||||||
typedef Optimization::Mult MultSIMD;
|
typedef Optimization::Mult MultSIMD;
|
||||||
typedef Optimization::MultComplex MultComplexSIMD;
|
typedef Optimization::MultComplex MultComplexSIMD;
|
||||||
|
#ifdef GRID_ARM_FEATURE_COMPLEX
|
||||||
|
typedef Optimization::MultAddComplex MultAddComplexSIMD;
|
||||||
|
// Asserts MultAddComplexSIMD and a three argument MultSIMD operator()
|
||||||
|
#define GRID_ARCH_HAS_COMPLEX_MULT_ADD 1
|
||||||
|
#endif
|
||||||
typedef Optimization::MultRealPart MultRealPartSIMD;
|
typedef Optimization::MultRealPart MultRealPartSIMD;
|
||||||
typedef Optimization::MaddRealPart MaddRealPartSIMD;
|
typedef Optimization::MaddRealPart MaddRealPartSIMD;
|
||||||
typedef Optimization::Conj ConjSIMD;
|
typedef Optimization::Conj ConjSIMD;
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(GRID_CUDA) || defined(GRID_HIP)
|
||||||
|
#include <thrust/complex.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define scalar and vector floating point types
|
||||||
|
//
|
||||||
|
// Scalar: RealF, RealD, ComplexF, ComplexD
|
||||||
|
//
|
||||||
|
// Vector: vRealF, vRealD, vComplexF, vComplexD
|
||||||
|
//
|
||||||
|
// Vector types are arch dependent
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define _MM_SELECT_FOUR_FOUR(A,B,C,D) ((A<<6)|(B<<4)|(C<<2)|(D))
|
||||||
|
#define _MM_SELECT_FOUR_FOUR_STRING(A,B,C,D) "((" #A "<<6)|(" #B "<<4)|(" #C "<<2)|(" #D "))"
|
||||||
|
#define _MM_SELECT_EIGHT_TWO(A,B,C,D,E,F,G,H) ((A<<7)|(B<<6)|(C<<5)|(D<<4)|(E<<3)|(F<<2)|(G<<4)|(H))
|
||||||
|
#define _MM_SELECT_FOUR_TWO (A,B,C,D) _MM_SELECT_EIGHT_TWO(0,0,0,0,A,B,C,D)
|
||||||
|
#define _MM_SELECT_TWO_TWO (A,B) _MM_SELECT_FOUR_TWO(0,0,A,B)
|
||||||
|
|
||||||
|
#define RotateBit (0x100)
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
typedef uint32_t Integer;
|
||||||
|
|
||||||
|
typedef float RealF;
|
||||||
|
typedef double RealD;
|
||||||
|
#ifdef GRID_DEFAULT_PRECISION_DOUBLE
|
||||||
|
typedef RealD Real;
|
||||||
|
#else
|
||||||
|
typedef RealF Real;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GRID_CUDA) || defined(GRID_HIP)
|
||||||
|
typedef thrust::complex<RealF> ComplexF;
|
||||||
|
typedef thrust::complex<RealD> ComplexD;
|
||||||
|
typedef thrust::complex<Real> Complex;
|
||||||
|
typedef thrust::complex<uint16_t> ComplexH;
|
||||||
|
template<class T> using complex = thrust::complex<T>;
|
||||||
|
|
||||||
|
accelerator_inline ComplexD pow(const ComplexD& r,RealD y){ return(thrust::pow(r,(double)y)); }
|
||||||
|
accelerator_inline ComplexF pow(const ComplexF& r,RealF y){ return(thrust::pow(r,(float)y)); }
|
||||||
|
#else
|
||||||
|
typedef std::complex<RealF> ComplexF;
|
||||||
|
typedef std::complex<RealD> ComplexD;
|
||||||
|
typedef std::complex<Real> Complex;
|
||||||
|
typedef std::complex<uint16_t> ComplexH; // Hack
|
||||||
|
template<class T> using complex = std::complex<T>;
|
||||||
|
|
||||||
|
accelerator_inline ComplexD pow(const ComplexD& r,RealD y){ return(std::pow(r,y)); }
|
||||||
|
accelerator_inline ComplexF pow(const ComplexF& r,RealF y){ return(std::pow(r,y)); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//accelerator_inline RealD pow(const RealD& r,RealD y){ return(std::pow(r,y)); }
|
||||||
|
//accelerator_inline RealD sqrt(const RealD & r){ return std::sqrt(r); }
|
||||||
|
|
||||||
|
// This comes from ::pow already from math.h and CUDA
|
||||||
|
// Calls either Grid::pow for complex, or std::pow for real
|
||||||
|
// Problem is CUDA math_functions is exposing ::pow, and I can't define
|
||||||
|
|
||||||
|
using std::abs;
|
||||||
|
using std::pow;
|
||||||
|
using std::sqrt;
|
||||||
|
using std::log;
|
||||||
|
using std::exp;
|
||||||
|
using std::sin;
|
||||||
|
using std::cos;
|
||||||
|
using std::asin;
|
||||||
|
using std::acos;
|
||||||
|
|
||||||
|
|
||||||
|
accelerator_inline RealF conjugate(const RealF & r){ return r; }
|
||||||
|
accelerator_inline RealD conjugate(const RealD & r){ return r; }
|
||||||
|
accelerator_inline ComplexD conjugate(const ComplexD& r){ return(conj(r)); }
|
||||||
|
accelerator_inline ComplexF conjugate(const ComplexF& r ){ return(conj(r)); }
|
||||||
|
|
||||||
|
accelerator_inline RealF adj(const RealF & r){ return r; }
|
||||||
|
accelerator_inline RealD adj(const RealD & r){ return r; }
|
||||||
|
accelerator_inline ComplexD adj(const ComplexD& r){ return(conjugate(r)); }
|
||||||
|
accelerator_inline ComplexF adj(const ComplexF& r ){ return(conjugate(r)); }
|
||||||
|
|
||||||
|
#if defined(GRID_CUDA) || defined(GRID_HIP)
|
||||||
|
//Provide for convenience
|
||||||
|
inline std::complex<double> conjugate(const std::complex<double>& r){ return(conj(r)); }
|
||||||
|
inline std::complex<float> conjugate(const std::complex<float>& r) { return(conj(r)); }
|
||||||
|
inline std::complex<double> adj(const std::complex<double>& r) { return(conj(r)); }
|
||||||
|
inline std::complex<float> adj(const std::complex<float>& r) { return(conj(r)); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
accelerator_inline RealF real(const RealF & r){ return r; }
|
||||||
|
accelerator_inline RealD real(const RealD & r){ return r; }
|
||||||
|
accelerator_inline RealF real(const ComplexF & r){ return r.real(); }
|
||||||
|
accelerator_inline RealD real(const ComplexD & r){ return r.real(); }
|
||||||
|
|
||||||
|
accelerator_inline RealF imag(const ComplexF & r){ return r.imag(); }
|
||||||
|
accelerator_inline RealD imag(const ComplexD & r){ return r.imag(); }
|
||||||
|
|
||||||
|
accelerator_inline ComplexD innerProduct(const ComplexD & l, const ComplexD & r) { return conjugate(l)*r; }
|
||||||
|
accelerator_inline ComplexF innerProduct(const ComplexF & l, const ComplexF & r) { return conjugate(l)*r; }
|
||||||
|
accelerator_inline RealD innerProduct(const RealD & l, const RealD & r) { return l*r; }
|
||||||
|
accelerator_inline RealF innerProduct(const RealF & l, const RealF & r) { return l*r; }
|
||||||
|
|
||||||
|
accelerator_inline ComplexD Reduce(const ComplexD& r){ return r; }
|
||||||
|
accelerator_inline ComplexF Reduce(const ComplexF& r){ return r; }
|
||||||
|
accelerator_inline RealD Reduce(const RealD& r){ return r; }
|
||||||
|
accelerator_inline RealF Reduce(const RealF& r){ return r; }
|
||||||
|
|
||||||
|
accelerator_inline RealD toReal(const ComplexD& r){ return r.real(); }
|
||||||
|
accelerator_inline RealF toReal(const ComplexF& r){ return r.real(); }
|
||||||
|
accelerator_inline RealD toReal(const RealD& r){ return r; }
|
||||||
|
accelerator_inline RealF toReal(const RealF& r){ return r; }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//Provide support functions for basic real and complex data types required by Grid
|
||||||
|
//Single and double precision versions. Should be able to template this once only.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
accelerator_inline void mac (ComplexD * __restrict__ y,const ComplexD * __restrict__ a,const ComplexD *__restrict__ x){ *y = (*a) * (*x)+(*y); };
|
||||||
|
accelerator_inline void mult(ComplexD * __restrict__ y,const ComplexD * __restrict__ l,const ComplexD *__restrict__ r){ *y = (*l) * (*r);}
|
||||||
|
accelerator_inline void sub (ComplexD * __restrict__ y,const ComplexD * __restrict__ l,const ComplexD *__restrict__ r){ *y = (*l) - (*r);}
|
||||||
|
accelerator_inline void add (ComplexD * __restrict__ y,const ComplexD * __restrict__ l,const ComplexD *__restrict__ r){ *y = (*l) + (*r);}
|
||||||
|
// conjugate already supported for complex
|
||||||
|
|
||||||
|
accelerator_inline void mac (ComplexF * __restrict__ y,const ComplexF * __restrict__ a,const ComplexF *__restrict__ x){ *y = (*a) * (*x)+(*y); }
|
||||||
|
accelerator_inline void mult(ComplexF * __restrict__ y,const ComplexF * __restrict__ l,const ComplexF *__restrict__ r){ *y = (*l) * (*r); }
|
||||||
|
accelerator_inline void sub (ComplexF * __restrict__ y,const ComplexF * __restrict__ l,const ComplexF *__restrict__ r){ *y = (*l) - (*r); }
|
||||||
|
accelerator_inline void add (ComplexF * __restrict__ y,const ComplexF * __restrict__ l,const ComplexF *__restrict__ r){ *y = (*l) + (*r); }
|
||||||
|
|
||||||
|
//conjugate already supported for complex
|
||||||
|
accelerator_inline ComplexF timesI(const ComplexF &r) { return(ComplexF(-r.imag(),r.real()));}
|
||||||
|
accelerator_inline ComplexD timesI(const ComplexD &r) { return(ComplexD(-r.imag(),r.real()));}
|
||||||
|
accelerator_inline ComplexF timesMinusI(const ComplexF &r){ return(ComplexF(r.imag(),-r.real()));}
|
||||||
|
accelerator_inline ComplexD timesMinusI(const ComplexD &r){ return(ComplexD(r.imag(),-r.real()));}
|
||||||
|
//accelerator_inline ComplexF timesI(const ComplexF &r) { return(r*ComplexF(0.0,1.0));}
|
||||||
|
//accelerator_inline ComplexD timesI(const ComplexD &r) { return(r*ComplexD(0.0,1.0));}
|
||||||
|
//accelerator_inline ComplexF timesMinusI(const ComplexF &r){ return(r*ComplexF(0.0,-1.0));}
|
||||||
|
//accelerator_inline ComplexD timesMinusI(const ComplexD &r){ return(r*ComplexD(0.0,-1.0));}
|
||||||
|
|
||||||
|
// define projections to real and imaginay parts
|
||||||
|
accelerator_inline ComplexF projReal(const ComplexF &r){return( ComplexF(r.real(), 0.0));}
|
||||||
|
accelerator_inline ComplexD projReal(const ComplexD &r){return( ComplexD(r.real(), 0.0));}
|
||||||
|
accelerator_inline ComplexF projImag(const ComplexF &r){return (ComplexF(r.imag(), 0.0 ));}
|
||||||
|
accelerator_inline ComplexD projImag(const ComplexD &r){return (ComplexD(r.imag(), 0.0));}
|
||||||
|
|
||||||
|
// define auxiliary functions for complex computations
|
||||||
|
accelerator_inline void timesI(ComplexF &ret,const ComplexF &r) { ret = timesI(r);}
|
||||||
|
accelerator_inline void timesI(ComplexD &ret,const ComplexD &r) { ret = timesI(r);}
|
||||||
|
accelerator_inline void timesMinusI(ComplexF &ret,const ComplexF &r){ ret = timesMinusI(r);}
|
||||||
|
accelerator_inline void timesMinusI(ComplexD &ret,const ComplexD &r){ ret = timesMinusI(r);}
|
||||||
|
|
||||||
|
accelerator_inline void mac (RealD * __restrict__ y,const RealD * __restrict__ a,const RealD *__restrict__ x){ *y = (*a) * (*x)+(*y);}
|
||||||
|
accelerator_inline void mult(RealD * __restrict__ y,const RealD * __restrict__ l,const RealD *__restrict__ r){ *y = (*l) * (*r);}
|
||||||
|
accelerator_inline void sub (RealD * __restrict__ y,const RealD * __restrict__ l,const RealD *__restrict__ r){ *y = (*l) - (*r);}
|
||||||
|
accelerator_inline void add (RealD * __restrict__ y,const RealD * __restrict__ l,const RealD *__restrict__ r){ *y = (*l) + (*r);}
|
||||||
|
|
||||||
|
accelerator_inline void mac (RealF * __restrict__ y,const RealF * __restrict__ a,const RealF *__restrict__ x){ *y = (*a) * (*x)+(*y); }
|
||||||
|
accelerator_inline void mult(RealF * __restrict__ y,const RealF * __restrict__ l,const RealF *__restrict__ r){ *y = (*l) * (*r); }
|
||||||
|
accelerator_inline void sub (RealF * __restrict__ y,const RealF * __restrict__ l,const RealF *__restrict__ r){ *y = (*l) - (*r); }
|
||||||
|
accelerator_inline void add (RealF * __restrict__ y,const RealF * __restrict__ l,const RealF *__restrict__ r){ *y = (*l) + (*r); }
|
||||||
|
|
||||||
|
accelerator_inline void vstream(ComplexF &l, const ComplexF &r){ l=r;}
|
||||||
|
accelerator_inline void vstream(ComplexD &l, const ComplexD &r){ l=r;}
|
||||||
|
accelerator_inline void vstream(RealF &l, const RealF &r){ l=r;}
|
||||||
|
accelerator_inline void vstream(RealD &l, const RealD &r){ l=r;}
|
||||||
|
|
||||||
|
accelerator_inline ComplexD toComplex(const RealD &in) { return ComplexD(in);}
|
||||||
|
accelerator_inline ComplexF toComplex(const RealF &in) { return ComplexF(in);}
|
||||||
|
|
||||||
|
class Zero{};
|
||||||
|
//static Zero Zero();
|
||||||
|
template<class itype> accelerator_inline void zeroit(itype &arg) { arg=Zero();};
|
||||||
|
template<> accelerator_inline void zeroit(ComplexF &arg){ arg=0; };
|
||||||
|
template<> accelerator_inline void zeroit(ComplexD &arg){ arg=0; };
|
||||||
|
template<> accelerator_inline void zeroit(RealF &arg) { arg=0; };
|
||||||
|
template<> accelerator_inline void zeroit(RealD &arg) { arg=0; };
|
||||||
|
|
||||||
|
// More limited Integer support
|
||||||
|
accelerator_inline Integer Reduce(const Integer& r){ return r; }
|
||||||
|
accelerator_inline void mac (Integer * __restrict__ y,const Integer * __restrict__ a,const Integer *__restrict__ x){ *y = (*a) * (*x)+(*y); }
|
||||||
|
accelerator_inline void mult(Integer * __restrict__ y,const Integer * __restrict__ l,const Integer *__restrict__ r){ *y = (*l) * (*r); }
|
||||||
|
accelerator_inline void sub (Integer * __restrict__ y,const Integer * __restrict__ l,const Integer *__restrict__ r){ *y = (*l) - (*r); }
|
||||||
|
accelerator_inline void add (Integer * __restrict__ y,const Integer * __restrict__ l,const Integer *__restrict__ r){ *y = (*l) + (*r); }
|
||||||
|
accelerator_inline void vstream(Integer &l, const RealD &r){ l=r;}
|
||||||
|
template<> accelerator_inline void zeroit(Integer &arg) { arg=0; };
|
||||||
|
|
||||||
|
accelerator_inline Integer mod (Integer a,Integer y) { return a%y;}
|
||||||
|
accelerator_inline Integer div (Integer a,Integer y) { return a/y;}
|
||||||
|
//accelerator_inline Integer abs (Integer &a) { return a%y;}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// Permute
|
||||||
|
// Permute 0 every ABCDEFGH -> BA DC FE HG
|
||||||
|
// Permute 1 every ABCDEFGH -> CD AB GH EF
|
||||||
|
// Permute 2 every ABCDEFGH -> EFGH ABCD
|
||||||
|
// Permute 3 possible on longer iVector lengths (512bit = 8 double = 16 single)
|
||||||
|
// Permute 4 possible on half precision @512bit vectors.
|
||||||
|
//
|
||||||
|
// Defined inside SIMD specialization files
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
template<class VectorSIMD> accelerator_inline void Gpermute(VectorSIMD &y,const VectorSIMD &b,int perm);
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
@@ -0,0 +1,568 @@
|
|||||||
|
#pragma once
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
template <class Scalar_type>
|
||||||
|
class Grid_simd1 {
|
||||||
|
public:
|
||||||
|
typedef typename RealPart<Scalar_type>::type Real;
|
||||||
|
typedef Scalar_type vector_type;
|
||||||
|
typedef Scalar_type scalar_type;
|
||||||
|
|
||||||
|
vector_type v;
|
||||||
|
|
||||||
|
static accelerator_inline constexpr int Nsimd(void) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
accelerator_inline Grid_simd1 &operator=(const Grid_simd1 &&rhs) {
|
||||||
|
v = rhs.v;
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
accelerator_inline Grid_simd1 &operator=(const Grid_simd1 &rhs) {
|
||||||
|
v = rhs.v;
|
||||||
|
return *this;
|
||||||
|
}; // faster than not declaring it and leaving to the compiler
|
||||||
|
|
||||||
|
accelerator Grid_simd1() = default;
|
||||||
|
accelerator_inline Grid_simd1(const Grid_simd1 &rhs) : v(rhs.v){}; // compiles in movaps
|
||||||
|
accelerator_inline Grid_simd1(const Grid_simd1 &&rhs) : v(rhs.v){};
|
||||||
|
|
||||||
|
accelerator_inline Grid_simd1(const Real a) { v=Scalar_type(a); };
|
||||||
|
|
||||||
|
template <typename S = Scalar_type> accelerator_inline
|
||||||
|
Grid_simd1(const typename std::enable_if<is_complex<S>::value, S>::type a) {
|
||||||
|
v=Scalar_type(a);
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
// Constructors
|
||||||
|
/////////////////////////////
|
||||||
|
accelerator_inline Grid_simd1 & operator=(const Zero &z) {
|
||||||
|
v=scalar_type(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// mac, mult, sub, add, adj
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
|
||||||
|
friend accelerator_inline void mac(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ a,
|
||||||
|
const Grid_simd1 *__restrict__ x) {
|
||||||
|
*y = (*a) * (*x) + (*y);
|
||||||
|
};
|
||||||
|
|
||||||
|
friend accelerator_inline void mult(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ l,
|
||||||
|
const Grid_simd1 *__restrict__ r) {
|
||||||
|
*y = (*l) * (*r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend accelerator_inline void sub(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ l,
|
||||||
|
const Grid_simd1 *__restrict__ r) {
|
||||||
|
*y = (*l) - (*r);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void add(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ l,
|
||||||
|
const Grid_simd1 *__restrict__ r) {
|
||||||
|
*y = (*l) + (*r);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void mac(Grid_simd1 *__restrict__ y,
|
||||||
|
const Scalar_type *__restrict__ a,
|
||||||
|
const Grid_simd1 *__restrict__ x) {
|
||||||
|
*y = (*a) * (*x) + (*y);
|
||||||
|
};
|
||||||
|
friend accelerator_inline void mult(Grid_simd1 *__restrict__ y,
|
||||||
|
const Scalar_type *__restrict__ l,
|
||||||
|
const Grid_simd1 *__restrict__ r) {
|
||||||
|
*y = (*l) * (*r);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void sub(Grid_simd1 *__restrict__ y,
|
||||||
|
const Scalar_type *__restrict__ l,
|
||||||
|
const Grid_simd1 *__restrict__ r) {
|
||||||
|
*y = (*l) - (*r);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void add(Grid_simd1 *__restrict__ y,
|
||||||
|
const Scalar_type *__restrict__ l,
|
||||||
|
const Grid_simd1 *__restrict__ r) {
|
||||||
|
*y = (*l) + (*r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend accelerator_inline void mac(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ a,
|
||||||
|
const Scalar_type *__restrict__ x) {
|
||||||
|
*y = (*a) * (*x) + (*y);
|
||||||
|
};
|
||||||
|
friend accelerator_inline void mult(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ l,
|
||||||
|
const Scalar_type *__restrict__ r) {
|
||||||
|
*y = (*l) * (*r);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void sub(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ l,
|
||||||
|
const Scalar_type *__restrict__ r) {
|
||||||
|
*y = (*l) - (*r);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void add(Grid_simd1 *__restrict__ y,
|
||||||
|
const Grid_simd1 *__restrict__ l,
|
||||||
|
const Scalar_type *__restrict__ r) {
|
||||||
|
*y = (*l) + (*r);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// FIXME: gonna remove these load/store, get, set, prefetch
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
friend accelerator_inline void vset(Grid_simd1 &ret, Scalar_type *a) {
|
||||||
|
ret.v = *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Vstore
|
||||||
|
///////////////////////
|
||||||
|
friend accelerator_inline void vstore(const Grid_simd1 &ret, Scalar_type *a) {
|
||||||
|
*a=ret.v;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Vprefetch
|
||||||
|
///////////////////////
|
||||||
|
friend accelerator_inline void vprefetch(const Grid_simd1 &v) { }
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Reduce
|
||||||
|
///////////////////////
|
||||||
|
friend accelerator_inline Scalar_type Reduce(const Grid_simd1 &in) {
|
||||||
|
return in.v;
|
||||||
|
}
|
||||||
|
////////////////////////////
|
||||||
|
// operator scalar * simd
|
||||||
|
////////////////////////////
|
||||||
|
friend accelerator_inline Grid_simd1 operator*(const Scalar_type &a, Grid_simd1 b) {
|
||||||
|
Grid_simd1 va;
|
||||||
|
va.v=a;
|
||||||
|
return va * b;
|
||||||
|
}
|
||||||
|
friend accelerator_inline Grid_simd1 operator*(Grid_simd1 b, const Scalar_type &a) {
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// Divides
|
||||||
|
//////////////////////////////////
|
||||||
|
friend accelerator_inline Grid_simd1 operator/(const Scalar_type &a, Grid_simd1 b) {
|
||||||
|
Grid_simd1 va;
|
||||||
|
va.v = a;
|
||||||
|
return va / b;
|
||||||
|
}
|
||||||
|
friend accelerator_inline Grid_simd1 operator/(Grid_simd1 b, const Scalar_type &a) {
|
||||||
|
Grid_simd1 va;
|
||||||
|
va.v=a;
|
||||||
|
return b / va;
|
||||||
|
}
|
||||||
|
///////////////////////
|
||||||
|
// Unary negation
|
||||||
|
///////////////////////
|
||||||
|
friend accelerator_inline Grid_simd1 operator-(const Grid_simd1 &r) {
|
||||||
|
Grid_simd1 ret;
|
||||||
|
ret.v = scalar_type(0);
|
||||||
|
ret = ret - r;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// *=,+=,-= operators
|
||||||
|
accelerator_inline Grid_simd1 &operator*=(const Grid_simd1 &r) {
|
||||||
|
*this = (*this) * r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
accelerator_inline Grid_simd1 &operator+=(const Grid_simd1 &r) {
|
||||||
|
*this = *this + r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
accelerator_inline Grid_simd1 &operator-=(const Grid_simd1 &r) {
|
||||||
|
*this = *this - r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Not all functions are supported
|
||||||
|
// through SIMD and must breakout to
|
||||||
|
// scalar type and back again. This
|
||||||
|
// provides support
|
||||||
|
///////////////////////////////////////
|
||||||
|
|
||||||
|
template <class functor>
|
||||||
|
friend accelerator_inline Grid_simd1 SimdApply(const functor &func, const Grid_simd1 &v) {
|
||||||
|
Grid_simd1 ret;
|
||||||
|
ret.v = func(v.v);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template <class functor>
|
||||||
|
friend accelerator_inline Grid_simd1 SimdApplyBinop(const functor &func,
|
||||||
|
const Grid_simd1 &x,
|
||||||
|
const Grid_simd1 &y) {
|
||||||
|
Grid_simd1 ret;
|
||||||
|
ret.v = func(x.v,y.v);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
///////////////////////
|
||||||
|
// Exchange
|
||||||
|
// Al Ah , Bl Bh -> Al Bl Ah,Bh
|
||||||
|
///////////////////////
|
||||||
|
friend accelerator_inline void exchange(Grid_simd1 &out1,Grid_simd1 &out2,Grid_simd1 in1,Grid_simd1 in2,int n)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void exchange0(Grid_simd1 &out1,Grid_simd1 &out2,Grid_simd1 in1,Grid_simd1 in2){
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void exchange1(Grid_simd1 &out1,Grid_simd1 &out2,Grid_simd1 in1,Grid_simd1 in2){
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void exchange2(Grid_simd1 &out1,Grid_simd1 &out2,Grid_simd1 in1,Grid_simd1 in2){
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void exchange3(Grid_simd1 &out1,Grid_simd1 &out2,Grid_simd1 in1,Grid_simd1 in2){
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Permute: unreachable at Nsimd=1
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
friend accelerator_inline void permute0(Grid_simd1 &y, Grid_simd1 b) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void permute1(Grid_simd1 &y, Grid_simd1 b) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void permute2(Grid_simd1 &y, Grid_simd1 b) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void permute3(Grid_simd1 &y, Grid_simd1 b) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
friend accelerator_inline void permute(Grid_simd1 &y, Grid_simd1 b, int perm) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// Getting single lanes
|
||||||
|
///////////////////////////////
|
||||||
|
accelerator_inline Scalar_type getlane(int lane) const {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
accelerator_inline void putlane(const Scalar_type &S, int lane){
|
||||||
|
v=S;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
template <class Scalar>
|
||||||
|
inline std::ostream& operator<< (std::ostream& stream, const Grid_simd1<Scalar> &o){
|
||||||
|
stream<<"<"<<o.v<<">";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Grid_simd1<RealF> sRealF;
|
||||||
|
typedef Grid_simd1<RealD> sRealD;
|
||||||
|
typedef Grid_simd1<ComplexF> sComplexF;
|
||||||
|
typedef Grid_simd1<ComplexD> sComplexD;
|
||||||
|
typedef Grid_simd1<Integer> sInteger;
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
// Permute
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
//accelerator_inline void permute(sComplexD &y,sComplexD b, int perm) { y=b; }
|
||||||
|
//accelerator_inline void permute(sComplexF &y,sComplexF b, int perm) { y=b; }
|
||||||
|
//accelerator_inline void permute(sRealD &y,sRealD b, int perm) { y=b; }
|
||||||
|
//accelerator_inline void permute(sRealF &y,sRealF b, int perm) { y=b; }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// General rotate
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
template <class S, IfNotComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> rotate(Grid_simd1<S> b, int nrot) { return b; }
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> rotate(Grid_simd1<S> b, int nrot) { return b; }
|
||||||
|
template <class S, IfNotComplex<S> =0>
|
||||||
|
accelerator_inline void rotate( Grid_simd1<S> &ret,Grid_simd1<S> b,int nrot)
|
||||||
|
{
|
||||||
|
ret = b;
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> =0>
|
||||||
|
accelerator_inline void rotate(Grid_simd1<S> &ret,Grid_simd1<S> b,int nrot)
|
||||||
|
{
|
||||||
|
ret = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline void vbroadcast(Grid_simd1<S> &ret,const Grid_simd1<S> &src,int lane){
|
||||||
|
ret = src;
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> =0>
|
||||||
|
accelerator_inline void rbroadcast(Grid_simd1<S> &ret,const Grid_simd1<S> &src,int lane){
|
||||||
|
ret.v = real(src.v);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Splat
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
// this is only for the complex version
|
||||||
|
template <class S, IfComplex<S> = 0, class ABtype>
|
||||||
|
accelerator_inline void vsplat(Grid_simd1<S> &ret, ABtype a, ABtype b) {
|
||||||
|
ret.v = S(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overload if complex
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline void vsplat(Grid_simd1<S> &ret, EnableIf<is_complex<S>, S> c) {
|
||||||
|
vsplat(ret, real(c), imag(c));
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline void rsplat(Grid_simd1<S> &ret, EnableIf<is_complex<S>, S> c) {
|
||||||
|
vsplat(ret, real(c), real(c));
|
||||||
|
}
|
||||||
|
// if real fill with a, if complex fill with a in the real part (first function
|
||||||
|
// above)
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline void vsplat(Grid_simd1<S> &ret, NotEnableIf<is_complex<S>, S> a) {
|
||||||
|
ret.v = a;
|
||||||
|
}
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// Initialise to 1,0,i for the correct types
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// For complex types
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void vone(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(1.0, 0.0));
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void vzero(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(0.0, 0.0));
|
||||||
|
} // use xor?
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void vcomplex_i(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void visign(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(1.0, -1.0));
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void vrsign(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(-1.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not complex overload here
|
||||||
|
template <class S, IfReal<S> = 0>
|
||||||
|
accelerator_inline void vone(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(1.0));
|
||||||
|
}
|
||||||
|
template <class S, IfReal<S> = 0>
|
||||||
|
accelerator_inline void vzero(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, S(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For integral types
|
||||||
|
template <class S, IfInteger<S> = 0>
|
||||||
|
accelerator_inline void vone(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, 1);
|
||||||
|
}
|
||||||
|
template <class S, IfInteger<S> = 0>
|
||||||
|
accelerator_inline void vzero(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, 0);
|
||||||
|
}
|
||||||
|
template <class S, IfInteger<S> = 0>
|
||||||
|
accelerator_inline void vtrue(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
template <class S, IfInteger<S> = 0>
|
||||||
|
accelerator_inline void vfalse(Grid_simd1<S> &ret) {
|
||||||
|
vsplat(ret, 0);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline void zeroit(Grid_simd1<S> &z) {
|
||||||
|
vzero(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Vstream
|
||||||
|
///////////////////////
|
||||||
|
template <class S, IfReal<S> = 0>
|
||||||
|
accelerator_inline void vstream(Grid_simd1<S> &out, const Grid_simd1<S> &in) {
|
||||||
|
out = in;
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void vstream(Grid_simd1<S> &out, const Grid_simd1<S> &in) {
|
||||||
|
out = in;
|
||||||
|
}
|
||||||
|
template <class S, IfInteger<S> = 0>
|
||||||
|
accelerator_inline void vstream(Grid_simd1<S> &out, const Grid_simd1<S> &in) {
|
||||||
|
out = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////
|
||||||
|
// Arithmetic operator overloads +,-,*
|
||||||
|
////////////////////////////////////
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> operator+(Grid_simd1<S> a, Grid_simd1<S> b) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
ret.v = a.v+b.v;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> operator-(Grid_simd1<S> a, Grid_simd1<S> b) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
ret.v = a.v-b.v;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Distinguish between complex types and others
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> real_mult(Grid_simd1<S> a, Grid_simd1<S> b) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
ret.v = S(real(a.v)*real(b.v),real(a.v)*imag(b.v));
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> real_madd(Grid_simd1<S> a, Grid_simd1<S> b, Grid_simd1<S> c) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
ret = real_mult(a,b) + c;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Distinguish between complex types and others
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> operator*(Grid_simd1<S> a, Grid_simd1<S> b) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
#ifndef STRICT_COMPLEX_MUL
|
||||||
|
// Direct product, matching the vector types. std::complex adds an inf/NaN
|
||||||
|
// recovery branch. Define STRICT_COMPLEX_MUL to restore std::complex.
|
||||||
|
if constexpr ( is_complex<S>::value ) {
|
||||||
|
ret.v = S(real(a.v)*real(b.v) - imag(a.v)*imag(b.v),
|
||||||
|
real(a.v)*imag(b.v) + imag(a.v)*real(b.v));
|
||||||
|
} else {
|
||||||
|
ret.v = a.v*b.v;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ret.v = a.v*b.v;
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
///////////////////////
|
||||||
|
// Conjugate
|
||||||
|
///////////////////////
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> conjugate(const Grid_simd1<S> &in) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
ret.v = S(real(in.v),-imag(in.v));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template <class S, IfNotComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> conjugate(const Grid_simd1<S> &in) {
|
||||||
|
return in; // for real objects
|
||||||
|
}
|
||||||
|
// Suppress adj for integer types... // odd; why conjugate above but not adj??
|
||||||
|
template <class S, IfNotInteger<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> adj(const Grid_simd1<S> &in) {
|
||||||
|
return conjugate(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// timesMinusI
|
||||||
|
///////////////////////
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void timesMinusI(Grid_simd1<S> &ret, const Grid_simd1<S> &in) {
|
||||||
|
ret.v = S(imag(in.v),-real(in.v));
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> timesMinusI(const Grid_simd1<S> &in) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
timesMinusI(ret,in);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template <class S, IfNotComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> timesMinusI(const Grid_simd1<S> &in) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
///////////////////////
|
||||||
|
// timesI
|
||||||
|
///////////////////////
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline void timesI(Grid_simd1<S> &ret, const Grid_simd1<S> &in) {
|
||||||
|
ret.v = S(-imag(in.v),real(in.v));
|
||||||
|
}
|
||||||
|
template <class S, IfComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> timesI(const Grid_simd1<S> &in) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
timesI(ret,in);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template <class S, IfNotComplex<S> = 0>
|
||||||
|
accelerator_inline Grid_simd1<S> timesI(const Grid_simd1<S> &in) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distinguish between complex types and others
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> operator/(Grid_simd1<S> a, Grid_simd1<S> b) {
|
||||||
|
Grid_simd1<S> ret;
|
||||||
|
ret.v = a.v/b.v;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// Inner, outer
|
||||||
|
/////////////////////
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> innerProduct(const Grid_simd1<S> &l,const Grid_simd1<S> &r) {
|
||||||
|
return conjugate(l) * r;
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> outerProduct(const Grid_simd1<S> &l,const Grid_simd1<S> &r) {
|
||||||
|
return l * conjugate(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> trace(const Grid_simd1<S> &arg) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// copy/splat complex real parts into real;
|
||||||
|
// insert real into complex and zero imag;
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
accelerator_inline sRealF toReal(const sComplexF &in) {
|
||||||
|
sRealF ret;
|
||||||
|
ret.v=real(in.v);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
accelerator_inline sRealD toReal(const sComplexD &in) {
|
||||||
|
sRealD ret;
|
||||||
|
ret.v=real(in.v);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
accelerator_inline sComplexF toComplex(sRealF &in)
|
||||||
|
{
|
||||||
|
sComplexF ret;
|
||||||
|
ret.v = in.v;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
accelerator_inline sComplexD toComplex(sRealD &in)
|
||||||
|
{
|
||||||
|
sComplexD ret;
|
||||||
|
ret.v = in.v;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
accelerator_inline void precisionChange(sRealF *out,const sRealD *in,int nvec){ assert(nvec==1); out->v = in->v;}
|
||||||
|
accelerator_inline void precisionChange(sRealD *out,const sRealF *in,int nvec){ assert(nvec==1); out->v = in->v;}
|
||||||
|
accelerator_inline void precisionChange(sComplexF *out,const sComplexD *in,int nvec){ assert(nvec==1); out->v = in->v;}
|
||||||
|
accelerator_inline void precisionChange(sComplexD *out,const sComplexF *in,int nvec){ assert(nvec==1); out->v = in->v;}
|
||||||
|
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
/////////////
|
||||||
|
// Unary operations
|
||||||
|
/////////////
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> real(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(RealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> imag(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(ImagFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> sqrt(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(SqrtRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> cos(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(CosRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> sin(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(SinRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> acos(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(AcosRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> asin(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(AsinRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> log(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(LogRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> abs(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(AbsRealFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> exp(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(ExpFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> Not(const Grid_simd1<S> &r) {
|
||||||
|
return SimdApply(NotFunctor<S>(), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> pow(const Grid_simd1<S> &r, double y) {
|
||||||
|
return SimdApply(PowRealFunctor<S>(y), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> mod(const Grid_simd1<S> &r, Integer y) {
|
||||||
|
return SimdApply(ModIntFunctor<S>(y), r);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline Grid_simd1<S> div(const Grid_simd1<S> &r, Integer y) {
|
||||||
|
return SimdApply(DivIntFunctor<S>(y), r);
|
||||||
|
}
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
+11
-106
@@ -36,8 +36,7 @@ Author: Michael Marshall <michael.marshall@ed.ac.au>
|
|||||||
*/
|
*/
|
||||||
// Time-stamp: <2015-07-10 17:45:33 neo>
|
// Time-stamp: <2015-07-10 17:45:33 neo>
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
#ifndef GRID_VECTOR_TYPES
|
#pragma once
|
||||||
#define GRID_VECTOR_TYPES
|
|
||||||
|
|
||||||
// PAB - Lifted and adapted from Eigen, which is GPL V2
|
// PAB - Lifted and adapted from Eigen, which is GPL V2
|
||||||
struct Grid_half {
|
struct Grid_half {
|
||||||
@@ -169,78 +168,6 @@ accelerator_inline Grid_half sfw_float_to_half(float ff) {
|
|||||||
|
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
|
||||||
// To take the floating point type of real/complex type
|
|
||||||
//////////////////////////////////////
|
|
||||||
template <typename T>
|
|
||||||
struct RealPart {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
template <typename T>
|
|
||||||
struct RealPart<complex<T> > {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
|
||||||
// demote a vector to real type
|
|
||||||
//////////////////////////////////////
|
|
||||||
// type alias used to simplify the syntax of std::enable_if
|
|
||||||
template <typename T> using Invoke = typename T::type;
|
|
||||||
template <typename Condition, typename ReturnType = void> using EnableIf = Invoke<std::enable_if<Condition::value, ReturnType> >;
|
|
||||||
template <typename Condition, typename ReturnType = void> using NotEnableIf = Invoke<std::enable_if<!Condition::value, ReturnType> >;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
// Check for complexity with type traits
|
|
||||||
template <typename T> struct is_complex : public std::false_type {};
|
|
||||||
template <> struct is_complex<ComplexD> : public std::true_type {};
|
|
||||||
template <> struct is_complex<ComplexF> : public std::true_type {};
|
|
||||||
|
|
||||||
template <typename T> struct is_ComplexD : public std::false_type {};
|
|
||||||
template <> struct is_ComplexD<ComplexD> : public std::true_type {};
|
|
||||||
|
|
||||||
template <typename T> struct is_ComplexF : public std::false_type {};
|
|
||||||
template <> struct is_ComplexF<ComplexF> : public std::true_type {};
|
|
||||||
|
|
||||||
template<typename T, typename V=void> struct is_real : public std::false_type {};
|
|
||||||
template<typename T> struct is_real<T, typename std::enable_if<std::is_floating_point<T>::value,
|
|
||||||
void>::type> : public std::true_type {};
|
|
||||||
|
|
||||||
template<typename T, typename V=void> struct is_integer : public std::false_type {};
|
|
||||||
template<typename T> struct is_integer<T, typename std::enable_if<std::is_integral<T>::value,
|
|
||||||
void>::type> : public std::true_type {};
|
|
||||||
|
|
||||||
template <typename T> using IfReal = Invoke<std::enable_if<is_real<T>::value, int> >;
|
|
||||||
template <typename T> using IfComplex = Invoke<std::enable_if<is_complex<T>::value, int> >;
|
|
||||||
template <typename T> using IfInteger = Invoke<std::enable_if<is_integer<T>::value, int> >;
|
|
||||||
template <typename T1,typename T2> using IfSame = Invoke<std::enable_if<std::is_same<T1,T2>::value, int> >;
|
|
||||||
|
|
||||||
template <typename T> using IfNotReal = Invoke<std::enable_if<!is_real<T>::value, int> >;
|
|
||||||
template <typename T> using IfNotComplex = Invoke<std::enable_if<!is_complex<T>::value, int> >;
|
|
||||||
template <typename T> using IfNotInteger = Invoke<std::enable_if<!is_integer<T>::value, int> >;
|
|
||||||
template <typename T1,typename T2> using IfNotSame = Invoke<std::enable_if<!std::is_same<T1,T2>::value, int> >;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
// Define the operation templates functors
|
|
||||||
// general forms to allow for vsplat syntax
|
|
||||||
// need explicit declaration of types when used since
|
|
||||||
// clang cannot automatically determine the output type sometimes
|
|
||||||
template <class Out, class Input1, class Input2, class Input3, class Operation>
|
|
||||||
Out accelerator_inline trinary(Input1 src_1, Input2 src_2, Input3 src_3, Operation op) {
|
|
||||||
return op(src_1, src_2, src_3);
|
|
||||||
}
|
|
||||||
template <class Out, class Input1, class Input2, class Operation>
|
|
||||||
Out accelerator_inline binary(Input1 src_1, Input2 src_2, Operation op) {
|
|
||||||
return op(src_1, src_2);
|
|
||||||
}
|
|
||||||
template <class Out, class Input, class Operation>
|
|
||||||
Out accelerator_inline unary(Input src, Operation op) {
|
|
||||||
return op(src);
|
|
||||||
}
|
|
||||||
///////////////////////////////////////////////
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@brief Grid_simd class for the SIMD vector type operations
|
@brief Grid_simd class for the SIMD vector type operations
|
||||||
*/
|
*/
|
||||||
@@ -378,11 +305,18 @@ public:
|
|||||||
|
|
||||||
// FIXME -- alias this to an accelerator_inline MAC struct.
|
// FIXME -- alias this to an accelerator_inline MAC struct.
|
||||||
|
|
||||||
#if defined(A64FX) || defined(A64FXFIXEDSIZE)
|
#ifdef GRID_ARCH_HAS_COMPLEX_MULT_ADD
|
||||||
|
// Architecture has a fused complex multiply-add (FCMLA and friends).
|
||||||
|
// Defining GRID_ARCH_HAS_COMPLEX_MULT_ADD asserts BOTH MultAddComplexSIMD
|
||||||
|
// and a three argument MultSIMD operator() computing a*b+c.
|
||||||
friend accelerator_inline void mac(Grid_simd *__restrict__ y,
|
friend accelerator_inline void mac(Grid_simd *__restrict__ y,
|
||||||
const Grid_simd *__restrict__ a,
|
const Grid_simd *__restrict__ a,
|
||||||
const Grid_simd *__restrict__ x) {
|
const Grid_simd *__restrict__ x) {
|
||||||
*y = fxmac((*a), (*x), (*y));
|
if constexpr ( is_complex<Scalar_type>::value ) {
|
||||||
|
y->v = trinary<Vector_type>(a->v, x->v, y->v, MultAddComplexSIMD());
|
||||||
|
} else {
|
||||||
|
y->v = trinary<Vector_type>(a->v, x->v, y->v, MultSIMD());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
friend accelerator_inline void mac(Grid_simd *__restrict__ y,
|
friend accelerator_inline void mac(Grid_simd *__restrict__ y,
|
||||||
@@ -670,7 +604,6 @@ typedef Grid_simd<complex<uint16_t>, SIMD_Htype> vComplexH;
|
|||||||
typedef Grid_simd<complex<float> , SIMD_Ftype> vComplexF;
|
typedef Grid_simd<complex<float> , SIMD_Ftype> vComplexF;
|
||||||
typedef Grid_simd<complex<double> , SIMD_Dtype> vComplexD;
|
typedef Grid_simd<complex<double> , SIMD_Dtype> vComplexD;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
// Pointer type to use on extractLane
|
// Pointer type to use on extractLane
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
@@ -885,25 +818,7 @@ accelerator_inline Grid_simd<S, V> operator*(Grid_simd<S, V> a, Grid_simd<S, V>
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------- A64FX MAC -------------------
|
// mac() selects MultAddComplexSIMD directly where the architecture has it.
|
||||||
// Distinguish between complex types and others
|
|
||||||
#if defined(A64FX) || defined(A64FXFIXEDSIZE)
|
|
||||||
template <class S, class V, IfComplex<S> = 0>
|
|
||||||
accelerator_inline Grid_simd<S, V> fxmac(Grid_simd<S, V> a, Grid_simd<S, V> b, Grid_simd<S, V> c) {
|
|
||||||
Grid_simd<S, V> ret;
|
|
||||||
ret.v = trinary<V>(a.v, b.v, c.v, MultAddComplexSIMD());
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Real/Integer types
|
|
||||||
template <class S, class V, IfNotComplex<S> = 0>
|
|
||||||
accelerator_inline Grid_simd<S, V> fxmac(Grid_simd<S, V> a, Grid_simd<S, V> b, Grid_simd<S, V> c) {
|
|
||||||
Grid_simd<S, V> ret;
|
|
||||||
ret.v = trinary<V>(a.v, b.v, c.v, MultSIMD());
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
// ----------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@@ -1141,13 +1056,3 @@ template<class vobj> void gpermute(vobj & inout,int perm){
|
|||||||
|
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
#ifdef GRID_SYCL
|
|
||||||
template<> struct sycl::is_device_copyable<Grid::vComplexF> : public std::true_type {};
|
|
||||||
template<> struct sycl::is_device_copyable<Grid::vComplexD> : public std::true_type {};
|
|
||||||
template<> struct sycl::is_device_copyable<Grid::vRealF > : public std::true_type {};
|
|
||||||
template<> struct sycl::is_device_copyable<Grid::vRealD > : public std::true_type {};
|
|
||||||
template<> struct sycl::is_device_copyable<Grid::vInteger > : public std::true_type {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
+139
-184
@@ -28,208 +28,163 @@ See the full license in the file "LICENSE" in the top level distribution
|
|||||||
directory
|
directory
|
||||||
*************************************************************************************/
|
*************************************************************************************/
|
||||||
/* END LEGAL */
|
/* END LEGAL */
|
||||||
#ifndef GRID_SIMD_H
|
#pragma once
|
||||||
#define GRID_SIMD_H
|
|
||||||
|
|
||||||
#if defined(GRID_CUDA) || defined(GRID_HIP)
|
#include <type_traits>
|
||||||
#include <thrust/complex.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
#include <Grid/simd/Grid_scalar_support.h>
|
||||||
// Define scalar and vector floating point types
|
|
||||||
//
|
|
||||||
// Scalar: RealF, RealD, ComplexF, ComplexD
|
|
||||||
//
|
|
||||||
// Vector: vRealF, vRealD, vComplexF, vComplexD
|
|
||||||
//
|
|
||||||
// Vector types are arch dependent
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#define _MM_SELECT_FOUR_FOUR(A,B,C,D) ((A<<6)|(B<<4)|(C<<2)|(D))
|
|
||||||
#define _MM_SELECT_FOUR_FOUR_STRING(A,B,C,D) "((" #A "<<6)|(" #B "<<4)|(" #C "<<2)|(" #D "))"
|
|
||||||
#define _MM_SELECT_EIGHT_TWO(A,B,C,D,E,F,G,H) ((A<<7)|(B<<6)|(C<<5)|(D<<4)|(E<<3)|(F<<2)|(G<<4)|(H))
|
|
||||||
#define _MM_SELECT_FOUR_TWO (A,B,C,D) _MM_SELECT_EIGHT_TWO(0,0,0,0,A,B,C,D)
|
|
||||||
#define _MM_SELECT_TWO_TWO (A,B) _MM_SELECT_FOUR_TWO(0,0,A,B)
|
|
||||||
|
|
||||||
#define RotateBit (0x100)
|
|
||||||
|
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
//////////////////////////////////////
|
||||||
typedef uint32_t Integer;
|
// To take the floating point type of real/complex type
|
||||||
|
//////////////////////////////////////
|
||||||
typedef float RealF;
|
template <typename T>
|
||||||
typedef double RealD;
|
struct RealPart {
|
||||||
#ifdef GRID_DEFAULT_PRECISION_DOUBLE
|
typedef T type;
|
||||||
typedef RealD Real;
|
};
|
||||||
#else
|
template <typename T>
|
||||||
typedef RealF Real;
|
struct RealPart<std::complex<T> > {
|
||||||
#endif
|
typedef T type;
|
||||||
|
};
|
||||||
#if defined(GRID_CUDA) || defined(GRID_HIP)
|
|
||||||
typedef thrust::complex<RealF> ComplexF;
|
|
||||||
typedef thrust::complex<RealD> ComplexD;
|
|
||||||
typedef thrust::complex<Real> Complex;
|
|
||||||
typedef thrust::complex<uint16_t> ComplexH;
|
|
||||||
template<class T> using complex = thrust::complex<T>;
|
|
||||||
|
|
||||||
accelerator_inline ComplexD pow(const ComplexD& r,RealD y){ return(thrust::pow(r,(double)y)); }
|
|
||||||
accelerator_inline ComplexF pow(const ComplexF& r,RealF y){ return(thrust::pow(r,(float)y)); }
|
|
||||||
#else
|
|
||||||
typedef std::complex<RealF> ComplexF;
|
|
||||||
typedef std::complex<RealD> ComplexD;
|
|
||||||
typedef std::complex<Real> Complex;
|
|
||||||
typedef std::complex<uint16_t> ComplexH; // Hack
|
|
||||||
template<class T> using complex = std::complex<T>;
|
|
||||||
|
|
||||||
accelerator_inline ComplexD pow(const ComplexD& r,RealD y){ return(std::pow(r,y)); }
|
|
||||||
accelerator_inline ComplexF pow(const ComplexF& r,RealF y){ return(std::pow(r,y)); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//accelerator_inline RealD pow(const RealD& r,RealD y){ return(std::pow(r,y)); }
|
|
||||||
//accelerator_inline RealD sqrt(const RealD & r){ return std::sqrt(r); }
|
|
||||||
|
|
||||||
// This comes from ::pow already from math.h and CUDA
|
|
||||||
// Calls either Grid::pow for complex, or std::pow for real
|
|
||||||
// Problem is CUDA math_functions is exposing ::pow, and I can't define
|
|
||||||
|
|
||||||
using std::abs;
|
|
||||||
using std::pow;
|
|
||||||
using std::sqrt;
|
|
||||||
using std::log;
|
|
||||||
using std::exp;
|
|
||||||
using std::sin;
|
|
||||||
using std::cos;
|
|
||||||
using std::asin;
|
|
||||||
using std::acos;
|
|
||||||
|
|
||||||
|
|
||||||
accelerator_inline RealF conjugate(const RealF & r){ return r; }
|
// type alias used to simplify the syntax of std::enable_if
|
||||||
accelerator_inline RealD conjugate(const RealD & r){ return r; }
|
template <typename T> using Invoke = typename T::type;
|
||||||
accelerator_inline ComplexD conjugate(const ComplexD& r){ return(conj(r)); }
|
template <typename Condition, typename ReturnType = void> using EnableIf = Invoke<std::enable_if<Condition::value, ReturnType> >;
|
||||||
accelerator_inline ComplexF conjugate(const ComplexF& r ){ return(conj(r)); }
|
template <typename Condition, typename ReturnType = void> using NotEnableIf = Invoke<std::enable_if<!Condition::value, ReturnType> >;
|
||||||
|
|
||||||
accelerator_inline RealF adj(const RealF & r){ return r; }
|
////////////////////////////////////////////////////////
|
||||||
accelerator_inline RealD adj(const RealD & r){ return r; }
|
// Check for complexity with type traits
|
||||||
accelerator_inline ComplexD adj(const ComplexD& r){ return(conjugate(r)); }
|
template <typename T> struct is_complex : public std::false_type {};
|
||||||
accelerator_inline ComplexF adj(const ComplexF& r ){ return(conjugate(r)); }
|
template <> struct is_complex<ComplexD> : public std::true_type {};
|
||||||
|
template <> struct is_complex<ComplexF> : public std::true_type {};
|
||||||
|
|
||||||
accelerator_inline RealF real(const RealF & r){ return r; }
|
template <typename T> struct is_ComplexD : public std::false_type {};
|
||||||
accelerator_inline RealD real(const RealD & r){ return r; }
|
template <> struct is_ComplexD<ComplexD> : public std::true_type {};
|
||||||
accelerator_inline RealF real(const ComplexF & r){ return r.real(); }
|
|
||||||
accelerator_inline RealD real(const ComplexD & r){ return r.real(); }
|
|
||||||
|
|
||||||
accelerator_inline RealF imag(const ComplexF & r){ return r.imag(); }
|
template <typename T> struct is_ComplexF : public std::false_type {};
|
||||||
accelerator_inline RealD imag(const ComplexD & r){ return r.imag(); }
|
template <> struct is_ComplexF<ComplexF> : public std::true_type {};
|
||||||
|
|
||||||
accelerator_inline ComplexD innerProduct(const ComplexD & l, const ComplexD & r) { return conjugate(l)*r; }
|
template<typename T, typename V=void> struct is_real : public std::false_type {};
|
||||||
accelerator_inline ComplexF innerProduct(const ComplexF & l, const ComplexF & r) { return conjugate(l)*r; }
|
template<typename T> struct is_real<T, typename std::enable_if<std::is_floating_point<T>::value,
|
||||||
accelerator_inline RealD innerProduct(const RealD & l, const RealD & r) { return l*r; }
|
void>::type> : public std::true_type {};
|
||||||
accelerator_inline RealF innerProduct(const RealF & l, const RealF & r) { return l*r; }
|
|
||||||
|
|
||||||
accelerator_inline ComplexD Reduce(const ComplexD& r){ return r; }
|
template<typename T, typename V=void> struct is_integer : public std::false_type {};
|
||||||
accelerator_inline ComplexF Reduce(const ComplexF& r){ return r; }
|
template<typename T> struct is_integer<T, typename std::enable_if<std::is_integral<T>::value,
|
||||||
accelerator_inline RealD Reduce(const RealD& r){ return r; }
|
void>::type> : public std::true_type {};
|
||||||
accelerator_inline RealF Reduce(const RealF& r){ return r; }
|
|
||||||
|
|
||||||
accelerator_inline RealD toReal(const ComplexD& r){ return r.real(); }
|
template <typename T> using IfReal = Invoke<std::enable_if<is_real<T>::value, int> >;
|
||||||
accelerator_inline RealF toReal(const ComplexF& r){ return r.real(); }
|
template <typename T> using IfComplex = Invoke<std::enable_if<is_complex<T>::value, int> >;
|
||||||
accelerator_inline RealD toReal(const RealD& r){ return r; }
|
template <typename T> using IfInteger = Invoke<std::enable_if<is_integer<T>::value, int> >;
|
||||||
accelerator_inline RealF toReal(const RealF& r){ return r; }
|
template <typename T1,typename T2> using IfSame = Invoke<std::enable_if<std::is_same<T1,T2>::value, int> >;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <typename T> using IfNotReal = Invoke<std::enable_if<!is_real<T>::value, int> >;
|
||||||
//Provide support functions for basic real and complex data types required by Grid
|
template <typename T> using IfNotComplex = Invoke<std::enable_if<!is_complex<T>::value, int> >;
|
||||||
//Single and double precision versions. Should be able to template this once only.
|
template <typename T> using IfNotInteger = Invoke<std::enable_if<!is_integer<T>::value, int> >;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <typename T1,typename T2> using IfNotSame = Invoke<std::enable_if<!std::is_same<T1,T2>::value, int> >;
|
||||||
accelerator_inline void mac (ComplexD * __restrict__ y,const ComplexD * __restrict__ a,const ComplexD *__restrict__ x){ *y = (*a) * (*x)+(*y); };
|
|
||||||
accelerator_inline void mult(ComplexD * __restrict__ y,const ComplexD * __restrict__ l,const ComplexD *__restrict__ r){ *y = (*l) * (*r);}
|
|
||||||
accelerator_inline void sub (ComplexD * __restrict__ y,const ComplexD * __restrict__ l,const ComplexD *__restrict__ r){ *y = (*l) - (*r);}
|
|
||||||
accelerator_inline void add (ComplexD * __restrict__ y,const ComplexD * __restrict__ l,const ComplexD *__restrict__ r){ *y = (*l) + (*r);}
|
|
||||||
// conjugate already supported for complex
|
|
||||||
|
|
||||||
accelerator_inline void mac (ComplexF * __restrict__ y,const ComplexF * __restrict__ a,const ComplexF *__restrict__ x){ *y = (*a) * (*x)+(*y); }
|
|
||||||
accelerator_inline void mult(ComplexF * __restrict__ y,const ComplexF * __restrict__ l,const ComplexF *__restrict__ r){ *y = (*l) * (*r); }
|
|
||||||
accelerator_inline void sub (ComplexF * __restrict__ y,const ComplexF * __restrict__ l,const ComplexF *__restrict__ r){ *y = (*l) - (*r); }
|
|
||||||
accelerator_inline void add (ComplexF * __restrict__ y,const ComplexF * __restrict__ l,const ComplexF *__restrict__ r){ *y = (*l) + (*r); }
|
|
||||||
|
|
||||||
//conjugate already supported for complex
|
|
||||||
accelerator_inline ComplexF timesI(const ComplexF &r) { return(ComplexF(-r.imag(),r.real()));}
|
|
||||||
accelerator_inline ComplexD timesI(const ComplexD &r) { return(ComplexD(-r.imag(),r.real()));}
|
|
||||||
accelerator_inline ComplexF timesMinusI(const ComplexF &r){ return(ComplexF(r.imag(),-r.real()));}
|
|
||||||
accelerator_inline ComplexD timesMinusI(const ComplexD &r){ return(ComplexD(r.imag(),-r.real()));}
|
|
||||||
//accelerator_inline ComplexF timesI(const ComplexF &r) { return(r*ComplexF(0.0,1.0));}
|
|
||||||
//accelerator_inline ComplexD timesI(const ComplexD &r) { return(r*ComplexD(0.0,1.0));}
|
|
||||||
//accelerator_inline ComplexF timesMinusI(const ComplexF &r){ return(r*ComplexF(0.0,-1.0));}
|
|
||||||
//accelerator_inline ComplexD timesMinusI(const ComplexD &r){ return(r*ComplexD(0.0,-1.0));}
|
|
||||||
|
|
||||||
// define projections to real and imaginay parts
|
|
||||||
accelerator_inline ComplexF projReal(const ComplexF &r){return( ComplexF(r.real(), 0.0));}
|
|
||||||
accelerator_inline ComplexD projReal(const ComplexD &r){return( ComplexD(r.real(), 0.0));}
|
|
||||||
accelerator_inline ComplexF projImag(const ComplexF &r){return (ComplexF(r.imag(), 0.0 ));}
|
|
||||||
accelerator_inline ComplexD projImag(const ComplexD &r){return (ComplexD(r.imag(), 0.0));}
|
|
||||||
|
|
||||||
// define auxiliary functions for complex computations
|
|
||||||
accelerator_inline void timesI(ComplexF &ret,const ComplexF &r) { ret = timesI(r);}
|
|
||||||
accelerator_inline void timesI(ComplexD &ret,const ComplexD &r) { ret = timesI(r);}
|
|
||||||
accelerator_inline void timesMinusI(ComplexF &ret,const ComplexF &r){ ret = timesMinusI(r);}
|
|
||||||
accelerator_inline void timesMinusI(ComplexD &ret,const ComplexD &r){ ret = timesMinusI(r);}
|
|
||||||
|
|
||||||
accelerator_inline void mac (RealD * __restrict__ y,const RealD * __restrict__ a,const RealD *__restrict__ x){ *y = (*a) * (*x)+(*y);}
|
|
||||||
accelerator_inline void mult(RealD * __restrict__ y,const RealD * __restrict__ l,const RealD *__restrict__ r){ *y = (*l) * (*r);}
|
|
||||||
accelerator_inline void sub (RealD * __restrict__ y,const RealD * __restrict__ l,const RealD *__restrict__ r){ *y = (*l) - (*r);}
|
|
||||||
accelerator_inline void add (RealD * __restrict__ y,const RealD * __restrict__ l,const RealD *__restrict__ r){ *y = (*l) + (*r);}
|
|
||||||
|
|
||||||
accelerator_inline void mac (RealF * __restrict__ y,const RealF * __restrict__ a,const RealF *__restrict__ x){ *y = (*a) * (*x)+(*y); }
|
|
||||||
accelerator_inline void mult(RealF * __restrict__ y,const RealF * __restrict__ l,const RealF *__restrict__ r){ *y = (*l) * (*r); }
|
|
||||||
accelerator_inline void sub (RealF * __restrict__ y,const RealF * __restrict__ l,const RealF *__restrict__ r){ *y = (*l) - (*r); }
|
|
||||||
accelerator_inline void add (RealF * __restrict__ y,const RealF * __restrict__ l,const RealF *__restrict__ r){ *y = (*l) + (*r); }
|
|
||||||
|
|
||||||
accelerator_inline void vstream(ComplexF &l, const ComplexF &r){ l=r;}
|
|
||||||
accelerator_inline void vstream(ComplexD &l, const ComplexD &r){ l=r;}
|
|
||||||
accelerator_inline void vstream(RealF &l, const RealF &r){ l=r;}
|
|
||||||
accelerator_inline void vstream(RealD &l, const RealD &r){ l=r;}
|
|
||||||
|
|
||||||
accelerator_inline ComplexD toComplex(const RealD &in) { return ComplexD(in);}
|
|
||||||
accelerator_inline ComplexF toComplex(const RealF &in) { return ComplexF(in);}
|
|
||||||
|
|
||||||
class Zero{};
|
|
||||||
//static Zero Zero();
|
|
||||||
template<class itype> accelerator_inline void zeroit(itype &arg) { arg=Zero();};
|
|
||||||
template<> accelerator_inline void zeroit(ComplexF &arg){ arg=0; };
|
|
||||||
template<> accelerator_inline void zeroit(ComplexD &arg){ arg=0; };
|
|
||||||
template<> accelerator_inline void zeroit(RealF &arg) { arg=0; };
|
|
||||||
template<> accelerator_inline void zeroit(RealD &arg) { arg=0; };
|
|
||||||
|
|
||||||
// More limited Integer support
|
|
||||||
accelerator_inline Integer Reduce(const Integer& r){ return r; }
|
|
||||||
accelerator_inline void mac (Integer * __restrict__ y,const Integer * __restrict__ a,const Integer *__restrict__ x){ *y = (*a) * (*x)+(*y); }
|
|
||||||
accelerator_inline void mult(Integer * __restrict__ y,const Integer * __restrict__ l,const Integer *__restrict__ r){ *y = (*l) * (*r); }
|
|
||||||
accelerator_inline void sub (Integer * __restrict__ y,const Integer * __restrict__ l,const Integer *__restrict__ r){ *y = (*l) - (*r); }
|
|
||||||
accelerator_inline void add (Integer * __restrict__ y,const Integer * __restrict__ l,const Integer *__restrict__ r){ *y = (*l) + (*r); }
|
|
||||||
accelerator_inline void vstream(Integer &l, const RealD &r){ l=r;}
|
|
||||||
template<> accelerator_inline void zeroit(Integer &arg) { arg=0; };
|
|
||||||
|
|
||||||
accelerator_inline Integer mod (Integer a,Integer y) { return a%y;}
|
|
||||||
accelerator_inline Integer div (Integer a,Integer y) { return a/y;}
|
|
||||||
//accelerator_inline Integer abs (Integer &a) { return a%y;}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
|
||||||
// Permute
|
|
||||||
// Permute 0 every ABCDEFGH -> BA DC FE HG
|
|
||||||
// Permute 1 every ABCDEFGH -> CD AB GH EF
|
|
||||||
// Permute 2 every ABCDEFGH -> EFGH ABCD
|
|
||||||
// Permute 3 possible on longer iVector lengths (512bit = 8 double = 16 single)
|
|
||||||
// Permute 4 possible on half precision @512bit vectors.
|
|
||||||
//
|
|
||||||
// Defined inside SIMD specialization files
|
|
||||||
//////////////////////////////////////////////////////////
|
|
||||||
template<class VectorSIMD>
|
|
||||||
accelerator_inline void Gpermute(VectorSIMD &y,const VectorSIMD &b,int perm);
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
// Define the operation templates functors
|
||||||
|
// general forms to allow for vsplat syntax
|
||||||
|
// need explicit declaration of types when used since
|
||||||
|
// clang cannot automatically determine the output type sometimes
|
||||||
|
template <class Out, class Input1, class Input2, class Input3, class Operation>
|
||||||
|
Out accelerator_inline trinary(Input1 src_1, Input2 src_2, Input3 src_3, Operation op) {
|
||||||
|
return op(src_1, src_2, src_3);
|
||||||
|
}
|
||||||
|
template <class Out, class Input1, class Input2, class Operation>
|
||||||
|
Out accelerator_inline binary(Input1 src_1, Input2 src_2, Operation op) {
|
||||||
|
return op(src_1, src_2);
|
||||||
|
}
|
||||||
|
template <class Out, class Input, class Operation>
|
||||||
|
Out accelerator_inline unary(Input src, Operation op) {
|
||||||
|
return op(src);
|
||||||
|
}
|
||||||
NAMESPACE_END(Grid);
|
NAMESPACE_END(Grid);
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
|
||||||
#include <Grid/simd/Grid_vector_types.h>
|
#include <Grid/simd/Grid_vector_types.h>
|
||||||
#include <Grid/simd/Grid_doubled_vector.h>
|
#include <Grid/simd/Grid_doubled_vector.h>
|
||||||
|
#include <Grid/simd/Grid_scalar_types.h>
|
||||||
|
|
||||||
|
#ifdef GRID_SYCL
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::vComplexF> : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::vComplexD> : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::vRealF > : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::vRealD > : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::vInteger > : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::sComplexF> : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::sComplexD> : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::sRealF > : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::sRealD > : public std::true_type {};
|
||||||
|
template<> struct sycl::is_device_copyable<Grid::sInteger > : public std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
// Detect vector types
|
||||||
|
/////////////////////////////////////////
|
||||||
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
template <typename T>
|
||||||
|
struct is_simd : public std::false_type {};
|
||||||
|
template <> struct is_simd<vRealF> : public std::true_type {};
|
||||||
|
template <> struct is_simd<vRealD> : public std::true_type {};
|
||||||
|
template <> struct is_simd<vRealH> : public std::true_type {};
|
||||||
|
template <> struct is_simd<vComplexF> : public std::true_type {};
|
||||||
|
template <> struct is_simd<vComplexD> : public std::true_type {};
|
||||||
|
template <> struct is_simd<vComplexH> : public std::true_type {};
|
||||||
|
template <> struct is_simd<vInteger> : public std::true_type {};
|
||||||
|
template <> struct is_simd<sRealF> : public std::true_type {};
|
||||||
|
template <> struct is_simd<sRealD> : public std::true_type {};
|
||||||
|
template <> struct is_simd<sComplexF> : public std::true_type {};
|
||||||
|
template <> struct is_simd<sComplexD> : public std::true_type {};
|
||||||
|
template <> struct is_simd<sInteger> : public std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> using IfSimd = Invoke<std::enable_if<is_simd<T>::value, int> >;
|
||||||
|
template <typename T> using IfNotSimd = Invoke<std::enable_if<!is_simd<T>::value, unsigned> >;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// insert / extract with complex support
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
template <class S, class V>
|
||||||
|
accelerator_inline S getlane(const Grid_simd<S, V> &in,int lane) {
|
||||||
|
return in.getlane(lane);
|
||||||
|
}
|
||||||
|
template <class S, class V>
|
||||||
|
accelerator_inline void putlane(Grid_simd<S, V> &vec,const S &_S, int lane){
|
||||||
|
vec.putlane(_S,lane);
|
||||||
|
}
|
||||||
|
template <class S,IfNotSimd<S> = 0 >
|
||||||
|
accelerator_inline S getlane(const S &in,int lane) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
template <class S,IfNotSimd<S> = 0 >
|
||||||
|
accelerator_inline void putlane(S &vec,const S &_S, int lane){
|
||||||
|
vec = _S;
|
||||||
|
}
|
||||||
|
template <class S, class V>
|
||||||
|
accelerator_inline S getlane(const Grid_simd2<S, V> &in,int lane) {
|
||||||
|
return in.getlane(lane);
|
||||||
|
}
|
||||||
|
template <class S, class V>
|
||||||
|
accelerator_inline void putlane(Grid_simd2<S, V> &vec,const S &_S, int lane){
|
||||||
|
vec.putlane(_S,lane);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline S getlane(const Grid_simd1<S> &in,int lane) {
|
||||||
|
return in.getlane(lane);
|
||||||
|
}
|
||||||
|
template <class S>
|
||||||
|
accelerator_inline void putlane(Grid_simd1<S> &vec,const S &_S, int lane){
|
||||||
|
vec.putlane(_S,lane);
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(Grid);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <Grid/simd/Grid_vector_unops.h>
|
#include <Grid/simd/Grid_vector_unops.h>
|
||||||
|
#include <Grid/simd/Grid_scalar_unops.h>
|
||||||
|
|
||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
|
|
||||||
@@ -309,4 +264,4 @@ inline std::ostream& operator<< (std::ostream& stream, const vInteger &o){
|
|||||||
}
|
}
|
||||||
|
|
||||||
NAMESPACE_END(Grid)
|
NAMESPACE_END(Grid)
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -163,6 +163,21 @@ accelerator_inline vRealD innerProductD(const vRealF &l,const vRealF &r)
|
|||||||
return innerProduct(la,ra) + innerProduct(lb,rb);
|
return innerProduct(la,ra) + innerProduct(lb,rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accelerator_inline sComplexD innerProductD(const sComplexD &l,const sComplexD &r){ return innerProduct(l,r); }
|
||||||
|
accelerator_inline sRealD innerProductD(const sRealD &l,const sRealD &r){ return innerProduct(l,r); }
|
||||||
|
accelerator_inline sComplexD innerProductD(const sComplexF &l,const sComplexF &r)
|
||||||
|
{
|
||||||
|
sComplexD ret;
|
||||||
|
ret.v = innerProduct(ComplexD(l.v),ComplexD(r.v));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
accelerator_inline sRealD innerProductD(const sRealF &l,const sRealF &r)
|
||||||
|
{
|
||||||
|
sRealD ret;
|
||||||
|
ret.v = innerProduct(RealD(l.v),RealD(r.v));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Now do it for vector, matrix, scalar
|
// Now do it for vector, matrix, scalar
|
||||||
template<class l,class r,int N> accelerator_inline
|
template<class l,class r,int N> accelerator_inline
|
||||||
auto innerProductD (const iVector<l,N>& lhs,const iVector<r,N>& rhs) -> iScalar<decltype(innerProductD(lhs._internal[0],rhs._internal[0]))>
|
auto innerProductD (const iVector<l,N>& lhs,const iVector<r,N>& rhs) -> iScalar<decltype(innerProductD(lhs._internal[0],rhs._internal[0]))>
|
||||||
@@ -212,6 +227,27 @@ accelerator_inline RealD innerProductD2(const RealF &l,const RealF &r){
|
|||||||
accelerator_inline vComplexD innerProductD2(const vComplexD &l,const vComplexD &r){ return innerProduct(l,r); }
|
accelerator_inline vComplexD innerProductD2(const vComplexD &l,const vComplexD &r){ return innerProduct(l,r); }
|
||||||
accelerator_inline vRealD innerProductD2(const vRealD &l,const vRealD &r){ return innerProduct(l,r); }
|
accelerator_inline vRealD innerProductD2(const vRealD &l,const vRealD &r){ return innerProduct(l,r); }
|
||||||
|
|
||||||
|
// Lex chart. D2 means double precision carried at the F type's Nsimd, so that
|
||||||
|
// both fit the same Grid; sComplexF and sComplexD are both Nsimd 1, so
|
||||||
|
// sComplexD2 would be sComplexD and no separate type is needed.
|
||||||
|
accelerator_inline sComplexD innerProductD2(const sComplexD &l,const sComplexD &r){ return innerProduct(l,r); }
|
||||||
|
accelerator_inline sRealD innerProductD2(const sRealD &l,const sRealD &r){ return innerProduct(l,r); }
|
||||||
|
|
||||||
|
accelerator_inline sComplexD innerProductD2(const sComplexF &l,const sComplexF &r)
|
||||||
|
{
|
||||||
|
sComplexD dl,dr;
|
||||||
|
precisionChange(&dl,&l,1);
|
||||||
|
precisionChange(&dr,&r,1);
|
||||||
|
return innerProduct(dl,dr);
|
||||||
|
}
|
||||||
|
accelerator_inline sRealD innerProductD2(const sRealF &l,const sRealF &r)
|
||||||
|
{
|
||||||
|
sRealD dl,dr;
|
||||||
|
precisionChange(&dl,&l,1);
|
||||||
|
precisionChange(&dr,&r,1);
|
||||||
|
return innerProduct(dl,dr);
|
||||||
|
}
|
||||||
|
|
||||||
accelerator_inline vComplexD2 innerProductD2(const vComplexF &l,const vComplexF &r)
|
accelerator_inline vComplexD2 innerProductD2(const vComplexF &l,const vComplexF &r)
|
||||||
{
|
{
|
||||||
vComplexD2 dl,dr;
|
vComplexD2 dl,dr;
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
template<> struct isGridFundamental<ComplexD> : public std::true_type { static constexpr bool notvalue = false; };
|
template<> struct isGridFundamental<ComplexD> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
template<> struct isGridFundamental<RealF> : public std::true_type { static constexpr bool notvalue = false; };
|
template<> struct isGridFundamental<RealF> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
template<> struct isGridFundamental<RealD> : public std::true_type { static constexpr bool notvalue = false; };
|
template<> struct isGridFundamental<RealD> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
|
template<> struct isGridFundamental<sComplexF> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
|
template<> struct isGridFundamental<sComplexD> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
|
template<> struct isGridFundamental<sRealF> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
|
template<> struct isGridFundamental<sRealD> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
template<> struct isGridFundamental<vComplexD2> : public std::true_type { static constexpr bool notvalue = false; };
|
template<> struct isGridFundamental<vComplexD2> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
template<> struct isGridFundamental<vRealD2> : public std::true_type { static constexpr bool notvalue = false; };
|
template<> struct isGridFundamental<vRealD2> : public std::true_type { static constexpr bool notvalue = false; };
|
||||||
|
|
||||||
@@ -103,6 +107,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef RealD scalar_objectD;
|
typedef RealD scalar_objectD;
|
||||||
typedef ComplexF Complexified;
|
typedef ComplexF Complexified;
|
||||||
typedef RealF Realified;
|
typedef RealF Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef RealD DoublePrecision;
|
typedef RealD DoublePrecision;
|
||||||
typedef RealD DoublePrecision2;
|
typedef RealD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -116,6 +121,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef RealD scalar_objectD;
|
typedef RealD scalar_objectD;
|
||||||
typedef ComplexD Complexified;
|
typedef ComplexD Complexified;
|
||||||
typedef RealD Realified;
|
typedef RealD Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef RealD DoublePrecision;
|
typedef RealD DoublePrecision;
|
||||||
typedef RealD DoublePrecision2;
|
typedef RealD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -129,6 +135,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef ComplexD scalar_objectD;
|
typedef ComplexD scalar_objectD;
|
||||||
typedef ComplexF Complexified;
|
typedef ComplexF Complexified;
|
||||||
typedef RealF Realified;
|
typedef RealF Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef ComplexD DoublePrecision;
|
typedef ComplexD DoublePrecision;
|
||||||
typedef ComplexD DoublePrecision2;
|
typedef ComplexD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -142,6 +149,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef ComplexD scalar_objectD;
|
typedef ComplexD scalar_objectD;
|
||||||
typedef ComplexD Complexified;
|
typedef ComplexD Complexified;
|
||||||
typedef RealD Realified;
|
typedef RealD Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef ComplexD DoublePrecision;
|
typedef ComplexD DoublePrecision;
|
||||||
typedef ComplexD DoublePrecision2;
|
typedef ComplexD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -157,6 +165,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef scalar_typeD scalar_objectD;
|
typedef scalar_typeD scalar_objectD;
|
||||||
typedef scalar_type Complexified;
|
typedef scalar_type Complexified;
|
||||||
typedef RealF Realified;
|
typedef RealF Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef scalar_typeD DoublePrecision;
|
typedef scalar_typeD DoublePrecision;
|
||||||
typedef scalar_typeD DoublePrecision2;
|
typedef scalar_typeD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -170,6 +179,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef scalar_typeD scalar_objectD;
|
typedef scalar_typeD scalar_objectD;
|
||||||
typedef scalar_type Complexified;
|
typedef scalar_type Complexified;
|
||||||
typedef RealD Realified;
|
typedef RealD Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef scalar_typeD DoublePrecision;
|
typedef scalar_typeD DoublePrecision;
|
||||||
typedef scalar_typeD DoublePrecision2;
|
typedef scalar_typeD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -185,6 +195,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef Integer scalar_objectD;
|
typedef Integer scalar_objectD;
|
||||||
typedef void Complexified;
|
typedef void Complexified;
|
||||||
typedef void Realified;
|
typedef void Realified;
|
||||||
|
typedef Integer Integerified;
|
||||||
typedef void DoublePrecision;
|
typedef void DoublePrecision;
|
||||||
typedef void DoublePrecision2;
|
typedef void DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -199,6 +210,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef RealD scalar_objectD;
|
typedef RealD scalar_objectD;
|
||||||
typedef vComplexF Complexified;
|
typedef vComplexF Complexified;
|
||||||
typedef vRealF Realified;
|
typedef vRealF Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vRealD DoublePrecision;
|
typedef vRealD DoublePrecision;
|
||||||
typedef vRealD2 DoublePrecision2;
|
typedef vRealD2 DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -212,6 +224,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef RealD scalar_objectD;
|
typedef RealD scalar_objectD;
|
||||||
typedef vComplexD Complexified;
|
typedef vComplexD Complexified;
|
||||||
typedef vRealD Realified;
|
typedef vRealD Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vRealD DoublePrecision;
|
typedef vRealD DoublePrecision;
|
||||||
typedef vRealD DoublePrecision2;
|
typedef vRealD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -225,6 +238,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef RealD scalar_objectD;
|
typedef RealD scalar_objectD;
|
||||||
typedef vComplexD2 Complexified;
|
typedef vComplexD2 Complexified;
|
||||||
typedef vRealD2 Realified;
|
typedef vRealD2 Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vRealD2 DoublePrecision;
|
typedef vRealD2 DoublePrecision;
|
||||||
typedef vRealD2 DoublePrecision2;
|
typedef vRealD2 DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -239,6 +253,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef RealD scalar_objectD;
|
typedef RealD scalar_objectD;
|
||||||
typedef vComplexH Complexified;
|
typedef vComplexH Complexified;
|
||||||
typedef vRealH Realified;
|
typedef vRealH Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vRealD DoublePrecision;
|
typedef vRealD DoublePrecision;
|
||||||
typedef vRealD DoublePrecision2;
|
typedef vRealD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -253,6 +268,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef ComplexD scalar_objectD;
|
typedef ComplexD scalar_objectD;
|
||||||
typedef vComplexH Complexified;
|
typedef vComplexH Complexified;
|
||||||
typedef vRealH Realified;
|
typedef vRealH Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vComplexD DoublePrecision;
|
typedef vComplexD DoublePrecision;
|
||||||
typedef vComplexD DoublePrecision2;
|
typedef vComplexD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -266,6 +282,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef ComplexD scalar_objectD;
|
typedef ComplexD scalar_objectD;
|
||||||
typedef vComplexF Complexified;
|
typedef vComplexF Complexified;
|
||||||
typedef vRealF Realified;
|
typedef vRealF Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vComplexD DoublePrecision;
|
typedef vComplexD DoublePrecision;
|
||||||
typedef vComplexD2 DoublePrecision2;
|
typedef vComplexD2 DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -279,6 +296,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef ComplexD scalar_objectD;
|
typedef ComplexD scalar_objectD;
|
||||||
typedef vComplexD Complexified;
|
typedef vComplexD Complexified;
|
||||||
typedef vRealD Realified;
|
typedef vRealD Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vComplexD DoublePrecision;
|
typedef vComplexD DoublePrecision;
|
||||||
typedef vComplexD DoublePrecision2;
|
typedef vComplexD DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -292,6 +310,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef ComplexD scalar_objectD;
|
typedef ComplexD scalar_objectD;
|
||||||
typedef vComplexD2 Complexified;
|
typedef vComplexD2 Complexified;
|
||||||
typedef vRealD2 Realified;
|
typedef vRealD2 Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
typedef vComplexD2 DoublePrecision;
|
typedef vComplexD2 DoublePrecision;
|
||||||
typedef vComplexD2 DoublePrecision2;
|
typedef vComplexD2 DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -305,6 +324,77 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
typedef Integer scalar_objectD;
|
typedef Integer scalar_objectD;
|
||||||
typedef void Complexified;
|
typedef void Complexified;
|
||||||
typedef void Realified;
|
typedef void Realified;
|
||||||
|
typedef vInteger Integerified;
|
||||||
|
typedef void DoublePrecision;
|
||||||
|
typedef void DoublePrecision2;
|
||||||
|
};
|
||||||
|
template<> struct GridTypeMapper<sRealF> : public GridTypeMapper_Base {
|
||||||
|
typedef RealF scalar_type;
|
||||||
|
typedef RealD scalar_typeD;
|
||||||
|
typedef sRealF vector_type;
|
||||||
|
typedef sRealD vector_typeD;
|
||||||
|
typedef sRealF tensor_reduced;
|
||||||
|
typedef RealF scalar_object;
|
||||||
|
typedef RealD scalar_objectD;
|
||||||
|
typedef sComplexF Complexified;
|
||||||
|
typedef sRealF Realified;
|
||||||
|
typedef sInteger Integerified;
|
||||||
|
typedef sRealD DoublePrecision;
|
||||||
|
typedef sRealD DoublePrecision2;
|
||||||
|
};
|
||||||
|
template<> struct GridTypeMapper<sRealD> : public GridTypeMapper_Base {
|
||||||
|
typedef RealD scalar_type;
|
||||||
|
typedef RealD scalar_typeD;
|
||||||
|
typedef sRealD vector_type;
|
||||||
|
typedef sRealD vector_typeD;
|
||||||
|
typedef sRealD tensor_reduced;
|
||||||
|
typedef RealD scalar_object;
|
||||||
|
typedef RealD scalar_objectD;
|
||||||
|
typedef sComplexD Complexified;
|
||||||
|
typedef sRealD Realified;
|
||||||
|
typedef sInteger Integerified;
|
||||||
|
typedef sRealD DoublePrecision;
|
||||||
|
typedef sRealD DoublePrecision2;
|
||||||
|
};
|
||||||
|
template<> struct GridTypeMapper<sComplexF> : public GridTypeMapper_Base {
|
||||||
|
typedef ComplexF scalar_type;
|
||||||
|
typedef ComplexD scalar_typeD;
|
||||||
|
typedef sComplexF vector_type;
|
||||||
|
typedef sComplexD vector_typeD;
|
||||||
|
typedef sComplexF tensor_reduced;
|
||||||
|
typedef ComplexF scalar_object;
|
||||||
|
typedef ComplexD scalar_objectD;
|
||||||
|
typedef sComplexF Complexified;
|
||||||
|
typedef sRealF Realified;
|
||||||
|
typedef sInteger Integerified;
|
||||||
|
typedef sComplexD DoublePrecision;
|
||||||
|
typedef sComplexD DoublePrecision2;
|
||||||
|
};
|
||||||
|
template<> struct GridTypeMapper<sComplexD> : public GridTypeMapper_Base {
|
||||||
|
typedef ComplexD scalar_type;
|
||||||
|
typedef ComplexD scalar_typeD;
|
||||||
|
typedef sComplexD vector_type;
|
||||||
|
typedef sComplexD vector_typeD;
|
||||||
|
typedef sComplexD tensor_reduced;
|
||||||
|
typedef ComplexD scalar_object;
|
||||||
|
typedef ComplexD scalar_objectD;
|
||||||
|
typedef sComplexD Complexified;
|
||||||
|
typedef sRealD Realified;
|
||||||
|
typedef sInteger Integerified;
|
||||||
|
typedef sComplexD DoublePrecision;
|
||||||
|
typedef sComplexD DoublePrecision2;
|
||||||
|
};
|
||||||
|
template<> struct GridTypeMapper<sInteger> : public GridTypeMapper_Base {
|
||||||
|
typedef Integer scalar_type;
|
||||||
|
typedef Integer scalar_typeD;
|
||||||
|
typedef sInteger vector_type;
|
||||||
|
typedef sInteger vector_typeD;
|
||||||
|
typedef sInteger tensor_reduced;
|
||||||
|
typedef Integer scalar_object;
|
||||||
|
typedef Integer scalar_objectD;
|
||||||
|
typedef void Complexified;
|
||||||
|
typedef void Realified;
|
||||||
|
typedef sInteger Integerified;
|
||||||
typedef void DoublePrecision;
|
typedef void DoublePrecision;
|
||||||
typedef void DoublePrecision2;
|
typedef void DoublePrecision2;
|
||||||
};
|
};
|
||||||
@@ -324,6 +414,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
using scalar_objectD = iScalar<typename BaseTraits::scalar_objectD>;
|
using scalar_objectD = iScalar<typename BaseTraits::scalar_objectD>;
|
||||||
using Complexified = iScalar<typename BaseTraits::Complexified>;
|
using Complexified = iScalar<typename BaseTraits::Complexified>;
|
||||||
using Realified = iScalar<typename BaseTraits::Realified>;
|
using Realified = iScalar<typename BaseTraits::Realified>;
|
||||||
|
using Integerified = iScalar<typename BaseTraits::Integerified>;
|
||||||
using DoublePrecision = iScalar<typename BaseTraits::DoublePrecision>;
|
using DoublePrecision = iScalar<typename BaseTraits::DoublePrecision>;
|
||||||
using DoublePrecision2= iScalar<typename BaseTraits::DoublePrecision2>;
|
using DoublePrecision2= iScalar<typename BaseTraits::DoublePrecision2>;
|
||||||
static constexpr int Rank = BaseTraits::Rank + 1;
|
static constexpr int Rank = BaseTraits::Rank + 1;
|
||||||
@@ -339,6 +430,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
using scalar_objectD = iVector<typename BaseTraits::scalar_objectD, N>;
|
using scalar_objectD = iVector<typename BaseTraits::scalar_objectD, N>;
|
||||||
using Complexified = iVector<typename BaseTraits::Complexified, N>;
|
using Complexified = iVector<typename BaseTraits::Complexified, N>;
|
||||||
using Realified = iVector<typename BaseTraits::Realified, N>;
|
using Realified = iVector<typename BaseTraits::Realified, N>;
|
||||||
|
using Integerified = iVector<typename BaseTraits::Integerified, N>;
|
||||||
using DoublePrecision = iVector<typename BaseTraits::DoublePrecision, N>;
|
using DoublePrecision = iVector<typename BaseTraits::DoublePrecision, N>;
|
||||||
using DoublePrecision2= iVector<typename BaseTraits::DoublePrecision2, N>;
|
using DoublePrecision2= iVector<typename BaseTraits::DoublePrecision2, N>;
|
||||||
static constexpr int Rank = BaseTraits::Rank + 1;
|
static constexpr int Rank = BaseTraits::Rank + 1;
|
||||||
@@ -354,6 +446,7 @@ NAMESPACE_BEGIN(Grid);
|
|||||||
using scalar_objectD = iMatrix<typename BaseTraits::scalar_objectD, N>;
|
using scalar_objectD = iMatrix<typename BaseTraits::scalar_objectD, N>;
|
||||||
using Complexified = iMatrix<typename BaseTraits::Complexified, N>;
|
using Complexified = iMatrix<typename BaseTraits::Complexified, N>;
|
||||||
using Realified = iMatrix<typename BaseTraits::Realified, N>;
|
using Realified = iMatrix<typename BaseTraits::Realified, N>;
|
||||||
|
using Integerified = iMatrix<typename BaseTraits::Integerified, N>;
|
||||||
using DoublePrecision = iMatrix<typename BaseTraits::DoublePrecision, N>;
|
using DoublePrecision = iMatrix<typename BaseTraits::DoublePrecision, N>;
|
||||||
using DoublePrecision2= iMatrix<typename BaseTraits::DoublePrecision2, N>;
|
using DoublePrecision2= iMatrix<typename BaseTraits::DoublePrecision2, N>;
|
||||||
static constexpr int Rank = BaseTraits::Rank + 2;
|
static constexpr int Rank = BaseTraits::Rank + 2;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
NAMESPACE_BEGIN(Grid);
|
NAMESPACE_BEGIN(Grid);
|
||||||
int world_rank; // Use to control world rank for print guarding
|
int world_rank; // Use to control world rank for print guarding
|
||||||
int acceleratorAbortOnGpuError=1;
|
int acceleratorAbortOnGpuError=1;
|
||||||
uint32_t accelerator_threads=2;
|
uint32_t accelerator_threads=8;
|
||||||
uint32_t acceleratorThreads(void) {return accelerator_threads;};
|
uint32_t acceleratorThreads(void) {return accelerator_threads;};
|
||||||
void acceleratorThreads(uint32_t t) {accelerator_threads = t;};
|
void acceleratorThreads(uint32_t t) {accelerator_threads = t;};
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ bool FlightRecorder::CsumLog(uint64_t hex)
|
|||||||
std::cerr<<"FlightRecorder::CsumLog Oops, I did it again "<< CsumLoggingCounter
|
std::cerr<<"FlightRecorder::CsumLog Oops, I did it again "<< CsumLoggingCounter
|
||||||
<<std::hex<<" "<<hex<<" "<<hexref<<std::dec<<std::endl;
|
<<std::hex<<" "<<hex<<" "<<hexref<<std::dec<<std::endl;
|
||||||
|
|
||||||
fprintf(stderr,"%s:%d Oops, I did it again! Reproduce failure for csum %d %lx expect %lx\n",
|
fprintf(stderr,"%s:%d Oops, I did it again! Reproduce failure for csum %d %llx expect %llx\n",
|
||||||
GridHostname(),
|
GridHostname(),
|
||||||
GlobalSharedMemory::WorldShmRank,
|
GlobalSharedMemory::WorldShmRank,
|
||||||
CsumLoggingCounter,hex, hexref);
|
CsumLoggingCounter,hex, hexref);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user