/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./tests/debug/Test_coarse_v2.cc Copyright (C) 2026 Author: Peter Boyle 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 */ // // MultiGeneralCoarsenedOperatorV2 against the existing mrhs coarse operator. // // V1 is constructed on the D+1 grid as now; V2 on the D dimensional grid, // with SetGrid() adopting the caller owned D+1 grid and building its padded // cell and neighbour table from the D dimensional stencil, with the Nrhs // factor multiplied in. // // Both are given identical matrix elements, so any difference in the apply is // the restructured neighbour table. The same geometry object is passed to // both: V1 adds one to skip for the rhs direction, V2 uses it as is on the D // dimensional grid, so both describe the same stencil over the D dimensions. // #include using namespace Grid; const int nbasis = 8; typedef vSpinColourVector FineObj; typedef sTComplexD CComplexT; // unvectorised coarse space typedef MultiGeneralCoarsenedMatrix MrhsV1; typedef MultiGeneralCoarsenedOperatorV2 MrhsV2; //////////////////////////////////////////////////////////////////////// // Identical random matrix elements into both operators //////////////////////////////////////////////////////////////////////// template void SeedMatrixElements(OpA &A,OpB &B,int npoint,GridSerialRNG &sRNG) { typedef typename OpA::calcMatrix calcMatrix; for(int p=0;p host(sites); ComplexD *w = (ComplexD *)&host[0]; int64_t words = sites*sizeof(calcMatrix)/sizeof(ComplexD); for(int64_t i=0;i RealD MatrixChecksum(Op &O,int npoint) { typedef typename Op::calcMatrix calcMatrix; RealD sum=0.0; for(int p=0;p host(sites); acceleratorCopyFromDevice(&O.BLAS_A[p][0],&host[0],sites*sizeof(calcMatrix)); ComplexD *w = (ComplexD *)&host[0]; int64_t words = sites*sizeof(calcMatrix)/sizeof(ComplexD); for(int64_t i=0;iNsimd() << std::endl; //////////////////////////////////////////////// // One geometry object for both, and one D+1 grid // owned here and shared by both operators: fields // conform only across a shared grid object. //////////////////////////////////////////////// NextToNearestStencilGeometry4D geom(CoarseD); Coordinate mlatt(1,nrhs), msimd(1,1), mmpi(1,1); for(int d=0;dNsimd() << std::endl; std::cout << GridLogMessage << "npoint V1 " << OpV1.geom.npoint << " npoint V2 " << OpV2.geom.npoint << std::endl; GRID_ASSERT(OpV1.geom.npoint == OpV2.geom.npoint); int npoint = OpV1.geom.npoint; //////////////////////////////////////////////// // Identical matrix elements //////////////////////////////////////////////// GridSerialRNG sRNG; sRNG.SeedFixedIntegers(std::vector({7,8,9,10})); SeedMatrixElements(OpV1,OpV2,npoint,sRNG); RealD ckV1 = MatrixChecksum(OpV1,npoint); RealD ckV2 = MatrixChecksum(OpV2,npoint); std::cout << GridLogMessage << "matrix element checksum V1 " << ckV1 << " V2 " << ckV2 << std::endl; GRID_ASSERT( ckV1 == ckV2 ); //////////////////////////////////////////////// // Same input, compare the applies //////////////////////////////////////////////// typedef MrhsV1::CoarseVector CoarseVector; // RNG on the D dimensional grid fills any D+1 field: the rhs direction is // undistributed and divides cleanly. One RNG serves every Nrhs. GridParallelRNG pRNG(CoarseD); pRNG.SeedFixedIntegers(std::vector({1,2,3,4})); CoarseVector in (CoarseMulti); random(pRNG,in); CoarseVector out1(CoarseMulti); CoarseVector out2(CoarseMulti); CoarseVector err (CoarseMulti); OpV1.M(in,out1); OpV2.M(in,out2); err = out1 - out2; std::cout << GridLogMessage << "|V1 out|^2 = " << norm2(out1) << " |V2 out|^2 = " << norm2(out2) << std::endl; std::cout << GridLogMessage << "|V1 - V2|^2 = " << norm2(err) << std::endl; GRID_ASSERT( norm2(out1) > 0.0 ); GRID_ASSERT( norm2(err) == 0.0 ); //////////////////////////////////////////////// // SetGrid is idempotent on pointer identity //////////////////////////////////////////////// OpV2.SetGrid(CoarseMulti); GRID_ASSERT( MatrixChecksum(OpV2,npoint) == ckV2 ); OpV2.M(in,out2); err = out1 - out2; GRID_ASSERT( norm2(err) == 0.0 ); std::cout << GridLogMessage << "SetGrid idempotent on identity" << std::endl; //////////////////////////////////////////////// // Move to a different Nrhs and back. The matrix // elements are Nrhs independent and must survive // both the release and the rebuild. //////////////////////////////////////////////// // Nrhs 1 is the single RHS case through the multiRHS path, and each slice // of the Nrhs 4 apply must come back unchanged. OpV2.M(in,out2); for(int nr=2;nr>=1;nr--){ Coordinate latt2(1,nr), simd2(1,1), mpi2(1,1); for(int d=0;d 2 -> 1 -> release -> 4, |V1 - V2|^2 = " << norm2(err) << std::endl; GRID_ASSERT( norm2(err) == 0.0 ); std::cout << GridLogMessage << "Test_coarse_v2: ALL PASS" << std::endl; Grid_finalize(); }