/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: Hadrons/Modules/MDistil/Distil.hpp Copyright (C) 2015-2019 Author: Felix Erben Author: Michael Marshall 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_MDistil_Distil_hpp_ #define Hadrons_MDistil_Distil_hpp_ #include #include #include #include #include #include BEGIN_HADRONS_NAMESPACE BEGIN_MODULE_NAMESPACE(MDistil) /****************************************************************************** Distillation code that is common across modules Documentation on how t use this code available at * https://aportelli.github.io/Hadrons-doc/#/mdistil * Notation for (stochastic) DistilParameters taken from 1104.3870: TI is interlaced dilution in time (corresponding to Nt = time-dimension of the lattice) LI is interlaced dilution in laplacian-eigenvector space (corresponding to nvec) SI is interlaced dilution in spin (corresponding to Ns, taken from Grid, usually Ns=4) This code automatically computes perambulators using exact distillation if * (TI,LI,SI) = (Nt,nvec,Ns) * In this case, nnoise=1 and Noises is set to an array of values =1 as well. tsrc then specifies the only timeslice on which the sources are supported. (( for stochastic distillation, the vaue of tsrc has no meaning in this code )) ******************************************************************************/ struct DistilParameters: Serializable { GRID_SERIALIZABLE_CLASS_MEMBERS(DistilParameters, int, nvec, int, nnoise, int, tsrc, int, TI, int, LI, int, SI ) DistilParameters() = default; DistilParameters( const DistilParameters &p ) = default; // member-wise copy }; /****************************************************************************** Make a lower dimensional grid in preparation for local slice operations ******************************************************************************/ inline GridCartesian * MakeLowerDimGrid( GridCartesian * gridHD ) { int nd{static_cast(gridHD->_ndimension)}; Coordinate latt_size = gridHD->_gdimensions; latt_size[nd-1] = 1; Coordinate simd_layout = GridDefaultSimd(nd-1, vComplex::Nsimd()); simd_layout.push_back( 1 ); Coordinate mpi_layout = gridHD->_processors; mpi_layout[nd-1] = 1; GridCartesian * gridLD = new GridCartesian(latt_size,simd_layout,mpi_layout,*gridHD); return gridLD; } /************************************************************************************* Rotate eigenvectors into our phase convention First component of first eigenvector is real and positive TODO: Should this be in Distil.hpp? *************************************************************************************/ inline void RotateEigen(std::vector & evec) { ColourVector cv0; auto grid = evec[0].Grid(); Coordinate siteFirst(grid->Nd(),0); peekSite(cv0, evec[0], siteFirst); Grid::Complex cplx0 = cv0()()(0); if( cplx0.imag() == 0 ) std::cout << GridLogMessage << "RotateEigen() : Site 0 : " << cplx0 << " => already meets phase convention" << std::endl; else { const Real cplx0_mag = Grid::sqrt(cplx0.real()*cplx0.real()+cplx0.imag()*cplx0.imag()); Grid::Complex phase{cplx0 / Grid::Complex(cplx0_mag, 0) }; phase.imag(-phase.imag()); #ifdef GRID_NVCC //const Real cplx0_mag = thrust::abs(cplx0); //const Grid::Complex phase = thrust::conj(cplx0 / cplx0_mag); const Real argphase = thrust::arg(phase); #else //const Real cplx0_mag = std::abs(cplx0); //const Grid::Complex phase = std::conj(cplx0 / cplx0_mag); const Real argphase = std::arg(phase); #endif std::cout << GridLogMessage << "RotateEigen() : Site 0 : |" << cplx0 << "|=" << cplx0_mag << " => phase=" << (argphase / 3.14159265) << " pi" << std::endl; { // TODO: Only really needed on the master slice for( int k = 0 ; k < evec.size() ; k++ ) evec[k] *= phase; if(grid->IsBoss()){ for( int c = 0 ; c < Nc ; c++ ) cv0()()(c) *= phase; cplx0.imag(0); // This assumes phase convention is real, positive (so I get rid of rounding error) //pokeSite(cv0, evec[0], siteFirst); pokeLocalSite(cv0, evec[0], siteFirst); } } } } END_MODULE_NAMESPACE END_HADRONS_NAMESPACE #endif // Hadrons_MDistil_Distil_hpp_