mirror of
https://github.com/paboyle/Grid.git
synced 2025-06-16 14:57:05 +01:00
Compare commits
216 Commits
feature/bl
...
feature/co
Author | SHA1 | Date | |
---|---|---|---|
de8b2dcca3 | |||
efe000341d | |||
11086c5c25 | |||
91a7fe247b | |||
8a1be021d3 | |||
fd66325321 | |||
c637c0c48c | |||
c4b472176c | |||
856476a890 | |||
c509bd3fe2 | |||
49b934310b | |||
01e8cf5017 | |||
12f4499502 | |||
05aec72887 | |||
136d3802cb | |||
a4c55406ed | |||
c7f33ca2a8 | |||
0e3035c51d | |||
10fc263675 | |||
bccfd4cbb3 | |||
0b50d4a328 | |||
e232257cb6 | |||
09451b5e48 | |||
6364aa8acf | |||
b9e84ecab7 | |||
41032fef44 | |||
d77bc88170 | |||
494b3c9e57 | |||
2ba19a9e07 | |||
5d7cc29eaf | |||
f22a27d7f9 | |||
33a0bbb17b | |||
f592ec8baa | |||
8b007b5c24 | |||
9bb170576d | |||
a7e3977b75 | |||
995f20e45d | |||
d058b4e681 | |||
8e0d2f3402 | |||
2ac57370f1 | |||
344e832a4e | |||
cfe281f1a4 | |||
f5422c7334 | |||
68c76a410d | |||
69b6ba0a73 | |||
65349b07a7 | |||
7cd9914f0e | |||
f3f24b3017 | |||
8ef4657805 | |||
78c1086f8b | |||
68c13045d6 | |||
e9b6f58fdc | |||
839605c45c | |||
1ff1422e07 | |||
32376f0437 | |||
0c6e581336 | |||
e0a79a5bbf | |||
4c016cc1a4 | |||
2205b1e63e | |||
88d9922e4f | |||
9734e3ee58 | |||
f1382cf81d | |||
85699daef2 | |||
1651111d18 | |||
1ed4ea344d | |||
4a7415e83c | |||
0ffcfea724 | |||
b48611b80f | |||
7d84dca8e9 | |||
f31d6bfec2 | |||
a7cfa26901 | |||
f333f3e575 | |||
f709329d96 | |||
f05b25dae4 | |||
3e1d268fa3 | |||
2881b3e8e5 | |||
cc5d025ea4 | |||
ddcb53bce2 | |||
d1c80e1d46 | |||
c73cc7d354 | |||
49fdc324a0 | |||
f32714a2d1 | |||
73a955be20 | |||
66b7a0f871 | |||
2ab9d4bc56 | |||
4f41cd114d | |||
11c4f5e32c | |||
e9b9550298 | |||
7564fedf68 | |||
6c27c72585 | |||
9c003d2d72 | |||
4b8710970c | |||
68d686ec38 | |||
c48b69ca81 | |||
df8c208f5c | |||
61812ab7f1 | |||
73ced656eb | |||
f69008edf1 | |||
57a49ed22f | |||
ff6413a764 | |||
2530bfed01 | |||
74f79c5ac7 | |||
58c30c0cb1 | |||
917a92118a | |||
04f9cf088d | |||
99107038f9 | |||
b78456bdf4 | |||
08543b6b11 | |||
63ba33371f | |||
683a7d2ddd | |||
afdcbf79d1 | |||
3c3ec4e267 | |||
bbe1d5b49e | |||
0f6009a29f | |||
1cfed3de7c | |||
edbc0d49d7 | |||
ee5cf6c8c5 | |||
a66cecc509 | |||
0f6cdf3d4b | |||
1e63b73a14 | |||
6ab60c5b70 | |||
8c692b7ffd | |||
2976132bdd | |||
48177f2f2d | |||
c4ce70a821 | |||
a3e009ba54 | |||
eb7cf239d9 | |||
13ae371ef8 | |||
9f79a87102 | |||
4ded1ceeb0 | |||
8bc12e0ce1 | |||
cc2f00f827 | |||
cd61e2e6d6 | |||
323ed1a588 | |||
68c66d2e4b | |||
1671adfd49 | |||
871649238c | |||
7c86d2085b | |||
9292be0b69 | |||
10141f90c9 | |||
a414430817 | |||
f20728baa9 | |||
d2e68c4355 | |||
1cb745c8dc | |||
faf4278019 | |||
194e4b94bb | |||
bfc1411c1f | |||
161637e573 | |||
04f92ccddf | |||
3b2d805398 | |||
9dc885d297 | |||
a70c1feecc | |||
38328100c9 | |||
9732519c41 | |||
fa4eeb28c4 | |||
10f7a17ae4 | |||
26f14d7dd7 | |||
73434db636 | |||
c6411f8514 | |||
6cf635d61c | |||
39558cce52 | |||
df152648d6 | |||
4e965c168e | |||
f260af546e | |||
649b8c9aca | |||
0afa22747d | |||
fa43206c79 | |||
a367835bf2 | |||
d7743591ea | |||
c6cbe533ea | |||
8402ab6cf9 | |||
c63095345e | |||
a7ae46b61e | |||
cd63052205 | |||
699d537cd6 | |||
9031f0ed95 | |||
26b3d441bb | |||
99bc4cde56 | |||
e843d83d9d | |||
0f75ea52b7 | |||
8107b785cc | |||
37b777d801 | |||
7382787856 | |||
781c611ca0 | |||
b069090b52 | |||
0c1c1d9900 | |||
7f4ed6c2e5 | |||
56d32a4afb | |||
b8ee496ed6 | |||
b87416dac4 | |||
176bf37372 | |||
b3d342ca22 | |||
e1f928398d | |||
8c579d2d4a | |||
fc7d07ade0 | |||
b3be9195b4 | |||
9e3c187a4d | |||
8363edfcdb | |||
74af31564f | |||
e0819d395f | |||
6f81906b00 | |||
a2d83d4f3d | |||
89bacb0470 | |||
19010ff66a | |||
5a477ed29e | |||
54128d579a | |||
e7b1933e88 | |||
1bad64ac6a | |||
15dfa9f663 | |||
2185b0d651 | |||
f61c0b5d03 | |||
074db32e54 | |||
d5f661ba70 | |||
1ab8d5cc13 | |||
789e892865 | |||
53cfa44d7a |
@ -48,6 +48,12 @@ Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
|||||||
#include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h>
|
#include <Grid/algorithms/iterative/ConjugateGradientMixedPrec.h>
|
||||||
#include <Grid/algorithms/iterative/BlockConjugateGradient.h>
|
#include <Grid/algorithms/iterative/BlockConjugateGradient.h>
|
||||||
#include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h>
|
#include <Grid/algorithms/iterative/ConjugateGradientReliableUpdate.h>
|
||||||
|
#include <Grid/algorithms/iterative/MinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/GeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/CommunicationAvoidingGeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/FlexibleCommunicationAvoidingGeneralisedMinimalResidual.h>
|
||||||
|
#include <Grid/algorithms/iterative/MixedPrecisionFlexibleGeneralisedMinimalResidual.h>
|
||||||
#include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h>
|
#include <Grid/algorithms/iterative/ImplicitlyRestartedLanczos.h>
|
||||||
#include <Grid/algorithms/CoarsenedMatrix.h>
|
#include <Grid/algorithms/CoarsenedMatrix.h>
|
||||||
#include <Grid/algorithms/FFT.h>
|
#include <Grid/algorithms/FFT.h>
|
||||||
|
@ -211,6 +211,7 @@ namespace Grid {
|
|||||||
|
|
||||||
for(int b=0;b<nn;b++){
|
for(int b=0;b<nn;b++){
|
||||||
|
|
||||||
|
subspace[b] = zero;
|
||||||
gaussian(RNG,noise);
|
gaussian(RNG,noise);
|
||||||
scale = std::pow(norm2(noise),-0.5);
|
scale = std::pow(norm2(noise),-0.5);
|
||||||
noise=noise*scale;
|
noise=noise*scale;
|
||||||
@ -296,12 +297,57 @@ namespace Grid {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RealD Mdag (const CoarseVector &in, CoarseVector &out){
|
RealD Mdag (const CoarseVector &in, CoarseVector &out){
|
||||||
return M(in,out);
|
// // corresponds to Petrov-Galerkin coarsening
|
||||||
|
// return M(in,out);
|
||||||
|
|
||||||
|
// corresponds to Galerkin coarsening
|
||||||
|
CoarseVector tmp(Grid());
|
||||||
|
G5C(tmp, in);
|
||||||
|
M(tmp, out);
|
||||||
|
G5C(out, out);
|
||||||
|
return norm2(out);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defer support for further coarsening for now
|
void Mdir(const CoarseVector &in, CoarseVector &out, int dir, int disp){
|
||||||
void Mdiag (const CoarseVector &in, CoarseVector &out){};
|
|
||||||
void Mdir (const CoarseVector &in, CoarseVector &out,int dir, int disp){};
|
conformable(_grid,in._grid);
|
||||||
|
conformable(in._grid,out._grid);
|
||||||
|
|
||||||
|
SimpleCompressor<siteVector> compressor;
|
||||||
|
Stencil.HaloExchange(in,compressor);
|
||||||
|
|
||||||
|
auto point = [dir, disp](){
|
||||||
|
if(dir == 0 and disp == 0)
|
||||||
|
return 8;
|
||||||
|
else
|
||||||
|
return (4 * dir + 1 - disp) / 2;
|
||||||
|
}();
|
||||||
|
|
||||||
|
parallel_for(int ss=0;ss<Grid()->oSites();ss++){
|
||||||
|
siteVector res = zero;
|
||||||
|
siteVector nbr;
|
||||||
|
int ptype;
|
||||||
|
StencilEntry *SE;
|
||||||
|
|
||||||
|
SE=Stencil.GetEntry(ptype,point,ss);
|
||||||
|
|
||||||
|
if(SE->_is_local&&SE->_permute) {
|
||||||
|
permute(nbr,in._odata[SE->_offset],ptype);
|
||||||
|
} else if(SE->_is_local) {
|
||||||
|
nbr = in._odata[SE->_offset];
|
||||||
|
} else {
|
||||||
|
nbr = Stencil.CommBuf()[SE->_offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
res = res + A[point]._odata[ss]*nbr;
|
||||||
|
|
||||||
|
vstream(out._odata[ss],res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void Mdiag(const CoarseVector &in, CoarseVector &out){
|
||||||
|
Mdir(in, out, 0, 0); // use the self coupling (= last) point of the stencil
|
||||||
|
};
|
||||||
|
|
||||||
CoarsenedMatrix(GridCartesian &CoarseGrid) :
|
CoarsenedMatrix(GridCartesian &CoarseGrid) :
|
||||||
|
|
||||||
@ -417,7 +463,7 @@ namespace Grid {
|
|||||||
std::cout<<GridLogMessage<<"Computed Coarse Operator"<<std::endl;
|
std::cout<<GridLogMessage<<"Computed Coarse Operator"<<std::endl;
|
||||||
#endif
|
#endif
|
||||||
// ForceHermitian();
|
// ForceHermitian();
|
||||||
AssertHermitian();
|
// AssertHermitian();
|
||||||
// ForceDiagonal();
|
// ForceDiagonal();
|
||||||
}
|
}
|
||||||
void ForceDiagonal(void) {
|
void ForceDiagonal(void) {
|
||||||
|
@ -0,0 +1,244 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/CommunicationAvoidingGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class CommunicationAvoidingGeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when CAGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the CAGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
CommunicationAvoidingGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
std::cout << GridLogWarning << "This algorithm currently doesn't differ from regular GMRES" << std::endl;
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "CommunicationAvoidingGeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "CommunicationAvoidingGeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "CommunicationAvoidingGeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "CAGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "CommunicationAvoidingGeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// this should probably be made a class member so that it is only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "CommunicationAvoidingGeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(v, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, Field &w, int iter) {
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(v[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &v, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + v[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,256 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/FlexibleCommunicationAvoidingGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_FLEXIBLE_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_FLEXIBLE_COMMUNICATION_AVOIDING_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class FlexibleCommunicationAvoidingGeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when FCAGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the FCAGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch PrecTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
LinearFunction<Field> &Preconditioner;
|
||||||
|
|
||||||
|
FlexibleCommunicationAvoidingGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
LinearFunction<Field> &Prec,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.)
|
||||||
|
, Preconditioner(Prec) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
std::cout << GridLogWarning << "This algorithm currently doesn't differ from regular FGMRES" << std::endl;
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
PrecTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Precon " << PrecTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FCAGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// these should probably be made class members so that they are only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
std::vector<Field> z(RestartLength + 1, src._grid); for (auto &elem : z) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, z, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "FlexibleCommunicationAvoidingGeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(z, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, std::vector<Field> &z, Field &w, int iter) {
|
||||||
|
|
||||||
|
PrecTimer.Start();
|
||||||
|
Preconditioner(v[iter], z[iter]);
|
||||||
|
PrecTimer.Stop();
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(z[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &z, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + z[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
254
Grid/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h
Normal file
254
Grid/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/FlexibleGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class FlexibleGeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when FGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the FGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch PrecTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
LinearFunction<Field> &Preconditioner;
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
LinearFunction<Field> &Prec,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.)
|
||||||
|
, Preconditioner(Prec) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "FlexibleGeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "FlexibleGeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
PrecTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleGeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Precon " << PrecTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "FGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "FlexibleGeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// these should probably be made class members so that they are only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
std::vector<Field> z(RestartLength + 1, src._grid); for (auto &elem : z) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, z, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "FlexibleGeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(z, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, std::vector<Field> &z, Field &w, int iter) {
|
||||||
|
|
||||||
|
PrecTimer.Start();
|
||||||
|
Preconditioner(v[iter], z[iter]);
|
||||||
|
PrecTimer.Stop();
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(z[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &z, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + z[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
242
Grid/algorithms/iterative/GeneralisedMinimalResidual.h
Normal file
242
Grid/algorithms/iterative/GeneralisedMinimalResidual.h
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/GeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field>
|
||||||
|
class GeneralisedMinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when GMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the GMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
GeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "GeneralisedMinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "GeneralisedMinimalResidual: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "GeneralisedMinimalResidual: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "GMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "GeneralisedMinimalResidual did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<Field> &LinOp, const Field &src, Field &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
Field w(src._grid);
|
||||||
|
Field r(src._grid);
|
||||||
|
|
||||||
|
// this should probably be made a class member so that it is only allocated once, not in every restart
|
||||||
|
std::vector<Field> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "GeneralisedMinimalResidual: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(v, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<Field> &LinOp, std::vector<Field> &v, Field &w, int iter) {
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(v[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<Field> const &v, Field &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + v[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
156
Grid/algorithms/iterative/MinimalResidual.h
Normal file
156
Grid/algorithms/iterative/MinimalResidual.h
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/MinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class Field> class MinimalResidual : public OperatorFunction<Field> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // throw an assert when the MR fails to converge.
|
||||||
|
// Defaults true.
|
||||||
|
RealD Tolerance;
|
||||||
|
Integer MaxIterations;
|
||||||
|
RealD overRelaxParam;
|
||||||
|
Integer IterationsToComplete; // Number of iterations the MR took to finish.
|
||||||
|
// Filled in upon completion
|
||||||
|
|
||||||
|
MinimalResidual(RealD tol, Integer maxit, Real ovrelparam = 1.0, bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol), MaxIterations(maxit), overRelaxParam(ovrelparam), ErrorOnNoConverge(err_on_no_conv){};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<Field> &Linop, const Field &src, Field &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
Complex a, c;
|
||||||
|
Real d;
|
||||||
|
|
||||||
|
Field Mr(src);
|
||||||
|
Field r(src);
|
||||||
|
|
||||||
|
// Initial residual computation & set up
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
Linop.Op(psi, Mr);
|
||||||
|
|
||||||
|
r = src - Mr;
|
||||||
|
|
||||||
|
RealD cp = norm2(r);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: src " << ssq << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: mp " << d << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: cp,r " << cp << std::endl;
|
||||||
|
|
||||||
|
if (cp <= rsq) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: k=0 residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
|
||||||
|
SolverTimer.Start();
|
||||||
|
int k;
|
||||||
|
for (k = 1; k <= MaxIterations; k++) {
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
Linop.Op(r, Mr);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
|
||||||
|
c = innerProduct(Mr, r);
|
||||||
|
|
||||||
|
d = norm2(Mr);
|
||||||
|
|
||||||
|
a = c / d;
|
||||||
|
|
||||||
|
a = a * overRelaxParam;
|
||||||
|
|
||||||
|
psi = psi + r * a;
|
||||||
|
|
||||||
|
r = r - Mr * a;
|
||||||
|
|
||||||
|
cp = norm2(r);
|
||||||
|
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "MinimalResidual: Iteration " << k
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
std::cout << GridLogDebug << "a = " << a << " c = " << c << " d = " << d << std::endl;
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
Linop.Op(psi, Mr);
|
||||||
|
r = src - Mr;
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MinimalResidual Converged on iteration " << k
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MR Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MR Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MR Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(true_residual / Tolerance < 10000.0);
|
||||||
|
|
||||||
|
IterationsToComplete = k;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MinimalResidual did NOT converge"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
IterationsToComplete = k;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Grid
|
||||||
|
#endif
|
@ -0,0 +1,273 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./lib/algorithms/iterative/MixedPrecisionFlexibleGeneralisedMinimalResidual.h
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_MIXED_PRECISION_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
#define GRID_MIXED_PRECISION_FLEXIBLE_GENERALISED_MINIMAL_RESIDUAL_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
template<class FieldD, class FieldF, typename std::enable_if<getPrecision<FieldD>::value == 2, int>::type = 0, typename std::enable_if< getPrecision<FieldF>::value == 1, int>::type = 0>
|
||||||
|
class MixedPrecisionFlexibleGeneralisedMinimalResidual : public OperatorFunction<FieldD> {
|
||||||
|
public:
|
||||||
|
bool ErrorOnNoConverge; // Throw an assert when MPFGMRES fails to converge,
|
||||||
|
// defaults to true
|
||||||
|
|
||||||
|
RealD Tolerance;
|
||||||
|
|
||||||
|
Integer MaxIterations;
|
||||||
|
Integer RestartLength;
|
||||||
|
Integer MaxNumberOfRestarts;
|
||||||
|
Integer IterationCount; // Number of iterations the MPFGMRES took to finish,
|
||||||
|
// filled in upon completion
|
||||||
|
|
||||||
|
GridStopWatch MatrixTimer;
|
||||||
|
GridStopWatch PrecTimer;
|
||||||
|
GridStopWatch LinalgTimer;
|
||||||
|
GridStopWatch QrTimer;
|
||||||
|
GridStopWatch CompSolutionTimer;
|
||||||
|
GridStopWatch ChangePrecTimer;
|
||||||
|
|
||||||
|
Eigen::MatrixXcd H;
|
||||||
|
|
||||||
|
std::vector<std::complex<double>> y;
|
||||||
|
std::vector<std::complex<double>> gamma;
|
||||||
|
std::vector<std::complex<double>> c;
|
||||||
|
std::vector<std::complex<double>> s;
|
||||||
|
|
||||||
|
GridBase* SinglePrecGrid;
|
||||||
|
|
||||||
|
LinearFunction<FieldF> &Preconditioner;
|
||||||
|
|
||||||
|
MixedPrecisionFlexibleGeneralisedMinimalResidual(RealD tol,
|
||||||
|
Integer maxit,
|
||||||
|
GridBase * sp_grid,
|
||||||
|
LinearFunction<FieldF> &Prec,
|
||||||
|
Integer restart_length,
|
||||||
|
bool err_on_no_conv = true)
|
||||||
|
: Tolerance(tol)
|
||||||
|
, MaxIterations(maxit)
|
||||||
|
, RestartLength(restart_length)
|
||||||
|
, MaxNumberOfRestarts(MaxIterations/RestartLength + ((MaxIterations%RestartLength == 0) ? 0 : 1))
|
||||||
|
, ErrorOnNoConverge(err_on_no_conv)
|
||||||
|
, H(Eigen::MatrixXcd::Zero(RestartLength, RestartLength + 1)) // sizes taken from DD-αAMG code base
|
||||||
|
, y(RestartLength + 1, 0.)
|
||||||
|
, gamma(RestartLength + 1, 0.)
|
||||||
|
, c(RestartLength + 1, 0.)
|
||||||
|
, s(RestartLength + 1, 0.)
|
||||||
|
, SinglePrecGrid(sp_grid)
|
||||||
|
, Preconditioner(Prec) {};
|
||||||
|
|
||||||
|
void operator()(LinearOperatorBase<FieldD> &LinOp, const FieldD &src, FieldD &psi) {
|
||||||
|
|
||||||
|
psi.checkerboard = src.checkerboard;
|
||||||
|
conformable(psi, src);
|
||||||
|
|
||||||
|
RealD guess = norm2(psi);
|
||||||
|
assert(std::isnan(guess) == 0);
|
||||||
|
|
||||||
|
RealD cp;
|
||||||
|
RealD ssq = norm2(src);
|
||||||
|
RealD rsq = Tolerance * Tolerance * ssq;
|
||||||
|
|
||||||
|
FieldD r(src._grid);
|
||||||
|
|
||||||
|
std::cout << std::setprecision(4) << std::scientific;
|
||||||
|
std::cout << GridLogIterative << "MPFGMRES: guess " << guess << std::endl;
|
||||||
|
std::cout << GridLogIterative << "MPFGMRES: src " << ssq << std::endl;
|
||||||
|
|
||||||
|
PrecTimer.Reset();
|
||||||
|
MatrixTimer.Reset();
|
||||||
|
LinalgTimer.Reset();
|
||||||
|
QrTimer.Reset();
|
||||||
|
CompSolutionTimer.Reset();
|
||||||
|
ChangePrecTimer.Reset();
|
||||||
|
|
||||||
|
GridStopWatch SolverTimer;
|
||||||
|
SolverTimer.Start();
|
||||||
|
|
||||||
|
IterationCount = 0;
|
||||||
|
|
||||||
|
for (int k=0; k<MaxNumberOfRestarts; k++) {
|
||||||
|
|
||||||
|
cp = outerLoopBody(LinOp, src, psi, rsq);
|
||||||
|
|
||||||
|
// Stopping condition
|
||||||
|
if (cp <= rsq) {
|
||||||
|
|
||||||
|
SolverTimer.Stop();
|
||||||
|
|
||||||
|
LinOp.Op(psi,r);
|
||||||
|
axpy(r,-1.0,src,r);
|
||||||
|
|
||||||
|
RealD srcnorm = sqrt(ssq);
|
||||||
|
RealD resnorm = sqrt(norm2(r));
|
||||||
|
RealD true_residual = resnorm / srcnorm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES: Converged on iteration " << IterationCount
|
||||||
|
<< " computed residual " << sqrt(cp / ssq)
|
||||||
|
<< " true residual " << true_residual
|
||||||
|
<< " target " << Tolerance << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Total " << SolverTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Precon " << PrecTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Matrix " << MatrixTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: Linalg " << LinalgTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: QR " << QrTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: CompSol " << CompSolutionTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES Time elapsed: PrecChange " << ChangePrecTimer.Elapsed() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "MPFGMRES did NOT converge" << std::endl;
|
||||||
|
|
||||||
|
if (ErrorOnNoConverge)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD outerLoopBody(LinearOperatorBase<FieldD> &LinOp, const FieldD &src, FieldD &psi, RealD rsq) {
|
||||||
|
|
||||||
|
RealD cp = 0;
|
||||||
|
|
||||||
|
FieldD w(src._grid);
|
||||||
|
FieldD r(src._grid);
|
||||||
|
|
||||||
|
// these should probably be made class members so that they are only allocated once, not in every restart
|
||||||
|
std::vector<FieldD> v(RestartLength + 1, src._grid); for (auto &elem : v) elem = zero;
|
||||||
|
std::vector<FieldD> z(RestartLength + 1, src._grid); for (auto &elem : z) elem = zero;
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(psi, w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
r = src - w;
|
||||||
|
|
||||||
|
gamma[0] = sqrt(norm2(r));
|
||||||
|
|
||||||
|
v[0] = (1. / gamma[0]) * r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
|
for (int i=0; i<RestartLength; i++) {
|
||||||
|
|
||||||
|
IterationCount++;
|
||||||
|
|
||||||
|
arnoldiStep(LinOp, v, z, w, i);
|
||||||
|
|
||||||
|
qrUpdate(i);
|
||||||
|
|
||||||
|
cp = std::norm(gamma[i+1]);
|
||||||
|
|
||||||
|
std::cout << GridLogIterative << "MPFGMRES: Iteration " << IterationCount
|
||||||
|
<< " residual " << cp << " target " << rsq << std::endl;
|
||||||
|
|
||||||
|
if ((i == RestartLength - 1) || (IterationCount == MaxIterations) || (cp <= rsq)) {
|
||||||
|
|
||||||
|
computeSolution(z, psi, i);
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Never reached
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arnoldiStep(LinearOperatorBase<FieldD> &LinOp, std::vector<FieldD> &v, std::vector<FieldD> &z, FieldD &w, int iter) {
|
||||||
|
|
||||||
|
FieldF v_f(SinglePrecGrid);
|
||||||
|
FieldF z_f(SinglePrecGrid);
|
||||||
|
|
||||||
|
ChangePrecTimer.Start();
|
||||||
|
precisionChange(v_f, v[iter]);
|
||||||
|
precisionChange(z_f, z[iter]);
|
||||||
|
ChangePrecTimer.Stop();
|
||||||
|
|
||||||
|
PrecTimer.Start();
|
||||||
|
Preconditioner(v_f, z_f);
|
||||||
|
PrecTimer.Stop();
|
||||||
|
|
||||||
|
ChangePrecTimer.Start();
|
||||||
|
precisionChange(z[iter], z_f);
|
||||||
|
ChangePrecTimer.Stop();
|
||||||
|
|
||||||
|
MatrixTimer.Start();
|
||||||
|
LinOp.Op(z[iter], w);
|
||||||
|
MatrixTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
|
for (int i = 0; i <= iter; ++i) {
|
||||||
|
H(iter, i) = innerProduct(v[i], w);
|
||||||
|
w = w - H(iter, i) * v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
H(iter, iter + 1) = sqrt(norm2(w));
|
||||||
|
v[iter + 1] = (1. / H(iter, iter + 1)) * w;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qrUpdate(int iter) {
|
||||||
|
|
||||||
|
QrTimer.Start();
|
||||||
|
for (int i = 0; i < iter ; ++i) {
|
||||||
|
auto tmp = -s[i] * H(iter, i) + c[i] * H(iter, i + 1);
|
||||||
|
H(iter, i) = std::conj(c[i]) * H(iter, i) + std::conj(s[i]) * H(iter, i + 1);
|
||||||
|
H(iter, i + 1) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute new Givens Rotation
|
||||||
|
ComplexD nu = sqrt(std::norm(H(iter, iter)) + std::norm(H(iter, iter + 1)));
|
||||||
|
c[iter] = H(iter, iter) / nu;
|
||||||
|
s[iter] = H(iter, iter + 1) / nu;
|
||||||
|
|
||||||
|
// Apply new Givens rotation
|
||||||
|
H(iter, iter) = nu;
|
||||||
|
H(iter, iter + 1) = 0.;
|
||||||
|
|
||||||
|
gamma[iter + 1] = -s[iter] * gamma[iter];
|
||||||
|
gamma[iter] = std::conj(c[iter]) * gamma[iter];
|
||||||
|
QrTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeSolution(std::vector<FieldD> const &z, FieldD &psi, int iter) {
|
||||||
|
|
||||||
|
CompSolutionTimer.Start();
|
||||||
|
for (int i = iter; i >= 0; i--) {
|
||||||
|
y[i] = gamma[i];
|
||||||
|
for (int k = i + 1; k <= iter; k++)
|
||||||
|
y[i] = y[i] - H(k, i) * y[k];
|
||||||
|
y[i] = y[i] / H(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= iter; i++)
|
||||||
|
psi = psi + z[i] * y[i];
|
||||||
|
CompSolutionTimer.Stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -139,7 +139,10 @@ namespace Grid {
|
|||||||
MatTimer.Start();
|
MatTimer.Start();
|
||||||
Linop.HermOpAndNorm(psi,Az,zAz,zAAz);
|
Linop.HermOpAndNorm(psi,Az,zAz,zAAz);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
r=src-Az;
|
r=src-Az;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// p = Prec(r)
|
// p = Prec(r)
|
||||||
@ -152,8 +155,10 @@ namespace Grid {
|
|||||||
Linop.HermOp(z,tmp);
|
Linop.HermOp(z,tmp);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
ttmp=tmp;
|
ttmp=tmp;
|
||||||
tmp=tmp-r;
|
tmp=tmp-r;
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
std::cout<<GridLogMessage<<r<<std::endl;
|
std::cout<<GridLogMessage<<r<<std::endl;
|
||||||
@ -166,12 +171,14 @@ namespace Grid {
|
|||||||
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
//p[0],q[0],qq[0]
|
//p[0],q[0],qq[0]
|
||||||
p[0]= z;
|
p[0]= z;
|
||||||
q[0]= Az;
|
q[0]= Az;
|
||||||
qq[0]= zAAz;
|
qq[0]= zAAz;
|
||||||
|
|
||||||
cp =norm2(r);
|
cp =norm2(r);
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
for(int k=0;k<nstep;k++){
|
for(int k=0;k<nstep;k++){
|
||||||
|
|
||||||
@ -181,12 +188,14 @@ namespace Grid {
|
|||||||
int peri_k = k %mmax;
|
int peri_k = k %mmax;
|
||||||
int peri_kp= kp%mmax;
|
int peri_kp= kp%mmax;
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
rq= real(innerProduct(r,q[peri_k])); // what if rAr not real?
|
rq= real(innerProduct(r,q[peri_k])); // what if rAr not real?
|
||||||
a = rq/qq[peri_k];
|
a = rq/qq[peri_k];
|
||||||
|
|
||||||
axpy(psi,a,p[peri_k],psi);
|
axpy(psi,a,p[peri_k],psi);
|
||||||
|
|
||||||
cp = axpy_norm(r,-a,q[peri_k],r);
|
cp = axpy_norm(r,-a,q[peri_k],r);
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
if((k==nstep-1)||(cp<rsq)){
|
if((k==nstep-1)||(cp<rsq)){
|
||||||
return cp;
|
return cp;
|
||||||
@ -202,6 +211,8 @@ namespace Grid {
|
|||||||
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
Linop.HermOpAndNorm(z,Az,zAz,zAAz);
|
||||||
Linop.HermOp(z,tmp);
|
Linop.HermOp(z,tmp);
|
||||||
MatTimer.Stop();
|
MatTimer.Stop();
|
||||||
|
|
||||||
|
LinalgTimer.Start();
|
||||||
tmp=tmp-r;
|
tmp=tmp-r;
|
||||||
std::cout<<GridLogMessage<< " Preconditioner resid " <<sqrt(norm2(tmp)/norm2(r))<<std::endl;
|
std::cout<<GridLogMessage<< " Preconditioner resid " <<sqrt(norm2(tmp)/norm2(r))<<std::endl;
|
||||||
|
|
||||||
@ -219,9 +230,9 @@ namespace Grid {
|
|||||||
|
|
||||||
}
|
}
|
||||||
qq[peri_kp]=norm2(q[peri_kp]); // could use axpy_norm
|
qq[peri_kp]=norm2(q[peri_kp]); // could use axpy_norm
|
||||||
|
LinalgTimer.Stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0); // never reached
|
assert(0); // never reached
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,6 @@ void CartesianCommunicator::Init(int *argc, char ***argv)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grid_quiesce_nodes();
|
|
||||||
|
|
||||||
// Never clean up as done once.
|
// Never clean up as done once.
|
||||||
MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world);
|
MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world);
|
||||||
|
|
||||||
@ -124,10 +122,8 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,
|
|||||||
// split the communicator
|
// split the communicator
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// int Nparent = parent._processors ;
|
// int Nparent = parent._processors ;
|
||||||
// std::cout << " splitting from communicator "<<parent.communicator <<std::endl;
|
|
||||||
int Nparent;
|
int Nparent;
|
||||||
MPI_Comm_size(parent.communicator,&Nparent);
|
MPI_Comm_size(parent.communicator,&Nparent);
|
||||||
// std::cout << " Parent size "<<Nparent <<std::endl;
|
|
||||||
|
|
||||||
int childsize=1;
|
int childsize=1;
|
||||||
for(int d=0;d<processors.size();d++) {
|
for(int d=0;d<processors.size();d++) {
|
||||||
@ -136,8 +132,6 @@ CartesianCommunicator::CartesianCommunicator(const std::vector<int> &processors,
|
|||||||
int Nchild = Nparent/childsize;
|
int Nchild = Nparent/childsize;
|
||||||
assert (childsize * Nchild == Nparent);
|
assert (childsize * Nchild == Nparent);
|
||||||
|
|
||||||
// std::cout << " child size "<<childsize <<std::endl;
|
|
||||||
|
|
||||||
std::vector<int> ccoor(_ndimension); // coor within subcommunicator
|
std::vector<int> ccoor(_ndimension); // coor within subcommunicator
|
||||||
std::vector<int> scoor(_ndimension); // coor of split within parent
|
std::vector<int> scoor(_ndimension); // coor of split within parent
|
||||||
std::vector<int> ssize(_ndimension); // coor of split within parent
|
std::vector<int> ssize(_ndimension); // coor of split within parent
|
||||||
|
@ -413,7 +413,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
assert(((uint64_t)ptr&0x3F)==0);
|
assert(((uint64_t)ptr&0x3F)==0);
|
||||||
close(fd);
|
close(fd);
|
||||||
WorldShmCommBufs[r] =ptr;
|
WorldShmCommBufs[r] =ptr;
|
||||||
std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
// std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
||||||
}
|
}
|
||||||
_ShmAlloc=1;
|
_ShmAlloc=1;
|
||||||
_ShmAllocBytes = bytes;
|
_ShmAllocBytes = bytes;
|
||||||
@ -455,7 +455,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
assert(((uint64_t)ptr&0x3F)==0);
|
assert(((uint64_t)ptr&0x3F)==0);
|
||||||
close(fd);
|
close(fd);
|
||||||
WorldShmCommBufs[r] =ptr;
|
WorldShmCommBufs[r] =ptr;
|
||||||
std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
// std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< bytes<< "bytes)"<<std::endl;
|
||||||
}
|
}
|
||||||
_ShmAlloc=1;
|
_ShmAlloc=1;
|
||||||
_ShmAllocBytes = bytes;
|
_ShmAllocBytes = bytes;
|
||||||
@ -499,7 +499,7 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags)
|
|||||||
#endif
|
#endif
|
||||||
void * ptr = mmap(NULL,size, PROT_READ | PROT_WRITE, mmap_flag, fd, 0);
|
void * ptr = mmap(NULL,size, PROT_READ | PROT_WRITE, mmap_flag, fd, 0);
|
||||||
|
|
||||||
std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< size<< "bytes)"<<std::endl;
|
// std::cout << "Set WorldShmCommBufs["<<r<<"]="<<ptr<< "("<< size<< "bytes)"<<std::endl;
|
||||||
if ( ptr == (void * )MAP_FAILED ) {
|
if ( ptr == (void * )MAP_FAILED ) {
|
||||||
perror("failed mmap");
|
perror("failed mmap");
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -464,9 +464,11 @@ void InsertSliceLocal(const Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int
|
|||||||
assert(orthog>=0);
|
assert(orthog>=0);
|
||||||
|
|
||||||
for(int d=0;d<nh;d++){
|
for(int d=0;d<nh;d++){
|
||||||
|
if ( d!=orthog ) {
|
||||||
assert(lg->_processors[d] == hg->_processors[d]);
|
assert(lg->_processors[d] == hg->_processors[d]);
|
||||||
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the above should guarantee that the operations are local
|
// the above should guarantee that the operations are local
|
||||||
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
||||||
@ -485,7 +487,7 @@ void InsertSliceLocal(const Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int
|
|||||||
|
|
||||||
|
|
||||||
template<class vobj>
|
template<class vobj>
|
||||||
void ExtractSliceLocal(Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int slice_lo,int slice_hi, int orthog)
|
void ExtractSliceLocal(Lattice<vobj> &lowDim,const Lattice<vobj> & higherDim,int slice_lo,int slice_hi, int orthog)
|
||||||
{
|
{
|
||||||
typedef typename vobj::scalar_object sobj;
|
typedef typename vobj::scalar_object sobj;
|
||||||
|
|
||||||
@ -499,9 +501,11 @@ void ExtractSliceLocal(Lattice<vobj> &lowDim, Lattice<vobj> & higherDim,int slic
|
|||||||
assert(orthog>=0);
|
assert(orthog>=0);
|
||||||
|
|
||||||
for(int d=0;d<nh;d++){
|
for(int d=0;d<nh;d++){
|
||||||
|
if ( d!=orthog ) {
|
||||||
assert(lg->_processors[d] == hg->_processors[d]);
|
assert(lg->_processors[d] == hg->_processors[d]);
|
||||||
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
assert(lg->_ldimensions[d] == hg->_ldimensions[d]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the above should guarantee that the operations are local
|
// the above should guarantee that the operations are local
|
||||||
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
parallel_for(int idx=0;idx<lg->lSites();idx++){
|
||||||
|
@ -59,6 +59,7 @@ void GridLogTimestamp(int on){
|
|||||||
}
|
}
|
||||||
|
|
||||||
Colours GridLogColours(0);
|
Colours GridLogColours(0);
|
||||||
|
GridLogger GridLogMG (1, "MG" , GridLogColours, "NORMAL");
|
||||||
GridLogger GridLogIRL (1, "IRL" , GridLogColours, "NORMAL");
|
GridLogger GridLogIRL (1, "IRL" , GridLogColours, "NORMAL");
|
||||||
GridLogger GridLogSolver (1, "Solver", GridLogColours, "NORMAL");
|
GridLogger GridLogSolver (1, "Solver", GridLogColours, "NORMAL");
|
||||||
GridLogger GridLogError (1, "Error" , GridLogColours, "RED");
|
GridLogger GridLogError (1, "Error" , GridLogColours, "RED");
|
||||||
|
@ -169,6 +169,7 @@ public:
|
|||||||
|
|
||||||
void GridLogConfigure(std::vector<std::string> &logstreams);
|
void GridLogConfigure(std::vector<std::string> &logstreams);
|
||||||
|
|
||||||
|
extern GridLogger GridLogMG;
|
||||||
extern GridLogger GridLogIRL;
|
extern GridLogger GridLogIRL;
|
||||||
extern GridLogger GridLogSolver;
|
extern GridLogger GridLogSolver;
|
||||||
extern GridLogger GridLogError;
|
extern GridLogger GridLogError;
|
||||||
|
3
Grid/parallelIO/BinaryIO.cc
Normal file
3
Grid/parallelIO/BinaryIO.cc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include <Grid/GridCore.h>
|
||||||
|
|
||||||
|
int Grid::BinaryIO::latticeWriteMaxRetry = -1;
|
@ -81,6 +81,7 @@ inline void removeWhitespace(std::string &key)
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
class BinaryIO {
|
class BinaryIO {
|
||||||
public:
|
public:
|
||||||
|
static int latticeWriteMaxRetry;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// more byte manipulation helpers
|
// more byte manipulation helpers
|
||||||
@ -370,7 +371,7 @@ PARALLEL_CRITICAL
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : "
|
std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : "
|
||||||
<< iodata.size() * sizeof(fobj) << " bytes" << std::endl;
|
<< iodata.size() * sizeof(fobj) << " bytes and offset " << offset << std::endl;
|
||||||
std::ifstream fin;
|
std::ifstream fin;
|
||||||
fin.open(file, std::ios::binary | std::ios::in);
|
fin.open(file, std::ios::binary | std::ios::in);
|
||||||
if (control & BINARYIO_MASTER_APPEND)
|
if (control & BINARYIO_MASTER_APPEND)
|
||||||
@ -582,7 +583,9 @@ PARALLEL_CRITICAL
|
|||||||
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;
|
||||||
GridBase *grid = Umu._grid;
|
GridBase *grid = Umu._grid;
|
||||||
uint64_t lsites = grid->lSites();
|
uint64_t lsites = grid->lSites(), offsetCopy = offset;
|
||||||
|
int attemptsLeft = std::max(0, BinaryIO::latticeWriteMaxRetry);
|
||||||
|
bool checkWrite = (BinaryIO::latticeWriteMaxRetry >= 0);
|
||||||
|
|
||||||
std::vector<sobj> scalardata(lsites);
|
std::vector<sobj> scalardata(lsites);
|
||||||
std::vector<fobj> iodata(lsites); // Munge, checksum, byte order in here
|
std::vector<fobj> iodata(lsites); // Munge, checksum, byte order in here
|
||||||
@ -597,9 +600,35 @@ PARALLEL_CRITICAL
|
|||||||
|
|
||||||
grid->Barrier();
|
grid->Barrier();
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
|
while (attemptsLeft >= 0)
|
||||||
|
{
|
||||||
|
grid->Barrier();
|
||||||
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
IOobject(w,grid,iodata,file,offset,format,BINARYIO_WRITE|BINARYIO_LEXICOGRAPHIC,
|
||||||
nersc_csum,scidac_csuma,scidac_csumb);
|
nersc_csum,scidac_csuma,scidac_csumb);
|
||||||
|
if (checkWrite)
|
||||||
|
{
|
||||||
|
std::vector<fobj> ckiodata(lsites);
|
||||||
|
uint32_t cknersc_csum, ckscidac_csuma, ckscidac_csumb;
|
||||||
|
uint64_t ckoffset = offsetCopy;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "writeLatticeObject: read back object" << std::endl;
|
||||||
|
grid->Barrier();
|
||||||
|
IOobject(w,grid,ckiodata,file,ckoffset,format,BINARYIO_READ|BINARYIO_LEXICOGRAPHIC,
|
||||||
|
cknersc_csum,ckscidac_csuma,ckscidac_csumb);
|
||||||
|
if ((cknersc_csum != nersc_csum) or (ckscidac_csuma != scidac_csuma) or (ckscidac_csumb != scidac_csumb))
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << "writeLatticeObject: read test checksum failure, re-writing (" << attemptsLeft << " attempt(s) remaining)" << std::endl;
|
||||||
|
offset = offsetCopy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << "writeLatticeObject: read test checksum correct" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attemptsLeft--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::cout<<GridLogMessage<<"writeLatticeObject: unvectorize overhead "<<timer.Elapsed() <<std::endl;
|
std::cout<<GridLogMessage<<"writeLatticeObject: unvectorize overhead "<<timer.Elapsed() <<std::endl;
|
||||||
}
|
}
|
||||||
@ -725,5 +754,6 @@ PARALLEL_CRITICAL
|
|||||||
std::cout << GridLogMessage << "RNG state overhead " << timer.Elapsed() << std::endl;
|
std::cout << GridLogMessage << "RNG state overhead " << timer.Elapsed() << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,7 +65,9 @@ inline std::ostream& operator<< (std::ostream & stream, const GridMillisecs & no
|
|||||||
GridSecs second(1);
|
GridSecs second(1);
|
||||||
auto secs = now/second ;
|
auto secs = now/second ;
|
||||||
auto subseconds = now%second ;
|
auto subseconds = now%second ;
|
||||||
|
auto fill = stream.fill();
|
||||||
stream << secs<<"."<<std::setw(3)<<std::setfill('0')<<subseconds.count()<<" s";
|
stream << secs<<"."<<std::setw(3)<<std::setfill('0')<<subseconds.count()<<" s";
|
||||||
|
stream.fill(fill);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
inline std::ostream& operator<< (std::ostream & stream, const GridUsecs & now)
|
inline std::ostream& operator<< (std::ostream & stream, const GridUsecs & now)
|
||||||
@ -73,7 +75,9 @@ inline std::ostream& operator<< (std::ostream & stream, const GridUsecs & now)
|
|||||||
GridSecs second(1);
|
GridSecs second(1);
|
||||||
auto seconds = now/second ;
|
auto seconds = now/second ;
|
||||||
auto subseconds = now%second ;
|
auto subseconds = now%second ;
|
||||||
|
auto fill = stream.fill();
|
||||||
stream << seconds<<"."<<std::setw(6)<<std::setfill('0')<<subseconds.count()<<" s";
|
stream << seconds<<"."<<std::setw(6)<<std::setfill('0')<<subseconds.count()<<" s";
|
||||||
|
stream.fill(fill);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,12 +44,15 @@ namespace QCD {
|
|||||||
|
|
||||||
struct WilsonImplParams {
|
struct WilsonImplParams {
|
||||||
bool overlapCommsCompute;
|
bool overlapCommsCompute;
|
||||||
|
std::vector<Real> twist_n_2pi_L;
|
||||||
std::vector<Complex> boundary_phases;
|
std::vector<Complex> boundary_phases;
|
||||||
WilsonImplParams() : overlapCommsCompute(false) {
|
WilsonImplParams() : overlapCommsCompute(false) {
|
||||||
boundary_phases.resize(Nd, 1.0);
|
boundary_phases.resize(Nd, 1.0);
|
||||||
|
twist_n_2pi_L.resize(Nd, 0.0);
|
||||||
};
|
};
|
||||||
WilsonImplParams(const std::vector<Complex> phi)
|
WilsonImplParams(const std::vector<Complex> phi) : boundary_phases(phi), overlapCommsCompute(false) {
|
||||||
: boundary_phases(phi), overlapCommsCompute(false) {}
|
twist_n_2pi_L.resize(Nd, 0.0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StaggeredImplParams {
|
struct StaggeredImplParams {
|
||||||
|
@ -240,16 +240,30 @@ namespace QCD {
|
|||||||
GaugeLinkField tmp(GaugeGrid);
|
GaugeLinkField tmp(GaugeGrid);
|
||||||
|
|
||||||
Lattice<iScalar<vInteger> > coor(GaugeGrid);
|
Lattice<iScalar<vInteger> > coor(GaugeGrid);
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
// apply any boundary phase or twists
|
||||||
|
////////////////////////////////////////////////////
|
||||||
for (int mu = 0; mu < Nd; mu++) {
|
for (int mu = 0; mu < Nd; mu++) {
|
||||||
|
|
||||||
|
////////// boundary phase /////////////
|
||||||
auto pha = Params.boundary_phases[mu];
|
auto pha = Params.boundary_phases[mu];
|
||||||
scalar_type phase( real(pha),imag(pha) );
|
scalar_type phase( real(pha),imag(pha) );
|
||||||
|
|
||||||
int Lmu = GaugeGrid->GlobalDimensions()[mu] - 1;
|
int L = GaugeGrid->GlobalDimensions()[mu];
|
||||||
|
int Lmu = L - 1;
|
||||||
|
|
||||||
LatticeCoordinate(coor, mu);
|
LatticeCoordinate(coor, mu);
|
||||||
|
|
||||||
U = PeekIndex<LorentzIndex>(Umu, mu);
|
U = PeekIndex<LorentzIndex>(Umu, mu);
|
||||||
|
|
||||||
|
// apply any twists
|
||||||
|
RealD theta = Params.twist_n_2pi_L[mu] * 2*M_PI / L;
|
||||||
|
if ( theta != 0.0) {
|
||||||
|
scalar_type twphase(::cos(theta),::sin(theta));
|
||||||
|
U = twphase*U;
|
||||||
|
std::cout << GridLogMessage << " Twist ["<<mu<<"] "<< Params.twist_n_2pi_L[mu]<< " phase"<<phase <<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
tmp = where(coor == Lmu, phase * U, U);
|
tmp = where(coor == Lmu, phase * U, U);
|
||||||
PokeIndex<LorentzIndex>(Uds, tmp, mu);
|
PokeIndex<LorentzIndex>(Uds, tmp, mu);
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
Source file: ./lib/qcd/action/gauge/Photon.h
|
Source file: ./lib/qcd/action/gauge/Photon.h
|
||||||
|
|
||||||
Copyright (C) 2015
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
Author: Antonin Portelli <antonin.portelli@me.com>
|
||||||
|
Author: James Harrison <J.Harrison@soton.ac.uk>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -30,8 +32,9 @@
|
|||||||
|
|
||||||
namespace Grid{
|
namespace Grid{
|
||||||
namespace QCD{
|
namespace QCD{
|
||||||
|
|
||||||
template <class S>
|
template <class S>
|
||||||
class QedGimpl
|
class QedGImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef S Simd;
|
typedef S Simd;
|
||||||
@ -43,27 +46,27 @@ namespace QCD{
|
|||||||
|
|
||||||
typedef iImplGaugeLink<Simd> SiteLink;
|
typedef iImplGaugeLink<Simd> SiteLink;
|
||||||
typedef iImplGaugeField<Simd> SiteField;
|
typedef iImplGaugeField<Simd> SiteField;
|
||||||
typedef SiteField SiteComplex;
|
typedef SiteLink SiteComplex;
|
||||||
|
|
||||||
typedef Lattice<SiteLink> LinkField;
|
typedef Lattice<SiteLink> LinkField;
|
||||||
typedef Lattice<SiteField> Field;
|
typedef Lattice<SiteField> Field;
|
||||||
typedef Field ComplexField;
|
typedef Field ComplexField;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QedGimpl<vComplex> QedGimplR;
|
typedef QedGImpl<vComplex> QedGImplR;
|
||||||
|
|
||||||
template<class Gimpl>
|
template <class GImpl>
|
||||||
class Photon
|
class Photon
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
INHERIT_GIMPL_TYPES(Gimpl);
|
INHERIT_GIMPL_TYPES(GImpl);
|
||||||
|
typedef typename SiteGaugeLink::scalar_object ScalarSite;
|
||||||
|
typedef typename ScalarSite::scalar_type ScalarComplex;
|
||||||
GRID_SERIALIZABLE_ENUM(Gauge, undef, feynman, 1, coulomb, 2, landau, 3);
|
GRID_SERIALIZABLE_ENUM(Gauge, undef, feynman, 1, coulomb, 2, landau, 3);
|
||||||
GRID_SERIALIZABLE_ENUM(ZmScheme, undef, qedL, 1, qedTL, 2, qedInf, 3);
|
GRID_SERIALIZABLE_ENUM(ZmScheme, undef, qedL, 1, qedTL, 2);
|
||||||
public:
|
public:
|
||||||
Photon(Gauge gauge, ZmScheme zmScheme);
|
Photon(GridBase *grid, Gauge gauge, ZmScheme zmScheme, std::vector<Real> improvement);
|
||||||
Photon(Gauge gauge, ZmScheme zmScheme, std::vector<Real> improvements);
|
Photon(GridBase *grid, Gauge gauge, ZmScheme zmScheme);
|
||||||
Photon(Gauge gauge, ZmScheme zmScheme, Real G0);
|
|
||||||
Photon(Gauge gauge, ZmScheme zmScheme, std::vector<Real> improvements, Real G0);
|
|
||||||
virtual ~Photon(void) = default;
|
virtual ~Photon(void) = default;
|
||||||
void FreePropagator(const GaugeField &in, GaugeField &out);
|
void FreePropagator(const GaugeField &in, GaugeField &out);
|
||||||
void MomentumSpacePropagator(const GaugeField &in, GaugeField &out);
|
void MomentumSpacePropagator(const GaugeField &in, GaugeField &out);
|
||||||
@ -73,345 +76,255 @@ namespace QCD{
|
|||||||
const GaugeLinkField &weight);
|
const GaugeLinkField &weight);
|
||||||
void UnitField(GaugeField &out);
|
void UnitField(GaugeField &out);
|
||||||
private:
|
private:
|
||||||
void infVolPropagator(GaugeLinkField &out);
|
void makeSpatialNorm(LatticeInteger &spNrm);
|
||||||
void invKHatSquared(GaugeLinkField &out);
|
void makeKHat(std::vector<GaugeLinkField> &khat);
|
||||||
|
void makeInvKHatSquared(GaugeLinkField &out);
|
||||||
void zmSub(GaugeLinkField &out);
|
void zmSub(GaugeLinkField &out);
|
||||||
|
void transverseProjectSpatial(GaugeField &out);
|
||||||
|
void gaugeTransform(GaugeField &out);
|
||||||
private:
|
private:
|
||||||
|
GridBase *grid_;
|
||||||
Gauge gauge_;
|
Gauge gauge_;
|
||||||
ZmScheme zmScheme_;
|
ZmScheme zmScheme_;
|
||||||
std::vector<Real> improvement_;
|
std::vector<Real> improvement_;
|
||||||
Real G0_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Photon<QedGimplR> PhotonR;
|
typedef Photon<QedGImplR> PhotonR;
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
Photon<Gimpl>::Photon(Gauge gauge, ZmScheme zmScheme)
|
Photon<GImpl>::Photon(GridBase *grid, Gauge gauge, ZmScheme zmScheme,
|
||||||
: gauge_(gauge), zmScheme_(zmScheme), improvement_(std::vector<Real>()),
|
|
||||||
G0_(0.15493339023106021408483720810737508876916113364521)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<class Gimpl>
|
|
||||||
Photon<Gimpl>::Photon(Gauge gauge, ZmScheme zmScheme,
|
|
||||||
std::vector<Real> improvements)
|
std::vector<Real> improvements)
|
||||||
: gauge_(gauge), zmScheme_(zmScheme), improvement_(improvements),
|
: grid_(grid), gauge_(gauge), zmScheme_(zmScheme), improvement_(improvements)
|
||||||
G0_(0.15493339023106021408483720810737508876916113364521)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
Photon<Gimpl>::Photon(Gauge gauge, ZmScheme zmScheme, Real G0)
|
Photon<GImpl>::Photon(GridBase *grid, Gauge gauge, ZmScheme zmScheme)
|
||||||
: gauge_(gauge), zmScheme_(zmScheme), improvement_(std::vector<Real>()), G0_(G0)
|
: Photon(grid, gauge, zmScheme, std::vector<Real>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
Photon<Gimpl>::Photon(Gauge gauge, ZmScheme zmScheme,
|
void Photon<GImpl>::FreePropagator(const GaugeField &in, GaugeField &out)
|
||||||
std::vector<Real> improvements, Real G0)
|
|
||||||
: gauge_(gauge), zmScheme_(zmScheme), improvement_(improvements), G0_(G0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<class Gimpl>
|
|
||||||
void Photon<Gimpl>::FreePropagator (const GaugeField &in,GaugeField &out)
|
|
||||||
{
|
{
|
||||||
FFT theFFT(in._grid);
|
FFT theFFT(dynamic_cast<GridCartesian *>(grid_));
|
||||||
|
GaugeField in_k(grid_);
|
||||||
GaugeField in_k(in._grid);
|
GaugeField prop_k(grid_);
|
||||||
GaugeField prop_k(in._grid);
|
|
||||||
|
|
||||||
theFFT.FFT_all_dim(in_k, in, FFT::forward);
|
theFFT.FFT_all_dim(in_k, in, FFT::forward);
|
||||||
MomentumSpacePropagator(prop_k, in_k);
|
MomentumSpacePropagator(prop_k, in_k);
|
||||||
theFFT.FFT_all_dim(out, prop_k, FFT::backward);
|
theFFT.FFT_all_dim(out, prop_k, FFT::backward);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::infVolPropagator(GaugeLinkField &out)
|
void Photon<GImpl>::makeSpatialNorm(LatticeInteger &spNrm)
|
||||||
{
|
{
|
||||||
auto *grid = dynamic_cast<GridCartesian *>(out._grid);
|
LatticeInteger coor(grid_);
|
||||||
LatticeReal xmu(grid);
|
std::vector<int> l = grid_->FullDimensions();
|
||||||
GaugeLinkField one(grid);
|
|
||||||
const unsigned int nd = grid->_ndimension;
|
|
||||||
std::vector<int> &l = grid->_fdimensions;
|
|
||||||
std::vector<int> x0(nd,0);
|
|
||||||
TComplex Tone = Complex(1.0,0.0);
|
|
||||||
TComplex Tzero = Complex(G0_,0.0);
|
|
||||||
FFT fft(grid);
|
|
||||||
|
|
||||||
one = Complex(1.0,0.0);
|
spNrm = zero;
|
||||||
out = zero;
|
for(int mu = 0; mu < grid_->Nd() - 1; mu++)
|
||||||
for(int mu = 0; mu < nd; mu++)
|
|
||||||
{
|
{
|
||||||
LatticeCoordinate(xmu,mu);
|
LatticeCoordinate(coor, mu);
|
||||||
Real lo2 = l[mu]/2.0;
|
coor = where(coor < Integer(l[mu]/2), coor, coor - Integer(l[mu]));
|
||||||
xmu = where(xmu < lo2, xmu, xmu-double(l[mu]));
|
spNrm = spNrm + coor*coor;
|
||||||
out = out + toComplex(4*M_PI*M_PI*xmu*xmu);
|
|
||||||
}
|
}
|
||||||
pokeSite(Tone, out, x0);
|
|
||||||
out = one/out;
|
|
||||||
pokeSite(Tzero, out, x0);
|
|
||||||
fft.FFT_all_dim(out, out, FFT::forward);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::invKHatSquared(GaugeLinkField &out)
|
void Photon<GImpl>::makeKHat(std::vector<GaugeLinkField> &khat)
|
||||||
{
|
{
|
||||||
GridBase *grid = out._grid;
|
const unsigned int nd = grid_->Nd();
|
||||||
GaugeLinkField kmu(grid), one(grid);
|
std::vector<int> l = grid_->FullDimensions();
|
||||||
const unsigned int nd = grid->_ndimension;
|
Complex ci(0., 1.);
|
||||||
std::vector<int> &l = grid->_fdimensions;
|
|
||||||
|
khat.resize(nd, grid_);
|
||||||
|
for (unsigned int mu = 0; mu < nd; ++mu)
|
||||||
|
{
|
||||||
|
Real piL = M_PI/l[mu];
|
||||||
|
|
||||||
|
LatticeCoordinate(khat[mu], mu);
|
||||||
|
khat[mu] = exp(piL*ci*khat[mu])*2.*sin(piL*khat[mu]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class GImpl>
|
||||||
|
void Photon<GImpl>::makeInvKHatSquared(GaugeLinkField &out)
|
||||||
|
{
|
||||||
|
std::vector<GaugeLinkField> khat;
|
||||||
|
GaugeLinkField lone(grid_);
|
||||||
|
const unsigned int nd = grid_->Nd();
|
||||||
std::vector<int> zm(nd, 0);
|
std::vector<int> zm(nd, 0);
|
||||||
TComplex Tone = Complex(1.0,0.0);
|
ScalarSite one = ScalarComplex(1., 0.), z = ScalarComplex(0., 0.);
|
||||||
TComplex Tzero= Complex(0.0,0.0);
|
|
||||||
|
|
||||||
one = Complex(1.0,0.0);
|
|
||||||
out = zero;
|
out = zero;
|
||||||
|
makeKHat(khat);
|
||||||
for(int mu = 0; mu < nd; mu++)
|
for(int mu = 0; mu < nd; mu++)
|
||||||
{
|
{
|
||||||
Real twoPiL = M_PI*2./l[mu];
|
out = out + khat[mu]*conjugate(khat[mu]);
|
||||||
|
|
||||||
LatticeCoordinate(kmu,mu);
|
|
||||||
kmu = 2.*sin(.5*twoPiL*kmu);
|
|
||||||
out = out + kmu*kmu;
|
|
||||||
}
|
}
|
||||||
pokeSite(Tone, out, zm);
|
lone = ScalarComplex(1., 0.);
|
||||||
out = one/out;
|
pokeSite(one, out, zm);
|
||||||
pokeSite(Tzero, out, zm);
|
out = lone/out;
|
||||||
|
pokeSite(z, out, zm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::zmSub(GaugeLinkField &out)
|
void Photon<GImpl>::zmSub(GaugeLinkField &out)
|
||||||
{
|
{
|
||||||
GridBase *grid = out._grid;
|
|
||||||
const unsigned int nd = grid->_ndimension;
|
|
||||||
std::vector<int> &l = grid->_fdimensions;
|
|
||||||
|
|
||||||
switch (zmScheme_)
|
switch (zmScheme_)
|
||||||
{
|
{
|
||||||
case ZmScheme::qedTL:
|
case ZmScheme::qedTL:
|
||||||
{
|
{
|
||||||
std::vector<int> zm(nd,0);
|
std::vector<int> zm(grid_->Nd(), 0);
|
||||||
TComplex Tzero = Complex(0.0,0.0);
|
ScalarSite z = ScalarComplex(0., 0.);
|
||||||
|
|
||||||
pokeSite(Tzero, out, zm);
|
|
||||||
|
|
||||||
|
pokeSite(z, out, zm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ZmScheme::qedL:
|
case ZmScheme::qedL:
|
||||||
{
|
{
|
||||||
LatticeInteger spNrm(grid), coor(grid);
|
LatticeInteger spNrm(grid_);
|
||||||
GaugeLinkField z(grid);
|
|
||||||
|
|
||||||
spNrm = zero;
|
makeSpatialNorm(spNrm);
|
||||||
for(int d = 0; d < grid->_ndimension - 1; d++)
|
|
||||||
{
|
|
||||||
LatticeCoordinate(coor,d);
|
|
||||||
coor = where(coor < Integer(l[d]/2), coor, coor-Integer(l[d]));
|
|
||||||
spNrm = spNrm + coor*coor;
|
|
||||||
}
|
|
||||||
out = where(spNrm == Integer(0), 0.*out, out);
|
out = where(spNrm == Integer(0), 0.*out, out);
|
||||||
|
|
||||||
// IR improvement
|
|
||||||
for(int i = 0; i < improvement_.size(); i++)
|
for(int i = 0; i < improvement_.size(); i++)
|
||||||
{
|
{
|
||||||
Real f = sqrt(improvement_[i] + 1);
|
Real f = sqrt(improvement_[i] + 1);
|
||||||
out = where(spNrm == Integer(i + 1), f*out, out);
|
out = where(spNrm == Integer(i + 1), f*out, out);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
assert(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::MomentumSpacePropagator(const GaugeField &in,
|
void Photon<GImpl>::transverseProjectSpatial(GaugeField &out)
|
||||||
|
{
|
||||||
|
const unsigned int nd = grid_->Nd();
|
||||||
|
GaugeLinkField invKHat(grid_), cst(grid_), spdiv(grid_);
|
||||||
|
LatticeInteger spNrm(grid_);
|
||||||
|
std::vector<GaugeLinkField> khat, a(nd, grid_), aProj(nd, grid_);
|
||||||
|
|
||||||
|
invKHat = zero;
|
||||||
|
makeSpatialNorm(spNrm);
|
||||||
|
makeKHat(khat);
|
||||||
|
for (unsigned int mu = 0; mu < nd; ++mu)
|
||||||
|
{
|
||||||
|
a[mu] = peekLorentz(out, mu);
|
||||||
|
if (mu < nd - 1)
|
||||||
|
{
|
||||||
|
invKHat += khat[mu]*conjugate(khat[mu]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cst = ScalarComplex(1., 0.);
|
||||||
|
invKHat = where(spNrm == Integer(0), cst, invKHat);
|
||||||
|
invKHat = cst/invKHat;
|
||||||
|
cst = zero;
|
||||||
|
invKHat = where(spNrm == Integer(0), cst, invKHat);
|
||||||
|
spdiv = zero;
|
||||||
|
for (unsigned int nu = 0; nu < nd - 1; ++nu)
|
||||||
|
{
|
||||||
|
spdiv += conjugate(khat[nu])*a[nu];
|
||||||
|
}
|
||||||
|
spdiv *= invKHat;
|
||||||
|
for (unsigned int mu = 0; mu < nd; ++mu)
|
||||||
|
{
|
||||||
|
aProj[mu] = a[mu] - khat[mu]*spdiv;
|
||||||
|
pokeLorentz(out, aProj[mu], mu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class GImpl>
|
||||||
|
void Photon<GImpl>::gaugeTransform(GaugeField &out)
|
||||||
|
{
|
||||||
|
switch (gauge_)
|
||||||
|
{
|
||||||
|
case Gauge::feynman:
|
||||||
|
break;
|
||||||
|
case Gauge::coulomb:
|
||||||
|
transverseProjectSpatial(out);
|
||||||
|
break;
|
||||||
|
case Gauge::landau:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class GImpl>
|
||||||
|
void Photon<GImpl>::MomentumSpacePropagator(const GaugeField &in,
|
||||||
GaugeField &out)
|
GaugeField &out)
|
||||||
{
|
{
|
||||||
GridBase *grid = out._grid;
|
LatticeComplex momProp(grid_);
|
||||||
LatticeComplex momProp(grid);
|
|
||||||
|
|
||||||
switch (zmScheme_)
|
makeInvKHatSquared(momProp);
|
||||||
{
|
|
||||||
case ZmScheme::qedTL:
|
|
||||||
case ZmScheme::qedL:
|
|
||||||
{
|
|
||||||
invKHatSquared(momProp);
|
|
||||||
zmSub(momProp);
|
zmSub(momProp);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ZmScheme::qedInf:
|
|
||||||
{
|
|
||||||
infVolPropagator(momProp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out = in*momProp;
|
out = in*momProp;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::StochasticWeight(GaugeLinkField &weight)
|
void Photon<GImpl>::StochasticWeight(GaugeLinkField &weight)
|
||||||
{
|
|
||||||
auto *grid = dynamic_cast<GridCartesian *>(weight._grid);
|
|
||||||
const unsigned int nd = grid->_ndimension;
|
|
||||||
std::vector<int> latt_size = grid->_fdimensions;
|
|
||||||
|
|
||||||
switch (zmScheme_)
|
|
||||||
{
|
|
||||||
case ZmScheme::qedTL:
|
|
||||||
case ZmScheme::qedL:
|
|
||||||
{
|
{
|
||||||
|
const unsigned int nd = grid_->Nd();
|
||||||
|
std::vector<int> l = grid_->FullDimensions();
|
||||||
Integer vol = 1;
|
Integer vol = 1;
|
||||||
for(int d = 0; d < nd; d++)
|
|
||||||
|
for(unsigned int mu = 0; mu < nd; mu++)
|
||||||
{
|
{
|
||||||
vol = vol * latt_size[d];
|
vol = vol*l[mu];
|
||||||
}
|
}
|
||||||
invKHatSquared(weight);
|
makeInvKHatSquared(weight);
|
||||||
weight = sqrt(vol)*sqrt(weight);
|
weight = sqrt(vol)*sqrt(weight);
|
||||||
zmSub(weight);
|
zmSub(weight);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ZmScheme::qedInf:
|
|
||||||
{
|
|
||||||
infVolPropagator(weight);
|
|
||||||
weight = sqrt(real(weight));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::StochasticField(GaugeField &out, GridParallelRNG &rng)
|
void Photon<GImpl>::StochasticField(GaugeField &out, GridParallelRNG &rng)
|
||||||
{
|
{
|
||||||
auto *grid = dynamic_cast<GridCartesian *>(out._grid);
|
GaugeLinkField weight(grid_);
|
||||||
GaugeLinkField weight(grid);
|
|
||||||
|
|
||||||
StochasticWeight(weight);
|
StochasticWeight(weight);
|
||||||
StochasticField(out, rng, weight);
|
StochasticField(out, rng, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::StochasticField(GaugeField &out, GridParallelRNG &rng,
|
void Photon<GImpl>::StochasticField(GaugeField &out, GridParallelRNG &rng,
|
||||||
const GaugeLinkField &weight)
|
const GaugeLinkField &weight)
|
||||||
{
|
{
|
||||||
auto *grid = dynamic_cast<GridCartesian *>(out._grid);
|
const unsigned int nd = grid_->Nd();
|
||||||
const unsigned int nd = grid->_ndimension;
|
GaugeLinkField r(grid_);
|
||||||
GaugeLinkField r(grid);
|
GaugeField aTilde(grid_);
|
||||||
GaugeField aTilde(grid);
|
FFT fft(dynamic_cast<GridCartesian *>(grid_));
|
||||||
FFT fft(grid);
|
|
||||||
|
|
||||||
switch (zmScheme_)
|
for(unsigned int mu = 0; mu < nd; mu++)
|
||||||
{
|
|
||||||
case ZmScheme::qedTL:
|
|
||||||
case ZmScheme::qedL:
|
|
||||||
{
|
|
||||||
for(int mu = 0; mu < nd; mu++)
|
|
||||||
{
|
{
|
||||||
gaussian(rng, r);
|
gaussian(rng, r);
|
||||||
r = weight*r;
|
r = weight*r;
|
||||||
pokeLorentz(aTilde, r, mu);
|
pokeLorentz(aTilde, r, mu);
|
||||||
}
|
}
|
||||||
break;
|
gaugeTransform(aTilde);
|
||||||
}
|
|
||||||
case ZmScheme::qedInf:
|
|
||||||
{
|
|
||||||
Complex shift(1., 1.); // This needs to be a GaugeLink element?
|
|
||||||
for(int mu = 0; mu < nd; mu++)
|
|
||||||
{
|
|
||||||
bernoulli(rng, r);
|
|
||||||
r = weight*(2.*r - shift);
|
|
||||||
pokeLorentz(aTilde, r, mu);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fft.FFT_all_dim(out, aTilde, FFT::backward);
|
fft.FFT_all_dim(out, aTilde, FFT::backward);
|
||||||
|
|
||||||
out = real(out);
|
out = real(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Gimpl>
|
template<class GImpl>
|
||||||
void Photon<Gimpl>::UnitField(GaugeField &out)
|
void Photon<GImpl>::UnitField(GaugeField &out)
|
||||||
{
|
{
|
||||||
auto *grid = dynamic_cast<GridCartesian *>(out._grid);
|
const unsigned int nd = grid_->Nd();
|
||||||
const unsigned int nd = grid->_ndimension;
|
GaugeLinkField r(grid_);
|
||||||
GaugeLinkField r(grid);
|
|
||||||
|
|
||||||
r = Complex(1.0,0.0);
|
r = ScalarComplex(1., 0.);
|
||||||
|
for(unsigned int mu = 0; mu < nd; mu++)
|
||||||
for(int mu = 0; mu < nd; mu++)
|
|
||||||
{
|
{
|
||||||
pokeLorentz(out, r, mu);
|
pokeLorentz(out, r, mu);
|
||||||
}
|
}
|
||||||
|
|
||||||
out = real(out);
|
out = real(out);
|
||||||
}
|
}
|
||||||
// template<class Gimpl>
|
|
||||||
// void Photon<Gimpl>::FeynmanGaugeMomentumSpacePropagator_L(GaugeField &out,
|
|
||||||
// const GaugeField &in)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// FeynmanGaugeMomentumSpacePropagator_TL(out,in);
|
|
||||||
//
|
|
||||||
// GridBase *grid = out._grid;
|
|
||||||
// LatticeInteger coor(grid);
|
|
||||||
// GaugeField zz(grid); zz=zero;
|
|
||||||
//
|
|
||||||
// // xyzt
|
|
||||||
// for(int d = 0; d < grid->_ndimension-1;d++){
|
|
||||||
// LatticeCoordinate(coor,d);
|
|
||||||
// out = where(coor==Integer(0),zz,out);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template<class Gimpl>
|
|
||||||
// void Photon<Gimpl>::FeynmanGaugeMomentumSpacePropagator_TL(GaugeField &out,
|
|
||||||
// const GaugeField &in)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// // what type LatticeComplex
|
|
||||||
// GridBase *grid = out._grid;
|
|
||||||
// int nd = grid->_ndimension;
|
|
||||||
//
|
|
||||||
// typedef typename GaugeField::vector_type vector_type;
|
|
||||||
// typedef typename GaugeField::scalar_type ScalComplex;
|
|
||||||
// typedef Lattice<iSinglet<vector_type> > LatComplex;
|
|
||||||
//
|
|
||||||
// std::vector<int> latt_size = grid->_fdimensions;
|
|
||||||
//
|
|
||||||
// LatComplex denom(grid); denom= zero;
|
|
||||||
// LatComplex one(grid); one = ScalComplex(1.0,0.0);
|
|
||||||
// LatComplex kmu(grid);
|
|
||||||
//
|
|
||||||
// ScalComplex ci(0.0,1.0);
|
|
||||||
// // momphase = n * 2pi / L
|
|
||||||
// for(int mu=0;mu<Nd;mu++) {
|
|
||||||
//
|
|
||||||
// LatticeCoordinate(kmu,mu);
|
|
||||||
//
|
|
||||||
// RealD TwoPiL = M_PI * 2.0/ latt_size[mu];
|
|
||||||
//
|
|
||||||
// kmu = TwoPiL * kmu ;
|
|
||||||
//
|
|
||||||
// denom = denom + 4.0*sin(kmu*0.5)*sin(kmu*0.5); // Wilson term
|
|
||||||
// }
|
|
||||||
// std::vector<int> zero_mode(nd,0);
|
|
||||||
// TComplexD Tone = ComplexD(1.0,0.0);
|
|
||||||
// TComplexD Tzero= ComplexD(0.0,0.0);
|
|
||||||
//
|
|
||||||
// pokeSite(Tone,denom,zero_mode);
|
|
||||||
//
|
|
||||||
// denom= one/denom;
|
|
||||||
//
|
|
||||||
// pokeSite(Tzero,denom,zero_mode);
|
|
||||||
//
|
|
||||||
// out = zero;
|
|
||||||
// out = in*denom;
|
|
||||||
// };
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
#endif
|
#endif
|
||||||
|
@ -173,6 +173,39 @@ void G5R5(Lattice<vobj> &z,const Lattice<vobj> &x)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}}
|
// I explicitly need these outside the QCD namespace
|
||||||
|
template<typename vobj>
|
||||||
|
void G5C(Lattice<vobj> &z, const Lattice<vobj> &x)
|
||||||
|
{
|
||||||
|
GridBase *grid = x._grid;
|
||||||
|
z.checkerboard = x.checkerboard;
|
||||||
|
conformable(x, z);
|
||||||
|
|
||||||
|
QCD::Gamma G5(QCD::Gamma::Algebra::Gamma5);
|
||||||
|
z = G5 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CComplex, int nbasis>
|
||||||
|
void G5C(Lattice<iVector<CComplex, nbasis>> &z, const Lattice<iVector<CComplex, nbasis>> &x)
|
||||||
|
{
|
||||||
|
GridBase *grid = x._grid;
|
||||||
|
z.checkerboard = x.checkerboard;
|
||||||
|
conformable(x, z);
|
||||||
|
|
||||||
|
static_assert(nbasis % 2 == 0, "");
|
||||||
|
int nb = nbasis / 2;
|
||||||
|
|
||||||
|
parallel_for(int ss = 0; ss < grid->oSites(); ss++) {
|
||||||
|
for(int n = 0; n < nb; ++n) {
|
||||||
|
z._odata[ss](n) = x._odata[ss](n);
|
||||||
|
}
|
||||||
|
for(int n = nb; n < nbasis; ++n) {
|
||||||
|
z._odata[ss](n) = -x._odata[ss](n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,6 +10,8 @@ Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk>
|
|||||||
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
Author: neo <cossu@post.kek.jp>
|
Author: neo <cossu@post.kek.jp>
|
||||||
Author: paboyle <paboyle@ph.ed.ac.uk>
|
Author: paboyle <paboyle@ph.ed.ac.uk>
|
||||||
|
Author: James Harrison <J.Harrison@soton.ac.uk>
|
||||||
|
Author: Antonin Portelli <antonin.portelli@me.com>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -645,6 +647,184 @@ static void StapleMult(GaugeMat &staple, const GaugeLorentz &Umu, int mu) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// Wilson loop of size (R1, R2), oriented in mu,nu plane
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static void wilsonLoop(GaugeMat &wl, const std::vector<GaugeMat> &U,
|
||||||
|
const int Rmu, const int Rnu,
|
||||||
|
const int mu, const int nu) {
|
||||||
|
wl = U[nu];
|
||||||
|
|
||||||
|
for(int i = 0; i < Rnu-1; i++){
|
||||||
|
wl = Gimpl::CovShiftForward(U[nu], nu, wl);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < Rmu; i++){
|
||||||
|
wl = Gimpl::CovShiftForward(U[mu], mu, wl);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < Rnu; i++){
|
||||||
|
wl = Gimpl::CovShiftBackward(U[nu], nu, wl);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < Rmu; i++){
|
||||||
|
wl = Gimpl::CovShiftBackward(U[mu], mu, wl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// trace of Wilson Loop oriented in mu,nu plane
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static void traceWilsonLoop(LatticeComplex &wl,
|
||||||
|
const std::vector<GaugeMat> &U,
|
||||||
|
const int Rmu, const int Rnu,
|
||||||
|
const int mu, const int nu) {
|
||||||
|
GaugeMat sp(U[0]._grid);
|
||||||
|
wilsonLoop(sp, U, Rmu, Rnu, mu, nu);
|
||||||
|
wl = trace(sp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// sum over all planes of Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static void siteWilsonLoop(LatticeComplex &Wl,
|
||||||
|
const std::vector<GaugeMat> &U,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
LatticeComplex siteWl(U[0]._grid);
|
||||||
|
Wl = zero;
|
||||||
|
for (int mu = 1; mu < U[0]._grid->_ndimension; mu++) {
|
||||||
|
for (int nu = 0; nu < mu; nu++) {
|
||||||
|
traceWilsonLoop(siteWl, U, R1, R2, mu, nu);
|
||||||
|
Wl = Wl + siteWl;
|
||||||
|
traceWilsonLoop(siteWl, U, R2, R1, mu, nu);
|
||||||
|
Wl = Wl + siteWl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// sum over planes of Wilson loop with length R1
|
||||||
|
// in the time direction
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static void siteTimelikeWilsonLoop(LatticeComplex &Wl,
|
||||||
|
const std::vector<GaugeMat> &U,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
LatticeComplex siteWl(U[0]._grid);
|
||||||
|
|
||||||
|
int ndim = U[0]._grid->_ndimension;
|
||||||
|
|
||||||
|
Wl = zero;
|
||||||
|
for (int nu = 0; nu < ndim - 1; nu++) {
|
||||||
|
traceWilsonLoop(siteWl, U, R1, R2, ndim-1, nu);
|
||||||
|
Wl = Wl + siteWl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// sum Wilson loop over all planes orthogonal to the time direction
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static void siteSpatialWilsonLoop(LatticeComplex &Wl,
|
||||||
|
const std::vector<GaugeMat> &U,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
LatticeComplex siteWl(U[0]._grid);
|
||||||
|
|
||||||
|
Wl = zero;
|
||||||
|
for (int mu = 1; mu < U[0]._grid->_ndimension - 1; mu++) {
|
||||||
|
for (int nu = 0; nu < mu; nu++) {
|
||||||
|
traceWilsonLoop(siteWl, U, R1, R2, mu, nu);
|
||||||
|
Wl = Wl + siteWl;
|
||||||
|
traceWilsonLoop(siteWl, U, R2, R1, mu, nu);
|
||||||
|
Wl = Wl + siteWl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// sum over all x,y,z,t and over all planes of Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static Real sumWilsonLoop(const GaugeLorentz &Umu,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
std::vector<GaugeMat> U(4, Umu._grid);
|
||||||
|
|
||||||
|
for (int mu = 0; mu < Umu._grid->_ndimension; mu++) {
|
||||||
|
U[mu] = PeekIndex<LorentzIndex>(Umu, mu);
|
||||||
|
}
|
||||||
|
|
||||||
|
LatticeComplex Wl(Umu._grid);
|
||||||
|
|
||||||
|
siteWilsonLoop(Wl, U, R1, R2);
|
||||||
|
|
||||||
|
TComplex Tp = sum(Wl);
|
||||||
|
Complex p = TensorRemove(Tp);
|
||||||
|
return p.real();
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// sum over all x,y,z,t and over all planes of timelike Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static Real sumTimelikeWilsonLoop(const GaugeLorentz &Umu,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
std::vector<GaugeMat> U(4, Umu._grid);
|
||||||
|
|
||||||
|
for (int mu = 0; mu < Umu._grid->_ndimension; mu++) {
|
||||||
|
U[mu] = PeekIndex<LorentzIndex>(Umu, mu);
|
||||||
|
}
|
||||||
|
|
||||||
|
LatticeComplex Wl(Umu._grid);
|
||||||
|
|
||||||
|
siteTimelikeWilsonLoop(Wl, U, R1, R2);
|
||||||
|
|
||||||
|
TComplex Tp = sum(Wl);
|
||||||
|
Complex p = TensorRemove(Tp);
|
||||||
|
return p.real();
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// sum over all x,y,z,t and over all planes of spatial Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static Real sumSpatialWilsonLoop(const GaugeLorentz &Umu,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
std::vector<GaugeMat> U(4, Umu._grid);
|
||||||
|
|
||||||
|
for (int mu = 0; mu < Umu._grid->_ndimension; mu++) {
|
||||||
|
U[mu] = PeekIndex<LorentzIndex>(Umu, mu);
|
||||||
|
}
|
||||||
|
|
||||||
|
LatticeComplex Wl(Umu._grid);
|
||||||
|
|
||||||
|
siteSpatialWilsonLoop(Wl, U, R1, R2);
|
||||||
|
|
||||||
|
TComplex Tp = sum(Wl);
|
||||||
|
Complex p = TensorRemove(Tp);
|
||||||
|
return p.real();
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// average over all x,y,z,t and over all planes of Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static Real avgWilsonLoop(const GaugeLorentz &Umu,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
int ndim = Umu._grid->_ndimension;
|
||||||
|
Real sumWl = sumWilsonLoop(Umu, R1, R2);
|
||||||
|
Real vol = Umu._grid->gSites();
|
||||||
|
Real faces = 1.0 * ndim * (ndim - 1);
|
||||||
|
return sumWl / vol / faces / Nc; // Nc dependent... FIXME
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// average over all x,y,z,t and over all planes of timelike Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static Real avgTimelikeWilsonLoop(const GaugeLorentz &Umu,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
int ndim = Umu._grid->_ndimension;
|
||||||
|
Real sumWl = sumTimelikeWilsonLoop(Umu, R1, R2);
|
||||||
|
Real vol = Umu._grid->gSites();
|
||||||
|
Real faces = 1.0 * (ndim - 1);
|
||||||
|
return sumWl / vol / faces / Nc; // Nc dependent... FIXME
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// average over all x,y,z,t and over all planes of spatial Wilson loop
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
static Real avgSpatialWilsonLoop(const GaugeLorentz &Umu,
|
||||||
|
const int R1, const int R2) {
|
||||||
|
int ndim = Umu._grid->_ndimension;
|
||||||
|
Real sumWl = sumSpatialWilsonLoop(Umu, R1, R2);
|
||||||
|
Real vol = Umu._grid->gSites();
|
||||||
|
Real faces = 1.0 * (ndim - 1) * (ndim - 2);
|
||||||
|
return sumWl / vol / faces / Nc; // Nc dependent... FIXME
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef WilsonLoops<PeriodicGimplR> ColourWilsonLoops;
|
typedef WilsonLoops<PeriodicGimplR> ColourWilsonLoops;
|
||||||
|
@ -61,9 +61,9 @@ Group & Hdf5Writer::getGroup(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reader implementation ///////////////////////////////////////////////////////
|
// Reader implementation ///////////////////////////////////////////////////////
|
||||||
Hdf5Reader::Hdf5Reader(const std::string &fileName)
|
Hdf5Reader::Hdf5Reader(const std::string &fileName, const bool readOnly)
|
||||||
: fileName_(fileName)
|
: fileName_(fileName)
|
||||||
, file_(fileName.c_str(), H5F_ACC_RDWR)
|
, file_(fileName.c_str(), readOnly ? H5F_ACC_RDONLY : H5F_ACC_RDWR)
|
||||||
{
|
{
|
||||||
group_ = file_.openGroup("/");
|
group_ = file_.openGroup("/");
|
||||||
readSingleAttribute(dataSetThres_, HDF5_GRID_GUARD "dataset_threshold",
|
readSingleAttribute(dataSetThres_, HDF5_GRID_GUARD "dataset_threshold",
|
||||||
|
@ -54,7 +54,7 @@ namespace Grid
|
|||||||
class Hdf5Reader: public Reader<Hdf5Reader>
|
class Hdf5Reader: public Reader<Hdf5Reader>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Hdf5Reader(const std::string &fileName);
|
Hdf5Reader(const std::string &fileName, const bool readOnly = true);
|
||||||
virtual ~Hdf5Reader(void) = default;
|
virtual ~Hdf5Reader(void) = default;
|
||||||
bool push(const std::string &s);
|
bool push(const std::string &s);
|
||||||
void pop(void);
|
void pop(void);
|
||||||
@ -124,8 +124,11 @@ namespace Grid
|
|||||||
if (flatx.size() > dataSetThres_)
|
if (flatx.size() > dataSetThres_)
|
||||||
{
|
{
|
||||||
H5NS::DataSet dataSet;
|
H5NS::DataSet dataSet;
|
||||||
|
H5NS::DSetCreatPropList plist;
|
||||||
|
|
||||||
dataSet = group_.createDataSet(s, Hdf5Type<Element>::type(), dataSpace);
|
plist.setChunk(dim.size(), dim.data());
|
||||||
|
plist.setFletcher32();
|
||||||
|
dataSet = group_.createDataSet(s, Hdf5Type<Element>::type(), dataSpace, plist);
|
||||||
dataSet.write(flatx.data(), Hdf5Type<Element>::type());
|
dataSet.write(flatx.data(), Hdf5Type<Element>::type());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -47,6 +47,7 @@ Author: paboyle <paboyle@ph.ed.ac.uk>
|
|||||||
#else
|
#else
|
||||||
#define PARALLEL_FOR_LOOP
|
#define PARALLEL_FOR_LOOP
|
||||||
#define PARALLEL_FOR_LOOP_INTERN
|
#define PARALLEL_FOR_LOOP_INTERN
|
||||||
|
#define PARALLEL_FOR_LOOP_REDUCE(op, var)
|
||||||
#define PARALLEL_NESTED_LOOP2
|
#define PARALLEL_NESTED_LOOP2
|
||||||
#define PARALLEL_NESTED_LOOP5
|
#define PARALLEL_NESTED_LOOP5
|
||||||
#define PARALLEL_REGION
|
#define PARALLEL_REGION
|
||||||
@ -58,6 +59,7 @@ Author: paboyle <paboyle@ph.ed.ac.uk>
|
|||||||
#define parallel_for_internal PARALLEL_FOR_LOOP_INTERN for
|
#define parallel_for_internal PARALLEL_FOR_LOOP_INTERN for
|
||||||
#define parallel_for_nest2 PARALLEL_NESTED_LOOP2 for
|
#define parallel_for_nest2 PARALLEL_NESTED_LOOP2 for
|
||||||
#define parallel_for_nest5 PARALLEL_NESTED_LOOP5 for
|
#define parallel_for_nest5 PARALLEL_NESTED_LOOP5 for
|
||||||
|
#define parallel_critical PARALLEL_CRITICAL
|
||||||
|
|
||||||
namespace Grid {
|
namespace Grid {
|
||||||
|
|
||||||
|
@ -28,16 +28,31 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
}
|
}
|
||||||
|
#ifdef USE_IPP
|
||||||
|
#include "ipp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class GridChecksum
|
class GridChecksum
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static inline uint32_t crc32(void *data,size_t bytes)
|
static inline uint32_t crc32(const void *data, size_t bytes)
|
||||||
{
|
{
|
||||||
return ::crc32(0L,(unsigned char *)data,bytes);
|
return ::crc32(0L,(unsigned char *)data,bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_IPP
|
||||||
|
static inline uint32_t crc32c(const void* data, size_t bytes)
|
||||||
|
{
|
||||||
|
uint32_t crc32c = ~(uint32_t)0;
|
||||||
|
ippsCRC32C_8u(reinterpret_cast<const unsigned char *>(data), bytes, &crc32c);
|
||||||
|
ippsSwapBytes_32u_I(&crc32c, 1);
|
||||||
|
|
||||||
|
return ~crc32c;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline std::string sha256_string(const std::vector<T> &hash)
|
static inline std::string sha256_string(const std::vector<T> &hash)
|
||||||
{
|
{
|
||||||
|
@ -32,11 +32,19 @@ See the full license in the file "LICENSE" in the top level distribution directo
|
|||||||
#include <Hadrons/Global.hpp>
|
#include <Hadrons/Global.hpp>
|
||||||
#include <Hadrons/TimerArray.hpp>
|
#include <Hadrons/TimerArray.hpp>
|
||||||
#include <Grid/Eigen/unsupported/CXX11/Tensor>
|
#include <Grid/Eigen/unsupported/CXX11/Tensor>
|
||||||
|
#ifdef USE_MKL
|
||||||
|
#include "mkl.h"
|
||||||
|
#include "mkl_cblas.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HADRONS_A2AM_NAME
|
#ifndef HADRONS_A2AM_NAME
|
||||||
#define HADRONS_A2AM_NAME "a2aMatrix"
|
#define HADRONS_A2AM_NAME "a2aMatrix"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef HADRONS_A2AM_IO_TYPE
|
||||||
|
#define HADRONS_A2AM_IO_TYPE ComplexF
|
||||||
|
#endif
|
||||||
|
|
||||||
#define HADRONS_A2AM_PARALLEL_IO
|
#define HADRONS_A2AM_PARALLEL_IO
|
||||||
|
|
||||||
BEGIN_HADRONS_NAMESPACE
|
BEGIN_HADRONS_NAMESPACE
|
||||||
@ -51,6 +59,15 @@ BEGIN_HADRONS_NAMESPACE
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using A2AMatrixSet = Eigen::TensorMap<Eigen::Tensor<T, 5, Eigen::RowMajor>>;
|
using A2AMatrixSet = Eigen::TensorMap<Eigen::Tensor<T, 5, Eigen::RowMajor>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using A2AMatrix = Eigen::Matrix<T, -1, -1, Eigen::RowMajor>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using A2AMatrixMap = Eigen::Map<A2AMatrix<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using A2AMatrixTr = Eigen::Matrix<T, -1, -1, Eigen::ColMajor>;
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Abstract class for A2A kernels *
|
* Abstract class for A2A kernels *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@ -76,10 +93,15 @@ public:
|
|||||||
// constructors
|
// constructors
|
||||||
A2AMatrixIo(void) = default;
|
A2AMatrixIo(void) = default;
|
||||||
A2AMatrixIo(std::string filename, std::string dataname,
|
A2AMatrixIo(std::string filename, std::string dataname,
|
||||||
const unsigned int nt, const unsigned int ni,
|
const unsigned int nt, const unsigned int ni = 0,
|
||||||
const unsigned int nj);
|
const unsigned int nj = 0);
|
||||||
// destructor
|
// destructor
|
||||||
~A2AMatrixIo(void) = default;
|
~A2AMatrixIo(void) = default;
|
||||||
|
// access
|
||||||
|
unsigned int getNi(void) const;
|
||||||
|
unsigned int getNj(void) const;
|
||||||
|
unsigned int getNt(void) const;
|
||||||
|
size_t getSize(void) const;
|
||||||
// file allocation
|
// file allocation
|
||||||
template <typename MetadataType>
|
template <typename MetadataType>
|
||||||
void initFile(const MetadataType &d, const unsigned int chunkSize);
|
void initFile(const MetadataType &d, const unsigned int chunkSize);
|
||||||
@ -88,9 +110,11 @@ public:
|
|||||||
const unsigned int blockSizei, const unsigned int blockSizej);
|
const unsigned int blockSizei, const unsigned int blockSizej);
|
||||||
void saveBlock(const A2AMatrixSet<T> &m, const unsigned int ext, const unsigned int str,
|
void saveBlock(const A2AMatrixSet<T> &m, const unsigned int ext, const unsigned int str,
|
||||||
const unsigned int i, const unsigned int j);
|
const unsigned int i, const unsigned int j);
|
||||||
|
template <template <class> class Vec, typename VecT>
|
||||||
|
void load(Vec<VecT> &v, double *tRead = nullptr, const bool useCache = true);
|
||||||
private:
|
private:
|
||||||
std::string filename_, dataname_;
|
std::string filename_{""}, dataname_{""};
|
||||||
unsigned int nt_, ni_, nj_;
|
unsigned int nt_{0}, ni_{0}, nj_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@ -136,6 +160,226 @@ private:
|
|||||||
std::vector<IoHelper> nodeIo_;
|
std::vector<IoHelper> nodeIo_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* A2A matrix contraction kernels *
|
||||||
|
******************************************************************************/
|
||||||
|
class A2AContraction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// accTrMul(acc, a, b): acc += tr(a*b)
|
||||||
|
template <typename C, typename MatLeft, typename MatRight>
|
||||||
|
static inline void accTrMul(C &acc, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
if ((MatLeft::Options == Eigen::RowMajor) and
|
||||||
|
(MatRight::Options == Eigen::ColMajor))
|
||||||
|
{
|
||||||
|
parallel_for (unsigned int r = 0; r < a.rows(); ++r)
|
||||||
|
{
|
||||||
|
C tmp;
|
||||||
|
#ifdef USE_MKL
|
||||||
|
dotuRow(tmp, r, a, b);
|
||||||
|
#else
|
||||||
|
tmp = a.row(r).conjugate().dot(b.col(r));
|
||||||
|
#endif
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
acc += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parallel_for (unsigned int c = 0; c < a.cols(); ++c)
|
||||||
|
{
|
||||||
|
C tmp;
|
||||||
|
#ifdef USE_MKL
|
||||||
|
dotuCol(tmp, c, a, b);
|
||||||
|
#else
|
||||||
|
tmp = a.col(c).conjugate().dot(b.row(c));
|
||||||
|
#endif
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
acc += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline double accTrMulFlops(const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
double n = a.rows()*a.cols();
|
||||||
|
|
||||||
|
return 8.*n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mul(res, a, b): res = a*b
|
||||||
|
#ifdef USE_MKL
|
||||||
|
template <template <class, int...> class Mat, int... Opts>
|
||||||
|
static inline void mul(Mat<ComplexD, Opts...> &res,
|
||||||
|
const Mat<ComplexD, Opts...> &a,
|
||||||
|
const Mat<ComplexD, Opts...> &b)
|
||||||
|
{
|
||||||
|
static const ComplexD one(1., 0.), zero(0., 0.);
|
||||||
|
|
||||||
|
if ((res.rows() != a.rows()) or (res.cols() != b.cols()))
|
||||||
|
{
|
||||||
|
res.resize(a.rows(), b.cols());
|
||||||
|
}
|
||||||
|
if (Mat<ComplexD, Opts...>::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, a.rows(), b.cols(),
|
||||||
|
a.cols(), &one, a.data(), a.cols(), b.data(), b.cols(), &zero,
|
||||||
|
res.data(), res.cols());
|
||||||
|
}
|
||||||
|
else if (Mat<ComplexD, Opts...>::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, a.rows(), b.cols(),
|
||||||
|
a.cols(), &one, a.data(), a.rows(), b.data(), b.rows(), &zero,
|
||||||
|
res.data(), res.rows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <class, int...> class Mat, int... Opts>
|
||||||
|
static inline void mul(Mat<ComplexF, Opts...> &res,
|
||||||
|
const Mat<ComplexF, Opts...> &a,
|
||||||
|
const Mat<ComplexF, Opts...> &b)
|
||||||
|
{
|
||||||
|
static const ComplexF one(1., 0.), zero(0., 0.);
|
||||||
|
|
||||||
|
if ((res.rows() != a.rows()) or (res.cols() != b.cols()))
|
||||||
|
{
|
||||||
|
res.resize(a.rows(), b.cols());
|
||||||
|
}
|
||||||
|
if (Mat<ComplexF, Opts...>::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, a.rows(), b.cols(),
|
||||||
|
a.cols(), &one, a.data(), a.cols(), b.data(), b.cols(), &zero,
|
||||||
|
res.data(), res.cols());
|
||||||
|
}
|
||||||
|
else if (Mat<ComplexF, Opts...>::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
cblas_cgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, a.rows(), b.cols(),
|
||||||
|
a.cols(), &one, a.data(), a.rows(), b.data(), b.rows(), &zero,
|
||||||
|
res.data(), res.rows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename Mat>
|
||||||
|
static inline void mul(Mat &res, const Mat &a, const Mat &b)
|
||||||
|
{
|
||||||
|
res = a*b;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
template <typename Mat>
|
||||||
|
static inline double mulFlops(const Mat &a, const Mat &b)
|
||||||
|
{
|
||||||
|
double nr = a.rows(), nc = a.cols();
|
||||||
|
|
||||||
|
return nr*nr*(6.*nc + 2.*(nc - 1.));
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
template <typename C, typename MatLeft, typename MatRight>
|
||||||
|
static inline void makeDotRowPt(C * &aPt, unsigned int &aInc, C * &bPt,
|
||||||
|
unsigned int &bInc, const unsigned int aRow,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
if (MatLeft::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aRow*a.cols();
|
||||||
|
aInc = 1;
|
||||||
|
}
|
||||||
|
else if (MatLeft::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aRow;
|
||||||
|
aInc = a.rows();
|
||||||
|
}
|
||||||
|
if (MatRight::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aRow;
|
||||||
|
bInc = b.cols();
|
||||||
|
}
|
||||||
|
else if (MatRight::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aRow*b.rows();
|
||||||
|
bInc = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MKL
|
||||||
|
template <typename C, typename MatLeft, typename MatRight>
|
||||||
|
static inline void makeDotColPt(C * &aPt, unsigned int &aInc, C * &bPt,
|
||||||
|
unsigned int &bInc, const unsigned int aCol,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
if (MatLeft::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aCol;
|
||||||
|
aInc = a.cols();
|
||||||
|
}
|
||||||
|
else if (MatLeft::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aCol*a.rows();
|
||||||
|
aInc = 1;
|
||||||
|
}
|
||||||
|
if (MatRight::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aCol*b.cols();
|
||||||
|
bInc = 1;
|
||||||
|
}
|
||||||
|
else if (MatRight::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aCol;
|
||||||
|
bInc = b.rows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline void dotuRow(ComplexF &res, const unsigned int aRow,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
const ComplexF *aPt, *bPt;
|
||||||
|
unsigned int aInc, bInc;
|
||||||
|
|
||||||
|
makeDotRowPt(aPt, aInc, bPt, bInc, aRow, a, b);
|
||||||
|
cblas_cdotu_sub(a.cols(), aPt, aInc, bPt, bInc, &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline void dotuCol(ComplexF &res, const unsigned int aCol,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
const ComplexF *aPt, *bPt;
|
||||||
|
unsigned int aInc, bInc;
|
||||||
|
|
||||||
|
makeDotColPt(aPt, aInc, bPt, bInc, aCol, a, b);
|
||||||
|
cblas_cdotu_sub(a.rows(), aPt, aInc, bPt, bInc, &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline void dotuRow(ComplexD &res, const unsigned int aRow,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
const ComplexD *aPt, *bPt;
|
||||||
|
unsigned int aInc, bInc;
|
||||||
|
|
||||||
|
makeDotRowPt(aPt, aInc, bPt, bInc, aRow, a, b);
|
||||||
|
cblas_zdotu_sub(a.cols(), aPt, aInc, bPt, bInc, &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline void dotuCol(ComplexD &res, const unsigned int aCol,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
const ComplexD *aPt, *bPt;
|
||||||
|
unsigned int aInc, bInc;
|
||||||
|
|
||||||
|
makeDotColPt(aPt, aInc, bPt, bInc, aCol, a, b);
|
||||||
|
cblas_zdotu_sub(a.rows(), aPt, aInc, bPt, bInc, &res);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* A2AMatrixIo template implementation *
|
* A2AMatrixIo template implementation *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@ -148,6 +392,31 @@ A2AMatrixIo<T>::A2AMatrixIo(std::string filename, std::string dataname,
|
|||||||
, nt_(nt), ni_(ni), nj_(nj)
|
, nt_(nt), ni_(ni), nj_(nj)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// access //////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
unsigned int A2AMatrixIo<T>::getNt(void) const
|
||||||
|
{
|
||||||
|
return nt_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
unsigned int A2AMatrixIo<T>::getNi(void) const
|
||||||
|
{
|
||||||
|
return ni_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
unsigned int A2AMatrixIo<T>::getNj(void) const
|
||||||
|
{
|
||||||
|
return nj_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
size_t A2AMatrixIo<T>::getSize(void) const
|
||||||
|
{
|
||||||
|
return nt_*ni_*nj_*sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
// file allocation /////////////////////////////////////////////////////////////
|
// file allocation /////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
template <typename MetadataType>
|
template <typename MetadataType>
|
||||||
@ -171,11 +440,12 @@ void A2AMatrixIo<T>::initFile(const MetadataType &d, const unsigned int chunkSiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the dataset
|
// create the dataset
|
||||||
Hdf5Reader reader(filename_);
|
Hdf5Reader reader(filename_, false);
|
||||||
|
|
||||||
push(reader, dataname_);
|
push(reader, dataname_);
|
||||||
auto &group = reader.getGroup();
|
auto &group = reader.getGroup();
|
||||||
plist.setChunk(chunk.size(), chunk.data());
|
plist.setChunk(chunk.size(), chunk.data());
|
||||||
|
plist.setFletcher32();
|
||||||
dataset = group.createDataSet(HADRONS_A2AM_NAME, Hdf5Type<T>::type(), dataspace, plist);
|
dataset = group.createDataSet(HADRONS_A2AM_NAME, Hdf5Type<T>::type(), dataspace, plist);
|
||||||
#else
|
#else
|
||||||
HADRONS_ERROR(Implementation, "all-to-all matrix I/O needs HDF5 library");
|
HADRONS_ERROR(Implementation, "all-to-all matrix I/O needs HDF5 library");
|
||||||
@ -191,7 +461,7 @@ void A2AMatrixIo<T>::saveBlock(const T *data,
|
|||||||
const unsigned int blockSizej)
|
const unsigned int blockSizej)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_HDF5
|
#ifdef HAVE_HDF5
|
||||||
Hdf5Reader reader(filename_);
|
Hdf5Reader reader(filename_, false);
|
||||||
std::vector<hsize_t> count = {nt_, blockSizei, blockSizej},
|
std::vector<hsize_t> count = {nt_, blockSizei, blockSizej},
|
||||||
offset = {0, static_cast<hsize_t>(i),
|
offset = {0, static_cast<hsize_t>(i),
|
||||||
static_cast<hsize_t>(j)},
|
static_cast<hsize_t>(j)},
|
||||||
@ -226,6 +496,99 @@ void A2AMatrixIo<T>::saveBlock(const A2AMatrixSet<T> &m,
|
|||||||
saveBlock(m.data() + offset, i, j, blockSizei, blockSizej);
|
saveBlock(m.data() + offset, i, j, blockSizei, blockSizej);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <template <class> class Vec, typename VecT>
|
||||||
|
void A2AMatrixIo<T>::load(Vec<VecT> &v, double *tRead, const bool useCache)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_HDF5
|
||||||
|
Hdf5Reader reader(filename_);
|
||||||
|
std::vector<hsize_t> hdim;
|
||||||
|
H5NS::DataSet dataset;
|
||||||
|
H5NS::DataSpace dataspace;
|
||||||
|
H5NS::CompType datatype;
|
||||||
|
|
||||||
|
push(reader, dataname_);
|
||||||
|
auto &group = reader.getGroup();
|
||||||
|
dataset = group.openDataSet(HADRONS_A2AM_NAME);
|
||||||
|
datatype = dataset.getCompType();
|
||||||
|
dataspace = dataset.getSpace();
|
||||||
|
hdim.resize(dataspace.getSimpleExtentNdims());
|
||||||
|
dataspace.getSimpleExtentDims(hdim.data());
|
||||||
|
if ((nt_*ni_*nj_ != 0) and
|
||||||
|
((hdim[0] != nt_) or (hdim[1] != ni_) or (hdim[2] != nj_)))
|
||||||
|
{
|
||||||
|
HADRONS_ERROR(Size, "all-to-all matrix size mismatch (got "
|
||||||
|
+ std::to_string(hdim[0]) + "x" + std::to_string(hdim[1]) + "x"
|
||||||
|
+ std::to_string(hdim[2]) + ", expected "
|
||||||
|
+ std::to_string(nt_) + "x" + std::to_string(ni_) + "x"
|
||||||
|
+ std::to_string(nj_));
|
||||||
|
}
|
||||||
|
else if (ni_*nj_ == 0)
|
||||||
|
{
|
||||||
|
if (hdim[0] != nt_)
|
||||||
|
{
|
||||||
|
HADRONS_ERROR(Size, "all-to-all time size mismatch (got "
|
||||||
|
+ std::to_string(hdim[0]) + ", expected "
|
||||||
|
+ std::to_string(nt_) + ")");
|
||||||
|
}
|
||||||
|
ni_ = hdim[1];
|
||||||
|
nj_ = hdim[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useCache)
|
||||||
|
{
|
||||||
|
std::vector<T> buf(nt_*ni_*nj_);
|
||||||
|
T *pt;
|
||||||
|
|
||||||
|
dataset.read(buf.data(), datatype);
|
||||||
|
pt = buf.data();
|
||||||
|
for (unsigned int t = 0; t < nt_; ++t)
|
||||||
|
{
|
||||||
|
A2AMatrixMap<T> bufMap(pt, ni_, nj_);
|
||||||
|
|
||||||
|
v[t] = bufMap.template cast<VecT>();
|
||||||
|
pt += ni_*nj_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if useCache = false, do I/O timeslice per timeslice (much slower)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
A2AMatrix<T> buf(ni_, nj_);
|
||||||
|
std::vector<hsize_t> count = {1, static_cast<hsize_t>(ni_),
|
||||||
|
static_cast<hsize_t>(nj_)},
|
||||||
|
stride = {1, 1, 1},
|
||||||
|
block = {1, 1, 1},
|
||||||
|
memCount = {static_cast<hsize_t>(ni_),
|
||||||
|
static_cast<hsize_t>(nj_)};
|
||||||
|
H5NS::DataSpace memspace(memCount.size(), memCount.data());
|
||||||
|
|
||||||
|
std::cout << "Loading timeslice";
|
||||||
|
std::cout.flush();
|
||||||
|
*tRead = 0.;
|
||||||
|
for (unsigned int tp1 = nt_; tp1 > 0; --tp1)
|
||||||
|
{
|
||||||
|
unsigned int t = tp1 - 1;
|
||||||
|
std::vector<hsize_t> offset = {static_cast<hsize_t>(t), 0, 0};
|
||||||
|
|
||||||
|
if (t % 10 == 0)
|
||||||
|
{
|
||||||
|
std::cout << " " << t;
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
||||||
|
dataspace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data(),
|
||||||
|
stride.data(), block.data());
|
||||||
|
if (tRead) *tRead -= usecond();
|
||||||
|
dataset.read(buf.data(), datatype, memspace, dataspace);
|
||||||
|
if (tRead) *tRead += usecond();
|
||||||
|
v[t] = buf.template cast<VecT>();
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
HADRONS_ERROR(Implementation, "all-to-all matrix I/O needs HDF5 library");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* A2AMatrixBlockComputation template implementation *
|
* A2AMatrixBlockComputation template implementation *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -108,6 +108,9 @@ void Application::run(void)
|
|||||||
HADRONS_ERROR(Definition, "run id is empty");
|
HADRONS_ERROR(Definition, "run id is empty");
|
||||||
}
|
}
|
||||||
LOG(Message) << "RUN ID '" << getPar().runId << "'" << std::endl;
|
LOG(Message) << "RUN ID '" << getPar().runId << "'" << std::endl;
|
||||||
|
BinaryIO::latticeWriteMaxRetry = getPar().parallelWriteMaxRetry;
|
||||||
|
LOG(Message) << "Attempt(s) for resilient parallel I/O: "
|
||||||
|
<< BinaryIO::latticeWriteMaxRetry << std::endl;
|
||||||
vm().setRunId(getPar().runId);
|
vm().setRunId(getPar().runId);
|
||||||
vm().printContent();
|
vm().printContent();
|
||||||
env().printContent();
|
env().printContent();
|
||||||
|
@ -41,14 +41,6 @@ BEGIN_HADRONS_NAMESPACE
|
|||||||
class Application
|
class Application
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class TrajRange: Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GRID_SERIALIZABLE_CLASS_MEMBERS(TrajRange,
|
|
||||||
unsigned int, start,
|
|
||||||
unsigned int, end,
|
|
||||||
unsigned int, step);
|
|
||||||
};
|
|
||||||
class GlobalPar: Serializable
|
class GlobalPar: Serializable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -56,7 +48,9 @@ public:
|
|||||||
TrajRange, trajCounter,
|
TrajRange, trajCounter,
|
||||||
VirtualMachine::GeneticPar, genetic,
|
VirtualMachine::GeneticPar, genetic,
|
||||||
std::string, runId,
|
std::string, runId,
|
||||||
std::string, graphFile);
|
std::string, graphFile,
|
||||||
|
int, parallelWriteMaxRetry);
|
||||||
|
GlobalPar(void): parallelWriteMaxRetry{-1} {}
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
// constructors
|
// constructors
|
||||||
|
@ -29,6 +29,7 @@ See the full license in the file "LICENSE" in the top level distribution directo
|
|||||||
#define Hadrons_DiskVector_hpp_
|
#define Hadrons_DiskVector_hpp_
|
||||||
|
|
||||||
#include <Hadrons/Global.hpp>
|
#include <Hadrons/Global.hpp>
|
||||||
|
#include <Hadrons/A2AMatrix.hpp>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
@ -59,14 +60,18 @@ public:
|
|||||||
: master_(master), cmaster_(master), i_(i) {}
|
: master_(master), cmaster_(master), i_(i) {}
|
||||||
|
|
||||||
// operator=: somebody is trying to store a vector element
|
// operator=: somebody is trying to store a vector element
|
||||||
// write to disk and cache
|
// write to cache and tag as modified
|
||||||
T &operator=(const T &obj) const
|
T &operator=(const T &obj) const
|
||||||
{
|
{
|
||||||
|
auto &cache = *master_.cachePtr_;
|
||||||
|
auto &modified = *master_.modifiedPtr_;
|
||||||
|
auto &index = *master_.indexPtr_;
|
||||||
|
|
||||||
DV_DEBUG_MSG(&master_, "writing to " << i_);
|
DV_DEBUG_MSG(&master_, "writing to " << i_);
|
||||||
master_.cacheInsert(i_, obj);
|
master_.cacheInsert(i_, obj);
|
||||||
master_.save(master_.filename(i_), obj);
|
modified[index.at(i_)] = true;
|
||||||
|
|
||||||
return master_.cachePtr_->at(i_);
|
return cache[index.at(i_)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// implicit cast to const object reference and redirection
|
// implicit cast to const object reference and redirection
|
||||||
@ -83,6 +88,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
DiskVectorBase(const std::string dirname, const unsigned int size = 0,
|
DiskVectorBase(const std::string dirname, const unsigned int size = 0,
|
||||||
const unsigned int cacheSize = 1, const bool clean = true);
|
const unsigned int cacheSize = 1, const bool clean = true);
|
||||||
|
DiskVectorBase(DiskVectorBase<T> &&v) = default;
|
||||||
virtual ~DiskVectorBase(void);
|
virtual ~DiskVectorBase(void);
|
||||||
const T & operator[](const unsigned int i) const;
|
const T & operator[](const unsigned int i) const;
|
||||||
RwAccessHelper operator[](const unsigned int i);
|
RwAccessHelper operator[](const unsigned int i);
|
||||||
@ -103,7 +109,10 @@ private:
|
|||||||
bool clean_;
|
bool clean_;
|
||||||
// using pointers to allow modifications when class is const
|
// using pointers to allow modifications when class is const
|
||||||
// semantic: const means data unmodified, but cache modification allowed
|
// semantic: const means data unmodified, but cache modification allowed
|
||||||
std::unique_ptr<std::map<unsigned int, T>> cachePtr_;
|
std::unique_ptr<std::vector<T>> cachePtr_;
|
||||||
|
std::unique_ptr<std::vector<bool>> modifiedPtr_;
|
||||||
|
std::unique_ptr<std::map<unsigned int, unsigned int>> indexPtr_;
|
||||||
|
std::unique_ptr<std::stack<unsigned int>> freePtr_;
|
||||||
std::unique_ptr<std::deque<unsigned int>> loadsPtr_;
|
std::unique_ptr<std::deque<unsigned int>> loadsPtr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,7 +144,7 @@ private:
|
|||||||
* Specialisation for Eigen matrices *
|
* Specialisation for Eigen matrices *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using EigenDiskVectorMat = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
|
using EigenDiskVectorMat = A2AMatrix<T>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class EigenDiskVector: public DiskVectorBase<EigenDiskVectorMat<T>>
|
class EigenDiskVector: public DiskVectorBase<EigenDiskVectorMat<T>>
|
||||||
@ -153,23 +162,30 @@ private:
|
|||||||
virtual void load(EigenDiskVectorMat<T> &obj, const std::string filename) const
|
virtual void load(EigenDiskVectorMat<T> &obj, const std::string filename) const
|
||||||
{
|
{
|
||||||
std::ifstream f(filename, std::ios::binary);
|
std::ifstream f(filename, std::ios::binary);
|
||||||
std::vector<unsigned char> hash(SHA256_DIGEST_LENGTH);
|
uint32_t crc, check;
|
||||||
Eigen::Index nRow, nCol;
|
Eigen::Index nRow, nCol;
|
||||||
size_t matSize;
|
size_t matSize;
|
||||||
double t;
|
double tRead, tHash;
|
||||||
|
|
||||||
f.read(reinterpret_cast<char *>(hash.data()), hash.size()*sizeof(unsigned char));
|
f.read(reinterpret_cast<char *>(&crc), sizeof(crc));
|
||||||
f.read(reinterpret_cast<char *>(&nRow), sizeof(Eigen::Index));
|
f.read(reinterpret_cast<char *>(&nRow), sizeof(nRow));
|
||||||
f.read(reinterpret_cast<char *>(&nCol), sizeof(Eigen::Index));
|
f.read(reinterpret_cast<char *>(&nCol), sizeof(nCol));
|
||||||
obj.resize(nRow, nCol);
|
obj.resize(nRow, nCol);
|
||||||
matSize = nRow*nCol*sizeof(T);
|
matSize = nRow*nCol*sizeof(T);
|
||||||
t = -usecond();
|
tRead = -usecond();
|
||||||
f.read(reinterpret_cast<char *>(obj.data()), matSize);
|
f.read(reinterpret_cast<char *>(obj.data()), matSize);
|
||||||
t += usecond();
|
tRead += usecond();
|
||||||
DV_DEBUG_MSG(this, "Eigen read " << matSize/t*1.0e6/1024/1024 << " MB/s");
|
tHash = -usecond();
|
||||||
auto check = GridChecksum::sha256(obj.data(), matSize);
|
#ifdef USE_IPP
|
||||||
DV_DEBUG_MSG(this, "Eigen sha256 " << GridChecksum::sha256_string(check));
|
check = GridChecksum::crc32c(obj.data(), matSize);
|
||||||
if (hash != check)
|
#else
|
||||||
|
check = GridChecksum::crc32(obj.data(), matSize);
|
||||||
|
#endif
|
||||||
|
tHash += usecond();
|
||||||
|
DV_DEBUG_MSG(this, "Eigen read " << tRead/1.0e6 << " sec " << matSize/tRead*1.0e6/1024/1024 << " MB/s");
|
||||||
|
DV_DEBUG_MSG(this, "Eigen crc32 " << std::hex << check << std::dec
|
||||||
|
<< " " << tHash/1.0e6 << " sec " << matSize/tHash*1.0e6/1024/1024 << " MB/s");
|
||||||
|
if (crc != check)
|
||||||
{
|
{
|
||||||
HADRONS_ERROR(Io, "checksum failed")
|
HADRONS_ERROR(Io, "checksum failed")
|
||||||
}
|
}
|
||||||
@ -178,23 +194,30 @@ private:
|
|||||||
virtual void save(const std::string filename, const EigenDiskVectorMat<T> &obj) const
|
virtual void save(const std::string filename, const EigenDiskVectorMat<T> &obj) const
|
||||||
{
|
{
|
||||||
std::ofstream f(filename, std::ios::binary);
|
std::ofstream f(filename, std::ios::binary);
|
||||||
std::vector<unsigned char> hash(SHA256_DIGEST_LENGTH);
|
uint32_t crc;
|
||||||
Eigen::Index nRow, nCol;
|
Eigen::Index nRow, nCol;
|
||||||
size_t matSize;
|
size_t matSize;
|
||||||
double t;
|
double tWrite, tHash;
|
||||||
|
|
||||||
nRow = obj.rows();
|
nRow = obj.rows();
|
||||||
nCol = obj.cols();
|
nCol = obj.cols();
|
||||||
matSize = nRow*nCol*sizeof(T);
|
matSize = nRow*nCol*sizeof(T);
|
||||||
hash = GridChecksum::sha256(obj.data(), matSize);
|
tHash = -usecond();
|
||||||
DV_DEBUG_MSG(this, "Eigen sha256 " << GridChecksum::sha256_string(hash));
|
#ifdef USE_IPP
|
||||||
f.write(reinterpret_cast<char *>(hash.data()), hash.size()*sizeof(unsigned char));
|
crc = GridChecksum::crc32c(obj.data(), matSize);
|
||||||
f.write(reinterpret_cast<char *>(&nRow), sizeof(Eigen::Index));
|
#else
|
||||||
f.write(reinterpret_cast<char *>(&nCol), sizeof(Eigen::Index));
|
crc = GridChecksum::crc32(obj.data(), matSize);
|
||||||
t = -usecond();
|
#endif
|
||||||
|
tHash += usecond();
|
||||||
|
f.write(reinterpret_cast<char *>(&crc), sizeof(crc));
|
||||||
|
f.write(reinterpret_cast<char *>(&nRow), sizeof(nRow));
|
||||||
|
f.write(reinterpret_cast<char *>(&nCol), sizeof(nCol));
|
||||||
|
tWrite = -usecond();
|
||||||
f.write(reinterpret_cast<const char *>(obj.data()), matSize);
|
f.write(reinterpret_cast<const char *>(obj.data()), matSize);
|
||||||
t += usecond();
|
tWrite += usecond();
|
||||||
DV_DEBUG_MSG(this, "Eigen write " << matSize/t*1.0e6/1024/1024 << " MB/s");
|
DV_DEBUG_MSG(this, "Eigen write " << tWrite/1.0e6 << " sec " << matSize/tWrite*1.0e6/1024/1024 << " MB/s");
|
||||||
|
DV_DEBUG_MSG(this, "Eigen crc32 " << std::hex << crc << std::dec
|
||||||
|
<< " " << tHash/1.0e6 << " sec " << matSize/tHash*1.0e6/1024/1024 << " MB/s");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -207,7 +230,10 @@ DiskVectorBase<T>::DiskVectorBase(const std::string dirname,
|
|||||||
const unsigned int cacheSize,
|
const unsigned int cacheSize,
|
||||||
const bool clean)
|
const bool clean)
|
||||||
: dirname_(dirname), size_(size), cacheSize_(cacheSize), clean_(clean)
|
: dirname_(dirname), size_(size), cacheSize_(cacheSize), clean_(clean)
|
||||||
, cachePtr_(new std::map<unsigned int, T>())
|
, cachePtr_(new std::vector<T>(size))
|
||||||
|
, modifiedPtr_(new std::vector<bool>(size, false))
|
||||||
|
, indexPtr_(new std::map<unsigned int, unsigned int>())
|
||||||
|
, freePtr_(new std::stack<unsigned int>)
|
||||||
, loadsPtr_(new std::deque<unsigned int>())
|
, loadsPtr_(new std::deque<unsigned int>())
|
||||||
{
|
{
|
||||||
struct stat s;
|
struct stat s;
|
||||||
@ -217,6 +243,10 @@ DiskVectorBase<T>::DiskVectorBase(const std::string dirname,
|
|||||||
HADRONS_ERROR(Io, "directory '" + dirname + "' already exists")
|
HADRONS_ERROR(Io, "directory '" + dirname + "' already exists")
|
||||||
}
|
}
|
||||||
mkdir(dirname);
|
mkdir(dirname);
|
||||||
|
for (unsigned int i = 0; i < cacheSize_; ++i)
|
||||||
|
{
|
||||||
|
freePtr_->push(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -232,6 +262,8 @@ template <typename T>
|
|||||||
const T & DiskVectorBase<T>::operator[](const unsigned int i) const
|
const T & DiskVectorBase<T>::operator[](const unsigned int i) const
|
||||||
{
|
{
|
||||||
auto &cache = *cachePtr_;
|
auto &cache = *cachePtr_;
|
||||||
|
auto &index = *indexPtr_;
|
||||||
|
auto &freeInd = *freePtr_;
|
||||||
auto &loads = *loadsPtr_;
|
auto &loads = *loadsPtr_;
|
||||||
|
|
||||||
DV_DEBUG_MSG(this, "accessing " << i << " (RO)");
|
DV_DEBUG_MSG(this, "accessing " << i << " (RO)");
|
||||||
@ -241,7 +273,7 @@ const T & DiskVectorBase<T>::operator[](const unsigned int i) const
|
|||||||
HADRONS_ERROR(Size, "index out of range");
|
HADRONS_ERROR(Size, "index out of range");
|
||||||
}
|
}
|
||||||
const_cast<double &>(access_)++;
|
const_cast<double &>(access_)++;
|
||||||
if (cache.find(i) == cache.end())
|
if (index.find(i) == index.end())
|
||||||
{
|
{
|
||||||
// cache miss
|
// cache miss
|
||||||
DV_DEBUG_MSG(this, "cache miss");
|
DV_DEBUG_MSG(this, "cache miss");
|
||||||
@ -268,7 +300,7 @@ const T & DiskVectorBase<T>::operator[](const unsigned int i) const
|
|||||||
DV_DEBUG_MSG(this, "in cache: " << msg);
|
DV_DEBUG_MSG(this, "in cache: " << msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return cache.at(i);
|
return cache[index.at(i)];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -307,12 +339,23 @@ template <typename T>
|
|||||||
void DiskVectorBase<T>::evict(void) const
|
void DiskVectorBase<T>::evict(void) const
|
||||||
{
|
{
|
||||||
auto &cache = *cachePtr_;
|
auto &cache = *cachePtr_;
|
||||||
|
auto &modified = *modifiedPtr_;
|
||||||
|
auto &index = *indexPtr_;
|
||||||
|
auto &freeInd = *freePtr_;
|
||||||
auto &loads = *loadsPtr_;
|
auto &loads = *loadsPtr_;
|
||||||
|
|
||||||
if (cache.size() >= cacheSize_)
|
if (index.size() >= cacheSize_)
|
||||||
{
|
{
|
||||||
DV_DEBUG_MSG(this, "evicting " << loads.front());
|
unsigned int i = loads.front();
|
||||||
cache.erase(loads.front());
|
|
||||||
|
DV_DEBUG_MSG(this, "evicting " << i);
|
||||||
|
if (modified[index.at(i)])
|
||||||
|
{
|
||||||
|
DV_DEBUG_MSG(this, "element " << i << " modified, saving to disk");
|
||||||
|
save(filename(i), cache[index.at(i)]);
|
||||||
|
}
|
||||||
|
freeInd.push(index.at(i));
|
||||||
|
index.erase(i);
|
||||||
loads.pop_front();
|
loads.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,29 +364,43 @@ template <typename T>
|
|||||||
void DiskVectorBase<T>::fetch(const unsigned int i) const
|
void DiskVectorBase<T>::fetch(const unsigned int i) const
|
||||||
{
|
{
|
||||||
auto &cache = *cachePtr_;
|
auto &cache = *cachePtr_;
|
||||||
|
auto &modified = *modifiedPtr_;
|
||||||
|
auto &index = *indexPtr_;
|
||||||
|
auto &freeInd = *freePtr_;
|
||||||
auto &loads = *loadsPtr_;
|
auto &loads = *loadsPtr_;
|
||||||
|
|
||||||
struct stat s;
|
struct stat s;
|
||||||
|
|
||||||
DV_DEBUG_MSG(this, "loading " << i << " from disk");
|
DV_DEBUG_MSG(this, "loading " << i << " from disk");
|
||||||
|
|
||||||
evict();
|
evict();
|
||||||
|
|
||||||
if(stat(filename(i).c_str(), &s) != 0)
|
if(stat(filename(i).c_str(), &s) != 0)
|
||||||
{
|
{
|
||||||
HADRONS_ERROR(Io, "disk vector element " + std::to_string(i) + " uninitialised");
|
HADRONS_ERROR(Io, "disk vector element " + std::to_string(i) + " uninitialised");
|
||||||
}
|
}
|
||||||
load(cache[i], filename(i));
|
index[i] = freeInd.top();
|
||||||
|
freeInd.pop();
|
||||||
|
load(cache[index.at(i)], filename(i));
|
||||||
loads.push_back(i);
|
loads.push_back(i);
|
||||||
|
modified[index.at(i)] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void DiskVectorBase<T>::cacheInsert(const unsigned int i, const T &obj) const
|
void DiskVectorBase<T>::cacheInsert(const unsigned int i, const T &obj) const
|
||||||
{
|
{
|
||||||
auto &cache = *cachePtr_;
|
auto &cache = *cachePtr_;
|
||||||
|
auto &modified = *modifiedPtr_;
|
||||||
|
auto &index = *indexPtr_;
|
||||||
|
auto &freeInd = *freePtr_;
|
||||||
auto &loads = *loadsPtr_;
|
auto &loads = *loadsPtr_;
|
||||||
|
|
||||||
evict();
|
evict();
|
||||||
cache[i] = obj;
|
index[i] = freeInd.top();
|
||||||
|
freeInd.pop();
|
||||||
|
cache[index.at(i)] = obj;
|
||||||
loads.push_back(i);
|
loads.push_back(i);
|
||||||
|
modified[index.at(i)] = false;
|
||||||
|
|
||||||
#ifdef DV_DEBUG
|
#ifdef DV_DEBUG
|
||||||
std::string msg;
|
std::string msg;
|
||||||
|
@ -166,7 +166,13 @@ std::string Hadrons::dirname(const std::string &s)
|
|||||||
|
|
||||||
void Hadrons::makeFileDir(const std::string filename, GridBase *g)
|
void Hadrons::makeFileDir(const std::string filename, GridBase *g)
|
||||||
{
|
{
|
||||||
if (g->IsBoss())
|
bool doIt = true;
|
||||||
|
|
||||||
|
if (g)
|
||||||
|
{
|
||||||
|
doIt = g->IsBoss();
|
||||||
|
}
|
||||||
|
if (doIt)
|
||||||
{
|
{
|
||||||
std::string dir = dirname(filename);
|
std::string dir = dirname(filename);
|
||||||
int status = mkdir(dir);
|
int status = mkdir(dir);
|
||||||
|
@ -32,6 +32,7 @@ See the full license in the file "LICENSE" in the top level distribution directo
|
|||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <regex>
|
||||||
#include <Grid/Grid.h>
|
#include <Grid/Grid.h>
|
||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
|
|
||||||
@ -217,15 +218,15 @@ typedef XmlReader ResultReader;
|
|||||||
typedef XmlWriter ResultWriter;
|
typedef XmlWriter ResultWriter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RESULT_FILE_NAME(name) \
|
#define RESULT_FILE_NAME(name, traj) \
|
||||||
name + "." + std::to_string(vm().getTrajectory()) + "." + resultFileExt
|
name + "." + std::to_string(traj) + "." + resultFileExt
|
||||||
|
|
||||||
// recursive mkdir
|
// recursive mkdir
|
||||||
#define MAX_PATH_LENGTH 512u
|
#define MAX_PATH_LENGTH 512u
|
||||||
int mkdir(const std::string dirName);
|
int mkdir(const std::string dirName);
|
||||||
std::string basename(const std::string &s);
|
std::string basename(const std::string &s);
|
||||||
std::string dirname(const std::string &s);
|
std::string dirname(const std::string &s);
|
||||||
void makeFileDir(const std::string filename, GridBase *g);
|
void makeFileDir(const std::string filename, GridBase *g = nullptr);
|
||||||
|
|
||||||
// default Schur convention
|
// default Schur convention
|
||||||
#ifndef HADRONS_DEFAULT_SCHUR
|
#ifndef HADRONS_DEFAULT_SCHUR
|
||||||
@ -248,6 +249,47 @@ void makeFileDir(const std::string filename, GridBase *g);
|
|||||||
// pretty print time profile
|
// pretty print time profile
|
||||||
void printTimeProfile(const std::map<std::string, GridTime> &timing, GridTime total);
|
void printTimeProfile(const std::map<std::string, GridTime> &timing, GridTime total);
|
||||||
|
|
||||||
|
// token replacement utility
|
||||||
|
template <typename T>
|
||||||
|
void tokenReplace(std::string &str, const std::string token,
|
||||||
|
const T &x, const std::string mark = "@")
|
||||||
|
{
|
||||||
|
std::string fullToken = mark + token + mark;
|
||||||
|
|
||||||
|
auto pos = str.find(fullToken);
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
str.replace(pos, fullToken.size(), std::to_string(x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trajectory range
|
||||||
|
class TrajRange: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(TrajRange,
|
||||||
|
unsigned int, start,
|
||||||
|
unsigned int, end,
|
||||||
|
unsigned int, step,
|
||||||
|
std::string, exclude);
|
||||||
|
|
||||||
|
inline std::vector<unsigned int> getTrajectoryList(void)
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> excVec = strToVec<unsigned int>(exclude);
|
||||||
|
std::vector<unsigned int> list;
|
||||||
|
|
||||||
|
for (unsigned int t = start; t < end; t += step)
|
||||||
|
{
|
||||||
|
if (std::find(excVec.begin(), excVec.end(), t) == excVec.end())
|
||||||
|
{
|
||||||
|
list.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
END_HADRONS_NAMESPACE
|
END_HADRONS_NAMESPACE
|
||||||
|
|
||||||
#include <Hadrons/Exceptions.hpp>
|
#include <Hadrons/Exceptions.hpp>
|
||||||
|
@ -5,17 +5,17 @@ lib_LIBRARIES = libHadrons.a
|
|||||||
include modules.inc
|
include modules.inc
|
||||||
|
|
||||||
libHadrons_a_SOURCES = \
|
libHadrons_a_SOURCES = \
|
||||||
$(modules_cc) \
|
|
||||||
Application.cc \
|
Application.cc \
|
||||||
Environment.cc \
|
Environment.cc \
|
||||||
Exceptions.cc \
|
Exceptions.cc \
|
||||||
Global.cc \
|
Global.cc \
|
||||||
Module.cc \
|
Module.cc \
|
||||||
TimerArray.cc \
|
TimerArray.cc \
|
||||||
VirtualMachine.cc
|
VirtualMachine.cc \
|
||||||
|
$(modules_cc)
|
||||||
|
|
||||||
libHadrons_adir = $(includedir)/Hadrons
|
libHadrons_adir = $(includedir)/Hadrons
|
||||||
nobase_libHadrons_a_HEADERS = \
|
nobase_libHadrons_a_HEADERS = \
|
||||||
$(modules_hpp) \
|
|
||||||
A2AVectors.hpp \
|
A2AVectors.hpp \
|
||||||
A2AMatrix.hpp \
|
A2AMatrix.hpp \
|
||||||
Application.hpp \
|
Application.hpp \
|
||||||
@ -33,4 +33,6 @@ nobase_libHadrons_a_HEADERS = \
|
|||||||
ModuleFactory.hpp \
|
ModuleFactory.hpp \
|
||||||
Solver.hpp \
|
Solver.hpp \
|
||||||
TimerArray.hpp \
|
TimerArray.hpp \
|
||||||
VirtualMachine.hpp
|
VirtualMachine.hpp \
|
||||||
|
Utilities/Contractor.hpp \
|
||||||
|
$(modules_hpp)
|
||||||
|
@ -144,7 +144,7 @@ if (env().getGrid()->IsBoss() and !ioStem.empty())\
|
|||||||
{\
|
{\
|
||||||
makeFileDir(ioStem, env().getGrid());\
|
makeFileDir(ioStem, env().getGrid());\
|
||||||
{\
|
{\
|
||||||
ResultWriter _writer(RESULT_FILE_NAME(ioStem));\
|
ResultWriter _writer(RESULT_FILE_NAME(ioStem, vm().getTrajectory()));\
|
||||||
write(_writer, name, result);\
|
write(_writer, name, result);\
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,11 @@
|
|||||||
#include <Hadrons/Modules/MSolver/Guesser.hpp>
|
#include <Hadrons/Modules/MSolver/Guesser.hpp>
|
||||||
#include <Hadrons/Modules/MSolver/RBPrecCG.hpp>
|
#include <Hadrons/Modules/MSolver/RBPrecCG.hpp>
|
||||||
#include <Hadrons/Modules/MSolver/A2AVectors.hpp>
|
#include <Hadrons/Modules/MSolver/A2AVectors.hpp>
|
||||||
|
#include <Hadrons/Modules/MSolver/A2AAslashVectors.hpp>
|
||||||
#include <Hadrons/Modules/MGauge/UnitEm.hpp>
|
#include <Hadrons/Modules/MGauge/UnitEm.hpp>
|
||||||
#include <Hadrons/Modules/MGauge/StoutSmearing.hpp>
|
#include <Hadrons/Modules/MGauge/StoutSmearing.hpp>
|
||||||
#include <Hadrons/Modules/MGauge/Unit.hpp>
|
#include <Hadrons/Modules/MGauge/Unit.hpp>
|
||||||
|
#include <Hadrons/Modules/MGauge/Electrify.hpp>
|
||||||
#include <Hadrons/Modules/MGauge/Random.hpp>
|
#include <Hadrons/Modules/MGauge/Random.hpp>
|
||||||
#include <Hadrons/Modules/MGauge/GaugeFix.hpp>
|
#include <Hadrons/Modules/MGauge/GaugeFix.hpp>
|
||||||
#include <Hadrons/Modules/MGauge/FundtoHirep.hpp>
|
#include <Hadrons/Modules/MGauge/FundtoHirep.hpp>
|
||||||
|
@ -49,7 +49,8 @@ public:
|
|||||||
unsigned int, Ls,
|
unsigned int, Ls,
|
||||||
double , mass,
|
double , mass,
|
||||||
double , M5,
|
double , M5,
|
||||||
std::string , boundary);
|
std::string , boundary,
|
||||||
|
std::string , twist);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FImpl>
|
template <typename FImpl>
|
||||||
@ -119,8 +120,9 @@ void TDWF<FImpl>::setup(void)
|
|||||||
auto &grb4 = *envGetRbGrid(FermionField);
|
auto &grb4 = *envGetRbGrid(FermionField);
|
||||||
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
||||||
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
||||||
std::vector<Complex> boundary = strToVec<Complex>(par().boundary);
|
typename DomainWallFermion<FImpl>::ImplParams implParams;
|
||||||
typename DomainWallFermion<FImpl>::ImplParams implParams(boundary);
|
implParams.boundary_phases = strToVec<Complex>(par().boundary);
|
||||||
|
implParams.twist_n_2pi_L = strToVec<Real>(par().twist);
|
||||||
envCreateDerived(FMat, DomainWallFermion<FImpl>, getName(), par().Ls, U, g5,
|
envCreateDerived(FMat, DomainWallFermion<FImpl>, getName(), par().Ls, U, g5,
|
||||||
grb5, g4, grb4, par().mass, par().M5, implParams);
|
grb5, g4, grb4, par().mass, par().M5, implParams);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,8 @@ public:
|
|||||||
double , M5,
|
double , M5,
|
||||||
double , b,
|
double , b,
|
||||||
double , c,
|
double , c,
|
||||||
std::string , boundary);
|
std::string , boundary,
|
||||||
|
std::string , twist);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FImpl>
|
template <typename FImpl>
|
||||||
@ -119,8 +120,9 @@ void TMobiusDWF<FImpl>::setup(void)
|
|||||||
auto &grb4 = *envGetRbGrid(FermionField);
|
auto &grb4 = *envGetRbGrid(FermionField);
|
||||||
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
||||||
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
||||||
std::vector<Complex> boundary = strToVec<Complex>(par().boundary);
|
typename MobiusFermion<FImpl>::ImplParams implParams;
|
||||||
typename MobiusFermion<FImpl>::ImplParams implParams(boundary);
|
implParams.boundary_phases = strToVec<Complex>(par().boundary);
|
||||||
|
implParams.twist_n_2pi_L = strToVec<Real>(par().twist);
|
||||||
envCreateDerived(FMat, MobiusFermion<FImpl>, getName(), par().Ls, U, g5,
|
envCreateDerived(FMat, MobiusFermion<FImpl>, getName(), par().Ls, U, g5,
|
||||||
grb5, g4, grb4, par().mass, par().M5, par().b, par().c,
|
grb5, g4, grb4, par().mass, par().M5, par().b, par().c,
|
||||||
implParams);
|
implParams);
|
||||||
|
@ -48,7 +48,8 @@ public:
|
|||||||
double , mass,
|
double , mass,
|
||||||
double , M5,
|
double , M5,
|
||||||
double , scale,
|
double , scale,
|
||||||
std::string , boundary);
|
std::string , boundary,
|
||||||
|
std::string , twist);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FImpl>
|
template <typename FImpl>
|
||||||
@ -118,8 +119,9 @@ void TScaledDWF<FImpl>::setup(void)
|
|||||||
auto &grb4 = *envGetRbGrid(FermionField);
|
auto &grb4 = *envGetRbGrid(FermionField);
|
||||||
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
||||||
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
||||||
std::vector<Complex> boundary = strToVec<Complex>(par().boundary);
|
typename ScaledShamirFermion<FImpl>::ImplParams implParams;
|
||||||
typename MobiusFermion<FImpl>::ImplParams implParams(boundary);
|
implParams.boundary_phases = strToVec<Complex>(par().boundary);
|
||||||
|
implParams.twist_n_2pi_L = strToVec<Real>(par().twist);
|
||||||
envCreateDerived(FMat, ScaledShamirFermion<FImpl>, getName(), par().Ls, U, g5,
|
envCreateDerived(FMat, ScaledShamirFermion<FImpl>, getName(), par().Ls, U, g5,
|
||||||
grb5, g4, grb4, par().mass, par().M5, par().scale,
|
grb5, g4, grb4, par().mass, par().M5, par().scale,
|
||||||
implParams);
|
implParams);
|
||||||
|
@ -47,7 +47,9 @@ public:
|
|||||||
GRID_SERIALIZABLE_CLASS_MEMBERS(WilsonPar,
|
GRID_SERIALIZABLE_CLASS_MEMBERS(WilsonPar,
|
||||||
std::string, gauge,
|
std::string, gauge,
|
||||||
double , mass,
|
double , mass,
|
||||||
std::string, boundary);
|
std::string, boundary,
|
||||||
|
std::string, string,
|
||||||
|
std::string, twist);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FImpl>
|
template <typename FImpl>
|
||||||
@ -113,8 +115,9 @@ void TWilson<FImpl>::setup(void)
|
|||||||
auto &U = envGet(GaugeField, par().gauge);
|
auto &U = envGet(GaugeField, par().gauge);
|
||||||
auto &grid = *envGetGrid(FermionField);
|
auto &grid = *envGetGrid(FermionField);
|
||||||
auto &gridRb = *envGetRbGrid(FermionField);
|
auto &gridRb = *envGetRbGrid(FermionField);
|
||||||
std::vector<Complex> boundary = strToVec<Complex>(par().boundary);
|
typename WilsonFermion<FImpl>::ImplParams implParams;
|
||||||
typename WilsonFermion<FImpl>::ImplParams implParams(boundary);
|
implParams.boundary_phases = strToVec<Complex>(par().boundary);
|
||||||
|
implParams.twist_n_2pi_L = strToVec<Real>(par().twist);
|
||||||
envCreateDerived(FMat, WilsonFermion<FImpl>, getName(), 1, U, grid, gridRb,
|
envCreateDerived(FMat, WilsonFermion<FImpl>, getName(), 1, U, grid, gridRb,
|
||||||
par().mass, implParams);
|
par().mass, implParams);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ public:
|
|||||||
double , csw_r,
|
double , csw_r,
|
||||||
double , csw_t,
|
double , csw_t,
|
||||||
WilsonAnisotropyCoefficients ,clover_anisotropy,
|
WilsonAnisotropyCoefficients ,clover_anisotropy,
|
||||||
std::string, boundary
|
std::string, boundary,
|
||||||
|
std::string, twist
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -119,8 +120,9 @@ void TWilsonClover<FImpl>::setup(void)
|
|||||||
auto &U = envGet(GaugeField, par().gauge);
|
auto &U = envGet(GaugeField, par().gauge);
|
||||||
auto &grid = *envGetGrid(FermionField);
|
auto &grid = *envGetGrid(FermionField);
|
||||||
auto &gridRb = *envGetRbGrid(FermionField);
|
auto &gridRb = *envGetRbGrid(FermionField);
|
||||||
std::vector<Complex> boundary = strToVec<Complex>(par().boundary);
|
typename WilsonCloverFermion<FImpl>::ImplParams implParams;
|
||||||
typename WilsonCloverFermion<FImpl>::ImplParams implParams(boundary);
|
implParams.boundary_phases = strToVec<Complex>(par().boundary);
|
||||||
|
implParams.twist_n_2pi_L = strToVec<Real>(par().twist);
|
||||||
envCreateDerived(FMat, WilsonCloverFermion<FImpl>, getName(), 1, U, grid,
|
envCreateDerived(FMat, WilsonCloverFermion<FImpl>, getName(), 1, U, grid,
|
||||||
gridRb, par().mass, par().csw_r, par().csw_t,
|
gridRb, par().mass, par().csw_r, par().csw_t,
|
||||||
par().clover_anisotropy, implParams);
|
par().clover_anisotropy, implParams);
|
||||||
|
@ -50,7 +50,8 @@ public:
|
|||||||
double , b,
|
double , b,
|
||||||
double , c,
|
double , c,
|
||||||
std::vector<std::complex<double>>, omega,
|
std::vector<std::complex<double>>, omega,
|
||||||
std::string , boundary);
|
std::string , boundary,
|
||||||
|
std::string , twist);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FImpl>
|
template <typename FImpl>
|
||||||
@ -127,8 +128,9 @@ void TZMobiusDWF<FImpl>::setup(void)
|
|||||||
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
auto &g5 = *envGetGrid(FermionField, par().Ls);
|
||||||
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
auto &grb5 = *envGetRbGrid(FermionField, par().Ls);
|
||||||
auto omega = par().omega;
|
auto omega = par().omega;
|
||||||
std::vector<Complex> boundary = strToVec<Complex>(par().boundary);
|
typename ZMobiusFermion<FImpl>::ImplParams implParams;
|
||||||
typename ZMobiusFermion<FImpl>::ImplParams implParams(boundary);
|
implParams.boundary_phases = strToVec<Complex>(par().boundary);
|
||||||
|
implParams.twist_n_2pi_L = strToVec<Real>(par().twist);
|
||||||
envCreateDerived(FMat, ZMobiusFermion<FImpl>, getName(), par().Ls, U, g5,
|
envCreateDerived(FMat, ZMobiusFermion<FImpl>, getName(), par().Ls, U, g5,
|
||||||
grb5, g4, grb4, par().mass, par().M5, omega,
|
grb5, g4, grb4, par().mass, par().M5, omega,
|
||||||
par().b, par().c, implParams);
|
par().b, par().c, implParams);
|
||||||
|
@ -33,10 +33,6 @@ See the full license in the file "LICENSE" in the top level distribution directo
|
|||||||
#include <Hadrons/ModuleFactory.hpp>
|
#include <Hadrons/ModuleFactory.hpp>
|
||||||
#include <Hadrons/A2AMatrix.hpp>
|
#include <Hadrons/A2AMatrix.hpp>
|
||||||
|
|
||||||
#ifndef ASF_IO_TYPE
|
|
||||||
#define ASF_IO_TYPE ComplexF
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BEGIN_HADRONS_NAMESPACE
|
BEGIN_HADRONS_NAMESPACE
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@ -113,7 +109,7 @@ public:
|
|||||||
typedef A2AMatrixBlockComputation<Complex,
|
typedef A2AMatrixBlockComputation<Complex,
|
||||||
FermionField,
|
FermionField,
|
||||||
A2AAslashFieldMetadata,
|
A2AAslashFieldMetadata,
|
||||||
ASF_IO_TYPE> Computation;
|
HADRONS_A2AM_IO_TYPE> Computation;
|
||||||
typedef AslashFieldKernel<Complex, FImpl> Kernel;
|
typedef AslashFieldKernel<Complex, FImpl> Kernel;
|
||||||
public:
|
public:
|
||||||
// constructor
|
// constructor
|
||||||
@ -196,7 +192,7 @@ void TA2AAslashField<FImpl, PhotonImpl>::execute(void)
|
|||||||
LOG(Message) << " " << name << std::endl;
|
LOG(Message) << " " << name << std::endl;
|
||||||
}
|
}
|
||||||
LOG(Message) << "A-slash field size: " << nt << "*" << N_i << "*" << N_j
|
LOG(Message) << "A-slash field size: " << nt << "*" << N_i << "*" << N_j
|
||||||
<< " (filesize " << sizeString(nt*N_i*N_j*sizeof(ASF_IO_TYPE))
|
<< " (filesize " << sizeString(nt*N_i*N_j*sizeof(HADRONS_A2AM_IO_TYPE))
|
||||||
<< "/EM field)" << std::endl;
|
<< "/EM field)" << std::endl;
|
||||||
|
|
||||||
// preparing "B" complexified fields
|
// preparing "B" complexified fields
|
||||||
|
@ -35,10 +35,6 @@ See the full license in the file "LICENSE" in the top level distribution directo
|
|||||||
#include <Hadrons/ModuleFactory.hpp>
|
#include <Hadrons/ModuleFactory.hpp>
|
||||||
#include <Hadrons/A2AMatrix.hpp>
|
#include <Hadrons/A2AMatrix.hpp>
|
||||||
|
|
||||||
#ifndef MF_IO_TYPE
|
|
||||||
#define MF_IO_TYPE ComplexF
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BEGIN_HADRONS_NAMESPACE
|
BEGIN_HADRONS_NAMESPACE
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
@ -118,7 +114,7 @@ public:
|
|||||||
typedef A2AMatrixBlockComputation<Complex,
|
typedef A2AMatrixBlockComputation<Complex,
|
||||||
FermionField,
|
FermionField,
|
||||||
A2AMesonFieldMetadata,
|
A2AMesonFieldMetadata,
|
||||||
MF_IO_TYPE> Computation;
|
HADRONS_A2AM_IO_TYPE> Computation;
|
||||||
typedef MesonFieldKernel<Complex, FImpl> Kernel;
|
typedef MesonFieldKernel<Complex, FImpl> Kernel;
|
||||||
public:
|
public:
|
||||||
// constructor
|
// constructor
|
||||||
@ -248,7 +244,7 @@ void TA2AMesonField<FImpl>::execute(void)
|
|||||||
LOG(Message) << " " << g << std::endl;
|
LOG(Message) << " " << g << std::endl;
|
||||||
}
|
}
|
||||||
LOG(Message) << "Meson field size: " << nt << "*" << N_i << "*" << N_j
|
LOG(Message) << "Meson field size: " << nt << "*" << N_i << "*" << N_j
|
||||||
<< " (filesize " << sizeString(nt*N_i*N_j*sizeof(MF_IO_TYPE))
|
<< " (filesize " << sizeString(nt*N_i*N_j*sizeof(HADRONS_A2AM_IO_TYPE))
|
||||||
<< "/momentum/bilinear)" << std::endl;
|
<< "/momentum/bilinear)" << std::endl;
|
||||||
|
|
||||||
auto &ph = envGet(std::vector<ComplexField>, momphName_);
|
auto &ph = envGet(std::vector<ComplexField>, momphName_);
|
||||||
|
34
Hadrons/Modules/MGauge/Electrify.cc
Normal file
34
Hadrons/Modules/MGauge/Electrify.cc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: Hadrons/Modules/MGauge/Electrify.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Vera Guelpers <Vera.Guelpers@ed.ac.uk>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Hadrons/Modules/MGauge/Electrify.hpp>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Hadrons;
|
||||||
|
using namespace MGauge;
|
||||||
|
|
||||||
|
template class Grid::Hadrons::MGauge::TElectrify<GIMPL>;
|
151
Hadrons/Modules/MGauge/Electrify.hpp
Normal file
151
Hadrons/Modules/MGauge/Electrify.hpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: Hadrons/Modules/MGauge/Electrify.hpp
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Vera Guelpers <Vera.Guelpers@ed.ac.uk>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#ifndef Hadrons_MGauge_Electrify_hpp_
|
||||||
|
#define Hadrons_MGauge_Electrify_hpp_
|
||||||
|
|
||||||
|
#include <Hadrons/Global.hpp>
|
||||||
|
#include <Hadrons/Module.hpp>
|
||||||
|
#include <Hadrons/ModuleFactory.hpp>
|
||||||
|
|
||||||
|
BEGIN_HADRONS_NAMESPACE
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Electrify gauge *
|
||||||
|
******************************************************************************/
|
||||||
|
BEGIN_MODULE_NAMESPACE(MGauge)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Electrify a gauge field:
|
||||||
|
*
|
||||||
|
* Ue_mu(x) = U_mu(x)*exp(ieqA_mu(x))
|
||||||
|
*
|
||||||
|
* with
|
||||||
|
*
|
||||||
|
* - gauge: U_mu(x): gauge field
|
||||||
|
* - emField: A_mu(x): electromagnetic photon field
|
||||||
|
* - e: value for the elementary charge
|
||||||
|
* - q: charge in units of e
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
class ElectrifyPar: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(ElectrifyPar,
|
||||||
|
std::string, gauge,
|
||||||
|
std::string, emField,
|
||||||
|
double, e,
|
||||||
|
double, charge);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename GImpl>
|
||||||
|
class TElectrify: public Module<ElectrifyPar>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GAUGE_TYPE_ALIASES(GImpl,);
|
||||||
|
public:
|
||||||
|
typedef PhotonR::GaugeField EmField;
|
||||||
|
public:
|
||||||
|
// constructor
|
||||||
|
TElectrify(const std::string name);
|
||||||
|
// destructor
|
||||||
|
virtual ~TElectrify(void) {};
|
||||||
|
// dependencies/products
|
||||||
|
virtual std::vector<std::string> getInput(void);
|
||||||
|
virtual std::vector<std::string> getOutput(void);
|
||||||
|
protected:
|
||||||
|
// setup
|
||||||
|
virtual void setup(void);
|
||||||
|
// execution
|
||||||
|
virtual void execute(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_REGISTER_TMP(Electrify, TElectrify<GIMPL>, MGauge);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* TElectrify implementation *
|
||||||
|
******************************************************************************/
|
||||||
|
// constructor /////////////////////////////////////////////////////////////////
|
||||||
|
template <typename GImpl>
|
||||||
|
TElectrify<GImpl>::TElectrify(const std::string name)
|
||||||
|
: Module<ElectrifyPar>(name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// dependencies/products ///////////////////////////////////////////////////////
|
||||||
|
template <typename GImpl>
|
||||||
|
std::vector<std::string> TElectrify<GImpl>::getInput(void)
|
||||||
|
{
|
||||||
|
std::vector<std::string> in = {par().gauge, par().emField};
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename GImpl>
|
||||||
|
std::vector<std::string> TElectrify<GImpl>::getOutput(void)
|
||||||
|
{
|
||||||
|
std::vector<std::string> out = {getName()};
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup ///////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename GImpl>
|
||||||
|
void TElectrify<GImpl>::setup(void)
|
||||||
|
{
|
||||||
|
envCreateLat(GaugeField, getName());
|
||||||
|
envTmpLat(LatticeComplex, "eiAmu");
|
||||||
|
}
|
||||||
|
|
||||||
|
// execution ///////////////////////////////////////////////////////////////////
|
||||||
|
template <typename GImpl>
|
||||||
|
void TElectrify<GImpl>::execute(void)
|
||||||
|
{
|
||||||
|
LOG(Message) << "Electrify the gauge field " << par().gauge << " using the photon field "
|
||||||
|
<< par().emField << " with charge e*q= " << par().e << "*" << par().charge << std::endl;
|
||||||
|
|
||||||
|
auto &Ue = envGet(GaugeField, getName());
|
||||||
|
auto &U = envGet(GaugeField, par().gauge);
|
||||||
|
auto &A = envGet(EmField, par().emField);
|
||||||
|
envGetTmp(LatticeComplex, eiAmu);
|
||||||
|
|
||||||
|
Complex i(0.0,1.0);
|
||||||
|
|
||||||
|
for(unsigned int mu = 0; mu < env().getNd(); mu++)
|
||||||
|
{
|
||||||
|
eiAmu = exp(i * (Real)(par().e * par().charge) * PeekIndex<LorentzIndex>(A, mu));
|
||||||
|
PokeIndex<LorentzIndex>(Ue, PeekIndex<LorentzIndex>(U, mu) * eiAmu, mu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
END_MODULE_NAMESPACE
|
||||||
|
|
||||||
|
END_HADRONS_NAMESPACE
|
||||||
|
|
||||||
|
#endif // Hadrons_MGauge_Electrify_hpp_
|
@ -70,7 +70,7 @@ void TStochEm::execute(void)
|
|||||||
LOG(Message) << "Generating stochastic EM potential..." << std::endl;
|
LOG(Message) << "Generating stochastic EM potential..." << std::endl;
|
||||||
|
|
||||||
std::vector<Real> improvements = strToVec<Real>(par().improvement);
|
std::vector<Real> improvements = strToVec<Real>(par().improvement);
|
||||||
PhotonR photon(par().gauge, par().zmScheme, improvements, par().G0_qedInf);
|
PhotonR photon(envGetGrid(EmField), par().gauge, par().zmScheme, improvements);
|
||||||
auto &a = envGet(EmField, getName());
|
auto &a = envGet(EmField, getName());
|
||||||
auto &w = envGet(EmComp, "_" + getName() + "_weight");
|
auto &w = envGet(EmComp, "_" + getName() + "_weight");
|
||||||
|
|
||||||
|
@ -47,8 +47,7 @@ public:
|
|||||||
GRID_SERIALIZABLE_CLASS_MEMBERS(StochEmPar,
|
GRID_SERIALIZABLE_CLASS_MEMBERS(StochEmPar,
|
||||||
PhotonR::Gauge, gauge,
|
PhotonR::Gauge, gauge,
|
||||||
PhotonR::ZmScheme, zmScheme,
|
PhotonR::ZmScheme, zmScheme,
|
||||||
std::string, improvement,
|
std::string, improvement);
|
||||||
Real, G0_qedInf);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TStochEm: public Module<StochEmPar>
|
class TStochEm: public Module<StochEmPar>
|
||||||
|
@ -62,7 +62,7 @@ void TUnitEm::setup(void)
|
|||||||
// execution ///////////////////////////////////////////////////////////////////
|
// execution ///////////////////////////////////////////////////////////////////
|
||||||
void TUnitEm::execute(void)
|
void TUnitEm::execute(void)
|
||||||
{
|
{
|
||||||
PhotonR photon(0, 0); // Just chose arbitrary input values here
|
PhotonR photon(envGetGrid(EmField), 0, 0); // Just chose arbitrary input values here
|
||||||
auto &a = envGet(EmField, getName());
|
auto &a = envGet(EmField, getName());
|
||||||
LOG(Message) << "Generating unit EM potential..." << std::endl;
|
LOG(Message) << "Generating unit EM potential..." << std::endl;
|
||||||
photon.UnitField(a);
|
photon.UnitField(a);
|
||||||
|
@ -146,7 +146,7 @@ void TChargedProp::execute(void)
|
|||||||
std::vector<int> siteCoor;
|
std::vector<int> siteCoor;
|
||||||
|
|
||||||
LOG(Message) << "Saving momentum-projected propagator to '"
|
LOG(Message) << "Saving momentum-projected propagator to '"
|
||||||
<< RESULT_FILE_NAME(par().output) << "'..."
|
<< RESULT_FILE_NAME(par().output, vm().getTrajectory()) << "'..."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
result.projection.resize(par().outputMom.size());
|
result.projection.resize(par().outputMom.size());
|
||||||
result.lattice_size = env().getGrid()->_fdimensions;
|
result.lattice_size = env().getGrid()->_fdimensions;
|
||||||
|
@ -462,7 +462,7 @@ void TScalarVP::execute(void)
|
|||||||
if (!par().output.empty())
|
if (!par().output.empty())
|
||||||
{
|
{
|
||||||
LOG(Message) << "Saving momentum-projected HVP to '"
|
LOG(Message) << "Saving momentum-projected HVP to '"
|
||||||
<< RESULT_FILE_NAME(par().output) << "'..."
|
<< RESULT_FILE_NAME(par().output, vm().getTrajectory()) << "'..."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
saveResult(par().output, "HVP", outputData);
|
saveResult(par().output, "HVP", outputData);
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ void TVPCounterTerms::execute(void)
|
|||||||
if (!par().output.empty())
|
if (!par().output.empty())
|
||||||
{
|
{
|
||||||
LOG(Message) << "Saving momentum-projected correlators to '"
|
LOG(Message) << "Saving momentum-projected correlators to '"
|
||||||
<< RESULT_FILE_NAME(par().output) << "'..."
|
<< RESULT_FILE_NAME(par().output, vm().getTrajectory()) << "'..."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
saveResult(par().output, "scalar_loops", outputData);
|
saveResult(par().output, "scalar_loops", outputData);
|
||||||
}
|
}
|
||||||
|
35
Hadrons/Modules/MSolver/A2AAslashVectors.cc
Normal file
35
Hadrons/Modules/MSolver/A2AAslashVectors.cc
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: Hadrons/Modules/MSolver/A2AAslashVectors.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Vera Guelpers <Vera.Guelpers@ed.ac.uk>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Hadrons/Modules/MSolver/A2AAslashVectors.hpp>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Hadrons;
|
||||||
|
using namespace MSolver;
|
||||||
|
|
||||||
|
template class Grid::Hadrons::MSolver::TA2AAslashVectors<FIMPL>;
|
||||||
|
template class Grid::Hadrons::MSolver::TA2AAslashVectors<ZFIMPL>;
|
194
Hadrons/Modules/MSolver/A2AAslashVectors.hpp
Normal file
194
Hadrons/Modules/MSolver/A2AAslashVectors.hpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: Hadrons/Modules/MSolver/A2AAslashVectors.hpp
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Vera Guelpers <Vera.Guelpers@ed.ac.uk>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef Hadrons_MSolver_A2AAslashVectors_hpp_
|
||||||
|
#define Hadrons_MSolver_A2AAslashVectors_hpp_
|
||||||
|
|
||||||
|
#include <Hadrons/Global.hpp>
|
||||||
|
#include <Hadrons/Module.hpp>
|
||||||
|
#include <Hadrons/ModuleFactory.hpp>
|
||||||
|
#include <Hadrons/Solver.hpp>
|
||||||
|
#include <Hadrons/A2AVectors.hpp>
|
||||||
|
|
||||||
|
BEGIN_HADRONS_NAMESPACE
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Create all-to-all V & W vectors *
|
||||||
|
******************************************************************************/
|
||||||
|
BEGIN_MODULE_NAMESPACE(MSolver)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Calculate a sequential propagator on an insertion of i*g_mu*A_mu
|
||||||
|
* on an A2A vector
|
||||||
|
*
|
||||||
|
* vv_i(y) = S(y,x) * i * g_mu*A_mu(x) * v_i(x)
|
||||||
|
*
|
||||||
|
* with
|
||||||
|
*
|
||||||
|
* - vector: A2A vector v_i(x)
|
||||||
|
* - emField: A_mu(x): electromagnetic photon field
|
||||||
|
* - solver: the solver for calculating the sequential propagator
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
class A2AAslashVectorsPar: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(A2AAslashVectorsPar,
|
||||||
|
std::string, vector,
|
||||||
|
std::string, emField,
|
||||||
|
std::string, solver,
|
||||||
|
std::string, output,
|
||||||
|
bool, multiFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename FImpl>
|
||||||
|
class TA2AAslashVectors : public Module<A2AAslashVectorsPar>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FERM_TYPE_ALIASES(FImpl,);
|
||||||
|
SOLVER_TYPE_ALIASES(FImpl,);
|
||||||
|
public:
|
||||||
|
typedef PhotonR::GaugeField EmField;
|
||||||
|
public:
|
||||||
|
// constructor
|
||||||
|
TA2AAslashVectors(const std::string name);
|
||||||
|
// destructor
|
||||||
|
virtual ~TA2AAslashVectors(void) {};
|
||||||
|
// dependency relation
|
||||||
|
virtual std::vector<std::string> getInput(void);
|
||||||
|
virtual std::vector<std::string> getOutput(void);
|
||||||
|
// setup
|
||||||
|
virtual void setup(void);
|
||||||
|
// execution
|
||||||
|
virtual void execute(void);
|
||||||
|
private:
|
||||||
|
unsigned int Ls_;
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_REGISTER_TMP(A2AAslashVectors, TA2AAslashVectors<FIMPL>, MSolver);
|
||||||
|
MODULE_REGISTER_TMP(ZA2AAslashVectors, TA2AAslashVectors<ZFIMPL>, MSolver);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* TA2AAslashVectors implementation *
|
||||||
|
******************************************************************************/
|
||||||
|
// constructor /////////////////////////////////////////////////////////////////
|
||||||
|
template <typename FImpl>
|
||||||
|
TA2AAslashVectors<FImpl>::TA2AAslashVectors(const std::string name)
|
||||||
|
: Module<A2AAslashVectorsPar>(name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// dependencies/products ///////////////////////////////////////////////////////
|
||||||
|
template <typename FImpl>
|
||||||
|
std::vector<std::string> TA2AAslashVectors<FImpl>::getInput(void)
|
||||||
|
{
|
||||||
|
std::vector<std::string> in = {par().vector, par().emField, par().solver};
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FImpl>
|
||||||
|
std::vector<std::string> TA2AAslashVectors<FImpl>::getOutput(void)
|
||||||
|
{
|
||||||
|
std::vector<std::string> out = {getName()};
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup ///////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename FImpl>
|
||||||
|
void TA2AAslashVectors<FImpl>::setup(void)
|
||||||
|
{
|
||||||
|
Ls_ = env().getObjectLs(par().solver);
|
||||||
|
auto &vvector = envGet(std::vector<FermionField>, par().vector);
|
||||||
|
unsigned int Nmodes = vvector.size();
|
||||||
|
envCreate(std::vector<FermionField>, getName(), 1,
|
||||||
|
Nmodes, envGetGrid(FermionField));
|
||||||
|
|
||||||
|
envTmpLat(FermionField, "v4dtmp");
|
||||||
|
envTmpLat(FermionField, "v5dtmp", Ls_);
|
||||||
|
envTmpLat(FermionField, "v5dtmp_sol", Ls_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// execution ///////////////////////////////////////////////////////////////////
|
||||||
|
template <typename FImpl>
|
||||||
|
void TA2AAslashVectors<FImpl>::execute(void)
|
||||||
|
{
|
||||||
|
auto &solver = envGet(Solver, par().solver);
|
||||||
|
auto &stoch_photon = envGet(EmField, par().emField);
|
||||||
|
auto &vvector = envGet(std::vector<FermionField>, par().vector);
|
||||||
|
auto &Aslashv = envGet(std::vector<FermionField>, getName());
|
||||||
|
unsigned int Nmodes = vvector.size();
|
||||||
|
auto &mat = solver.getFMat();
|
||||||
|
envGetTmp(FermionField, v4dtmp);
|
||||||
|
envGetTmp(FermionField, v5dtmp);
|
||||||
|
envGetTmp(FermionField, v5dtmp_sol);
|
||||||
|
|
||||||
|
Complex ci(0.0,1.0);
|
||||||
|
|
||||||
|
startTimer("Seq Aslash");
|
||||||
|
LOG(Message) << "Calculate Sequential propagator on Aslash * v with the A2A vector "
|
||||||
|
<< par().vector << " and the photon field " << par().emField << std::endl;
|
||||||
|
for(unsigned int i=0; i<Nmodes; i++)
|
||||||
|
{
|
||||||
|
v4dtmp = zero;
|
||||||
|
startTimer("Multiply Aslash");
|
||||||
|
for(unsigned int mu=0;mu<=3;mu++)
|
||||||
|
{
|
||||||
|
Gamma gmu(Gamma::gmu[mu]);
|
||||||
|
v4dtmp += ci * PeekIndex<LorentzIndex>(stoch_photon, mu) * (gmu * vvector[i]);
|
||||||
|
}
|
||||||
|
stopTimer("Multiply Aslash");
|
||||||
|
|
||||||
|
startTimer("Inversion");
|
||||||
|
if (Ls_ == 1)
|
||||||
|
{
|
||||||
|
solver(Aslashv[i], v4dtmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mat.ImportPhysicalFermionSource(v4dtmp, v5dtmp);
|
||||||
|
solver(v5dtmp_sol, v5dtmp);
|
||||||
|
mat.ExportPhysicalFermionSolution(v5dtmp_sol, v4dtmp);
|
||||||
|
Aslashv[i] = v4dtmp;
|
||||||
|
}
|
||||||
|
stopTimer("Inversion");
|
||||||
|
}
|
||||||
|
stopTimer("Seq Aslash");
|
||||||
|
if (!par().output.empty())
|
||||||
|
{
|
||||||
|
startTimer("I/O");
|
||||||
|
A2AVectorsIo::write(par().output, Aslashv, par().multiFile, vm().getTrajectory());
|
||||||
|
stopTimer("I/O");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
END_MODULE_NAMESPACE
|
||||||
|
|
||||||
|
END_HADRONS_NAMESPACE
|
||||||
|
|
||||||
|
#endif // Hadrons_MSolver_A2AAslashVectors_hpp_
|
442
Hadrons/Utilities/Contractor.cc
Normal file
442
Hadrons/Utilities/Contractor.cc
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: Hadrons/Utilities/Contractor.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Hadrons/Global.hpp>
|
||||||
|
#include <Hadrons/A2AMatrix.hpp>
|
||||||
|
#include <Hadrons/DiskVector.hpp>
|
||||||
|
#include <Hadrons/TimerArray.hpp>
|
||||||
|
#include <Hadrons/Utilities/Contractor.hpp>
|
||||||
|
|
||||||
|
#ifdef GRID_COMMS_MPI3
|
||||||
|
#define GET_RANK(rank, nMpi) \
|
||||||
|
MPI_Comm_size(MPI_COMM_WORLD, &(nMpi));\
|
||||||
|
MPI_Comm_rank(MPI_COMM_WORLD, &(rank))
|
||||||
|
#define BARRIER() MPI_Barrier(MPI_COMM_WORLD)
|
||||||
|
#define GLOBAL_DSUM(x) MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD)
|
||||||
|
#define GLOBAL_DMAX(x) MPI_Allreduce(MPI_IN_PLACE, &x, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD)
|
||||||
|
#define INIT() MPI_Init(NULL, NULL)
|
||||||
|
#define FINALIZE() MPI_Finalize()
|
||||||
|
#else
|
||||||
|
#define GET_RANK(rank, nMpi) (nMpi) = 1; (rank) = 0
|
||||||
|
#define BARRIER()
|
||||||
|
#define GLOBAL_DSUM(x)
|
||||||
|
#define GLOBAL_DMAX(x)
|
||||||
|
#define INIT()
|
||||||
|
#define FINALIZE()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace QCD;
|
||||||
|
using namespace Hadrons;
|
||||||
|
|
||||||
|
#define TIME_MOD(t) (((t) + par.global.nt) % par.global.nt)
|
||||||
|
|
||||||
|
struct ContractorPar
|
||||||
|
{
|
||||||
|
Contractor::GlobalPar global;
|
||||||
|
std::vector<Contractor::A2AMatrixPar> a2aMatrix;
|
||||||
|
std::vector<Contractor::ProductPar> product;
|
||||||
|
};
|
||||||
|
|
||||||
|
void makeTimeSeq(std::vector<std::vector<unsigned int>> &timeSeq,
|
||||||
|
const std::vector<std::set<unsigned int>> ×,
|
||||||
|
std::vector<unsigned int> ¤t,
|
||||||
|
const unsigned int depth)
|
||||||
|
{
|
||||||
|
if (depth > 0)
|
||||||
|
{
|
||||||
|
for (auto t: times[times.size() - depth])
|
||||||
|
{
|
||||||
|
current[times.size() - depth] = t;
|
||||||
|
makeTimeSeq(timeSeq, times, current, depth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timeSeq.push_back(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeTimeSeq(std::vector<std::vector<unsigned int>> &timeSeq,
|
||||||
|
const std::vector<std::set<unsigned int>> ×)
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> current(times.size());
|
||||||
|
|
||||||
|
makeTimeSeq(timeSeq, times, current, times.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveCorrelator(const Contractor::CorrelatorResult &result, const std::string dir,
|
||||||
|
const unsigned int dt, const unsigned int traj)
|
||||||
|
{
|
||||||
|
std::string fileStem = "", filename;
|
||||||
|
std::vector<std::string> terms = strToVec<std::string>(result.contraction.terms);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < terms.size() - 1; i++)
|
||||||
|
{
|
||||||
|
fileStem += terms[i] + "_" + std::to_string(result.times[i]) + "_";
|
||||||
|
}
|
||||||
|
fileStem += terms.back();
|
||||||
|
if (!result.contraction.translationAverage)
|
||||||
|
{
|
||||||
|
fileStem += "_dt_" + std::to_string(dt);
|
||||||
|
}
|
||||||
|
filename = dir + "/" + RESULT_FILE_NAME(fileStem, traj);
|
||||||
|
std::cout << "Saving correlator to '" << filename << "'" << std::endl;
|
||||||
|
makeFileDir(dir);
|
||||||
|
ResultWriter writer(filename);
|
||||||
|
write(writer, fileStem, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printPerf(const double bytes, const double usec)
|
||||||
|
{
|
||||||
|
double maxt;
|
||||||
|
|
||||||
|
maxt = usec;
|
||||||
|
GLOBAL_DMAX(maxt);
|
||||||
|
std::cout << maxt/1.0e6 << " sec " << bytes/maxt*1.0e6/1024/1024/1024 << " GB/s";
|
||||||
|
}
|
||||||
|
|
||||||
|
void printPerf(const double bytes, const double busec,
|
||||||
|
const double flops, const double fusec)
|
||||||
|
{
|
||||||
|
double maxt;
|
||||||
|
|
||||||
|
printPerf(bytes, busec);
|
||||||
|
std::cout << " ";
|
||||||
|
maxt = fusec;
|
||||||
|
GLOBAL_DMAX(maxt);
|
||||||
|
std::cout << flops/fusec/1.0e3 << " GFlop/s";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<unsigned int> parseTimeRange(const std::string str, const unsigned int nt)
|
||||||
|
{
|
||||||
|
std::regex rex("([0-9]+)|(([0-9]+)\\.\\.([0-9]+))");
|
||||||
|
std::smatch sm;
|
||||||
|
std::vector<std::string> rstr = strToVec<std::string>(str);
|
||||||
|
std::set<unsigned int> tSet;
|
||||||
|
|
||||||
|
for (auto &s: rstr)
|
||||||
|
{
|
||||||
|
std::regex_match(s, sm, rex);
|
||||||
|
if (sm[1].matched)
|
||||||
|
{
|
||||||
|
unsigned int t;
|
||||||
|
|
||||||
|
t = std::stoi(sm[1].str());
|
||||||
|
if (t >= nt)
|
||||||
|
{
|
||||||
|
HADRONS_ERROR(Range, "time out of range (from expression '" + str + "')");
|
||||||
|
}
|
||||||
|
tSet.insert(t);
|
||||||
|
}
|
||||||
|
else if (sm[2].matched)
|
||||||
|
{
|
||||||
|
unsigned int ta, tb;
|
||||||
|
|
||||||
|
ta = std::stoi(sm[3].str());
|
||||||
|
tb = std::stoi(sm[4].str());
|
||||||
|
if ((ta >= nt) or (tb >= nt))
|
||||||
|
{
|
||||||
|
HADRONS_ERROR(Range, "time out of range (from expression '" + str + "')");
|
||||||
|
}
|
||||||
|
for (unsigned int ti = ta; ti <= tb; ++ti)
|
||||||
|
{
|
||||||
|
tSet.insert(ti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
// MPI init
|
||||||
|
int nMpi, rank;
|
||||||
|
|
||||||
|
INIT();
|
||||||
|
GET_RANK(rank, nMpi);
|
||||||
|
if (rank != 0)
|
||||||
|
{
|
||||||
|
std::cout.setstate(std::ios::badbit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse command line
|
||||||
|
std::string parFilename;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
std::cerr << "usage: " << argv[0] << " <parameter file>";
|
||||||
|
std::cerr << std::endl;
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
parFilename = argv[1];
|
||||||
|
|
||||||
|
// parse parameter file
|
||||||
|
ContractorPar par;
|
||||||
|
unsigned int nMat, nCont;
|
||||||
|
XmlReader reader(parFilename);
|
||||||
|
|
||||||
|
read(reader, "global", par.global);
|
||||||
|
read(reader, "a2aMatrix", par.a2aMatrix);
|
||||||
|
read(reader, "product", par.product);
|
||||||
|
nMat = par.a2aMatrix.size();
|
||||||
|
nCont = par.product.size();
|
||||||
|
|
||||||
|
// create diskvectors
|
||||||
|
std::map<std::string, EigenDiskVector<ComplexD>> a2aMat;
|
||||||
|
unsigned int cacheSize;
|
||||||
|
|
||||||
|
for (auto &p: par.a2aMatrix)
|
||||||
|
{
|
||||||
|
std::string dirName = par.global.diskVectorDir + "/" + p.name + "." + std::to_string(rank);
|
||||||
|
|
||||||
|
a2aMat.emplace(p.name, EigenDiskVector<ComplexD>(dirName, par.global.nt, p.cacheSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// trajectory loop
|
||||||
|
std::vector<unsigned int> tList = par.global.trajCounter.getTrajectoryList();
|
||||||
|
unsigned int indi, inde, indPerRank;
|
||||||
|
|
||||||
|
indPerRank = tList.size()/nMpi;
|
||||||
|
indi = rank*indPerRank;
|
||||||
|
BARRIER();
|
||||||
|
for (unsigned int tInd = indi; tInd < indi + indPerRank; tInd++)
|
||||||
|
{
|
||||||
|
unsigned int traj;
|
||||||
|
|
||||||
|
if (tInd < tList.size())
|
||||||
|
{
|
||||||
|
traj = tList[tInd];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
traj = tList.back();
|
||||||
|
}
|
||||||
|
if (nMpi > 1)
|
||||||
|
{
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << ":::::::: Trajectories ";
|
||||||
|
for (unsigned int r = 0; r < nMpi - 1; ++r)
|
||||||
|
{
|
||||||
|
std::cout << tList[tInd + r*indPerRank] << " ";
|
||||||
|
}
|
||||||
|
if (tInd + (nMpi - 1)*indPerRank < tList.size())
|
||||||
|
{
|
||||||
|
std::cout << tList[tInd + (nMpi - 1)*indPerRank];
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << ":::::::: Trajectory " << traj << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load data
|
||||||
|
for (auto &p: par.a2aMatrix)
|
||||||
|
{
|
||||||
|
std::string filename = p.file;
|
||||||
|
double t;
|
||||||
|
|
||||||
|
tokenReplace(filename, "traj", traj);
|
||||||
|
std::cout << "======== Loading '" << p.file << "'" << std::endl;
|
||||||
|
|
||||||
|
BARRIER();
|
||||||
|
A2AMatrixIo<HADRONS_A2AM_IO_TYPE> a2aIo(filename, p.dataset, par.global.nt);
|
||||||
|
|
||||||
|
a2aIo.load(a2aMat.at(p.name), &t);
|
||||||
|
GLOBAL_DMAX(t);
|
||||||
|
std::cout << "Read " << nMpi*a2aIo.getSize() << " bytes in " << t/1.0e6
|
||||||
|
<< " sec, " << nMpi*a2aIo.getSize()/t*1.0e6/1024/1024
|
||||||
|
<< " MB/s" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// contract
|
||||||
|
EigenDiskVector<ComplexD>::Matrix buf;
|
||||||
|
|
||||||
|
for (auto &p: par.product)
|
||||||
|
{
|
||||||
|
std::vector<std::string> term = strToVec<std::string>(p.terms);
|
||||||
|
std::vector<std::set<unsigned int>> times;
|
||||||
|
std::vector<std::vector<unsigned int>> timeSeq;
|
||||||
|
std::set<unsigned int> translations;
|
||||||
|
std::vector<A2AMatrixTr<ComplexD>> lastTerm(par.global.nt);
|
||||||
|
A2AMatrix<ComplexD> prod, buf, tmp;
|
||||||
|
TimerArray tAr;
|
||||||
|
double fusec, busec, flops, bytes, tusec;
|
||||||
|
Contractor::CorrelatorResult result;
|
||||||
|
|
||||||
|
BARRIER();
|
||||||
|
tAr.startTimer("Total");
|
||||||
|
std::cout << "======== Contraction tr(";
|
||||||
|
for (unsigned int g = 0; g < term.size(); ++g)
|
||||||
|
{
|
||||||
|
std::cout << term[g] << ((g == term.size() - 1) ? ')' : '*');
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
if (term.size() != p.times.size() + 1)
|
||||||
|
{
|
||||||
|
HADRONS_ERROR(Size, "number of terms (" + std::to_string(term.size())
|
||||||
|
+ ") different from number of times ("
|
||||||
|
+ std::to_string(p.times.size() + 1) + ")");
|
||||||
|
}
|
||||||
|
for (auto &s: p.times)
|
||||||
|
{
|
||||||
|
times.push_back(parseTimeRange(s, par.global.nt));
|
||||||
|
}
|
||||||
|
for (auto &m: par.a2aMatrix)
|
||||||
|
{
|
||||||
|
if (std::find(result.a2aMatrix.begin(), result.a2aMatrix.end(), m) == result.a2aMatrix.end())
|
||||||
|
{
|
||||||
|
result.a2aMatrix.push_back(m);
|
||||||
|
tokenReplace(result.a2aMatrix.back().file, "traj", traj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.contraction = p;
|
||||||
|
result.correlator.resize(par.global.nt, 0.);
|
||||||
|
|
||||||
|
translations = parseTimeRange(p.translations, par.global.nt);
|
||||||
|
makeTimeSeq(timeSeq, times);
|
||||||
|
std::cout << timeSeq.size()*translations.size()*(term.size() - 2) << " A*B, "
|
||||||
|
<< timeSeq.size()*translations.size()*par.global.nt << " tr(A*B)"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
std::cout << "* Caching transposed last term" << std::endl;
|
||||||
|
for (unsigned int t = 0; t < par.global.nt; ++t)
|
||||||
|
{
|
||||||
|
tAr.startTimer("Disk vector overhead");
|
||||||
|
const A2AMatrix<ComplexD> &ref = a2aMat.at(term.back())[t];
|
||||||
|
tAr.stopTimer("Disk vector overhead");
|
||||||
|
|
||||||
|
tAr.startTimer("Transpose caching");
|
||||||
|
lastTerm[t].resize(ref.rows(), ref.cols());
|
||||||
|
parallel_for (unsigned int j = 0; j < ref.cols(); ++j)
|
||||||
|
for (unsigned int i = 0; i < ref.rows(); ++i)
|
||||||
|
{
|
||||||
|
lastTerm[t](i, j) = ref(i, j);
|
||||||
|
}
|
||||||
|
tAr.stopTimer("Transpose caching");
|
||||||
|
}
|
||||||
|
bytes = par.global.nt*lastTerm[0].rows()*lastTerm[0].cols();
|
||||||
|
bytes *= sizeof(ComplexD)*nMpi;
|
||||||
|
printPerf(bytes, tAr.getDTimer("Transpose caching"));
|
||||||
|
std::cout << std::endl;
|
||||||
|
for (unsigned int i = 0; i < timeSeq.size(); ++i)
|
||||||
|
{
|
||||||
|
unsigned int dti = 0;
|
||||||
|
auto &t = timeSeq[i];
|
||||||
|
|
||||||
|
result.times = t;
|
||||||
|
for (unsigned int tLast = 0; tLast < par.global.nt; ++tLast)
|
||||||
|
{
|
||||||
|
result.correlator[tLast] = 0.;
|
||||||
|
}
|
||||||
|
for (auto &dt: translations)
|
||||||
|
{
|
||||||
|
std::cout << "* Step " << i*translations.size() + dti + 1
|
||||||
|
<< "/" << timeSeq.size()*translations.size()
|
||||||
|
<< " -- positions= " << t << ", dt= " << dt << std::endl;
|
||||||
|
if (term.size() > 2)
|
||||||
|
{
|
||||||
|
std::cout << std::setw(10) << "products ";
|
||||||
|
}
|
||||||
|
flops = 0.;
|
||||||
|
bytes = 0.;
|
||||||
|
fusec = tAr.getDTimer("A*B algebra");
|
||||||
|
busec = tAr.getDTimer("A*B total");
|
||||||
|
tAr.startTimer("Linear algebra");
|
||||||
|
tAr.startTimer("Disk vector overhead");
|
||||||
|
prod = a2aMat.at(term[0])[TIME_MOD(t[0] + dt)];
|
||||||
|
tAr.stopTimer("Disk vector overhead");
|
||||||
|
for (unsigned int j = 1; j < term.size() - 1; ++j)
|
||||||
|
{
|
||||||
|
tAr.startTimer("Disk vector overhead");
|
||||||
|
const A2AMatrix<ComplexD> &ref = a2aMat.at(term[j])[TIME_MOD(t[j] + dt)];
|
||||||
|
tAr.stopTimer("Disk vector overhead");
|
||||||
|
|
||||||
|
tAr.startTimer("A*B total");
|
||||||
|
tAr.startTimer("A*B algebra");
|
||||||
|
A2AContraction::mul(tmp, prod, ref);
|
||||||
|
tAr.stopTimer("A*B algebra");
|
||||||
|
flops += A2AContraction::mulFlops(prod, ref);
|
||||||
|
prod = tmp;
|
||||||
|
tAr.stopTimer("A*B total");
|
||||||
|
bytes += 3.*tmp.rows()*tmp.cols()*sizeof(ComplexD);
|
||||||
|
}
|
||||||
|
if (term.size() > 2)
|
||||||
|
{
|
||||||
|
printPerf(bytes*nMpi, tAr.getDTimer("A*B total") - busec,
|
||||||
|
flops*nMpi, tAr.getDTimer("A*B algebra") - fusec);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::setw(10) << "traces ";
|
||||||
|
flops = 0.;
|
||||||
|
bytes = 0.;
|
||||||
|
fusec = tAr.getDTimer("tr(A*B)");
|
||||||
|
busec = tAr.getDTimer("tr(A*B)");
|
||||||
|
for (unsigned int tLast = 0; tLast < par.global.nt; ++tLast)
|
||||||
|
{
|
||||||
|
tAr.startTimer("tr(A*B)");
|
||||||
|
A2AContraction::accTrMul(result.correlator[TIME_MOD(tLast - dt)], prod, lastTerm[tLast]);
|
||||||
|
tAr.stopTimer("tr(A*B)");
|
||||||
|
flops += A2AContraction::accTrMulFlops(prod, lastTerm[tLast]);
|
||||||
|
bytes += 2.*prod.rows()*prod.cols()*sizeof(ComplexD);
|
||||||
|
}
|
||||||
|
tAr.stopTimer("Linear algebra");
|
||||||
|
printPerf(bytes*nMpi, tAr.getDTimer("tr(A*B)") - busec,
|
||||||
|
flops*nMpi, tAr.getDTimer("tr(A*B)") - fusec);
|
||||||
|
std::cout << std::endl;
|
||||||
|
if (!p.translationAverage)
|
||||||
|
{
|
||||||
|
saveCorrelator(result, par.global.output, dt, traj);
|
||||||
|
for (unsigned int tLast = 0; tLast < par.global.nt; ++tLast)
|
||||||
|
{
|
||||||
|
result.correlator[tLast] = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dti++;
|
||||||
|
}
|
||||||
|
if (p.translationAverage)
|
||||||
|
{
|
||||||
|
for (unsigned int tLast = 0; tLast < par.global.nt; ++tLast)
|
||||||
|
{
|
||||||
|
result.correlator[tLast] /= translations.size();
|
||||||
|
}
|
||||||
|
saveCorrelator(result, par.global.output, 0, traj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tAr.stopTimer("Total");
|
||||||
|
printTimeProfile(tAr.getTimings(), tAr.getTimer("Total"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FINALIZE();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
53
Hadrons/Utilities/Contractor.hpp
Normal file
53
Hadrons/Utilities/Contractor.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef Hadrons_Contractor_hpp_
|
||||||
|
#define Hadrons_Contractor_hpp_
|
||||||
|
|
||||||
|
#include <Hadrons/Global.hpp>
|
||||||
|
|
||||||
|
BEGIN_HADRONS_NAMESPACE
|
||||||
|
|
||||||
|
namespace Contractor
|
||||||
|
{
|
||||||
|
class GlobalPar: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(GlobalPar,
|
||||||
|
TrajRange, trajCounter,
|
||||||
|
unsigned int, nt,
|
||||||
|
std::string, diskVectorDir,
|
||||||
|
std::string, output);
|
||||||
|
};
|
||||||
|
|
||||||
|
class A2AMatrixPar: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(A2AMatrixPar,
|
||||||
|
std::string, file,
|
||||||
|
std::string, dataset,
|
||||||
|
unsigned int, cacheSize,
|
||||||
|
std::string, name);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProductPar: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(ProductPar,
|
||||||
|
std::string, terms,
|
||||||
|
std::vector<std::string>, times,
|
||||||
|
std::string, translations,
|
||||||
|
bool, translationAverage);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CorrelatorResult: Serializable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(CorrelatorResult,
|
||||||
|
std::vector<Contractor::A2AMatrixPar>, a2aMatrix,
|
||||||
|
ProductPar, contraction,
|
||||||
|
std::vector<unsigned int>, times,
|
||||||
|
std::vector<ComplexD>, correlator);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
END_HADRONS_NAMESPACE
|
||||||
|
|
||||||
|
#endif // Hadrons_Contractor_hpp_
|
434
Hadrons/Utilities/ContractorBenchmark.cc
Normal file
434
Hadrons/Utilities/ContractorBenchmark.cc
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
#include <Hadrons/Global.hpp>
|
||||||
|
#include <Hadrons/A2AMatrix.hpp>
|
||||||
|
#ifdef USE_MKL
|
||||||
|
#include "mkl.h"
|
||||||
|
#include "mkl_cblas.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Hadrons;
|
||||||
|
|
||||||
|
#ifdef GRID_COMMS_MPI3
|
||||||
|
#define GET_RANK(rank, nMpi) \
|
||||||
|
MPI_Comm_size(MPI_COMM_WORLD, &(nMpi));\
|
||||||
|
MPI_Comm_rank(MPI_COMM_WORLD, &(rank))
|
||||||
|
#define BARRIER() MPI_Barrier(MPI_COMM_WORLD)
|
||||||
|
#define INIT() MPI_Init(NULL, NULL)
|
||||||
|
#define FINALIZE() MPI_Finalize()
|
||||||
|
#else
|
||||||
|
#define GET_RANK(rank, nMpi) (nMpi) = 1; (rank) = 0
|
||||||
|
#define BARRIER()
|
||||||
|
#define INIT()
|
||||||
|
#define FINALIZE()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename Function, typename MatLeft, typename MatRight>
|
||||||
|
inline void trBenchmark(const std::string name, const MatLeft &left,
|
||||||
|
const MatRight &right, const ComplexD ref, Function fn)
|
||||||
|
{
|
||||||
|
double t, flops, bytes, n = left[0].rows()*left[0].cols();
|
||||||
|
unsigned int nMat = left.size();
|
||||||
|
int nMpi, rank;
|
||||||
|
ComplexD buf;
|
||||||
|
|
||||||
|
t = 0.;
|
||||||
|
GET_RANK(rank, nMpi);
|
||||||
|
t = -usecond();
|
||||||
|
BARRIER();
|
||||||
|
for (unsigned int i = rank*nMat/nMpi; i < (rank+1)*nMat/nMpi; ++i)
|
||||||
|
{
|
||||||
|
fn(buf, left[i], right[i]);
|
||||||
|
}
|
||||||
|
BARRIER();
|
||||||
|
t += usecond();
|
||||||
|
flops = nMat*(6.*n + 2.*(n - 1.));
|
||||||
|
bytes = nMat*(2.*n*sizeof(ComplexD));
|
||||||
|
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << std::setw(34) << name << ": diff= "
|
||||||
|
<< std::setw(12) << std::norm(buf-ref)
|
||||||
|
<< std::setw(10) << t/1.0e6 << " sec "
|
||||||
|
<< std::setw(10) << flops/t/1.0e3 << " GFlop/s "
|
||||||
|
<< std::setw(10) << bytes/t*1.0e6/1024/1024/1024 << " GB/s "
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
::sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function, typename MatV, typename Mat>
|
||||||
|
inline void mulBenchmark(const std::string name, const MatV &left,
|
||||||
|
const MatV &right, const Mat &ref, Function fn)
|
||||||
|
{
|
||||||
|
double t, flops, bytes;
|
||||||
|
double nr = left[0].rows(), nc = left[0].cols(), n = nr*nc;
|
||||||
|
unsigned int nMat = left.size();
|
||||||
|
int nMpi, rank;
|
||||||
|
Mat buf(left[0].rows(), left[0].rows());
|
||||||
|
|
||||||
|
t = 0.;
|
||||||
|
GET_RANK(rank, nMpi);
|
||||||
|
t = -usecond();
|
||||||
|
BARRIER();
|
||||||
|
for (unsigned int i = rank*nMat/nMpi; i < (rank+1)*nMat/nMpi; ++i)
|
||||||
|
{
|
||||||
|
fn(buf, left[i], right[i]);
|
||||||
|
}
|
||||||
|
BARRIER();
|
||||||
|
t += usecond();
|
||||||
|
flops = nMat*(nr*nr*(6.*nc + 2.*(nc - 1.)));
|
||||||
|
bytes = nMat*(2*nc*nr*sizeof(ComplexD));
|
||||||
|
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << std::setw(34) << name << ": diff= "
|
||||||
|
<< std::setw(12) << (buf-ref).squaredNorm()
|
||||||
|
<< std::setw(10) << t/1.0e6 << " sec "
|
||||||
|
<< std::setw(10) << flops/t/1.0e3 << " GFlop/s "
|
||||||
|
<< std::setw(10) << bytes/t*1.0e6/1024/1024/1024 << " GB/s "
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
::sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MKL
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline void zdotuRow(ComplexD &res, const unsigned int aRow,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
const ComplexD *aPt, *bPt;
|
||||||
|
unsigned int aInc, bInc;
|
||||||
|
|
||||||
|
if (MatLeft::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aRow*a.cols();
|
||||||
|
aInc = 1;
|
||||||
|
}
|
||||||
|
else if (MatLeft::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aRow;
|
||||||
|
aInc = a.rows();
|
||||||
|
}
|
||||||
|
if (MatRight::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aRow;
|
||||||
|
bInc = b.cols();
|
||||||
|
}
|
||||||
|
else if (MatRight::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aRow*b.rows();
|
||||||
|
bInc = 1;
|
||||||
|
}
|
||||||
|
cblas_zdotu_sub(a.cols(), aPt, aInc, bPt, bInc, &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
static inline void zdotuCol(ComplexD &res, const unsigned int aCol,
|
||||||
|
const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
const ComplexD *aPt, *bPt;
|
||||||
|
unsigned int aInc, bInc;
|
||||||
|
|
||||||
|
if (MatLeft::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aCol;
|
||||||
|
aInc = a.cols();
|
||||||
|
}
|
||||||
|
else if (MatLeft::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
aPt = a.data() + aCol*a.rows();
|
||||||
|
aInc = 1;
|
||||||
|
}
|
||||||
|
if (MatRight::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aCol*b.cols();
|
||||||
|
bInc = 1;
|
||||||
|
}
|
||||||
|
else if (MatRight::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
bPt = b.data() + aCol;
|
||||||
|
bInc = b.rows();
|
||||||
|
}
|
||||||
|
cblas_zdotu_sub(a.rows(), aPt, aInc, bPt, bInc, &res);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename MatLeft, typename MatRight>
|
||||||
|
void fullTrBenchmark(const unsigned int ni, const unsigned int nj, const unsigned int nMat)
|
||||||
|
{
|
||||||
|
std::vector<MatLeft> left;
|
||||||
|
std::vector<MatRight> right;
|
||||||
|
MatRight buf;
|
||||||
|
ComplexD ref;
|
||||||
|
int rank, nMpi;
|
||||||
|
|
||||||
|
left.resize(nMat, MatLeft::Random(ni, nj));
|
||||||
|
right.resize(nMat, MatRight::Random(nj, ni));
|
||||||
|
GET_RANK(rank, nMpi);
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << "==== tr(A*B) benchmarks" << std::endl;
|
||||||
|
std::cout << "A matrices use ";
|
||||||
|
if (MatLeft::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
std::cout << "row-major ordering" << std::endl;
|
||||||
|
}
|
||||||
|
else if (MatLeft::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
std::cout << "col-major ordering" << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << "B matrices use ";
|
||||||
|
if (MatRight::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
std::cout << "row-major ordering" << std::endl;
|
||||||
|
}
|
||||||
|
else if (MatRight::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
std::cout << "col-major ordering" << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
BARRIER();
|
||||||
|
ref = (left.back()*right.back()).trace();
|
||||||
|
trBenchmark("Hadrons A2AContraction::accTrMul", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = 0.;
|
||||||
|
A2AContraction::accTrMul(res, a, b);
|
||||||
|
});
|
||||||
|
trBenchmark("Naive loop rows first", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
auto nr = a.rows(), nc = a.cols();
|
||||||
|
|
||||||
|
res = 0.;
|
||||||
|
parallel_for (unsigned int i = 0; i < nr; ++i)
|
||||||
|
{
|
||||||
|
ComplexD tmp = 0.;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < nc; ++j)
|
||||||
|
{
|
||||||
|
tmp += a(i, j)*b(j, i);
|
||||||
|
}
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
res += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trBenchmark("Naive loop cols first", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
auto nr = a.rows(), nc = a.cols();
|
||||||
|
|
||||||
|
res = 0.;
|
||||||
|
parallel_for (unsigned int j = 0; j < nc; ++j)
|
||||||
|
{
|
||||||
|
ComplexD tmp = 0.;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < nr; ++i)
|
||||||
|
{
|
||||||
|
tmp += a(i, j)*b(j, i);
|
||||||
|
}
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
res += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trBenchmark("Eigen tr(A*B)", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = (a*b).trace();
|
||||||
|
});
|
||||||
|
trBenchmark("Eigen row-wise dot", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = 0.;
|
||||||
|
parallel_for (unsigned int r = 0; r < a.rows(); ++r)
|
||||||
|
{
|
||||||
|
ComplexD tmp;
|
||||||
|
|
||||||
|
tmp = a.row(r).conjugate().dot(b.col(r));
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
res += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trBenchmark("Eigen col-wise dot", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = 0.;
|
||||||
|
parallel_for (unsigned int c = 0; c < a.cols(); ++c)
|
||||||
|
{
|
||||||
|
ComplexD tmp;
|
||||||
|
|
||||||
|
tmp = a.col(c).conjugate().dot(b.row(c));
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
res += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trBenchmark("Eigen Hadamard", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = a.cwiseProduct(b.transpose()).sum();
|
||||||
|
});
|
||||||
|
#ifdef USE_MKL
|
||||||
|
trBenchmark("MKL row-wise zdotu", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = 0.;
|
||||||
|
parallel_for (unsigned int r = 0; r < a.rows(); ++r)
|
||||||
|
{
|
||||||
|
ComplexD tmp;
|
||||||
|
|
||||||
|
zdotuRow(tmp, r, a, b);
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
res += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trBenchmark("MKL col-wise zdotu", left, right, ref,
|
||||||
|
[](ComplexD &res, const MatLeft &a, const MatRight &b)
|
||||||
|
{
|
||||||
|
res = 0.;
|
||||||
|
parallel_for (unsigned int c = 0; c < a.cols(); ++c)
|
||||||
|
{
|
||||||
|
ComplexD tmp;
|
||||||
|
|
||||||
|
zdotuCol(tmp, c, a, b);
|
||||||
|
parallel_critical
|
||||||
|
{
|
||||||
|
res += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
BARRIER();
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Mat>
|
||||||
|
void fullMulBenchmark(const unsigned int ni, const unsigned int nj, const unsigned int nMat)
|
||||||
|
{
|
||||||
|
std::vector<Mat> left, right;
|
||||||
|
Mat ref;
|
||||||
|
int rank, nMpi;
|
||||||
|
|
||||||
|
left.resize(nMat, Mat::Random(ni, nj));
|
||||||
|
right.resize(nMat, Mat::Random(nj, ni));
|
||||||
|
GET_RANK(rank, nMpi);
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << "==== A*B benchmarks" << std::endl;
|
||||||
|
std::cout << "all matrices use ";
|
||||||
|
if (Mat::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
std::cout << "row-major ordering" << std::endl;
|
||||||
|
}
|
||||||
|
else if (Mat::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
std::cout << "col-major ordering" << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
BARRIER();
|
||||||
|
ref = left.back()*right.back();
|
||||||
|
mulBenchmark("Hadrons A2AContraction::mul", left, right, ref,
|
||||||
|
[](Mat &res, const Mat &a, const Mat &b)
|
||||||
|
{
|
||||||
|
A2AContraction::mul(res, a, b);
|
||||||
|
});
|
||||||
|
mulBenchmark("Eigen A*B", left, right, ref,
|
||||||
|
[](Mat &res, const Mat &a, const Mat &b)
|
||||||
|
{
|
||||||
|
res = a*b;
|
||||||
|
});
|
||||||
|
#ifdef USE_MKL
|
||||||
|
mulBenchmark("MKL A*B", left, right, ref,
|
||||||
|
[](Mat &res, const Mat &a, const Mat &b)
|
||||||
|
{
|
||||||
|
const ComplexD one(1., 0.), zero(0., 0.);
|
||||||
|
if (Mat::Options == Eigen::RowMajor)
|
||||||
|
{
|
||||||
|
cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, a.rows(), b.cols(),
|
||||||
|
a.cols(), &one, a.data(), a.cols(), b.data(), b.cols(), &zero,
|
||||||
|
res.data(), res.cols());
|
||||||
|
}
|
||||||
|
else if (Mat::Options == Eigen::ColMajor)
|
||||||
|
{
|
||||||
|
cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, a.rows(), b.cols(),
|
||||||
|
a.cols(), &one, a.data(), a.rows(), b.data(), b.rows(), &zero,
|
||||||
|
res.data(), res.rows());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
BARRIER();
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// parse command line
|
||||||
|
Eigen::Index ni, nj, nMat;
|
||||||
|
int nMpi, rank;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
{
|
||||||
|
std::cerr << "usage: " << argv[0] << " <Ni> <Nj> <#matrices>";
|
||||||
|
std::cerr << std::endl;
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
ni = std::stoi(argv[1]);
|
||||||
|
nj = std::stoi(argv[2]);
|
||||||
|
nMat = std::stoi(argv[3]);
|
||||||
|
|
||||||
|
INIT();
|
||||||
|
GET_RANK(rank, nMpi);
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
std::cout << "\n*** ALL-TO-ALL MATRIX CONTRACTION BENCHMARK ***\n" << std::endl;
|
||||||
|
std::cout << nMat << " couples of " << ni << "x" << nj << " matrices\n" << std::endl;
|
||||||
|
|
||||||
|
std::cout << nMpi << " MPI processes" << std::endl;
|
||||||
|
#ifdef GRID_OMP
|
||||||
|
#pragma omp parallel
|
||||||
|
{
|
||||||
|
#pragma omp single
|
||||||
|
std::cout << omp_get_num_threads() << " threads\n" << std::endl;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::cout << "Single-threaded\n" << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EIGEN_USE_MKL_ALL
|
||||||
|
std::cout << "Eigen uses the MKL" << std::endl;
|
||||||
|
#endif
|
||||||
|
std::cout << "Eigen uses " << Eigen::nbThreads() << " threads" << std::endl;
|
||||||
|
#ifdef USE_MKL
|
||||||
|
std::cout << "MKL uses " << mkl_get_max_threads() << " threads" << std::endl;
|
||||||
|
#endif
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullTrBenchmark<A2AMatrix<ComplexD>, A2AMatrix<ComplexD>>(ni, nj, nMat);
|
||||||
|
fullTrBenchmark<A2AMatrix<ComplexD>, A2AMatrixTr<ComplexD>>(ni, nj, nMat);
|
||||||
|
fullTrBenchmark<A2AMatrixTr<ComplexD>, A2AMatrix<ComplexD>>(ni, nj, nMat);
|
||||||
|
fullTrBenchmark<A2AMatrixTr<ComplexD>, A2AMatrixTr<ComplexD>>(ni, nj, nMat);
|
||||||
|
fullMulBenchmark<A2AMatrix<ComplexD>>(ni, nj, nMat);
|
||||||
|
fullMulBenchmark<A2AMatrixTr<ComplexD>>(ni, nj, nMat);
|
||||||
|
FINALIZE();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
bin_PROGRAMS = HadronsXmlRun HadronsFermionEP64To32
|
bin_PROGRAMS = HadronsXmlRun HadronsFermionEP64To32 HadronsContractor HadronsContractorBenchmark
|
||||||
|
|
||||||
HadronsXmlRun_SOURCES = HadronsXmlRun.cc
|
HadronsXmlRun_SOURCES = HadronsXmlRun.cc
|
||||||
HadronsXmlRun_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
HadronsXmlRun_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
||||||
@ -6,3 +6,9 @@ HadronsXmlRun_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
|||||||
HadronsFermionEP64To32_SOURCES = EigenPackCast.cc
|
HadronsFermionEP64To32_SOURCES = EigenPackCast.cc
|
||||||
HadronsFermionEP64To32_CXXFLAGS = $(AM_CXXFLAGS) -DFIN=WilsonImplD::FermionField -DFOUT=WilsonImplF::FermionField
|
HadronsFermionEP64To32_CXXFLAGS = $(AM_CXXFLAGS) -DFIN=WilsonImplD::FermionField -DFOUT=WilsonImplF::FermionField
|
||||||
HadronsFermionEP64To32_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
HadronsFermionEP64To32_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
||||||
|
|
||||||
|
HadronsContractor_SOURCES = Contractor.cc Contractor.hpp
|
||||||
|
HadronsContractor_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
||||||
|
|
||||||
|
HadronsContractorBenchmark_SOURCES = ContractorBenchmark.cc
|
||||||
|
HadronsContractorBenchmark_LDADD = ../libHadrons.a ../../Grid/libGrid.a
|
||||||
|
@ -20,11 +20,13 @@ modules_cc =\
|
|||||||
Modules/MSink/Point.cc \
|
Modules/MSink/Point.cc \
|
||||||
Modules/MSink/Smear.cc \
|
Modules/MSink/Smear.cc \
|
||||||
Modules/MSolver/A2AVectors.cc \
|
Modules/MSolver/A2AVectors.cc \
|
||||||
|
Modules/MSolver/A2AAslashVectors.cc \
|
||||||
Modules/MSolver/RBPrecCG.cc \
|
Modules/MSolver/RBPrecCG.cc \
|
||||||
Modules/MSolver/MixedPrecisionRBPrecCG.cc \
|
Modules/MSolver/MixedPrecisionRBPrecCG.cc \
|
||||||
Modules/MSolver/LocalCoherenceLanczos.cc \
|
Modules/MSolver/LocalCoherenceLanczos.cc \
|
||||||
Modules/MGauge/StoutSmearing.cc \
|
Modules/MGauge/StoutSmearing.cc \
|
||||||
Modules/MGauge/Unit.cc \
|
Modules/MGauge/Unit.cc \
|
||||||
|
Modules/MGauge/Electrify.cc \
|
||||||
Modules/MGauge/UnitEm.cc \
|
Modules/MGauge/UnitEm.cc \
|
||||||
Modules/MGauge/StochEm.cc \
|
Modules/MGauge/StochEm.cc \
|
||||||
Modules/MGauge/Random.cc \
|
Modules/MGauge/Random.cc \
|
||||||
@ -95,9 +97,11 @@ modules_hpp =\
|
|||||||
Modules/MSolver/Guesser.hpp \
|
Modules/MSolver/Guesser.hpp \
|
||||||
Modules/MSolver/RBPrecCG.hpp \
|
Modules/MSolver/RBPrecCG.hpp \
|
||||||
Modules/MSolver/A2AVectors.hpp \
|
Modules/MSolver/A2AVectors.hpp \
|
||||||
|
Modules/MSolver/A2AAslashVectors.hpp \
|
||||||
Modules/MGauge/UnitEm.hpp \
|
Modules/MGauge/UnitEm.hpp \
|
||||||
Modules/MGauge/StoutSmearing.hpp \
|
Modules/MGauge/StoutSmearing.hpp \
|
||||||
Modules/MGauge/Unit.hpp \
|
Modules/MGauge/Unit.hpp \
|
||||||
|
Modules/MGauge/Electrify.hpp \
|
||||||
Modules/MGauge/Random.hpp \
|
Modules/MGauge/Random.hpp \
|
||||||
Modules/MGauge/GaugeFix.hpp \
|
Modules/MGauge/GaugeFix.hpp \
|
||||||
Modules/MGauge/FundtoHirep.hpp \
|
Modules/MGauge/FundtoHirep.hpp \
|
||||||
|
26
configure.ac
26
configure.ac
@ -123,10 +123,13 @@ case ${ac_SFW_FP16} in
|
|||||||
AC_MSG_ERROR(["SFW FP16 option not supported ${ac_SFW_FP16}"]);;
|
AC_MSG_ERROR(["SFW FP16 option not supported ${ac_SFW_FP16}"]);;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
############### MKL
|
############### Intel libraries
|
||||||
AC_ARG_ENABLE([mkl],
|
AC_ARG_ENABLE([mkl],
|
||||||
[AC_HELP_STRING([--enable-mkl=yes|no|prefix], [enable Intel MKL for LAPACK & FFTW])],
|
[AC_HELP_STRING([--enable-mkl=yes|no|prefix], [enable Intel MKL for LAPACK & FFTW])],
|
||||||
[ac_MKL=${enable_mkl}], [ac_MKL=no])
|
[ac_MKL=${enable_mkl}], [ac_MKL=no])
|
||||||
|
AC_ARG_ENABLE([ipp],
|
||||||
|
[AC_HELP_STRING([--enable-ipp=yes|no|prefix], [enable Intel IPP for fast CRC32C])],
|
||||||
|
[ac_IPP=${enable_mkl}], [ac_IPP=no])
|
||||||
|
|
||||||
case ${ac_MKL} in
|
case ${ac_MKL} in
|
||||||
no)
|
no)
|
||||||
@ -139,6 +142,17 @@ case ${ac_MKL} in
|
|||||||
AC_DEFINE([USE_MKL], [1], [Define to 1 if you use the Intel MKL]);;
|
AC_DEFINE([USE_MKL], [1], [Define to 1 if you use the Intel MKL]);;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
case ${ac_IPP} in
|
||||||
|
no)
|
||||||
|
;;
|
||||||
|
yes)
|
||||||
|
AC_DEFINE([USE_IPP], [1], [Define to 1 if you use the Intel IPP]);;
|
||||||
|
*)
|
||||||
|
AM_CXXFLAGS="-I$ac_IPP/include $AM_CXXFLAGS"
|
||||||
|
AM_LDFLAGS="-L$ac_IPP/lib $AM_LDFLAGS"
|
||||||
|
AC_DEFINE([USE_IPP], [1], [Define to 1 if you use the Intel IPP]);;
|
||||||
|
esac
|
||||||
|
|
||||||
############### HDF5
|
############### HDF5
|
||||||
AC_ARG_WITH([hdf5],
|
AC_ARG_WITH([hdf5],
|
||||||
[AS_HELP_STRING([--with-hdf5=prefix],
|
[AS_HELP_STRING([--with-hdf5=prefix],
|
||||||
@ -170,7 +184,13 @@ AC_CHECK_FUNCS([gettimeofday])
|
|||||||
|
|
||||||
if test "${ac_MKL}x" != "nox"; then
|
if test "${ac_MKL}x" != "nox"; then
|
||||||
AC_SEARCH_LIBS([mkl_set_interface_layer], [mkl_rt], [],
|
AC_SEARCH_LIBS([mkl_set_interface_layer], [mkl_rt], [],
|
||||||
[AC_MSG_ERROR("MKL enabled but library not found")])
|
[AC_MSG_ERROR("Intel MKL enabled but library not found")])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "${ac_IPP}x" != "nox"; then
|
||||||
|
AC_SEARCH_LIBS([ippsCRC32C_8u], [ippdc],
|
||||||
|
[LIBS="${LIBS} -lippdc -lippvm -lipps -lippcore"],
|
||||||
|
[AC_MSG_ERROR("Intel IPP enabled but library not found")])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_SEARCH_LIBS([__gmpf_init], [gmp],
|
AC_SEARCH_LIBS([__gmpf_init], [gmp],
|
||||||
@ -485,6 +505,7 @@ DX_INIT_DOXYGEN([$PACKAGE_NAME], [doxygen.cfg])
|
|||||||
|
|
||||||
############### Ouput
|
############### Ouput
|
||||||
cwd=`pwd -P`; cd ${srcdir}; abs_srcdir=`pwd -P`; cd ${cwd}
|
cwd=`pwd -P`; cd ${srcdir}; abs_srcdir=`pwd -P`; cd ${cwd}
|
||||||
|
GRID_CXX="$CXX"
|
||||||
GRID_CXXFLAGS="$AM_CXXFLAGS $CXXFLAGS"
|
GRID_CXXFLAGS="$AM_CXXFLAGS $CXXFLAGS"
|
||||||
GRID_LDFLAGS="$AM_LDFLAGS $LDFLAGS"
|
GRID_LDFLAGS="$AM_LDFLAGS $LDFLAGS"
|
||||||
GRID_LIBS=$LIBS
|
GRID_LIBS=$LIBS
|
||||||
@ -497,6 +518,7 @@ AM_LDFLAGS="-L${cwd}/Grid $AM_LDFLAGS"
|
|||||||
AC_SUBST([AM_CFLAGS])
|
AC_SUBST([AM_CFLAGS])
|
||||||
AC_SUBST([AM_CXXFLAGS])
|
AC_SUBST([AM_CXXFLAGS])
|
||||||
AC_SUBST([AM_LDFLAGS])
|
AC_SUBST([AM_LDFLAGS])
|
||||||
|
AC_SUBST([GRID_CXX])
|
||||||
AC_SUBST([GRID_CXXFLAGS])
|
AC_SUBST([GRID_CXXFLAGS])
|
||||||
AC_SUBST([GRID_LDFLAGS])
|
AC_SUBST([GRID_LDFLAGS])
|
||||||
AC_SUBST([GRID_LIBS])
|
AC_SUBST([GRID_LIBS])
|
||||||
|
@ -61,6 +61,10 @@ while test $# -gt 0; do
|
|||||||
echo @GRID_CXXFLAGS@
|
echo @GRID_CXXFLAGS@
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
--cxx)
|
||||||
|
echo @GRID_CXX@
|
||||||
|
;;
|
||||||
|
|
||||||
--ldflags)
|
--ldflags)
|
||||||
echo @GRID_LDFLAGS@
|
echo @GRID_LDFLAGS@
|
||||||
;;
|
;;
|
||||||
|
138
tests/core/Test_qed.cc
Normal file
138
tests/core/Test_qed.cc
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: tests/core/Test_qed.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Antonin Portelli <antonin.portelli@me.com>
|
||||||
|
Author: James Harrison <J.Harrison@soton.ac.uk>
|
||||||
|
|
||||||
|
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
|
||||||
|
*************************************************************************************/
|
||||||
|
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace QCD;
|
||||||
|
|
||||||
|
typedef PeriodicGaugeImpl<QedGImplR> QedPeriodicGImplR;
|
||||||
|
typedef PhotonR::GaugeField EmField;
|
||||||
|
typedef PhotonR::GaugeLinkField EmComp;
|
||||||
|
|
||||||
|
const int NCONFIGS = 20;
|
||||||
|
const int NWILSON = 10;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// initialization
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
std::cout << GridLogMessage << "Grid initialized" << std::endl;
|
||||||
|
|
||||||
|
// QED stuff
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(4, vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridParallelRNG pRNG(&grid);
|
||||||
|
PhotonR photon(&grid, PhotonR::Gauge::coulomb, PhotonR::ZmScheme::qedL);
|
||||||
|
EmField a(&grid);
|
||||||
|
EmField expA(&grid);
|
||||||
|
|
||||||
|
Complex imag_unit(0, 1);
|
||||||
|
|
||||||
|
Real wlA;
|
||||||
|
std::vector<Real> logWlAvg(NWILSON, 0.0), logWlTime(NWILSON, 0.0), logWlSpace(NWILSON, 0.0);
|
||||||
|
|
||||||
|
pRNG.SeedFixedIntegers({1, 2, 3, 4});
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Wilson loop calculation beginning" << std::endl;
|
||||||
|
for(int ic = 0; ic < NCONFIGS; ic++){
|
||||||
|
std::cout << GridLogMessage << "Configuration " << ic <<std::endl;
|
||||||
|
photon.StochasticField(a, pRNG);
|
||||||
|
|
||||||
|
// Exponentiate photon field
|
||||||
|
expA = exp(imag_unit*a);
|
||||||
|
|
||||||
|
// Calculate zero-modes
|
||||||
|
std::vector<EmField::vector_object::scalar_object> zm;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Total zero-mode norm 2 "
|
||||||
|
<< std::sqrt(norm2(sum(a))) << std::endl;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Spatial zero-mode norm 2" << std::endl;
|
||||||
|
sliceSum(a, zm, grid.Nd() - 1);
|
||||||
|
for (unsigned int t = 0; t < latt_size.back(); ++t)
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << "t = " << t << " " << std::sqrt(norm2(zm[t])) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate divergence
|
||||||
|
EmComp diva(&grid), amu(&grid);
|
||||||
|
|
||||||
|
diva = zero;
|
||||||
|
for (unsigned int mu = 0; mu < grid.Nd(); ++mu)
|
||||||
|
{
|
||||||
|
amu = peekLorentz(a, mu);
|
||||||
|
diva += amu - Cshift(amu, mu, -1);
|
||||||
|
if (mu == grid.Nd() - 2)
|
||||||
|
{
|
||||||
|
std::cout << GridLogMessage << "Spatial divergence norm 2 " << std::sqrt(norm2(diva)) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << GridLogMessage << "Total divergence norm 2 " << std::sqrt(norm2(diva)) << std::endl;
|
||||||
|
|
||||||
|
// Calculate Wilson loops
|
||||||
|
for(int iw=1; iw<=NWILSON; iw++){
|
||||||
|
wlA = WilsonLoops<QedPeriodicGImplR>::avgWilsonLoop(expA, iw, iw) * 3;
|
||||||
|
logWlAvg[iw-1] -= 2*log(wlA);
|
||||||
|
wlA = WilsonLoops<QedPeriodicGImplR>::avgTimelikeWilsonLoop(expA, iw, iw) * 3;
|
||||||
|
logWlTime[iw-1] -= 2*log(wlA);
|
||||||
|
wlA = WilsonLoops<QedPeriodicGImplR>::avgSpatialWilsonLoop(expA, iw, iw) * 3;
|
||||||
|
logWlSpace[iw-1] -= 2*log(wlA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << GridLogMessage << "Wilson loop calculation completed" << std::endl;
|
||||||
|
|
||||||
|
// Calculate Wilson loops
|
||||||
|
// From A. Portelli's PhD thesis:
|
||||||
|
// size -2*log(W)
|
||||||
|
// 1 0.500000000(1)
|
||||||
|
// 2 1.369311535(1)
|
||||||
|
// 3 2.305193057(1)
|
||||||
|
// 4 3.261483854(1)
|
||||||
|
// 5 4.228829967(1)
|
||||||
|
// 6 5.203604529(1)
|
||||||
|
// 7 6.183728249(1)
|
||||||
|
// 8 7.167859805(1)
|
||||||
|
// 9 8.155091868(1)
|
||||||
|
// 10 9.144788116(1)
|
||||||
|
|
||||||
|
for(int iw=1; iw<=10; iw++){
|
||||||
|
std::cout << GridLogMessage << iw << 'x' << iw << " Wilson loop" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "-2*log(W) average: " << logWlAvg[iw-1]/NCONFIGS << std::endl;
|
||||||
|
std::cout << GridLogMessage << "-2*log(W) timelike: " << logWlTime[iw-1]/NCONFIGS << std::endl;
|
||||||
|
std::cout << GridLogMessage << "-2*log(W) spatial: " << logWlSpace[iw-1]/NCONFIGS << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// epilogue
|
||||||
|
std::cout << GridLogMessage << "Grid is finalizing now" << std::endl;
|
||||||
|
Grid_finalize();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
104
tests/debug/Test_split_laplacian.cc
Normal file
104
tests/debug/Test_split_laplacian.cc
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/Test_dwf_mrhs_cg.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015
|
||||||
|
|
||||||
|
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
typedef LatticeComplex ComplexField;
|
||||||
|
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
int nd = latt_size.size();
|
||||||
|
int ndm1 = nd-1;
|
||||||
|
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
std::vector<int> mpi_split (mpi_layout.size(),1);
|
||||||
|
|
||||||
|
std::cout << " Full " << GridCmdVectorIntToString(latt_size) << " subgrid" <<std::endl;
|
||||||
|
std::cout << " Full " << GridCmdVectorIntToString(mpi_layout) << " sub communicator"<<std::endl;
|
||||||
|
std::cout << " Full " << GridCmdVectorIntToString(simd_layout)<< " simd layout " <<std::endl;
|
||||||
|
|
||||||
|
GridCartesian * GridN = new GridCartesian(latt_size,
|
||||||
|
simd_layout,
|
||||||
|
mpi_layout);
|
||||||
|
|
||||||
|
std::vector<int> latt_m = latt_size; latt_m[nd-1] = 1;
|
||||||
|
std::vector<int> mpi_m = mpi_layout; mpi_m [nd-1] = 1;
|
||||||
|
std::vector<int> simd_m = GridDefaultSimd(ndm1,vComplex::Nsimd()); simd_m.push_back(1);
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << " Requesting " << GridCmdVectorIntToString(latt_m)<< " subgrid" <<std::endl;
|
||||||
|
std::cout << " Requesting " << GridCmdVectorIntToString(mpi_m) << " sub communicator"<<std::endl;
|
||||||
|
std::cout << " Requesting " << GridCmdVectorIntToString(simd_m)<< " simd layout " <<std::endl;
|
||||||
|
GridCartesian * Grid_m = new GridCartesian(latt_m,
|
||||||
|
simd_m,
|
||||||
|
mpi_m,
|
||||||
|
*GridN);
|
||||||
|
|
||||||
|
Complex C(1.0);
|
||||||
|
Complex tmp;
|
||||||
|
|
||||||
|
ComplexField Full(GridN); Full = C;
|
||||||
|
ComplexField Full_cpy(GridN);
|
||||||
|
ComplexField Split(Grid_m);Split= C;
|
||||||
|
|
||||||
|
std::cout << GridLogMessage<< " Full volume "<< norm2(Full) <<std::endl;
|
||||||
|
std::cout << GridLogMessage<< " Split volume "<< norm2(Split) <<std::endl;
|
||||||
|
|
||||||
|
tmp=C;
|
||||||
|
GridN->GlobalSum(tmp);
|
||||||
|
std::cout << GridLogMessage<< " Full nodes "<< tmp <<std::endl;
|
||||||
|
|
||||||
|
tmp=C;
|
||||||
|
Grid_m->GlobalSum(tmp);
|
||||||
|
std::cout << GridLogMessage<< " Split nodes "<< tmp <<std::endl;
|
||||||
|
GridN->Barrier();
|
||||||
|
|
||||||
|
auto local_latt = GridN->LocalDimensions();
|
||||||
|
|
||||||
|
Full_cpy = zero;
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG RNG(GridN); RNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
random(RNG,Full);
|
||||||
|
for(int t=0;t<local_latt[nd-1];t++){
|
||||||
|
ExtractSliceLocal(Split,Full,0,t,Tp);
|
||||||
|
InsertSliceLocal (Split,Full_cpy,0,t,Tp);
|
||||||
|
}
|
||||||
|
Full_cpy = Full_cpy - Full;
|
||||||
|
std::cout << " NormFull " << norm2(Full)<<std::endl;
|
||||||
|
std::cout << " NormDiff " << norm2(Full_cpy)<<std::endl;
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
@ -72,6 +72,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// set fermion boundary conditions to be periodic space, antiperiodic time.
|
// set fermion boundary conditions to be periodic space, antiperiodic time.
|
||||||
std::string boundary = "1 1 1 -1";
|
std::string boundary = "1 1 1 -1";
|
||||||
|
std::string twist = "0. 0. 0. 0.";
|
||||||
|
|
||||||
//stochastic photon field
|
//stochastic photon field
|
||||||
MGauge::StochEm::Par photonPar;
|
MGauge::StochEm::Par photonPar;
|
||||||
@ -90,6 +91,7 @@ int main(int argc, char *argv[])
|
|||||||
actionPar.M5 = 1.8;
|
actionPar.M5 = 1.8;
|
||||||
actionPar.mass = mass[i];
|
actionPar.mass = mass[i];
|
||||||
actionPar.boundary = boundary;
|
actionPar.boundary = boundary;
|
||||||
|
actionPar.twist = "0. 0. 0. 0.";
|
||||||
application.createModule<MAction::DWF>("DWF_" + flavour[i], actionPar);
|
application.createModule<MAction::DWF>("DWF_" + flavour[i], actionPar);
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@ inline void makeWilsonAction(Application &application, std::string actionName,
|
|||||||
actionPar.gauge = gaugeField;
|
actionPar.gauge = gaugeField;
|
||||||
actionPar.mass = mass;
|
actionPar.mass = mass;
|
||||||
actionPar.boundary = boundary;
|
actionPar.boundary = boundary;
|
||||||
|
actionPar.twist = "0. 0. 0. 0.";
|
||||||
application.createModule<MAction::Wilson>(actionName, actionPar);
|
application.createModule<MAction::Wilson>(actionName, actionPar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,6 +155,7 @@ inline void makeDWFAction(Application &application, std::string actionName,
|
|||||||
actionPar.M5 = M5;
|
actionPar.M5 = M5;
|
||||||
actionPar.mass = mass;
|
actionPar.mass = mass;
|
||||||
actionPar.boundary = boundary;
|
actionPar.boundary = boundary;
|
||||||
|
actionPar.twist = "0. 0. 0. 0.";
|
||||||
application.createModule<MAction::DWF>(actionName, actionPar);
|
application.createModule<MAction::DWF>(actionName, actionPar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// set fermion boundary conditions to be periodic space, antiperiodic time.
|
// set fermion boundary conditions to be periodic space, antiperiodic time.
|
||||||
std::string boundary = "1 1 1 -1";
|
std::string boundary = "1 1 1 -1";
|
||||||
|
std::string twist = "0. 0. 0. 0.";
|
||||||
|
|
||||||
// sink
|
// sink
|
||||||
MSink::Point::Par sinkPar;
|
MSink::Point::Par sinkPar;
|
||||||
@ -80,6 +81,7 @@ int main(int argc, char *argv[])
|
|||||||
actionPar.M5 = 1.8;
|
actionPar.M5 = 1.8;
|
||||||
actionPar.mass = mass[i];
|
actionPar.mass = mass[i];
|
||||||
actionPar.boundary = boundary;
|
actionPar.boundary = boundary;
|
||||||
|
actionPar.twist = twist;
|
||||||
application.createModule<MAction::DWF>("DWF_" + flavour[i], actionPar);
|
application.createModule<MAction::DWF>("DWF_" + flavour[i], actionPar);
|
||||||
|
|
||||||
// solvers
|
// solvers
|
||||||
|
@ -72,6 +72,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// set fermion boundary conditions to be periodic space, antiperiodic time.
|
// set fermion boundary conditions to be periodic space, antiperiodic time.
|
||||||
std::string boundary = "1 1 1 -1";
|
std::string boundary = "1 1 1 -1";
|
||||||
|
std::string twist = "0. 0. 0. 0.";
|
||||||
|
|
||||||
for (unsigned int i = 0; i < flavour.size(); ++i)
|
for (unsigned int i = 0; i < flavour.size(); ++i)
|
||||||
{
|
{
|
||||||
@ -82,6 +83,7 @@ int main(int argc, char *argv[])
|
|||||||
actionPar.M5 = 1.8;
|
actionPar.M5 = 1.8;
|
||||||
actionPar.mass = mass[i];
|
actionPar.mass = mass[i];
|
||||||
actionPar.boundary = boundary;
|
actionPar.boundary = boundary;
|
||||||
|
actionPar.twist = twist;
|
||||||
application.createModule<MAction::DWF>("DWF_" + flavour[i], actionPar);
|
application.createModule<MAction::DWF>("DWF_" + flavour[i], actionPar);
|
||||||
|
|
||||||
// solvers
|
// solvers
|
||||||
|
670
tests/solver/Test_multigrid_common.h
Normal file
670
tests/solver/Test_multigrid_common.h
Normal file
@ -0,0 +1,670 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_multigrid_common.h
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#ifndef GRID_TEST_MULTIGRID_COMMON_H
|
||||||
|
#define GRID_TEST_MULTIGRID_COMMON_H
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
|
||||||
|
// TODO: Can think about having one parameter struct per level and then a
|
||||||
|
// vector of these structs. How well would that work together with the
|
||||||
|
// serialization strategy of Grid?
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
struct MultiGridParams : Serializable {
|
||||||
|
public:
|
||||||
|
GRID_SERIALIZABLE_CLASS_MEMBERS(MultiGridParams,
|
||||||
|
int, nLevels,
|
||||||
|
std::vector<std::vector<int>>, blockSizes, // size == nLevels - 1
|
||||||
|
std::vector<double>, smootherTol, // size == nLevels - 1
|
||||||
|
std::vector<int>, smootherMaxOuterIter, // size == nLevels - 1
|
||||||
|
std::vector<int>, smootherMaxInnerIter, // size == nLevels - 1
|
||||||
|
bool, kCycle,
|
||||||
|
std::vector<double>, kCycleTol, // size == nLevels - 1
|
||||||
|
std::vector<int>, kCycleMaxOuterIter, // size == nLevels - 1
|
||||||
|
std::vector<int>, kCycleMaxInnerIter, // size == nLevels - 1
|
||||||
|
double, coarseSolverTol,
|
||||||
|
int, coarseSolverMaxOuterIter,
|
||||||
|
int, coarseSolverMaxInnerIter);
|
||||||
|
|
||||||
|
// constructor with default values
|
||||||
|
MultiGridParams(int _nLevels = 2,
|
||||||
|
std::vector<std::vector<int>> _blockSizes = {{4, 4, 4, 4}},
|
||||||
|
std::vector<double> _smootherTol = {1e-14},
|
||||||
|
std::vector<int> _smootherMaxOuterIter = {4},
|
||||||
|
std::vector<int> _smootherMaxInnerIter = {4},
|
||||||
|
bool _kCycle = true,
|
||||||
|
std::vector<double> _kCycleTol = {1e-1},
|
||||||
|
std::vector<int> _kCycleMaxOuterIter = {2},
|
||||||
|
std::vector<int> _kCycleMaxInnerIter = {5},
|
||||||
|
double _coarseSolverTol = 5e-2,
|
||||||
|
int _coarseSolverMaxOuterIter = 10,
|
||||||
|
int _coarseSolverMaxInnerIter = 500)
|
||||||
|
: nLevels(_nLevels)
|
||||||
|
, blockSizes(_blockSizes)
|
||||||
|
, smootherTol(_smootherTol)
|
||||||
|
, smootherMaxOuterIter(_smootherMaxOuterIter)
|
||||||
|
, smootherMaxInnerIter(_smootherMaxInnerIter)
|
||||||
|
, kCycle(_kCycle)
|
||||||
|
, kCycleTol(_kCycleTol)
|
||||||
|
, kCycleMaxOuterIter(_kCycleMaxOuterIter)
|
||||||
|
, kCycleMaxInnerIter(_kCycleMaxInnerIter)
|
||||||
|
, coarseSolverTol(_coarseSolverTol)
|
||||||
|
, coarseSolverMaxOuterIter(_coarseSolverMaxOuterIter)
|
||||||
|
, coarseSolverMaxInnerIter(_coarseSolverMaxInnerIter)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
void checkParameterValidity(MultiGridParams const ¶ms) {
|
||||||
|
|
||||||
|
auto correctSize = params.nLevels - 1;
|
||||||
|
|
||||||
|
assert(correctSize == params.blockSizes.size());
|
||||||
|
assert(correctSize == params.smootherTol.size());
|
||||||
|
assert(correctSize == params.smootherMaxOuterIter.size());
|
||||||
|
assert(correctSize == params.smootherMaxInnerIter.size());
|
||||||
|
assert(correctSize == params.kCycleTol.size());
|
||||||
|
assert(correctSize == params.kCycleMaxOuterIter.size());
|
||||||
|
assert(correctSize == params.kCycleMaxInnerIter.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LevelInfo {
|
||||||
|
public:
|
||||||
|
std::vector<std::vector<int>> Seeds;
|
||||||
|
std::vector<GridCartesian *> Grids;
|
||||||
|
std::vector<GridParallelRNG> PRNGs;
|
||||||
|
|
||||||
|
LevelInfo(GridCartesian *FineGrid, MultiGridParams const &mgParams) {
|
||||||
|
|
||||||
|
auto nCoarseLevels = mgParams.blockSizes.size();
|
||||||
|
|
||||||
|
assert(nCoarseLevels == mgParams.nLevels - 1);
|
||||||
|
|
||||||
|
// set up values for finest grid
|
||||||
|
Grids.push_back(FineGrid);
|
||||||
|
Seeds.push_back({1, 2, 3, 4});
|
||||||
|
PRNGs.push_back(GridParallelRNG(Grids.back()));
|
||||||
|
PRNGs.back().SeedFixedIntegers(Seeds.back());
|
||||||
|
|
||||||
|
// set up values for coarser grids
|
||||||
|
for(int level = 1; level < mgParams.nLevels; ++level) {
|
||||||
|
auto Nd = Grids[level - 1]->_ndimension;
|
||||||
|
auto tmp = Grids[level - 1]->_fdimensions;
|
||||||
|
assert(tmp.size() == Nd);
|
||||||
|
|
||||||
|
Seeds.push_back(std::vector<int>(Nd));
|
||||||
|
|
||||||
|
for(int d = 0; d < Nd; ++d) {
|
||||||
|
tmp[d] /= mgParams.blockSizes[level - 1][d];
|
||||||
|
Seeds[level][d] = (level)*Nd + d + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grids.push_back(QCD::SpaceTimeGrid::makeFourDimGrid(tmp, Grids[level - 1]->_simd_layout, GridDefaultMpi()));
|
||||||
|
PRNGs.push_back(GridParallelRNG(Grids[level]));
|
||||||
|
|
||||||
|
PRNGs[level].SeedFixedIntegers(Seeds[level]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "Constructed " << mgParams.nLevels << " levels" << std::endl;
|
||||||
|
|
||||||
|
for(int level = 0; level < mgParams.nLevels; ++level) {
|
||||||
|
std::cout << GridLogMessage << "level = " << level << ":" << std::endl;
|
||||||
|
Grids[level]->show_decomposition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Field> class MultiGridPreconditionerBase : public LinearFunction<Field> {
|
||||||
|
public:
|
||||||
|
virtual ~MultiGridPreconditionerBase() = default;
|
||||||
|
virtual void setup() = 0;
|
||||||
|
virtual void operator()(Field const &in, Field &out) = 0;
|
||||||
|
virtual void runChecks(RealD tolerance) = 0;
|
||||||
|
virtual void reportTimings() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Fobj, class CComplex, int nBasis, int nCoarserLevels, class Matrix>
|
||||||
|
class MultiGridPreconditioner : public MultiGridPreconditionerBase<Lattice<Fobj>> {
|
||||||
|
public:
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Type Definitions
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
typedef Aggregation<Fobj, CComplex, nBasis> Aggregates;
|
||||||
|
typedef CoarsenedMatrix<Fobj, CComplex, nBasis> CoarseDiracMatrix;
|
||||||
|
typedef typename Aggregates::CoarseVector CoarseVector;
|
||||||
|
typedef typename Aggregates::siteVector CoarseSiteVector;
|
||||||
|
typedef Matrix FineDiracMatrix;
|
||||||
|
typedef typename Aggregates::FineField FineVector;
|
||||||
|
typedef MultiGridPreconditioner<CoarseSiteVector, iScalar<CComplex>, nBasis, nCoarserLevels - 1, CoarseDiracMatrix> NextPreconditionerLevel;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Member Data
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _CurrentLevel;
|
||||||
|
int _NextCoarserLevel;
|
||||||
|
|
||||||
|
MultiGridParams &_MultiGridParams;
|
||||||
|
LevelInfo & _LevelInfo;
|
||||||
|
|
||||||
|
FineDiracMatrix & _FineMatrix;
|
||||||
|
FineDiracMatrix & _SmootherMatrix;
|
||||||
|
Aggregates _Aggregates;
|
||||||
|
CoarseDiracMatrix _CoarseMatrix;
|
||||||
|
|
||||||
|
std::unique_ptr<NextPreconditionerLevel> _NextPreconditionerLevel;
|
||||||
|
|
||||||
|
GridStopWatch _SetupTotalTimer;
|
||||||
|
GridStopWatch _SetupCreateSubspaceTimer;
|
||||||
|
GridStopWatch _SetupProjectToChiralitiesTimer;
|
||||||
|
GridStopWatch _SetupCoarsenOperatorTimer;
|
||||||
|
GridStopWatch _SetupNextLevelTimer;
|
||||||
|
GridStopWatch _SolveTotalTimer;
|
||||||
|
GridStopWatch _SolveRestrictionTimer;
|
||||||
|
GridStopWatch _SolveProlongationTimer;
|
||||||
|
GridStopWatch _SolveSmootherTimer;
|
||||||
|
GridStopWatch _SolveNextLevelTimer;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Member Functions
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
MultiGridPreconditioner(MultiGridParams &mgParams, LevelInfo &LvlInfo, FineDiracMatrix &FineMat, FineDiracMatrix &SmootherMat)
|
||||||
|
: _CurrentLevel(mgParams.nLevels - (nCoarserLevels + 1)) // _Level = 0 corresponds to finest
|
||||||
|
, _NextCoarserLevel(_CurrentLevel + 1) // incremented for instances on coarser levels
|
||||||
|
, _MultiGridParams(mgParams)
|
||||||
|
, _LevelInfo(LvlInfo)
|
||||||
|
, _FineMatrix(FineMat)
|
||||||
|
, _SmootherMatrix(SmootherMat)
|
||||||
|
, _Aggregates(_LevelInfo.Grids[_NextCoarserLevel], _LevelInfo.Grids[_CurrentLevel], 0)
|
||||||
|
, _CoarseMatrix(*_LevelInfo.Grids[_NextCoarserLevel]) {
|
||||||
|
|
||||||
|
_NextPreconditionerLevel
|
||||||
|
= std::unique_ptr<NextPreconditionerLevel>(new NextPreconditionerLevel(_MultiGridParams, _LevelInfo, _CoarseMatrix, _CoarseMatrix));
|
||||||
|
|
||||||
|
resetTimers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
_SetupTotalTimer.Start();
|
||||||
|
|
||||||
|
static_assert((nBasis & 0x1) == 0, "MG Preconditioner only supports an even number of basis vectors");
|
||||||
|
int nb = nBasis / 2;
|
||||||
|
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineMdagMOp(_FineMatrix);
|
||||||
|
|
||||||
|
_SetupCreateSubspaceTimer.Start();
|
||||||
|
_Aggregates.CreateSubspace(_LevelInfo.PRNGs[_CurrentLevel], fineMdagMOp, nb);
|
||||||
|
_SetupCreateSubspaceTimer.Stop();
|
||||||
|
|
||||||
|
_SetupProjectToChiralitiesTimer.Start();
|
||||||
|
FineVector tmp1(_Aggregates.subspace[0]._grid);
|
||||||
|
FineVector tmp2(_Aggregates.subspace[0]._grid);
|
||||||
|
for(int n = 0; n < nb; n++) {
|
||||||
|
auto tmp1 = _Aggregates.subspace[n];
|
||||||
|
G5C(tmp2, _Aggregates.subspace[n]);
|
||||||
|
axpby(_Aggregates.subspace[n], 0.5, 0.5, tmp1, tmp2);
|
||||||
|
axpby(_Aggregates.subspace[n + nb], 0.5, -0.5, tmp1, tmp2);
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Chirally doubled vector " << n << ". "
|
||||||
|
<< "norm2(vec[" << n << "]) = " << norm2(_Aggregates.subspace[n]) << ". "
|
||||||
|
<< "norm2(vec[" << n + nb << "]) = " << norm2(_Aggregates.subspace[n + nb]) << std::endl;
|
||||||
|
}
|
||||||
|
_SetupProjectToChiralitiesTimer.Stop();
|
||||||
|
|
||||||
|
_SetupCoarsenOperatorTimer.Start();
|
||||||
|
_CoarseMatrix.CoarsenOperator(_LevelInfo.Grids[_CurrentLevel], fineMdagMOp, _Aggregates);
|
||||||
|
_SetupCoarsenOperatorTimer.Stop();
|
||||||
|
|
||||||
|
_SetupNextLevelTimer.Start();
|
||||||
|
_NextPreconditionerLevel->setup();
|
||||||
|
_SetupNextLevelTimer.Stop();
|
||||||
|
|
||||||
|
_SetupTotalTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(FineVector const &in, FineVector &out) {
|
||||||
|
|
||||||
|
conformable(_LevelInfo.Grids[_CurrentLevel], in._grid);
|
||||||
|
conformable(in, out);
|
||||||
|
|
||||||
|
// TODO: implement a W-cycle
|
||||||
|
if(_MultiGridParams.kCycle)
|
||||||
|
kCycle(in, out);
|
||||||
|
else
|
||||||
|
vCycle(in, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vCycle(FineVector const &in, FineVector &out) {
|
||||||
|
|
||||||
|
_SolveTotalTimer.Start();
|
||||||
|
|
||||||
|
RealD inputNorm = norm2(in);
|
||||||
|
|
||||||
|
CoarseVector coarseSrc(_LevelInfo.Grids[_NextCoarserLevel]);
|
||||||
|
CoarseVector coarseSol(_LevelInfo.Grids[_NextCoarserLevel]);
|
||||||
|
coarseSol = zero;
|
||||||
|
|
||||||
|
FineVector fineTmp(in._grid);
|
||||||
|
|
||||||
|
auto maxSmootherIter = _MultiGridParams.smootherMaxOuterIter[_CurrentLevel] * _MultiGridParams.smootherMaxInnerIter[_CurrentLevel];
|
||||||
|
|
||||||
|
TrivialPrecon<FineVector> fineTrivialPreconditioner;
|
||||||
|
FlexibleGeneralisedMinimalResidual<FineVector> fineFGMRES(_MultiGridParams.smootherTol[_CurrentLevel],
|
||||||
|
maxSmootherIter,
|
||||||
|
fineTrivialPreconditioner,
|
||||||
|
_MultiGridParams.smootherMaxInnerIter[_CurrentLevel],
|
||||||
|
false);
|
||||||
|
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineMdagMOp(_FineMatrix);
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineSmootherMdagMOp(_SmootherMatrix);
|
||||||
|
|
||||||
|
_SolveRestrictionTimer.Start();
|
||||||
|
_Aggregates.ProjectToSubspace(coarseSrc, in);
|
||||||
|
_SolveRestrictionTimer.Stop();
|
||||||
|
|
||||||
|
_SolveNextLevelTimer.Start();
|
||||||
|
(*_NextPreconditionerLevel)(coarseSrc, coarseSol);
|
||||||
|
_SolveNextLevelTimer.Stop();
|
||||||
|
|
||||||
|
_SolveProlongationTimer.Start();
|
||||||
|
_Aggregates.PromoteFromSubspace(coarseSol, out);
|
||||||
|
_SolveProlongationTimer.Stop();
|
||||||
|
|
||||||
|
fineMdagMOp.Op(out, fineTmp);
|
||||||
|
fineTmp = in - fineTmp;
|
||||||
|
auto r = norm2(fineTmp);
|
||||||
|
auto residualAfterCoarseGridCorrection = std::sqrt(r / inputNorm);
|
||||||
|
|
||||||
|
_SolveSmootherTimer.Start();
|
||||||
|
fineFGMRES(fineSmootherMdagMOp, in, out);
|
||||||
|
_SolveSmootherTimer.Stop();
|
||||||
|
|
||||||
|
fineMdagMOp.Op(out, fineTmp);
|
||||||
|
fineTmp = in - fineTmp;
|
||||||
|
r = norm2(fineTmp);
|
||||||
|
auto residualAfterPostSmoother = std::sqrt(r / inputNorm);
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": V-cycle: Input norm = " << std::sqrt(inputNorm)
|
||||||
|
<< " Coarse residual = " << residualAfterCoarseGridCorrection << " Post-Smoother residual = " << residualAfterPostSmoother
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
_SolveTotalTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void kCycle(FineVector const &in, FineVector &out) {
|
||||||
|
|
||||||
|
_SolveTotalTimer.Start();
|
||||||
|
|
||||||
|
RealD inputNorm = norm2(in);
|
||||||
|
|
||||||
|
CoarseVector coarseSrc(_LevelInfo.Grids[_NextCoarserLevel]);
|
||||||
|
CoarseVector coarseSol(_LevelInfo.Grids[_NextCoarserLevel]);
|
||||||
|
coarseSol = zero;
|
||||||
|
|
||||||
|
FineVector fineTmp(in._grid);
|
||||||
|
|
||||||
|
auto smootherMaxIter = _MultiGridParams.smootherMaxOuterIter[_CurrentLevel] * _MultiGridParams.smootherMaxInnerIter[_CurrentLevel];
|
||||||
|
auto kCycleMaxIter = _MultiGridParams.kCycleMaxOuterIter[_CurrentLevel] * _MultiGridParams.kCycleMaxInnerIter[_CurrentLevel];
|
||||||
|
|
||||||
|
TrivialPrecon<FineVector> fineTrivialPreconditioner;
|
||||||
|
FlexibleGeneralisedMinimalResidual<FineVector> fineFGMRES(_MultiGridParams.smootherTol[_CurrentLevel],
|
||||||
|
smootherMaxIter,
|
||||||
|
fineTrivialPreconditioner,
|
||||||
|
_MultiGridParams.smootherMaxInnerIter[_CurrentLevel],
|
||||||
|
false);
|
||||||
|
FlexibleGeneralisedMinimalResidual<CoarseVector> coarseFGMRES(_MultiGridParams.kCycleTol[_CurrentLevel],
|
||||||
|
kCycleMaxIter,
|
||||||
|
*_NextPreconditionerLevel,
|
||||||
|
_MultiGridParams.kCycleMaxInnerIter[_CurrentLevel],
|
||||||
|
false);
|
||||||
|
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineMdagMOp(_FineMatrix);
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineSmootherMdagMOp(_SmootherMatrix);
|
||||||
|
MdagMLinearOperator<CoarseDiracMatrix, CoarseVector> coarseMdagMOp(_CoarseMatrix);
|
||||||
|
|
||||||
|
_SolveRestrictionTimer.Start();
|
||||||
|
_Aggregates.ProjectToSubspace(coarseSrc, in);
|
||||||
|
_SolveRestrictionTimer.Stop();
|
||||||
|
|
||||||
|
_SolveNextLevelTimer.Start();
|
||||||
|
coarseFGMRES(coarseMdagMOp, coarseSrc, coarseSol);
|
||||||
|
_SolveNextLevelTimer.Stop();
|
||||||
|
|
||||||
|
_SolveProlongationTimer.Start();
|
||||||
|
_Aggregates.PromoteFromSubspace(coarseSol, out);
|
||||||
|
_SolveProlongationTimer.Stop();
|
||||||
|
|
||||||
|
fineMdagMOp.Op(out, fineTmp);
|
||||||
|
fineTmp = in - fineTmp;
|
||||||
|
auto r = norm2(fineTmp);
|
||||||
|
auto residualAfterCoarseGridCorrection = std::sqrt(r / inputNorm);
|
||||||
|
|
||||||
|
_SolveSmootherTimer.Start();
|
||||||
|
fineFGMRES(fineSmootherMdagMOp, in, out);
|
||||||
|
_SolveSmootherTimer.Stop();
|
||||||
|
|
||||||
|
fineMdagMOp.Op(out, fineTmp);
|
||||||
|
fineTmp = in - fineTmp;
|
||||||
|
r = norm2(fineTmp);
|
||||||
|
auto residualAfterPostSmoother = std::sqrt(r / inputNorm);
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": K-cycle: Input norm = " << std::sqrt(inputNorm)
|
||||||
|
<< " Coarse residual = " << residualAfterCoarseGridCorrection << " Post-Smoother residual = " << residualAfterPostSmoother
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
_SolveTotalTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void runChecks(RealD tolerance) {
|
||||||
|
|
||||||
|
std::vector<FineVector> fineTmps(7, _LevelInfo.Grids[_CurrentLevel]);
|
||||||
|
std::vector<CoarseVector> coarseTmps(4, _LevelInfo.Grids[_NextCoarserLevel]);
|
||||||
|
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineMdagMOp(_FineMatrix);
|
||||||
|
MdagMLinearOperator<CoarseDiracMatrix, CoarseVector> coarseMdagMOp(_CoarseMatrix);
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": MG correctness check: 0 == (M - (Mdiag + Σ_μ Mdir_μ)) * v" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
|
||||||
|
random(_LevelInfo.PRNGs[_CurrentLevel], fineTmps[0]);
|
||||||
|
|
||||||
|
fineMdagMOp.Op(fineTmps[0], fineTmps[1]); // M * v
|
||||||
|
fineMdagMOp.OpDiag(fineTmps[0], fineTmps[2]); // Mdiag * v
|
||||||
|
|
||||||
|
fineTmps[4] = zero;
|
||||||
|
for(int dir = 0; dir < 4; dir++) { // Σ_μ Mdir_μ * v
|
||||||
|
for(auto disp : {+1, -1}) {
|
||||||
|
fineMdagMOp.OpDir(fineTmps[0], fineTmps[3], dir, disp);
|
||||||
|
fineTmps[4] = fineTmps[4] + fineTmps[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fineTmps[5] = fineTmps[2] + fineTmps[4]; // (Mdiag + Σ_μ Mdir_μ) * v
|
||||||
|
|
||||||
|
fineTmps[6] = fineTmps[1] - fineTmps[5];
|
||||||
|
auto deviation = std::sqrt(norm2(fineTmps[6]) / norm2(fineTmps[1]));
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": norm2(M * v) = " << norm2(fineTmps[1]) << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": norm2(Mdiag * v) = " << norm2(fineTmps[2]) << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": norm2(Σ_μ Mdir_μ * v) = " << norm2(fineTmps[4]) << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": norm2((Mdiag + Σ_μ Mdir_μ) * v) = " << norm2(fineTmps[5]) << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": relative deviation = " << deviation;
|
||||||
|
|
||||||
|
if(deviation > tolerance) {
|
||||||
|
std::cout << " > " << tolerance << " -> check failed" << std::endl;
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
std::cout << " < " << tolerance << " -> check passed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": MG correctness check: 0 == (1 - P R) v" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
|
||||||
|
for(auto i = 0; i < _Aggregates.subspace.size(); ++i) {
|
||||||
|
_Aggregates.ProjectToSubspace(coarseTmps[0], _Aggregates.subspace[i]); // R v_i
|
||||||
|
_Aggregates.PromoteFromSubspace(coarseTmps[0], fineTmps[0]); // P R v_i
|
||||||
|
|
||||||
|
fineTmps[1] = _Aggregates.subspace[i] - fineTmps[0]; // v_i - P R v_i
|
||||||
|
deviation = std::sqrt(norm2(fineTmps[1]) / norm2(_Aggregates.subspace[i]));
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Vector " << i << ": norm2(v_i) = " << norm2(_Aggregates.subspace[i])
|
||||||
|
<< " | norm2(R v_i) = " << norm2(coarseTmps[0]) << " | norm2(P R v_i) = " << norm2(fineTmps[0])
|
||||||
|
<< " | relative deviation = " << deviation;
|
||||||
|
|
||||||
|
if(deviation > tolerance) {
|
||||||
|
std::cout << " > " << tolerance << " -> check failed" << std::endl;
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
std::cout << " < " << tolerance << " -> check passed" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": MG correctness check: 0 == (1 - R P) v_c" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
|
||||||
|
random(_LevelInfo.PRNGs[_NextCoarserLevel], coarseTmps[0]);
|
||||||
|
|
||||||
|
_Aggregates.PromoteFromSubspace(coarseTmps[0], fineTmps[0]); // P v_c
|
||||||
|
_Aggregates.ProjectToSubspace(coarseTmps[1], fineTmps[0]); // R P v_c
|
||||||
|
|
||||||
|
coarseTmps[2] = coarseTmps[0] - coarseTmps[1]; // v_c - R P v_c
|
||||||
|
deviation = std::sqrt(norm2(coarseTmps[2]) / norm2(coarseTmps[0]));
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": norm2(v_c) = " << norm2(coarseTmps[0])
|
||||||
|
<< " | norm2(R P v_c) = " << norm2(coarseTmps[1]) << " | norm2(P v_c) = " << norm2(fineTmps[0])
|
||||||
|
<< " | relative deviation = " << deviation;
|
||||||
|
|
||||||
|
if(deviation > tolerance) {
|
||||||
|
std::cout << " > " << tolerance << " -> check failed" << std::endl;
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
std::cout << " < " << tolerance << " -> check passed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": MG correctness check: 0 == (R D P - D_c) v_c" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
|
||||||
|
random(_LevelInfo.PRNGs[_NextCoarserLevel], coarseTmps[0]);
|
||||||
|
|
||||||
|
_Aggregates.PromoteFromSubspace(coarseTmps[0], fineTmps[0]); // P v_c
|
||||||
|
fineMdagMOp.Op(fineTmps[0], fineTmps[1]); // D P v_c
|
||||||
|
_Aggregates.ProjectToSubspace(coarseTmps[1], fineTmps[1]); // R D P v_c
|
||||||
|
|
||||||
|
coarseMdagMOp.Op(coarseTmps[0], coarseTmps[2]); // D_c v_c
|
||||||
|
|
||||||
|
coarseTmps[3] = coarseTmps[1] - coarseTmps[2]; // R D P v_c - D_c v_c
|
||||||
|
deviation = std::sqrt(norm2(coarseTmps[3]) / norm2(coarseTmps[1]));
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": norm2(R D P v_c) = " << norm2(coarseTmps[1])
|
||||||
|
<< " | norm2(D_c v_c) = " << norm2(coarseTmps[2]) << " | relative deviation = " << deviation;
|
||||||
|
|
||||||
|
if(deviation > tolerance) {
|
||||||
|
std::cout << " > " << tolerance << " -> check failed" << std::endl;
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
std::cout << " < " << tolerance << " -> check passed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": MG correctness check: 0 == |(Im(v_c^dag D_c^dag D_c v_c)|" << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": **************************************************" << std::endl;
|
||||||
|
|
||||||
|
random(_LevelInfo.PRNGs[_NextCoarserLevel], coarseTmps[0]);
|
||||||
|
|
||||||
|
coarseMdagMOp.Op(coarseTmps[0], coarseTmps[1]); // D_c v_c
|
||||||
|
coarseMdagMOp.AdjOp(coarseTmps[1], coarseTmps[2]); // D_c^dag D_c v_c
|
||||||
|
|
||||||
|
auto dot = innerProduct(coarseTmps[0], coarseTmps[2]); //v_c^dag D_c^dag D_c v_c
|
||||||
|
deviation = std::abs(imag(dot)) / std::abs(real(dot));
|
||||||
|
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Re(v_c^dag D_c^dag D_c v_c) = " << real(dot)
|
||||||
|
<< " | Im(v_c^dag D_c^dag D_c v_c) = " << imag(dot) << " | relative deviation = " << deviation;
|
||||||
|
|
||||||
|
if(deviation > tolerance) {
|
||||||
|
std::cout << " > " << tolerance << " -> check failed" << std::endl;
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
std::cout << " < " << tolerance << " -> check passed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NextPreconditionerLevel->runChecks(tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reportTimings() {
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Sum total " << _SetupTotalTimer.Elapsed() + _SolveTotalTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Setup total " << _SetupTotalTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Setup create subspace " << _SetupCreateSubspaceTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Setup project chiral " << _SetupProjectToChiralitiesTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Setup coarsen operator " << _SetupCoarsenOperatorTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Setup next level " << _SetupNextLevelTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve total " << _SolveTotalTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve restriction " << _SolveRestrictionTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve prolongation " << _SolveProlongationTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve smoother " << _SolveSmootherTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve next level " << _SolveNextLevelTimer.Elapsed() << std::endl;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
_NextPreconditionerLevel->reportTimings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetTimers() {
|
||||||
|
|
||||||
|
_SetupTotalTimer.Reset();
|
||||||
|
_SetupCreateSubspaceTimer.Reset();
|
||||||
|
_SetupProjectToChiralitiesTimer.Reset();
|
||||||
|
_SetupCoarsenOperatorTimer.Reset();
|
||||||
|
_SetupNextLevelTimer.Reset();
|
||||||
|
_SolveTotalTimer.Reset();
|
||||||
|
_SolveRestrictionTimer.Reset();
|
||||||
|
_SolveProlongationTimer.Reset();
|
||||||
|
_SolveSmootherTimer.Reset();
|
||||||
|
_SolveNextLevelTimer.Reset();
|
||||||
|
|
||||||
|
_NextPreconditionerLevel->resetTimers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for the coarsest level
|
||||||
|
template<class Fobj, class CComplex, int nBasis, class Matrix>
|
||||||
|
class MultiGridPreconditioner<Fobj, CComplex, nBasis, 0, Matrix> : public MultiGridPreconditionerBase<Lattice<Fobj>> {
|
||||||
|
public:
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Type Definitions
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef Matrix FineDiracMatrix;
|
||||||
|
typedef Lattice<Fobj> FineVector;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Member Data
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _CurrentLevel;
|
||||||
|
|
||||||
|
MultiGridParams &_MultiGridParams;
|
||||||
|
LevelInfo & _LevelInfo;
|
||||||
|
|
||||||
|
FineDiracMatrix &_FineMatrix;
|
||||||
|
FineDiracMatrix &_SmootherMatrix;
|
||||||
|
|
||||||
|
GridStopWatch _SolveTotalTimer;
|
||||||
|
GridStopWatch _SolveSmootherTimer;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Member Functions
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
MultiGridPreconditioner(MultiGridParams &mgParams, LevelInfo &LvlInfo, FineDiracMatrix &FineMat, FineDiracMatrix &SmootherMat)
|
||||||
|
: _CurrentLevel(mgParams.nLevels - (0 + 1))
|
||||||
|
, _MultiGridParams(mgParams)
|
||||||
|
, _LevelInfo(LvlInfo)
|
||||||
|
, _FineMatrix(FineMat)
|
||||||
|
, _SmootherMatrix(SmootherMat) {
|
||||||
|
|
||||||
|
resetTimers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {}
|
||||||
|
|
||||||
|
virtual void operator()(FineVector const &in, FineVector &out) {
|
||||||
|
|
||||||
|
_SolveTotalTimer.Start();
|
||||||
|
|
||||||
|
conformable(_LevelInfo.Grids[_CurrentLevel], in._grid);
|
||||||
|
conformable(in, out);
|
||||||
|
|
||||||
|
auto coarseSolverMaxIter = _MultiGridParams.coarseSolverMaxOuterIter * _MultiGridParams.coarseSolverMaxInnerIter;
|
||||||
|
|
||||||
|
// On the coarsest level we only have what I above call the fine level, no coarse one
|
||||||
|
TrivialPrecon<FineVector> fineTrivialPreconditioner;
|
||||||
|
FlexibleGeneralisedMinimalResidual<FineVector> fineFGMRES(
|
||||||
|
_MultiGridParams.coarseSolverTol, coarseSolverMaxIter, fineTrivialPreconditioner, _MultiGridParams.coarseSolverMaxInnerIter, false);
|
||||||
|
|
||||||
|
MdagMLinearOperator<FineDiracMatrix, FineVector> fineMdagMOp(_FineMatrix);
|
||||||
|
|
||||||
|
_SolveSmootherTimer.Start();
|
||||||
|
fineFGMRES(fineMdagMOp, in, out);
|
||||||
|
_SolveSmootherTimer.Stop();
|
||||||
|
|
||||||
|
_SolveTotalTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void runChecks(RealD tolerance) {}
|
||||||
|
|
||||||
|
void reportTimings() {
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve total " << _SolveTotalTimer.Elapsed() << std::endl;
|
||||||
|
std::cout << GridLogMG << " Level " << _CurrentLevel << ": Time elapsed: Solve smoother " << _SolveSmootherTimer.Elapsed() << std::endl;
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetTimers() {
|
||||||
|
|
||||||
|
_SolveTotalTimer.Reset();
|
||||||
|
_SolveSmootherTimer.Reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Fobj, class CComplex, int nBasis, int nLevels, class Matrix>
|
||||||
|
using NLevelMGPreconditioner = MultiGridPreconditioner<Fobj, CComplex, nBasis, nLevels - 1, Matrix>;
|
||||||
|
|
||||||
|
template<class Fobj, class CComplex, int nBasis, class Matrix>
|
||||||
|
std::unique_ptr<MultiGridPreconditionerBase<Lattice<Fobj>>>
|
||||||
|
createMGInstance(MultiGridParams &mgParams, LevelInfo &levelInfo, Matrix &FineMat, Matrix &SmootherMat) {
|
||||||
|
|
||||||
|
#define CASE_FOR_N_LEVELS(nLevels) \
|
||||||
|
case nLevels: \
|
||||||
|
return std::unique_ptr<NLevelMGPreconditioner<Fobj, CComplex, nBasis, nLevels, Matrix>>( \
|
||||||
|
new NLevelMGPreconditioner<Fobj, CComplex, nBasis, nLevels, Matrix>(mgParams, levelInfo, FineMat, SmootherMat)); \
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch(mgParams.nLevels) {
|
||||||
|
CASE_FOR_N_LEVELS(2);
|
||||||
|
CASE_FOR_N_LEVELS(3);
|
||||||
|
CASE_FOR_N_LEVELS(4);
|
||||||
|
default:
|
||||||
|
std::cout << GridLogError << "We currently only support nLevels ∈ {2, 3, 4}" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef CASE_FOR_N_LEVELS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
72
tests/solver/Test_staggered_cagmres_unprec.cc
Normal file
72
tests/solver/Test_staggered_cagmres_unprec.cc
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_staggered_cagmres_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
typedef typename ImprovedStaggeredFermionR::FermionField FermionField;
|
||||||
|
typedef typename ImprovedStaggeredFermionR::ComplexField ComplexField;
|
||||||
|
typename ImprovedStaggeredFermionR::ImplParams params;
|
||||||
|
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
RealD c1=9.0/8.0;
|
||||||
|
RealD c2=-1.0/24.0;
|
||||||
|
RealD u0=1.0;
|
||||||
|
ImprovedStaggeredFermionR Ds(Umu,Umu,Grid,RBGrid,mass,c1,c2,u0);
|
||||||
|
|
||||||
|
MdagMLinearOperator<ImprovedStaggeredFermionR,FermionField> HermOp(Ds);
|
||||||
|
CommunicationAvoidingGeneralisedMinimalResidual<FermionField> CAGMRES(1.0e-8, 10000, 25);
|
||||||
|
CAGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
75
tests/solver/Test_staggered_fcagmres_prec.cc
Normal file
75
tests/solver/Test_staggered_fcagmres_prec.cc
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_staggered_fcagmres_prec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
typedef typename ImprovedStaggeredFermionR::FermionField FermionField;
|
||||||
|
typedef typename ImprovedStaggeredFermionR::ComplexField ComplexField;
|
||||||
|
typename ImprovedStaggeredFermionR::ImplParams params;
|
||||||
|
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
RealD c1=9.0/8.0;
|
||||||
|
RealD c2=-1.0/24.0;
|
||||||
|
RealD u0=1.0;
|
||||||
|
ImprovedStaggeredFermionR Ds(Umu,Umu,Grid,RBGrid,mass,c1,c2,u0);
|
||||||
|
|
||||||
|
MdagMLinearOperator<ImprovedStaggeredFermionR,FermionField> HermOp(Ds);
|
||||||
|
|
||||||
|
TrivialPrecon<FermionField> simple;
|
||||||
|
|
||||||
|
FlexibleCommunicationAvoidingGeneralisedMinimalResidual<FermionField> FCAGMRES(1.0e-8, 10000, simple, 25);
|
||||||
|
FCAGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
75
tests/solver/Test_staggered_fgmres_prec.cc
Normal file
75
tests/solver/Test_staggered_fgmres_prec.cc
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_staggered_fgmres_prec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
typedef typename ImprovedStaggeredFermionR::FermionField FermionField;
|
||||||
|
typedef typename ImprovedStaggeredFermionR::ComplexField ComplexField;
|
||||||
|
typename ImprovedStaggeredFermionR::ImplParams params;
|
||||||
|
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
RealD c1=9.0/8.0;
|
||||||
|
RealD c2=-1.0/24.0;
|
||||||
|
RealD u0=1.0;
|
||||||
|
ImprovedStaggeredFermionR Ds(Umu,Umu,Grid,RBGrid,mass,c1,c2,u0);
|
||||||
|
|
||||||
|
MdagMLinearOperator<ImprovedStaggeredFermionR,FermionField> HermOp(Ds);
|
||||||
|
|
||||||
|
TrivialPrecon<FermionField> simple;
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual<FermionField> FGMRES(1.0e-8, 10000, simple, 25);
|
||||||
|
FGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
72
tests/solver/Test_staggered_gmres_unprec.cc
Normal file
72
tests/solver/Test_staggered_gmres_unprec.cc
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_staggered_gmres_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
typedef typename ImprovedStaggeredFermionR::FermionField FermionField;
|
||||||
|
typedef typename ImprovedStaggeredFermionR::ComplexField ComplexField;
|
||||||
|
typename ImprovedStaggeredFermionR::ImplParams params;
|
||||||
|
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
RealD c1=9.0/8.0;
|
||||||
|
RealD c2=-1.0/24.0;
|
||||||
|
RealD u0=1.0;
|
||||||
|
ImprovedStaggeredFermionR Ds(Umu,Umu,Grid,RBGrid,mass,c1,c2,u0);
|
||||||
|
|
||||||
|
MdagMLinearOperator<ImprovedStaggeredFermionR,FermionField> HermOp(Ds);
|
||||||
|
GeneralisedMinimalResidual<FermionField> GMRES(1.0e-8, 10000, 25);
|
||||||
|
GMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
72
tests/solver/Test_staggered_mr_unprec.cc
Normal file
72
tests/solver/Test_staggered_mr_unprec.cc
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_staggered_mr_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
typedef typename ImprovedStaggeredFermionR::FermionField FermionField;
|
||||||
|
typedef typename ImprovedStaggeredFermionR::ComplexField ComplexField;
|
||||||
|
typename ImprovedStaggeredFermionR::ImplParams params;
|
||||||
|
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
RealD c1=9.0/8.0;
|
||||||
|
RealD c2=-1.0/24.0;
|
||||||
|
RealD u0=1.0;
|
||||||
|
ImprovedStaggeredFermionR Ds(Umu,Umu,Grid,RBGrid,mass,c1,c2,u0);
|
||||||
|
|
||||||
|
MdagMLinearOperator<ImprovedStaggeredFermionR,FermionField> HermOp(Ds);
|
||||||
|
MinimalResidual<FermionField> MR(1.0e-8,10000,0.8);
|
||||||
|
MR(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
65
tests/solver/Test_wilson_cagmres_unprec.cc
Normal file
65
tests/solver/Test_wilson_cagmres_unprec.cc
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_cagmres_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
LatticeFermion src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
LatticeFermion result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
WilsonFermionR Dw(Umu,Grid,RBGrid,mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionR,LatticeFermion> HermOp(Dw);
|
||||||
|
CommunicationAvoidingGeneralisedMinimalResidual<LatticeFermion> CAGMRES(1.0e-8, 10000, 25);
|
||||||
|
CAGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
68
tests/solver/Test_wilson_fcagmres_prec.cc
Normal file
68
tests/solver/Test_wilson_fcagmres_prec.cc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_fcagmres_prec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
LatticeFermion src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
LatticeFermion result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
WilsonFermionR Dw(Umu,Grid,RBGrid,mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionR,LatticeFermion> HermOp(Dw);
|
||||||
|
|
||||||
|
TrivialPrecon<LatticeFermion> simple;
|
||||||
|
|
||||||
|
FlexibleCommunicationAvoidingGeneralisedMinimalResidual<LatticeFermion> FCAGMRES(1.0e-8, 10000, simple, 25);
|
||||||
|
FCAGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
68
tests/solver/Test_wilson_fgmres_prec.cc
Normal file
68
tests/solver/Test_wilson_fgmres_prec.cc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_fgmres_prec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
LatticeFermion src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
LatticeFermion result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
WilsonFermionR Dw(Umu,Grid,RBGrid,mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionR,LatticeFermion> HermOp(Dw);
|
||||||
|
|
||||||
|
TrivialPrecon<LatticeFermion> simple;
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual<LatticeFermion> FGMRES(1.0e-8, 10000, simple, 25);
|
||||||
|
FGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
65
tests/solver/Test_wilson_gmres_unprec.cc
Normal file
65
tests/solver/Test_wilson_gmres_unprec.cc
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_gmres_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
LatticeFermion src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
LatticeFermion result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
WilsonFermionR Dw(Umu,Grid,RBGrid,mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionR,LatticeFermion> HermOp(Dw);
|
||||||
|
GeneralisedMinimalResidual<LatticeFermion> GMRES(1.0e-8, 10000, 25);
|
||||||
|
GMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
114
tests/solver/Test_wilson_mg.cc
Normal file
114
tests/solver/Test_wilson_mg.cc
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_mg.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
#include <Test_multigrid_common.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
|
||||||
|
GridCartesian * FGrid = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *FrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(FGrid);
|
||||||
|
|
||||||
|
std::vector<int> fSeeds({1, 2, 3, 4});
|
||||||
|
GridParallelRNG fPRNG(FGrid);
|
||||||
|
fPRNG.SeedFixedIntegers(fSeeds);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
LatticeFermion src(FGrid); gaussian(fPRNG, src);
|
||||||
|
LatticeFermion result(FGrid); result = zero;
|
||||||
|
LatticeGaugeField Umu(FGrid); SU3::HotConfiguration(fPRNG, Umu);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RealD mass = -0.25;
|
||||||
|
|
||||||
|
MultiGridParams mgParams;
|
||||||
|
std::string inputXml{"./mg_params.xml"};
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--inputxml")) {
|
||||||
|
inputXml = GridCmdOptionPayload(argv, argv + argc, "--inputxml");
|
||||||
|
assert(inputXml.length() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
XmlWriter writer("mg_params_template.xml");
|
||||||
|
write(writer, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Written mg_params_template.xml" << std::endl;
|
||||||
|
|
||||||
|
XmlReader reader(inputXml);
|
||||||
|
read(reader, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Read in " << inputXml << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkParameterValidity(mgParams);
|
||||||
|
std::cout << mgParams << std::endl;
|
||||||
|
|
||||||
|
LevelInfo levelInfo(FGrid, mgParams);
|
||||||
|
|
||||||
|
// Note: We do chiral doubling, so actually only nbasis/2 full basis vectors are used
|
||||||
|
const int nbasis = 40;
|
||||||
|
|
||||||
|
WilsonFermionR Dw(Umu, *FGrid, *FrbGrid, mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionR, LatticeFermion> MdagMOpDw(Dw);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Testing Multigrid for Wilson" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
TrivialPrecon<LatticeFermion> TrivialPrecon;
|
||||||
|
auto MGPreconDw = createMGInstance<vSpinColourVector, vTComplex, nbasis, WilsonFermionR>(mgParams, levelInfo, Dw, Dw);
|
||||||
|
|
||||||
|
MGPreconDw->setup();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--runchecks")) {
|
||||||
|
RealD toleranceForMGChecks = (getPrecision<LatticeFermion>::value == 1) ? 1e-6 : 1e-13;
|
||||||
|
MGPreconDw->runChecks(toleranceForMGChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<OperatorFunction<LatticeFermion>>> solversDw;
|
||||||
|
|
||||||
|
solversDw.emplace_back(new ConjugateGradient<LatticeFermion>(1.0e-12, 50000, false));
|
||||||
|
solversDw.emplace_back(new FlexibleGeneralisedMinimalResidual<LatticeFermion>(1.0e-12, 50000, TrivialPrecon, 100, false));
|
||||||
|
solversDw.emplace_back(new FlexibleGeneralisedMinimalResidual<LatticeFermion>(1.0e-12, 50000, *MGPreconDw, 100, false));
|
||||||
|
|
||||||
|
for(auto const &solver : solversDw) {
|
||||||
|
std::cout << std::endl << "Starting with a new solver" << std::endl;
|
||||||
|
result = zero;
|
||||||
|
(*solver)(MdagMOpDw, src, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MGPreconDw->reportTimings();
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
166
tests/solver/Test_wilson_mg_mp.cc
Normal file
166
tests/solver/Test_wilson_mg_mp.cc
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_mg_mp.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
#include <Test_multigrid_common.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
GridCartesian *FGrid_d = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexD::Nsimd()), GridDefaultMpi());
|
||||||
|
GridCartesian *FGrid_f = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *FrbGrid_d = SpaceTimeGrid::makeFourDimRedBlackGrid(FGrid_d);
|
||||||
|
GridRedBlackCartesian *FrbGrid_f = SpaceTimeGrid::makeFourDimRedBlackGrid(FGrid_f);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
std::vector<int> fSeeds({1, 2, 3, 4});
|
||||||
|
GridParallelRNG fPRNG(FGrid_d);
|
||||||
|
fPRNG.SeedFixedIntegers(fSeeds);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
LatticeFermionD src_d(FGrid_d); gaussian(fPRNG, src_d);
|
||||||
|
LatticeFermionD resultMGD_d(FGrid_d); resultMGD_d = zero;
|
||||||
|
LatticeFermionD resultMGF_d(FGrid_d); resultMGF_d = zero;
|
||||||
|
LatticeGaugeFieldD Umu_d(FGrid_d); SU3::HotConfiguration(fPRNG, Umu_d);
|
||||||
|
LatticeGaugeFieldF Umu_f(FGrid_f); precisionChange(Umu_f, Umu_d);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RealD mass = -0.25;
|
||||||
|
|
||||||
|
MultiGridParams mgParams;
|
||||||
|
std::string inputXml{"./mg_params.xml"};
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--inputxml")) {
|
||||||
|
inputXml = GridCmdOptionPayload(argv, argv + argc, "--inputxml");
|
||||||
|
assert(inputXml.length() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
XmlWriter writer("mg_params_template.xml");
|
||||||
|
write(writer, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Written mg_params_template.xml" << std::endl;
|
||||||
|
|
||||||
|
XmlReader reader(inputXml);
|
||||||
|
read(reader, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Read in " << inputXml << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkParameterValidity(mgParams);
|
||||||
|
std::cout << mgParams << std::endl;
|
||||||
|
|
||||||
|
LevelInfo levelInfo_d(FGrid_d, mgParams);
|
||||||
|
LevelInfo levelInfo_f(FGrid_f, mgParams);
|
||||||
|
|
||||||
|
// Note: We do chiral doubling, so actually only nbasis/2 full basis vectors are used
|
||||||
|
const int nbasis = 40;
|
||||||
|
|
||||||
|
WilsonFermionD Dw_d(Umu_d, *FGrid_d, *FrbGrid_d, mass);
|
||||||
|
WilsonFermionF Dw_f(Umu_f, *FGrid_f, *FrbGrid_f, mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionD, LatticeFermionD> MdagMOpDw_d(Dw_d);
|
||||||
|
MdagMLinearOperator<WilsonFermionF, LatticeFermionF> MdagMOpDw_f(Dw_f);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Testing single-precision Multigrid for Wilson" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
auto MGPreconDw_f = createMGInstance<vSpinColourVectorF, vTComplexF, nbasis, WilsonFermionF>(mgParams, levelInfo_f, Dw_f, Dw_f);
|
||||||
|
|
||||||
|
MGPreconDw_f->setup();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--runchecks")) {
|
||||||
|
MGPreconDw_f->runChecks(1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
MixedPrecisionFlexibleGeneralisedMinimalResidual<LatticeFermionD, LatticeFermionF> MPFGMRESPREC(1.0e-12, 50000, FGrid_f, *MGPreconDw_f, 100, false);
|
||||||
|
|
||||||
|
std::cout << std::endl << "Starting with a new solver" << std::endl;
|
||||||
|
MPFGMRESPREC(MdagMOpDw_d, src_d, resultMGF_d);
|
||||||
|
|
||||||
|
MGPreconDw_f->reportTimings();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--docomparison")) {
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Testing double-precision Multigrid for Wilson" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
auto MGPreconDw_d = createMGInstance<vSpinColourVectorD, vTComplexD, nbasis, WilsonFermionD>(mgParams, levelInfo_d, Dw_d, Dw_d);
|
||||||
|
|
||||||
|
MGPreconDw_d->setup();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--runchecks")) {
|
||||||
|
MGPreconDw_d->runChecks(1e-13);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual<LatticeFermionD> FGMRESPREC(1.0e-12, 50000, *MGPreconDw_d, 100, false);
|
||||||
|
|
||||||
|
std::cout << std::endl << "Starting with a new solver" << std::endl;
|
||||||
|
FGMRESPREC(MdagMOpDw_d, src_d, resultMGD_d);
|
||||||
|
|
||||||
|
MGPreconDw_d->reportTimings();
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Comparing single-precision Multigrid with double-precision one for Wilson" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
LatticeFermionD diffFullSolver(FGrid_d);
|
||||||
|
|
||||||
|
RealD deviationFullSolver = axpy_norm(diffFullSolver, -1.0, resultMGF_d, resultMGD_d);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
LatticeFermionF src_f(FGrid_f); precisionChange(src_f, src_d);
|
||||||
|
LatticeFermionF resMGF_f(FGrid_f); resMGF_f = zero;
|
||||||
|
LatticeFermionD resMGD_d(FGrid_d); resMGD_d = zero;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
(*MGPreconDw_f)(src_f, resMGF_f);
|
||||||
|
(*MGPreconDw_d)(src_d, resMGD_d);
|
||||||
|
|
||||||
|
LatticeFermionD diffOnlyMG(FGrid_d);
|
||||||
|
LatticeFermionD resMGF_d(FGrid_d);
|
||||||
|
precisionChange(resMGF_d, resMGF_f);
|
||||||
|
|
||||||
|
RealD deviationOnlyPrec = axpy_norm(diffOnlyMG, -1.0, resMGF_d, resMGD_d);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
std::cout << GridLogMessage << "Absolute difference between FGMRES preconditioned by double and single precicision MG: " << deviationFullSolver << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Relative deviation between FGMRES preconditioned by double and single precicision MG: " << deviationFullSolver / norm2(resultMGD_d) << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Absolute difference between one iteration of MG Prec in double and single precision: " << deviationOnlyPrec << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Relative deviation between one iteration of MG Prec in double and single precision: " << deviationOnlyPrec / norm2(resMGD_d) << std::endl;
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
65
tests/solver/Test_wilson_mr_unprec.cc
Normal file
65
tests/solver/Test_wilson_mr_unprec.cc
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilson_mr_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
LatticeFermion src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
LatticeFermion result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass=0.5;
|
||||||
|
WilsonFermionR Dw(Umu,Grid,RBGrid,mass);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonFermionR,LatticeFermion> HermOp(Dw);
|
||||||
|
MinimalResidual<LatticeFermion> MR(1.0e-8,10000,0.8);
|
||||||
|
MR(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
71
tests/solver/Test_wilsonclover_cagmres_unprec.cc
Normal file
71
tests/solver/Test_wilsonclover_cagmres_unprec.cc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_cagmres_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
typedef typename WilsonCloverFermionR::FermionField FermionField;
|
||||||
|
typename WilsonCloverFermionR::ImplParams params;
|
||||||
|
WilsonAnisotropyCoefficients anis;
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass = 0.5;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
WilsonCloverFermionR Dwc(Umu,Grid,RBGrid,mass,csw_r,csw_t,anis,params);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionR,FermionField> HermOp(Dwc);
|
||||||
|
CommunicationAvoidingGeneralisedMinimalResidual<FermionField> CAGMRES(1.0e-8, 10000, 25);
|
||||||
|
CAGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
74
tests/solver/Test_wilsonclover_fcagmres_prec.cc
Normal file
74
tests/solver/Test_wilsonclover_fcagmres_prec.cc
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_fcagmres_prec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
typedef typename WilsonCloverFermionR::FermionField FermionField;
|
||||||
|
typename WilsonCloverFermionR::ImplParams params;
|
||||||
|
WilsonAnisotropyCoefficients anis;
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass = 0.5;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
WilsonCloverFermionR Dwc(Umu,Grid,RBGrid,mass,csw_r,csw_t,anis,params);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionR,FermionField> HermOp(Dwc);
|
||||||
|
|
||||||
|
TrivialPrecon<FermionField> simple;
|
||||||
|
|
||||||
|
FlexibleCommunicationAvoidingGeneralisedMinimalResidual<FermionField> FCAGMRES(1.0e-8, 10000, simple, 25);
|
||||||
|
FCAGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
74
tests/solver/Test_wilsonclover_fgmres_prec.cc
Normal file
74
tests/solver/Test_wilsonclover_fgmres_prec.cc
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_fgmres_prec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
typedef typename WilsonCloverFermionR::FermionField FermionField;
|
||||||
|
typename WilsonCloverFermionR::ImplParams params;
|
||||||
|
WilsonAnisotropyCoefficients anis;
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass = 0.5;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
WilsonCloverFermionR Dwc(Umu,Grid,RBGrid,mass,csw_r,csw_t,anis,params);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionR,FermionField> HermOp(Dwc);
|
||||||
|
|
||||||
|
TrivialPrecon<FermionField> simple;
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual<FermionField> FGMRES(1.0e-8, 10000, simple, 25);
|
||||||
|
FGMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
71
tests/solver/Test_wilsonclover_gmres_unprec.cc
Normal file
71
tests/solver/Test_wilsonclover_gmres_unprec.cc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_gmres_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
typedef typename WilsonCloverFermionR::FermionField FermionField;
|
||||||
|
typename WilsonCloverFermionR::ImplParams params;
|
||||||
|
WilsonAnisotropyCoefficients anis;
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass = 0.5;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
WilsonCloverFermionR Dwc(Umu,Grid,RBGrid,mass,csw_r,csw_t,anis,params);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionR,FermionField> HermOp(Dwc);
|
||||||
|
GeneralisedMinimalResidual<FermionField> GMRES(1.0e-8, 10000, 25);
|
||||||
|
GMRES(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
117
tests/solver/Test_wilsonclover_mg.cc
Normal file
117
tests/solver/Test_wilsonclover_mg.cc
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_mg.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
#include <Test_multigrid_common.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
|
||||||
|
GridCartesian * FGrid = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplex::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *FrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(FGrid);
|
||||||
|
|
||||||
|
std::vector<int> fSeeds({1, 2, 3, 4});
|
||||||
|
GridParallelRNG fPRNG(FGrid);
|
||||||
|
fPRNG.SeedFixedIntegers(fSeeds);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
LatticeFermion src(FGrid); gaussian(fPRNG, src);
|
||||||
|
LatticeFermion result(FGrid); result = zero;
|
||||||
|
LatticeGaugeField Umu(FGrid); SU3::HotConfiguration(fPRNG, Umu);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RealD mass = -0.25;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
|
||||||
|
MultiGridParams mgParams;
|
||||||
|
std::string inputXml{"./mg_params.xml"};
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--inputxml")) {
|
||||||
|
inputXml = GridCmdOptionPayload(argv, argv + argc, "--inputxml");
|
||||||
|
assert(inputXml.length() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
XmlWriter writer("mg_params_template.xml");
|
||||||
|
write(writer, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Written mg_params_template.xml" << std::endl;
|
||||||
|
|
||||||
|
XmlReader reader(inputXml);
|
||||||
|
read(reader, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Read in " << inputXml << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkParameterValidity(mgParams);
|
||||||
|
std::cout << mgParams << std::endl;
|
||||||
|
|
||||||
|
LevelInfo levelInfo(FGrid, mgParams);
|
||||||
|
|
||||||
|
// Note: We do chiral doubling, so actually only nbasis/2 full basis vectors are used
|
||||||
|
const int nbasis = 40;
|
||||||
|
|
||||||
|
WilsonCloverFermionR Dwc(Umu, *FGrid, *FrbGrid, mass, csw_r, csw_t);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionR, LatticeFermion> MdagMOpDwc(Dwc);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Testing Multigrid for Wilson Clover" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
TrivialPrecon<LatticeFermion> TrivialPrecon;
|
||||||
|
auto MGPreconDwc = createMGInstance<vSpinColourVector, vTComplex, nbasis, WilsonCloverFermionR>(mgParams, levelInfo, Dwc, Dwc);
|
||||||
|
|
||||||
|
MGPreconDwc->setup();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--runchecks")) {
|
||||||
|
RealD toleranceForMGChecks = (getPrecision<LatticeFermion>::value == 1) ? 1e-6 : 1e-13;
|
||||||
|
MGPreconDwc->runChecks(toleranceForMGChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<OperatorFunction<LatticeFermion>>> solversDwc;
|
||||||
|
|
||||||
|
solversDwc.emplace_back(new ConjugateGradient<LatticeFermion>(1.0e-12, 50000, false));
|
||||||
|
solversDwc.emplace_back(new FlexibleGeneralisedMinimalResidual<LatticeFermion>(1.0e-12, 50000, TrivialPrecon, 100, false));
|
||||||
|
solversDwc.emplace_back(new FlexibleGeneralisedMinimalResidual<LatticeFermion>(1.0e-12, 50000, *MGPreconDwc, 100, false));
|
||||||
|
|
||||||
|
for(auto const &solver : solversDwc) {
|
||||||
|
std::cout << std::endl << "Starting with a new solver" << std::endl;
|
||||||
|
result = zero;
|
||||||
|
(*solver)(MdagMOpDwc, src, result);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
MGPreconDwc->reportTimings();
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
169
tests/solver/Test_wilsonclover_mg_mp.cc
Normal file
169
tests/solver/Test_wilsonclover_mg_mp.cc
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_mg_mp.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
#include <Test_multigrid_common.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
Grid_init(&argc, &argv);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
GridCartesian *FGrid_d = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexD::Nsimd()), GridDefaultMpi());
|
||||||
|
GridCartesian *FGrid_f = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), GridDefaultSimd(Nd, vComplexF::Nsimd()), GridDefaultMpi());
|
||||||
|
GridRedBlackCartesian *FrbGrid_d = SpaceTimeGrid::makeFourDimRedBlackGrid(FGrid_d);
|
||||||
|
GridRedBlackCartesian *FrbGrid_f = SpaceTimeGrid::makeFourDimRedBlackGrid(FGrid_f);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
std::vector<int> fSeeds({1, 2, 3, 4});
|
||||||
|
GridParallelRNG fPRNG(FGrid_d);
|
||||||
|
fPRNG.SeedFixedIntegers(fSeeds);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
LatticeFermionD src_d(FGrid_d); gaussian(fPRNG, src_d);
|
||||||
|
LatticeFermionD resultMGD_d(FGrid_d); resultMGD_d = zero;
|
||||||
|
LatticeFermionD resultMGF_d(FGrid_d); resultMGF_d = zero;
|
||||||
|
LatticeGaugeFieldD Umu_d(FGrid_d); SU3::HotConfiguration(fPRNG, Umu_d);
|
||||||
|
LatticeGaugeFieldF Umu_f(FGrid_f); precisionChange(Umu_f, Umu_d);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RealD mass = -0.25;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
|
||||||
|
MultiGridParams mgParams;
|
||||||
|
std::string inputXml{"./mg_params.xml"};
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--inputxml")) {
|
||||||
|
inputXml = GridCmdOptionPayload(argv, argv + argc, "--inputxml");
|
||||||
|
assert(inputXml.length() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
XmlWriter writer("mg_params_template.xml");
|
||||||
|
write(writer, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Written mg_params_template.xml" << std::endl;
|
||||||
|
|
||||||
|
XmlReader reader(inputXml);
|
||||||
|
read(reader, "Params", mgParams);
|
||||||
|
std::cout << GridLogMessage << "Read in " << inputXml << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkParameterValidity(mgParams);
|
||||||
|
std::cout << mgParams << std::endl;
|
||||||
|
|
||||||
|
LevelInfo levelInfo_d(FGrid_d, mgParams);
|
||||||
|
LevelInfo levelInfo_f(FGrid_f, mgParams);
|
||||||
|
|
||||||
|
// Note: We do chiral doubling, so actually only nbasis/2 full basis vectors are used
|
||||||
|
const int nbasis = 40;
|
||||||
|
|
||||||
|
WilsonCloverFermionD Dwc_d(Umu_d, *FGrid_d, *FrbGrid_d, mass, csw_r, csw_t);
|
||||||
|
WilsonCloverFermionF Dwc_f(Umu_f, *FGrid_f, *FrbGrid_f, mass, csw_r, csw_t);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionD, LatticeFermionD> MdagMOpDwc_d(Dwc_d);
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionF, LatticeFermionF> MdagMOpDwc_f(Dwc_f);
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Testing single-precision Multigrid for Wilson Clover" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
auto MGPreconDwc_f = createMGInstance<vSpinColourVectorF, vTComplexF, nbasis, WilsonCloverFermionF>(mgParams, levelInfo_f, Dwc_f, Dwc_f);
|
||||||
|
|
||||||
|
MGPreconDwc_f->setup();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--runchecks")) {
|
||||||
|
MGPreconDwc_f->runChecks(1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
MixedPrecisionFlexibleGeneralisedMinimalResidual<LatticeFermionD, LatticeFermionF> MPFGMRESPREC(
|
||||||
|
1.0e-12, 50000, FGrid_f, *MGPreconDwc_f, 100, false);
|
||||||
|
|
||||||
|
std::cout << std::endl << "Starting with a new solver" << std::endl;
|
||||||
|
MPFGMRESPREC(MdagMOpDwc_d, src_d, resultMGF_d);
|
||||||
|
|
||||||
|
MGPreconDwc_f->reportTimings();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--docomparison")) {
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Testing double-precision Multigrid for Wilson Clover" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
auto MGPreconDwc_d = createMGInstance<vSpinColourVectorD, vTComplexD, nbasis, WilsonCloverFermionD>(mgParams, levelInfo_d, Dwc_d, Dwc_d);
|
||||||
|
|
||||||
|
MGPreconDwc_d->setup();
|
||||||
|
|
||||||
|
if(GridCmdOptionExists(argv, argv + argc, "--runchecks")) {
|
||||||
|
MGPreconDwc_d->runChecks(1e-13);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexibleGeneralisedMinimalResidual<LatticeFermionD> FGMRESPREC(1.0e-12, 50000, *MGPreconDwc_d, 100, false);
|
||||||
|
|
||||||
|
std::cout << std::endl << "Starting with a new solver" << std::endl;
|
||||||
|
FGMRESPREC(MdagMOpDwc_d, src_d, resultMGD_d);
|
||||||
|
|
||||||
|
MGPreconDwc_d->reportTimings();
|
||||||
|
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Comparing single-precision Multigrid with double-precision one for Wilson Clover" << std::endl;
|
||||||
|
std::cout << GridLogMessage << "**************************************************" << std::endl;
|
||||||
|
|
||||||
|
LatticeFermionD diffFullSolver(FGrid_d);
|
||||||
|
|
||||||
|
RealD deviationFullSolver = axpy_norm(diffFullSolver, -1.0, resultMGF_d, resultMGD_d);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
LatticeFermionF src_f(FGrid_f); precisionChange(src_f, src_d);
|
||||||
|
LatticeFermionF resMGF_f(FGrid_f); resMGF_f = zero;
|
||||||
|
LatticeFermionD resMGD_d(FGrid_d); resMGD_d = zero;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
(*MGPreconDwc_f)(src_f, resMGF_f);
|
||||||
|
(*MGPreconDwc_d)(src_d, resMGD_d);
|
||||||
|
|
||||||
|
LatticeFermionD diffOnlyMG(FGrid_d);
|
||||||
|
LatticeFermionD resMGF_d(FGrid_d);
|
||||||
|
precisionChange(resMGF_d, resMGF_f);
|
||||||
|
|
||||||
|
RealD deviationOnlyPrec = axpy_norm(diffOnlyMG, -1.0, resMGF_d, resMGD_d);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
std::cout << GridLogMessage << "Absolute difference between FGMRES preconditioned by double and single precicision MG: " << deviationFullSolver << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Relative deviation between FGMRES preconditioned by double and single precicision MG: " << deviationFullSolver / norm2(resultMGD_d) << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Absolute difference between one iteration of MG Prec in double and single precision: " << deviationOnlyPrec << std::endl;
|
||||||
|
std::cout << GridLogMessage << "Relative deviation between one iteration of MG Prec in double and single precision: " << deviationOnlyPrec / norm2(resMGD_d) << std::endl;
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
71
tests/solver/Test_wilsonclover_mr_unprec.cc
Normal file
71
tests/solver/Test_wilsonclover_mr_unprec.cc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*************************************************************************************
|
||||||
|
|
||||||
|
Grid physics library, www.github.com/paboyle/Grid
|
||||||
|
|
||||||
|
Source file: ./tests/solver/Test_wilsonclover_mr_unprec.cc
|
||||||
|
|
||||||
|
Copyright (C) 2015-2018
|
||||||
|
|
||||||
|
Author: Daniel Richtmann <daniel.richtmann@ur.de>
|
||||||
|
|
||||||
|
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 */
|
||||||
|
#include <Grid/Grid.h>
|
||||||
|
|
||||||
|
using namespace Grid;
|
||||||
|
using namespace Grid::QCD;
|
||||||
|
|
||||||
|
int main (int argc, char ** argv)
|
||||||
|
{
|
||||||
|
Grid_init(&argc,&argv);
|
||||||
|
|
||||||
|
std::vector<int> latt_size = GridDefaultLatt();
|
||||||
|
std::vector<int> simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
||||||
|
std::vector<int> mpi_layout = GridDefaultMpi();
|
||||||
|
GridCartesian Grid(latt_size,simd_layout,mpi_layout);
|
||||||
|
GridRedBlackCartesian RBGrid(&Grid);
|
||||||
|
|
||||||
|
std::vector<int> seeds({1,2,3,4});
|
||||||
|
GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(seeds);
|
||||||
|
|
||||||
|
typedef typename WilsonCloverFermionR::FermionField FermionField;
|
||||||
|
typename WilsonCloverFermionR::ImplParams params;
|
||||||
|
WilsonAnisotropyCoefficients anis;
|
||||||
|
|
||||||
|
FermionField src(&Grid); random(pRNG,src);
|
||||||
|
RealD nrm = norm2(src);
|
||||||
|
FermionField result(&Grid); result=zero;
|
||||||
|
LatticeGaugeField Umu(&Grid); SU3::HotConfiguration(pRNG,Umu);
|
||||||
|
|
||||||
|
double volume=1;
|
||||||
|
for(int mu=0;mu<Nd;mu++){
|
||||||
|
volume=volume*latt_size[mu];
|
||||||
|
}
|
||||||
|
|
||||||
|
RealD mass = 0.5;
|
||||||
|
RealD csw_r = 1.0;
|
||||||
|
RealD csw_t = 1.0;
|
||||||
|
WilsonCloverFermionR Dwc(Umu,Grid,RBGrid,mass,csw_r,csw_t,anis,params);
|
||||||
|
|
||||||
|
MdagMLinearOperator<WilsonCloverFermionR,FermionField> HermOp(Dwc);
|
||||||
|
MinimalResidual<FermionField> MR(1.0e-8,10000,0.8);
|
||||||
|
MR(HermOp,src,result);
|
||||||
|
|
||||||
|
Grid_finalize();
|
||||||
|
}
|
Reference in New Issue
Block a user